From 8bf62ecee58360749c5f0e68bc97d5e02a6816b1 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Thu, 12 May 2005 15:29:42 -0400 Subject: [PATCH 0001/1939] [libata] C/H/S support, for older devices --- drivers/scsi/libata-core.c | 140 ++++++++++++++---- drivers/scsi/libata-scsi.c | 292 +++++++++++++++++++++++-------------- include/linux/ata.h | 14 ++ include/linux/libata.h | 6 + 4 files changed, 318 insertions(+), 134 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 0b5d3a5b7eda..96355b05fe5c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -52,6 +52,7 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); @@ -1008,7 +1009,7 @@ static inline void ata_dump_id(struct ata_device *dev) static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; - unsigned int i; + unsigned int major_version; u16 tmp; unsigned long xfer_modes; u8 status; @@ -1106,9 +1107,9 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) * common ATA, ATAPI feature tests */ - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) { - printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id); + /* we require DMA support (bits 8 of word 49) */ + if (!ata_id_has_dma(dev->id)) { + printk(KERN_DEBUG "ata%u: no dma\n", ap->id); goto err_out_nosup; } @@ -1128,32 +1129,69 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) if (!ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; + /* get major version */ tmp = dev->id[ATA_ID_MAJOR_VER]; - for (i = 14; i >= 1; i--) - if (tmp & (1 << i)) + for (major_version = 14; major_version >= 1; major_version--) + if (tmp & (1 << major_version)) break; - /* we require at least ATA-3 */ - if (i < 3) { - printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id); - goto err_out_nosup; - } + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY + * INITIALIZE DEVICE PARAMETERS + * anything else.. + * Some drives were very specific about that exact sequence. + */ + if (major_version < 4 || (!ata_id_has_lba(dev->id))) + ata_dev_init_params(ap, dev); + + if (ata_id_has_lba(dev->id)) { + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(dev->id)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev->id, 100); + } else { + dev->n_sectors = ata_id_u32(dev->id, 60); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA"); + } else { + /* CHS */ + + /* Default translation */ + dev->cylinders = dev->id[1]; + dev->heads = dev->id[3]; + dev->sectors = dev->id[6]; + dev->n_sectors = dev->cylinders * dev->heads * dev->sectors; + + if (ata_id_current_chs_valid(dev->id)) { + /* Current CHS translation is valid. */ + dev->cylinders = dev->id[54]; + dev->heads = dev->id[55]; + dev->sectors = dev->id[56]; + + dev->n_sectors = ata_id_u32(dev->id, 57); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + (int)dev->cylinders, (int)dev->heads, (int)dev->sectors); - if (ata_id_has_lba48(dev->id)) { - dev->flags |= ATA_DFLAG_LBA48; - dev->n_sectors = ata_id_u64(dev->id, 100); - } else { - dev->n_sectors = ata_id_u32(dev->id, 60); } ap->host->max_cmd_len = 16; - - /* print device info to dmesg */ - printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", - ap->id, device, - ata_mode_string(xfer_modes), - (unsigned long long)dev->n_sectors, - dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } /* ATAPI-specific feature tests */ @@ -1946,6 +1984,54 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) DPRINTK("EXIT\n"); } +/** + * ata_dev_init_params - Issue INIT DEV PARAMS command + * @ap: Port associated with device @dev + * @dev: Device to which command will be sent + * + * LOCKING: + */ + +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; + u16 sectors = dev->id[6]; + u16 heads = dev->id[3]; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return; + + /* set up init dev params taskfile */ + DPRINTK("init dev params \n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + qc->tf.command = ATA_CMD_INIT_DEV_PARAMS; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = sectors; + qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + /** * ata_sg_clean - * @qc: @@ -2736,8 +2822,12 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, ata_tf_init(ap, &qc->tf, dev->devno); - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; + if (dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) + qc->tf.flags |= ATA_TFLAG_LBA48; + } } return qc; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 4c96df060c3b..8b065ef0e39a 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -435,78 +435,108 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; + unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 dev_sectors = qc->dev->n_sectors; - u64 sect = 0; - u32 n_sect = 0; + u64 block = 0; + u32 n_block = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - tf->device |= ATA_LBA; if (scsicmd[0] == VERIFY) { - sect |= ((u64)scsicmd[2]) << 24; - sect |= ((u64)scsicmd[3]) << 16; - sect |= ((u64)scsicmd[4]) << 8; - sect |= ((u64)scsicmd[5]); + block |= ((u64)scsicmd[2]) << 24; + block |= ((u64)scsicmd[3]) << 16; + block |= ((u64)scsicmd[4]) << 8; + block |= ((u64)scsicmd[5]); - n_sect |= ((u32)scsicmd[7]) << 8; - n_sect |= ((u32)scsicmd[8]); + n_block |= ((u32)scsicmd[7]) << 8; + n_block |= ((u32)scsicmd[8]); } else if (scsicmd[0] == VERIFY_16) { - sect |= ((u64)scsicmd[2]) << 56; - sect |= ((u64)scsicmd[3]) << 48; - sect |= ((u64)scsicmd[4]) << 40; - sect |= ((u64)scsicmd[5]) << 32; - sect |= ((u64)scsicmd[6]) << 24; - sect |= ((u64)scsicmd[7]) << 16; - sect |= ((u64)scsicmd[8]) << 8; - sect |= ((u64)scsicmd[9]); + block |= ((u64)scsicmd[2]) << 56; + block |= ((u64)scsicmd[3]) << 48; + block |= ((u64)scsicmd[4]) << 40; + block |= ((u64)scsicmd[5]) << 32; + block |= ((u64)scsicmd[6]) << 24; + block |= ((u64)scsicmd[7]) << 16; + block |= ((u64)scsicmd[8]) << 8; + block |= ((u64)scsicmd[9]); - n_sect |= ((u32)scsicmd[10]) << 24; - n_sect |= ((u32)scsicmd[11]) << 16; - n_sect |= ((u32)scsicmd[12]) << 8; - n_sect |= ((u32)scsicmd[13]); + n_block |= ((u32)scsicmd[10]) << 24; + n_block |= ((u32)scsicmd[11]) << 16; + n_block |= ((u32)scsicmd[12]) << 8; + n_block |= ((u32)scsicmd[13]); } else return 1; - if (!n_sect) + if (!n_block) return 1; - if (sect >= dev_sectors) + if (block >= dev_sectors) return 1; - if ((sect + n_sect) > dev_sectors) + if ((block + n_block) > dev_sectors) return 1; if (lba48) { - if (n_sect > (64 * 1024)) + if (n_block > (64 * 1024)) return 1; } else { - if (n_sect > 256) + if (n_block > 256) return 1; } - if (lba48) { - tf->command = ATA_CMD_VERIFY_EXT; + if (lba) { + if (lba48) { + tf->command = ATA_CMD_VERIFY_EXT; - tf->hob_nsect = (n_sect >> 8) & 0xff; + tf->hob_nsect = (n_block >> 8) & 0xff; - tf->hob_lbah = (sect >> 40) & 0xff; - tf->hob_lbam = (sect >> 32) & 0xff; - tf->hob_lbal = (sect >> 24) & 0xff; + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + tf->command = ATA_CMD_VERIFY; + + tf->device |= (block >> 24) & 0xf; + } + + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return 1; + tf->command = ATA_CMD_VERIFY; - - tf->device |= (sect >> 24) & 0xf; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - tf->nsect = n_sect & 0xff; - - tf->lbah = (sect >> 16) & 0xff; - tf->lbam = (sect >> 8) & 0xff; - tf->lbal = sect & 0xff; - return 0; } @@ -533,11 +563,14 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; + unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 block = 0; + u32 n_block = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = qc->dev->xfer_protocol; - tf->device |= ATA_LBA; if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || scsicmd[0] == READ_16) { @@ -547,80 +580,111 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->flags |= ATA_TFLAG_WRITE; } + /* Calculate the SCSI LBA and transfer length. */ if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - if (lba48) { - tf->hob_nsect = scsicmd[7]; - tf->hob_lbal = scsicmd[2]; + block |= ((u64)scsicmd[2]) << 24; + block |= ((u64)scsicmd[3]) << 16; + block |= ((u64)scsicmd[4]) << 8; + block |= ((u64)scsicmd[5]); - qc->nsect = ((unsigned int)scsicmd[7] << 8) | - scsicmd[8]; - } else { - /* if we don't support LBA48 addressing, the request - * -may- be too large. */ - if ((scsicmd[2] & 0xf0) || scsicmd[7]) - return 1; - - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; - - qc->nsect = scsicmd[8]; - } - - tf->nsect = scsicmd[8]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[4]; - tf->lbah = scsicmd[3]; + n_block |= ((u32)scsicmd[7]) << 8; + n_block |= ((u32)scsicmd[8]); VPRINTK("ten-byte command\n"); - return 0; - } - - if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - qc->nsect = tf->nsect = scsicmd[4]; - tf->lbal = scsicmd[3]; - tf->lbam = scsicmd[2]; - tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ - + } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { + block |= ((u64)scsicmd[2]) << 8; + block |= ((u64)scsicmd[3]); + n_block |= ((u32)scsicmd[4]); + VPRINTK("six-byte command\n"); - return 0; - } + } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { + block |= ((u64)scsicmd[2]) << 56; + block |= ((u64)scsicmd[3]) << 48; + block |= ((u64)scsicmd[4]) << 40; + block |= ((u64)scsicmd[5]) << 32; + block |= ((u64)scsicmd[6]) << 24; + block |= ((u64)scsicmd[7]) << 16; + block |= ((u64)scsicmd[8]) << 8; + block |= ((u64)scsicmd[9]); - if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - /* rule out impossible LBAs and sector counts */ - if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) - return 1; - - if (lba48) { - tf->hob_nsect = scsicmd[12]; - tf->hob_lbal = scsicmd[6]; - tf->hob_lbam = scsicmd[5]; - tf->hob_lbah = scsicmd[4]; - - qc->nsect = ((unsigned int)scsicmd[12] << 8) | - scsicmd[13]; - } else { - /* once again, filter out impossible non-zero values */ - if (scsicmd[4] || scsicmd[5] || scsicmd[12] || - (scsicmd[6] & 0xf0)) - return 1; - - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[6]; - - qc->nsect = scsicmd[13]; - } - - tf->nsect = scsicmd[13]; - tf->lbal = scsicmd[9]; - tf->lbam = scsicmd[8]; - tf->lbah = scsicmd[7]; + n_block |= ((u32)scsicmd[10]) << 24; + n_block |= ((u32)scsicmd[11]) << 16; + n_block |= ((u32)scsicmd[12]) << 8; + n_block |= ((u32)scsicmd[13]); VPRINTK("sixteen-byte command\n"); - return 0; + } else { + DPRINTK("no-byte command\n"); + return 1; } - DPRINTK("no-byte command\n"); - return 1; + /* Check and compose ATA command */ + if (!n_block) + /* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */ + return 1; + + if (lba) { + if (lba48) { + /* The request -may- be too large for LBA48. */ + if ((block >> 48) || (n_block > 65536)) + return 1; + + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + /* LBA28 */ + + /* The request -may- be too large for LBA28. */ + if ((block >> 28) || (n_block > 256)) + return 1; + + tf->device |= (block >> 24) & 0xf; + } + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if ((block >> 28) || (n_block > 256)) + return 1; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return 1; + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } + + return 0; } static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) @@ -1167,10 +1231,20 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, VPRINTK("ENTER\n"); - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); + if (ata_id_has_lba(args->id)) { + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + } else { + /* CHS default translation */ + n_sectors = args->id[1] * args->id[3] * args->id[6]; + + if (ata_id_current_chs_valid(args->id)) + /* CHS current translation */ + n_sectors = ata_id_u32(args->id, 57); + } + n_sectors--; /* ATA TotalUserSectors - 1 */ tmp = n_sectors; /* note: truncates, if lba48 */ diff --git a/include/linux/ata.h b/include/linux/ata.h index f178894edd04..d8981402cd5b 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -125,6 +125,7 @@ enum { ATA_CMD_PACKET = 0xA0, ATA_CMD_VERIFY = 0x40, ATA_CMD_VERIFY_EXT = 0x42, + ATA_CMD_INIT_DEV_PARAMS = 0x91, /* SETFEATURES stuff */ SETFEATURES_XFER = 0x03, @@ -174,6 +175,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_LBA = (1 << 4), /* enable LBA */ }; enum ata_tf_protocols { @@ -242,6 +244,18 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) +static inline int ata_id_current_chs_valid(u16 *id) +{ + /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command + has not been issued to the device then the values of + id[54] to id[56] are vendor specific. */ + return (id[53] & 0x01) && /* Current translation valid */ + id[54] && /* cylinders in current translation */ + id[55] && /* heads in current translation */ + id[55] <= 16 && + id[56]; /* sectors in current translation */ +} + 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 505160ab472b..bd0df84cfd87 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -95,6 +95,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_LBA = (1 << 3), /* device supports LBA */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -278,6 +279,11 @@ struct ata_device { u8 xfer_protocol; /* taskfile xfer protocol */ u8 read_cmd; /* opcode to use on read */ u8 write_cmd; /* opcode to use on write */ + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ }; struct ata_port { From b095518ef51c37658c58367bd19240b8a113f25c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 12 May 2005 15:45:22 -0400 Subject: [PATCH 0002/1939] [libata] ATA passthru (arbitrary ATA command execution) Authors: Brett Russ John W. Linville Andy Warner --- drivers/scsi/libata-scsi.c | 659 +++++++++++++++++++++++++++++++------ drivers/scsi/libata.h | 3 +- include/scsi/scsi.h | 3 + 3 files changed, 556 insertions(+), 109 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 4c96df060c3b..22c77a113536 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -29,10 +29,13 @@ #include "scsi.h" #include #include +#include #include #include "libata.h" +#define SECTOR_SIZE 512 + typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); @@ -67,6 +70,148 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +/** + * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ + +int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[4], *argbuf = NULL; + int argsize = 0; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) + return -EINTR; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + + if (args[3]) { + argsize = SECTOR_SIZE * args[3]; + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) + return -ENOMEM; + + scsi_cmd[1] = (4 << 1); /* PIO Data-in */ + scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, + block count in sector count field */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + } else { + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + sreq->sr_data_direction = DMA_NONE; + } + + scsi_cmd[0] = ATA_16; + + scsi_cmd[4] = args[2]; + if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */ + scsi_cmd[6] = args[3]; + scsi_cmd[8] = args[1]; + scsi_cmd[10] = 0x4f; + scsi_cmd[12] = 0xc2; + } else { + scsi_cmd[6] = args[1]; + } + scsi_cmd[14] = args[0]; + + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + + if ((argbuf) + && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize)) + rc = -EFAULT; +error: + scsi_release_request(sreq); + + if (argbuf) + kfree(argbuf); + + return rc; +} + +/** + * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ +int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[7]; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[4] = args[1]; + scsi_cmd[6] = args[2]; + scsi_cmd[8] = args[3]; + scsi_cmd[10] = args[4]; + scsi_cmd[12] = args[5]; + scsi_cmd[14] = args[0]; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) { + rc = -EINTR; + goto error; + } + + sreq->sr_data_direction = DMA_NONE; + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + +error: + scsi_release_request(sreq); + return rc; +} + int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { struct ata_port *ap; @@ -96,6 +241,16 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) return -EINVAL; return 0; + case HDIO_DRIVE_CMD: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_cmd_ioctl(scsidev, arg); + + case HDIO_DRIVE_TASK: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_task_ioctl(scsidev, arg); + default: rc = -ENOTTY; break; @@ -154,24 +309,69 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, } /** - * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out - * @drv_stat: value contained in ATA status register + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, struct ata_taskfile *tf) +{ + u8 stat = tf->command, err = tf->feature; + + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + if (stat & ATA_BUSY) { + printk("Busy }\n"); /* Data is not valid in this case */ + } else { + if (stat & 0x40) printk("DriveReady "); + if (stat & 0x20) printk("DeviceFault "); + if (stat & 0x10) printk("SeekComplete "); + if (stat & 0x08) printk("DataRequest "); + if (stat & 0x04) printk("CorrectedError "); + if (stat & 0x02) printk("Index "); + if (stat & 0x01) printk("Error "); + printk("}\n"); + + if (err) { + printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); + if (err & 0x04) printk("DriveStatusError "); + if (err & 0x80) { + if (err & 0x04) printk("BadCRC "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** + * ata_to_sense_error - convert ATA error to SCSI error + * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out + * + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -212,105 +412,183 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ - - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); - - /* Display the ATA level error info */ - - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { - printk("Busy "); - err = 0; /* Data is not valid in this case */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); - } - printk("}\n"); - if(err) - { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - printk("BadCRC "); - else - printk("Sector "); + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == + sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + goto translate_done; + } } - if(err & 0x40) printk("UncorrectableError "); - if(err & 0x10) printk("SectorIdNotFound "); - if(err & 0x02) printk("TrackZeroNotFound "); - if(err & 0x01) printk("AddrMarkNotFound "); - printk("}\n"); - - /* Should we dump sector info here too ?? */ + /* No immediate match */ + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } - - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { - /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; - } - i++; - } - /* No immediate match */ - if(err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); - - i = 0; /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; - return; + for (i = 0; stat_table[i][0] != 0xFF; i++) { + if (stat_table[i][0] & drv_stat) { + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; + goto translate_done; } - i++; } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ + /* No error? Undecoded? */ + printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ + + translate_done: + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " + "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, + *sk, *asc, *ascq); + return; +} + +/* + * ata_gen_ata_desc_sense - Generate check condition sense block. + * @qc: Command that completed. + * + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. Regardless + * of whether the command errored or not, return a sense + * block. Copy all controller registers into the sense + * block. Clear sense key, ASC & ASCQ if there is no error. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; + } + + /* + * Sense data is current and format is descriptor. + */ + sb[0] = 0x72; + + desc[0] = 0x09; + + /* + * Set length of additional sense data. + * Since we only populate descriptor 0, the total + * length is the same (fixed) length as descriptor 0. + */ + desc[1] = sb[7] = 14; + + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00; + desc[3] = tf->feature; /* == error reg */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->command; /* == status reg */ + + /* + * Fill in Extend bit, and the high order bytes + * if applicable. + */ + if (tf->flags & ATA_TFLAG_LBA48) { + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; + } +} + +/** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; + } sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + sb[7] = 0x0a; + if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; } } @@ -626,11 +904,36 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ); - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else - cmd->result = SAM_STAT_GOOD; + /* 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 + * is generated and the ATA register values are returned + * whether the command completed successfully or not. If there + * was no error, SK, ASC and ASCQ will all be zero. + */ + if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && + ((cmd->cmnd[2] & 0x20) || need_sense)) { + ata_gen_ata_desc_sense(qc); + } else { + if (!need_sense) { + cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } + + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); + } qc->scsidone(cmd); @@ -671,8 +974,8 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, return; /* data is present; dma-map it */ - if (cmd->sc_data_direction == DMA_FROM_DEVICE || - cmd->sc_data_direction == DMA_TO_DEVICE) { + if (cmd->sc_data_direction == SCSI_DATA_READ || + cmd->sc_data_direction == SCSI_DATA_WRITE) { if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", ap->id, dev->devno); @@ -692,7 +995,6 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, if (xlat_func(qc, scsicmd)) goto err_out; - /* select device, send command to hardware */ if (ata_qc_issue(qc)) goto err_out; @@ -1304,7 +1606,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); - int nodata = (cmd->sc_data_direction == DMA_NONE); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); if (!using_pio) /* Check whether ATAPI DMA is safe */ @@ -1316,7 +1618,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - if (cmd->sc_data_direction == DMA_TO_DEVICE) { + if (cmd->sc_data_direction == SCSI_DATA_WRITE) { qc->tf.flags |= ATA_TFLAG_WRITE; DPRINTK("direction: write\n"); } @@ -1340,7 +1642,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) #ifdef ATAPI_ENABLE_DMADIR /* some SATA bridges need us to indicate data xfer direction */ - if (cmd->sc_data_direction != DMA_TO_DEVICE) + if (cmd->sc_data_direction != SCSI_DATA_WRITE) qc->tf.feature |= ATAPI_DMADIR; #endif } @@ -1393,6 +1695,143 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) return dev; } +/* + * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value. + * @byte1: Byte 1 from pass-thru CDB. + * + * RETURNS: + * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise. + */ +static u8 +ata_scsi_map_proto(u8 byte1) +{ + switch((byte1 & 0x1e) >> 1) { + case 3: /* Non-data */ + return ATA_PROT_NODATA; + + case 6: /* DMA */ + return ATA_PROT_DMA; + + case 4: /* PIO Data-in */ + case 5: /* PIO Data-out */ + if (byte1 & 0xe0) { + return ATA_PROT_PIO_MULT; + } + return ATA_PROT_PIO; + + case 10: /* Device Reset */ + case 0: /* Hard Reset */ + case 1: /* SRST */ + case 2: /* Bus Idle */ + case 7: /* Packet */ + case 8: /* DMA Queued */ + case 9: /* Device Diagnostic */ + case 11: /* UDMA Data-in */ + case 12: /* UDMA Data-Out */ + case 13: /* FPDMA */ + default: /* Reserved */ + break; + } + + return ATA_PROT_UNKNOWN; +} + +/** + * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile + * @qc: command structure to be initialized + * @cmd: SCSI command to convert + * + * Handles either 12 or 16-byte versions of the CDB. + * + * RETURNS: + * Zero on success, non-zero on failure. + */ +static unsigned int +ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &(qc->tf); + struct scsi_cmnd *cmd = qc->scsicmd; + + if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) + return 1; + + /* + * 12 and 16 byte CDBs use different offsets to + * provide the various register values. + */ + if (scsicmd[0] == ATA_16) { + /* + * 16-byte CDB - may contain extended commands. + * + * If that is the case, copy the upper byte register values. + */ + if (scsicmd[1] & 0x01) { + tf->hob_feature = scsicmd[3]; + tf->hob_nsect = scsicmd[5]; + tf->hob_lbal = scsicmd[7]; + tf->hob_lbam = scsicmd[9]; + tf->hob_lbah = scsicmd[11]; + tf->flags |= ATA_TFLAG_LBA48; + } else + tf->flags &= ~ATA_TFLAG_LBA48; + + /* + * Always copy low byte, device and command registers. + */ + tf->feature = scsicmd[4]; + tf->nsect = scsicmd[6]; + tf->lbal = scsicmd[8]; + tf->lbam = scsicmd[10]; + tf->lbah = scsicmd[12]; + tf->device = scsicmd[13]; + tf->command = scsicmd[14]; + } else { + /* + * 12-byte CDB - incapable of extended commands. + */ + tf->flags &= ~ATA_TFLAG_LBA48; + + tf->feature = scsicmd[3]; + tf->nsect = scsicmd[4]; + tf->lbal = scsicmd[5]; + tf->lbam = scsicmd[6]; + tf->lbah = scsicmd[7]; + tf->device = scsicmd[8]; + tf->command = scsicmd[9]; + } + + /* + * Filter SET_FEATURES - XFER MODE command -- otherwise, + * SET_FEATURES - XFER MODE must be preceded/succeeded + * by an update to hardware-specific registers for each + * controller (i.e. the reason for ->set_piomode(), + * ->set_dmamode(), and ->post_set_mode() hooks). + */ + if ((tf->command == ATA_CMD_SET_FEATURES) + && (tf->feature == SETFEATURES_XFER)) + return 1; + + /* + * Set flags so that all registers will be written, + * and pass on write indication (used for PIO/DMA + * setup.) + */ + tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); + + if (cmd->sc_data_direction == SCSI_DATA_WRITE) + tf->flags |= ATA_TFLAG_WRITE; + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + qc->nsect = cmd->bufflen / ATA_SECT_SIZE; + + return 0; +} + /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -1425,6 +1864,10 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + + case ATA_12: + case ATA_16: + return ata_scsi_pass_thru; } return NULL; @@ -1581,7 +2024,7 @@ void ata_scsi_simulate(u16 *id, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandantory commands we haven't implemented yet */ + /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 6518226b8f87..c595f5f58c16 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -44,10 +44,11 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); +extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); +extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); 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); diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 659ecf48fb4a..27d4d9ea6c6d 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -113,6 +113,9 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 +/* Values for T10/04-262r7 */ +#define ATA_16 0x85 /* 16-byte pass-thru */ +#define ATA_12 0xa1 /* 12-byte pass-thru */ /* * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft From 0274aa2506fd2fe89a58dd6cd64d3b3f7b976af8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 22 Jun 2005 13:50:56 -0400 Subject: [PATCH 0003/1939] libata: Update 'passthru' branch for latest libata --- drivers/scsi/libata-scsi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index cdc0a10a606c..c1cf5e038967 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -582,7 +582,11 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc) sb[0] = 0x70; sb[7] = 0x0a; + +#if 0 /* when C/H/S support is merged */ if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { +#endif + if (!(tf->flags & ATA_TFLAG_LBA48)) { /* A small (28b) LBA will fit in the 32b info field */ sb[0] |= 0x80; /* set valid bit */ sb[3] = tf->device & 0x0f; @@ -977,8 +981,8 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, return; /* data is present; dma-map it */ - if (cmd->sc_data_direction == SCSI_DATA_READ || - cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (cmd->sc_data_direction == DMA_FROM_DEVICE || + 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); @@ -1609,7 +1613,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); - int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + int nodata = (cmd->sc_data_direction == DMA_NONE); if (!using_pio) /* Check whether ATAPI DMA is safe */ @@ -1621,7 +1625,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - if (cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { qc->tf.flags |= ATA_TFLAG_WRITE; DPRINTK("direction: write\n"); } @@ -1645,7 +1649,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) #ifdef ATAPI_ENABLE_DMADIR /* some SATA bridges need us to indicate data xfer direction */ - if (cmd->sc_data_direction != SCSI_DATA_WRITE) + if (cmd->sc_data_direction != DMA_TO_DEVICE) qc->tf.feature |= ATAPI_DMADIR; #endif } @@ -1821,7 +1825,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd) */ tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); - if (cmd->sc_data_direction == SCSI_DATA_WRITE) + if (cmd->sc_data_direction == DMA_TO_DEVICE) tf->flags |= ATA_TFLAG_WRITE; /* From edb3366703224d5d8df573ae698ccd6b488dc743 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Jul 2005 10:36:22 +0900 Subject: [PATCH 0004/1939] [PATCH] SATA: rewritten sil24 driver This is rewritten sil24 driver against v2.6.13-rc3. Rewritten based on driver originally submitted by Silicon Image. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/Kconfig | 8 + drivers/scsi/Makefile | 1 + drivers/scsi/sata_sil24.c | 786 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 795 insertions(+) create mode 100644 drivers/scsi/sata_sil24.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 96df148ed969..939d3442c13a 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -499,6 +499,14 @@ config SCSI_SATA_SIL If unsure, say N. +config SCSI_SATA_SIL24 + tristate "Silicon Image 3124/3132 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Silicon Image 3124/3132 Serial ATA. + + If unsure, say N. + config SCSI_SATA_SIS tristate "SiS 964/180 SATA support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 3746fb9fa2f5..64aaab64aeb6 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o +obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c new file mode 100644 index 000000000000..9958bc10a258 --- /dev/null +++ b/drivers/scsi/sata_sil24.c @@ -0,0 +1,786 @@ +/* + * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers + * + * Copyright 2005 Tejun Heo + * + * Based on preview driver from Silicon Image. + * + * NOTE: No NCQ/ATAPI support yet. The preview driver didn't support + * NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make + * those work. Enabling those shouldn't be difficult. Basic + * structure is all there (in libata-dev tree). If you have any + * information about this hardware, please contact me or linux-ide. + * Info is needed on... + * + * - How to issue tagged commands and turn on sactive on issue accordingly. + * - Where to put an ATAPI command and how to tell the device to send it. + * - How to enable/use 64bit. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "sata_sil24" +#define DRV_VERSION "0.20" /* Silicon Image's preview driver was 0.10 */ + +#define NR_PORTS 4 + +/* + * Port request block (PRB) 32 bytes + */ +struct sil24_prb { + u16 ctrl; + u16 prot; + u32 rx_cnt; + u8 fis[6 * 4]; +}; + +/* + * Scatter gather entry (SGE) 16 bytes + */ +struct sil24_sge { + u64 addr; + u32 cnt; + u32 flags; +}; + +/* + * Port multiplier + */ +struct sil24_port_multiplier { + u32 diag; + u32 sactive; +}; + +enum { + /* + * Global controller registers (128 bytes @ BAR0) + */ + /* 32 bit regs */ + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */ + /* TF is overlayed w/ PRB regs in the preview driver, + * but it doesn't seem to work. */ + PORT_TF = 0x0000, + + PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write:ctrl, read:stat */ + PORT_CTRL_CLR = 0x1004, + PORT_IRQ_STAT = 0x1008, + PORT_IRQ_ENABLE_SET = 0x1010, + PORT_IRQ_ENABLE_CLR = 0x1014, + PORT_ACTIVATE_UPPER_ADDR= 0x101c, + PORT_EXEC_FIFO = 0x1020, + PORT_CMD_ERR = 0x1024, + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_RESUME = (1 << 4), /* port resume */ + PORT_CS_32BIT_ACTV = (1 << 5), /* 32-bit activation */ + PORT_CS_PM_EN = (1 << 6), /* port multiplier enable */ + PORT_CS_RDY = (1 << 7), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* Unknown FIS received */ + PORT_IRQ_SDB_FIS = (1 << 11), /* SDB FIS received */ + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */ + PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */ + PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */ + PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */ + PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */ + PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */ + PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */ + PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */ + PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */ + PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */ + PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */ + PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */ + PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ + PORT_CERR_SENDSERVICE = 36, /* FIS received whiel sending service */ + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* board id */ + BID_SIL3124 = 0, + BID_SIL3132 = 1, + + IRQ_STAT_4PORTS = 0xf, +}; + +struct sil24_cmd_block { + struct sil24_prb prb; + struct sil24_sge sge[LIBATA_MAX_PRD]; +}; + +/* + * ap->private_data + * + * The preview driver always returned 0 for status. We emulate it + * here from the previous interrupt. + */ +struct sil24_port_priv { + void *port; + struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ + dma_addr_t cmd_block_dma; /* DMA base addr for them */ +}; + +/* ap->host_set->private_data */ +struct sil24_host_priv { + void *host_base; /* global controller control (128 bytes @BAR0) */ + void *port_base; /* port registers (4 * 8192 bytes @BAR2) */ +}; + +static u8 sil24_check_status(struct ata_port *ap); +static u8 sil24_check_err(struct ata_port *ap); +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static void sil24_phy_reset(struct ata_port *ap); +static void sil24_qc_prep(struct ata_queued_cmd *qc); +static int sil24_qc_issue(struct ata_queued_cmd *qc); +static void sil24_irq_clear(struct ata_port *ap); +static void sil24_eng_timeout(struct ata_port *ap); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sil24_port_start(struct ata_port *ap); +static void sil24_port_stop(struct ata_port *ap); +static void sil24_host_stop(struct ata_host_set *host_set); +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +static struct pci_device_id sil24_pci_tbl[] = { + { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, + { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, +}; + +static struct pci_driver sil24_pci_driver = { + .name = DRV_NAME, + .id_table = sil24_pci_tbl, + .probe = sil24_init_one, + .remove = ata_pci_remove_one, /* safe? */ +}; + +static Scsi_Host_Template sil24_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, + .ordered_flush = 1, /* NCQ not supported yet */ +}; + +static struct ata_port_operations sil24_ops = { + .port_disable = ata_port_disable, + + .check_status = sil24_check_status, + .check_altstatus = sil24_check_status, + .check_err = sil24_check_err, + .dev_select = ata_noop_dev_select, + + .phy_reset = sil24_phy_reset, + + .qc_prep = sil24_qc_prep, + .qc_issue = sil24_qc_issue, + + .eng_timeout = sil24_eng_timeout, + + .irq_handler = sil24_interrupt, + .irq_clear = sil24_irq_clear, + + .scr_read = sil24_scr_read, + .scr_write = sil24_scr_write, + + .port_start = sil24_port_start, + .port_stop = sil24_port_stop, + .host_stop = sil24_host_stop, +}; + +static struct ata_port_info sil24_port_info[] = { + /* sil_3124 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3132 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, +}; + +static u8 sil24_check_status(struct ata_port *ap) +{ + return ATA_DRDY; +} + +static u8 sil24_check_err(struct ata_port *ap) +{ + return 0; +} + +static int sil24_scr_map[] = { + [SCR_CONTROL] = 0, + [SCR_STATUS] = 1, + [SCR_ERROR] = 2, + [SCR_ACTIVE] = 3, +}; + +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + return readl(scr_addr + sil24_scr_map[sc_reg] * 4); + } + return 0xffffffffU; +} + +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); + } +} + +static void sil24_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + /* + * No ATAPI yet. Just unconditionally indicate ATA device. + * If ATAPI device is attached, it will fail ATA_CMD_ID_ATA + * and libata core will ignore the device. + */ + if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) + ap->device[0].class = ATA_DEV_ATA; +} + +static inline void sil24_fill_sg(struct ata_queued_cmd *qc, + struct sil24_cmd_block *cb) +{ + struct scatterlist *sg = qc->sg; + struct sil24_sge *sge = cb->sge; + unsigned i; + + for (i = 0; i < qc->n_elem; i++, sg++, sge++) { + sge->addr = cpu_to_le64(sg_dma_address(sg)); + sge->cnt = cpu_to_le32(sg_dma_len(sg)); + sge->flags = 0; + sge->flags = i < qc->n_elem - 1 ? 0 : cpu_to_le32(SGE_TRM); + } +} + +static void sil24_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct sil24_port_priv *pp = ap->private_data; + struct sil24_cmd_block *cb = pp->cmd_block + qc->tag; + struct sil24_prb *prb = &cb->prb; + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + break; + default: + /* ATAPI isn't supported yet */ + BUG(); + } + + ata_tf_to_fis(&qc->tf, prb->fis, 0); + + if (qc->flags & ATA_QCFLAG_DMAMAP) + sil24_fill_sg(qc, cb); +} + +static int sil24_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct sil24_port_priv *pp = ap->private_data; + dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); + + writel((u32)paddr, pp->port + PORT_CMD_ACTIVATE); + return 0; +} + +static void sil24_irq_clear(struct ata_port *ap) +{ + /* unused */ +} + +static void sil24_reset_controller(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + void *port = pp->port; + int cnt; + u32 tmp; + + printk(KERN_NOTICE DRV_NAME + " ata%u: resetting controller...\n", ap->id); + + /* Reset controller state. Is this correct? */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); /* sync */ + + /* Max ~100ms */ + for (cnt = 0; cnt < 1000; cnt++) { + udelay(100); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_DEV_RST)) + break; + } + if (tmp & PORT_CS_DEV_RST) + printk(KERN_ERR DRV_NAME + " ata%u: failed to reset controller\n", ap->id); +} + +static void sil24_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: tiemout without command\n", + ap->id); + return; + } + + /* + * hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); +} + +static inline void sil24_host_intr(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct sil24_port_priv *pp = ap->private_data; + void *port = pp->port; + u32 slot_stat; + + slot_stat = readl(port + PORT_SLOT_STAT); + if (!(slot_stat & HOST_SSTAT_ATTN)) { + if (qc) + ata_qc_complete(qc, 0); + } else { + u32 irq_stat, cmd_err, sstatus, serror; + + irq_stat = readl(port + PORT_IRQ_STAT); + cmd_err = readl(port + PORT_CMD_ERR); + sstatus = readl(port + PORT_SSTATUS); + serror = readl(port + PORT_SERROR); + + /* Clear IRQ/errors */ + writel(irq_stat, port + PORT_IRQ_STAT); + if (cmd_err) + writel(cmd_err, port + PORT_CMD_ERR); + if (serror) + writel(serror, port + PORT_SERROR); + + printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" + " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", + ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + + if (qc) + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); + } +} + +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct sil24_host_priv *hpriv = host_set->private_data; + unsigned handled = 0; + u32 status; + int i; + + status = readl(hpriv->host_base + HOST_IRQ_STAT); + + if (!(status & IRQ_STAT_4PORTS)) + goto out; + + spin_lock(&host_set->lock); + + 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)) + sil24_host_intr(host_set->ports[i]); + else { + u32 tmp; + printk(KERN_WARNING DRV_NAME + ": spurious interrupt from port %d\n", i); + tmp = readl(hpriv->host_base + HOST_CTRL); + tmp &= ~(1 << i); + writel(tmp, hpriv->host_base + HOST_CTRL); + } + handled++; + } + + spin_unlock(&host_set->lock); + out: + return IRQ_RETVAL(handled); +} + +static int sil24_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_host_priv *hpriv = ap->host_set->private_data; + struct sil24_port_priv *pp; + struct sil24_cmd_block *cb; + size_t cb_size = sizeof(*cb); + dma_addr_t cb_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + memset(pp, 0, sizeof(*pp)); + + cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); + if (!cb) { + kfree(pp); + return -ENOMEM; + } + memset(cb, 0, cb_size); + + pp->port = hpriv->port_base + ap->port_no * PORT_REGS_SIZE; + pp->cmd_block = cb; + pp->cmd_block_dma = cb_dma; + + ap->private_data = pp; + + return 0; +} + +static void sil24_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp = ap->private_data; + size_t cb_size = sizeof(*pp->cmd_block); + + dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); + kfree(pp); +} + +static void sil24_host_stop(struct ata_host_set *host_set) +{ + struct sil24_host_priv *hpriv = host_set->private_data; + + iounmap(hpriv->host_base); + iounmap(hpriv->port_base); + kfree(hpriv); +} + +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_probe_ent *probe_ent = NULL; + struct sil24_host_priv *hpriv = NULL; + void *host_base = NULL, *port_base = NULL; + int i, rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto out_disable; + + rc = -ENOMEM; + /* ioremap mmio registers */ + host_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host_base) + goto out_free; + port_base = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!port_base) + goto out_free; + + /* allocate & init probe_ent and hpriv */ + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + goto out_free; + + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + goto out_free; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = sil24_port_info[board_id].sht; + probe_ent->host_flags = sil24_port_info[board_id].host_flags; + probe_ent->pio_mask = sil24_port_info[board_id].pio_mask; + probe_ent->udma_mask = sil24_port_info[board_id].udma_mask; + probe_ent->port_ops = sil24_port_info[board_id].port_ops; + probe_ent->n_ports = (board_id == BID_SIL3124) ? 4 : 2; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = port_base; + probe_ent->private_data = hpriv; + + memset(hpriv, 0, sizeof(*hpriv)); + hpriv->host_base = host_base; + hpriv->port_base = port_base; + + /* + * Configure the device + */ + /* + * FIXME: This device is certainly 64-bit capable. We just + * don't know how to use it. After fixing 32bit activation in + * this function, enable 64bit masks here. + */ + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + + /* GPIO off */ + writel(0, host_base + HOST_FLASH_CMD); + + /* Mask interrupts during initialization */ + writel(0, host_base + HOST_CTRL); + + for (i = 0; i < probe_ent->n_ports; i++) { + void *port = port_base + i * PORT_REGS_SIZE; + unsigned long portu = (unsigned long)port; + u32 tmp; + int cnt; + + probe_ent->port[i].cmd_addr = portu + PORT_TF; + probe_ent->port[i].ctl_addr = portu + PORT_TF + 0xa; + probe_ent->port[i].altstatus_addr = portu + PORT_TF + 0xa; + probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + + ata_std_ports(&probe_ent->port[i]); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* Clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + readl(port + PORT_CTRL_STAT); /* sync */ + for (cnt = 0; cnt < 10; cnt++) { + msleep(10); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_PORT_RST)) + break; + } + if (tmp & PORT_CS_PORT_RST) + printk(KERN_ERR DRV_NAME + "(%s): failed to clear port RST\n", + pci_name(pdev)); + } + + /* Zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* FIXME: 32bit activation? */ + writel(0, port + PORT_ACTIVATE_UPPER_ADDR); + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_STAT); + + /* Configure interrupts */ + writel(0xffff, port + PORT_IRQ_ENABLE_CLR); + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_SDB_FIS, + port + PORT_IRQ_ENABLE_SET); + + /* Clear interrupts */ + writel(0x0fff0fff, port + PORT_IRQ_STAT); + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + } + + /* Turn on interrupts */ + writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); + + pci_set_master(pdev); + + ata_device_add(probe_ent); + + kfree(probe_ent); + return 0; + + out_free: + if (host_base) + iounmap(host_base); + if (port_base) + iounmap(port_base); + kfree(probe_ent); + kfree(hpriv); + pci_release_regions(pdev); + out_disable: + pci_disable_device(pdev); + return rc; +} + +static int __init sil24_init(void) +{ + return pci_module_init(&sil24_pci_driver); +} + +static void __exit sil24_exit(void) +{ + pci_unregister_driver(&sil24_pci_driver); +} + +MODULE_AUTHOR("Tejun Heo"); +MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sil24_pci_tbl); + +module_init(sil24_init); +module_exit(sil24_exit); From 1483467faa0170cf401955b3d8d3486ea0fe802d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:08:42 +0900 Subject: [PATCH 0005/1939] [PATCH] sil24: add FIXME comment above ata_device_add 01_sil24_add-FIXME-comment.patch Add FIXME comment above ata_device_add. Signed-off-by: Tejun Heo sata_sil24.c | 1 + 1 files changed, 1 insertion(+) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 9958bc10a258..4868ad79b92e 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -749,6 +749,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); + /* FIXME: check ata_device_add return value */ ata_device_add(probe_ent); kfree(probe_ent); From 3cc4571c4106735665e048850ff6656de9558d60 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:08:47 +0900 Subject: [PATCH 0006/1939] [PATCH] sil24: remove irq disable code on spurious interrupt 02_sil24_remove-irq-disable-on-spurious-intr.patch If interrupt occurs on a disabled port, the driver used to mask the port's interrupt, but we don't know if such action is necessary yet and that's not what other drives do. So, just do nothing and tell IRQ subsystem that it's not our interrupt. Signed-off-by: Tejun Heo sata_sil24.c | 15 +++++---------- 1 files changed, 5 insertions(+), 10 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 4868ad79b92e..0f810cdd3cc2 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -535,17 +535,12 @@ 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_PORT_DISABLED)) { sil24_host_intr(host_set->ports[i]); - else { - u32 tmp; - printk(KERN_WARNING DRV_NAME - ": spurious interrupt from port %d\n", i); - tmp = readl(hpriv->host_base + HOST_CTRL); - tmp &= ~(1 << i); - writel(tmp, hpriv->host_base + HOST_CTRL); - } - handled++; + handled++; + } else + printk(KERN_ERR DRV_NAME + ": interrupt from disabled port %d\n", i); } spin_unlock(&host_set->lock); From 06460aeaa26ed4a86b92c8451365d3f48abd3786 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:08:52 +0900 Subject: [PATCH 0007/1939] [PATCH] sil24: add testing for PCI fault 03_sil24_add-pci-fault-check.patch On entry to interrupt handler, PORT_SLOT_STAT register is read first. Check if PCI fault or device removal has occurred by testing the value for 0xffffffff. Signed-off-by: Tejun Heo sata_sil24.c | 6 ++++++ 1 files changed, 6 insertions(+) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 0f810cdd3cc2..c9318bda46a3 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -527,6 +527,12 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs * status = readl(hpriv->host_base + HOST_IRQ_STAT); + if (status == 0xffffffff) { + printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); + goto out; + } + if (!(status & IRQ_STAT_4PORTS)) goto out; From 8746618d4f18fab25916686b0d8a6be2c2912de1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:08:57 +0900 Subject: [PATCH 0008/1939] [PATCH] sil24: move error handling out of hot interrupt path 04_sil24_add-error_intr-function.patch Move error handling from sil24_host_intr into separate function - sil24_error_intr. Signed-off-by: Tejun Heo sata_sil24.c | 55 +++++++++++++++++++++++++++++++------------------------ 1 files changed, 31 insertions(+), 24 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 55 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index c9318bda46a3..6544226c1b28 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -480,6 +480,35 @@ static void sil24_eng_timeout(struct ata_port *ap) sil24_reset_controller(ap); } +static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct sil24_port_priv *pp = ap->private_data; + void *port = pp->port; + u32 irq_stat, cmd_err, sstatus, serror; + + irq_stat = readl(port + PORT_IRQ_STAT); + cmd_err = readl(port + PORT_CMD_ERR); + sstatus = readl(port + PORT_SSTATUS); + serror = readl(port + PORT_SERROR); + + /* Clear IRQ/errors */ + writel(irq_stat, port + PORT_IRQ_STAT); + if (cmd_err) + writel(cmd_err, port + PORT_CMD_ERR); + if (serror) + writel(serror, port + PORT_SERROR); + + printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" + " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", + ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + + if (qc) + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); +} + static inline void sil24_host_intr(struct ata_port *ap) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); @@ -491,30 +520,8 @@ static inline void sil24_host_intr(struct ata_port *ap) if (!(slot_stat & HOST_SSTAT_ATTN)) { if (qc) ata_qc_complete(qc, 0); - } else { - u32 irq_stat, cmd_err, sstatus, serror; - - irq_stat = readl(port + PORT_IRQ_STAT); - cmd_err = readl(port + PORT_CMD_ERR); - sstatus = readl(port + PORT_SSTATUS); - serror = readl(port + PORT_SERROR); - - /* Clear IRQ/errors */ - writel(irq_stat, port + PORT_IRQ_STAT); - if (cmd_err) - writel(cmd_err, port + PORT_CMD_ERR); - if (serror) - writel(serror, port + PORT_SERROR); - - printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" - " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", - ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); - - if (qc) - ata_qc_complete(qc, ATA_ERR); - - sil24_reset_controller(ap); - } + } else + sil24_error_intr(ap, slot_stat); } static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) From 33d015b9f24d143859bb40dbe7bbb4c7805cee7d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:09:02 +0900 Subject: [PATCH 0009/1939] [PATCH] sil24: remove PORT_TF 05_sil24_remove-PORT_TF.patch Remove PORT_TF, as taskfile isn't located at PORT_TF. Signed-off-by: Tejun Heo sata_sil24.c | 7 +------ 1 files changed, 1 insertion(+), 6 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 6544226c1b28..47a7bfc4a6d8 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -104,9 +104,6 @@ enum { */ PORT_REGS_SIZE = 0x2000, PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */ - /* TF is overlayed w/ PRB regs in the preview driver, - * but it doesn't seem to work. */ - PORT_TF = 0x0000, PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ /* 32 bit regs */ @@ -703,9 +700,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u32 tmp; int cnt; - probe_ent->port[i].cmd_addr = portu + PORT_TF; - probe_ent->port[i].ctl_addr = portu + PORT_TF + 0xa; - probe_ent->port[i].altstatus_addr = portu + PORT_TF + 0xa; + probe_ent->port[i].cmd_addr = portu; probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; ata_std_ports(&probe_ent->port[i]); From 4f50c3cbb4b608ae4d8ee73ce273d819d901a83f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:09:07 +0900 Subject: [PATCH 0010/1939] [PATCH] sil24: replace pp->port w/ ap->ioaddr.cmd_addr 06_sil24_remove-pp-port.patch As ap->ioaddr.cmd_addr isn't used for PORT_TF anymore, replace pp->port w/ it as AHCI does. Signed-off-by: Tejun Heo sata_sil24.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 47a7bfc4a6d8..547c29a5613b 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -214,7 +214,6 @@ struct sil24_cmd_block { * here from the previous interrupt. */ struct sil24_port_priv { - void *port; struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ dma_addr_t cmd_block_dma; /* DMA base addr for them */ }; @@ -414,10 +413,11 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) static int sil24_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + void *port = (void *)ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); - writel((u32)paddr, pp->port + PORT_CMD_ACTIVATE); + writel((u32)paddr, port + PORT_CMD_ACTIVATE); return 0; } @@ -428,8 +428,7 @@ static void sil24_irq_clear(struct ata_port *ap) static void sil24_reset_controller(struct ata_port *ap) { - struct sil24_port_priv *pp = ap->private_data; - void *port = pp->port; + void *port = (void *)ap->ioaddr.cmd_addr; int cnt; u32 tmp; @@ -480,8 +479,7 @@ static void sil24_eng_timeout(struct ata_port *ap) static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - struct sil24_port_priv *pp = ap->private_data; - void *port = pp->port; + void *port = (void *)ap->ioaddr.cmd_addr; u32 irq_stat, cmd_err, sstatus, serror; irq_stat = readl(port + PORT_IRQ_STAT); @@ -509,8 +507,7 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) static inline void sil24_host_intr(struct ata_port *ap) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - struct sil24_port_priv *pp = ap->private_data; - void *port = pp->port; + void *port = (void *)ap->ioaddr.cmd_addr; u32 slot_stat; slot_stat = readl(port + PORT_SLOT_STAT); @@ -561,7 +558,6 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs * static int sil24_port_start(struct ata_port *ap) { struct device *dev = ap->host_set->dev; - struct sil24_host_priv *hpriv = ap->host_set->private_data; struct sil24_port_priv *pp; struct sil24_cmd_block *cb; size_t cb_size = sizeof(*cb); @@ -579,7 +575,6 @@ static int sil24_port_start(struct ata_port *ap) } memset(cb, 0, cb_size); - pp->port = hpriv->port_base + ap->port_no * PORT_REGS_SIZE; pp->cmd_block = cb; pp->cmd_block_dma = cb_dma; @@ -700,7 +695,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u32 tmp; int cnt; - probe_ent->port[i].cmd_addr = portu; + probe_ent->port[i].cmd_addr = portu + PORT_PRB; probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; ata_std_ports(&probe_ent->port[i]); From e382eb1dbdb2dec69806a72551bcb4a736142f6d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:09:13 +0900 Subject: [PATCH 0011/1939] [PATCH] sil24: fix PORT_CTRL_STAT constants 07_sil24_fix-PORT_CTRL_STAT-constants.patch PORT_CTRL_STAT constants were copied incorrectly from the preview driver. Signed-off-by: Edward Falk sata_sil24.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 547c29a5613b..7a3d50dcd938 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -140,10 +140,10 @@ enum { PORT_CS_DEV_RST = (1 << 1), /* device reset */ PORT_CS_INIT = (1 << 2), /* port initialize */ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ - PORT_CS_RESUME = (1 << 4), /* port resume */ - PORT_CS_32BIT_ACTV = (1 << 5), /* 32-bit activation */ - PORT_CS_PM_EN = (1 << 6), /* port multiplier enable */ - PORT_CS_RDY = (1 << 7), /* port ready to accept commands */ + PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ /* PORT_IRQ_STAT/ENABLE_SET/CLR */ /* bits[11:0] are masked */ From 83bbecc905b3431c60fe282830e09aaaab97b26a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 17 Aug 2005 13:09:18 +0900 Subject: [PATCH 0012/1939] [PATCH] sil24: add more comments for constants 08_sil24_add-comments-for-constants.patch Add more comments to constants. Signed-off-by: Edward Falk sata_sil24.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 7a3d50dcd938..cb91894471f2 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -107,14 +107,14 @@ enum { PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ /* 32 bit regs */ - PORT_CTRL_STAT = 0x1000, /* write:ctrl, read:stat */ - PORT_CTRL_CLR = 0x1004, - PORT_IRQ_STAT = 0x1008, - PORT_IRQ_ENABLE_SET = 0x1010, - PORT_IRQ_ENABLE_CLR = 0x1014, + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ PORT_ACTIVATE_UPPER_ADDR= 0x101c, - PORT_EXEC_FIFO = 0x1020, - PORT_CMD_ERR = 0x1024, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ PORT_FIS_CFG = 0x1028, PORT_FIFO_THRES = 0x102c, /* 16 bit regs */ @@ -187,7 +187,7 @@ enum { PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */ PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */ PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ - PORT_CERR_SENDSERVICE = 36, /* FIS received whiel sending service */ + PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */ /* * Other constants From 25732ad493b22b7d9f0d250c5a9ad17219f96a47 Mon Sep 17 00:00:00 2001 From: Bruce Losure Date: Fri, 2 Sep 2005 15:16:35 -0500 Subject: [PATCH 0013/1939] [IA64] Altix patch for fpga reset 1) workaround a h/w reset issue 2) to improve the determination of FPGA-based h/w in the arch/ia64/sn/kernel/tiocx code. Signed-off-by: Bruce Losure Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/tiocx.c | 58 +++++++++++++++++++----------------- include/asm-ia64/sn/l1.h | 12 ++++++++ include/asm-ia64/sn/sn_sal.h | 43 ++++++++++++++++++++++++++ include/asm-ia64/sn/tiocx.h | 3 +- 4 files changed, 88 insertions(+), 28 deletions(-) diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 254fe15c064b..d8664715764b 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -183,11 +183,12 @@ int cx_driver_unregister(struct cx_drv *cx_driver) * @part_num: device's part number * @mfg_num: device's manufacturer number * @hubdev: hub info associated with this device + * @bt: board type of the device * */ int cx_device_register(nasid_t nasid, int part_num, int mfg_num, - struct hubdev_info *hubdev) + struct hubdev_info *hubdev, int bt) { struct cx_dev *cx_dev; @@ -200,6 +201,7 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num, cx_dev->cx_id.mfg_num = mfg_num; cx_dev->cx_id.nasid = nasid; cx_dev->hubdev = hubdev; + cx_dev->bt = bt; cx_dev->dev.parent = NULL; cx_dev->dev.bus = &tiocx_bus_type; @@ -238,7 +240,8 @@ static int cx_device_reload(struct cx_dev *cx_dev) { cx_device_unregister(cx_dev); return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num, - cx_dev->cx_id.mfg_num, cx_dev->hubdev); + cx_dev->cx_id.mfg_num, cx_dev->hubdev, + cx_dev->bt); } static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget, @@ -365,26 +368,20 @@ static void tio_corelet_reset(nasid_t nasid, int corelet) udelay(2000); } -static int tiocx_btchar_get(int nasid) +static int is_fpga_tio(int nasid, int *bt) { - moduleid_t module_id; - geoid_t geoid; - int cnodeid; + int ioboard_type; - cnodeid = nasid_to_cnodeid(nasid); - geoid = cnodeid_get_geoid(cnodeid); - module_id = geo_module(geoid); - return MODULE_GET_BTCHAR(module_id); -} + ioboard_type = ia64_sn_sysctl_ioboard_get(nasid); -static int is_fpga_brick(int nasid) -{ - switch (tiocx_btchar_get(nasid)) { + switch (ioboard_type) { case L1_BRICKTYPE_SA: case L1_BRICKTYPE_ATHENA: - case L1_BRICKTYPE_DAYTONA: + case L1_BOARDTYPE_DAYTONA: + *bt = ioboard_type; return 1; } + return 0; } @@ -407,16 +404,22 @@ static int tiocx_reload(struct cx_dev *cx_dev) if (bitstream_loaded(nasid)) { uint64_t cx_id; + int rv; - cx_id = - *(volatile uint64_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) + + rv = ia64_sn_sysctl_tio_clock_reset(nasid); + if (rv) { + printk(KERN_ALERT "CX port JTAG reset failed.\n"); + } else { + cx_id = *(volatile uint64_t *) + (TIO_SWIN_BASE(nasid, TIOCX_CORELET) + WIDGET_ID); - part_num = XWIDGET_PART_NUM(cx_id); - mfg_num = XWIDGET_MFG_NUM(cx_id); - DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num); - /* just ignore it if it's a CE */ - if (part_num == TIO_CE_ASIC_PARTNUM) - return 0; + part_num = XWIDGET_PART_NUM(cx_id); + mfg_num = XWIDGET_MFG_NUM(cx_id); + DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num); + /* just ignore it if it's a CE */ + if (part_num == TIO_CE_ASIC_PARTNUM) + return 0; + } } cx_dev->cx_id.part_num = part_num; @@ -436,10 +439,10 @@ static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *a { struct cx_dev *cx_dev = to_cx_dev(dev); - return sprintf(buf, "0x%x 0x%x 0x%x %d\n", + return sprintf(buf, "0x%x 0x%x 0x%x 0x%x\n", cx_dev->cx_id.nasid, cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num, - tiocx_btchar_get(cx_dev->cx_id.nasid)); + cx_dev->bt); } static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf, @@ -488,11 +491,12 @@ static int __init tiocx_init(void) for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) { nasid_t nasid; + int bt; if ((nasid = cnodeid_to_nasid(cnodeid)) < 0) break; /* No more nasids .. bail out of loop */ - if ((nasid & 0x1) && is_fpga_brick(nasid)) { + if ((nasid & 0x1) && is_fpga_tio(nasid, &bt)) { struct hubdev_info *hubdev; struct xwidget_info *widgetp; @@ -512,7 +516,7 @@ static int __init tiocx_init(void) if (cx_device_register (nasid, widgetp->xwi_hwid.part_num, - widgetp->xwi_hwid.mfg_num, hubdev) < 0) + widgetp->xwi_hwid.mfg_num, hubdev, bt) < 0) return -ENXIO; else found_tiocx_device++; diff --git a/include/asm-ia64/sn/l1.h b/include/asm-ia64/sn/l1.h index 2e5f0aa38889..e3b819110d47 100644 --- a/include/asm-ia64/sn/l1.h +++ b/include/asm-ia64/sn/l1.h @@ -35,4 +35,16 @@ #define L1_BRICKTYPE_ATHENA 0x2b /* + */ #define L1_BRICKTYPE_DAYTONA 0x7a /* z */ +/* board type response codes */ +#define L1_BOARDTYPE_IP69 0x0100 /* CA */ +#define L1_BOARDTYPE_IP63 0x0200 /* CB */ +#define L1_BOARDTYPE_BASEIO 0x0300 /* IB */ +#define L1_BOARDTYPE_PCIE2SLOT 0x0400 /* IC */ +#define L1_BOARDTYPE_PCIX3SLOT 0x0500 /* ID */ +#define L1_BOARDTYPE_PCIXPCIE4SLOT 0x0600 /* IE */ +#define L1_BOARDTYPE_ABACUS 0x0700 /* AB */ +#define L1_BOARDTYPE_DAYTONA 0x0800 /* AD */ +#define L1_BOARDTYPE_INVAL (-1) /* invalid brick type */ + + #endif /* _ASM_IA64_SN_L1_H */ diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index e67825ad1930..6f96ae8b4fbe 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -47,6 +47,7 @@ #define SN_SAL_CONSOLE_PUTB 0x02000028 #define SN_SAL_CONSOLE_XMIT_CHARS 0x0200002a #define SN_SAL_CONSOLE_READC 0x0200002b +#define SN_SAL_SYSCTL_OP 0x02000030 #define SN_SAL_SYSCTL_MODID_GET 0x02000031 #define SN_SAL_SYSCTL_GET 0x02000032 #define SN_SAL_SYSCTL_IOBRICK_MODULE_GET 0x02000033 @@ -97,6 +98,13 @@ #define SAL_INTR_ALLOC 1 #define SAL_INTR_FREE 2 +/* + * operations available on the generic SN_SAL_SYSCTL_OP + * runtime service + */ +#define SAL_SYSCTL_OP_IOBOARD 0x0001 /* retrieve board type */ +#define SAL_SYSCTL_OP_TIO_JLCK_RST 0x0002 /* issue TIO clock reset */ + /* * IRouter (i.e. generalized system controller) operations */ @@ -876,6 +884,41 @@ ia64_sn_sysctl_event_init(nasid_t nasid) return (int) rv.v0; } +/* + * Ask the system controller on the specified nasid to reset + * the CX corelet clock. Only valid on TIO nodes. + */ +static inline int +ia64_sn_sysctl_tio_clock_reset(nasid_t nasid) +{ + struct ia64_sal_retval rv; + SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_TIO_JLCK_RST, + nasid, 0, 0, 0, 0, 0); + if (rv.status != 0) + return (int)rv.status; + if (rv.v0 != 0) + return (int)rv.v0; + + return 0; +} + +/* + * Get the associated ioboard type for a given nasid. + */ +static inline int +ia64_sn_sysctl_ioboard_get(nasid_t nasid) +{ + struct ia64_sal_retval rv; + SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_IOBOARD, + nasid, 0, 0, 0, 0, 0); + if (rv.v0 != 0) + return (int)rv.v0; + if (rv.v1 != 0) + return (int)rv.v1; + + return 0; +} + /** * ia64_sn_get_fit_compt - read a FIT entry from the PROM header * @nasid: NASID of node to read diff --git a/include/asm-ia64/sn/tiocx.h b/include/asm-ia64/sn/tiocx.h index c5447a504509..5699e75e5024 100644 --- a/include/asm-ia64/sn/tiocx.h +++ b/include/asm-ia64/sn/tiocx.h @@ -19,6 +19,7 @@ struct cx_id_s { struct cx_dev { struct cx_id_s cx_id; + int bt; /* board/blade type */ void *soft; /* driver specific */ struct hubdev_info *hubdev; struct device dev; @@ -59,7 +60,7 @@ struct cx_drv { extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int); extern void tiocx_irq_free(struct sn_irq_info *); extern int cx_device_unregister(struct cx_dev *); -extern int cx_device_register(nasid_t, int, int, struct hubdev_info *); +extern int cx_device_register(nasid_t, int, int, struct hubdev_info *, int); extern int cx_driver_unregister(struct cx_drv *); extern int cx_driver_register(struct cx_drv *); extern uint64_t tiocx_dma_addr(uint64_t addr); From a607c38971fd078865fa9bef39e6c1d4435680c8 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Thu, 1 Sep 2005 14:01:37 -0500 Subject: [PATCH 0014/1939] [IA64-SGI] get XPC to cleanly disengage from remote memory references When XPC is being shutdown (i.e., rmmod, reboot) it doesn't ensure that other partitions with whom it was connected have completely disengaged from any attempt at cross-partition memory references. This can lead to MCAs in any of these other partitions when the partition is reset. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/xpc.h | 288 +++++++++++++++++++++++-- arch/ia64/sn/kernel/xpc_channel.c | 222 +++++++++++--------- arch/ia64/sn/kernel/xpc_main.c | 242 +++++++++++++++------ arch/ia64/sn/kernel/xpc_partition.c | 314 +++++++++++++++++++++++----- include/asm-ia64/sn/xp.h | 10 +- 5 files changed, 830 insertions(+), 246 deletions(-) diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h index d0ee635daf2e..565822ab3d08 100644 --- a/arch/ia64/sn/kernel/xpc.h +++ b/arch/ia64/sn/kernel/xpc.h @@ -57,7 +57,7 @@ #define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2) #define XPC_HB_DEFAULT_INTERVAL 5 /* incr HB every x secs */ -#define XPC_HB_CHECK_DEFAULT_TIMEOUT 20 /* check HB every x secs */ +#define XPC_HB_CHECK_DEFAULT_INTERVAL 20 /* check HB every x secs */ /* define the process name of HB checker and the CPU it is pinned to */ #define XPC_HB_CHECK_THREAD_NAME "xpc_hb" @@ -67,11 +67,6 @@ #define XPC_DISCOVERY_THREAD_NAME "xpc_discovery" -#define XPC_HB_ALLOWED(_p, _v) ((_v)->heartbeating_to_mask & (1UL << (_p))) -#define XPC_ALLOW_HB(_p, _v) (_v)->heartbeating_to_mask |= (1UL << (_p)) -#define XPC_DISALLOW_HB(_p, _v) (_v)->heartbeating_to_mask &= (~(1UL << (_p))) - - /* * Reserved Page provided by SAL. * @@ -88,14 +83,38 @@ struct xpc_rsvd_page { u8 version; u8 pad[6]; /* pad to u64 align */ volatile u64 vars_pa; + struct timespec stamp; /* time when reserved page was initialized */ u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; }; -#define XPC_RP_VERSION _XPC_VERSION(1,0) /* version 1.0 of the reserved page */ #define XPC_RSVD_PAGE_ALIGNED_SIZE \ (L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))) +#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ + +#define XPC_SUPPORTS_RP_STAMP(_version) \ + (_version >= _XPC_VERSION(1,1)) + +/* + * compare stamps - the return value is: + * + * < 0, if stamp1 < stamp2 + * = 0, if stamp1 == stamp2 + * > 0, if stamp1 > stamp2 + */ +static inline int +xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) +{ + int ret; + + + if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) { + ret = stamp1->tv_nsec - stamp2->tv_nsec; + } + return ret; +} + /* * Define the structures by which XPC variables can be exported to other @@ -121,12 +140,61 @@ struct xpc_vars { u64 vars_part_pa; u64 amos_page_pa; /* paddr of page of AMOs from MSPEC driver */ AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ - AMO_t *act_amos; /* pointer to the first activation AMO */ }; -#define XPC_V_VERSION _XPC_VERSION(3,0) /* version 3.0 of the cross vars */ #define XPC_VARS_ALIGNED_SIZE (L1_CACHE_ALIGN(sizeof(struct xpc_vars))) +#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ + +#define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ + (_version >= _XPC_VERSION(3,1)) + + +static inline int +xpc_hb_allowed(partid_t partid, struct xpc_vars *vars) +{ + return ((vars->heartbeating_to_mask & (1UL << partid)) != 0); +} + +static inline void +xpc_allow_hb(partid_t partid, struct xpc_vars *vars) +{ + u64 old_mask, new_mask; + + do { + old_mask = vars->heartbeating_to_mask; + new_mask = (old_mask | (1UL << partid)); + } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != + old_mask); +} + +static inline void +xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) +{ + u64 old_mask, new_mask; + + do { + old_mask = vars->heartbeating_to_mask; + new_mask = (old_mask & ~(1UL << partid)); + } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != + old_mask); +} + + +/* + * The AMOs page consists of a number of AMO variables which are divided into + * four groups, The first two groups are used to identify an IRQ's sender. + * These two groups consist of 64 and 16 AMO variables respectively. The last + * two groups, consisting of just one AMO variable each, are used to identify + * the remote partitions that are currently engaged (from the viewpoint of + * the XPC running on the remote partition). + */ +#define XPC_NOTIFY_IRQ_AMOS 0 +#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS) +#define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) +#define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) + + /* * The following structure describes the per partition specific variables. * @@ -358,7 +426,7 @@ struct xpc_channel { void *key; /* pointer to user's key */ struct semaphore msg_to_pull_sema; /* next msg to pull serialization */ - struct semaphore teardown_sema; /* wait for teardown completion */ + struct semaphore wdisconnect_sema; /* wait for channel disconnect */ struct xpc_openclose_args *local_openclose_args; /* args passed on */ /* opening or closing of channel */ @@ -410,6 +478,7 @@ struct xpc_channel { #define XPC_C_DISCONNECTED 0x00002000 /* channel is disconnected */ #define XPC_C_DISCONNECTING 0x00004000 /* channel is being disconnected */ +#define XPC_C_WDISCONNECT 0x00008000 /* waiting for channel disconnect */ @@ -422,6 +491,8 @@ struct xpc_partition { /* XPC HB infrastructure */ + u8 remote_rp_version; /* version# of partition's rsvd pg */ + struct timespec remote_rp_stamp;/* time when rsvd pg was initialized */ u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ u64 remote_vars_pa; /* phys addr of partition's vars */ u64 remote_vars_part_pa; /* phys addr of partition's vars part */ @@ -432,10 +503,14 @@ struct xpc_partition { u32 act_IRQ_rcvd; /* IRQs since activation */ spinlock_t act_lock; /* protect updating of act_state */ u8 act_state; /* from XPC HB viewpoint */ + u8 remote_vars_version; /* version# of partition's vars */ enum xpc_retval reason; /* reason partition is deactivating */ int reason_line; /* line# deactivation initiated from */ int reactivate_nasid; /* nasid in partition to reactivate */ + unsigned long disengage_request_timeout; /* timeout in XPC_TICKS */ + struct timer_list disengage_request_timer; + /* XPC infrastructure referencing and teardown control */ @@ -454,6 +529,7 @@ struct xpc_partition { u8 nchannels; /* #of defined channels supported */ atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ + atomic_t nchannels_engaged;/* #of channels engaged with remote part */ struct xpc_channel *channels;/* array of channel structures */ void *local_GPs_base; /* base address of kmalloc'd space */ @@ -518,6 +594,7 @@ struct xpc_partition { #define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */ + /* * struct xpc_partition IPI_timer #of seconds to wait before checking for * dropped IPIs. These occur whenever an IPI amo write doesn't complete until @@ -526,6 +603,13 @@ struct xpc_partition { #define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ) +/* number of seconds to wait for other partitions to disengage */ +#define XPC_DISENGAGE_REQUEST_TIMELIMIT 90 + +/* interval in seconds to print 'waiting disengagement' messages */ +#define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 + + #define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0])) @@ -550,8 +634,6 @@ extern void xpc_activate_partition(struct xpc_partition *); /* found in xpc_partition.c */ extern int xpc_exiting; -extern int xpc_hb_interval; -extern int xpc_hb_check_interval; extern struct xpc_vars *xpc_vars; extern struct xpc_rsvd_page *xpc_rsvd_page; extern struct xpc_vars_part *xpc_vars_part; @@ -561,6 +643,7 @@ extern struct xpc_rsvd_page *xpc_rsvd_page_init(void); extern void xpc_allow_IPI_ops(void); extern void xpc_restrict_IPI_ops(void); extern int xpc_identify_act_IRQ_sender(void); +extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *); extern void xpc_mark_partition_inactive(struct xpc_partition *); extern void xpc_discovery(void); @@ -585,8 +668,8 @@ extern void xpc_connected_callout(struct xpc_channel *); extern void xpc_deliver_msg(struct xpc_channel *); extern void xpc_disconnect_channel(const int, struct xpc_channel *, enum xpc_retval, unsigned long *); -extern void xpc_disconnected_callout(struct xpc_channel *); -extern void xpc_partition_down(struct xpc_partition *, enum xpc_retval); +extern void xpc_disconnecting_callout(struct xpc_channel *); +extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval); extern void xpc_teardown_infrastructure(struct xpc_partition *); @@ -673,6 +756,157 @@ xpc_part_ref(struct xpc_partition *part) +/* + * This next set of inlines are used to keep track of when a partition is + * potentially engaged in accessing memory belonging to another partition. + */ + +static inline void +xpc_mark_partition_engaged(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_mark_partition_disengaged(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_request_partition_disengage(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_cancel_partition_disengage_request(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline u64 +xpc_partition_engaged(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static inline u64 +xpc_partition_disengage_requested(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static inline void +xpc_clear_partition_engaged(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~partid_mask); +} + +static inline void +xpc_clear_partition_disengage_request(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~partid_mask); +} + + + /* * The following set of macros and inlines are used for the sending and * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, @@ -722,13 +956,13 @@ xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) * Flag the appropriate AMO variable and send an IPI to the specified node. */ static inline void -xpc_activate_IRQ_send(u64 amos_page, int from_nasid, int to_nasid, +xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid, int to_phys_cpuid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); - AMO_t *amos = (AMO_t *) __va(amos_page + - (XP_MAX_PARTITIONS * sizeof(AMO_t))); + AMO_t *amos = (AMO_t *) __va(amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); (void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, @@ -756,6 +990,13 @@ xpc_IPI_send_reactivate(struct xpc_partition *part) xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); } +static inline void +xpc_IPI_send_disengage(struct xpc_partition *part) +{ + xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), + part->remote_act_nasid, part->remote_act_phys_cpuid); +} + /* * IPIs associated with SGI_XPC_NOTIFY IRQ. @@ -903,17 +1144,18 @@ xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) * cacheable mapping for the entire region. This will prevent speculative * reading of cached copies of our lines from being issued which will cause * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * (XP_MAX_PARTITIONS) AMO variables for message notification (xpc_main.c) - * and an additional 16 AMO variables for partition activation (xpc_hb.c). + * (XP_MAX_PARTITIONS) AMO variables for message notification and an + * additional 16 (XP_NASID_MASK_WORDS) AMO variables for partition activation + * and 2 AMO variables for partition deactivation. */ static inline AMO_t * -xpc_IPI_init(partid_t partid) +xpc_IPI_init(int index) { - AMO_t *part_amo = xpc_vars->amos_page + partid; + AMO_t *amo = xpc_vars->amos_page + index; - xpc_IPI_receive(part_amo); - return part_amo; + (void) xpc_IPI_receive(amo); /* clear AMO variable */ + return amo; } diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index 94698bea7be0..195ac1b8e262 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c @@ -57,6 +57,7 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid) spin_lock_init(&ch->lock); sema_init(&ch->msg_to_pull_sema, 1); /* mutex */ + sema_init(&ch->wdisconnect_sema, 0); /* event wait */ atomic_set(&ch->n_on_msg_allocate_wq, 0); init_waitqueue_head(&ch->msg_allocate_wq); @@ -166,6 +167,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) xpc_initialize_channels(part, partid); atomic_set(&part->nchannels_active, 0); + atomic_set(&part->nchannels_engaged, 0); /* local_IPI_amo were set to 0 by an earlier memset() */ @@ -555,8 +557,6 @@ xpc_allocate_msgqueues(struct xpc_channel *ch) sema_init(&ch->notify_queue[i].sema, 0); } - sema_init(&ch->teardown_sema, 0); /* event wait */ - spin_lock_irqsave(&ch->lock, irq_flags); ch->flags |= XPC_C_SETUP; spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -625,6 +625,55 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) } +/* + * Notify those who wanted to be notified upon delivery of their message. + */ +static void +xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) +{ + struct xpc_notify *notify; + u8 notify_type; + s64 get = ch->w_remote_GP.get - 1; + + + while (++get < put && atomic_read(&ch->n_to_notify) > 0) { + + notify = &ch->notify_queue[get % ch->local_nentries]; + + /* + * See if the notify entry indicates it was associated with + * a message who's sender wants to be notified. It is possible + * that it is, but someone else is doing or has done the + * notification. + */ + notify_type = notify->type; + if (notify_type == 0 || + cmpxchg(¬ify->type, notify_type, 0) != + notify_type) { + continue; + } + + DBUG_ON(notify_type != XPC_N_CALL); + + atomic_dec(&ch->n_to_notify); + + if (notify->func != NULL) { + dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " + "msg_number=%ld, partid=%d, channel=%d\n", + (void *) notify, get, ch->partid, ch->number); + + notify->func(reason, ch->partid, ch->number, + notify->key); + + dev_dbg(xpc_chan, "notify->func() returned, " + "notify=0x%p, msg_number=%ld, partid=%d, " + "channel=%d\n", (void *) notify, get, + ch->partid, ch->number); + } + } +} + + /* * Free up message queues and other stuff that were allocated for the specified * channel. @@ -669,9 +718,6 @@ xpc_free_msgqueues(struct xpc_channel *ch) ch->remote_msgqueue = NULL; kfree(ch->notify_queue); ch->notify_queue = NULL; - - /* in case someone is waiting for the teardown to complete */ - up(&ch->teardown_sema); } } @@ -683,7 +729,7 @@ static void xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_partition *part = &xpc_partitions[ch->partid]; - u32 ch_flags = ch->flags; + u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED); DBUG_ON(!spin_is_locked(&ch->lock)); @@ -701,12 +747,13 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) } DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0); - /* it's now safe to free the channel's message queues */ + if (part->act_state == XPC_P_DEACTIVATING) { + /* can't proceed until the other side disengages from us */ + if (xpc_partition_engaged(1UL << ch->partid)) { + return; + } - xpc_free_msgqueues(ch); - DBUG_ON(ch->flags & XPC_C_SETUP); - - if (part->act_state != XPC_P_DEACTIVATING) { + } else { /* as long as the other side is up do the full protocol */ @@ -724,16 +771,33 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) } } + /* wake those waiting for notify completion */ + if (atomic_read(&ch->n_to_notify) > 0) { + /* >>> we do callout while holding ch->lock */ + xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put); + } + /* both sides are disconnected now */ - ch->flags = XPC_C_DISCONNECTED; /* clear all flags, but this one */ + /* it's now safe to free the channel's message queues */ + xpc_free_msgqueues(ch); + + /* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */ + ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); atomic_dec(&part->nchannels_active); - if (ch_flags & XPC_C_WASCONNECTED) { + if (channel_was_connected) { dev_info(xpc_chan, "channel %d to partition %d disconnected, " "reason=%d\n", ch->number, ch->partid, ch->reason); } + + /* wake the thread that is waiting for this channel to disconnect */ + if (ch->flags & XPC_C_WDISCONNECT) { + spin_unlock_irqrestore(&ch->lock, *irq_flags); + up(&ch->wdisconnect_sema); + spin_lock_irqsave(&ch->lock, *irq_flags); + } } @@ -764,7 +828,7 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, /* * If RCLOSEREQUEST is set, we're probably waiting for * RCLOSEREPLY. We should find it and a ROPENREQUEST packed - * with this RCLOSEQREUQEST in the IPI_flags. + * with this RCLOSEREQUEST in the IPI_flags. */ if (ch->flags & XPC_C_RCLOSEREQUEST) { @@ -852,7 +916,7 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, "channel=%d\n", args->msg_size, args->local_nentries, ch->partid, ch->number); - if ((ch->flags & XPC_C_DISCONNECTING) || + if ((ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) || part->act_state == XPC_P_DEACTIVATING) { spin_unlock_irqrestore(&ch->lock, irq_flags); return; @@ -1039,55 +1103,6 @@ xpc_connect_channel(struct xpc_channel *ch) } -/* - * Notify those who wanted to be notified upon delivery of their message. - */ -static void -xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) -{ - struct xpc_notify *notify; - u8 notify_type; - s64 get = ch->w_remote_GP.get - 1; - - - while (++get < put && atomic_read(&ch->n_to_notify) > 0) { - - notify = &ch->notify_queue[get % ch->local_nentries]; - - /* - * See if the notify entry indicates it was associated with - * a message who's sender wants to be notified. It is possible - * that it is, but someone else is doing or has done the - * notification. - */ - notify_type = notify->type; - if (notify_type == 0 || - cmpxchg(¬ify->type, notify_type, 0) != - notify_type) { - continue; - } - - DBUG_ON(notify_type != XPC_N_CALL); - - atomic_dec(&ch->n_to_notify); - - if (notify->func != NULL) { - dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", - (void *) notify, get, ch->partid, ch->number); - - notify->func(reason, ch->partid, ch->number, - notify->key); - - dev_dbg(xpc_chan, "notify->func() returned, " - "notify=0x%p, msg_number=%ld, partid=%d, " - "channel=%d\n", (void *) notify, get, - ch->partid, ch->number); - } - } -} - - /* * Clear some of the msg flags in the local message queue. */ @@ -1240,6 +1255,7 @@ xpc_process_channel_activity(struct xpc_partition *part) u64 IPI_amo, IPI_flags; struct xpc_channel *ch; int ch_number; + u32 ch_flags; IPI_amo = xpc_get_IPI_flags(part); @@ -1266,8 +1282,9 @@ xpc_process_channel_activity(struct xpc_partition *part) xpc_process_openclose_IPI(part, ch_number, IPI_flags); } + ch_flags = ch->flags; /* need an atomic snapshot of flags */ - if (ch->flags & XPC_C_DISCONNECTING) { + if (ch_flags & XPC_C_DISCONNECTING) { spin_lock_irqsave(&ch->lock, irq_flags); xpc_process_disconnect(ch, &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -1278,9 +1295,9 @@ xpc_process_channel_activity(struct xpc_partition *part) continue; } - if (!(ch->flags & XPC_C_CONNECTED)) { - if (!(ch->flags & XPC_C_OPENREQUEST)) { - DBUG_ON(ch->flags & XPC_C_SETUP); + if (!(ch_flags & XPC_C_CONNECTED)) { + if (!(ch_flags & XPC_C_OPENREQUEST)) { + DBUG_ON(ch_flags & XPC_C_SETUP); (void) xpc_connect_channel(ch); } else { spin_lock_irqsave(&ch->lock, irq_flags); @@ -1305,8 +1322,8 @@ xpc_process_channel_activity(struct xpc_partition *part) /* - * XPC's heartbeat code calls this function to inform XPC that a partition has - * gone down. XPC responds by tearing down the XPartition Communication + * XPC's heartbeat code calls this function to inform XPC that a partition is + * going down. XPC responds by tearing down the XPartition Communication * infrastructure used for the just downed partition. * * XPC's heartbeat code will never call this function and xpc_partition_up() @@ -1314,7 +1331,7 @@ xpc_process_channel_activity(struct xpc_partition *part) * at the same time. */ void -xpc_partition_down(struct xpc_partition *part, enum xpc_retval reason) +xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) { unsigned long irq_flags; int ch_number; @@ -1330,12 +1347,11 @@ xpc_partition_down(struct xpc_partition *part, enum xpc_retval reason) } - /* disconnect all channels associated with the downed partition */ + /* disconnect channels associated with the partition going down */ for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; - xpc_msgqueue_ref(ch); spin_lock_irqsave(&ch->lock, irq_flags); @@ -1370,6 +1386,7 @@ xpc_teardown_infrastructure(struct xpc_partition *part) * this partition. */ + DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); DBUG_ON(atomic_read(&part->nchannels_active) != 0); DBUG_ON(part->setup_state != XPC_P_SETUP); part->setup_state = XPC_P_WTEARDOWN; @@ -1506,8 +1523,12 @@ xpc_initiate_disconnect(int ch_number) spin_lock_irqsave(&ch->lock, irq_flags); - XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, + if (!(ch->flags & XPC_C_DISCONNECTED)) { + ch->flags |= XPC_C_WDISCONNECT; + + XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, &irq_flags); + } spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -1523,8 +1544,9 @@ xpc_initiate_disconnect(int ch_number) /* * To disconnect a channel, and reflect it back to all who may be waiting. * - * >>> An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by - * >>> xpc_free_msgqueues(). + * An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by + * xpc_process_disconnect(), and if set, XPC_C_WDISCONNECT is cleared by + * xpc_disconnect_wait(). * * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN. */ @@ -1532,7 +1554,7 @@ void xpc_disconnect_channel(const int line, struct xpc_channel *ch, enum xpc_retval reason, unsigned long *irq_flags) { - u32 flags; + u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED); DBUG_ON(!spin_is_locked(&ch->lock)); @@ -1547,37 +1569,28 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, XPC_SET_REASON(ch, reason, line); - flags = ch->flags; + ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); /* some of these may not have been set */ ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY | XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | XPC_C_CONNECTING | XPC_C_CONNECTED); - ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); xpc_IPI_send_closerequest(ch, irq_flags); - if (flags & XPC_C_CONNECTED) { + if (channel_was_connected) { ch->flags |= XPC_C_WASCONNECTED; } - if (atomic_read(&ch->kthreads_idle) > 0) { - /* wake all idle kthreads so they can exit */ - wake_up_all(&ch->idle_wq); - } - spin_unlock_irqrestore(&ch->lock, *irq_flags); - - /* wake those waiting to allocate an entry from the local msg queue */ - - if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { - wake_up(&ch->msg_allocate_wq); + /* wake all idle kthreads so they can exit */ + if (atomic_read(&ch->kthreads_idle) > 0) { + wake_up_all(&ch->idle_wq); } - /* wake those waiting for notify completion */ - - if (atomic_read(&ch->n_to_notify) > 0) { - xpc_notify_senders(ch, reason, ch->w_local_GP.put); + /* wake those waiting to allocate an entry from the local msg queue */ + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { + wake_up(&ch->msg_allocate_wq); } spin_lock_irqsave(&ch->lock, *irq_flags); @@ -1585,23 +1598,24 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, void -xpc_disconnected_callout(struct xpc_channel *ch) +xpc_disconnecting_callout(struct xpc_channel *ch) { /* - * Let the channel's registerer know that the channel is now + * Let the channel's registerer know that the channel is being * disconnected. We don't want to do this if the registerer was never - * informed of a connection being made, unless the disconnect was for - * abnormal reasons. + * informed of a connection being made. */ if (ch->func != NULL) { - dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, " - "channel=%d\n", ch->reason, ch->partid, ch->number); + dev_dbg(xpc_chan, "ch->func() called, reason=xpcDisconnecting," + " partid=%d, channel=%d\n", ch->partid, ch->number); - ch->func(ch->reason, ch->partid, ch->number, NULL, ch->key); + ch->func(xpcDisconnecting, ch->partid, ch->number, NULL, + ch->key); - dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, " - "channel=%d\n", ch->reason, ch->partid, ch->number); + dev_dbg(xpc_chan, "ch->func() returned, reason=" + "xpcDisconnecting, partid=%d, channel=%d\n", + ch->partid, ch->number); } } @@ -1848,7 +1862,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, xpc_notify_func func, void *key) { enum xpc_retval ret = xpcSuccess; - struct xpc_notify *notify = NULL; // >>> to keep the compiler happy!! + struct xpc_notify *notify = notify; s64 put, msg_number = msg->number; diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index bb1d5cf30440..feece200b3c3 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -82,11 +83,13 @@ struct device *xpc_chan = &xpc_chan_dbg_subname; /* systune related variables for /proc/sys directories */ -static int xpc_hb_min = 1; -static int xpc_hb_max = 10; +static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; +static int xpc_hb_min_interval = 1; +static int xpc_hb_max_interval = 10; -static int xpc_hb_check_min = 10; -static int xpc_hb_check_max = 120; +static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL; +static int xpc_hb_check_min_interval = 10; +static int xpc_hb_check_max_interval = 120; static ctl_table xpc_sys_xpc_hb_dir[] = { { @@ -99,7 +102,8 @@ static ctl_table xpc_sys_xpc_hb_dir[] = { &proc_dointvec_minmax, &sysctl_intvec, NULL, - &xpc_hb_min, &xpc_hb_max + &xpc_hb_min_interval, + &xpc_hb_max_interval }, { 2, @@ -111,7 +115,8 @@ static ctl_table xpc_sys_xpc_hb_dir[] = { &proc_dointvec_minmax, &sysctl_intvec, NULL, - &xpc_hb_check_min, &xpc_hb_check_max + &xpc_hb_check_min_interval, + &xpc_hb_check_max_interval }, {0} }; @@ -148,11 +153,11 @@ static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); static unsigned long xpc_hb_check_timeout; -/* xpc_hb_checker thread exited notification */ -static DECLARE_MUTEX_LOCKED(xpc_hb_checker_exited); +/* used as an indication of when the xpc_hb_checker thread is inactive */ +static DECLARE_MUTEX_LOCKED(xpc_hb_checker_inactive); -/* xpc_discovery thread exited notification */ -static DECLARE_MUTEX_LOCKED(xpc_discovery_exited); +/* used as an indication of when the xpc_discovery thread is inactive */ +static DECLARE_MUTEX_LOCKED(xpc_discovery_inactive); static struct timer_list xpc_hb_timer; @@ -161,6 +166,30 @@ static struct timer_list xpc_hb_timer; static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); +static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); +static struct notifier_block xpc_reboot_notifier = { + .notifier_call = xpc_system_reboot, +}; + + +/* + * Timer function to enforce the timelimit on the partition disengage request. + */ +static void +xpc_timeout_partition_disengage_request(unsigned long data) +{ + struct xpc_partition *part = (struct xpc_partition *) data; + + + DBUG_ON(XPC_TICKS < part->disengage_request_timeout); + + (void) xpc_partition_disengaged(part); + + DBUG_ON(part->disengage_request_timeout != 0); + DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); +} + + /* * Notify the heartbeat check thread that an IRQ has been received. */ @@ -214,12 +243,6 @@ xpc_hb_checker(void *ignore) while (!(volatile int) xpc_exiting) { - /* wait for IRQ or timeout */ - (void) wait_event_interruptible(xpc_act_IRQ_wq, - (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) || - jiffies >= xpc_hb_check_timeout || - (volatile int) xpc_exiting)); - dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " "been received\n", (int) (xpc_hb_check_timeout - jiffies), @@ -240,6 +263,7 @@ xpc_hb_checker(void *ignore) } + /* check for outstanding IRQs */ new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { force_IRQ = 0; @@ -257,13 +281,19 @@ xpc_hb_checker(void *ignore) xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); } + + /* wait for IRQ or timeout */ + (void) wait_event_interruptible(xpc_act_IRQ_wq, + (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) || + jiffies >= xpc_hb_check_timeout || + (volatile int) xpc_exiting)); } dev_dbg(xpc_part, "heartbeat checker is exiting\n"); /* mark this thread as inactive */ - up(&xpc_hb_checker_exited); + up(&xpc_hb_checker_inactive); return 0; } @@ -283,7 +313,7 @@ xpc_initiate_discovery(void *ignore) dev_dbg(xpc_part, "discovery thread is exiting\n"); /* mark this thread as inactive */ - up(&xpc_discovery_exited); + up(&xpc_discovery_inactive); return 0; } @@ -309,7 +339,7 @@ xpc_make_first_contact(struct xpc_partition *part) "partition %d\n", XPC_PARTID(part)); /* wait a 1/4 of a second or so */ - msleep_interruptible(250); + (void) msleep_interruptible(250); if (part->act_state == XPC_P_DEACTIVATING) { return part->reason; @@ -336,7 +366,8 @@ static void xpc_channel_mgr(struct xpc_partition *part) { while (part->act_state != XPC_P_DEACTIVATING || - atomic_read(&part->nchannels_active) > 0) { + atomic_read(&part->nchannels_active) > 0 || + !xpc_partition_disengaged(part)) { xpc_process_channel_activity(part); @@ -360,7 +391,8 @@ xpc_channel_mgr(struct xpc_partition *part) (volatile u64) part->local_IPI_amo != 0 || ((volatile u8) part->act_state == XPC_P_DEACTIVATING && - atomic_read(&part->nchannels_active) == 0))); + atomic_read(&part->nchannels_active) == 0 && + xpc_partition_disengaged(part)))); atomic_set(&part->channel_mgr_requests, 1); // >>> Does it need to wakeup periodically as well? In case we @@ -482,7 +514,7 @@ xpc_activating(void *__partid) return 0; } - XPC_ALLOW_HB(partid, xpc_vars); + xpc_allow_hb(partid, xpc_vars); xpc_IPI_send_activated(part); @@ -492,6 +524,7 @@ xpc_activating(void *__partid) */ (void) xpc_partition_up(part); + xpc_disallow_hb(partid, xpc_vars); xpc_mark_partition_inactive(part); if (part->reason == xpcReactivating) { @@ -704,11 +737,14 @@ xpc_daemonize_kthread(void *args) xpc_kthread_waitmsgs(part, ch); } - if (atomic_dec_return(&ch->kthreads_assigned) == 0 && - ((ch->flags & XPC_C_CONNECTCALLOUT) || - (ch->reason != xpcUnregistering && - ch->reason != xpcOtherUnregistering))) { - xpc_disconnected_callout(ch); + if (atomic_dec_return(&ch->kthreads_assigned) == 0) { + if (ch->flags & XPC_C_CONNECTCALLOUT) { + xpc_disconnecting_callout(ch); + } + if (atomic_dec_return(&part->nchannels_engaged) == 0) { + xpc_mark_partition_disengaged(part); + xpc_IPI_send_disengage(part); + } } @@ -740,6 +776,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) unsigned long irq_flags; pid_t pid; u64 args = XPC_PACK_ARGS(ch->partid, ch->number); + struct xpc_partition *part = &xpc_partitions[ch->partid]; while (needed-- > 0) { @@ -770,9 +807,13 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) * kthread. That kthread is responsible for doing the * counterpart to the following before it exits. */ - (void) xpc_part_ref(&xpc_partitions[ch->partid]); + (void) xpc_part_ref(part); xpc_msgqueue_ref(ch); - atomic_inc(&ch->kthreads_assigned); + if (atomic_inc_return(&ch->kthreads_assigned) == 1) { + if (atomic_inc_return(&part->nchannels_engaged) == 1) { + xpc_mark_partition_engaged(part); + } + } ch->kthreads_created++; // >>> temporary debug only!!! } } @@ -781,6 +822,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) void xpc_disconnect_wait(int ch_number) { + unsigned long irq_flags; partid_t partid; struct xpc_partition *part; struct xpc_channel *ch; @@ -793,10 +835,13 @@ xpc_disconnect_wait(int ch_number) if (xpc_part_ref(part)) { ch = &part->channels[ch_number]; -// >>> how do we keep from falling into the window between our check and going -// >>> down and coming back up where sema is re-inited? - if (ch->flags & XPC_C_SETUP) { - (void) down(&ch->teardown_sema); + if (ch->flags & XPC_C_WDISCONNECT) { + if (!(ch->flags & XPC_C_DISCONNECTED)) { + (void) down(&ch->wdisconnect_sema); + } + spin_lock_irqsave(&ch->lock, irq_flags); + ch->flags &= ~XPC_C_WDISCONNECT; + spin_unlock_irqrestore(&ch->lock, irq_flags); } xpc_part_deref(part); @@ -806,62 +851,89 @@ xpc_disconnect_wait(int ch_number) static void -xpc_do_exit(void) +xpc_do_exit(enum xpc_retval reason) { partid_t partid; int active_part_count; struct xpc_partition *part; + unsigned long printmsg_time; - /* now it's time to eliminate our heartbeat */ - del_timer_sync(&xpc_hb_timer); - xpc_vars->heartbeating_to_mask = 0; - - /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->vars_pa = 0; + /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ + DBUG_ON(xpc_exiting == 1); /* - * Ignore all incoming interrupts. Without interupts the heartbeat - * checker won't activate any new partitions that may come up. - */ - free_irq(SGI_XPC_ACTIVATE, NULL); - - /* - * Cause the heartbeat checker and the discovery threads to exit. - * We don't want them attempting to activate new partitions as we - * try to deactivate the existing ones. + * Let the heartbeat checker thread and the discovery thread + * (if one is running) know that they should exit. Also wake up + * the heartbeat checker thread in case it's sleeping. */ xpc_exiting = 1; wake_up_interruptible(&xpc_act_IRQ_wq); - /* wait for the heartbeat checker thread to mark itself inactive */ - down(&xpc_hb_checker_exited); + /* ignore all incoming interrupts */ + free_irq(SGI_XPC_ACTIVATE, NULL); /* wait for the discovery thread to mark itself inactive */ - down(&xpc_discovery_exited); + down(&xpc_discovery_inactive); + + /* wait for the heartbeat checker thread to mark itself inactive */ + down(&xpc_hb_checker_inactive); - msleep_interruptible(300); + /* sleep for a 1/3 of a second or so */ + (void) msleep_interruptible(300); /* wait for all partitions to become inactive */ + printmsg_time = jiffies; + do { active_part_count = 0; for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - if (part->act_state != XPC_P_INACTIVE) { - active_part_count++; - - XPC_DEACTIVATE_PARTITION(part, xpcUnloading); + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { + continue; } + + active_part_count++; + + XPC_DEACTIVATE_PARTITION(part, reason); } - if (active_part_count) - msleep_interruptible(300); - } while (active_part_count > 0); + if (active_part_count == 0) { + break; + } + if (jiffies >= printmsg_time) { + dev_info(xpc_part, "waiting for partitions to " + "deactivate/disengage, active count=%d, remote " + "engaged=0x%lx\n", active_part_count, + xpc_partition_engaged(1UL << partid)); + + printmsg_time = jiffies + + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); + } + + /* sleep for a 1/3 of a second or so */ + (void) msleep_interruptible(300); + + } while (1); + + DBUG_ON(xpc_partition_engaged(-1UL)); + + + /* indicate to others that our reserved page is uninitialized */ + xpc_rsvd_page->vars_pa = 0; + + /* now it's time to eliminate our heartbeat */ + del_timer_sync(&xpc_hb_timer); + DBUG_ON(xpc_vars->heartbeating_to_mask == 0); + + /* take ourselves off of the reboot_notifier_list */ + (void) unregister_reboot_notifier(&xpc_reboot_notifier); /* close down protections for IPI operations */ xpc_restrict_IPI_ops(); @@ -876,6 +948,34 @@ xpc_do_exit(void) } +/* + * This function is called when the system is being rebooted. + */ +static int +xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) +{ + enum xpc_retval reason; + + + switch (event) { + case SYS_RESTART: + reason = xpcSystemReboot; + break; + case SYS_HALT: + reason = xpcSystemHalt; + break; + case SYS_POWER_OFF: + reason = xpcSystemPoweroff; + break; + default: + reason = xpcSystemGoingDown; + } + + xpc_do_exit(reason); + return NOTIFY_DONE; +} + + int __init xpc_init(void) { @@ -920,6 +1020,12 @@ xpc_init(void) spin_lock_init(&part->act_lock); part->act_state = XPC_P_INACTIVE; XPC_SET_REASON(part, 0, 0); + + init_timer(&part->disengage_request_timer); + part->disengage_request_timer.function = + xpc_timeout_partition_disengage_request; + part->disengage_request_timer.data = (unsigned long) part; + part->setup_state = XPC_P_UNSET; init_waitqueue_head(&part->teardown_wq); atomic_set(&part->references, 0); @@ -976,6 +1082,13 @@ xpc_init(void) } + /* add ourselves to the reboot_notifier_list */ + ret = register_reboot_notifier(&xpc_reboot_notifier); + if (ret != 0) { + dev_warn(xpc_part, "can't register reboot notifier\n"); + } + + /* * Set the beating to other partitions into motion. This is * the last requirement for other partitions' discovery to @@ -997,6 +1110,9 @@ xpc_init(void) /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->vars_pa = 0; + /* take ourselves off of the reboot_notifier_list */ + (void) unregister_reboot_notifier(&xpc_reboot_notifier); + del_timer_sync(&xpc_hb_timer); free_irq(SGI_XPC_ACTIVATE, NULL); xpc_restrict_IPI_ops(); @@ -1018,9 +1134,9 @@ xpc_init(void) dev_err(xpc_part, "failed while forking discovery thread\n"); /* mark this new thread as a non-starter */ - up(&xpc_discovery_exited); + up(&xpc_discovery_inactive); - xpc_do_exit(); + xpc_do_exit(xpcUnloading); return -EBUSY; } @@ -1039,7 +1155,7 @@ module_init(xpc_init); void __exit xpc_exit(void) { - xpc_do_exit(); + xpc_do_exit(xpcUnloading); } module_exit(xpc_exit); diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 578265ea9e67..79a0fc4c860c 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -76,11 +76,6 @@ char ____cacheline_aligned xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE]; -/* systune related variables */ -int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; -int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_TIMEOUT; - - /* * Given a nasid, get the physical address of the partition's reserved page * for that nasid. This function returns 0 on any error. @@ -239,16 +234,21 @@ xpc_rsvd_page_init(void) xpc_vars->amos_page = amos_page; /* save for next load of XPC */ - /* - * Initialize the activation related AMO variables. - */ - xpc_vars->act_amos = xpc_IPI_init(XP_MAX_PARTITIONS); - for (i = 1; i < XP_NASID_MASK_WORDS; i++) { - xpc_IPI_init(i + XP_MAX_PARTITIONS); + /* initialize the activate IRQ related AMO variables */ + for (i = 0; i < XP_NASID_MASK_WORDS; i++) { + (void) xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); } + + /* initialize the engaged remote partitions related AMO variables */ + (void) xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); + (void) xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); + /* export AMO page's physical address to other partitions */ xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page); + /* timestamp of when reserved page was initialized */ + rp->stamp = CURRENT_TIME; + /* * This signifies to the remote partition that our reserved * page is initialized. @@ -387,6 +387,11 @@ xpc_check_remote_hb(void) remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + + if (xpc_exiting) { + break; + } + if (partid == sn_partition_id) { continue; } @@ -417,7 +422,7 @@ xpc_check_remote_hb(void) if (((remote_vars->heartbeat == part->last_heartbeat) && (remote_vars->kdb_status == 0)) || - !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) { + !xpc_hb_allowed(sn_partition_id, remote_vars)) { XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat); continue; @@ -436,23 +441,23 @@ xpc_check_remote_hb(void) */ static enum xpc_retval xpc_get_remote_rp(int nasid, u64 *discovered_nasids, - struct xpc_rsvd_page *remote_rp, u64 *remote_rsvd_page_pa) + struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) { int bres, i; /* get the reserved page's physical address */ - *remote_rsvd_page_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp, + *remote_rp_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp, XPC_RSVD_PAGE_ALIGNED_SIZE); - if (*remote_rsvd_page_pa == 0) { + if (*remote_rp_pa == 0) { return xpcNoRsvdPageAddr; } /* pull over the reserved page structure */ - bres = xp_bte_copy(*remote_rsvd_page_pa, ia64_tpa((u64) remote_rp), + bres = xp_bte_copy(*remote_rp_pa, ia64_tpa((u64) remote_rp), XPC_RSVD_PAGE_ALIGNED_SIZE, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { @@ -523,6 +528,55 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) } +/* + * Update the remote partition's info. + */ +static void +xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, + struct timespec *remote_rp_stamp, u64 remote_rp_pa, + u64 remote_vars_pa, struct xpc_vars *remote_vars) +{ + part->remote_rp_version = remote_rp_version; + dev_dbg(xpc_part, " remote_rp_version = 0x%016lx\n", + part->remote_rp_version); + + part->remote_rp_stamp = *remote_rp_stamp; + dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", + part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); + + part->remote_rp_pa = remote_rp_pa; + dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); + + part->remote_vars_pa = remote_vars_pa; + dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", + part->remote_vars_pa); + + part->last_heartbeat = remote_vars->heartbeat; + dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", + part->last_heartbeat); + + part->remote_vars_part_pa = remote_vars->vars_part_pa; + dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", + part->remote_vars_part_pa); + + part->remote_act_nasid = remote_vars->act_nasid; + dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", + part->remote_act_nasid); + + part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; + dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", + part->remote_act_phys_cpuid); + + part->remote_amos_page_pa = remote_vars->amos_page_pa; + dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", + part->remote_amos_page_pa); + + part->remote_vars_version = remote_vars->version; + dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", + part->remote_vars_version); +} + + /* * Prior code has determine the nasid which generated an IPI. Inspect * that nasid to determine if its partition needs to be activated or @@ -542,8 +596,12 @@ xpc_identify_act_IRQ_req(int nasid) { struct xpc_rsvd_page *remote_rp; struct xpc_vars *remote_vars; - u64 remote_rsvd_page_pa; + u64 remote_rp_pa; u64 remote_vars_pa; + int remote_rp_version; + int reactivate = 0; + int stamp_diff; + struct timespec remote_rp_stamp = { 0, 0 }; partid_t partid; struct xpc_partition *part; enum xpc_retval ret; @@ -553,7 +611,7 @@ xpc_identify_act_IRQ_req(int nasid) remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer; - ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rsvd_page_pa); + ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); if (ret != xpcSuccess) { dev_warn(xpc_part, "unable to get reserved page from nasid %d, " "which sent interrupt, reason=%d\n", nasid, ret); @@ -561,6 +619,10 @@ xpc_identify_act_IRQ_req(int nasid) } remote_vars_pa = remote_rp->vars_pa; + remote_rp_version = remote_rp->version; + if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + remote_rp_stamp = remote_rp->stamp; + } partid = remote_rp->partid; part = &xpc_partitions[partid]; @@ -586,44 +648,117 @@ xpc_identify_act_IRQ_req(int nasid) "%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd, remote_vars->heartbeat, remote_vars->heartbeating_to_mask); + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { - if (part->act_state == XPC_P_INACTIVE) { + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); - part->remote_rp_pa = remote_rsvd_page_pa; - dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", - part->remote_rp_pa); - - part->remote_vars_pa = remote_vars_pa; - dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", - part->remote_vars_pa); - - part->last_heartbeat = remote_vars->heartbeat; - dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", - part->last_heartbeat); - - part->remote_vars_part_pa = remote_vars->vars_part_pa; - dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", - part->remote_vars_part_pa); - - part->remote_act_nasid = remote_vars->act_nasid; - dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", - part->remote_act_nasid); - - part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; - dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", - part->remote_act_phys_cpuid); - - part->remote_amos_page_pa = remote_vars->amos_page_pa; - dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", - part->remote_amos_page_pa); + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + if (xpc_partition_disengage_requested(1UL << partid)) { + /* + * Other side is waiting on us to disengage, + * even though we already have. + */ + return; + } + } else { + /* other side doesn't support disengage requests */ + xpc_clear_partition_disengage_request(1UL << partid); + } xpc_activate_partition(part); + return; + } - } else if (part->remote_amos_page_pa != remote_vars->amos_page_pa || - !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) { + DBUG_ON(part->remote_rp_version == 0); + DBUG_ON(part->remote_vars_version == 0); + if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> + remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> + version)); + /* see if the other side rebooted */ + if (part->remote_amos_page_pa == + remote_vars->amos_page_pa && + xpc_hb_allowed(sn_partition_id, + remote_vars)) { + /* doesn't look that way, so ignore the IPI */ + return; + } + } + + /* + * Other side rebooted and previous XPC didn't support the + * disengage request, so we don't need to do anything special. + */ + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); part->reactivate_nasid = nasid; XPC_DEACTIVATE_PARTITION(part, xpcReactivating); + return; + } + + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + /* + * Other side rebooted and previous XPC did support the + * disengage request, but the new one doesn't. + */ + + xpc_clear_partition_engaged(1UL << partid); + xpc_clear_partition_disengage_request(1UL << partid); + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + reactivate = 1; + + } else { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, + &remote_rp_stamp); + if (stamp_diff != 0) { + DBUG_ON(stamp_diff >= 0); + + /* + * Other side rebooted and the previous XPC did support + * the disengage request, as does the new one. + */ + + DBUG_ON(xpc_partition_engaged(1UL << partid)); + DBUG_ON(xpc_partition_disengage_requested(1UL << + partid)); + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + reactivate = 1; + } + } + + if (!xpc_partition_disengaged(part)) { + /* still waiting on other side to disengage from us */ + return; + } + + if (reactivate) { + part->reactivate_nasid = nasid; + XPC_DEACTIVATE_PARTITION(part, xpcReactivating); + + } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && + xpc_partition_disengage_requested(1UL << partid)) { + XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown); } } @@ -646,12 +781,16 @@ xpc_identify_act_IRQ_sender(void) struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page; - act_amos = xpc_vars->act_amos; + act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; /* scan through act AMO variable looking for non-zero entries */ for (word = 0; word < XP_NASID_MASK_WORDS; word++) { + if (xpc_exiting) { + break; + } + nasid_mask = xpc_IPI_receive(&act_amos[word]); if (nasid_mask == 0) { /* no IRQs from nasids in this variable */ @@ -687,6 +826,55 @@ xpc_identify_act_IRQ_sender(void) } +/* + * See if the other side has responded to a partition disengage request + * from us. + */ +int +xpc_partition_disengaged(struct xpc_partition *part) +{ + partid_t partid = XPC_PARTID(part); + int disengaged; + + + disengaged = (xpc_partition_engaged(1UL << partid) == 0); + if (part->disengage_request_timeout) { + if (!disengaged) { + if (jiffies < part->disengage_request_timeout) { + /* timelimit hasn't been reached yet */ + return 0; + } + + /* + * Other side hasn't responded to our disengage + * request in a timely fashion, so assume it's dead. + */ + + xpc_clear_partition_engaged(1UL << partid); + disengaged = 1; + } + part->disengage_request_timeout = 0; + + /* cancel the timer function, provided it's not us */ + if (!in_interrupt()) { + del_singleshot_timer_sync(&part-> + disengage_request_timer); + } + + DBUG_ON(part->act_state != XPC_P_DEACTIVATING && + part->act_state != XPC_P_INACTIVE); + if (part->act_state != XPC_P_INACTIVE) { + xpc_wakeup_channel_mgr(part); + } + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + xpc_cancel_partition_disengage_request(part); + } + } + return disengaged; +} + + /* * Mark specified partition as active. */ @@ -721,7 +909,6 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, enum xpc_retval reason) { unsigned long irq_flags; - partid_t partid = XPC_PARTID(part); spin_lock_irqsave(&part->act_lock, irq_flags); @@ -749,17 +936,27 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, spin_unlock_irqrestore(&part->act_lock, irq_flags); - XPC_DISALLOW_HB(partid, xpc_vars); + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + xpc_request_partition_disengage(part); + xpc_IPI_send_disengage(part); + + /* set a timelimit on the disengage request */ + part->disengage_request_timeout = jiffies + + (XPC_DISENGAGE_REQUEST_TIMELIMIT * HZ); + part->disengage_request_timer.expires = + part->disengage_request_timeout; + add_timer(&part->disengage_request_timer); + } dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid, reason); - xpc_partition_down(part, reason); + xpc_partition_going_down(part, reason); } /* - * Mark specified partition as active. + * Mark specified partition as inactive. */ void xpc_mark_partition_inactive(struct xpc_partition *part) @@ -792,7 +989,7 @@ xpc_discovery(void) void *remote_rp_base; struct xpc_rsvd_page *remote_rp; struct xpc_vars *remote_vars; - u64 remote_rsvd_page_pa; + u64 remote_rp_pa; u64 remote_vars_pa; int region; int max_regions; @@ -877,7 +1074,7 @@ xpc_discovery(void) /* pull over the reserved page structure */ ret = xpc_get_remote_rp(nasid, discovered_nasids, - remote_rp, &remote_rsvd_page_pa); + remote_rp, &remote_rp_pa); if (ret != xpcSuccess) { dev_dbg(xpc_part, "unable to get reserved page " "from nasid %d, reason=%d\n", nasid, @@ -948,6 +1145,13 @@ xpc_discovery(void) remote_vars->act_nasid, remote_vars->act_phys_cpuid); + if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> + version)) { + part->remote_amos_page_pa = + remote_vars->amos_page_pa; + xpc_mark_partition_disengaged(part); + xpc_cancel_partition_disengage_request(part); + } xpc_IPI_send_activate(remote_vars); } } diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h index 1df1c9f61a65..f3052a54932b 100644 --- a/include/asm-ia64/sn/xp.h +++ b/include/asm-ia64/sn/xp.h @@ -217,7 +217,15 @@ enum xpc_retval { xpcInvalidPartid, /* 42: invalid partition ID */ xpcLocalPartid, /* 43: local partition ID */ - xpcUnknownReason /* 44: unknown reason -- must be last in list */ + xpcOtherGoingDown, /* 44: other side going down, reason unknown */ + xpcSystemGoingDown, /* 45: system is going down, reason unknown */ + xpcSystemHalt, /* 46: system is being halted */ + xpcSystemReboot, /* 47: system is being rebooted */ + xpcSystemPoweroff, /* 48: system is being powered off */ + + xpcDisconnecting, /* 49: channel disconnecting (closing) */ + + xpcUnknownReason /* 50: unknown reason -- must be last in list */ }; From 5fbcf9a5c6904bd563f584d12d1f4d3f68a19d7d Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Tue, 6 Sep 2005 13:03:51 -0500 Subject: [PATCH 0015/1939] [IA64-SGI] volatile semantics in places where it seems necessary Resend using accessors instead of volatile qualifiers per hch comments, and easier to understand convenience macros per rja comments. Patch to apply volatile semantics when accessing MMR's in various SN files. Signed-off-by: Mark Maule Signed-off-by: Tony Luck --- arch/ia64/sn/pci/pcibr/pcibr_reg.c | 58 ++++++++++++++-------------- arch/ia64/sn/pci/tioca_provider.c | 31 +++++++-------- arch/ia64/sn/pci/tioce_provider.c | 29 +++++++------- include/asm-ia64/sn/io.h | 9 +++++ include/asm-ia64/sn/tioca_provider.h | 14 +++---- 5 files changed, 76 insertions(+), 65 deletions(-) diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c index 21426d02fbe6..1624b39cb3ec 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c @@ -29,10 +29,10 @@ void pcireg_control_bit_clr(struct pcibus_info *pcibus_info, uint64_t bits) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_control &= ~bits; + __sn_clrq_relaxed(&ptr->tio.cp_control, bits); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_wid_control &= ~bits; + __sn_clrq_relaxed(&ptr->pic.p_wid_control, bits); break; default: panic @@ -49,10 +49,10 @@ void pcireg_control_bit_set(struct pcibus_info *pcibus_info, uint64_t bits) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_control |= bits; + __sn_setq_relaxed(&ptr->tio.cp_control, bits); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_wid_control |= bits; + __sn_setq_relaxed(&ptr->pic.p_wid_control, bits); break; default: panic @@ -73,10 +73,10 @@ uint64_t pcireg_tflush_get(struct pcibus_info *pcibus_info) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ret = ptr->tio.cp_tflush; + ret = __sn_readq_relaxed(&ptr->tio.cp_tflush); break; case PCIBR_BRIDGETYPE_PIC: - ret = ptr->pic.p_wid_tflush; + ret = __sn_readq_relaxed(&ptr->pic.p_wid_tflush); break; default: panic @@ -103,10 +103,10 @@ uint64_t pcireg_intr_status_get(struct pcibus_info * pcibus_info) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ret = ptr->tio.cp_int_status; + ret = __sn_readq_relaxed(&ptr->tio.cp_int_status); break; case PCIBR_BRIDGETYPE_PIC: - ret = ptr->pic.p_int_status; + ret = __sn_readq_relaxed(&ptr->pic.p_int_status); break; default: panic @@ -127,10 +127,10 @@ void pcireg_intr_enable_bit_clr(struct pcibus_info *pcibus_info, uint64_t bits) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_int_enable &= ~bits; + __sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_int_enable &= ~bits; + __sn_clrq_relaxed(&ptr->pic.p_int_enable, ~bits); break; default: panic @@ -147,10 +147,10 @@ void pcireg_intr_enable_bit_set(struct pcibus_info *pcibus_info, uint64_t bits) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_int_enable |= bits; + __sn_setq_relaxed(&ptr->tio.cp_int_enable, bits); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_int_enable |= bits; + __sn_setq_relaxed(&ptr->pic.p_int_enable, bits); break; default: panic @@ -171,14 +171,16 @@ void pcireg_intr_addr_addr_set(struct pcibus_info *pcibus_info, int int_n, if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_int_addr[int_n] &= ~TIOCP_HOST_INTR_ADDR; - ptr->tio.cp_int_addr[int_n] |= - (addr & TIOCP_HOST_INTR_ADDR); + __sn_clrq_relaxed(&ptr->tio.cp_int_addr[int_n], + TIOCP_HOST_INTR_ADDR); + __sn_setq_relaxed(&ptr->tio.cp_int_addr[int_n], + (addr & TIOCP_HOST_INTR_ADDR)); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_int_addr[int_n] &= ~PIC_HOST_INTR_ADDR; - ptr->pic.p_int_addr[int_n] |= - (addr & PIC_HOST_INTR_ADDR); + __sn_clrq_relaxed(&ptr->pic.p_int_addr[int_n], + PIC_HOST_INTR_ADDR); + __sn_setq_relaxed(&ptr->pic.p_int_addr[int_n], + (addr & PIC_HOST_INTR_ADDR)); break; default: panic @@ -198,10 +200,10 @@ void pcireg_force_intr_set(struct pcibus_info *pcibus_info, int int_n) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_force_pin[int_n] = 1; + writeq(1, &ptr->tio.cp_force_pin[int_n]); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_force_pin[int_n] = 1; + writeq(1, &ptr->pic.p_force_pin[int_n]); break; default: panic @@ -222,10 +224,12 @@ uint64_t pcireg_wrb_flush_get(struct pcibus_info *pcibus_info, int device) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ret = ptr->tio.cp_wr_req_buf[device]; + ret = + __sn_readq_relaxed(&ptr->tio.cp_wr_req_buf[device]); break; case PCIBR_BRIDGETYPE_PIC: - ret = ptr->pic.p_wr_req_buf[device]; + ret = + __sn_readq_relaxed(&ptr->pic.p_wr_req_buf[device]); break; default: panic("pcireg_wrb_flush_get: unknown bridgetype bridge 0x%p", (void *)ptr); @@ -244,10 +248,10 @@ void pcireg_int_ate_set(struct pcibus_info *pcibus_info, int ate_index, if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ptr->tio.cp_int_ate_ram[ate_index] = (uint64_t) val; + writeq(val, &ptr->tio.cp_int_ate_ram[ate_index]); break; case PCIBR_BRIDGETYPE_PIC: - ptr->pic.p_int_ate_ram[ate_index] = (uint64_t) val; + writeq(val, &ptr->pic.p_int_ate_ram[ate_index]); break; default: panic @@ -265,12 +269,10 @@ uint64_t *pcireg_int_ate_addr(struct pcibus_info *pcibus_info, int ate_index) if (pcibus_info) { switch (pcibus_info->pbi_bridge_type) { case PCIBR_BRIDGETYPE_TIOCP: - ret = - (uint64_t *) & (ptr->tio.cp_int_ate_ram[ate_index]); + ret = &ptr->tio.cp_int_ate_ram[ate_index]; break; case PCIBR_BRIDGETYPE_PIC: - ret = - (uint64_t *) & (ptr->pic.p_int_ate_ram[ate_index]); + ret = &ptr->pic.p_int_ate_ram[ate_index]; break; default: panic diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index ea09c12f0258..eaae2472d6b4 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -37,7 +37,7 @@ tioca_gart_init(struct tioca_kernel *tioca_kern) uint64_t offset; struct page *tmp; struct tioca_common *tioca_common; - volatile struct tioca *ca_base; + struct tioca *ca_base; tioca_common = tioca_kern->ca_common; ca_base = (struct tioca *)tioca_common->ca_common.bs_base; @@ -174,27 +174,29 @@ tioca_gart_init(struct tioca_kernel *tioca_kern) * DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029 */ - ca_base->ca_control1 |= CA_AGPDMA_OP_ENB_COMBDELAY; /* PV895469 ? */ - ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); - ca_base->ca_control2 |= (0x2ull << CA_GART_MEM_PARAM_SHFT); + __sn_setq_relaxed(&ca_base->ca_control1, + CA_AGPDMA_OP_ENB_COMBDELAY); /* PV895469 ? */ + __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM); + __sn_setq_relaxed(&ca_base->ca_control2, + (0x2ull << CA_GART_MEM_PARAM_SHFT)); tioca_kern->ca_gart_iscoherent = 1; - ca_base->ca_control2 &= - ~(CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB); + __sn_clrq_relaxed(&ca_base->ca_control2, + (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB)); /* * Unmask GART fetch error interrupts. Clear residual errors first. */ - ca_base->ca_int_status_alias = CA_GART_FETCH_ERR; - ca_base->ca_mult_error_alias = CA_GART_FETCH_ERR; - ca_base->ca_int_mask &= ~CA_GART_FETCH_ERR; + writeq(CA_GART_FETCH_ERR, &ca_base->ca_int_status_alias); + writeq(CA_GART_FETCH_ERR, &ca_base->ca_mult_error_alias); + __sn_clrq_relaxed(&ca_base->ca_int_mask, CA_GART_FETCH_ERR); /* * Program the aperature and gart registers in TIOCA */ - ca_base->ca_gart_aperature = ap_reg; - ca_base->ca_gart_ptr_table = tioca_kern->ca_gart_coretalk_addr | 1; + writeq(ap_reg, &ca_base->ca_gart_aperature); + writeq(tioca_kern->ca_gart_coretalk_addr|1, &ca_base->ca_gart_ptr_table); return 0; } @@ -211,7 +213,6 @@ void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) { int cap_ptr; - uint64_t ca_control1; uint32_t reg; struct tioca *tioca_base; struct pci_dev *pdev; @@ -256,9 +257,7 @@ tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) */ tioca_base = (struct tioca *)common->ca_common.bs_base; - ca_control1 = tioca_base->ca_control1; - ca_control1 |= CA_AGP_FW_ENABLE; - tioca_base->ca_control1 = ca_control1; + __sn_setq_relaxed(&tioca_base->ca_control1, CA_AGP_FW_ENABLE); } EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */ @@ -345,7 +344,7 @@ tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr) return 0; } - agp_dma_extn = ca_base->ca_agp_dma_addr_extn; + agp_dma_extn = __sn_readq_relaxed(&ca_base->ca_agp_dma_addr_extn); if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) { printk(KERN_ERR "%s: coretalk upper node (%u) " "mismatch with ca_agp_dma_addr_extn (%lu)\n", diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index 8e75db2b825d..204826c2fa44 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c @@ -227,7 +227,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, ate = ATE_MAKE(addr, pagesize); ate_shadow[i + j] = ate; - ate_reg[i + j] = ate; + writeq(ate, &ate_reg[i + j]); addr += pagesize; } @@ -268,10 +268,10 @@ tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr) pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port); if (ce_kern->ce_port[port].dirmap_refcnt == 0) { - volatile uint64_t tmp; + uint64_t tmp; ce_kern->ce_port[port].dirmap_shadow = ct_upper; - ce_mmr->ce_ure_dir_map[port] = ct_upper; + writeq(ct_upper, &ce_mmr->ce_ure_dir_map[port]); tmp = ce_mmr->ce_ure_dir_map[port]; dma_ok = 1; } else @@ -343,7 +343,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) if (TIOCE_D32_ADDR(bus_addr)) { if (--ce_kern->ce_port[port].dirmap_refcnt == 0) { ce_kern->ce_port[port].dirmap_shadow = 0; - ce_mmr->ce_ure_dir_map[port] = 0; + writeq(0, &ce_mmr->ce_ure_dir_map[port]); } } else { struct tioce_dmamap *map; @@ -582,18 +582,18 @@ tioce_kern_init(struct tioce_common *tioce_common) */ tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; - tioce_mmr->ce_ure_page_map &= ~CE_URE_PAGESIZE_MASK; - tioce_mmr->ce_ure_page_map |= CE_URE_256K_PAGESIZE; + __sn_clrq_relaxed(&tioce_mmr->ce_ure_page_map, CE_URE_PAGESIZE_MASK); + __sn_setq_relaxed(&tioce_mmr->ce_ure_page_map, CE_URE_256K_PAGESIZE); tioce_kern->ce_ate3240_pagesize = KB(256); for (i = 0; i < TIOCE_NUM_M40_ATES; i++) { tioce_kern->ce_ate40_shadow[i] = 0; - tioce_mmr->ce_ure_ate40[i] = 0; + writeq(0, &tioce_mmr->ce_ure_ate40[i]); } for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) { tioce_kern->ce_ate3240_shadow[i] = 0; - tioce_mmr->ce_ure_ate3240[i] = 0; + writeq(0, &tioce_mmr->ce_ure_ate3240[i]); } return tioce_kern; @@ -665,7 +665,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) default: return; } - ce_mmr->ce_adm_force_int = force_int_val; + writeq(force_int_val, &ce_mmr->ce_adm_force_int); } /** @@ -686,6 +686,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) struct tioce_common *ce_common; struct tioce *ce_mmr; int bit; + uint64_t vector; pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; if (!pcidev_info) @@ -696,11 +697,11 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) bit = sn_irq_info->irq_int_bit; - ce_mmr->ce_adm_int_mask |= (1UL << bit); - ce_mmr->ce_adm_int_dest[bit] = - ((uint64_t)sn_irq_info->irq_irq << INTR_VECTOR_SHFT) | - sn_irq_info->irq_xtalkaddr; - ce_mmr->ce_adm_int_mask &= ~(1UL << bit); + __sn_setq_relaxed(&ce_mmr->ce_adm_int_mask, (1UL << bit)); + vector = (uint64_t)sn_irq_info->irq_irq << INTR_VECTOR_SHFT; + vector |= sn_irq_info->irq_xtalkaddr; + writeq(vector, &ce_mmr->ce_adm_int_dest[bit]); + __sn_clrq_relaxed(&ce_mmr->ce_adm_int_mask, (1UL << bit)); tioce_force_interrupt(sn_irq_info); } diff --git a/include/asm-ia64/sn/io.h b/include/asm-ia64/sn/io.h index 42209733f6b1..7597a52b426c 100644 --- a/include/asm-ia64/sn/io.h +++ b/include/asm-ia64/sn/io.h @@ -35,6 +35,15 @@ extern void sn_dma_flush(unsigned long); #define __sn_readl_relaxed ___sn_readl_relaxed #define __sn_readq_relaxed ___sn_readq_relaxed +/* + * Convenience macros for setting/clearing bits using the above accessors + */ + +#define __sn_setq_relaxed(addr, val) \ + writeq((__sn_readq_relaxed(addr) | (val)), (addr)) +#define __sn_clrq_relaxed(addr, val) \ + writeq((__sn_readq_relaxed(addr) & ~(val)), (addr)) + /* * The following routines are SN Platform specific, called when * a reference is made to inX/outX set macros. SN Platform diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h index 5ccec608d325..b532ef6148ed 100644 --- a/include/asm-ia64/sn/tioca_provider.h +++ b/include/asm-ia64/sn/tioca_provider.h @@ -182,11 +182,11 @@ tioca_tlbflush(struct tioca_kernel *tioca_kernel) * touch every CL aligned GART entry. */ - ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); - ca_base->ca_control2 |= CA_GART_FLUSH_TLB; - ca_base->ca_control2 |= - (0x2ull << CA_GART_MEM_PARAM_SHFT); - tmp = ca_base->ca_control2; + __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM); + __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB); + __sn_setq_relaxed(&ca_base->ca_control2, + (0x2ull << CA_GART_MEM_PARAM_SHFT)); + tmp = __sn_readq_relaxed(&ca_base->ca_control2); } return; @@ -196,8 +196,8 @@ tioca_tlbflush(struct tioca_kernel *tioca_kernel) * Gart in uncached mode ... need an explicit flush. */ - ca_base->ca_control2 |= CA_GART_FLUSH_TLB; - tmp = ca_base->ca_control2; + __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB); + tmp = __sn_readq_relaxed(&ca_base->ca_control2); } extern uint32_t tioca_gart_found; From d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 8 Sep 2005 12:39:59 -0700 Subject: [PATCH 0016/1939] [IA64] simplified efi memory map parsing New version leaves the original memory map unmodified. Also saves any granule trimmings for use by the uncached memory allocator. Inspired by Khalid Aziz (various traces of his patch still remain). Fixes to uncached_build_memmap() and sn2 testing by Martin Hicks. Signed-off-by: Tony Luck --- arch/ia64/kernel/efi.c | 423 +++++++++++++++++++++--------------- arch/ia64/kernel/setup.c | 3 + arch/ia64/kernel/uncached.c | 17 +- include/asm-ia64/meminit.h | 4 +- 4 files changed, 254 insertions(+), 193 deletions(-) diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 179f230816ed..1291db581721 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -239,57 +239,30 @@ is_available_memory (efi_memory_desc_t *md) return 0; } -/* - * Trim descriptor MD so its starts at address START_ADDR. If the descriptor covers - * memory that is normally available to the kernel, issue a warning that some memory - * is being ignored. - */ -static void -trim_bottom (efi_memory_desc_t *md, u64 start_addr) -{ - u64 num_skipped_pages; +typedef struct kern_memdesc { + u64 attribute; + u64 start; + u64 num_pages; +} kern_memdesc_t; - if (md->phys_addr >= start_addr || !md->num_pages) - return; - - num_skipped_pages = (start_addr - md->phys_addr) >> EFI_PAGE_SHIFT; - if (num_skipped_pages > md->num_pages) - num_skipped_pages = md->num_pages; - - if (is_available_memory(md)) - printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " - "at 0x%lx\n", __FUNCTION__, - (num_skipped_pages << EFI_PAGE_SHIFT) >> 10, - md->phys_addr, start_addr - IA64_GRANULE_SIZE); - /* - * NOTE: Don't set md->phys_addr to START_ADDR because that could cause the memory - * descriptor list to become unsorted. In such a case, md->num_pages will be - * zero, so the Right Thing will happen. - */ - md->phys_addr += num_skipped_pages << EFI_PAGE_SHIFT; - md->num_pages -= num_skipped_pages; -} +static kern_memdesc_t *kern_memmap; static void -trim_top (efi_memory_desc_t *md, u64 end_addr) +walk (efi_freemem_callback_t callback, void *arg, u64 attr) { - u64 num_dropped_pages, md_end_addr; + kern_memdesc_t *k; + u64 start, end, voff; - md_end_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - - if (md_end_addr <= end_addr || !md->num_pages) - return; - - num_dropped_pages = (md_end_addr - end_addr) >> EFI_PAGE_SHIFT; - if (num_dropped_pages > md->num_pages) - num_dropped_pages = md->num_pages; - - if (is_available_memory(md)) - printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " - "at 0x%lx\n", __FUNCTION__, - (num_dropped_pages << EFI_PAGE_SHIFT) >> 10, - md->phys_addr, end_addr); - md->num_pages -= num_dropped_pages; + voff = (attr == EFI_MEMORY_WB) ? PAGE_OFFSET : __IA64_UNCACHED_OFFSET; + for (k = kern_memmap; k->start != ~0UL; k++) { + if (k->attribute != attr) + continue; + start = PAGE_ALIGN(k->start); + end = (k->start + (k->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK; + if (start < end) + if ((*callback)(start + voff, end + voff, arg) < 0) + return; + } } /* @@ -299,148 +272,19 @@ trim_top (efi_memory_desc_t *md, u64 end_addr) void efi_memmap_walk (efi_freemem_callback_t callback, void *arg) { - int prev_valid = 0; - struct range { - u64 start; - u64 end; - } prev, curr; - void *efi_map_start, *efi_map_end, *p, *q; - efi_memory_desc_t *md, *check_md; - u64 efi_desc_size, start, end, granule_addr, last_granule_addr, first_non_wb_addr = 0; - unsigned long total_mem = 0; - - 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; - - for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { - md = p; - - /* skip over non-WB memory descriptors; that's all we're interested in... */ - if (!(md->attribute & EFI_MEMORY_WB)) - continue; - - /* - * granule_addr is the base of md's first granule. - * [granule_addr - first_non_wb_addr) is guaranteed to - * be contiguous WB memory. - */ - granule_addr = GRANULEROUNDDOWN(md->phys_addr); - first_non_wb_addr = max(first_non_wb_addr, granule_addr); - - if (first_non_wb_addr < md->phys_addr) { - trim_bottom(md, granule_addr + IA64_GRANULE_SIZE); - granule_addr = GRANULEROUNDDOWN(md->phys_addr); - first_non_wb_addr = max(first_non_wb_addr, granule_addr); - } - - for (q = p; q < efi_map_end; q += efi_desc_size) { - check_md = q; - - if ((check_md->attribute & EFI_MEMORY_WB) && - (check_md->phys_addr == first_non_wb_addr)) - first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT; - else - break; /* non-WB or hole */ - } - - last_granule_addr = GRANULEROUNDDOWN(first_non_wb_addr); - if (last_granule_addr < md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) - trim_top(md, last_granule_addr); - - if (is_available_memory(md)) { - if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) >= max_addr) { - if (md->phys_addr >= max_addr) - continue; - md->num_pages = (max_addr - md->phys_addr) >> EFI_PAGE_SHIFT; - first_non_wb_addr = max_addr; - } - - if (total_mem >= mem_limit) - continue; - - if (total_mem + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) { - unsigned long limit_addr = md->phys_addr; - - limit_addr += mem_limit - total_mem; - limit_addr = GRANULEROUNDDOWN(limit_addr); - - if (md->phys_addr > limit_addr) - continue; - - md->num_pages = (limit_addr - md->phys_addr) >> - EFI_PAGE_SHIFT; - first_non_wb_addr = max_addr = md->phys_addr + - (md->num_pages << EFI_PAGE_SHIFT); - } - total_mem += (md->num_pages << EFI_PAGE_SHIFT); - - if (md->num_pages == 0) - continue; - - curr.start = PAGE_OFFSET + md->phys_addr; - curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT); - - if (!prev_valid) { - prev = curr; - prev_valid = 1; - } else { - if (curr.start < prev.start) - printk(KERN_ERR "Oops: EFI memory table not ordered!\n"); - - if (prev.end == curr.start) { - /* merge two consecutive memory ranges */ - prev.end = curr.end; - } else { - start = PAGE_ALIGN(prev.start); - end = prev.end & PAGE_MASK; - if ((end > start) && (*callback)(start, end, arg) < 0) - return; - prev = curr; - } - } - } - } - if (prev_valid) { - start = PAGE_ALIGN(prev.start); - end = prev.end & PAGE_MASK; - if (end > start) - (*callback)(start, end, arg); - } + walk(callback, arg, EFI_MEMORY_WB); } /* - * Walk the EFI memory map to pull out leftover pages in the lower - * memory regions which do not end up in the regular memory map and - * stick them into the uncached allocator - * - * The regular walk function is significantly more complex than the - * uncached walk which means it really doesn't make sense to try and - * marge the two. + * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that + * has memory that is available for uncached allocator. */ -void __init -efi_memmap_walk_uc (efi_freemem_callback_t callback) +void +efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg) { - void *efi_map_start, *efi_map_end, *p; - efi_memory_desc_t *md; - u64 efi_desc_size, start, end; - - 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; - - for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { - md = p; - if (md->attribute == EFI_MEMORY_UC) { - start = PAGE_ALIGN(md->phys_addr); - end = PAGE_ALIGN((md->phys_addr+(md->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK); - if ((*callback)(start, end, NULL) < 0) - return; - } - } + walk(callback, arg, EFI_MEMORY_UC); } - /* * Look for the PAL_CODE region reported by EFI and maps it using an * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor @@ -862,3 +706,220 @@ efi_uart_console_only(void) printk(KERN_ERR "Malformed %s value\n", name); return 0; } + +#define efi_md_size(md) (md->num_pages << EFI_PAGE_SHIFT) + +static inline u64 +kmd_end(kern_memdesc_t *kmd) +{ + return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT)); +} + +static inline u64 +efi_md_end(efi_memory_desc_t *md) +{ + return (md->phys_addr + efi_md_size(md)); +} + +static inline int +efi_wb(efi_memory_desc_t *md) +{ + return (md->attribute & EFI_MEMORY_WB); +} + +static inline int +efi_uc(efi_memory_desc_t *md) +{ + return (md->attribute & EFI_MEMORY_UC); +} + +/* + * Look for the first granule aligned memory descriptor memory + * that is big enough to hold EFI memory map. Make sure this + * descriptor is atleast granule sized so it does not get trimmed + */ +struct kern_memdesc * +find_memmap_space (void) +{ + u64 contig_low=0, contig_high=0; + u64 as = 0, ae; + void *efi_map_start, *efi_map_end, *p, *q; + efi_memory_desc_t *md, *pmd = NULL, *check_md; + u64 space_needed, efi_desc_size; + unsigned long total_mem = 0; + + 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; + + /* + * Worst case: we need 3 kernel descriptors for each efi descriptor + * (if every entry has a WB part in the middle, and UC head and tail), + * plus one for the end marker. + */ + space_needed = sizeof(kern_memdesc_t) * + (3 * (ia64_boot_param->efi_memmap_size/efi_desc_size) + 1); + + for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) { + md = p; + if (!efi_wb(md)) { + continue; + } + if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) { + contig_low = GRANULEROUNDUP(md->phys_addr); + contig_high = efi_md_end(md); + for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) { + check_md = q; + if (!efi_wb(check_md)) + break; + if (contig_high != check_md->phys_addr) + break; + contig_high = efi_md_end(check_md); + } + contig_high = GRANULEROUNDDOWN(contig_high); + } + if (!is_available_memory(md) || md->type == EFI_LOADER_DATA) + continue; + + /* Round ends inward to granule boundaries */ + as = max(contig_low, md->phys_addr); + ae = min(contig_high, efi_md_end(md)); + + /* keep within max_addr= command line arg */ + ae = min(ae, max_addr); + if (ae <= as) + continue; + + /* avoid going over mem= command line arg */ + if (total_mem + (ae - as) > mem_limit) + ae -= total_mem + (ae - as) - mem_limit; + + if (ae <= as) + continue; + + if (ae - as > space_needed) + break; + } + if (p >= efi_map_end) + panic("Can't allocate space for kernel memory descriptors"); + + return __va(as); +} + +/* + * Walk the EFI memory map and gather all memory available for kernel + * to use. We can allocate partial granules only if the unavailable + * parts exist, and are WB. + */ +void +efi_memmap_init(unsigned long *s, unsigned long *e) +{ + struct kern_memdesc *k, *prev = 0; + u64 contig_low=0, contig_high=0; + u64 as, ae, lim; + void *efi_map_start, *efi_map_end, *p, *q; + efi_memory_desc_t *md, *pmd = NULL, *check_md; + u64 efi_desc_size; + unsigned long total_mem = 0; + + k = kern_memmap = find_memmap_space(); + + 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; + + for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) { + md = p; + if (!efi_wb(md)) { + if (efi_uc(md) && (md->type == EFI_CONVENTIONAL_MEMORY || + md->type == EFI_BOOT_SERVICES_DATA)) { + k->attribute = EFI_MEMORY_UC; + k->start = md->phys_addr; + k->num_pages = md->num_pages; + k++; + } + continue; + } + if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) { + contig_low = GRANULEROUNDUP(md->phys_addr); + contig_high = efi_md_end(md); + for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) { + check_md = q; + if (!efi_wb(check_md)) + break; + if (contig_high != check_md->phys_addr) + break; + contig_high = efi_md_end(check_md); + } + contig_high = GRANULEROUNDDOWN(contig_high); + } + if (!is_available_memory(md)) + continue; + + /* + * Round ends inward to granule boundaries + * Give trimmings to uncached allocator + */ + if (md->phys_addr < contig_low) { + lim = min(efi_md_end(md), contig_low); + if (efi_uc(md)) { + if (k > kern_memmap && (k-1)->attribute == EFI_MEMORY_UC && + kmd_end(k-1) == md->phys_addr) { + (k-1)->num_pages += (lim - md->phys_addr) >> EFI_PAGE_SHIFT; + } else { + k->attribute = EFI_MEMORY_UC; + k->start = md->phys_addr; + k->num_pages = (lim - md->phys_addr) >> EFI_PAGE_SHIFT; + k++; + } + } + as = contig_low; + } else + as = md->phys_addr; + + if (efi_md_end(md) > contig_high) { + lim = max(md->phys_addr, contig_high); + if (efi_uc(md)) { + if (lim == md->phys_addr && k > kern_memmap && + (k-1)->attribute == EFI_MEMORY_UC && + kmd_end(k-1) == md->phys_addr) { + (k-1)->num_pages += md->num_pages; + } else { + k->attribute = EFI_MEMORY_UC; + k->start = lim; + k->num_pages = (efi_md_end(md) - lim) >> EFI_PAGE_SHIFT; + k++; + } + } + ae = contig_high; + } else + ae = efi_md_end(md); + + /* keep within max_addr= command line arg */ + ae = min(ae, max_addr); + if (ae <= as) + continue; + + /* avoid going over mem= command line arg */ + if (total_mem + (ae - as) > mem_limit) + ae -= total_mem + (ae - as) - mem_limit; + + if (ae <= as) + continue; + if (prev && kmd_end(prev) == md->phys_addr) { + prev->num_pages += (ae - as) >> EFI_PAGE_SHIFT; + total_mem += ae - as; + continue; + } + k->attribute = EFI_MEMORY_WB; + k->start = as; + k->num_pages = (ae - as) >> EFI_PAGE_SHIFT; + total_mem += ae - as; + prev = k++; + } + k->start = ~0L; /* end-marker */ + + /* reserve the memory we are using for kern_memmap */ + *s = (u64)kern_memmap; + *e = (u64)++k; +} diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 84f89da7c640..1658d687b79c 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -211,6 +211,9 @@ reserve_memory (void) } #endif + efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); + n++; + /* end of memory marker */ rsvd_region[n].start = ~0UL; rsvd_region[n].end = ~0UL; diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c index 4e9d06c48a8b..c6d40446c2c4 100644 --- a/arch/ia64/kernel/uncached.c +++ b/arch/ia64/kernel/uncached.c @@ -205,23 +205,18 @@ EXPORT_SYMBOL(uncached_free_page); static int __init uncached_build_memmap(unsigned long start, unsigned long end, void *arg) { - long length; - unsigned long vstart, vend; + long length = end - start; int node; - length = end - start; - vstart = start + __IA64_UNCACHED_OFFSET; - vend = end + __IA64_UNCACHED_OFFSET; - dprintk(KERN_ERR "uncached_build_memmap(%lx %lx)\n", start, end); - memset((char *)vstart, 0, length); + memset((char *)start, 0, length); - node = paddr_to_nid(start); + node = paddr_to_nid(start - __IA64_UNCACHED_OFFSET); - for (; vstart < vend ; vstart += PAGE_SIZE) { - dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart); - gen_pool_free(uncached_pool[node], vstart, PAGE_SIZE); + 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); } return 0; diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h index 1590dc65b30b..90646632237c 100644 --- a/include/asm-ia64/meminit.h +++ b/include/asm-ia64/meminit.h @@ -16,10 +16,11 @@ * - initrd (optional) * - command line string * - kernel code & data + * - Kernel memory map built from EFI memory map * * More could be added if necessary */ -#define IA64_MAX_RSVD_REGIONS 5 +#define IA64_MAX_RSVD_REGIONS 6 struct rsvd_region { unsigned long start; /* virtual address of beginning of element */ @@ -33,6 +34,7 @@ extern void find_memory (void); extern void reserve_memory (void); extern void find_initrd (void); extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg); +extern void efi_memmap_init(unsigned long *, unsigned long *); /* * For rounding an address to the next IA64_GRANULE_SIZE or order From 1fa92957282e4595727c1a21bf6687ea5a2d612f Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 9 Sep 2005 11:41:12 -0700 Subject: [PATCH 0017/1939] [IA64] Need to include in a few more places. Signed-off-by: Tony Luck --- arch/ia64/sn/pci/pcibr/pcibr_reg.c | 1 + arch/ia64/sn/pci/tioca_provider.c | 1 + arch/ia64/sn/pci/tioce_provider.c | 1 + drivers/char/agp/sgi-agp.c | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c index 1624b39cb3ec..4f718c3e93d3 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index eaae2472d6b4..9b8dbce2b7b6 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index 204826c2fa44..9f03d4e5121c 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index d3aa159c9dec..7957fc91f6ad 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include From 923f122573851d18a3832ca808269fa2d5046fb1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 13 Sep 2005 13:21:29 +0900 Subject: [PATCH 0018/1939] [PATCH] sil24: initialization fix sil24 0.20 didn't use to perform (what seems to be) port multiplier initialization and controller reset 0.10 driver does. This makes some sil24 controllers malfunction. This patch adds PM initialization and controller resetting to initilization and bumps version to 0.21. Please refer to the following thread for more information. http://marc.theaimsgroup.com/?l=linux-ide&m=112582819830324&w=2 http://marc.theaimsgroup.com/?l=linux-ide&m=112636045531060&w=2 Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index cb91894471f2..d8a2f5f04e82 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "sata_sil24" -#define DRV_VERSION "0.20" /* Silicon Image's preview driver was 0.10 */ +#define DRV_VERSION "0.21" /* Silicon Image's preview driver was 0.10 */ #define NR_PORTS 4 @@ -426,15 +426,11 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } -static void sil24_reset_controller(struct ata_port *ap) +static int __sil24_reset_controller(void *port) { - void *port = (void *)ap->ioaddr.cmd_addr; int cnt; u32 tmp; - printk(KERN_NOTICE DRV_NAME - " ata%u: resetting controller...\n", ap->id); - /* Reset controller state. Is this correct? */ writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); readl(port + PORT_CTRL_STAT); /* sync */ @@ -446,9 +442,19 @@ static void sil24_reset_controller(struct ata_port *ap) if (!(tmp & PORT_CS_DEV_RST)) break; } + if (tmp & PORT_CS_DEV_RST) - printk(KERN_ERR DRV_NAME - " ata%u: failed to reset controller\n", ap->id); + return -1; + return 0; +} + +static void sil24_reset_controller(struct ata_port *ap) +{ + printk(KERN_NOTICE DRV_NAME + " ata%u: resetting controller...\n", ap->id); + if (__sil24_reset_controller((void *)ap->ioaddr.cmd_addr)) + printk(KERN_ERR DRV_NAME + " ata%u: failed to reset controller\n", ap->id); } static void sil24_eng_timeout(struct ata_port *ap) @@ -740,6 +746,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Clear interrupts */ writel(0x0fff0fff, port + PORT_IRQ_STAT); writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* Clear port multiplier enable and resume bits */ + writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + + /* Reset itself */ + if (__sil24_reset_controller(port)) + printk(KERN_ERR DRV_NAME + "(%s): failed to reset controller\n", + pci_name(pdev)); } /* Turn on interrupts */ From bb0ce608a3386268bd76ee6642a4cc8e6818a29b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:54 -0400 Subject: [PATCH 0019/1939] [PATCH] 8139cp: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to 8139cp. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 34b80de34fae..ebc20d9e7d7b 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1575,6 +1575,7 @@ static struct ethtool_ops cp_ethtool_ops = { .set_wol = cp_set_wol, .get_strings = cp_get_strings, .get_ethtool_stats = cp_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) @@ -1773,6 +1774,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; dev->stop = cp_close; From 62a720b889a37496d5f36d09875578956745d196 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:55 -0400 Subject: [PATCH 0020/1939] [PATCH] 8139too: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to 8139too. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/8139too.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 4c2cf7bbd252..76ef6efd5950 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -970,6 +970,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; @@ -2465,6 +2466,7 @@ static struct ethtool_ops rtl8139_ethtool_ops = { .get_strings = rtl8139_get_strings, .get_stats_count = rtl8139_get_stats_count, .get_ethtool_stats = rtl8139_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) From 2160de53cc17a40ad07bd38bf52dd0bb72dd5183 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:55 -0400 Subject: [PATCH 0021/1939] [PATCH] b44: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to b44. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 94939f570f78..d27e870e59ab 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1676,6 +1676,7 @@ static struct ethtool_ops b44_ethtool_ops = { .set_pauseparam = b44_set_pauseparam, .get_msglevel = b44_get_msglevel, .set_msglevel = b44_set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1718,6 +1719,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->dev->dev_addr[3] = eeprom[80]; bp->dev->dev_addr[4] = eeprom[83]; bp->dev->dev_addr[5] = eeprom[82]; + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); bp->phy_addr = eeprom[90] & 0x1f; From 9beb0ac17bcfed23feb0a6fac328216568b74bc1 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:55 -0400 Subject: [PATCH 0022/1939] [PATCH] e1000: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to e1000. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 1 + drivers/net/e1000/e1000_main.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f133ff0b0b94..8f3a13420278 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1739,6 +1739,7 @@ struct ethtool_ops e1000_ethtool_ops = { .phys_id = e1000_phys_id, .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7c8a0a22dcd5..d02883dcc9b3 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -614,8 +614,9 @@ e1000_probe(struct pci_dev *pdev, if(e1000_read_mac_addr(&adapter->hw)) DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; From a92dd9233ad185904daf95d040cf88c3da2d7ef6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:56 -0400 Subject: [PATCH 0023/1939] [PATCH] e100: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to e100. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 25cc20e415da..1c918309539f 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2391,6 +2391,7 @@ static struct ethtool_ops e100_ethtool_ops = { .phys_id = e100_phys_id, .get_stats_count = e100_get_stats_count, .get_ethtool_stats = e100_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) @@ -2541,7 +2542,8 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_phy_init(nic); memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); - if(!is_valid_ether_addr(netdev->dev_addr)) { + memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC address from " "EEPROM, aborting.\n"); err = -EAGAIN; From c704b8566b060695e90ac401833db4b62813ad8a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:56 -0400 Subject: [PATCH 0024/1939] [PATCH] forcedeth: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to forcedeth. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d6eefdb71c17..6e042ecf6965 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2065,6 +2065,7 @@ static struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int nv_open(struct net_device *dev) @@ -2377,8 +2378,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { /* * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab From df859c519ef7b72d9be7396443316da87272e8b6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:56 -0400 Subject: [PATCH 0025/1939] [PATCH] ixgb: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to ixgb. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/ixgb/ixgb_ethtool.c | 1 + drivers/net/ixgb/ixgb_main.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 9d026ed77ddd..319ee4cd70d8 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -723,6 +723,7 @@ struct ethtool_ops ixgb_ethtool_ops = { .phys_id = ixgb_phys_id, .get_stats_count = ixgb_get_stats_count, .get_ethtool_stats = ixgb_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void ixgb_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 5c555373adbe..5015eaf4e20a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -460,8 +460,9 @@ ixgb_probe(struct pci_dev *pdev, } ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); + memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { err = -EIO; goto err_eeprom; } From 78b345890a91dc57fecea8b6792012e0098c058f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:57 -0400 Subject: [PATCH 0026/1939] [PATCH] ne2k-pci: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to ne2k-pci. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/ne2k-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f1c01ac29102..e531a4eedfee 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -372,6 +372,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); dev->dev_addr[i] = SA_prom[i]; } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); return 0; @@ -637,6 +638,7 @@ static struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) From db0276b060918fac94c9d216213a31ee02cdd73e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:57 -0400 Subject: [PATCH 0027/1939] [PATCH] pcnet32: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to pcnet32. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 113b68099216..6c3731b608da 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -957,6 +957,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* only probes for non-PCI devices, the rest are handled by @@ -1185,9 +1186,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memcpy(dev->dev_addr, promaddr, 6); } } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if (!is_valid_ether_addr(dev->dev_addr)) + if (!is_valid_ether_addr(dev->perm_addr)) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { From 6d6525b7f74f9593e647f8c17b1de0f652e1f177 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:57 -0400 Subject: [PATCH 0028/1939] [PATCH] r8169: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to r8169. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/r8169.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index f0471d102e3c..cbc60ce365cb 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1028,6 +1028,7 @@ static struct ethtool_ops rtl8169_ethtool_ops = { .get_strings = rtl8169_get_strings, .get_stats_count = rtl8169_get_stats_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, @@ -1512,6 +1513,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; From 56230d538233ba037eb679b0fc0b218d33b9b8b8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:57 -0400 Subject: [PATCH 0029/1939] [PATCH] skge: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to skge. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d7c98515fdfd..757c83387a29 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -743,6 +743,7 @@ static struct ethtool_ops skge_ethtool_ops = { .phys_id = skge_phys_id, .get_stats_count = skge_get_stats_count, .get_ethtool_stats = skge_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* @@ -3080,6 +3081,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* device is off until link detection */ netif_carrier_off(dev); From 30d60a8288ab6f59939736f5775a7110a8bfff9a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:58 -0400 Subject: [PATCH 0030/1939] [PATCH] sundance: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to sundance. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d500a5771dbc..e148a7212073 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -549,6 +549,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; @@ -1619,6 +1620,7 @@ static struct ethtool_ops ethtool_ops = { .get_link = get_link, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) From b81e8e1f4a51556586f72711a165bc3a0de230f3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Sep 2005 10:48:58 -0400 Subject: [PATCH 0031/1939] [PATCH] via-rhine: support ETHTOOL_GPERMADDR Add support for ETHTOOL_GPERMADDR to via-rhine. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fc7738ffbfff..e7b4bc3820e3 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -814,8 +814,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { rc = -EIO; printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; @@ -1829,6 +1830,7 @@ static struct ethtool_ops netdev_ethtool_ops = { .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) From 343c686c04eec556645f251f7d6c9b3d7335dae0 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 9 Sep 2005 18:43:02 -0400 Subject: [PATCH 0032/1939] [PATCH] orinoco: WE-18 support Author: Jean Tourrilhes Signed-off-by: Pavel Roskin Use new Wireless Extension API for wireless stats. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 137 ++++++++------------------------- drivers/net/wireless/orinoco.h | 6 +- 2 files changed, 33 insertions(+), 110 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 8de49fe57233..639b8e4ba684 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -137,7 +137,7 @@ MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); /* We do this this way to avoid ifdefs in the actual code */ #ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_number) +#define SPY_NUMBER(priv) (priv->spy_data.spy_number) #else #define SPY_NUMBER(priv) 0 #endif /* WIRELESS_SPY */ @@ -396,10 +396,10 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) /* If a spy address is defined, we report stats of the * first spy address - Jean II */ if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; + wstats->qual.qual = priv->spy_data.spy_stat[0].qual; + wstats->qual.level = priv->spy_data.spy_stat[0].level; + wstats->qual.noise = priv->spy_data.spy_stat[0].noise; + wstats->qual.updated = priv->spy_data.spy_stat[0].updated; } } else { struct { @@ -718,18 +718,13 @@ static inline int is_ethersnap(void *_hdr) static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - struct orinoco_private *priv = netdev_priv(dev); - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].level = level - 0x95; - priv->spy_stat[i].noise = noise - 0x95; - priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; - priv->spy_stat[i].updated = 7; - } + struct iw_quality wstats; + wstats.level = level - 0x95; + wstats.noise = noise - 0x95; + wstats.qual = (level > noise) ? (level - noise) : 0; + wstats.updated = 7; + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); } static void orinoco_stat_gather(struct net_device *dev, @@ -2458,8 +2453,11 @@ struct net_device *alloc_orinocodev(int sizeof_card, dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->get_stats = orinoco_get_stats; dev->ethtool_ops = &orinoco_ethtool_ops; - dev->get_wireless_stats = orinoco_get_wireless_stats; dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; +#ifdef WIRELESS_SPY + priv->wireless_data.spy_data = &priv->spy_data; + dev->wireless_data = &priv->wireless_data; +#endif dev->change_mtu = orinoco_change_mtu; dev->set_multicast_list = orinoco_set_multicast_list; /* we use the default eth_mac_addr for setting the MAC addr */ @@ -2831,7 +2829,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, } } - if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ /* Quality stats meaningless in ad-hoc mode */ } else { range->max_qual.qual = 0x8b - 0x2f; @@ -2878,6 +2876,14 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, range->min_r_time = 0; range->max_r_time = 65535 * 1000; /* ??? */ + /* Event capability (kernel) */ + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + /* Event capability (driver) */ + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + TRACE_EXIT(dev->name); return 0; @@ -3837,92 +3843,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Spy is used for link quality/strength measurements in Ad-Hoc mode - * Jean II */ -static int orinoco_ioctl_setspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) - -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number = srq->length; - int i; - unsigned long flags; - - /* Make sure nobody mess with the structure while we do */ - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* orinoco_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Now, let the others play */ - orinoco_unlock(priv, &flags); - - /* Do NOT call commit handler */ - return 0; -} - -static int orinoco_ioctl_getspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - number = priv->spy_number; - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - if (number > 0) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path might update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(extra + (sizeof(struct sockaddr) * number), - priv->spy_stat, sizeof(struct iw_quality) * number); - } - /* Reset updated flags. */ - for (i = 0; i < number; i++) - priv->spy_stat[i].updated = 0; - - orinoco_unlock(priv, &flags); - - srq->length = number; - - return 0; -} - /* Trigger a scan (look for other cells in the vicinity */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, @@ -4353,8 +4273,10 @@ static const iw_handler orinoco_handler[] = { [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy, - [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, @@ -4399,6 +4321,7 @@ static const struct iw_handler_def orinoco_handler_def = { .standard = orinoco_handler, .private = orinoco_private_handler, .private_args = orinoco_privtab, + .get_wireless_stats = orinoco_get_wireless_stats, }; static void orinoco_get_drvinfo(struct net_device *dev, diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 2f213a7103fe..c800563034a7 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "hermes.h" @@ -112,9 +113,8 @@ struct orinoco_private { u16 pm_on, pm_mcast, pm_period, pm_timeout; u16 preamble; #ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; + struct iw_spy_data spy_data; /* iwspy support */ + struct iw_public_data wireless_data; #endif /* Configuration dependent variables */ From 3173c8907ffb2c64456142da3df2bd0500bd59e0 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Sun, 11 Sep 2005 02:09:55 -0700 Subject: [PATCH 0033/1939] [PATCH] drivers/net: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan Cc: Jeff Garzik Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 3 +- drivers/net/hp100.c | 48 ++++++++--------------- drivers/net/irda/stir4200.c | 7 ++-- drivers/net/ixgb/ixgb_ethtool.c | 7 ++-- drivers/net/ns83820.c | 3 +- drivers/net/tokenring/ibmtr.c | 9 ++--- drivers/net/tokenring/olympic.c | 2 +- drivers/net/tokenring/tms380tr.c | 3 +- drivers/net/typhoon.c | 7 ++-- drivers/net/wan/cosa.c | 6 +-- drivers/net/wan/dscc4.c | 9 ++--- drivers/net/wan/farsync.c | 3 +- drivers/net/wireless/ipw2100.c | 17 +++----- drivers/net/wireless/prism54/islpci_dev.c | 6 +-- drivers/net/wireless/prism54/islpci_mgt.c | 5 +-- include/linux/ibmtr.h | 4 +- include/linux/netdevice.h | 6 +-- 17 files changed, 53 insertions(+), 92 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ebc20d9e7d7b..bd99c268e2da 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1029,8 +1029,7 @@ static void cp_reset_hw (struct cp_private *cp) if (!(cpr8(Cmd) & CmdReset)) return; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index cf0ac6fda1a1..b71fab6e34f4 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2517,10 +2517,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_after_eq(jiffies, time)) /* no signal->no logout */ @@ -2536,10 +2534,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); #ifdef HP100_DEBUG @@ -2577,10 +2573,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ @@ -2591,10 +2585,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_before_eq(time, jiffies)) { @@ -2606,10 +2598,8 @@ static int hp100_down_vg_link(struct net_device *dev) time = jiffies + (2 * HZ); /* This seems to take a while.... */ do { - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); return 0; @@ -2659,10 +2649,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); /* Start an addressed training and optionally request promiscuous port */ @@ -2697,10 +2685,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_before(jiffies, time)); if (time_after_eq(jiffies, time)) { @@ -2723,10 +2709,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) #endif break; } - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); } diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 15f207323d97..3961a754e920 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -678,10 +678,9 @@ static void turnaround_delay(const struct stir_cb *stir, long us) return; ticks = us / (1000000 / HZ); - if (ticks > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1 + ticks); - } else + if (ticks > 0) + schedule_timeout_interruptible(1 + ticks); + else udelay(us); } diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 319ee4cd70d8..04e47189d830 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -645,11 +645,10 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - if(data) - schedule_timeout(data * HZ); + if (data) + schedule_timeout_interruptible(data * HZ); else - schedule_timeout(MAX_SCHEDULE_TIMEOUT); + schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); del_timer_sync(&adapter->blink_timer); ixgb_led_off(&adapter->hw); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index e64df4d0800b..ed72a23c85dd 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1632,8 +1632,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab timed_out = 1; break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (status & fail) diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index e7b001017b9a..8154bbbb7792 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -318,7 +318,7 @@ static void ibmtr_cleanup_card(struct net_device *dev) if (dev->base_addr) { outb(0,dev->base_addr+ADAPTRESET); - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0,dev->base_addr+ADAPTRESETREL); } @@ -859,8 +859,7 @@ static int tok_init_card(struct net_device *dev) writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); outb(0, PIOaddr + ADAPTRESET); - current->state=TASK_UNINTERRUPTIBLE; - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0, PIOaddr + ADAPTRESETREL); #ifdef ENABLE_PAGING @@ -908,8 +907,8 @@ static int tok_open(struct net_device *dev) DPRINTK("Adapter is up and running\n"); return 0; } - current->state=TASK_INTERRUPTIBLE; - i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */ + i=schedule_timeout_interruptible(TR_RETRY_INTERVAL); + /* wait 30 seconds */ if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */ } outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 9e7923192a49..05477d24fd49 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1101,7 +1101,7 @@ static int olympic_close(struct net_device *dev) while(olympic_priv->srb_queued) { - t = schedule_timeout(60*HZ); + t = schedule_timeout_interruptible(60*HZ); if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 2e39bf1f7462..c1925590a0e1 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1243,8 +1243,7 @@ void tms380tr_wait(unsigned long time) tmp = jiffies + time/(1000000/HZ); do { - current->state = TASK_INTERRUPTIBLE; - tmp = schedule_timeout(tmp); + tmp = schedule_timeout_interruptible(tmp); } while(time_after(tmp, jiffies)); #else udelay(time); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index ecfa6f8805ce..4c76cb794bfb 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -419,10 +419,9 @@ typhoon_reset(void __iomem *ioaddr, int wait_type) TYPHOON_STATUS_WAITING_FOR_HOST) goto out; - if(wait_type == WaitSleep) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } else + if(wait_type == WaitSleep) + schedule_timeout_uninterruptible(1); + else udelay(TYPHOON_UDELAY); } diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7ff814fd65d0..ae9e897c255e 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -1617,8 +1617,7 @@ static int get_wait_data(struct cosa_data *cosa) return r; } /* sleep if not ready to read */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", cosa_getstatus(cosa)); @@ -1644,8 +1643,7 @@ static int put_wait_data(struct cosa_data *cosa, int data) } #if 0 /* sleep if not ready to read */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); #endif } printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 520a77a798e2..0c1ab4ac8bdb 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -542,8 +542,7 @@ static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv, msg, i); goto done; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); rmb(); } while (++i > 0); printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); @@ -588,8 +587,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) (dpriv->iqtx[cur] & Xpr)) break; smp_rmb(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } while (++i > 0); return (i >= 0 ) ? i : -EAGAIN; @@ -1035,8 +1033,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr) /* Flush posted writes */ readl(ioaddr + GSTAR); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); for (i = 0; i < 16; i++) pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]); diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 2c83cca34b86..10befb02d768 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -980,8 +980,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd) /* Wait for any previous command to complete */ while (mbval > NAK) { spin_unlock_irqrestore(&card->card_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&card->card_lock, flags); if (++safety > 2000) { diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 2414e6493aa5..e5cdb5bfabc8 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -800,8 +800,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, * doesn't seem to have as many firmware restart cycles... * * As a test, we're sticking in a 1/100s delay here */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100); + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); return 0; @@ -1256,8 +1255,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv) IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); i = 5000; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(40 * HZ / 1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(40)); /* Todo... wait for sync command ... */ read_register(priv->net_dev, IPW_REG_INTA, &inta); @@ -1411,8 +1409,7 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) (val2 & IPW2100_COMMAND_PHY_OFF)) return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_PHY_OFF_LOOP_DELAY); + schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); } return -EIO; @@ -1466,7 +1463,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv) static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) { -#define HW_POWER_DOWN_DELAY (HZ / 10) +#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) struct host_command cmd = { .host_command = HOST_PRE_POWER_DOWN, @@ -1520,10 +1517,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) printk(KERN_WARNING DRV_NAME ": " "%s: Power down command failed: Error %d\n", priv->net_dev->name, err); - else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_POWER_DOWN_DELAY); - } + else + schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); } priv->status &= ~STATUS_ENABLED; diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 6f13d4a8e2d3..10cce514c15d 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -439,8 +439,7 @@ prism54_bring_down(islpci_private *priv) wmb(); /* wait a while for the device to reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50*HZ/1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(50)); return 0; } @@ -491,8 +490,7 @@ islpci_reset_if(islpci_private *priv) /* The software reset acknowledge needs about 220 msec here. * Be conservative and wait for up to one second. */ - set_current_state(TASK_UNINTERRUPTIBLE); - remaining = schedule_timeout(HZ); + remaining = schedule_timeout_uninterruptible(HZ); if(remaining > 0) { result = 0; diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index b6f2e5a223be..4937a5ad4b2c 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -455,7 +455,7 @@ islpci_mgt_transaction(struct net_device *ndev, struct islpci_mgmtframe **recvframe) { islpci_private *priv = netdev_priv(ndev); - const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10); long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; int err; DEFINE_WAIT(wait); @@ -475,8 +475,7 @@ islpci_mgt_transaction(struct net_device *ndev, int timeleft; struct islpci_mgmtframe *frame; - set_current_state(TASK_UNINTERRUPTIBLE); - timeleft = schedule_timeout(wait_cycle_jiffies); + timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies); frame = xchg(&priv->mgmt_received, NULL); if (frame) { if (frame->header->oid == oid) { diff --git a/include/linux/ibmtr.h b/include/linux/ibmtr.h index 2ef0b21517fb..1c7a0dd5536a 100644 --- a/include/linux/ibmtr.h +++ b/include/linux/ibmtr.h @@ -7,8 +7,8 @@ /* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ #define TR_RETRY_INTERVAL (30*HZ) /* 500 on PC = 5 s */ -#define TR_RST_TIME (HZ/20) /* 5 on PC = 50 ms */ -#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ +#define TR_RST_TIME (msecs_to_jiffies(50)) /* 5 on PC = 50 ms */ +#define TR_BUSY_INTERVAL (msecs_to_jiffies(200)) /* 5 on PC = 200 ms */ #define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ #define TR_ISA 1 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7c717907896d..98c98e6cd4f3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -852,11 +852,9 @@ static inline void netif_rx_complete(struct net_device *dev) static inline void netif_poll_disable(struct net_device *dev) { - while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) { + while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) /* No hurry. */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } + schedule_timeout_interruptible(1); } static inline void netif_poll_enable(struct net_device *dev) From 8e18d1f9c9dcbf2de5b79cad771ed639983ab6cd Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 10 Sep 2005 14:45:00 -0700 Subject: [PATCH 0034/1939] [PATCH] Replace drivers/net/wan custom ctype macros with standard ones Replace the custom is_digit()/is_hex_digit() macros with isdigit()/isxdigit() from Additionaly remove unused macro is_alpha() from Signed-off-by: Tobias Klauser Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/wan/cycx_x25.c | 5 +++-- drivers/net/wan/sdla_fr.c | 4 ++-- drivers/net/wan/sdla_x25.c | 8 ++++---- include/linux/cyclomx.h | 2 -- include/linux/wanpipe.h | 9 --------- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 02d57c0b4243..a631d1c2fa14 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -78,6 +78,7 @@ #define CYCLOMX_X25_DEBUG 1 +#include /* isdigit() */ #include /* return codes */ #include /* ARPHRD_HWX25 */ #include /* printk(), and other useful stuff */ @@ -418,7 +419,7 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, /* Set channel timeouts (default if not specified) */ chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; - } else if (is_digit(conf->addr[0])) { /* PVC */ + } else if (isdigit(conf->addr[0])) { /* PVC */ s16 lcn = dec_to_uint(conf->addr, 0); if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) @@ -1531,7 +1532,7 @@ static unsigned dec_to_uint(u8 *str, int len) if (!len) len = strlen(str); - for (; len && is_digit(*str); ++str, --len) + for (; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned) '0'); return val; diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 0497dbdb8631..7f1ce9d4333e 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -822,7 +822,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->card = card; /* verify media address */ - if (is_digit(conf->addr[0])) { + if (isdigit(conf->addr[0])) { dlci = dec_to_uint(conf->addr, 0); @@ -3456,7 +3456,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c index 8a95d61a2f8f..63f846d6f3a6 100644 --- a/drivers/net/wan/sdla_x25.c +++ b/drivers/net/wan/sdla_x25.c @@ -957,7 +957,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - }else if (is_digit(conf->addr[0])){ /* PVC */ + }else if (isdigit(conf->addr[0])){ /* PVC */ int lcn = dec_to_uint(conf->addr, 0); if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ @@ -3875,7 +3875,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; @@ -3896,9 +3896,9 @@ static unsigned int hex_to_uint (unsigned char* str, int len) for (val = 0; len; ++str, --len) { ch = *str; - if (is_digit(ch)) + if (isdigit(ch)) val = (val << 4) + (ch - (unsigned)'0'); - else if (is_hex_digit(ch)) + else if (isxdigit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); else break; } diff --git a/include/linux/cyclomx.h b/include/linux/cyclomx.h index 04fa7dff079c..300d704bdb9a 100644 --- a/include/linux/cyclomx.h +++ b/include/linux/cyclomx.h @@ -37,8 +37,6 @@ #include #endif -#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0) - /* Adapter Data Space. * This structure is needed because we handle multiple cards, otherwise * static data would do it. diff --git a/include/linux/wanpipe.h b/include/linux/wanpipe.h index 167d956c492b..dae9860091dd 100644 --- a/include/linux/wanpipe.h +++ b/include/linux/wanpipe.h @@ -265,15 +265,6 @@ typedef struct { #include #include - -#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0) -#define is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\ - ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0) -#define is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\ - ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\ - ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0) - - /****** Data Structures *****************************************************/ /* Adapter Data Space. From 7665a08928f241247afe8c76865cdbe4ef5489bf Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 9 Sep 2005 23:17:28 -0700 Subject: [PATCH 0035/1939] [PATCH] drivers/net/wan/: possible cleanups This patch contains possible cleanups including the following: - make needlessly global code static - #if 0 the following unused global function: - sdladrv.c: sdla_intde - remove the following unused global variable: - lmc_media.c: lmc_t1_cables - remove the following unneeded EXPORT_SYMBOL's: - cycx_drv.c: cycx_inten - sdladrv.c: sdla_inten - sdladrv.c: sdla_intde - sdladrv.c: sdla_intack - sdladrv.c: sdla_intr - syncppp.c: sppp_input - syncppp.c: sppp_change_mtu Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/wan/cycx_drv.c | 7 ++- drivers/net/wan/cycx_main.c | 2 +- drivers/net/wan/dscc4.c | 14 +++--- drivers/net/wan/farsync.c | 24 ++++----- drivers/net/wan/hdlc_fr.c | 2 +- drivers/net/wan/lmc/lmc_debug.c | 12 ++--- drivers/net/wan/lmc/lmc_media.c | 8 --- drivers/net/wan/pc300.h | 16 ------ drivers/net/wan/pc300_drv.c | 87 +++++++++++++++++---------------- drivers/net/wan/pc300_tty.c | 18 +++---- drivers/net/wan/sdla.c | 20 ++++---- drivers/net/wan/sdladrv.c | 16 +++--- drivers/net/wan/syncppp.c | 10 ++-- include/linux/cycx_drv.h | 1 - include/linux/sdladrv.h | 4 -- include/net/syncppp.h | 1 - 16 files changed, 102 insertions(+), 140 deletions(-) diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index 9e56fc346ba4..e6d005726aad 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -109,7 +109,7 @@ static long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; * < 0 error. * Context: process */ -int __init cycx_drv_init(void) +static int __init cycx_drv_init(void) { printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); @@ -119,7 +119,7 @@ int __init cycx_drv_init(void) /* Module 'remove' entry point. * o release all remaining system resources */ -void cycx_drv_cleanup(void) +static void cycx_drv_cleanup(void) { } @@ -184,8 +184,7 @@ int cycx_down(struct cycx_hw *hw) } /* Enable interrupt generation. */ -EXPORT_SYMBOL(cycx_inten); -void cycx_inten(struct cycx_hw *hw) +static void cycx_inten(struct cycx_hw *hw) { writeb(0, hw->dpmbase); } diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 7b48064364dc..430b1f630fb4 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -103,7 +103,7 @@ static struct cycx_device *cycx_card_array; /* adapter data space */ * < 0 error. * Context: process */ -int __init cycx_init(void) +static int __init cycx_init(void) { int cnt, err = -ENOMEM; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 0c1ab4ac8bdb..2f61a47b4716 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -446,8 +446,8 @@ static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv, return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda; } -int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, - const char *msg) +static int state_check(u32 state, struct dscc4_dev_priv *dpriv, + struct net_device *dev, const char *msg) { int ret = 0; @@ -466,8 +466,9 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, return ret; } -void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv, - char *msg) +static void dscc4_tx_print(struct net_device *dev, + struct dscc4_dev_priv *dpriv, + char *msg) { printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n", dev->name, dpriv->tx_current, dpriv->tx_dirty, msg); @@ -507,7 +508,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) } } -inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev) +static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, + struct net_device *dev) { unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE; struct RxFD *rx_fd = dpriv->rx_fd + dirty; @@ -1891,7 +1893,7 @@ static void dscc4_rx_irq(struct dscc4_pci_priv *priv, * It failed and locked solid. Thus the introduction of a dummy skb. * Problem is acknowledged in errata sheet DS5. Joy :o/ */ -struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) +static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) { struct sk_buff *skb; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 10befb02d768..7981a2c7906e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -74,11 +74,11 @@ MODULE_LICENSE("GPL"); /* * Modules parameters and associated varaibles */ -int fst_txq_low = FST_LOW_WATER_MARK; -int fst_txq_high = FST_HIGH_WATER_MARK; -int fst_max_reads = 7; -int fst_excluded_cards = 0; -int fst_excluded_list[FST_MAX_CARDS]; +static int fst_txq_low = FST_LOW_WATER_MARK; +static int fst_txq_high = FST_HIGH_WATER_MARK; +static int fst_max_reads = 7; +static int fst_excluded_cards = 0; +static int fst_excluded_list[FST_MAX_CARDS]; module_param(fst_txq_low, int, 0); module_param(fst_txq_high, int, 0); @@ -572,13 +572,13 @@ static void do_bottom_half_rx(struct fst_card_info *card); static void fst_process_tx_work_q(unsigned long work_q); static void fst_process_int_work_q(unsigned long work_q); -DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); -DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); +static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); +static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); -struct fst_card_info *fst_card_array[FST_MAX_CARDS]; -spinlock_t fst_work_q_lock; -u64 fst_work_txq; -u64 fst_work_intq; +static struct fst_card_info *fst_card_array[FST_MAX_CARDS]; +static spinlock_t fst_work_q_lock; +static u64 fst_work_txq; +static u64 fst_work_intq; static void fst_q_work_item(u64 * queue, int card_index) @@ -1497,7 +1497,7 @@ do_bottom_half_rx(struct fst_card_info *card) * The interrupt service routine * Dev_id is our fst_card_info pointer */ -irqreturn_t +static irqreturn_t fst_intr(int irq, void *dev_id, struct pt_regs *regs) { struct fst_card_info *card; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index a5d6891c9d4c..e1601d35dced 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -330,7 +330,7 @@ static int pvc_close(struct net_device *dev) -int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { pvc_device *pvc = dev_to_pvc(dev); fr_proto_pvc_info info; diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c index 9dccd9546a17..3b94352b0d03 100644 --- a/drivers/net/wan/lmc/lmc_debug.c +++ b/drivers/net/wan/lmc/lmc_debug.c @@ -8,10 +8,10 @@ /* * Prints out len, max to 80 octets using printk, 20 per line */ -void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) -{ #ifdef DEBUG #ifdef LMC_PACKET_LOG +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) +{ int iNewLine = 1; char str[80], *pstr; @@ -43,26 +43,24 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) } sprintf(pstr, "\n"); printk(str); -#endif -#endif } +#endif +#endif #ifdef DEBUG u_int32_t lmcEventLogIndex = 0; u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; -#endif void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) { -#ifdef DEBUG lmcEventLogBuf[lmcEventLogIndex++] = EventNum; lmcEventLogBuf[lmcEventLogIndex++] = arg2; lmcEventLogBuf[lmcEventLogIndex++] = arg3; lmcEventLogBuf[lmcEventLogIndex++] = jiffies; lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1; -#endif } +#endif /* DEBUG */ void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index f55ce76b00ed..af8b55fdd9d9 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -47,14 +47,6 @@ * of the GNU General Public License version 2, incorporated herein by reference. */ -/* - * For lack of a better place, put the SSI cable stuff here. - */ -char *lmc_t1_cables[] = { - "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35", - "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL -}; - /* * protocol independent method. */ diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index 73401b0f0151..2024b26b99e6 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -472,24 +472,8 @@ enum pc300_loopback_cmds { #ifdef __KERNEL__ /* Function Prototypes */ -int dma_buf_write(pc300_t *, int, ucchar *, int); -int dma_buf_read(pc300_t *, int, struct sk_buff *); void tx_dma_start(pc300_t *, int); -void rx_dma_start(pc300_t *, int); -void tx_dma_stop(pc300_t *, int); -void rx_dma_stop(pc300_t *, int); -int cpc_queue_xmit(struct sk_buff *, struct net_device *); -void cpc_net_rx(struct net_device *); -void cpc_sca_status(pc300_t *, int); -int cpc_change_mtu(struct net_device *, int); -int cpc_ioctl(struct net_device *, struct ifreq *, int); -int ch_config(pc300dev_t *); -int rx_config(pc300dev_t *); -int tx_config(pc300dev_t *); -void cpc_opench(pc300dev_t *); -void cpc_closech(pc300dev_t *); int cpc_open(struct net_device *dev); -int cpc_close(struct net_device *dev); int cpc_set_media(hdlc_device *, int); #endif /* __KERNEL__ */ diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 3e7753b10717..a3e65d1bc19b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -291,6 +291,7 @@ static uclong detect_ram(pc300_t *); static void plx_init(pc300_t *); static void cpc_trace(struct net_device *, struct sk_buff *, char); static int cpc_attach(struct net_device *, unsigned short, unsigned short); +static int cpc_close(struct net_device *dev); #ifdef CONFIG_PC300_MLPPP void cpc_tty_init(pc300dev_t * dev); @@ -437,7 +438,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch) printk("\n"); } -int dma_get_rx_frame_size(pc300_t * card, int ch) +static int dma_get_rx_frame_size(pc300_t * card, int ch) { volatile pcsca_bd_t __iomem *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; @@ -462,7 +463,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) * dma_buf_write: writes a frame to the Tx DMA buffers * NOTE: this function writes one frame at a time. */ -int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) +static int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) { int i, nchar; volatile pcsca_bd_t __iomem *ptdescr; @@ -503,7 +504,7 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) * dma_buf_read: reads a frame from the Rx DMA buffers * NOTE: this function reads one frame at a time. */ -int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) +static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) { int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -560,7 +561,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) return (rcvd); } -void tx_dma_stop(pc300_t * card, int ch) +static void tx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); @@ -571,7 +572,7 @@ void tx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_stop(pc300_t * card, int ch) +static void rx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); @@ -582,7 +583,7 @@ void rx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_start(pc300_t * card, int ch) +static void rx_dma_start(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -607,7 +608,7 @@ void rx_dma_start(pc300_t * card, int ch) /*************************/ /*** FALC Routines ***/ /*************************/ -void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) +static void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) { void __iomem *falcbase = card->hw.falcbase; unsigned long i = 0; @@ -622,7 +623,7 @@ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) cpc_writeb(falcbase + F_REG(CMDR, ch), cmd); } -void falc_intr_enable(pc300_t * card, int ch) +static void falc_intr_enable(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -672,7 +673,7 @@ void falc_intr_enable(pc300_t * card, int ch) } } -void falc_open_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_open_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -688,7 +689,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot) (0x80 >> (timeslot & 0x07))); } -void falc_close_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_close_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -704,7 +705,7 @@ void falc_close_timeslot(pc300_t * card, int ch, int timeslot) ~(0x80 >> (timeslot & 0x07))); } -void falc_close_all_timeslots(pc300_t * card, int ch) +static void falc_close_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -726,7 +727,7 @@ void falc_close_all_timeslots(pc300_t * card, int ch) } } -void falc_open_all_timeslots(pc300_t * card, int ch) +static void falc_open_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -758,7 +759,7 @@ void falc_open_all_timeslots(pc300_t * card, int ch) } } -void falc_init_timeslot(pc300_t * card, int ch) +static void falc_init_timeslot(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -776,7 +777,7 @@ void falc_init_timeslot(pc300_t * card, int ch) } } -void falc_enable_comm(pc300_t * card, int ch) +static void falc_enable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -792,7 +793,7 @@ void falc_enable_comm(pc300_t * card, int ch) ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_disable_comm(pc300_t * card, int ch) +static void falc_disable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -806,7 +807,7 @@ void falc_disable_comm(pc300_t * card, int ch) ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_init_t1(pc300_t * card, int ch) +static void falc_init_t1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -975,7 +976,7 @@ void falc_init_t1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_e1(pc300_t * card, int ch) +static void falc_init_e1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1155,7 +1156,7 @@ void falc_init_e1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_hdlc(pc300_t * card, int ch) +static void falc_init_hdlc(pc300_t * card, int ch) { void __iomem *falcbase = card->hw.falcbase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -1181,7 +1182,7 @@ void falc_init_hdlc(pc300_t * card, int ch) falc_intr_enable(card, ch); } -void te_config(pc300_t * card, int ch) +static void te_config(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1241,7 +1242,7 @@ void te_config(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -void falc_check_status(pc300_t * card, int ch, unsigned char frs0) +static void falc_check_status(pc300_t * card, int ch, unsigned char frs0) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1397,7 +1398,7 @@ void falc_check_status(pc300_t * card, int ch, unsigned char frs0) } } -void falc_update_stats(pc300_t * card, int ch) +static void falc_update_stats(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1450,7 +1451,7 @@ void falc_update_stats(pc300_t * card, int ch) * the synchronizer and then sent to the system interface. *---------------------------------------------------------------------------- */ -void falc_remote_loop(pc300_t * card, int ch, int loop_on) +static void falc_remote_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1495,7 +1496,7 @@ void falc_remote_loop(pc300_t * card, int ch, int loop_on) * coding must be identical. *---------------------------------------------------------------------------- */ -void falc_local_loop(pc300_t * card, int ch, int loop_on) +static void falc_local_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1522,7 +1523,7 @@ void falc_local_loop(pc300_t * card, int ch, int loop_on) * looped. They are originated by the FALC-LH transmitter. *---------------------------------------------------------------------------- */ -void falc_payload_loop(pc300_t * card, int ch, int loop_on) +static void falc_payload_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1576,7 +1577,7 @@ void falc_payload_loop(pc300_t * card, int ch, int loop_on) * Description: Turns XLU bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xlu(pc300_t * card, int ch) +static void turn_off_xlu(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1597,7 +1598,7 @@ void turn_off_xlu(pc300_t * card, int ch) * Description: Turns XLD bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xld(pc300_t * card, int ch) +static void turn_off_xld(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1619,7 +1620,7 @@ void turn_off_xld(pc300_t * card, int ch) * to generate a LOOP activation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_up_code(pc300_t * card, int ch) +static void falc_generate_loop_up_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1652,7 +1653,7 @@ void falc_generate_loop_up_code(pc300_t * card, int ch) * to generate a LOOP deactivation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_down_code(pc300_t * card, int ch) +static void falc_generate_loop_down_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1682,7 +1683,7 @@ void falc_generate_loop_down_code(pc300_t * card, int ch) * it on the reception side. *---------------------------------------------------------------------------- */ -void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) +static void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1729,7 +1730,7 @@ void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) * Description: This routine returns the bit error counter value *---------------------------------------------------------------------------- */ -ucshort falc_pattern_test_error(pc300_t * card, int ch) +static ucshort falc_pattern_test_error(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1769,7 +1770,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) netif_rx(skb); } -void cpc_tx_timeout(struct net_device *dev) +static void cpc_tx_timeout(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1797,7 +1798,7 @@ void cpc_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) +static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1880,7 +1881,7 @@ int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -void cpc_net_rx(struct net_device *dev) +static void cpc_net_rx(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -2403,7 +2404,7 @@ static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void cpc_sca_status(pc300_t * card, int ch) +static void cpc_sca_status(pc300_t * card, int ch) { ucchar ilar; void __iomem *scabase = card->hw.scabase; @@ -2495,7 +2496,7 @@ void cpc_sca_status(pc300_t * card, int ch) } } -void cpc_falc_status(pc300_t * card, int ch) +static void cpc_falc_status(pc300_t * card, int ch) { pc300ch_t *chan = &card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -2523,7 +2524,7 @@ void cpc_falc_status(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -int cpc_change_mtu(struct net_device *dev, int new_mtu) +static int cpc_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU)) return -EINVAL; @@ -2531,7 +2532,7 @@ int cpc_change_mtu(struct net_device *dev, int new_mtu) return 0; } -int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; @@ -2856,7 +2857,7 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io) } } -int ch_config(pc300dev_t * d) +static int ch_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -3004,7 +3005,7 @@ int ch_config(pc300dev_t * d) return 0; } -int rx_config(pc300dev_t * d) +static int rx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3035,7 +3036,7 @@ int rx_config(pc300dev_t * d) return 0; } -int tx_config(pc300dev_t * d) +static int tx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3098,7 +3099,7 @@ static int cpc_attach(struct net_device *dev, unsigned short encoding, return 0; } -void cpc_opench(pc300dev_t * d) +static void cpc_opench(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3116,7 +3117,7 @@ void cpc_opench(pc300dev_t * d) cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR)); } -void cpc_closech(pc300dev_t * d) +static void cpc_closech(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3173,7 +3174,7 @@ int cpc_open(struct net_device *dev) return 0; } -int cpc_close(struct net_device *dev) +static int cpc_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 8454bf6caaa7..52f26b9c69d2 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -112,10 +112,10 @@ typedef struct _st_cpc_tty_area { static struct tty_driver serial_drv; /* local variables */ -st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; +static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; -int cpc_tty_cnt=0; /* number of intrfaces configured with MLPPP */ -int cpc_tty_unreg_flag = 0; +static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */ +static int cpc_tty_unreg_flag = 0; /* TTY functions prototype */ static int cpc_tty_open(struct tty_struct *tty, struct file *flip); @@ -132,9 +132,9 @@ static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); -int pc300_tiocmset(struct tty_struct *, struct file *, - unsigned int, unsigned int); -int pc300_tiocmget(struct tty_struct *, struct file *); +static int pc300_tiocmset(struct tty_struct *, struct file *, + unsigned int, unsigned int); +static int pc300_tiocmget(struct tty_struct *, struct file *); /* functions called by PC300 driver */ void cpc_tty_init(pc300dev_t *dev); @@ -538,8 +538,8 @@ static int cpc_tty_chars_in_buffer(struct tty_struct *tty) return(0); } -int pc300_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static int pc300_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { st_cpc_tty_area *cpc_tty; @@ -565,7 +565,7 @@ int pc300_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -int pc300_tiocmget(struct tty_struct *tty, struct file *file) +static int pc300_tiocmget(struct tty_struct *tty, struct file *file) { unsigned int result; unsigned char status; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 3ac9a45b20fa..036adc4f8ba7 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -182,7 +182,7 @@ static char sdla_byte(struct net_device *dev, int addr) return(byte); } -void sdla_stop(struct net_device *dev) +static void sdla_stop(struct net_device *dev) { struct frad_local *flp; @@ -209,7 +209,7 @@ void sdla_stop(struct net_device *dev) } } -void sdla_start(struct net_device *dev) +static void sdla_start(struct net_device *dev) { struct frad_local *flp; @@ -247,7 +247,7 @@ void sdla_start(struct net_device *dev) * ***************************************************/ -int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) +static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) { unsigned long start, done, now; char resp, *temp; @@ -505,7 +505,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, static int sdla_reconfig(struct net_device *dev); -int sdla_activate(struct net_device *slave, struct net_device *master) +static int sdla_activate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -527,7 +527,7 @@ int sdla_activate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deactivate(struct net_device *slave, struct net_device *master) +static int sdla_deactivate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -549,7 +549,7 @@ int sdla_deactivate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_assoc(struct net_device *slave, struct net_device *master) +static int sdla_assoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -585,7 +585,7 @@ int sdla_assoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deassoc(struct net_device *slave, struct net_device *master) +static int sdla_deassoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -613,7 +613,7 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) +static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) { struct frad_local *flp; struct dlci_local *dlp; @@ -1324,7 +1324,7 @@ NOTE: This is rather a useless action right now, as the return(0); } -int sdla_change_mtu(struct net_device *dev, int new_mtu) +static int sdla_change_mtu(struct net_device *dev, int new_mtu) { struct frad_local *flp; @@ -1337,7 +1337,7 @@ int sdla_change_mtu(struct net_device *dev, int new_mtu) return(-EOPNOTSUPP); } -int sdla_set_config(struct net_device *dev, struct ifmap *map) +static int sdla_set_config(struct net_device *dev, struct ifmap *map) { struct frad_local *flp; int i; diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index c8bc6da57a41..7c2cf2e76300 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -642,9 +642,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) * Enable interrupt generation. */ -EXPORT_SYMBOL(sdla_inten); - -int sdla_inten (sdlahw_t* hw) +static int sdla_inten (sdlahw_t* hw) { unsigned port = hw->port; int tmp, i; @@ -698,8 +696,7 @@ int sdla_inten (sdlahw_t* hw) * Disable interrupt generation. */ -EXPORT_SYMBOL(sdla_intde); - +#if 0 int sdla_intde (sdlahw_t* hw) { unsigned port = hw->port; @@ -748,14 +745,13 @@ int sdla_intde (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Acknowledge SDLA hardware interrupt. */ -EXPORT_SYMBOL(sdla_intack); - -int sdla_intack (sdlahw_t* hw) +static int sdla_intack (sdlahw_t* hw) { unsigned port = hw->port; int tmp; @@ -827,8 +823,7 @@ void read_S514_int_stat (sdlahw_t* hw, u32* int_status) * Generate an interrupt to adapter's CPU. */ -EXPORT_SYMBOL(sdla_intr); - +#if 0 int sdla_intr (sdlahw_t* hw) { unsigned port = hw->port; @@ -863,6 +858,7 @@ int sdla_intr (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Execute Adapter Command. diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index b56a7b516d24..3731b22f6757 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -221,7 +221,7 @@ static void sppp_clear_timeout(struct sppp *p) * here. */ -void sppp_input (struct net_device *dev, struct sk_buff *skb) +static void sppp_input (struct net_device *dev, struct sk_buff *skb) { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); @@ -355,8 +355,6 @@ void sppp_input (struct net_device *dev, struct sk_buff *skb) return; } -EXPORT_SYMBOL(sppp_input); - /* * Handle transmit packets. */ @@ -990,7 +988,7 @@ EXPORT_SYMBOL(sppp_reopen); * the mtu is out of range. */ -int sppp_change_mtu(struct net_device *dev, int new_mtu) +static int sppp_change_mtu(struct net_device *dev, int new_mtu) { if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) return -EINVAL; @@ -998,8 +996,6 @@ int sppp_change_mtu(struct net_device *dev, int new_mtu) return 0; } -EXPORT_SYMBOL(sppp_change_mtu); - /** * sppp_do_ioctl - Ioctl handler for ppp/hdlc * @dev: Device subject to ioctl @@ -1456,7 +1452,7 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t return 0; } -struct packet_type sppp_packet_type = { +static struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, }; diff --git a/include/linux/cycx_drv.h b/include/linux/cycx_drv.h index 6621df86a748..12fe6b0bfcff 100644 --- a/include/linux/cycx_drv.h +++ b/include/linux/cycx_drv.h @@ -60,6 +60,5 @@ extern int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len); extern int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len); extern int cycx_exec(void __iomem *addr); -extern void cycx_inten(struct cycx_hw *hw); extern void cycx_intr(struct cycx_hw *hw); #endif /* _CYCX_DRV_H */ diff --git a/include/linux/sdladrv.h b/include/linux/sdladrv.h index 78f634007fc6..c85e103d5e7b 100644 --- a/include/linux/sdladrv.h +++ b/include/linux/sdladrv.h @@ -52,12 +52,8 @@ typedef struct sdlahw extern int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len); extern int sdla_down (sdlahw_t* hw); -extern int sdla_inten (sdlahw_t* hw); -extern int sdla_intde (sdlahw_t* hw); -extern int sdla_intack (sdlahw_t* hw); extern void S514_intack (sdlahw_t* hw, u32 int_status); extern void read_S514_int_stat (sdlahw_t* hw, u32* int_status); -extern int sdla_intr (sdlahw_t* hw); extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr); extern int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len); diff --git a/include/net/syncppp.h b/include/net/syncppp.h index 614cb6ba564e..877efa434700 100644 --- a/include/net/syncppp.h +++ b/include/net/syncppp.h @@ -86,7 +86,6 @@ static inline struct sppp *sppp_of(struct net_device *dev) void sppp_attach (struct ppp_device *pd); void sppp_detach (struct net_device *dev); -void sppp_input (struct net_device *dev, struct sk_buff *m); int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); struct sk_buff *sppp_dequeue (struct net_device *dev); int sppp_isempty (struct net_device *dev); From 387d890db88b4eb7c1dd55a2a0c16d6f0dccc7ad Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" Date: Fri, 9 Sep 2005 17:22:14 +0100 Subject: [PATCH 0036/1939] [PATCH] lne390 bogus casts We already have the iomem pointer we need... Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/lne390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 27f0d8ac4c40..309d254842cf 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -298,7 +298,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) return 0; unmap: if (ei_status.reg0) - iounmap((void *)dev->mem_start); + iounmap(ei_status.mem); cleanup: free_irq(dev->irq, dev); return ret; From 7a700fafbed55eee2cc766fbe47cf68e229da281 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" Date: Fri, 9 Sep 2005 20:40:23 +0100 Subject: [PATCH 0037/1939] [PATCH] C99 initializers in ray_cs.c Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/wireless/ray_cs.c | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e9c5ea0f5535..70fd6fd8feb9 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1649,28 +1649,28 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev) */ static const iw_handler ray_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit, - [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) ray_get_name, - [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) ray_set_freq, - [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) ray_get_freq, - [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) ray_set_mode, - [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) ray_get_mode, - [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range, + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) ray_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) ray_get_name, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) ray_set_freq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) ray_get_freq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) ray_set_mode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) ray_get_mode, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) ray_get_range, #ifdef WIRELESS_SPY - [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_set_spy, - [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_get_spy, - [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy, - [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, #endif /* WIRELESS_SPY */ - [SIOCGIWAP -SIOCIWFIRST] (iw_handler) ray_get_wap, - [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid, - [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid, - [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) ray_set_rate, - [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) ray_get_rate, - [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) ray_set_rts, - [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) ray_get_rts, - [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) ray_set_frag, - [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) ray_get_frag, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) ray_get_wap, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) ray_set_essid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) ray_get_essid, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) ray_set_rate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) ray_get_rate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) ray_set_rts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) ray_get_rts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) ray_set_frag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) ray_get_frag, }; #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ @@ -1678,9 +1678,9 @@ static const iw_handler ray_handler[] = { #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ static const iw_handler ray_private_handler[] = { - [0] (iw_handler) ray_set_framing, - [1] (iw_handler) ray_get_framing, - [3] (iw_handler) ray_get_country, + [0] = (iw_handler) ray_set_framing, + [1] = (iw_handler) ray_get_framing, + [3] = (iw_handler) ray_get_country, }; static const struct iw_priv_args ray_private_args[] = { From 43ec6e95e4d8a73afc2405a44b955c380aeeb65a Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Tue, 23 Aug 2005 10:30:29 -0700 Subject: [PATCH 0038/1939] [PATCH] mii: Add test for GigE support Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mii.c | 15 +++++++++++++++ include/linux/mii.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/net/mii.c b/drivers/net/mii.c index c33cb3dc942b..e42aa797f08b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -207,6 +207,20 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } +int mii_check_gmii_support(struct mii_if_info *mii) +{ + int reg; + + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (reg & BMSR_ESTATEN) { + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS); + if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) + return 1; + } + + return 0; +} + int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -394,5 +408,6 @@ EXPORT_SYMBOL(mii_ethtool_gset); EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_media); +EXPORT_SYMBOL(mii_check_gmii_support); EXPORT_SYMBOL(generic_mii_ioctl); diff --git a/include/linux/mii.h b/include/linux/mii.h index 9b8d0476988a..68f5a0f392dd 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -158,6 +158,7 @@ extern int mii_link_ok (struct mii_if_info *mii); extern int mii_nway_restart (struct mii_if_info *mii); extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); +extern int mii_check_gmii_support(struct mii_if_info *mii); extern void mii_check_link (struct mii_if_info *mii); extern unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, From f89efd523b25cc1702e074dafdcac283da657002 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 9 Sep 2005 12:10:10 -0700 Subject: [PATCH 0039/1939] [PATCH] Add rapidio net driver Adds an "Ethernet" driver which sends Ethernet packets over the standard RapidIO messaging. This depends on the core RIO patch for mailbox/doorbell access. Signed-off-by: Matt Porter Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 14 ++ drivers/net/Makefile | 1 + drivers/net/rionet.c | 574 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 589 insertions(+) create mode 100644 drivers/net/rionet.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 54fff9c2e802..82603e419d76 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2235,6 +2235,20 @@ config ISERIES_VETH tristate "iSeries Virtual Ethernet driver support" depends on PPC_ISERIES +config RIONET + tristate "RapidIO Ethernet over messaging driver support" + depends on NETDEVICES && RAPIDIO + +config RIONET_TX_SIZE + int "Number of outbound queue entries" + depends on RIONET + default "128" + +config RIONET_RX_SIZE + int "Number of inbound queue entries" + depends on RIONET + default "128" + config FDDI bool "FDDI driver support" depends on (PCI || EISA) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8645c843cf4d..e6acba68923a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o +obj-$(CONFIG_RIONET) += rionet.o # # end link order section diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c new file mode 100644 index 000000000000..12cde0604580 --- /dev/null +++ b/drivers/net/rionet.c @@ -0,0 +1,574 @@ +/* + * rionet - Ethernet driver over RapidIO messaging services + * + * Copyright 2005 MontaVista Software, Inc. + * Matt Porter + * + * 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 + +#define DRV_NAME "rionet" +#define DRV_VERSION "0.2" +#define DRV_AUTHOR "Matt Porter " +#define DRV_DESC "Ethernet over RapidIO" + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); + +#define RIONET_DEFAULT_MSGLEVEL \ + (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + +#define RIONET_DOORBELL_JOIN 0x1000 +#define RIONET_DOORBELL_LEAVE 0x1001 + +#define RIONET_MAILBOX 0 + +#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE +#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE + +static LIST_HEAD(rionet_peers); + +struct rionet_private { + struct rio_mport *mport; + struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; + struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; + struct net_device_stats stats; + int rx_slot; + int tx_slot; + int tx_cnt; + int ack_slot; + spinlock_t lock; + spinlock_t tx_lock; + u32 msg_enable; +}; + +struct rionet_peer { + struct list_head node; + struct rio_dev *rdev; + struct resource *res; +}; + +static int rionet_check = 0; +static int rionet_capable = 1; + +/* + * This is a fast lookup table for for translating TX + * Ethernet packets into a destination RIO device. It + * could be made into a hash table to save memory depending + * on system trade-offs. + */ +static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; + +#define is_rionet_capable(pef, src_ops, dst_ops) \ + ((pef & RIO_PEF_INB_MBOX) && \ + (pef & RIO_PEF_INB_DOORBELL) && \ + (src_ops & RIO_SRC_OPS_DOORBELL) && \ + (dst_ops & RIO_DST_OPS_DOORBELL)) +#define dev_rionet_capable(dev) \ + is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops) + +#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) +#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) + +static struct net_device_stats *rionet_stats(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + return &rnet->stats; +} + +static int rionet_rx_clean(struct net_device *ndev) +{ + int i; + int error = 0; + struct rionet_private *rnet = ndev->priv; + void *data; + + i = rnet->rx_slot; + + do { + if (!rnet->rx_skb[i]) + continue; + + if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX))) + break; + + rnet->rx_skb[i]->data = data; + skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); + rnet->rx_skb[i]->dev = ndev; + rnet->rx_skb[i]->protocol = + eth_type_trans(rnet->rx_skb[i], ndev); + error = netif_rx(rnet->rx_skb[i]); + + if (error == NET_RX_DROP) { + rnet->stats.rx_dropped++; + } else if (error == NET_RX_BAD) { + if (netif_msg_rx_err(rnet)) + printk(KERN_WARNING "%s: bad rx packet\n", + DRV_NAME); + rnet->stats.rx_errors++; + } else { + rnet->stats.rx_packets++; + rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; + } + + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); + + return i; +} + +static void rionet_rx_fill(struct net_device *ndev, int end) +{ + int i; + struct rionet_private *rnet = ndev->priv; + + i = rnet->rx_slot; + do { + rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE); + + if (!rnet->rx_skb[i]) + break; + + rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX, + rnet->rx_skb[i]->data); + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end); + + rnet->rx_slot = i; +} + +static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, + struct rio_dev *rdev) +{ + struct rionet_private *rnet = ndev->priv; + + rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); + rnet->tx_skb[rnet->tx_slot] = skb; + + rnet->stats.tx_packets++; + rnet->stats.tx_bytes += skb->len; + + if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) + netif_stop_queue(ndev); + + ++rnet->tx_slot; + rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1); + + if (netif_msg_tx_queued(rnet)) + printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME, + (u32) skb, skb->len); + + return 0; +} + +static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int i; + struct rionet_private *rnet = ndev->priv; + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 destid; + unsigned long flags; + + local_irq_save(flags); + if (!spin_trylock(&rnet->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { + netif_stop_queue(ndev); + spin_unlock_irqrestore(&rnet->tx_lock, flags); + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", + ndev->name); + return NETDEV_TX_BUSY; + } + + if (eth->h_dest[0] & 0x01) { + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) + if (rionet_active[i]) + rionet_queue_tx_msg(skb, ndev, + rionet_active[i]); + } else if (RIONET_MAC_MATCH(eth->h_dest)) { + destid = RIONET_GET_DESTID(eth->h_dest); + if (rionet_active[destid]) + rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); + } + + spin_unlock_irqrestore(&rnet->tx_lock, flags); + + return 0; +} + +static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, + u16 info) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + struct rionet_peer *peer; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", + DRV_NAME, sid, tid, info); + if (info == RIONET_DOORBELL_JOIN) { + if (!rionet_active[sid]) { + list_for_each_entry(peer, &rionet_peers, node) { + if (peer->rdev->destid == sid) + rionet_active[sid] = peer->rdev; + } + rio_mport_send_doorbell(mport, sid, + RIONET_DOORBELL_JOIN); + } + } else if (info == RIONET_DOORBELL_LEAVE) { + rionet_active[sid] = NULL; + } else { + if (netif_msg_intr(rnet)) + printk(KERN_WARNING "%s: unhandled doorbell\n", + DRV_NAME); + } +} + +static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + int n; + struct net_device *ndev = dev_id; + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + spin_lock(&rnet->lock); + if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot) + rionet_rx_fill(ndev, n); + spin_unlock(&rnet->lock); +} + +static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + + spin_lock(&rnet->lock); + + if (netif_msg_intr(rnet)) + printk(KERN_INFO + "%s: outbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + while (rnet->tx_cnt && (rnet->ack_slot != slot)) { + /* dma unmap single */ + dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]); + rnet->tx_skb[rnet->ack_slot] = NULL; + ++rnet->ack_slot; + rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1); + rnet->tx_cnt--; + } + + if (rnet->tx_cnt < RIONET_TX_RING_SIZE) + netif_wake_queue(ndev); + + spin_unlock(&rnet->lock); +} + +static int rionet_open(struct net_device *ndev) +{ + int i, rc = 0; + struct rionet_peer *peer, *tmp; + u32 pwdcsr; + struct rionet_private *rnet = ndev->priv; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: open\n", DRV_NAME); + + if ((rc = rio_request_inb_dbell(rnet->mport, + (void *)ndev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE, + rionet_dbell_event)) < 0) + goto out; + + if ((rc = rio_request_inb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_RX_RING_SIZE, + rionet_inb_msg_event)) < 0) + goto out; + + if ((rc = rio_request_outb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_TX_RING_SIZE, + rionet_outb_msg_event)) < 0) + goto out; + + /* Initialize inbound message ring */ + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + rnet->rx_skb[i] = NULL; + rnet->rx_slot = 0; + rionet_rx_fill(ndev, 0); + + rnet->tx_slot = 0; + rnet->tx_cnt = 0; + rnet->ack_slot = 0; + + netif_carrier_on(ndev); + netif_start_queue(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (!(peer->res = rio_request_outb_dbell(peer->rdev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE))) + { + printk(KERN_ERR "%s: error requesting doorbells\n", + DRV_NAME); + continue; + } + + /* + * If device has initialized inbound doorbells, + * send a join message + */ + rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr); + if (pwdcsr & RIO_DOORBELL_AVAIL) + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); + } + + out: + return rc; +} + +static int rionet_close(struct net_device *ndev) +{ + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_peer *peer, *tmp; + int i; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: close\n", DRV_NAME); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + if (rnet->rx_skb[i]) + kfree_skb(rnet->rx_skb[i]); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (rionet_active[peer->rdev->destid]) { + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); + rionet_active[peer->rdev->destid] = NULL; + } + rio_release_outb_dbell(peer->rdev, peer->res); + } + + rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE); + rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX); + rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX); + + return 0; +} + +static void rionet_remove(struct rio_dev *rdev) +{ + struct net_device *ndev = NULL; + struct rionet_peer *peer, *tmp; + + unregister_netdev(ndev); + kfree(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + list_del(&peer->node); + kfree(peer); + } +} + +static void rionet_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct rionet_private *rnet = ndev->priv; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "n/a"); + strcpy(info->bus_info, rnet->mport->name); +} + +static u32 rionet_get_msglevel(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + + return rnet->msg_enable; +} + +static void rionet_set_msglevel(struct net_device *ndev, u32 value) +{ + struct rionet_private *rnet = ndev->priv; + + rnet->msg_enable = value; +} + +static struct ethtool_ops rionet_ethtool_ops = { + .get_drvinfo = rionet_get_drvinfo, + .get_msglevel = rionet_get_msglevel, + .set_msglevel = rionet_set_msglevel, + .get_link = ethtool_op_get_link, +}; + +static int rionet_setup_netdev(struct rio_mport *mport) +{ + int rc = 0; + struct net_device *ndev = NULL; + struct rionet_private *rnet; + u16 device_id; + + /* Allocate our net_device structure */ + ndev = alloc_etherdev(sizeof(struct rionet_private)); + if (ndev == NULL) { + printk(KERN_INFO "%s: could not allocate ethernet device.\n", + DRV_NAME); + rc = -ENOMEM; + goto out; + } + + /* Set up private area */ + rnet = (struct rionet_private *)ndev->priv; + rnet->mport = mport; + + /* Set the default MAC address */ + device_id = rio_local_get_device_id(mport); + ndev->dev_addr[0] = 0x00; + ndev->dev_addr[1] = 0x01; + ndev->dev_addr[2] = 0x00; + ndev->dev_addr[3] = 0x01; + ndev->dev_addr[4] = device_id >> 8; + ndev->dev_addr[5] = device_id & 0xff; + + /* Fill in the driver function table */ + ndev->open = &rionet_open; + ndev->hard_start_xmit = &rionet_start_xmit; + ndev->stop = &rionet_close; + ndev->get_stats = &rionet_stats; + ndev->mtu = RIO_MAX_MSG_SIZE - 14; + ndev->features = NETIF_F_LLTX; + SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); + + SET_MODULE_OWNER(ndev); + + spin_lock_init(&rnet->lock); + spin_lock_init(&rnet->tx_lock); + + rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; + + rc = register_netdev(ndev); + if (rc != 0) + goto out; + + printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, + DRV_NAME, + DRV_DESC, + DRV_VERSION, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + out: + return rc; +} + +/* + * XXX Make multi-net safe + */ +static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + int rc = -ENODEV; + u32 lpef, lsrc_ops, ldst_ops; + struct rionet_peer *peer; + + /* If local device is not rionet capable, give up quickly */ + if (!rionet_capable) + goto out; + + /* + * First time through, make sure local device is rionet + * capable, setup netdev, and set flags so this is skipped + * on later probes + */ + if (!rionet_check) { + rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef); + rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, + &lsrc_ops); + rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, + &ldst_ops); + if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) { + printk(KERN_ERR + "%s: local device is not network capable\n", + DRV_NAME); + rionet_check = 1; + rionet_capable = 0; + goto out; + } + + rc = rionet_setup_netdev(rdev->net->hport); + rionet_check = 1; + } + + /* + * If the remote device has mailbox/doorbell capabilities, + * add it to the peer list. + */ + if (dev_rionet_capable(rdev)) { + if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) { + rc = -ENOMEM; + goto out; + } + peer->rdev = rdev; + list_add_tail(&peer->node, &rionet_peers); + } + + out: + return rc; +} + +static struct rio_device_id rionet_id_table[] = { + {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)} +}; + +static struct rio_driver rionet_driver = { + .name = "rionet", + .id_table = rionet_id_table, + .probe = rionet_probe, + .remove = rionet_remove, +}; + +static int __init rionet_init(void) +{ + return rio_register_driver(&rionet_driver); +} + +static void __exit rionet_exit(void) +{ + rio_unregister_driver(&rionet_driver); +} + +module_init(rionet_init); +module_exit(rionet_exit); From f2b518d71636c2bda65a837b0a93c3365207a4f0 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 14 Sep 2005 16:50:19 -0600 Subject: [PATCH 0040/1939] [IA64] Update default configs PNP and PNPACPI turned on i8042 recently changed from ACPI to PNP detection. Without PNP, it probes legacy I/O ports for the keyboard controller, which causes an MCA on HP boxes. Also, I'm about to remove 8250_acpi.c, so we'll need PNP to detect non-PCI serial ports. Until 8250_acpi.c is removed, some systems will see serial ports reported twice (once from 8250_acpi.c and again from 8250_pnp.c). This is harmless. PNPACPI is still marked EXPERIMENTAL, but I'm not aware of any outstanding issues on ia64. IDE_GENERIC turned off (except for SGI simulator, all ia64 IDE is PCI) ide-generic probes compiled-in legacy I/O ports for IDE devices, which again causes an MCA. It would be nicer to just get rid of all the legacy junk from include/asm-ia64/ide.h, but that is a bit riskier because it could break ide-cs and the HDIO_REGISTER_HWIF ioctl (http://www.ussg.iu.edu/hypermail/linux/kernel/0508.2/0049.html). Here's the essence of the patch: -# CONFIG_PNP is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y -CONFIG_IDE_GENERIC=y +# CONFIG_IDE_GENERIC is not set Tested on tiger, bigsur, and zx1. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/configs/bigsur_defconfig | 421 +++++++++++++++++++---------- arch/ia64/configs/tiger_defconfig | 86 ++++-- arch/ia64/configs/zx1_defconfig | 92 +++++-- arch/ia64/defconfig | 265 +++++++++++------- 4 files changed, 589 insertions(+), 275 deletions(-) diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig index 3b65cbb31b1d..b40672bb3ab0 100644 --- a/arch/ia64/configs/bigsur_defconfig +++ b/arch/ia64/configs/bigsur_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2 -# Mon Nov 29 13:27:48 2004 +# Linux kernel version: 2.6.14-rc1 +# Wed Sep 14 15:18:49 2005 # # @@ -10,34 +10,40 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=16 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +# CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -58,12 +64,15 @@ CONFIG_IA64=y CONFIG_64BIT=y CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y # CONFIG_IA64_GENERIC is not set CONFIG_IA64_DIG=y # CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_HP_SIM is not set CONFIG_ITANIUM=y @@ -72,17 +81,30 @@ CONFIG_ITANIUM=y # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 CONFIG_IA64_BRL_EMU=y CONFIG_IA64_L1_CACHE_SHIFT=6 # CONFIG_NUMA is not set # CONFIG_VIRTUAL_MEM_MAP is not set # CONFIG_IA64_CYCLONE is not set CONFIG_IOSAPIC=y +# CONFIG_IA64_SGI_SN_XP is not set CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=2 # CONFIG_HOTPLUG_CPU is not set +# CONFIG_SCHED_SMT is not set CONFIG_PREEMPT=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_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -95,6 +117,7 @@ CONFIG_IA64_PALINFO=y # CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y +# CONFIG_DELL_RBU is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m @@ -102,18 +125,26 @@ CONFIG_BINFMT_MISC=m # Power management and ACPI # CONFIG_PM=y -CONFIG_ACPI=y +# CONFIG_PM_DEBUG is not set # # ACPI (Advanced Configuration and Power Interface) Support # +CONFIG_ACPI=y CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y +# CONFIG_ACPI_CONTAINER is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set # # Bus options (PCI, PCMCIA) @@ -122,7 +153,7 @@ CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCI Hotplug Support @@ -135,8 +166,70 @@ CONFIG_PCI_NAMES=y # CONFIG_PCCARD is not set # -# PC-card bridges +# Networking # +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_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_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK 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 @@ -150,6 +243,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -163,7 +261,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # -# CONFIG_PNP is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y # # Block devices @@ -172,14 +276,15 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # 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=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -189,6 +294,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set # # ATA/ATAPI/MFM/RLL support @@ -211,7 +317,8 @@ CONFIG_BLK_DEV_IDEFLOPPY=m # # IDE chipset support/bugfixes # -CONFIG_IDE_GENERIC=m +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPNP is not set CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_OFFBOARD is not set @@ -233,6 +340,7 @@ CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=m +# 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 @@ -250,6 +358,7 @@ CONFIG_IDEDMA_AUTO=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -261,6 +370,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -274,6 +384,8 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_SPI_ATTRS=m # CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -288,18 +400,13 @@ CONFIG_SCSI_SPI_ATTRS=m # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set CONFIG_SCSI_QLOGIC_1280=y # CONFIG_SCSI_QLOGIC_1280_1040 is not set @@ -309,7 +416,8 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set @@ -332,11 +440,14 @@ CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m +# CONFIG_DM_MULTIPATH is not set # # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set # # IEEE 1394 (FireWire) support @@ -349,78 +460,25 @@ CONFIG_DM_ZERO=m # CONFIG_I2O is not set # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -443,7 +501,6 @@ CONFIG_NET_PCI=y # CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=y -# CONFIG_EEPRO100_PIO is not set # CONFIG_E100 is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set @@ -465,13 +522,17 @@ CONFIG_EEPRO100=y # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -496,6 +557,8 @@ CONFIG_EEPRO100=y # CONFIG_NET_FC 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 @@ -524,18 +587,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set -# CONFIG_SERIO_RAW is not set - # # Input Device Drivers # @@ -553,6 +604,17 @@ CONFIG_MOUSE_PS2=y # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + # # Character devices # @@ -571,7 +633,6 @@ CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -579,6 +640,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y # 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 @@ -603,14 +665,22 @@ CONFIG_EFI_RTC=y # CONFIG_AGP=m CONFIG_AGP_I460=m -CONFIG_DRM=y +CONFIG_DRM=m # CONFIG_DRM_TDFX is not set CONFIG_DRM_R128=m # CONFIG_DRM_RADEON is not set # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set # CONFIG_RAW_DRIVER is not set # CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set # # I2C support @@ -635,7 +705,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set -# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -651,41 +721,16 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_PCA_ISA is not set # -# Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_ADM1025 is not set -# CONFIG_SENSORS_ADM1031 is not set -# CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_DS1621 is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_GL518SM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM63 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM77 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM80 is not set -# CONFIG_SENSORS_LM83 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set -# CONFIG_SENSORS_LM90 is not set -# CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_W83781D is not set -# CONFIG_SENSORS_W83L785TS is not set -# CONFIG_SENSORS_W83627HF is not set - -# -# Other I2C Chip support +# Miscellaneous I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -696,10 +741,55 @@ CONFIG_I2C_ALGOBIT=y # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -752,11 +842,12 @@ CONFIG_SND_OPL3_LIB=m # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_BUS=m # # PCI devices # -CONFIG_SND_AC97_CODEC=m # CONFIG_SND_ALI5451 is not set # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -768,6 +859,8 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_CS46XX is not set CONFIG_SND_CS4281=m # CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set # CONFIG_SND_KORG1212 is not set # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set @@ -775,9 +868,10 @@ CONFIG_SND_CS4281=m # CONFIG_SND_RME96 is not set # CONFIG_SND_RME9652 is not set # CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set # CONFIG_SND_TRIDENT is not set # CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_AD1889 is not set # CONFIG_SND_CMIPCI is not set # CONFIG_SND_ENS1370 is not set # CONFIG_SND_ENS1371 is not set @@ -791,13 +885,14 @@ CONFIG_SND_CS4281=m # CONFIG_SND_INTEL8X0M is not set # CONFIG_SND_SONICVIBES is not set # CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set # CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set # # USB devices # # CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_USX2Y is not set # # Open Sound System @@ -807,6 +902,8 @@ CONFIG_SND_CS4281=m # # USB support # +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB=m # CONFIG_USB_DEBUG is not set @@ -818,35 +915,38 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y # # USB Host Controller Drivers # # CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_OHCI_HCD is not set CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set # # USB Device Class drivers # -CONFIG_USB_AUDIO=m +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set CONFIG_USB_BLUETOOTH_TTY=m -CONFIG_USB_MIDI=m CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set # # USB Input Devices @@ -863,19 +963,23 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_MOUSE is not set # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices # # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set # # USB Multimedia devices @@ -894,6 +998,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y # # USB port drivers @@ -909,7 +1014,6 @@ CONFIG_USB_HIDDEV=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -918,10 +1022,12 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_LD is not set # CONFIG_USB_TEST is not set # -# USB ATM/DSL drivers +# USB DSL modem support # # @@ -929,11 +1035,26 @@ CONFIG_USB_HIDDEV=y # # CONFIG_USB_GADGET is not set +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + # # 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 @@ -945,17 +1066,20 @@ CONFIG_FS_MBCACHE=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y CONFIG_XFS_FS=y -# CONFIG_XFS_RT is not set +CONFIG_XFS_EXPORT=y CONFIG_XFS_QUOTA=y CONFIG_XFS_SECURITY=y CONFIG_XFS_POSIX_ACL=y +# CONFIG_XFS_RT is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_QUOTACTL=y CONFIG_DNOTIFY=y CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -982,14 +1106,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -CONFIG_DEVPTS_FS_XATTR=y -CONFIG_DEVPTS_FS_SECURITY=y CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1013,15 +1134,18 @@ CONFIG_RAMFS=y # CONFIG_NFS_FS=m CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set CONFIG_NFSD=m CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=m +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m @@ -1031,9 +1155,11 @@ CONFIG_CIFS=m CONFIG_CIFS_STATS=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_EXPERIMENTAL 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 @@ -1103,8 +1229,12 @@ CONFIG_NLS_UTF8=m # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y # # Profiling support @@ -1115,14 +1245,20 @@ CONFIG_OPROFILE=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=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_KPROBES is not set # CONFIG_IA64_GRANULE_16MB is not set CONFIG_IA64_GRANULE_64MB=y # CONFIG_IA64_PRINT_HAZARDS is not set @@ -1149,6 +1285,7 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set @@ -1164,3 +1301,7 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index d452e18ac494..9bc8bcafc905 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc6-tiger-smp -# Wed Aug 17 10:19:51 2005 +# Linux kernel version: 2.6.14-rc1 +# Wed Sep 14 15:17:57 2005 # # @@ -16,6 +16,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -27,6 +28,7 @@ CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y @@ -103,6 +105,7 @@ CONFIG_FLATMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -115,6 +118,7 @@ CONFIG_IA64_PALINFO=y # CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y +# CONFIG_DELL_RBU is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m @@ -122,20 +126,27 @@ CONFIG_BINFMT_MISC=m # Power management and ACPI # CONFIG_PM=y -CONFIG_ACPI=y +# CONFIG_PM_DEBUG is not set # # ACPI (Advanced Configuration and Power Interface) Support # +CONFIG_ACPI=y CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m -# CONFIG_ACPI_HOTPLUG_CPU is not set +CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y -# CONFIG_ACPI_CONTAINER is not set +CONFIG_ACPI_CONTAINER=m + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set # # Bus options (PCI, PCMCIA) @@ -144,7 +155,6 @@ CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y # CONFIG_PCI_DEBUG is not set # @@ -188,13 +198,18 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 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_NETFILTER is not set +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + # # SCTP Configuration (EXPERIMENTAL) # @@ -218,9 +233,11 @@ CONFIG_TCP_CONG_BIC=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK 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 @@ -234,6 +251,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -247,7 +269,13 @@ CONFIG_FW_LOADER=m # # Plug and Play support # -# CONFIG_PNP is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y # # Block devices @@ -266,7 +294,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -299,7 +326,8 @@ CONFIG_BLK_DEV_IDESCSI=m # # IDE chipset support/bugfixes # -CONFIG_IDE_GENERIC=y +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPNP is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set # CONFIG_BLK_DEV_OFFBOARD is not set @@ -339,6 +367,7 @@ CONFIG_IDEDMA_AUTO=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -366,6 +395,7 @@ CONFIG_CHR_DEV_SG=m CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -454,12 +484,18 @@ CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -481,6 +517,7 @@ CONFIG_TULIP=m # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set @@ -512,6 +549,7 @@ CONFIG_E1000=y # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set @@ -521,6 +559,7 @@ CONFIG_TIGON3=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -618,6 +657,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_NONSTANDARD=y # CONFIG_ROCKETPORT is not set # CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set # CONFIG_SYNCLINKMP is not set @@ -675,6 +715,7 @@ CONFIG_DRM_RADEON=m CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m # CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set CONFIG_RAW_DRIVER=m CONFIG_HPET=y # CONFIG_HPET_RTC_IRQ is not set @@ -691,7 +732,6 @@ CONFIG_MAX_RAW_DEVS=256 # I2C support # # CONFIG_I2C is not set -# CONFIG_I2C_SENSOR is not set # # Dallas's 1-wire bus @@ -702,12 +742,17 @@ CONFIG_MAX_RAW_DEVS=256 # Hardware Monitoring support # CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set # CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -800,9 +845,11 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_MTOUCH is not set # CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices @@ -902,16 +949,12 @@ CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# CONFIG_XFS_FS=y CONFIG_XFS_EXPORT=y -# CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -919,6 +962,7 @@ CONFIG_INOTIFY=y CONFIG_DNOTIFY=y CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -947,13 +991,11 @@ CONFIG_NTFS_FS=m CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -CONFIG_TMPFS_XATTR=y -CONFIG_TMPFS_SECURITY=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1003,6 +1045,7 @@ CONFIG_CIFS=m # 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 @@ -1072,10 +1115,12 @@ CONFIG_NLS_UTF8=m # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y # # Profiling support @@ -1089,6 +1134,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=20 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig index 80b0e9eb7fb3..0856ca67dd50 100644 --- a/arch/ia64/configs/zx1_defconfig +++ b/arch/ia64/configs/zx1_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc6 -# Wed Aug 17 10:02:43 2005 +# Linux kernel version: 2.6.14-rc1 +# Wed Sep 14 15:15:01 2005 # # @@ -18,6 +18,7 @@ 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 @@ -29,6 +30,7 @@ CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set @@ -103,6 +105,7 @@ CONFIG_FLATMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -115,6 +118,7 @@ CONFIG_IA64_PALINFO=y # CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y +# CONFIG_DELL_RBU is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y @@ -122,20 +126,27 @@ CONFIG_BINFMT_MISC=y # Power management and ACPI # CONFIG_PM=y -CONFIG_ACPI=y +# CONFIG_PM_DEBUG is not set # # ACPI (Advanced Configuration and Power Interface) Support # +CONFIG_ACPI=y CONFIG_ACPI_BUTTON=y CONFIG_ACPI_FAN=y CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y # CONFIG_ACPI_CONTAINER is not set +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + # # Bus options (PCI, PCMCIA) # @@ -143,7 +154,6 @@ CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y # CONFIG_PCI_DEBUG is not set # @@ -187,8 +197,8 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y @@ -204,13 +214,17 @@ CONFIG_NETFILTER=y # IP: Netfilter Configuration # # CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_CONNTRACK_MARK is not set # CONFIG_IP_NF_QUEUE is not set # CONFIG_IP_NF_IPTABLES is not set CONFIG_IP_NF_ARPTABLES=y # CONFIG_IP_NF_ARPFILTER is not set # CONFIG_IP_NF_ARP_MANGLE is not set +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + # # SCTP Configuration (EXPERIMENTAL) # @@ -234,9 +248,11 @@ CONFIG_IP_NF_ARPTABLES=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK 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 @@ -250,6 +266,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -263,7 +284,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # -# CONFIG_PNP is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y # # Block devices @@ -282,7 +309,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -315,7 +341,8 @@ CONFIG_BLK_DEV_IDECD=y # # IDE chipset support/bugfixes # -CONFIG_IDE_GENERIC=y +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPNP is not set CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_OFFBOARD is not set @@ -354,6 +381,7 @@ CONFIG_BLK_DEV_IDEDMA=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -381,6 +409,7 @@ CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -457,12 +486,18 @@ CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -485,6 +520,7 @@ CONFIG_TULIP_NAPI_HW_MITIGATION=y # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set @@ -516,6 +552,7 @@ CONFIG_E1000=y # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set @@ -525,6 +562,7 @@ CONFIG_TIGON3=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -650,12 +688,12 @@ CONFIG_AGP=y CONFIG_AGP_HP_ZX1=y CONFIG_DRM=y # CONFIG_DRM_TDFX is not set -# CONFIG_DRM_GAMMA is not set # CONFIG_DRM_R128 is not set CONFIG_DRM_RADEON=y # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set # CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set # CONFIG_RAW_DRIVER is not set # CONFIG_HPET is not set # CONFIG_HANGCHECK_TIMER is not set @@ -689,7 +727,6 @@ CONFIG_I2C_ALGOPCF=y # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set -# CONFIG_I2C_ISA is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -703,7 +740,6 @@ CONFIG_I2C_ALGOPCF=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set -# CONFIG_I2C_SENSOR is not set # # Miscellaneous I2C Chip support @@ -730,11 +766,16 @@ CONFIG_I2C_ALGOPCF=y # Hardware Monitoring support # # CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -806,6 +847,7 @@ CONFIG_FB_RADEON_DEBUG=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set # CONFIG_FB_PM3 is not set # CONFIG_FB_S1D13XXX is not set @@ -862,11 +904,12 @@ CONFIG_SND_OPL3_LIB=y # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_AC97_BUS=y # # PCI devices # -CONFIG_SND_AC97_CODEC=y # CONFIG_SND_ALI5451 is not set # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -890,7 +933,7 @@ CONFIG_SND_AC97_CODEC=y # CONFIG_SND_HDSPM is not set # CONFIG_SND_TRIDENT is not set # CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_AD1889 is not set # CONFIG_SND_CMIPCI is not set # CONFIG_SND_ENS1370 is not set # CONFIG_SND_ENS1371 is not set @@ -952,9 +995,8 @@ CONFIG_USB_UHCI_HCD=y # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -971,6 +1013,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set # # USB Input Devices @@ -987,9 +1030,11 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_MTOUCH is not set # CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices @@ -1088,10 +1133,6 @@ CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set - -# -# XFS support -# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1100,6 +1141,7 @@ CONFIG_FS_MBCACHE=y CONFIG_DNOTIFY=y CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -1126,13 +1168,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -CONFIG_TMPFS_XATTR=y -CONFIG_TMPFS_SECURITY=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1177,6 +1217,7 @@ CONFIG_RPCSEC_GSS_KRB5=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -1246,10 +1287,12 @@ CONFIG_NLS_UTF8=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y # # Profiling support @@ -1263,6 +1306,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=17 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index 5da208115ea1..6e3f147e03e5 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12 -# Tue Jun 21 11:30:42 2005 +# Linux kernel version: 2.6.14-rc1 +# Wed Sep 14 15:13:03 2005 # # @@ -16,6 +16,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -27,6 +28,7 @@ CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y @@ -80,6 +82,10 @@ CONFIG_MCKINLEY=y # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 CONFIG_IA64_L1_CACHE_SHIFT=7 CONFIG_NUMA=y CONFIG_VIRTUAL_MEM_MAP=y @@ -87,12 +93,21 @@ CONFIG_HOLES_IN_ZONE=y CONFIG_ARCH_DISCONTIGMEM_ENABLE=y CONFIG_IA64_CYCLONE=y CONFIG_IOSAPIC=y +# CONFIG_IA64_SGI_SN_XP is not set CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=512 CONFIG_HOTPLUG_CPU=y # CONFIG_SCHED_SMT is not set # CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y @@ -105,6 +120,7 @@ CONFIG_IA64_PALINFO=y # CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y +# CONFIG_DELL_RBU is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m @@ -112,22 +128,29 @@ CONFIG_BINFMT_MISC=m # Power management and ACPI # CONFIG_PM=y -CONFIG_ACPI=y +# CONFIG_PM_DEBUG is not set # # ACPI (Advanced Configuration and Power Interface) Support # +CONFIG_ACPI=y CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=m CONFIG_ACPI_NUMA=y +CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y CONFIG_ACPI_CONTAINER=m +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + # # Bus options (PCI, PCMCIA) # @@ -135,7 +158,6 @@ CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y # CONFIG_PCI_DEBUG is not set # @@ -147,12 +169,80 @@ CONFIG_HOTPLUG_PCI_ACPI=m # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HOTPLUG_PCI_SGI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_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_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK 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 # @@ -162,9 +252,14 @@ CONFIG_HOTPLUG_PCI_ACPI=m # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -178,7 +273,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # -# CONFIG_PNP is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y # # Block devices @@ -197,7 +298,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -230,7 +330,8 @@ CONFIG_BLK_DEV_IDESCSI=m # # IDE chipset support/bugfixes # -CONFIG_IDE_GENERIC=y +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPNP is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set # CONFIG_BLK_DEV_OFFBOARD is not set @@ -252,6 +353,7 @@ CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y +# 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 @@ -270,6 +372,7 @@ CONFIG_IDEDMA_AUTO=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -297,6 +400,7 @@ CONFIG_CHR_DEV_SG=m CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -314,6 +418,7 @@ CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_AHCI is not set # CONFIG_SCSI_SATA_SVW is not set # CONFIG_SCSI_ATA_PIIX is not set +# CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set # CONFIG_SCSI_SATA_PROMISE is not set # CONFIG_SCSI_SATA_QSTOR is not set @@ -335,7 +440,6 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set CONFIG_SCSI_QLOGIC_1280=y # CONFIG_SCSI_QLOGIC_1280_1040 is not set CONFIG_SCSI_QLA2XXX=y @@ -344,6 +448,7 @@ CONFIG_SCSI_QLA22XX=m CONFIG_SCSI_QLA2300=m CONFIG_SCSI_QLA2322=m # CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -390,80 +495,25 @@ CONFIG_FUSION_MAX_SGE=128 # CONFIG_I2O is not set # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -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_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_ARPD=y -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -CONFIG_NET_POLL_CONTROLLER=y -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -485,6 +535,7 @@ CONFIG_TULIP=m # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set @@ -516,6 +567,7 @@ CONFIG_E1000=y # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set @@ -525,6 +577,7 @@ CONFIG_TIGON3=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -549,6 +602,10 @@ CONFIG_TIGON3=y # CONFIG_NET_FC is not set # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y # # ISDN subsystem @@ -607,9 +664,7 @@ CONFIG_GAMEPORT=m # CONFIG_GAMEPORT_NS558 is not set # CONFIG_GAMEPORT_L4 is not set # CONFIG_GAMEPORT_EMU10K1 is not set -# CONFIG_GAMEPORT_VORTEX is not set # CONFIG_GAMEPORT_FM801 is not set -# CONFIG_GAMEPORT_CS461X is not set # # Character devices @@ -620,6 +675,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_NONSTANDARD=y # CONFIG_ROCKETPORT is not set # CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set # CONFIG_SYNCLINKMP is not set @@ -641,7 +697,6 @@ CONFIG_SERIAL_8250_NR_UARTS=6 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -650,8 +705,8 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y -CONFIG_SERIAL_SGI_IOC4=y # CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_SGI_IOC4=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -684,6 +739,8 @@ CONFIG_DRM_R128=m CONFIG_DRM_RADEON=m CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set CONFIG_RAW_DRIVER=m CONFIG_HPET=y # CONFIG_HPET_RTC_IRQ is not set @@ -707,10 +764,21 @@ CONFIG_MMTIMER=y # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -753,6 +821,7 @@ CONFIG_SND_PCM_OSS=m CONFIG_SND_SEQUENCER_OSS=y CONFIG_SND_VERBOSE_PRINTK=y # CONFIG_SND_DEBUG is not set +CONFIG_SND_GENERIC_DRIVER=y # # Generic devices @@ -764,11 +833,12 @@ CONFIG_SND_VIRMIDI=m CONFIG_SND_MTPAV=m CONFIG_SND_SERIAL_U16550=m CONFIG_SND_MPU401=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_BUS=m # # PCI devices # -CONFIG_SND_AC97_CODEC=m # CONFIG_SND_ALI5451 is not set # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -790,9 +860,10 @@ CONFIG_SND_EMU10K1=m # CONFIG_SND_RME96 is not set # CONFIG_SND_RME9652 is not set # CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set # CONFIG_SND_TRIDENT is not set # CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_AD1889 is not set # CONFIG_SND_CMIPCI is not set # CONFIG_SND_ENS1370 is not set # CONFIG_SND_ENS1371 is not set @@ -844,6 +915,7 @@ CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=m # CONFIG_USB_OHCI_BIG_ENDIAN is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y @@ -853,9 +925,8 @@ CONFIG_USB_UHCI_HCD=m # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -888,12 +959,17 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_MOUSE is not set # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices @@ -918,7 +994,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set -CONFIG_USB_MON=m +CONFIG_USB_MON=y # # USB port drivers @@ -944,10 +1020,11 @@ CONFIG_USB_MON=m # CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set # CONFIG_USB_TEST is not set # -# USB ATM/DSL drivers +# USB DSL modem support # # @@ -964,6 +1041,8 @@ CONFIG_USB_MON=m # InfiniBand support # CONFIG_INFINIBAND=m +# CONFIG_INFINIBAND_USER_MAD is not set +# CONFIG_INFINIBAND_USER_ACCESS is not set CONFIG_INFINIBAND_MTHCA=m # CONFIG_INFINIBAND_MTHCA_DEBUG is not set CONFIG_INFINIBAND_IPOIB=m @@ -981,6 +1060,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -996,22 +1076,20 @@ CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# CONFIG_XFS_FS=y CONFIG_XFS_EXPORT=y -# CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT 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=y CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -1040,14 +1118,11 @@ CONFIG_NTFS_FS=m CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -CONFIG_TMPFS_XATTR=y -CONFIG_TMPFS_SECURITY=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1071,15 +1146,18 @@ CONFIG_RAMFS=y # CONFIG_NFS_FS=m CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y CONFIG_NFS_DIRECTIO=y CONFIG_NFSD=m CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m @@ -1094,6 +1172,7 @@ CONFIG_CIFS=m # 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 @@ -1163,10 +1242,12 @@ CONFIG_NLS_UTF8=m # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y # # HP Simulator drivers @@ -1187,6 +1268,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=20 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1194,6 +1276,7 @@ CONFIG_LOG_BUF_SHIFT=20 # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set +# CONFIG_KPROBES is not set CONFIG_IA64_GRANULE_16MB=y # CONFIG_IA64_GRANULE_64MB is not set # CONFIG_IA64_PRINT_HAZARDS is not set @@ -1215,7 +1298,7 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_SHA1 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set From 24ee0a6d7b0a52b140c880aae24c255de3b4a9a1 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Mon, 12 Sep 2005 12:15:43 -0500 Subject: [PATCH 0041/1939] [IA64] Cleanup use of various #defines related to nodes Some of the SN code & #defines related to compact nodes & IO discovery have gotten stale over the years. This patch attempts to clean them up. Some of the various SN MAX_xxx #defines were also unclear & misused. The primary changes are: - use MAX_NUMNODES. This is the generic linux #define for the number of nodes that are known to the generic kernel. Arrays & loops for constructs that are 1:1 with linux-defined nodes should use the linux #define - not an SN equivalent. - use MAX_COMPACT_NODES for MAX_NUMNODES + NUM_TIOS. This is the number of nodes in the SSI system. Compact nodes are a hack to get around the IA64 architectural limit of 256 nodes. Large SGI systems have more than 256 nodes. When we upgrade to ACPI3.0, I _hope_ that all nodes will be real nodes that are known to the generic kernel. That will allow us to delete the notion of "compact nodes". - add MAX_NUMALINK_NODES for the total number of nodes that are in the numalink domain - all partitions. - simplified (understandable) scan_for_ionodes() - small amount of cleanup related to cnodes Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/io_init.c | 4 +- arch/ia64/sn/kernel/setup.c | 164 +++++++++------------------- arch/ia64/sn/kernel/sn2/sn_hwperf.c | 4 +- arch/ia64/sn/kernel/tiocx.c | 5 +- arch/ia64/sn/kernel/xpc_partition.c | 2 +- drivers/char/snsc.c | 4 +- include/asm-ia64/sn/arch.h | 36 ++++-- include/asm-ia64/sn/io.h | 2 +- include/asm-ia64/sn/klconfig.h | 34 +----- include/asm-ia64/sn/sn_cpuid.h | 3 - include/asm-ia64/sn/sn_sal.h | 12 +- include/asm-ia64/sn/xp.h | 2 +- 12 files changed, 94 insertions(+), 178 deletions(-) diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 906622d9f933..b4f5053f5e1b 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -22,8 +22,6 @@ #include "xtalk/hubdev.h" #include "xtalk/xwidgetdev.h" -nasid_t master_nasid = INVALID_NASID; /* Partition Master */ - static struct list_head sn_sysdata_list; /* sysdata list struct */ @@ -165,7 +163,7 @@ static void sn_fixup_ionodes(void) * Get SGI Specific HUB chipset information. * Inform Prom that this kernel can support domain bus numbering. */ - for (i = 0; i < numionodes; i++) { + for (i = 0; i < num_cnodes; i++) { hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); nasid = cnodeid_to_nasid(i); hubdev->max_segment_number = 0xffffffff; diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 6f8c5883716b..0fb579ef18c2 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -59,8 +59,6 @@ DEFINE_PER_CPU(struct pda_s, pda_percpu); #define MAX_PHYS_MEMORY (1UL << IA64_MAX_PHYS_BITS) /* Max physical address supported */ -lboard_t *root_lboard[MAX_COMPACT_NODES]; - extern void bte_init_node(nodepda_t *, cnodeid_t); extern void sn_timer_init(void); @@ -97,15 +95,15 @@ u8 sn_region_size; EXPORT_SYMBOL(sn_region_size); int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */ -short physical_node_map[MAX_PHYSNODE_ID]; +short physical_node_map[MAX_NUMALINK_NODES]; static unsigned long sn_prom_features[MAX_PROM_FEATURE_SETS]; EXPORT_SYMBOL(physical_node_map); -int numionodes; +int num_cnodes; static void sn_init_pdas(char **); -static void scan_for_ionodes(void); +static void build_cnode_tables(void); static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; @@ -139,19 +137,6 @@ extern char drive_info[4 * 16]; char drive_info[4 * 16]; #endif -/* - * Get nasid of current cpu early in boot before nodepda is initialized - */ -static int -boot_get_nasid(void) -{ - int nasid; - - if (ia64_sn_get_sapic_info(get_sapicid(), &nasid, NULL, NULL)) - BUG(); - return nasid; -} - /* * This routine can only be used during init, since * smp_boot_data is an init data structure. @@ -223,7 +208,6 @@ void __init early_sn_setup(void) } extern int platform_intr_list[]; -extern nasid_t master_nasid; static int __initdata shub_1_1_found = 0; /* @@ -269,7 +253,6 @@ static void __init sn_check_for_wars(void) void __init sn_setup(char **cmdline_p) { long status, ticks_per_sec, drift; - int pxm; u32 version = sn_sal_rev(); extern void sn_cpu_init(void); @@ -300,11 +283,10 @@ void __init sn_setup(char **cmdline_p) MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; - memset(physical_node_map, -1, sizeof(physical_node_map)); - for (pxm = 0; pxm < MAX_PXM_DOMAINS; pxm++) - if (pxm_to_nid_map[pxm] != -1) - physical_node_map[pxm_to_nasid(pxm)] = - pxm_to_nid_map[pxm]; + /* + * Build the tables for managing cnodes. + */ + build_cnode_tables(); /* * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard @@ -319,8 +301,6 @@ void __init sn_setup(char **cmdline_p) printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); - master_nasid = boot_get_nasid(); - status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift); @@ -378,15 +358,6 @@ static void __init sn_init_pdas(char **cmdline_p) { cnodeid_t cnode; - memset(sn_cnodeid_to_nasid, -1, - sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid))); - for_each_online_node(cnode) - sn_cnodeid_to_nasid[cnode] = - pxm_to_nasid(nid_to_pxm_map[cnode]); - - numionodes = num_online_nodes(); - scan_for_ionodes(); - /* * Allocate & initalize the nodepda for each node. */ @@ -402,7 +373,7 @@ static void __init sn_init_pdas(char **cmdline_p) /* * Allocate & initialize nodepda for TIOs. For now, put them on node 0. */ - for (cnode = num_online_nodes(); cnode < numionodes; cnode++) { + for (cnode = num_online_nodes(); cnode < num_cnodes; cnode++) { nodepdaindr[cnode] = alloc_bootmem_node(NODE_DATA(0), sizeof(nodepda_t)); memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); @@ -411,7 +382,7 @@ static void __init sn_init_pdas(char **cmdline_p) /* * Now copy the array of nodepda pointers to each nodepda. */ - for (cnode = 0; cnode < numionodes; cnode++) + for (cnode = 0; cnode < num_cnodes; cnode++) memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); @@ -428,7 +399,7 @@ static void __init sn_init_pdas(char **cmdline_p) * Initialize the per node hubdev. This includes IO Nodes and * headless/memless nodes. */ - for (cnode = 0; cnode < numionodes; cnode++) { + for (cnode = 0; cnode < num_cnodes; cnode++) { hubdev_init_node(nodepdaindr[cnode], cnode); } } @@ -553,87 +524,58 @@ void __init sn_cpu_init(void) } /* - * Scan klconfig for ionodes. Add the nasids to the - * physical_node_map and the pda and increment numionodes. + * Build tables for converting between NASIDs and cnodes. */ - -static void __init scan_for_ionodes(void) +static inline int __init board_needs_cnode(int type) { - int nasid = 0; + return (type == KLTYPE_SNIA || type == KLTYPE_TIO); +} + +void __init build_cnode_tables(void) +{ + int nasid; + int node; lboard_t *brd; + memset(physical_node_map, -1, sizeof(physical_node_map)); + memset(sn_cnodeid_to_nasid, -1, + sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid))); + + /* + * First populate the tables with C/M bricks. This ensures that + * cnode == node for all C & M bricks. + */ + for_each_online_node(node) { + nasid = pxm_to_nasid(nid_to_pxm_map[node]); + sn_cnodeid_to_nasid[node] = nasid; + physical_node_map[nasid] = node; + } + + /* + * num_cnodes is total number of C/M/TIO bricks. Because of the 256 node + * limit on the number of nodes, we can't use the generic node numbers + * for this. Note that num_cnodes is incremented below as TIOs or + * headless/memoryless nodes are discovered. + */ + num_cnodes = num_online_nodes(); + /* fakeprom does not support klgraph */ if (IS_RUNNING_ON_FAKE_PROM()) return; - /* Setup ionodes with memory */ - for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { - char *klgraph_header; - cnodeid_t cnodeid; - - if (physical_node_map[nasid] == -1) - continue; - - cnodeid = -1; - klgraph_header = __va(ia64_sn_get_klconfig_addr(nasid)); - if (!klgraph_header) { - BUG(); /* All nodes must have klconfig tables! */ - } - cnodeid = nasid_to_cnodeid(nasid); - root_lboard[cnodeid] = (lboard_t *) - NODE_OFFSET_TO_LBOARD((nasid), - ((kl_config_hdr_t - *) (klgraph_header))-> - ch_board_info); - } - - /* Scan headless/memless IO Nodes. */ - for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { - /* if there's no nasid, don't try to read the klconfig on the node */ - if (physical_node_map[nasid] == -1) - continue; - brd = find_lboard_any((lboard_t *) - root_lboard[nasid_to_cnodeid(nasid)], - KLTYPE_SNIA); - if (brd) { - brd = KLCF_NEXT_ANY(brd); /* Skip this node's lboard */ - if (!brd) - continue; - } - - brd = find_lboard_any(brd, KLTYPE_SNIA); - + /* Find TIOs & headless/memoryless nodes and add them to the tables */ + for_each_online_node(node) { + kl_config_hdr_t *klgraph_header; + nasid = cnodeid_to_nasid(node); + if ((klgraph_header = ia64_sn_get_klconfig_addr(nasid)) == NULL) + BUG(); + brd = NODE_OFFSET_TO_LBOARD(nasid, klgraph_header->ch_board_info); while (brd) { - sn_cnodeid_to_nasid[numionodes] = brd->brd_nasid; - physical_node_map[brd->brd_nasid] = numionodes; - root_lboard[numionodes] = brd; - numionodes++; - brd = KLCF_NEXT_ANY(brd); - if (!brd) - break; - - brd = find_lboard_any(brd, KLTYPE_SNIA); - } - } - - /* Scan for TIO nodes. */ - for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { - /* if there's no nasid, don't try to read the klconfig on the node */ - if (physical_node_map[nasid] == -1) - continue; - brd = find_lboard_any((lboard_t *) - root_lboard[nasid_to_cnodeid(nasid)], - KLTYPE_TIO); - while (brd) { - sn_cnodeid_to_nasid[numionodes] = brd->brd_nasid; - physical_node_map[brd->brd_nasid] = numionodes; - root_lboard[numionodes] = brd; - numionodes++; - brd = KLCF_NEXT_ANY(brd); - if (!brd) - break; - - brd = find_lboard_any(brd, KLTYPE_TIO); + if (board_needs_cnode(brd->brd_type) && physical_node_map[brd->brd_nasid] < 0) { + sn_cnodeid_to_nasid[num_cnodes] = brd->brd_nasid; + physical_node_map[brd->brd_nasid] = num_cnodes++; + } + brd = find_lboard_next(brd); } } } diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 0513aacac8c1..6c6fbca3229c 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -476,8 +476,8 @@ static int sn_topology_show(struct seq_file *s, void *d) for_each_online_cpu(j) { seq_printf(s, j ? ":%d" : ", dist %d", node_distance( - cpuid_to_cnodeid(i), - cpuid_to_cnodeid(j))); + cpu_to_node(i), + cpu_to_node(j))); } seq_putc(s, '\n'); } diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index b45db5133f55..7e9764a69dc8 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -486,11 +486,10 @@ static int __init tiocx_init(void) bus_register(&tiocx_bus_type); - for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) { + for (cnodeid = 0; cnodeid < num_cnodes; cnodeid++) { nasid_t nasid; - if ((nasid = cnodeid_to_nasid(cnodeid)) < 0) - break; /* No more nasids .. bail out of loop */ + nasid = cnodeid_to_nasid(cnodeid); if ((nasid & 0x1) && is_fpga_brick(nasid)) { struct hubdev_info *hubdev; diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 578265ea9e67..72ef330fb784 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -44,7 +44,7 @@ static u64 xpc_sh2_IPI_access3; /* original protection values for each node */ -u64 xpc_prot_vec[MAX_COMPACT_NODES]; +u64 xpc_prot_vec[MAX_NUMNODES]; /* this partition's reserved page */ diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 261a41bf6d02..a025a89ea70a 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -377,7 +377,7 @@ scdrv_init(void) dev_t first_dev, dev; nasid_t event_nasid = ia64_sn_get_console_nasid(); - if (alloc_chrdev_region(&first_dev, 0, numionodes, + if (alloc_chrdev_region(&first_dev, 0, num_cnodes, SYSCTL_BASENAME) < 0) { printk("%s: failed to register SN system controller device\n", __FUNCTION__); @@ -385,7 +385,7 @@ scdrv_init(void) } snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); - for (cnode = 0; cnode < numionodes; cnode++) { + for (cnode = 0; cnode < num_cnodes; cnode++) { geoid = cnodeid_get_geoid(cnode); devnamep = devname; format_module_id(devnamep, geo_module(geoid), diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h index ab827d298569..8fce5a6db951 100644 --- a/include/asm-ia64/sn/arch.h +++ b/include/asm-ia64/sn/arch.h @@ -17,6 +17,32 @@ #include #include +/* + * This is the maximum number of NUMALINK nodes that can be part of a single + * SSI kernel. This number includes C-brick, M-bricks, and TIOs. Nodes in + * remote partitions are NOT included in this number. + * The number of compact nodes cannot exceed size of a coherency domain. + * The purpose of this define is to specify a node count that includes + * all C/M/TIO nodes in an SSI system. + * + * SGI system can currently support up to 256 C/M nodes plus additional TIO nodes. + * + * Note: ACPI20 has an architectural limit of 256 nodes. When we upgrade + * to ACPI3.0, this limit will be removed. The notion of "compact nodes" + * should be deleted and TIOs should be included in MAX_NUMNODES. + */ +#define MAX_COMPACT_NODES 512 + +/* + * Maximum number of nodes in all partitions and in all coherency domains. + * This is the total number of nodes accessible in the numalink fabric. It + * includes all C & M bricks, plus all TIOs. + * + * This value is also the value of the maximum number of NASIDs in the numalink + * fabric. + */ +#define MAX_NUMALINK_NODES 2048 + /* * The following defines attributes of the HUB chip. These attributes are * frequently referenced. They are kept in the per-cpu data areas of each cpu. @@ -40,15 +66,6 @@ DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); #define enable_shub_wars_1_1() (sn_hub_info->shub_1_1_found) -/* - * This is the maximum number of nodes that can be part of a kernel. - * Effectively, it's the maximum number of compact node ids (cnodeid_t). - * This is not necessarily the same as MAX_NASIDS. - */ -#define MAX_COMPACT_NODES 2048 -#define CPUS_PER_NODE 4 - - /* * Compact node ID to nasid mappings kept in the per-cpu data areas of each * cpu. @@ -57,7 +74,6 @@ DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_NUMNODES]); #define sn_cnodeid_to_nasid (&__get_cpu_var(__sn_cnodeid_to_nasid[0])) - extern u8 sn_partition_id; extern u8 sn_system_size; extern u8 sn_sharing_domain_size; diff --git a/include/asm-ia64/sn/io.h b/include/asm-ia64/sn/io.h index 42209733f6b1..ac30c747c5ab 100644 --- a/include/asm-ia64/sn/io.h +++ b/include/asm-ia64/sn/io.h @@ -14,7 +14,7 @@ extern void * sn_io_addr(unsigned long port) __attribute_const__; /* Forward definition */ extern void __sn_mmiowb(void); /* Forward definition */ -extern int numionodes; +extern int num_cnodes; #define __sn_mf_a() ia64_mfa() diff --git a/include/asm-ia64/sn/klconfig.h b/include/asm-ia64/sn/klconfig.h index 9f920c70a62a..bcbf209d63be 100644 --- a/include/asm-ia64/sn/klconfig.h +++ b/include/asm-ia64/sn/klconfig.h @@ -208,19 +208,6 @@ typedef struct lboard_s { klconf_off_t brd_next_same; /* Next BOARD with same nasid */ } lboard_t; -#define KLCF_NUM_COMPS(_brd) ((_brd)->brd_numcompts) -#define NODE_OFFSET_TO_KLINFO(n,off) ((klinfo_t*) TO_NODE_CAC(n,off)) -#define KLCF_NEXT(_brd) \ - ((_brd)->brd_next_same ? \ - (NODE_OFFSET_TO_LBOARD((_brd)->brd_next_same_host, (_brd)->brd_next_same)): NULL) -#define KLCF_NEXT_ANY(_brd) \ - ((_brd)->brd_next_any ? \ - (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next_any)): NULL) -#define KLCF_COMP(_brd, _ndx) \ - ((((_brd)->brd_compts[(_ndx)]) == 0) ? 0 : \ - (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)]))) - - /* * Generic info structure. This stores common info about a * component. @@ -249,24 +236,11 @@ typedef struct klinfo_s { /* Generic info */ } klinfo_t ; -static inline lboard_t *find_lboard_any(lboard_t * start, unsigned char brd_type) +static inline lboard_t *find_lboard_next(lboard_t * brd) { - /* Search all boards stored on this node. */ - - while (start) { - if (start->brd_type == brd_type) - return start; - start = KLCF_NEXT_ANY(start); - } - /* Didn't find it. */ - return (lboard_t *) NULL; + if (brd && brd->brd_next_any) + return NODE_OFFSET_TO_LBOARD(NASID_GET(brd), brd->brd_next_any); + return NULL; } - -/* external declarations of Linux kernel functions. */ - -extern lboard_t *root_lboard[]; -extern klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char type); -extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type); - #endif /* _ASM_IA64_SN_KLCONFIG_H */ diff --git a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h index d2c1d34dcce4..749deb2ca6c1 100644 --- a/include/asm-ia64/sn/sn_cpuid.h +++ b/include/asm-ia64/sn/sn_cpuid.h @@ -105,7 +105,6 @@ extern short physical_node_map[]; /* indexed by nasid to get cnode */ #define cpuid_to_nasid(cpuid) (sn_nodepda->phys_cpuid[cpuid].nasid) #define cpuid_to_subnode(cpuid) (sn_nodepda->phys_cpuid[cpuid].subnode) #define cpuid_to_slice(cpuid) (sn_nodepda->phys_cpuid[cpuid].slice) -#define cpuid_to_cnodeid(cpuid) (physical_node_map[cpuid_to_nasid(cpuid)]) /* @@ -113,8 +112,6 @@ extern short physical_node_map[]; /* indexed by nasid to get cnode */ * of potentially large tables. */ extern int nasid_slice_to_cpuid(int, int); -#define nasid_slice_to_cpu_physical_id(nasid, slice) \ - cpu_physical_id(nasid_slice_to_cpuid(nasid, slice)) /* * cnodeid_to_nasid - convert a cnodeid to a NASID diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index fea35b33d4e4..5ad855db8464 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -198,26 +198,16 @@ ia64_sn_get_master_baseio_nasid(void) return ret_stuff.v0; } -static inline char * +static inline void * ia64_sn_get_klconfig_addr(nasid_t nasid) { struct ia64_sal_retval ret_stuff; - int cnodeid; - cnodeid = nasid_to_cnodeid(nasid); ret_stuff.status = 0; ret_stuff.v0 = 0; ret_stuff.v1 = 0; ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, (u64)nasid, 0, 0, 0, 0, 0, 0); - - /* - * We should panic if a valid cnode nasid does not produce - * a klconfig address. - */ - if (ret_stuff.status != 0) { - panic("ia64_sn_get_klconfig_addr: Returned error %lx\n", ret_stuff.status); - } return ret_stuff.v0 ? __va(ret_stuff.v0) : NULL; } diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h index 1df1c9f61a65..75a2f39c6ac6 100644 --- a/include/asm-ia64/sn/xp.h +++ b/include/asm-ia64/sn/xp.h @@ -49,7 +49,7 @@ * C-brick nasids, thus the need for bitmaps which don't account for * odd-numbered (non C-brick) nasids. */ -#define XP_MAX_PHYSNODE_ID (MAX_PHYSNODE_ID / 2) +#define XP_MAX_PHYSNODE_ID (MAX_NUMALINK_NODES / 2) #define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) #define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) From 55642d36cd0f626c614f6dfa1151a5af1ff84f36 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 15 Sep 2005 17:00:10 -0700 Subject: [PATCH 0042/1939] [IA64] Two more uses of cpuid_to_cnodeid() must go. s/cpuid_to_cnodeid/cpu_to_node/ Signed-off-by: Tony Luck --- drivers/char/mmtimer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 12006182f575..78c89a3e7825 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -441,7 +441,7 @@ static irqreturn_t mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int i; - mmtimer_t *base = timers + cpuid_to_cnodeid(smp_processor_id()) * + mmtimer_t *base = timers + cpu_to_node(smp_processor_id()) * NUM_COMPARATORS; unsigned long expires = 0; int result = IRQ_NONE; @@ -608,7 +608,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, */ preempt_disable(); - nodeid = cpuid_to_cnodeid(smp_processor_id()); + nodeid = cpu_to_node(smp_processor_id()); base = timers + nodeid * NUM_COMPARATORS; retry: /* Don't use an allocated timer, or a deleted one that's pending */ From eabf04151682bc7b57c84fea58cf9e4e5a3cf2a9 Mon Sep 17 00:00:00 2001 From: Hubert WS Lin Date: Wed, 14 Sep 2005 11:39:25 -0700 Subject: [PATCH 0043/1939] [PATCH] pcnet32: set_ringparam implementation This patch implements the set_ringparam(), one of the ethtool operations, which allows changing tx/rx ring sizes via ethtool. - Changed memery allocation of tx/rx ring from static to dynamic - Implemented set_ringparam() - Tested on i386 and ppc64 Signed-off-by: Hubert WS Lin Signed-off-by: Jay Vosburgh Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 263 +++++++++++++++++++++++++++++++++--------- 1 file changed, 209 insertions(+), 54 deletions(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 6c3731b608da..7350c27ea2dc 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.30j" -#define DRV_RELDATE "29.04.2005" +#define DRV_VERSION "1.31" +#define DRV_RELDATE "02.Sep.2005" #define PFX DRV_NAME ": " static const char *version = @@ -257,6 +257,7 @@ static int homepna[MAX_UNITS]; * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. * v1.30i 28 Jun 2004 Don Fry change to use module_param. * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. + * v1.31 02 Sep 2005 Hubert WS Lin added set_ringparam(). */ @@ -266,17 +267,17 @@ static int homepna[MAX_UNITS]; * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ #ifndef PCNET32_LOG_TX_BUFFERS -#define PCNET32_LOG_TX_BUFFERS 4 -#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_TX_BUFFERS 4 +#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */ +#define PCNET32_LOG_MAX_RX_BUFFERS 9 #endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) +#define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS)) #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) +#define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) #define PKT_BUF_SZ 1544 @@ -339,8 +340,8 @@ struct pcnet32_access { */ struct pcnet32_private { /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet32_rx_head *rx_ring; + struct pcnet32_tx_head *tx_ring; struct pcnet32_init_block init_block; dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by @@ -349,13 +350,21 @@ struct pcnet32_private { structure */ const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t tx_dma_addr[TX_RING_SIZE]; - dma_addr_t rx_dma_addr[RX_RING_SIZE]; + struct sk_buff **tx_skbuff; + struct sk_buff **rx_skbuff; + dma_addr_t *tx_dma_addr; + dma_addr_t *rx_dma_addr; struct pcnet32_access a; spinlock_t lock; /* Guard lock */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int rx_ring_size; /* current rx ring size */ + unsigned int tx_ring_size; /* current tx ring size */ + unsigned int rx_mod_mask; /* rx ring modular mask */ + unsigned int tx_mod_mask; /* tx ring modular mask */ + unsigned short rx_len_bits; + unsigned short tx_len_bits; + dma_addr_t rx_ring_dma_addr; + dma_addr_t tx_ring_dma_addr; unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; @@ -397,6 +406,9 @@ static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); static void pcnet32_purge_tx_ring(struct net_device *dev); +static int pcnet32_alloc_ring(struct net_device *dev); +static void pcnet32_free_ring(struct net_device *dev); + enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -613,10 +625,59 @@ static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringpar { struct pcnet32_private *lp = dev->priv; - ering->tx_max_pending = TX_RING_SIZE - 1; - ering->tx_pending = lp->cur_tx - lp->dirty_tx; - ering->rx_max_pending = RX_RING_SIZE - 1; - ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK; + ering->tx_max_pending = TX_MAX_RING_SIZE - 1; + ering->tx_pending = lp->tx_ring_size - 1; + ering->rx_max_pending = RX_MAX_RING_SIZE - 1; + ering->rx_pending = lp->rx_ring_size - 1; +} + +static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int i; + + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + if (netif_running(dev)) + pcnet32_close(dev); + + spin_lock_irqsave(&lp->lock, flags); + pcnet32_free_ring(dev); + lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE); + lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE); + + for (i = 0; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { + if (lp->tx_ring_size <= (1 << i)) + break; + } + lp->tx_ring_size = (1 << i); + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->tx_len_bits = (i << 12); + + for (i = 0; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { + if (lp->rx_ring_size <= (1 << i)) + break; + } + lp->rx_ring_size = (1 << i); + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->rx_len_bits = (i << 4); + + if (pcnet32_alloc_ring(dev)) { + pcnet32_free_ring(dev); + return -ENOMEM; + } + + spin_unlock_irqrestore(&lp->lock, flags); + + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_INFO PFX "Ring Param Settings: RX: %d, TX: %d\n", lp->rx_ring_size, lp->tx_ring_size); + + if (netif_running(dev)) + pcnet32_open(dev); + + return 0; } static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -948,6 +1009,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .nway_reset = pcnet32_nway_reset, .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, + .set_ringparam = pcnet32_set_ringparam, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, .get_tso = ethtool_op_get_tso, @@ -1241,6 +1303,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; + lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ + lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); + lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); lp->mii_if.full_duplex = fdx; lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; @@ -1267,21 +1335,23 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } lp->a = *a; + if (pcnet32_alloc_ring(dev)) { + ret = -ENOMEM; + goto err_free_ring; + } /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); @@ -1312,7 +1382,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) if (pcnet32_debug & NETIF_MSG_PROBE) printk(", failed to detect IRQ line.\n"); ret = -ENODEV; - goto err_free_consistent; + goto err_free_ring; } if (pcnet32_debug & NETIF_MSG_PROBE) printk(", probed IRQ %d.\n", dev->irq); @@ -1343,7 +1413,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) - goto err_free_consistent; + goto err_free_ring; if (pdev) { pci_set_drvdata(pdev, dev); @@ -1361,6 +1431,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) return 0; +err_free_ring: + pcnet32_free_ring(dev); err_free_consistent: pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); err_free_netdev: @@ -1371,6 +1443,86 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } +static int pcnet32_alloc_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + if ((lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + &lp->tx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if ((lp->rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + &lp->rx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if (!(lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); + + if (!(lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); + + if (!(lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); + + if (!(lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); + + return 0; +} + + +static void pcnet32_free_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + kfree(lp->tx_skbuff); + lp->tx_skbuff = NULL; + + kfree(lp->rx_skbuff); + lp->rx_skbuff = NULL; + + kfree(lp->tx_dma_addr); + lp->tx_dma_addr = NULL; + + kfree(lp->rx_dma_addr); + lp->rx_dma_addr = NULL; + + if (lp->tx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + lp->tx_ring, lp->tx_ring_dma_addr); + lp->tx_ring = NULL; + } + + if (lp->rx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + lp->rx_ring, lp->rx_ring_dma_addr); + lp->rx_ring = NULL; + } +} + + static int pcnet32_open(struct net_device *dev) { @@ -1402,8 +1554,8 @@ pcnet32_open(struct net_device *dev) if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)), - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)), + (u32) (lp->tx_ring_dma_addr), + (u32) (lp->rx_ring_dma_addr), (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block))); /* set/reset autoselect bit */ @@ -1523,7 +1675,7 @@ pcnet32_open(struct net_device *dev) err_free_ring: /* free any allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, @@ -1533,6 +1685,9 @@ pcnet32_open(struct net_device *dev) lp->rx_skbuff[i] = NULL; lp->rx_dma_addr[i] = 0; } + + pcnet32_free_ring(dev); + /* * Switch back to 16bit mode to avoid problems with dumb * DOS packet driver after a warm reboot @@ -1564,7 +1719,7 @@ pcnet32_purge_tx_ring(struct net_device *dev) struct pcnet32_private *lp = dev->priv; int i; - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -1589,7 +1744,7 @@ pcnet32_init_ring(struct net_device *dev) lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; if (rx_skbuff == NULL) { if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { @@ -1613,20 +1768,18 @@ pcnet32_init_ring(struct net_device *dev) } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ lp->tx_ring[i].base = 0; lp->tx_dma_addr[i] = 0; } - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -1684,13 +1837,13 @@ pcnet32_tx_timeout (struct net_device *dev) printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) + for (i = 0 ; i < lp->rx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->rx_ring[i].base), (-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff, le32_to_cpu(lp->rx_ring[i].msg_length), le16_to_cpu(lp->rx_ring[i].status)); - for (i = 0 ; i < TX_RING_SIZE; i++) + for (i = 0 ; i < lp->tx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->tx_ring[i].base), (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, @@ -1731,7 +1884,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; + entry = lp->cur_tx & lp->tx_mod_mask; /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ @@ -1755,7 +1908,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) { + if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) { lp->tx_full = 1; netif_stop_queue(dev); } @@ -1808,7 +1961,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) int delta; while (dirty_tx != lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; + int entry = dirty_tx & lp->tx_mod_mask; int status = (short)le16_to_cpu(lp->tx_ring[entry].status); if (status < 0) @@ -1866,18 +2019,18 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) dirty_tx++; } - delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE); - if (delta > TX_RING_SIZE) { + delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size); + if (delta > lp->tx_ring_size) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += TX_RING_SIZE; - delta -= TX_RING_SIZE; + dirty_tx += lp->tx_ring_size; + delta -= lp->tx_ring_size; } if (lp->tx_full && netif_queue_stopped(dev) && - delta < TX_RING_SIZE - 2) { + delta < lp->tx_ring_size - 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); @@ -1934,8 +2087,8 @@ static int pcnet32_rx(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int boguscnt = RX_RING_SIZE / 2; + int entry = lp->cur_rx & lp->rx_mod_mask; + int boguscnt = lp->rx_ring_size / 2; /* If we own the next entry, it's a new packet. Send it up. */ while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { @@ -2000,12 +2153,12 @@ pcnet32_rx(struct net_device *dev) if (netif_msg_drv(lp)) printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) + for (i = 0; i < lp->rx_ring_size; i++) if ((short)le16_to_cpu(lp->rx_ring[(entry+i) - & RX_RING_MOD_MASK].status) < 0) + & lp->rx_mod_mask].status) < 0) break; - if (i > RX_RING_SIZE -2) { + if (i > lp->rx_ring_size -2) { lp->stats.rx_dropped++; lp->rx_ring[entry].status |= le16_to_cpu(0x8000); wmb(); /* Make sure adapter sees owner change */ @@ -2043,7 +2196,7 @@ pcnet32_rx(struct net_device *dev) lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + entry = (++lp->cur_rx) & lp->rx_mod_mask; if (--boguscnt <= 0) break; /* don't stay in loop forever */ } @@ -2086,7 +2239,7 @@ pcnet32_close(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); /* free all allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { @@ -2098,7 +2251,7 @@ pcnet32_close(struct net_device *dev) lp->rx_dma_addr[i] = 0; } - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -2267,6 +2420,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) struct pcnet32_private *lp = dev->priv; unregister_netdev(dev); + pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(dev); @@ -2342,6 +2496,7 @@ static void __exit pcnet32_cleanup_module(void) struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); + pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(pcnet32_dev); From 76209926e3756f66c9cdc8a4becbf34df8c47799 Mon Sep 17 00:00:00 2001 From: Hubert WS Lin Date: Wed, 14 Sep 2005 11:39:27 -0700 Subject: [PATCH 0044/1939] [PATCH] pcnet32: set min ring size to 4 Don Fry reminded me that the pcnet32_loopback_test() asssumes the ring size is no less than 4. The minimum ring size was changed to 4 in pcnet32_set_ringparam() to allow the loopback test to work unchanged. - Set minimum ring size to 4 to allow loopback test to work unchanged - Moved variable init_block to first field in struct pcnet32_private Signed-off-by: Hubert WS Lin Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 7350c27ea2dc..70fe81a89df9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.31" -#define DRV_RELDATE "02.Sep.2005" +#define DRV_VERSION "1.31a" +#define DRV_RELDATE "12.Sep.2005" #define PFX DRV_NAME ": " static const char *version = @@ -258,6 +258,8 @@ static int homepna[MAX_UNITS]; * v1.30i 28 Jun 2004 Don Fry change to use module_param. * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. * v1.31 02 Sep 2005 Hubert WS Lin added set_ringparam(). + * v1.31a 12 Sep 2005 Hubert WS Lin set min ring size to 4 + * to allow loopback test to work unchanged. */ @@ -335,14 +337,14 @@ struct pcnet32_access { }; /* - * The first three fields of pcnet32_private are read by the ethernet device - * so we allocate the structure should be allocated by pci_alloc_consistent(). + * The first field of pcnet32_private is read by the ethernet device + * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { + struct pcnet32_init_block init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ struct pcnet32_rx_head *rx_ring; struct pcnet32_tx_head *tx_ring; - struct pcnet32_init_block init_block; dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by pci_alloc_consistent */ @@ -648,7 +650,10 @@ static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringpara lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE); lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE); - for (i = 0; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { + /* set the minimum ring size to 4, to allow the loopback test to work + * unchanged. + */ + for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { if (lp->tx_ring_size <= (1 << i)) break; } @@ -656,7 +661,7 @@ static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringpara lp->tx_mod_mask = lp->tx_ring_size - 1; lp->tx_len_bits = (i << 12); - for (i = 0; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { + for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { if (lp->rx_ring_size <= (1 << i)) break; } From 65853b133d0256786df25f03eea0e5a6799e8d17 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 16 Sep 2005 02:15:13 -0400 Subject: [PATCH 0045/1939] [PATCH] orinoco: Remove conditionals that are useless in the kernel drivers. Author: Pavel Roskin Date: Fri Sep 16 00:49:05 2005 -0400 Remove conditionals that are useless in the kernel drivers. Kernel drivers are never compiled against pcmcia-cs headers. Firmware is never embedded into spectrum_cs module. Signed-off-by: Pavel Roskin Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco_cs.c | 3 --- drivers/net/wireless/spectrum_cs.c | 26 +------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index bedd7f9f23e4..1cedabf583b3 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -14,9 +14,6 @@ #define PFX DRIVER_NAME ": " #include -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif /* __IN_PCMCIA_PACKAGE__ */ #include #include diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 39c6cdf7f3f7..256d31b42966 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -22,9 +22,6 @@ #define PFX DRIVER_NAME ": " #include -#ifdef __IN_PCMCIA_PACKAGE__ -#include -#endif /* __IN_PCMCIA_PACKAGE__ */ #include #include @@ -38,6 +35,7 @@ #include #include #include +#include #include #include @@ -51,29 +49,10 @@ #include "orinoco.h" -/* - * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into - * the driver. Use get_symbol_fw script to generate spectrum_fw.h and - * copy it to the same directory as spectrum_cs.c. - * - * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the - * runtime using hotplug. Use the same get_symbol_fw script to generate - * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the - * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and - * make sure that you have hotplug installed and enabled in the kernel. - */ -/* #define SPECTRUM_FW_INCLUDED 1 */ - -#ifdef SPECTRUM_FW_INCLUDED -/* Header with the firmware */ -#include "spectrum_fw.h" -#else /* !SPECTRUM_FW_INCLUDED */ -#include static unsigned char *primsym; static unsigned char *secsym; static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; -#endif /* !SPECTRUM_FW_INCLUDED */ /********************************************************************/ /* Module stuff */ @@ -571,8 +550,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) { int ret; client_handle_t handle = link->handle; - -#ifndef SPECTRUM_FW_INCLUDED const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, @@ -592,7 +569,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) secondary_fw_name); return -ENOENT; } -#endif /* Load primary firmware */ ret = spectrum_dl_image(hw, link, primsym); From 27c91efba4c121f90c0e6d371c7064733b286a69 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 16 Sep 2005 02:16:52 -0400 Subject: [PATCH 0046/1939] [PATCH] orinoco: Don't include twice. Author: Pavel Roskin Date: Fri Sep 16 00:50:00 2005 -0400 Don't include twice. Signed-off-by: Pavel Roskin Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 639b8e4ba684..77e93a225530 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -94,8 +94,6 @@ #include #include -#include - #include #include #include From 9c8a11d7c2298680ff3ee8acda54575c88668bfc Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 16 Sep 2005 02:18:31 -0400 Subject: [PATCH 0047/1939] [PATCH] orinoco: Update PCMCIA ID's. Author: Pavel Roskin Date: Fri Sep 16 01:07:47 2005 -0400 Update PCMCIA ID's. Intel Pro/Wireless 2011 and 2011B have the same numeric ID, so use strings instead. Take all entries from *.conf for Orinoco, HostAP and linux-wlan-ng and adds them with minimal changes (e.g. we don't need a revision string after a string that identifies the chipset). Add comments with card names to all numeric entries. Note: the comments don't and cannot cover all cards, since the main reason of having numeric IDs is to cover cards that are often rebranded. Signed-off-by: Pavel Roskin Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco_cs.c | 76 ++++++++++++++++++++++-------- drivers/net/wireless/spectrum_cs.c | 2 +- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1cedabf583b3..80920b1c6fcf 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -600,49 +600,85 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION "Pavel Roskin , et al)"; static struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ + PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ + PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ + PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ + PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ + PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ + PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ + PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ + PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), + PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), + PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), + PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), + PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), + PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), + PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), + PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), + PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), + PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 256d31b42966..63e00422d1a0 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -1061,7 +1061,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static struct pcmcia_device_id spectrum_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */ + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); From fd27817ce941c7134adefd2852f8a5f274315ff4 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:25:51 -0500 Subject: [PATCH 0048/1939] [PATCH] Fixed some endian issues with 802.11 header usage in ieee80211_rx.c Fixed some endian issues with 802.11 header usage in ieee80211_rx.c Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_rx.c | 43 ++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index f7dcd854139e..74c4ed77cfd9 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -787,11 +787,11 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, /* Pull out fixed field data */ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); - network->capability = beacon->capability; + network->capability = le16_to_cpu(beacon->capability); network->last_scanned = jiffies; - network->time_stamp[0] = beacon->time_stamp[0]; - network->time_stamp[1] = beacon->time_stamp[1]; - network->beacon_interval = beacon->beacon_interval; + network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]); + network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]); + network->beacon_interval = le16_to_cpu(beacon->beacon_interval); /* Where to pull this? beacon->listen_interval; */ network->listen_interval = 0x0A; network->rates_len = network->rates_ex_len = 0; @@ -1070,8 +1070,9 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(info_element->data, info_element->len), MAC_ARG(beacon->header.addr3), - WLAN_FC_GET_STYPE(beacon->header. - frame_ctl) == + WLAN_FC_GET_STYPE(le16_to_cpu + (beacon->header. + frame_ctl)) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); return; @@ -1122,8 +1123,9 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(network.ssid, network.ssid_len), MAC_ARG(network.bssid), - WLAN_FC_GET_STYPE(beacon->header. - frame_ctl) == + WLAN_FC_GET_STYPE(le16_to_cpu + (beacon->header. + frame_ctl)) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); #endif @@ -1134,8 +1136,9 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(target->ssid, target->ssid_len), MAC_ARG(target->bssid), - WLAN_FC_GET_STYPE(beacon->header. - frame_ctl) == + WLAN_FC_GET_STYPE(le16_to_cpu + (beacon->header. + frame_ctl)) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); update_network(target, &network); @@ -1148,20 +1151,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr *header, struct ieee80211_rx_stats *stats) { - switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { case IEEE80211_STYPE_ASSOC_RESP: IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); break; case IEEE80211_STYPE_REASSOC_RESP: IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); break; case IEEE80211_STYPE_PROBE_RESP: IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); IEEE80211_DEBUG_SCAN("Probe response\n"); ieee80211_process_probe_response(ieee, (struct @@ -1171,7 +1177,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, case IEEE80211_STYPE_BEACON: IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); IEEE80211_DEBUG_SCAN("Beacon\n"); ieee80211_process_probe_response(ieee, (struct @@ -1181,10 +1188,12 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, default: IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); IEEE80211_WARNING("%s: Unknown management packet: %d\n", ieee->dev->name, - WLAN_FC_GET_STYPE(header->frame_ctl)); + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); break; } } From b1b508e1b13529b3cc5b59c352f49b9b58a302b6 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:27:19 -0500 Subject: [PATCH 0049/1939] [PATCH] ieee80211 quality scaling algorithm extension handler Incorporated Bill Moss' quality scaling algorithm into default wireless extension handler. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 3 +++ net/ieee80211/ieee80211_wx.c | 40 +++++++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index dc36b1be6745..ce966b7ff563 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -719,6 +719,9 @@ struct ieee80211_device { int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ int abg_ture; /* ABG flag */ + int perfect_rssi; + int worst_rssi; + /* Callback functions */ void (*set_security)(struct net_device *dev, struct ieee80211_security *sec); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 94882f39b072..04f0897b0653 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -140,18 +140,38 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, start = iwe_stream_add_point(start, stop, &iwe, custom); /* Add quality statistics */ - /* TODO: Fix these values... */ iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = network->stats.signal; - iwe.u.qual.level = network->stats.rssi; - iwe.u.qual.noise = network->stats.noise; - iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; - if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) - iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; - if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) + iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED; + + if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { + iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | + IW_QUAL_LEVEL_INVALID; + iwe.u.qual.qual = 0; + iwe.u.qual.level = 0; + } else { + iwe.u.qual.level = network->stats.rssi; + iwe.u.qual.qual = + (100 * + (ieee->perfect_rssi - ieee->worst_rssi) * + (ieee->perfect_rssi - ieee->worst_rssi) - + (ieee->perfect_rssi - network->stats.rssi) * + (15 * (ieee->perfect_rssi - ieee->worst_rssi) + + 62 * (ieee->perfect_rssi - network->stats.rssi))) / + ((ieee->perfect_rssi - ieee->worst_rssi) * + (ieee->perfect_rssi - ieee->worst_rssi)); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + else if (iwe.u.qual.qual < 1) + iwe.u.qual.qual = 0; + } + + if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; - if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) - iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; + iwe.u.qual.noise = 0; + } else { + iwe.u.qual.noise = network->stats.noise; + } start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); From 74079fdce472a2b16d502fe39e06b135ef06c69b Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:35:21 -0500 Subject: [PATCH 0050/1939] [PATCH] ieee80211 Added wireless spy support Added wireless spy support to Rx code path. Signed-off-by: James Ketrenos NOTE: Looks like scripts/Lindent generated output different than the Lindented version already in-kernel, hence all the whitespace deltas... *sigh* Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 109 +++++++++++---------------- include/net/ieee80211_crypt.h | 24 +++--- net/ieee80211/ieee80211_crypt.c | 24 +++--- net/ieee80211/ieee80211_crypt_ccmp.c | 26 +++---- net/ieee80211/ieee80211_crypt_tkip.c | 26 +++---- net/ieee80211/ieee80211_crypt_wep.c | 26 +++---- net/ieee80211/ieee80211_rx.c | 43 +++++++---- 7 files changed, 134 insertions(+), 144 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index ce966b7ff563..d8bb8f74ed7b 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -20,8 +20,8 @@ */ #ifndef IEEE80211_H #define IEEE80211_H -#include /* ETH_ALEN */ -#include /* ARRAY_SIZE */ +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ #include #define IEEE80211_DATA_LEN 2304 @@ -33,7 +33,6 @@ represents the 2304 bytes of real data, plus a possible 8 bytes of WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ - #define IEEE80211_HLEN 30 #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) @@ -117,7 +116,6 @@ struct ieee80211_hdr_3addr { #define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_SEQ 0xFFF0 - /* debug macros */ #ifdef CONFIG_IEEE80211_DEBUG @@ -128,8 +126,7 @@ do { if (ieee80211_debug_level & (level)) \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #else #define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) -#endif /* CONFIG_IEEE80211_DEBUG */ - +#endif /* CONFIG_IEEE80211_DEBUG */ /* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ @@ -140,7 +137,6 @@ do { if (ieee80211_debug_level & (level)) \ * messages. It should never be used for passing essid to user space. */ const char *escape_essid(const char *essid, u8 essid_len); - /* * To use the debug system: * @@ -192,7 +188,7 @@ const char *escape_essid(const char *essid, u8 essid_len); #define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) #include #include -#include /* ARPHRD_ETHER */ +#include /* ARPHRD_ETHER */ #ifndef WIRELESS_SPY #define WIRELESS_SPY /* enable iwspy support */ @@ -200,10 +196,10 @@ const char *escape_essid(const char *essid, u8 essid_len); #include /* new driver API */ #ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#endif /* ETH_P_PAE */ +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ -#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ #ifndef ETH_P_80211_RAW #define ETH_P_80211_RAW (ETH_P_ECONET + 1) @@ -215,10 +211,10 @@ const char *escape_essid(const char *essid, u8 essid_len); struct ieee80211_snap_hdr { - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ } __attribute__ ((packed)); @@ -312,14 +308,12 @@ enum ieee80211_reasoncode { WLAN_REASON_CIPHER_SUITE_REJECTED = 24, }; - #define IEEE80211_STATMASK_SIGNAL (1<<0) #define IEEE80211_STATMASK_RSSI (1<<1) #define IEEE80211_STATMASK_NOISE (1<<2) #define IEEE80211_STATMASK_RATE (1<<3) #define IEEE80211_STATMASK_WEMASK 0x7 - #define IEEE80211_CCK_MODULATION (1<<0) #define IEEE80211_OFDM_MODULATION (1<<1) @@ -377,9 +371,6 @@ enum ieee80211_reasoncode { #define IEEE80211_NUM_CCK_RATES 4 #define IEEE80211_OFDM_SHIFT_MASK_A 4 - - - /* NOTE: This data is for statistical purposes; not all hardware provides this * information for frames received. Not setting these will not cause * any adverse affects. */ @@ -388,7 +379,7 @@ struct ieee80211_rx_stats { s8 rssi; u8 signal; u8 noise; - u16 rate; /* in 100 kbps */ + u16 rate; /* in 100 kbps */ u8 received_channel; u8 control; u8 mask; @@ -449,28 +440,24 @@ struct ieee80211_device; #define SEC_LEVEL (1<<7) #define SEC_ENABLED (1<<8) -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ #define WEP_KEYS 4 #define WEP_KEY_LEN 13 struct ieee80211_security { u16 active_key:2, - enabled:1, - auth_mode:2, - auth_algo:4, - unicast_uses_group:1; + enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1; u8 key_sizes[WEP_KEYS]; u8 keys[WEP_KEYS][WEP_KEY_LEN]; u8 level; u16 flags; } __attribute__ ((packed)); - /* 802.11 data frame from AP @@ -494,7 +481,7 @@ enum ieee80211_mfie { MFIE_TYPE_RATES = 1, MFIE_TYPE_FH_SET = 2, MFIE_TYPE_DS_SET = 3, - MFIE_TYPE_CF_SET = 4, + MFIE_TYPE_CF_SET = 4, MFIE_TYPE_TIM = 5, MFIE_TYPE_IBSS_SET = 6, MFIE_TYPE_COUNTRY = 7, @@ -554,7 +541,6 @@ struct ieee80211_authentication { struct ieee80211_info_element info_element; } __attribute__ ((packed)); - struct ieee80211_probe_response { struct ieee80211_hdr_3addr header; u32 time_stamp[2]; @@ -575,10 +561,9 @@ struct ieee80211_assoc_response_frame { __le16 capability; __le16 status; __le16 aid; - struct ieee80211_info_element info_element; /* supported rates */ + struct ieee80211_info_element info_element; /* supported rates */ } __attribute__ ((packed)); - struct ieee80211_txb { u8 nr_frags; u8 encrypted; @@ -588,7 +573,6 @@ struct ieee80211_txb { struct sk_buff *fragments[0]; }; - /* SWEEP TABLE ENTRIES NUMBER */ #define MAX_SWEEP_TAB_ENTRIES 42 #define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 @@ -651,7 +635,6 @@ enum ieee80211_state { #define DEFAULT_MAX_SCAN_AGE (15 * HZ) #define DEFAULT_FTS 2346 - #define CFG_IEEE80211_RESERVE_FCS (1<<0) #define CFG_IEEE80211_COMPUTE_FCS (1<<1) @@ -669,24 +652,25 @@ struct ieee80211_device { int scans; int scan_age; - int iw_mode; /* operating mode (IW_MODE_*) */ + int iw_mode; /* operating mode (IW_MODE_*) */ + struct iw_spy_data spy_data; /* iwspy support */ spinlock_t lock; - int tx_headroom; /* Set to size of any additional room needed at front - * of allocated Tx SKBs */ + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ u32 config; /* WEP and other encryption related settings at the device level */ - int open_wep; /* Set to 1 to allow unencrypted frames */ + int open_wep; /* Set to 1 to allow unencrypted frames */ - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on * WEP key changes */ /* If the host performs {en,de}cryption, then set to 1 */ int host_encrypt; int host_decrypt; - int ieee802_1x; /* is IEEE 802.1X used */ + int ieee802_1x; /* is IEEE 802.1X used */ /* WPA data */ int wpa_enabled; @@ -698,36 +682,36 @@ struct ieee80211_device { struct list_head crypt_deinit_list; struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ struct timer_list crypt_deinit_timer; - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ /* Fragmentation structures */ struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; unsigned int frag_next_idx; - u16 fts; /* Fragmentation Threshold */ + u16 fts; /* Fragmentation Threshold */ /* Association info */ u8 bssid[ETH_ALEN]; enum ieee80211_state state; - int mode; /* A, B, G */ - int modulation; /* CCK, OFDM */ - int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ - int abg_ture; /* ABG flag */ + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_ture; /* ABG flag */ int perfect_rssi; int worst_rssi; /* Callback functions */ - void (*set_security)(struct net_device *dev, - struct ieee80211_security *sec); - int (*hard_start_xmit)(struct ieee80211_txb *txb, - struct net_device *dev); - int (*reset_port)(struct net_device *dev); + void (*set_security) (struct net_device * dev, + struct ieee80211_security * sec); + int (*hard_start_xmit) (struct ieee80211_txb * txb, + struct net_device * dev); + int (*reset_port) (struct net_device * dev); /* This must be the last item so that it points to the data * allocated beyond this structure by alloc_ieee80211 */ @@ -760,7 +744,8 @@ extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) return 1; } -extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, + int mode) { /* * It is possible for both access points and our device to support @@ -811,8 +796,6 @@ extern inline int ieee80211_get_hdrlen(u16 fc) return hdrlen; } - - /* ieee80211.c */ extern void free_ieee80211(struct net_device *dev); extern struct net_device *alloc_ieee80211(int sizeof_priv); @@ -820,11 +803,9 @@ extern struct net_device *alloc_ieee80211(int sizeof_priv); extern int ieee80211_set_encryption(struct ieee80211_device *ieee); /* ieee80211_tx.c */ -extern int ieee80211_xmit(struct sk_buff *skb, - struct net_device *dev); +extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); - /* ieee80211_rx.c */ extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); @@ -843,7 +824,6 @@ extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *key); - extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { ieee->scans++; @@ -854,5 +834,4 @@ extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) return ieee->scans; } - -#endif /* IEEE80211_H */ +#endif /* IEEE80211_H */ diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index b58a3bcc0dc0..93bf91fda82e 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -31,10 +31,10 @@ struct ieee80211_crypto_ops { /* init new crypto context (e.g., allocate private data space, * select IV, etc.); returns NULL on failure or pointer to allocated * private data on success */ - void * (*init)(int keyidx); + void *(*init) (int keyidx); /* deinitialize crypto context and free allocated private data */ - void (*deinit)(void *priv); + void (*deinit) (void *priv); /* encrypt/decrypt return < 0 on error or >= 0 on success. The return * value from decrypt_mpdu is passed as the keyidx value for @@ -42,21 +42,21 @@ struct ieee80211_crypto_ops { * encryption; if not, error will be returned; these functions are * called for all MPDUs (i.e., fragments). */ - int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); /* These functions are called for full MSDUs, i.e. full frames. * These can be NULL if full MSDU operations are not needed. */ - int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, - void *priv); + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); - int (*set_key)(void *key, int len, u8 *seq, void *priv); - int (*get_key)(void *key, int len, u8 *seq, void *priv); + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); /* procfs handler for printing out key information and possible * statistics */ - char * (*print_stats)(char *p, void *priv); + char *(*print_stats) (char *p, void *priv); /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and @@ -69,7 +69,7 @@ struct ieee80211_crypto_ops { }; struct ieee80211_crypt_data { - struct list_head list; /* delayed deletion list */ + struct list_head list; /* delayed deletion list */ struct ieee80211_crypto_ops *ops; void *priv; atomic_t refcnt; @@ -77,7 +77,7 @@ struct ieee80211_crypt_data { int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); -struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name); void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); void ieee80211_crypt_deinit_handler(unsigned long); void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 61a9d92e455b..dc835f68edd3 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -191,18 +191,18 @@ static void ieee80211_crypt_null_deinit(void *priv) } static struct ieee80211_crypto_ops ieee80211_crypt_null = { - .name = "NULL", - .init = ieee80211_crypt_null_init, - .deinit = ieee80211_crypt_null_deinit, - .encrypt_mpdu = NULL, - .decrypt_mpdu = NULL, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = NULL, - .get_key = NULL, - .extra_prefix_len = 0, - .extra_postfix_len = 0, - .owner = THIS_MODULE, + .name = "NULL", + .init = ieee80211_crypt_null_init, + .deinit = ieee80211_crypt_null_deinit, + .encrypt_mpdu = NULL, + .decrypt_mpdu = NULL, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = NULL, + .get_key = NULL, + .extra_prefix_len = 0, + .extra_postfix_len = 0, + .owner = THIS_MODULE, }; static int __init ieee80211_crypto_init(void) diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 8fc13f45971e..7b6290885e7d 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -426,19 +426,19 @@ static char *ieee80211_ccmp_print_stats(char *p, void *priv) } static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { - .name = "CCMP", - .init = ieee80211_ccmp_init, - .deinit = ieee80211_ccmp_deinit, - .encrypt_mpdu = ieee80211_ccmp_encrypt, - .decrypt_mpdu = ieee80211_ccmp_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = ieee80211_ccmp_set_key, - .get_key = ieee80211_ccmp_get_key, - .print_stats = ieee80211_ccmp_print_stats, - .extra_prefix_len = CCMP_HDR_LEN, - .extra_postfix_len = CCMP_MIC_LEN, - .owner = THIS_MODULE, + .name = "CCMP", + .init = ieee80211_ccmp_init, + .deinit = ieee80211_ccmp_deinit, + .encrypt_mpdu = ieee80211_ccmp_encrypt, + .decrypt_mpdu = ieee80211_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = ieee80211_ccmp_set_key, + .get_key = ieee80211_ccmp_get_key, + .print_stats = ieee80211_ccmp_print_stats, + .extra_prefix_len = CCMP_HDR_LEN, + .extra_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, }; static int __init ieee80211_crypto_ccmp_init(void) diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index d4f9164be1a1..dca380e57454 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -654,19 +654,19 @@ static char *ieee80211_tkip_print_stats(char *p, void *priv) } static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { - .name = "TKIP", - .init = ieee80211_tkip_init, - .deinit = ieee80211_tkip_deinit, - .encrypt_mpdu = ieee80211_tkip_encrypt, - .decrypt_mpdu = ieee80211_tkip_decrypt, - .encrypt_msdu = ieee80211_michael_mic_add, - .decrypt_msdu = ieee80211_michael_mic_verify, - .set_key = ieee80211_tkip_set_key, - .get_key = ieee80211_tkip_get_key, - .print_stats = ieee80211_tkip_print_stats, - .extra_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_postfix_len = 8 + 4, /* MIC + ICV */ - .owner = THIS_MODULE, + .name = "TKIP", + .init = ieee80211_tkip_init, + .deinit = ieee80211_tkip_deinit, + .encrypt_mpdu = ieee80211_tkip_encrypt, + .decrypt_mpdu = ieee80211_tkip_decrypt, + .encrypt_msdu = ieee80211_michael_mic_add, + .decrypt_msdu = ieee80211_michael_mic_verify, + .set_key = ieee80211_tkip_set_key, + .get_key = ieee80211_tkip_get_key, + .print_stats = ieee80211_tkip_print_stats, + .extra_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .owner = THIS_MODULE, }; static int __init ieee80211_crypto_tkip_init(void) diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index b4d2514a0902..ebe16155e792 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -229,19 +229,19 @@ static char *prism2_wep_print_stats(char *p, void *priv) } static struct ieee80211_crypto_ops ieee80211_crypt_wep = { - .name = "WEP", - .init = prism2_wep_init, - .deinit = prism2_wep_deinit, - .encrypt_mpdu = prism2_wep_encrypt, - .decrypt_mpdu = prism2_wep_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = prism2_wep_set_key, - .get_key = prism2_wep_get_key, - .print_stats = prism2_wep_print_stats, - .extra_prefix_len = 4, /* IV */ - .extra_postfix_len = 4, /* ICV */ - .owner = THIS_MODULE, + .name = "WEP", + .init = prism2_wep_init, + .deinit = prism2_wep_deinit, + .encrypt_mpdu = prism2_wep_encrypt, + .decrypt_mpdu = prism2_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = prism2_wep_set_key, + .get_key = prism2_wep_get_key, + .print_stats = prism2_wep_print_stats, + .extra_prefix_len = 4, /* IV */ + .extra_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, }; static int __init ieee80211_crypto_wep_init(void) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 74c4ed77cfd9..6bbaa44a0d03 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -378,33 +378,47 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, frag = WLAN_GET_SEQ_FRAG(sc); hdrlen = ieee80211_get_hdrlen(fc); -#ifdef NOT_YET -#if WIRELESS_EXT > 15 /* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */ #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ /* If spy monitoring on */ - if (iface->spy_data.spy_number > 0) { + if (ieee->spy_data.spy_number > 0) { struct iw_quality wstats; - wstats.level = rx_stats->signal; - wstats.noise = rx_stats->noise; - wstats.updated = 6; /* No qual value */ + + wstats.updated = 0; + if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { + wstats.level = rx_stats->rssi; + wstats.updated |= IW_QUAL_LEVEL_UPDATED; + } else + wstats.updated |= IW_QUAL_LEVEL_INVALID; + + if (rx_stats->mask & IEEE80211_STATMASK_NOISE) { + wstats.noise = rx_stats->noise; + wstats.updated |= IW_QUAL_NOISE_UPDATED; + } else + wstats.updated |= IW_QUAL_NOISE_INVALID; + + if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) { + wstats.qual = rx_stats->signal; + wstats.updated |= IW_QUAL_QUAL_UPDATED; + } else + wstats.updated |= IW_QUAL_QUAL_INVALID; + /* Update spy records */ - wireless_spy_update(dev, hdr->addr2, &wstats); + wireless_spy_update(ieee->dev, hdr->addr2, &wstats); } #endif /* IW_WIRELESS_SPY */ -#endif /* WIRELESS_EXT > 15 */ + +#ifdef NOT_YET hostap_update_rx_stats(local->ap, hdr, rx_stats); #endif -#if WIRELESS_EXT > 15 if (ieee->iw_mode == IW_MODE_MONITOR) { ieee80211_monitor_rx(ieee, skb, rx_stats); stats->rx_packets++; stats->rx_bytes += skb->len; return 1; } -#endif if (ieee->host_decrypt) { int idx = 0; @@ -771,8 +785,7 @@ static inline int ieee80211_is_ofdm_rate(u8 rate) return 0; } -static inline int ieee80211_network_init(struct ieee80211_device *ieee, - struct ieee80211_probe_response +static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_network *network, struct ieee80211_rx_stats *stats) @@ -1028,11 +1041,9 @@ static inline void update_network(struct ieee80211_network *dst, } static inline void ieee80211_process_probe_response(struct ieee80211_device - *ieee, - struct + *ieee, struct ieee80211_probe_response - *beacon, - struct ieee80211_rx_stats + *beacon, struct ieee80211_rx_stats *stats) { struct ieee80211_network network; From 68e4e036b841d5fb23ae1ac51b1e40baf9d582bf Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:37:22 -0500 Subject: [PATCH 0051/1939] [PATCH] Changed 802.11 headers to use ieee80211_info_element[0] Changed 802.11 headers to use ieee80211_info_element as zero sized array so that sizeof calculations do not account for IE sizes. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 8 ++++---- net/ieee80211/ieee80211_rx.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index d8bb8f74ed7b..6394ae4bf17d 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -538,7 +538,7 @@ struct ieee80211_authentication { __le16 algorithm; __le16 transaction; __le16 status; - struct ieee80211_info_element info_element; + struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); struct ieee80211_probe_response { @@ -546,14 +546,14 @@ struct ieee80211_probe_response { u32 time_stamp[2]; __le16 beacon_interval; __le16 capability; - struct ieee80211_info_element info_element; + struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); struct ieee80211_assoc_request_frame { __le16 capability; __le16 listen_interval; u8 current_ap[ETH_ALEN]; - struct ieee80211_info_element info_element; + struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); struct ieee80211_assoc_response_frame { @@ -561,7 +561,7 @@ struct ieee80211_assoc_response_frame { __le16 capability; __le16 status; __le16 aid; - struct ieee80211_info_element info_element; /* supported rates */ + struct ieee80211_info_element info_element[0]; /* supported rates */ } __attribute__ ((packed)); struct ieee80211_txb { diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 6bbaa44a0d03..cae55e5ccb2e 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -822,7 +822,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->wpa_ie_len = 0; network->rsn_ie_len = 0; - info_element = &beacon->info_element; + info_element = beacon->info_element; left = stats->len - ((void *)info_element - (void *)beacon); while (left >= sizeof(struct ieee80211_info_element_hdr)) { if (sizeof(struct ieee80211_info_element_hdr) + @@ -1050,7 +1050,7 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device struct ieee80211_network *target; struct ieee80211_network *oldest = NULL; #ifdef CONFIG_IEEE80211_DEBUG - struct ieee80211_info_element *info_element = &beacon->info_element; + struct ieee80211_info_element *info_element = beacon->info_element; #endif unsigned long flags; From 7b1fa54020985fa4b154f9f5d2f04ba174c7f1a5 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:38:13 -0500 Subject: [PATCH 0052/1939] [PATCH] ieee80211 Removed ieee80211_info_element_hdr Removed ieee80211_info_element_hdr structure as ieee80211_info_element provides the same use. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 5 ----- net/ieee80211/ieee80211_rx.c | 10 +++++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 6394ae4bf17d..27374c27c408 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -505,11 +505,6 @@ enum ieee80211_mfie { MFIE_TYPE_GENERIC = 221, }; -struct ieee80211_info_element_hdr { - u8 id; - u8 len; -} __attribute__ ((packed)); - struct ieee80211_info_element { u8 id; u8 len; diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index cae55e5ccb2e..e0337c8fcde8 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -823,10 +823,10 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->rsn_ie_len = 0; info_element = beacon->info_element; - left = stats->len - ((void *)info_element - (void *)beacon); - while (left >= sizeof(struct ieee80211_info_element_hdr)) { - if (sizeof(struct ieee80211_info_element_hdr) + - info_element->len > left) { + left = stats->len - sizeof(*beacon); + while (left >= sizeof(struct ieee80211_info_element)) { + if (sizeof(struct ieee80211_info_element) + info_element->len > + left) { IEEE80211_DEBUG_SCAN ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", info_element->len + @@ -967,7 +967,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i break; } - left -= sizeof(struct ieee80211_info_element_hdr) + + left -= sizeof(struct ieee80211_info_element) + info_element->len; info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len]; From 18294d8727b825eb2f3f98d6b6ae4a999dff854a Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:40:29 -0500 Subject: [PATCH 0053/1939] [PATCH] ieee80211 Cleanup memcpy parameters. Cleanup memcpy parameters. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_tx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index c9aaff3fea1e..1a09448016ed 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -285,8 +285,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } /* Save source and destination addresses */ - memcpy(&dest, skb->data, ETH_ALEN); - memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(dest, skb->data, ETH_ALEN); + memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); /* Advance the SKB to the start of the payload */ skb_pull(skb, sizeof(struct ethhdr)); @@ -304,15 +304,15 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) fc |= IEEE80211_FCTL_TODS; /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ - memcpy(&header.addr1, ieee->bssid, ETH_ALEN); - memcpy(&header.addr2, &src, ETH_ALEN); - memcpy(&header.addr3, &dest, ETH_ALEN); + memcpy(header.addr1, ieee->bssid, ETH_ALEN); + memcpy(header.addr2, src, ETH_ALEN); + memcpy(header.addr3, dest, ETH_ALEN); } else if (ieee->iw_mode == IW_MODE_ADHOC) { /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ - memcpy(&header.addr1, dest, ETH_ALEN); - memcpy(&header.addr2, src, ETH_ALEN); - memcpy(&header.addr3, ieee->bssid, ETH_ALEN); + memcpy(header.addr1, dest, ETH_ALEN); + memcpy(header.addr2, src, ETH_ALEN); + memcpy(header.addr3, ieee->bssid, ETH_ALEN); } header.frame_ctl = cpu_to_le16(fc); hdr_len = IEEE80211_3ADDR_LEN; From 262d8e467710a1c870717bc432caaf74cde3ce20 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:42:53 -0500 Subject: [PATCH 0054/1939] [PATCH] ieee80211 Switched to sscanf in store_debug_level Switched to sscanf as per friendly comment in store_debug_level. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_module.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 03a47343ddc7..4b43ae1235f9 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -195,34 +195,20 @@ static int show_debug_level(char *page, char **start, off_t offset, static int store_debug_level(struct file *file, const char __user * buffer, unsigned long count, void *data) { - char buf[] = "0x00000000"; - char *p = (char *)buf; + char buf[] = "0x00000000\n"; + unsigned long len = min((unsigned long)sizeof(buf) - 1, count); unsigned long val; - if (count > sizeof(buf) - 1) - count = sizeof(buf) - 1; - - if (copy_from_user(buf, buffer, count)) + if (copy_from_user(buf, buffer, len)) return count; - buf[count] = 0; - /* - * what a FPOS... What, sscanf(buf, "%i", &val) would be too - * scary? - */ - if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { - p++; - if (p[0] == 'x' || p[0] == 'X') - p++; - val = simple_strtoul(p, &p, 16); - } else - val = simple_strtoul(p, &p, 10); - if (p == buf) + buf[len] = 0; + if (sscanf(buf, "%li", &val) != 1) printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else ieee80211_debug_level = val; - return strlen(buf); + return strnlen(buf, len); } static int __init ieee80211_init(void) From 3bc5ed684253f407b1567799d13cb06a0d86fe80 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:48:54 -0500 Subject: [PATCH 0055/1939] [PATCH] ieee80211 Fixed type-o of abg_ture -> abg_true [PATCH 14/29] Fixed type-o of abg_ture -> abg_true. Signed-off-by: James Ketrenos NOTE: This patch requires drivers using abg_ture to be updated. Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 27374c27c408..2d9c679cf6b6 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -696,7 +696,7 @@ struct ieee80211_device { int mode; /* A, B, G */ int modulation; /* CCK, OFDM */ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ - int abg_ture; /* ABG flag */ + int abg_true; /* ABG flag */ int perfect_rssi; int worst_rssi; From a33a1982012e9070736e3717231714dc9892303b Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 14 Sep 2005 14:28:59 -0500 Subject: [PATCH 0056/1939] [PATCH] Updated ipw2200 to compile with ieee80211 abg_ture to abg_true change author James Ketrenos 1126713327 -0500 committer James Ketrenos 1126713327 -0500 Updated ipw2200 to compile with ieee80211 abg_ture to abg_true change. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2200.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b7f275c00de3..86feef732dbb 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6010,12 +6010,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } if (priv->adapter == IPW_2915ABG) { - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; if (mode & IEEE_A) { band |= IEEE80211_52GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } else { if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " @@ -6023,20 +6023,20 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, return -EINVAL; } - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } if (mode & IEEE_B) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_CCK_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; if (mode & IEEE_G) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; priv->ieee->mode = mode; priv->ieee->freq_band = band; @@ -7108,7 +7108,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; @@ -7124,7 +7124,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; band = IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; From 54703d3678d13e7406d0b5aa451abb9526d53b9d Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Wed, 14 Sep 2005 10:33:40 -0500 Subject: [PATCH 0057/1939] [IA64] Increase max NR_CPUS on IA64 from 512 to 1024 This patch increases the maximum number of cpus supported on IA64 to 1024. No changes are made to the default SSI size. The patch simply allows specifying up to 1024p. There are certainly scaling (& other) issues that also need to be addressed!!! Additional patches will follow..... Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- arch/ia64/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 945c15a0722b..cb7fc19ff080 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -254,8 +254,8 @@ config SMP If you don't know what to do here, say N. config NR_CPUS - int "Maximum number of CPUs (2-512)" - range 2 512 + int "Maximum number of CPUs (2-1024)" + range 2 1024 depends on SMP default "64" help From 0a1e1222b77b9b02457d8126f598e3713559d5c7 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Tue, 6 Sep 2005 15:51:47 -0500 Subject: [PATCH 0058/1939] [PATCH] powerpc: Merge kmap_types.h Here is a patch to merge the ppc and pp64 version of kmap_types.h Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/asm-powerpc/kmap_types.h | 33 ++++++++++++++++++++++++++++++++ include/asm-ppc/kmap_types.h | 25 ------------------------ include/asm-ppc64/kmap_types.h | 23 ---------------------- 3 files changed, 33 insertions(+), 48 deletions(-) create mode 100644 include/asm-powerpc/kmap_types.h delete mode 100644 include/asm-ppc/kmap_types.h delete mode 100644 include/asm-ppc64/kmap_types.h diff --git a/include/asm-powerpc/kmap_types.h b/include/asm-powerpc/kmap_types.h new file mode 100644 index 000000000000..b6bac6f61c16 --- /dev/null +++ b/include/asm-powerpc/kmap_types.h @@ -0,0 +1,33 @@ +#ifndef _ASM_POWERPC_KMAP_TYPES_H +#define _ASM_POWERPC_KMAP_TYPES_H + +#ifdef __KERNEL__ + +/* + * 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. + */ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_PPC_SYNC_PAGE, + KM_PPC_SYNC_ICACHE, + KM_TYPE_NR +}; + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_KMAP_TYPES_H */ diff --git a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h deleted file mode 100644 index 6d6fc78731e5..000000000000 --- a/include/asm-ppc/kmap_types.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _ASM_KMAP_TYPES_H -#define _ASM_KMAP_TYPES_H - -enum km_type { - KM_BOUNCE_READ, - KM_SKB_SUNRPC_DATA, - KM_SKB_DATA_SOFTIRQ, - KM_USER0, - KM_USER1, - KM_BIO_SRC_IRQ, - KM_BIO_DST_IRQ, - KM_PTE0, - KM_PTE1, - KM_IRQ0, - KM_IRQ1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, - KM_PPC_SYNC_PAGE, - KM_PPC_SYNC_ICACHE, - KM_TYPE_NR -}; - -#endif -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc64/kmap_types.h b/include/asm-ppc64/kmap_types.h deleted file mode 100644 index fd1574648223..000000000000 --- a/include/asm-ppc64/kmap_types.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _ASM_KMAP_TYPES_H -#define _ASM_KMAP_TYPES_H - -enum km_type { - KM_BOUNCE_READ, - KM_SKB_SUNRPC_DATA, - KM_SKB_DATA_SOFTIRQ, - KM_USER0, - KM_USER1, - KM_BIO_SRC_IRQ, - KM_BIO_DST_IRQ, - KM_PTE0, - KM_PTE1, - KM_IRQ0, - KM_IRQ1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, - KM_TYPE_NR -}; - -#endif -#endif /* __KERNEL__ */ From 5f7c690728ace1404f72d74972dcc261674c0dd4 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 9 Sep 2005 15:02:25 -0500 Subject: [PATCH 0059/1939] [PATCH] powerpc: Merged ppc_asm.h Merged ppc_asm.h between ppc32 & ppc64. The majority of the file is common between the two architectures excluding how a single GPR is saved/restored and which GPRs are non-volatile. Additionally, moved the ASM_CONST macro used on ppc64 into ppc_asm.h. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/head.S | 6 +- arch/ppc/kernel/head_fsl_booke.S | 6 +- include/{asm-ppc => asm-powerpc}/ppc_asm.h | 211 ++++++++++++------ include/asm-ppc64/cputable.h | 2 +- include/asm-ppc64/mmu.h | 1 + include/asm-ppc64/page.h | 8 +- include/asm-ppc64/ppc_asm.h | 242 --------------------- 7 files changed, 158 insertions(+), 318 deletions(-) rename include/{asm-ppc => asm-powerpc}/ppc_asm.h (62%) delete mode 100644 include/asm-ppc64/ppc_asm.h diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 1960fb8c259c..d05509f197d0 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -804,7 +804,7 @@ load_up_altivec: beq 1f add r4,r4,r6 addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ - SAVE_32VR(0,r10,r4) + SAVE_32VRS(0,r10,r4) mfvscr vr0 li r10,THREAD_VSCR stvx vr0,r10,r4 @@ -824,7 +824,7 @@ load_up_altivec: stw r4,THREAD_USED_VR(r5) lvx vr0,r10,r5 mtvscr vr0 - REST_32VR(0,r10,r5) + REST_32VRS(0,r10,r5) #ifndef CONFIG_SMP subi r4,r5,THREAD sub r4,r4,r6 @@ -870,7 +870,7 @@ giveup_altivec: addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) cmpwi 0,r5,0 - SAVE_32VR(0, r4, r3) + SAVE_32VRS(0, r4, r3) mfvscr vr0 li r4,THREAD_VSCR stvx vr0,r4,r3 diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index 8e52e8408316..eba5a5f8ff08 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -853,7 +853,7 @@ load_up_spe: cmpi 0,r4,0 beq 1f addi r4,r4,THREAD /* want THREAD of last_task_used_spe */ - SAVE_32EVR(0,r10,r4) + SAVE_32EVRS(0,r10,r4) evxor evr10, evr10, evr10 /* clear out evr10 */ evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */ li r5,THREAD_ACC @@ -873,7 +873,7 @@ load_up_spe: stw r4,THREAD_USED_SPE(r5) evlddx evr4,r10,r5 evmra evr4,evr4 - REST_32EVR(0,r10,r5) + REST_32EVRS(0,r10,r5) #ifndef CONFIG_SMP subi r4,r5,THREAD stw r4,last_task_used_spe@l(r3) @@ -963,7 +963,7 @@ _GLOBAL(giveup_spe) addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) cmpi 0,r5,0 - SAVE_32EVR(0, r4, r3) + SAVE_32EVRS(0, r4, r3) evxor evr6, evr6, evr6 /* clear out evr6 */ evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */ li r4,THREAD_ACC diff --git a/include/asm-ppc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h similarity index 62% rename from include/asm-ppc/ppc_asm.h rename to include/asm-powerpc/ppc_asm.h index bb53e2def363..553035cda00e 100644 --- a/include/asm-ppc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -1,37 +1,39 @@ /* - * include/asm-ppc/ppc_asm.h - * - * Definitions used by various bits of low-level assembly code on PowerPC. - * * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. - * - * 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 +#ifndef _ASM_POWERPC_PPC_ASM_H +#define _ASM_POWERPC_PPC_ASM_H + +#ifdef __ASSEMBLY__ /* * Macros for storing registers into and loading registers from * exception frames. */ +#ifdef __powerpc64__ +#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) +#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) +#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) +#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base) +#else #define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) #define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - #define SAVE_NVGPRS(base) SAVE_GPR(13, base); SAVE_8GPRS(14, base); \ SAVE_10GPRS(22, base) #define REST_NVGPRS(base) REST_GPR(13, base); REST_8GPRS(14, base); \ REST_10GPRS(22, base) +#endif + + +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) #define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) #define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) @@ -47,32 +49,80 @@ #define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) #define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); stvx n,b,base -#define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) -#define SAVE_4VR(n,b,base) SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) -#define SAVE_8VR(n,b,base) SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) -#define SAVE_16VR(n,b,base) SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base) -#define SAVE_32VR(n,b,base) SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base) +#define SAVE_2VRS(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) +#define SAVE_4VRS(n,b,base) SAVE_2VRS(n,b,base); SAVE_2VRS(n+2,b,base) +#define SAVE_8VRS(n,b,base) SAVE_4VRS(n,b,base); SAVE_4VRS(n+4,b,base) +#define SAVE_16VRS(n,b,base) SAVE_8VRS(n,b,base); SAVE_8VRS(n+8,b,base) +#define SAVE_32VRS(n,b,base) SAVE_16VRS(n,b,base); SAVE_16VRS(n+16,b,base) #define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); lvx n,b,base -#define REST_2VR(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) -#define REST_4VR(n,b,base) REST_2VR(n,b,base); REST_2VR(n+2,b,base) -#define REST_8VR(n,b,base) REST_4VR(n,b,base); REST_4VR(n+4,b,base) -#define REST_16VR(n,b,base) REST_8VR(n,b,base); REST_8VR(n+8,b,base) -#define REST_32VR(n,b,base) REST_16VR(n,b,base); REST_16VR(n+16,b,base) +#define REST_2VRS(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) +#define REST_4VRS(n,b,base) REST_2VRS(n,b,base); REST_2VRS(n+2,b,base) +#define REST_8VRS(n,b,base) REST_4VRS(n,b,base); REST_4VRS(n+4,b,base) +#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base) +#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base) #define SAVE_EVR(n,s,base) evmergehi s,s,n; stw s,THREAD_EVR0+4*(n)(base) -#define SAVE_2EVR(n,s,base) SAVE_EVR(n,s,base); SAVE_EVR(n+1,s,base) -#define SAVE_4EVR(n,s,base) SAVE_2EVR(n,s,base); SAVE_2EVR(n+2,s,base) -#define SAVE_8EVR(n,s,base) SAVE_4EVR(n,s,base); SAVE_4EVR(n+4,s,base) -#define SAVE_16EVR(n,s,base) SAVE_8EVR(n,s,base); SAVE_8EVR(n+8,s,base) -#define SAVE_32EVR(n,s,base) SAVE_16EVR(n,s,base); SAVE_16EVR(n+16,s,base) - +#define SAVE_2EVRS(n,s,base) SAVE_EVR(n,s,base); SAVE_EVR(n+1,s,base) +#define SAVE_4EVRS(n,s,base) SAVE_2EVRS(n,s,base); SAVE_2EVRS(n+2,s,base) +#define SAVE_8EVRS(n,s,base) SAVE_4EVRS(n,s,base); SAVE_4EVRS(n+4,s,base) +#define SAVE_16EVRS(n,s,base) SAVE_8EVRS(n,s,base); SAVE_8EVRS(n+8,s,base) +#define SAVE_32EVRS(n,s,base) SAVE_16EVRS(n,s,base); SAVE_16EVRS(n+16,s,base) #define REST_EVR(n,s,base) lwz s,THREAD_EVR0+4*(n)(base); evmergelo n,s,n -#define REST_2EVR(n,s,base) REST_EVR(n,s,base); REST_EVR(n+1,s,base) -#define REST_4EVR(n,s,base) REST_2EVR(n,s,base); REST_2EVR(n+2,s,base) -#define REST_8EVR(n,s,base) REST_4EVR(n,s,base); REST_4EVR(n+4,s,base) -#define REST_16EVR(n,s,base) REST_8EVR(n,s,base); REST_8EVR(n+8,s,base) -#define REST_32EVR(n,s,base) REST_16EVR(n,s,base); REST_16EVR(n+16,s,base) +#define REST_2EVRS(n,s,base) REST_EVR(n,s,base); REST_EVR(n+1,s,base) +#define REST_4EVRS(n,s,base) REST_2EVRS(n,s,base); REST_2EVRS(n+2,s,base) +#define REST_8EVRS(n,s,base) REST_4EVRS(n,s,base); REST_4EVRS(n+4,s,base) +#define REST_16EVRS(n,s,base) REST_8EVRS(n,s,base); REST_8EVRS(n+8,s,base) +#define REST_32EVRS(n,s,base) REST_16EVRS(n,s,base); REST_16EVRS(n+16,s,base) +/* Macros to adjust thread priority for Iseries hardware multithreading */ +#define HMT_LOW or 1,1,1 +#define HMT_MEDIUM or 2,2,2 +#define HMT_HIGH or 3,3,3 + +/* handle instructions that older assemblers may not know */ +#define RFCI .long 0x4c000066 /* rfci instruction */ +#define RFDI .long 0x4c00004e /* rfdi instruction */ +#define RFMCI .long 0x4c00004c /* rfmci instruction */ + +/* + * LOADADDR( rn, name ) + * loads the address of 'name' into 'rn' + * + * LOADBASE( rn, name ) + * loads the address (less the low 16 bits) of 'name' into 'rn' + * suitable for base+disp addressing + */ +#ifdef __powerpc64__ +#define LOADADDR(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + +#define LOADBASE(rn,name) \ + lis rn,name@highest; \ + ori rn,rn,name@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name@ha + + +#define SET_REG_TO_CONST(reg, value) \ + lis reg,(((value)>>48)&0xFFFF); \ + ori reg,reg,(((value)>>32)&0xFFFF); \ + rldicr reg,reg,32,31; \ + oris reg,reg,(((value)>>16)&0xFFFF); \ + ori reg,reg,((value)&0xFFFF); + +#define SET_REG_TO_LABEL(reg, label) \ + lis reg,(label)@highest; \ + ori reg,reg,(label)@higher; \ + rldicr reg,reg,32,31; \ + oris reg,reg,(label)@h; \ + ori reg,reg,(label)@l; +#endif + +/* various errata or part fixups */ #ifdef CONFIG_PPC601_SYNC_FIX #define SYNC \ BEGIN_FTR_SECTION \ @@ -93,6 +143,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) #define ISYNC_601 #endif + #ifndef CONFIG_SMP #define TLBSYNC #else /* CONFIG_SMP */ @@ -104,6 +155,7 @@ BEGIN_FTR_SECTION \ END_FTR_SECTION_IFCLR(CPU_FTR_601) #endif + /* * This instruction is not implemented on the PPC 603 or 601; however, on * the 403GCX and 405GP tlbia IS defined and tlbie is not. @@ -121,14 +173,44 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) bdnz 0b #endif -#ifdef CONFIG_BOOKE + +#ifdef CONFIG_IBM405_ERR77 +#define PPC405_ERR77(ra,rb) dcbt ra, rb; +#define PPC405_ERR77_SYNC sync; +#else +#define PPC405_ERR77(ra,rb) +#define PPC405_ERR77_SYNC +#endif + + +#ifdef CONFIG_IBM440EP_ERR42 +#define PPC440EP_ERR42 isync +#else +#define PPC440EP_ERR42 +#endif + + +#if defined(CONFIG_BOOKE) #define tophys(rd,rs) \ addis rd,rs,0 #define tovirt(rd,rs) \ addis rd,rs,0 -#else /* CONFIG_BOOKE */ +#elif defined(CONFIG_PPC64) +/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., + * Then we can easily do this with one asm insn. -Peter + */ +#define tophys(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + sub rd,rs,rd + +#define tovirt(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + add rd,rs,rd +#else /* * On APUS (Amiga PowerPC cpu upgrade board), we don't know the * physical base address of RAM at compile time. @@ -146,14 +228,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) .align 1; \ .long 0b; \ .previous -#endif /* CONFIG_BOOKE */ +#endif /* * On 64-bit cpus, we use the rfid instruction instead of rfi, but * we then have to make sure we preserve the top 32 bits except for * the 64-bit mode bit, which we clear. */ -#ifdef CONFIG_PPC64BRIDGE +#if defined(CONFIG_PPC64BRIDGE) #define FIX_SRR1(ra, rb) \ mr rb,ra; \ mfmsr ra; \ @@ -162,6 +244,17 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define RFI .long 0x4c000024 /* rfid instruction */ #define MTMSRD(r) .long (0x7c000164 + ((r) << 21)) /* mtmsrd */ #define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ +#elif defined(CONFIG_PPC64) +/* Insert the high 32 bits of the MSR into what will be the new + MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF + bits. */ + +#define FIX_SRR1(ra, rb) \ + mr rb,ra; \ + mfmsr ra; \ + rldimi ra,rb,0,32 + +#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ #else #define FIX_SRR1(ra, rb) @@ -172,24 +265,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #endif #define MTMSRD(r) mtmsr r #define CLR_TOP32(r) -#endif /* CONFIG_PPC64BRIDGE */ - -#define RFCI .long 0x4c000066 /* rfci instruction */ -#define RFDI .long 0x4c00004e /* rfdi instruction */ -#define RFMCI .long 0x4c00004c /* rfmci instruction */ - -#ifdef CONFIG_IBM405_ERR77 -#define PPC405_ERR77(ra,rb) dcbt ra, rb; -#define PPC405_ERR77_SYNC sync; -#else -#define PPC405_ERR77(ra,rb) -#define PPC405_ERR77_SYNC -#endif - -#ifdef CONFIG_IBM440EP_ERR42 -#define PPC440EP_ERR42 isync -#else -#define PPC440EP_ERR42 #endif /* The boring bits... */ @@ -277,6 +352,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define fr30 30 #define fr31 31 +/* AltiVec Registers (VPRs) */ + #define vr0 0 #define vr1 1 #define vr2 2 @@ -310,6 +387,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define vr30 30 #define vr31 31 +/* SPE Registers (EVPRs) */ + #define evr0 0 #define evr1 1 #define evr2 2 @@ -348,3 +427,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define N_RSYM 64 #define N_SLINE 68 #define N_SO 100 + +#define ASM_CONST(x) x +#else + #define __ASM_CONST(x) x##UL + #define ASM_CONST(x) __ASM_CONST(x) +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_POWERPC_PPC_ASM_H */ diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h index acc9b4d6c168..35121408ed1c 100644 --- a/include/asm-ppc64/cputable.h +++ b/include/asm-ppc64/cputable.h @@ -16,7 +16,7 @@ #define __ASM_PPC_CPUTABLE_H #include -#include /* for ASM_CONST */ +#include /* for ASM_CONST */ /* Exposed to userland CPU features - Must match ppc32 definitions */ #define PPC_FEATURE_32 0x80000000 diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h index 7bc42eb087ad..737e85a5ce3c 100644 --- a/include/asm-ppc64/mmu.h +++ b/include/asm-ppc64/mmu.h @@ -14,6 +14,7 @@ #define _PPC64_MMU_H_ #include +#include /* for ASM_CONST */ #include /* diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index a15422bcf30d..d404431f0a9a 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h @@ -11,13 +11,7 @@ */ #include - -#ifdef __ASSEMBLY__ - #define ASM_CONST(x) x -#else - #define __ASM_CONST(x) x##UL - #define ASM_CONST(x) __ASM_CONST(x) -#endif +#include /* for ASM_CONST */ /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 diff --git a/include/asm-ppc64/ppc_asm.h b/include/asm-ppc64/ppc_asm.h deleted file mode 100644 index 9031d8a29aca..000000000000 --- a/include/asm-ppc64/ppc_asm.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * arch/ppc64/kernel/ppc_asm.h - * - * Definitions used by various bits of low-level assembly code on PowerPC. - * - * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. - * - * 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 _PPC64_PPC_ASM_H -#define _PPC64_PPC_ASM_H -/* - * Macros for storing registers into and loading registers from - * exception frames. - */ -#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) -#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - -#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) -#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base) - -#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) -#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) -#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) -#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) -#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) -#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) -#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) -#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) -#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) -#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) -#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) -#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) - -#define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); stvx n,b,base -#define SAVE_2VRS(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) -#define SAVE_4VRS(n,b,base) SAVE_2VRS(n,b,base); SAVE_2VRS(n+2,b,base) -#define SAVE_8VRS(n,b,base) SAVE_4VRS(n,b,base); SAVE_4VRS(n+4,b,base) -#define SAVE_16VRS(n,b,base) SAVE_8VRS(n,b,base); SAVE_8VRS(n+8,b,base) -#define SAVE_32VRS(n,b,base) SAVE_16VRS(n,b,base); SAVE_16VRS(n+16,b,base) -#define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); lvx n,b,base -#define REST_2VRS(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) -#define REST_4VRS(n,b,base) REST_2VRS(n,b,base); REST_2VRS(n+2,b,base) -#define REST_8VRS(n,b,base) REST_4VRS(n,b,base); REST_4VRS(n+4,b,base) -#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base) -#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base) - -/* Macros to adjust thread priority for Iseries hardware multithreading */ -#define HMT_LOW or 1,1,1 -#define HMT_MEDIUM or 2,2,2 -#define HMT_HIGH or 3,3,3 - -/* Insert the high 32 bits of the MSR into what will be the new - MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF - bits. */ - -#define FIX_SRR1(ra, rb) \ - mr rb,ra; \ - mfmsr ra; \ - rldimi ra,rb,0,32 - -#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ - -/* - * LOADADDR( rn, name ) - * loads the address of 'name' into 'rn' - * - * LOADBASE( rn, name ) - * loads the address (less the low 16 bits) of 'name' into 'rn' - * suitable for base+disp addressing - */ -#define LOADADDR(rn,name) \ - lis rn,name##@highest; \ - ori rn,rn,name##@higher; \ - rldicr rn,rn,32,31; \ - oris rn,rn,name##@h; \ - ori rn,rn,name##@l - -#define LOADBASE(rn,name) \ - lis rn,name@highest; \ - ori rn,rn,name@higher; \ - rldicr rn,rn,32,31; \ - oris rn,rn,name@ha - - -#define SET_REG_TO_CONST(reg, value) \ - lis reg,(((value)>>48)&0xFFFF); \ - ori reg,reg,(((value)>>32)&0xFFFF); \ - rldicr reg,reg,32,31; \ - oris reg,reg,(((value)>>16)&0xFFFF); \ - ori reg,reg,((value)&0xFFFF); - -#define SET_REG_TO_LABEL(reg, label) \ - lis reg,(label)@highest; \ - ori reg,reg,(label)@higher; \ - rldicr reg,reg,32,31; \ - oris reg,reg,(label)@h; \ - ori reg,reg,(label)@l; - - -/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., - * Then we can easily do this with one asm insn. -Peter - */ -#define tophys(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - sub rd,rs,rd - -#define tovirt(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - add rd,rs,rd - -/* Condition Register Bit Fields */ - -#define cr0 0 -#define cr1 1 -#define cr2 2 -#define cr3 3 -#define cr4 4 -#define cr5 5 -#define cr6 6 -#define cr7 7 - - -/* General Purpose Registers (GPRs) */ - -#define r0 0 -#define r1 1 -#define r2 2 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 -#define r9 9 -#define r10 10 -#define r11 11 -#define r12 12 -#define r13 13 -#define r14 14 -#define r15 15 -#define r16 16 -#define r17 17 -#define r18 18 -#define r19 19 -#define r20 20 -#define r21 21 -#define r22 22 -#define r23 23 -#define r24 24 -#define r25 25 -#define r26 26 -#define r27 27 -#define r28 28 -#define r29 29 -#define r30 30 -#define r31 31 - - -/* Floating Point Registers (FPRs) */ - -#define fr0 0 -#define fr1 1 -#define fr2 2 -#define fr3 3 -#define fr4 4 -#define fr5 5 -#define fr6 6 -#define fr7 7 -#define fr8 8 -#define fr9 9 -#define fr10 10 -#define fr11 11 -#define fr12 12 -#define fr13 13 -#define fr14 14 -#define fr15 15 -#define fr16 16 -#define fr17 17 -#define fr18 18 -#define fr19 19 -#define fr20 20 -#define fr21 21 -#define fr22 22 -#define fr23 23 -#define fr24 24 -#define fr25 25 -#define fr26 26 -#define fr27 27 -#define fr28 28 -#define fr29 29 -#define fr30 30 -#define fr31 31 - -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 - -#endif /* _PPC64_PPC_ASM_H */ From 7da8f8600a4751d7f0248e00d973901b7371fabc Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 16 Sep 2005 11:37:33 -0500 Subject: [PATCH 0060/1939] [PATCH] ppc32: Removed non-inlined versions of local_irq* functions We always use the inlined versions of local_irq_enable, local_irq_disable, local_save_flags_ptr, and local_irq_restore on ppc32 so the non-inlined versions where just taking up space. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/misc.S | 128 ------------------------------------ arch/ppc/kernel/ppc_ksyms.c | 10 --- include/asm-ppc/hw_irq.h | 16 ----- 3 files changed, 154 deletions(-) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 90d917d2e856..9d2cb79475c6 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -273,134 +273,6 @@ _GLOBAL(low_choose_7447a_dfs) #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */ -/* void local_save_flags_ptr(unsigned long *flags) */ -_GLOBAL(local_save_flags_ptr) - mfmsr r4 - stw r4,0(r3) - blr - /* - * Need these nops here for taking over save/restore to - * handle lost intrs - * -- Cort - */ - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -_GLOBAL(local_save_flags_ptr_end) - -/* void local_irq_restore(unsigned long flags) */ -_GLOBAL(local_irq_restore) -/* - * Just set/clear the MSR_EE bit through restore/flags but do not - * change anything else. This is needed by the RT system and makes - * sense anyway. - * -- Cort - */ - mfmsr r4 - /* Copy all except the MSR_EE bit from r4 (current MSR value) - to r3. This is the sort of thing the rlwimi instruction is - designed for. -- paulus. */ - rlwimi r3,r4,0,17,15 - /* Check if things are setup the way we want _already_. */ - cmpw 0,r3,r4 - beqlr -1: SYNC - mtmsr r3 - SYNC - blr - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -_GLOBAL(local_irq_restore_end) - -_GLOBAL(local_irq_disable) - mfmsr r0 /* Get current interrupt state */ - rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ - SYNC /* Some chip revs have problems here... */ - mtmsr r0 /* Update machine state */ - blr /* Done */ - /* - * Need these nops here for taking over save/restore to - * handle lost intrs - * -- Cort - */ - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -_GLOBAL(local_irq_disable_end) - -_GLOBAL(local_irq_enable) - mfmsr r3 /* Get current state */ - ori r3,r3,MSR_EE /* Turn on 'EE' bit */ - SYNC /* Some chip revs have problems here... */ - mtmsr r3 /* Update machine state */ - blr - /* - * Need these nops here for taking over save/restore to - * handle lost intrs - * -- Cort - */ - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -_GLOBAL(local_irq_enable_end) - /* * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 88f6bb7b6964..1545621d44d2 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -272,16 +272,6 @@ EXPORT_SYMBOL(screen_info); #endif EXPORT_SYMBOL(__delay); -#ifndef INLINE_IRQS -EXPORT_SYMBOL(local_irq_enable); -EXPORT_SYMBOL(local_irq_enable_end); -EXPORT_SYMBOL(local_irq_disable); -EXPORT_SYMBOL(local_irq_disable_end); -EXPORT_SYMBOL(local_save_flags_ptr); -EXPORT_SYMBOL(local_save_flags_ptr_end); -EXPORT_SYMBOL(local_irq_restore); -EXPORT_SYMBOL(local_irq_restore_end); -#endif EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); EXPORT_SYMBOL(tb_ticks_per_jiffy); diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h index 47dc7990fb26..51a1d7ef5253 100644 --- a/include/asm-ppc/hw_irq.h +++ b/include/asm-ppc/hw_irq.h @@ -10,12 +10,8 @@ extern void timer_interrupt(struct pt_regs *); -#define INLINE_IRQS - #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) -#ifdef INLINE_IRQS - static inline void local_irq_disable(void) { unsigned long msr; @@ -45,18 +41,6 @@ static inline void local_irq_save_ptr(unsigned long *flags) #define local_irq_save(flags) local_irq_save_ptr(&flags) #define local_irq_restore(flags) mtmsr(flags) -#else - -extern void local_irq_enable(void); -extern void local_irq_disable(void); -extern void local_irq_restore(unsigned long); -extern void local_save_flags_ptr(unsigned long *); - -#define local_save_flags(flags) local_save_flags_ptr(&flags) -#define local_irq_save(flags) ({local_save_flags(flags);local_irq_disable();}) - -#endif - extern void do_lost_interrupts(unsigned long); #define mask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->disable) irq_desc[irq].handler->disable(irq);}) From f495a8bfd6a52cf32859f93d5320bb234d8a9560 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 17 Sep 2005 10:35:08 -0500 Subject: [PATCH 0061/1939] [PATCH] powerpc: Remove sections use from ppc Here is a new patch that removes all notion of the pmac, prep, chrp and openfirmware initialization sections, and then unifies the sections.h files without those __pmac, etc, sections identifiers cluttering things up. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/pci.c | 10 +- arch/ppc/kernel/setup.c | 2 +- arch/ppc/platforms/chrp_pci.c | 8 +- arch/ppc/platforms/chrp_setup.c | 16 +-- arch/ppc/platforms/chrp_smp.c | 2 +- arch/ppc/platforms/chrp_time.c | 8 +- arch/ppc/platforms/pmac_backlight.c | 16 +-- arch/ppc/platforms/pmac_cpufreq.c | 36 +++--- arch/ppc/platforms/pmac_feature.c | 176 ++++++++++++++-------------- arch/ppc/platforms/pmac_nvram.c | 42 +++---- arch/ppc/platforms/pmac_pci.c | 22 ++-- arch/ppc/platforms/pmac_pic.c | 26 ++-- arch/ppc/platforms/pmac_setup.c | 12 +- arch/ppc/platforms/pmac_smp.c | 10 +- arch/ppc/platforms/pmac_time.c | 8 +- arch/ppc/platforms/prep_pci.c | 64 +++++----- arch/ppc/platforms/prep_setup.c | 44 +++---- arch/ppc/platforms/residual.c | 2 +- arch/ppc/syslib/btext.c | 6 +- arch/ppc/syslib/prep_nvram.c | 13 +- arch/ppc/syslib/prom.c | 18 +-- 21 files changed, 269 insertions(+), 272 deletions(-) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 854e45beb387..2d3c557538b5 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -644,7 +644,7 @@ pcibios_alloc_controller(void) /* * Functions below are used on OpenFirmware machines. */ -static void __openfirmware +static void make_one_node_map(struct device_node* node, u8 pci_bus) { int *bus_range; @@ -678,7 +678,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus) } } -void __openfirmware +void pcibios_make_OF_bus_map(void) { int i; @@ -720,7 +720,7 @@ pcibios_make_OF_bus_map(void) typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data); -static struct device_node* __openfirmware +static struct device_node* scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data) { struct device_node* sub_node; @@ -761,7 +761,7 @@ scan_OF_pci_childs_iterator(struct device_node* node, void* data) return 0; } -static struct device_node* __openfirmware +static struct device_node* scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) { u8 filter_data[2] = {bus, dev_fn}; @@ -842,7 +842,7 @@ pci_find_hose_for_OF_device(struct device_node* node) return NULL; } -static int __openfirmware +static int find_OF_pci_device_filter(struct device_node* node, void* data) { return ((void *)node == data); diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 545cfd0fab59..8b06b8e00332 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -339,7 +339,7 @@ early_init(int r3, int r4, int r5) * Assume here that all clock rates are the same in a * smp system. -- Cort */ -int __openfirmware +int of_show_percpuinfo(struct seq_file *m, int i) { struct device_node *cpu_node; diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c index 7d3fbb5c5db2..f12192cc4d42 100644 --- a/arch/ppc/platforms/chrp_pci.c +++ b/arch/ppc/platforms/chrp_pci.c @@ -29,7 +29,7 @@ void __iomem *gg2_pci_config_base; * limit the bus number to 3 bits */ -int __chrp gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, +int gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, int len, u32 *val) { volatile void __iomem *cfg_data; @@ -56,7 +56,7 @@ int __chrp gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, return PCIBIOS_SUCCESSFUL; } -int __chrp gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, +int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, int len, u32 val) { volatile void __iomem *cfg_data; @@ -92,7 +92,7 @@ static struct pci_ops gg2_pci_ops = /* * Access functions for PCI config space using RTAS calls. */ -int __chrp +int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -108,7 +108,7 @@ rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; } -int __chrp +int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index 57f29ab29bda..47b154c27617 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -105,7 +105,7 @@ static const char *gg2_cachemodes[4] = { "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" }; -int __chrp +int chrp_show_cpuinfo(struct seq_file *m) { int i, sdramen; @@ -303,7 +303,7 @@ void __init chrp_setup_arch(void) pci_create_OF_bus_map(); } -void __chrp +void chrp_event_scan(void) { unsigned char log[1024]; @@ -314,7 +314,7 @@ chrp_event_scan(void) ppc_md.heartbeat_count = ppc_md.heartbeat_reset; } -void __chrp +void chrp_restart(char *cmd) { printk("RTAS system-reboot returned %d\n", @@ -322,7 +322,7 @@ chrp_restart(char *cmd) for (;;); } -void __chrp +void chrp_power_off(void) { /* allow power on only with power button press */ @@ -331,13 +331,13 @@ chrp_power_off(void) for (;;); } -void __chrp +void chrp_halt(void) { chrp_power_off(); } -u_int __chrp +u_int chrp_irq_canonicalize(u_int irq) { if (irq == 2) @@ -572,7 +572,7 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); } -void __chrp +void rtas_display_progress(char *s, unsigned short hex) { int width; @@ -599,7 +599,7 @@ rtas_display_progress(char *s, unsigned short hex) call_rtas( "display-character", 1, 1, NULL, ' ' ); } -void __chrp +void rtas_indicator_progress(char *s, unsigned short hex) { call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c index 0ea1f7d9e46a..dc62e3209443 100644 --- a/arch/ppc/platforms/chrp_smp.c +++ b/arch/ppc/platforms/chrp_smp.c @@ -88,7 +88,7 @@ smp_chrp_take_timebase(void) } /* CHRP with openpic */ -struct smp_ops_t chrp_smp_ops __chrpdata = { +struct smp_ops_t chrp_smp_ops = { .message_pass = smp_openpic_message_pass, .probe = smp_chrp_probe, .kick_cpu = smp_chrp_kick_cpu, diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c index 6037ce7796f5..29d074c305f0 100644 --- a/arch/ppc/platforms/chrp_time.c +++ b/arch/ppc/platforms/chrp_time.c @@ -52,7 +52,7 @@ long __init chrp_time_init(void) return 0; } -int __chrp chrp_cmos_clock_read(int addr) +int chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -60,7 +60,7 @@ int __chrp chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void __chrp chrp_cmos_clock_write(unsigned long val, int addr) +void chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -72,7 +72,7 @@ void __chrp chrp_cmos_clock_write(unsigned long val, int addr) /* * Set the hardware clock. -- Cort */ -int __chrp chrp_set_rtc_time(unsigned long nowtime) +int chrp_set_rtc_time(unsigned long nowtime) { unsigned char save_control, save_freq_select; struct rtc_time tm; @@ -118,7 +118,7 @@ int __chrp chrp_set_rtc_time(unsigned long nowtime) return 0; } -unsigned long __chrp chrp_get_rtc_time(void) +unsigned long chrp_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; int uip, i; diff --git a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c index ed2b1cebc19a..8be2f7d071f0 100644 --- a/arch/ppc/platforms/pmac_backlight.c +++ b/arch/ppc/platforms/pmac_backlight.c @@ -37,7 +37,7 @@ static int backlight_req_enable = -1; static void backlight_callback(void *); static DECLARE_WORK(backlight_work, backlight_callback, NULL); -void __pmac register_backlight_controller(struct backlight_controller *ctrler, +void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type) { struct device_node* bk_node; @@ -99,7 +99,7 @@ void __pmac register_backlight_controller(struct backlight_controller *ctrler, } EXPORT_SYMBOL(register_backlight_controller); -void __pmac unregister_backlight_controller(struct backlight_controller +void unregister_backlight_controller(struct backlight_controller *ctrler, void *data) { /* We keep the current backlight level (for now) */ @@ -108,7 +108,7 @@ void __pmac unregister_backlight_controller(struct backlight_controller } EXPORT_SYMBOL(unregister_backlight_controller); -static int __pmac __set_backlight_enable(int enable) +static int __set_backlight_enable(int enable) { int rc; @@ -122,7 +122,7 @@ static int __pmac __set_backlight_enable(int enable) release_console_sem(); return rc; } -int __pmac set_backlight_enable(int enable) +int set_backlight_enable(int enable) { if (!backlighter) return -ENODEV; @@ -133,7 +133,7 @@ int __pmac set_backlight_enable(int enable) EXPORT_SYMBOL(set_backlight_enable); -int __pmac get_backlight_enable(void) +int get_backlight_enable(void) { if (!backlighter) return -ENODEV; @@ -141,7 +141,7 @@ int __pmac get_backlight_enable(void) } EXPORT_SYMBOL(get_backlight_enable); -static int __pmac __set_backlight_level(int level) +static int __set_backlight_level(int level) { int rc = 0; @@ -165,7 +165,7 @@ static int __pmac __set_backlight_level(int level) } return rc; } -int __pmac set_backlight_level(int level) +int set_backlight_level(int level) { if (!backlighter) return -ENODEV; @@ -176,7 +176,7 @@ int __pmac set_backlight_level(int level) EXPORT_SYMBOL(set_backlight_level); -int __pmac get_backlight_level(void) +int get_backlight_level(void) { if (!backlighter) return -ENODEV; diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index c0605244edda..ebb8be9bf8aa 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -136,7 +136,7 @@ static inline void debug_calc_bogomips(void) /* Switch CPU speed under 750FX CPU control */ -static int __pmac cpu_750fx_cpu_speed(int low_speed) +static int cpu_750fx_cpu_speed(int low_speed) { u32 hid2; @@ -172,7 +172,7 @@ static int __pmac cpu_750fx_cpu_speed(int low_speed) return 0; } -static unsigned int __pmac cpu_750fx_get_cpu_speed(void) +static unsigned int cpu_750fx_get_cpu_speed(void) { if (mfspr(SPRN_HID1) & HID1_PS) return low_freq; @@ -181,7 +181,7 @@ static unsigned int __pmac cpu_750fx_get_cpu_speed(void) } /* Switch CPU speed using DFS */ -static int __pmac dfs_set_cpu_speed(int low_speed) +static int dfs_set_cpu_speed(int low_speed) { if (low_speed == 0) { /* ramping up, set voltage first */ @@ -205,7 +205,7 @@ static int __pmac dfs_set_cpu_speed(int low_speed) return 0; } -static unsigned int __pmac dfs_get_cpu_speed(void) +static unsigned int dfs_get_cpu_speed(void) { if (mfspr(SPRN_HID1) & HID1_DFS) return low_freq; @@ -216,7 +216,7 @@ static unsigned int __pmac dfs_get_cpu_speed(void) /* Switch CPU speed using slewing GPIOs */ -static int __pmac gpios_set_cpu_speed(int low_speed) +static int gpios_set_cpu_speed(int low_speed) { int gpio, timeout = 0; @@ -258,7 +258,7 @@ static int __pmac gpios_set_cpu_speed(int low_speed) /* Switch CPU speed under PMU control */ -static int __pmac pmu_set_cpu_speed(int low_speed) +static int pmu_set_cpu_speed(int low_speed) { struct adb_request req; unsigned long save_l2cr; @@ -354,7 +354,7 @@ static int __pmac pmu_set_cpu_speed(int low_speed) return 0; } -static int __pmac do_set_cpu_speed(int speed_mode, int notify) +static int do_set_cpu_speed(int speed_mode, int notify) { struct cpufreq_freqs freqs; unsigned long l3cr; @@ -391,17 +391,17 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify) return 0; } -static unsigned int __pmac pmac_cpufreq_get_speed(unsigned int cpu) +static unsigned int pmac_cpufreq_get_speed(unsigned int cpu) { return cur_freq; } -static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy) +static int pmac_cpufreq_verify(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); } -static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy, +static int pmac_cpufreq_target( struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { @@ -414,13 +414,13 @@ static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy, return do_set_cpu_speed(newstate, 1); } -unsigned int __pmac pmac_get_one_cpufreq(int i) +unsigned int pmac_get_one_cpufreq(int i) { /* Supports only one CPU for now */ return (i == 0) ? cur_freq : 0; } -static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) +static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) { if (policy->cpu != 0) return -ENODEV; @@ -433,7 +433,7 @@ static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs); } -static u32 __pmac read_gpio(struct device_node *np) +static u32 read_gpio(struct device_node *np) { u32 *reg = (u32 *)get_property(np, "reg", NULL); u32 offset; @@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np) return offset; } -static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg) +static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg) { /* Ok, this could be made a bit smarter, but let's be robust for now. We * always force a speed change to high speed before sleep, to make sure @@ -468,7 +468,7 @@ static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message return 0; } -static int __pmac pmac_cpufreq_resume(struct cpufreq_policy *policy) +static int pmac_cpufreq_resume(struct cpufreq_policy *policy) { /* If we resume, first check if we have a get() function */ if (get_speed_proc) @@ -501,7 +501,7 @@ static struct cpufreq_driver pmac_cpufreq_driver = { }; -static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) +static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) { struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio"); @@ -593,7 +593,7 @@ static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) return 0; } -static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) +static int pmac_cpufreq_init_7447A(struct device_node *cpunode) { struct device_node *volt_gpio_np; @@ -620,7 +620,7 @@ static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) return 0; } -static int __pmac pmac_cpufreq_init_750FX(struct device_node *cpunode) +static int pmac_cpufreq_init_750FX(struct device_node *cpunode) { struct device_node *volt_gpio_np; u32 pvr, *value; diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index 867336ad5d36..e8cd0a8b6a76 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c @@ -63,7 +63,7 @@ extern struct device_node *k2_skiplist[2]; * We use a single global lock to protect accesses. Each driver has * to take care of its own locking */ -static DEFINE_SPINLOCK(feature_lock __pmacdata); +static DEFINE_SPINLOCK(feature_lock); #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); @@ -72,9 +72,9 @@ static DEFINE_SPINLOCK(feature_lock __pmacdata); /* * Instance of some macio stuffs */ -struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; +struct macio_chip macio_chips[MAX_MACIO_CHIPS]; -struct macio_chip* __pmac macio_find(struct device_node* child, int type) +struct macio_chip* macio_find(struct device_node* child, int type) { while(child) { int i; @@ -89,7 +89,7 @@ struct macio_chip* __pmac macio_find(struct device_node* child, int type) } EXPORT_SYMBOL_GPL(macio_find); -static const char* macio_names[] __pmacdata = +static const char* macio_names[] = { "Unknown", "Grand Central", @@ -116,10 +116,10 @@ static const char* macio_names[] __pmacdata = #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) -static struct device_node* uninorth_node __pmacdata; -static u32 __iomem * uninorth_base __pmacdata; -static u32 uninorth_rev __pmacdata; -static int uninorth_u3 __pmacdata; +static struct device_node* uninorth_node; +static u32 __iomem * uninorth_base; +static u32 uninorth_rev; +static int uninorth_u3; static void __iomem *u3_ht; /* @@ -142,13 +142,13 @@ struct pmac_mb_def struct feature_table_entry* features; unsigned long board_flags; }; -static struct pmac_mb_def pmac_mb __pmacdata; +static struct pmac_mb_def pmac_mb; /* * Here are the chip specific feature functions */ -static inline int __pmac +static inline int simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value) { struct macio_chip* macio; @@ -170,7 +170,7 @@ simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int #ifndef CONFIG_POWER4 -static long __pmac +static long ohare_htw_scc_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -263,21 +263,21 @@ ohare_htw_scc_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long ohare_floppy_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_ohare, OHARE_FCR, OH_FLOPPY_ENABLE, value); } -static long __pmac +static long ohare_mesh_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_ohare, OHARE_FCR, OH_MESH_ENABLE, value); } -static long __pmac +static long ohare_ide_enable(struct device_node* node, long param, long value) { switch(param) { @@ -298,7 +298,7 @@ ohare_ide_enable(struct device_node* node, long param, long value) } } -static long __pmac +static long ohare_ide_reset(struct device_node* node, long param, long value) { switch(param) { @@ -313,7 +313,7 @@ ohare_ide_reset(struct device_node* node, long param, long value) } } -static long __pmac +static long ohare_sleep_state(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -329,7 +329,7 @@ ohare_sleep_state(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long heathrow_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -373,7 +373,7 @@ heathrow_modem_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long heathrow_floppy_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_unknown, @@ -382,7 +382,7 @@ heathrow_floppy_enable(struct device_node* node, long param, long value) value); } -static long __pmac +static long heathrow_mesh_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -411,7 +411,7 @@ heathrow_mesh_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long heathrow_ide_enable(struct device_node* node, long param, long value) { switch(param) { @@ -426,7 +426,7 @@ heathrow_ide_enable(struct device_node* node, long param, long value) } } -static long __pmac +static long heathrow_ide_reset(struct device_node* node, long param, long value) { switch(param) { @@ -441,7 +441,7 @@ heathrow_ide_reset(struct device_node* node, long param, long value) } } -static long __pmac +static long heathrow_bmac_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -470,7 +470,7 @@ heathrow_bmac_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long heathrow_sound_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -501,16 +501,16 @@ heathrow_sound_enable(struct device_node* node, long param, long value) return 0; } -static u32 save_fcr[6] __pmacdata; -static u32 save_mbcr __pmacdata; -static u32 save_gpio_levels[2] __pmacdata; -static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata; -static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata; -static u32 save_unin_clock_ctl __pmacdata; -static struct dbdma_regs save_dbdma[13] __pmacdata; -static struct dbdma_regs save_alt_dbdma[13] __pmacdata; +static u32 save_fcr[6]; +static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; +static u32 save_unin_clock_ctl; +static struct dbdma_regs save_dbdma[13]; +static struct dbdma_regs save_alt_dbdma[13]; -static void __pmac +static void dbdma_save(struct macio_chip* macio, struct dbdma_regs* save) { int i; @@ -527,7 +527,7 @@ dbdma_save(struct macio_chip* macio, struct dbdma_regs* save) } } -static void __pmac +static void dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save) { int i; @@ -547,7 +547,7 @@ dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save) } } -static void __pmac +static void heathrow_sleep(struct macio_chip* macio, int secondary) { if (secondary) { @@ -580,7 +580,7 @@ heathrow_sleep(struct macio_chip* macio, int secondary) (void)MACIO_IN32(HEATHROW_FCR); } -static void __pmac +static void heathrow_wakeup(struct macio_chip* macio, int secondary) { if (secondary) { @@ -605,7 +605,7 @@ heathrow_wakeup(struct macio_chip* macio, int secondary) } } -static long __pmac +static long heathrow_sleep_state(struct device_node* node, long param, long value) { if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) @@ -622,7 +622,7 @@ heathrow_sleep_state(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_scc_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -723,7 +723,7 @@ core99_scc_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -775,7 +775,7 @@ core99_modem_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long pangea_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -830,7 +830,7 @@ pangea_modem_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_ata100_enable(struct device_node* node, long value) { unsigned long flags; @@ -860,7 +860,7 @@ core99_ata100_enable(struct device_node* node, long value) return 0; } -static long __pmac +static long core99_ide_enable(struct device_node* node, long param, long value) { /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 @@ -883,7 +883,7 @@ core99_ide_enable(struct device_node* node, long param, long value) } } -static long __pmac +static long core99_ide_reset(struct device_node* node, long param, long value) { switch(param) { @@ -901,7 +901,7 @@ core99_ide_reset(struct device_node* node, long param, long value) } } -static long __pmac +static long core99_gmac_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -918,7 +918,7 @@ core99_gmac_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_gmac_phy_reset(struct device_node* node, long param, long value) { unsigned long flags; @@ -943,7 +943,7 @@ core99_gmac_phy_reset(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_sound_chip_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -973,7 +973,7 @@ core99_sound_chip_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_airport_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -1060,7 +1060,7 @@ core99_airport_enable(struct device_node* node, long param, long value) } #ifdef CONFIG_SMP -static long __pmac +static long core99_reset_cpu(struct device_node* node, long param, long value) { unsigned int reset_io = 0; @@ -1104,7 +1104,7 @@ core99_reset_cpu(struct device_node* node, long param, long value) } #endif /* CONFIG_SMP */ -static long __pmac +static long core99_usb_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; @@ -1257,7 +1257,7 @@ core99_usb_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_firewire_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -1284,7 +1284,7 @@ core99_firewire_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long core99_firewire_cable_power(struct device_node* node, long param, long value) { unsigned long flags; @@ -1315,7 +1315,7 @@ core99_firewire_cable_power(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long intrepid_aack_delay_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -1336,7 +1336,7 @@ intrepid_aack_delay_enable(struct device_node* node, long param, long value) #endif /* CONFIG_POWER4 */ -static long __pmac +static long core99_read_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1345,7 +1345,7 @@ core99_read_gpio(struct device_node* node, long param, long value) } -static long __pmac +static long core99_write_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1356,7 +1356,7 @@ core99_write_gpio(struct device_node* node, long param, long value) #ifdef CONFIG_POWER4 -static long __pmac +static long g5_gmac_enable(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1380,7 +1380,7 @@ g5_gmac_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long g5_fw_enable(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1403,7 +1403,7 @@ g5_fw_enable(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long g5_mpic_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -1419,7 +1419,7 @@ g5_mpic_enable(struct device_node* node, long param, long value) } #ifdef CONFIG_SMP -static long __pmac +static long g5_reset_cpu(struct device_node* node, long param, long value) { unsigned int reset_io = 0; @@ -1465,7 +1465,7 @@ g5_reset_cpu(struct device_node* node, long param, long value) * This takes the second CPU off the bus on dual CPU machines * running UP */ -void __pmac g5_phy_disable_cpu1(void) +void g5_phy_disable_cpu1(void) { UN_OUT(U3_API_PHY_CONFIG_1, 0); } @@ -1474,7 +1474,7 @@ void __pmac g5_phy_disable_cpu1(void) #ifndef CONFIG_POWER4 -static void __pmac +static void keylargo_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; @@ -1528,7 +1528,7 @@ keylargo_shutdown(struct macio_chip* macio, int sleep_mode) (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } -static void __pmac +static void pangea_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; @@ -1562,7 +1562,7 @@ pangea_shutdown(struct macio_chip* macio, int sleep_mode) (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } -static void __pmac +static void intrepid_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; @@ -1591,7 +1591,7 @@ intrepid_shutdown(struct macio_chip* macio, int sleep_mode) } -void __pmac pmac_tweak_clock_spreading(int enable) +void pmac_tweak_clock_spreading(int enable) { struct macio_chip* macio = &macio_chips[0]; @@ -1698,7 +1698,7 @@ void __pmac pmac_tweak_clock_spreading(int enable) } -static int __pmac +static int core99_sleep(void) { struct macio_chip* macio; @@ -1791,7 +1791,7 @@ core99_sleep(void) return 0; } -static int __pmac +static int core99_wake_up(void) { struct macio_chip* macio; @@ -1854,7 +1854,7 @@ core99_wake_up(void) return 0; } -static long __pmac +static long core99_sleep_state(struct device_node* node, long param, long value) { /* Param == 1 means to enter the "fake sleep" mode that is @@ -1884,7 +1884,7 @@ core99_sleep_state(struct device_node* node, long param, long value) #endif /* CONFIG_POWER4 */ -static long __pmac +static long generic_dev_can_wake(struct device_node* node, long param, long value) { /* Todo: eventually check we are really dealing with on-board @@ -1896,7 +1896,7 @@ generic_dev_can_wake(struct device_node* node, long param, long value) return 0; } -static long __pmac +static long generic_get_mb_info(struct device_node* node, long param, long value) { switch(param) { @@ -1919,7 +1919,7 @@ generic_get_mb_info(struct device_node* node, long param, long value) /* Used on any machine */ -static struct feature_table_entry any_features[] __pmacdata = { +static struct feature_table_entry any_features[] = { { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, { PMAC_FTR_DEVICE_CAN_WAKE, generic_dev_can_wake }, { 0, NULL } @@ -1931,7 +1931,7 @@ static struct feature_table_entry any_features[] __pmacdata = { * 2400,3400 and 3500 series powerbooks. Some older desktops seem * to have issues with turning on/off those asic cells */ -static struct feature_table_entry ohare_features[] __pmacdata = { +static struct feature_table_entry ohare_features[] = { { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable }, { PMAC_FTR_MESH_ENABLE, ohare_mesh_enable }, @@ -1945,7 +1945,7 @@ static struct feature_table_entry ohare_features[] __pmacdata = { * Separated as some features couldn't be properly tested * and the serial port control bits appear to confuse it. */ -static struct feature_table_entry heathrow_desktop_features[] __pmacdata = { +static struct feature_table_entry heathrow_desktop_features[] = { { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, @@ -1957,7 +1957,7 @@ static struct feature_table_entry heathrow_desktop_features[] __pmacdata = { /* Heathrow based laptop, that is the Wallstreet and mainstreet * powerbooks. */ -static struct feature_table_entry heathrow_laptop_features[] __pmacdata = { +static struct feature_table_entry heathrow_laptop_features[] = { { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, @@ -1973,7 +1973,7 @@ static struct feature_table_entry heathrow_laptop_features[] __pmacdata = { /* Paddington based machines * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4. */ -static struct feature_table_entry paddington_features[] __pmacdata = { +static struct feature_table_entry paddington_features[] = { { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, @@ -1991,7 +1991,7 @@ static struct feature_table_entry paddington_features[] __pmacdata = { * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo * used on iBook2 & iMac "flow power". */ -static struct feature_table_entry core99_features[] __pmacdata = { +static struct feature_table_entry core99_features[] = { { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, { PMAC_FTR_MODEM_ENABLE, core99_modem_enable }, { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, @@ -2014,7 +2014,7 @@ static struct feature_table_entry core99_features[] __pmacdata = { /* RackMac */ -static struct feature_table_entry rackmac_features[] __pmacdata = { +static struct feature_table_entry rackmac_features[] = { { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, { PMAC_FTR_IDE_RESET, core99_ide_reset }, @@ -2034,7 +2034,7 @@ static struct feature_table_entry rackmac_features[] __pmacdata = { /* Pangea features */ -static struct feature_table_entry pangea_features[] __pmacdata = { +static struct feature_table_entry pangea_features[] = { { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, @@ -2054,7 +2054,7 @@ static struct feature_table_entry pangea_features[] __pmacdata = { /* Intrepid features */ -static struct feature_table_entry intrepid_features[] __pmacdata = { +static struct feature_table_entry intrepid_features[] = { { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, @@ -2077,7 +2077,7 @@ static struct feature_table_entry intrepid_features[] __pmacdata = { /* G5 features */ -static struct feature_table_entry g5_features[] __pmacdata = { +static struct feature_table_entry g5_features[] = { { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, { PMAC_FTR_1394_ENABLE, g5_fw_enable }, { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, @@ -2091,7 +2091,7 @@ static struct feature_table_entry g5_features[] __pmacdata = { #endif /* CONFIG_POWER4 */ -static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { +static struct pmac_mb_def pmac_mb_defs[] = { #ifndef CONFIG_POWER4 /* * Desktops @@ -2352,7 +2352,7 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* * The toplevel feature_call callback */ -long __pmac +long pmac_do_feature_call(unsigned int selector, ...) { struct device_node* node; @@ -2935,8 +2935,8 @@ void __init pmac_check_ht_link(void) * Early video resume hook */ -static void (*pmac_early_vresume_proc)(void *data) __pmacdata; -static void *pmac_early_vresume_data __pmacdata; +static void (*pmac_early_vresume_proc)(void *data); +static void *pmac_early_vresume_data; void pmac_set_early_video_resume(void (*proc)(void *data), void *data) { @@ -2949,7 +2949,7 @@ void pmac_set_early_video_resume(void (*proc)(void *data), void *data) } EXPORT_SYMBOL(pmac_set_early_video_resume); -void __pmac pmac_call_early_video_resume(void) +void pmac_call_early_video_resume(void) { if (pmac_early_vresume_proc) pmac_early_vresume_proc(pmac_early_vresume_data); @@ -2959,11 +2959,11 @@ void __pmac pmac_call_early_video_resume(void) * AGP related suspend/resume code */ -static struct pci_dev *pmac_agp_bridge __pmacdata; -static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata; -static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata; +static struct pci_dev *pmac_agp_bridge; +static int (*pmac_agp_suspend)(struct pci_dev *bridge); +static int (*pmac_agp_resume)(struct pci_dev *bridge); -void __pmac pmac_register_agp_pm(struct pci_dev *bridge, +void pmac_register_agp_pm(struct pci_dev *bridge, int (*suspend)(struct pci_dev *bridge), int (*resume)(struct pci_dev *bridge)) { @@ -2980,7 +2980,7 @@ void __pmac pmac_register_agp_pm(struct pci_dev *bridge, } EXPORT_SYMBOL(pmac_register_agp_pm); -void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev) +void pmac_suspend_agp_for_card(struct pci_dev *dev) { if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) return; @@ -2990,7 +2990,7 @@ void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev) } EXPORT_SYMBOL(pmac_suspend_agp_for_card); -void __pmac pmac_resume_agp_for_card(struct pci_dev *dev) +void pmac_resume_agp_for_card(struct pci_dev *dev) { if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) return; diff --git a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c index c9de64205996..8c9b008c7226 100644 --- a/arch/ppc/platforms/pmac_nvram.c +++ b/arch/ppc/platforms/pmac_nvram.c @@ -88,17 +88,17 @@ extern int system_running; static int (*core99_write_bank)(int bank, u8* datas); static int (*core99_erase_bank)(int bank); -static char *nvram_image __pmacdata; +static char *nvram_image; -static unsigned char __pmac core99_nvram_read_byte(int addr) +static unsigned char core99_nvram_read_byte(int addr) { if (nvram_image == NULL) return 0xff; return nvram_image[addr]; } -static void __pmac core99_nvram_write_byte(int addr, unsigned char val) +static void core99_nvram_write_byte(int addr, unsigned char val) { if (nvram_image == NULL) return; @@ -106,18 +106,18 @@ static void __pmac core99_nvram_write_byte(int addr, unsigned char val) } -static unsigned char __openfirmware direct_nvram_read_byte(int addr) +static unsigned char direct_nvram_read_byte(int addr) { return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]); } -static void __openfirmware direct_nvram_write_byte(int addr, unsigned char val) +static void direct_nvram_write_byte(int addr, unsigned char val) { out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val); } -static unsigned char __pmac indirect_nvram_read_byte(int addr) +static unsigned char indirect_nvram_read_byte(int addr) { unsigned char val; unsigned long flags; @@ -130,7 +130,7 @@ static unsigned char __pmac indirect_nvram_read_byte(int addr) return val; } -static void __pmac indirect_nvram_write_byte(int addr, unsigned char val) +static void indirect_nvram_write_byte(int addr, unsigned char val) { unsigned long flags; @@ -143,13 +143,13 @@ static void __pmac indirect_nvram_write_byte(int addr, unsigned char val) #ifdef CONFIG_ADB_PMU -static void __pmac pmu_nvram_complete(struct adb_request *req) +static void pmu_nvram_complete(struct adb_request *req) { if (req->arg) complete((struct completion *)req->arg); } -static unsigned char __pmac pmu_nvram_read_byte(int addr) +static unsigned char pmu_nvram_read_byte(int addr) { struct adb_request req; DECLARE_COMPLETION(req_complete); @@ -165,7 +165,7 @@ static unsigned char __pmac pmu_nvram_read_byte(int addr) return req.reply[0]; } -static void __pmac pmu_nvram_write_byte(int addr, unsigned char val) +static void pmu_nvram_write_byte(int addr, unsigned char val) { struct adb_request req; DECLARE_COMPLETION(req_complete); @@ -183,7 +183,7 @@ static void __pmac pmu_nvram_write_byte(int addr, unsigned char val) #endif /* CONFIG_ADB_PMU */ -static u8 __pmac chrp_checksum(struct chrp_header* hdr) +static u8 chrp_checksum(struct chrp_header* hdr) { u8 *ptr; u16 sum = hdr->signature; @@ -194,7 +194,7 @@ static u8 __pmac chrp_checksum(struct chrp_header* hdr) return sum; } -static u32 __pmac core99_calc_adler(u8 *buffer) +static u32 core99_calc_adler(u8 *buffer) { int cnt; u32 low, high; @@ -216,7 +216,7 @@ static u32 __pmac core99_calc_adler(u8 *buffer) return (high << 16) | low; } -static u32 __pmac core99_check(u8* datas) +static u32 core99_check(u8* datas) { struct core99_header* hdr99 = (struct core99_header*)datas; @@ -235,7 +235,7 @@ static u32 __pmac core99_check(u8* datas) return hdr99->generation; } -static int __pmac sm_erase_bank(int bank) +static int sm_erase_bank(int bank) { int stat, i; unsigned long timeout; @@ -267,7 +267,7 @@ static int __pmac sm_erase_bank(int bank) return 0; } -static int __pmac sm_write_bank(int bank, u8* datas) +static int sm_write_bank(int bank, u8* datas) { int i, stat = 0; unsigned long timeout; @@ -302,7 +302,7 @@ static int __pmac sm_write_bank(int bank, u8* datas) return 0; } -static int __pmac amd_erase_bank(int bank) +static int amd_erase_bank(int bank) { int i, stat = 0; unsigned long timeout; @@ -349,7 +349,7 @@ static int __pmac amd_erase_bank(int bank) return 0; } -static int __pmac amd_write_bank(int bank, u8* datas) +static int amd_write_bank(int bank, u8* datas) { int i, stat = 0; unsigned long timeout; @@ -430,7 +430,7 @@ static void __init lookup_partitions(void) DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]); } -static void __pmac core99_nvram_sync(void) +static void core99_nvram_sync(void) { struct core99_header* hdr99; unsigned long flags; @@ -554,12 +554,12 @@ void __init pmac_nvram_init(void) lookup_partitions(); } -int __pmac pmac_get_partition(int partition) +int pmac_get_partition(int partition) { return nvram_partitions[partition]; } -u8 __pmac pmac_xpram_read(int xpaddr) +u8 pmac_xpram_read(int xpaddr) { int offset = nvram_partitions[pmac_nvram_XPRAM]; @@ -569,7 +569,7 @@ u8 __pmac pmac_xpram_read(int xpaddr) return ppc_md.nvram_read_val(xpaddr + offset); } -void __pmac pmac_xpram_write(int xpaddr, u8 data) +void pmac_xpram_write(int xpaddr, u8 data) { int offset = nvram_partitions[pmac_nvram_XPRAM]; diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c index 719fb49fe2bc..1dc638f72239 100644 --- a/arch/ppc/platforms/pmac_pci.c +++ b/arch/ppc/platforms/pmac_pci.c @@ -141,7 +141,7 @@ fixup_bus_range(struct device_node *bridge) |(((unsigned long)(off)) & 0xFCUL) \ |1UL) -static void volatile __iomem * __pmac +static void volatile __iomem * macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) { unsigned int caddr; @@ -162,7 +162,7 @@ macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) return hose->cfg_data + offset; } -static int __pmac +static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -190,7 +190,7 @@ macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset, return PCIBIOS_SUCCESSFUL; } -static int __pmac +static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { @@ -230,7 +230,7 @@ static struct pci_ops macrisc_pci_ops = /* * Verifiy that a specific (bus, dev_fn) exists on chaos */ -static int __pmac +static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) { struct device_node *np; @@ -252,7 +252,7 @@ chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) return PCIBIOS_SUCCESSFUL; } -static int __pmac +static int chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -264,7 +264,7 @@ chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, return macrisc_read_config(bus, devfn, offset, len, val); } -static int __pmac +static int chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { @@ -294,7 +294,7 @@ static struct pci_ops chaos_pci_ops = + (((unsigned long)bus) << 16) \ + 0x01000000UL) -static void volatile __iomem * __pmac +static void volatile __iomem * u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset) { if (bus == hose->first_busno) { @@ -307,7 +307,7 @@ u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset) return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); } -static int __pmac +static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -357,7 +357,7 @@ u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, return PCIBIOS_SUCCESSFUL; } -static int __pmac +static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { @@ -899,7 +899,7 @@ pmac_pcibios_fixup(void) pcibios_fixup_OF_interrupts(); } -int __pmac +int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) { struct device_node* node; @@ -1096,7 +1096,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); * Disable second function on K2-SATA, it's broken * and disable IO BARs on first one */ -void __pmac pmac_pci_fixup_k2_sata(struct pci_dev* dev) +void pmac_pci_fixup_k2_sata(struct pci_dev* dev) { int i; u16 cmd; diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c index 2ce058895e03..3349cfb624a0 100644 --- a/arch/ppc/platforms/pmac_pic.c +++ b/arch/ppc/platforms/pmac_pic.c @@ -53,7 +53,7 @@ struct pmac_irq_hw { }; /* Default addresses */ -static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = { +static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { (struct pmac_irq_hw *) 0xf3000020, (struct pmac_irq_hw *) 0xf3000010, (struct pmac_irq_hw *) 0xf4000020, @@ -64,22 +64,22 @@ static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = { #define OHARE_LEVEL_MASK 0x1ff00000 #define HEATHROW_LEVEL_MASK 0x1ff00000 -static int max_irqs __pmacdata; -static int max_real_irqs __pmacdata; -static u32 level_mask[4] __pmacdata; +static int max_irqs; +static int max_real_irqs; +static u32 level_mask[4]; -static DEFINE_SPINLOCK(pmac_pic_lock __pmacdata); +static DEFINE_SPINLOCK(pmac_pic_lock); #define GATWICK_IRQ_POOL_SIZE 10 -static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata; +static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; /* * Mark an irq as "lost". This is only used on the pmac * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac +void __set_lost(unsigned long irq_nr, int nokick) { if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { @@ -89,7 +89,7 @@ __set_lost(unsigned long irq_nr, int nokick) } } -static void __pmac +static void pmac_mask_and_ack_irq(unsigned int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); @@ -114,7 +114,7 @@ pmac_mask_and_ack_irq(unsigned int irq_nr) spin_unlock_irqrestore(&pmac_pic_lock, flags); } -static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) +static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; @@ -147,7 +147,7 @@ static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) /* When an irq gets requested for the first client, if it's an * edge interrupt, we clear any previous one on the controller */ -static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr) +static unsigned int pmac_startup_irq(unsigned int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; @@ -160,20 +160,20 @@ static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr) return 0; } -static void __pmac pmac_mask_irq(unsigned int irq_nr) +static void pmac_mask_irq(unsigned int irq_nr) { clear_bit(irq_nr, ppc_cached_irq_mask); pmac_set_irq_mask(irq_nr, 0); mb(); } -static void __pmac pmac_unmask_irq(unsigned int irq_nr) +static void pmac_unmask_irq(unsigned int irq_nr) { set_bit(irq_nr, ppc_cached_irq_mask); pmac_set_irq_mask(irq_nr, 0); } -static void __pmac pmac_end_irq(unsigned int irq_nr) +static void pmac_end_irq(unsigned int irq_nr) { if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq_nr].action) { diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index b392b9a15987..12cbc85555d9 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -123,7 +123,7 @@ extern struct smp_ops_t psurge_smp_ops; extern struct smp_ops_t core99_smp_ops; #endif /* CONFIG_SMP */ -static int __pmac +static int pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; @@ -227,7 +227,7 @@ pmac_show_cpuinfo(struct seq_file *m) return 0; } -static int __openfirmware +static int pmac_show_percpuinfo(struct seq_file *m, int i) { #ifdef CONFIG_CPU_FREQ_PMAC @@ -486,7 +486,7 @@ static int pmac_late_init(void) late_initcall(pmac_late_init); /* can't be __init - can be called whenever a disk is first accessed */ -void __pmac +void note_bootable_part(dev_t dev, int part, int goodness) { static int found_boot = 0; @@ -512,7 +512,7 @@ note_bootable_part(dev_t dev, int part, int goodness) } } -static void __pmac +static void pmac_restart(char *cmd) { #ifdef CONFIG_ADB_CUDA @@ -537,7 +537,7 @@ pmac_restart(char *cmd) } } -static void __pmac +static void pmac_power_off(void) { #ifdef CONFIG_ADB_CUDA @@ -562,7 +562,7 @@ pmac_power_off(void) } } -static void __pmac +static void pmac_halt(void) { pmac_power_off(); diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index 794a23994b82..e613f0e0d9eb 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -186,7 +186,7 @@ static inline void psurge_clr_ipi(int cpu) */ static unsigned long psurge_smp_message[NR_CPUS]; -void __pmac psurge_smp_message_recv(struct pt_regs *regs) +void psurge_smp_message_recv(struct pt_regs *regs) { int cpu = smp_processor_id(); int msg; @@ -203,13 +203,13 @@ void __pmac psurge_smp_message_recv(struct pt_regs *regs) smp_message_recv(msg, regs); } -irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs) +irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs) { psurge_smp_message_recv(regs); return IRQ_HANDLED; } -static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data, +static void smp_psurge_message_pass(int target, int msg, unsigned long data, int wait) { int i; @@ -629,7 +629,7 @@ void smp_core99_give_timebase(void) /* PowerSurge-style Macs */ -struct smp_ops_t psurge_smp_ops __pmacdata = { +struct smp_ops_t psurge_smp_ops = { .message_pass = smp_psurge_message_pass, .probe = smp_psurge_probe, .kick_cpu = smp_psurge_kick_cpu, @@ -639,7 +639,7 @@ struct smp_ops_t psurge_smp_ops __pmacdata = { }; /* Core99 Macs (dual G4s) */ -struct smp_ops_t core99_smp_ops __pmacdata = { +struct smp_ops_t core99_smp_ops = { .message_pass = smp_openpic_message_pass, .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c index 778ce4fec368..ff6adff36cb8 100644 --- a/arch/ppc/platforms/pmac_time.c +++ b/arch/ppc/platforms/pmac_time.c @@ -77,7 +77,7 @@ pmac_time_init(void) #endif } -unsigned long __pmac +unsigned long pmac_get_rtc_time(void) { #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) @@ -118,7 +118,7 @@ pmac_get_rtc_time(void) return 0; } -int __pmac +int pmac_set_rtc_time(unsigned long nowtime) { #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) @@ -210,7 +210,7 @@ via_calibrate_decr(void) /* * Reset the time after a sleep. */ -static int __pmac +static int time_sleep_notify(struct pmu_sleep_notifier *self, int when) { static unsigned long time_diff; @@ -235,7 +235,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) return PBOOK_SLEEP_OK; } -static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = { +static struct pmu_sleep_notifier time_sleep_notifier = { time_sleep_notify, SLEEP_LEVEL_MISC, }; #endif /* CONFIG_PM */ diff --git a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c index 4760cb64251d..e50b9996848c 100644 --- a/arch/ppc/platforms/prep_pci.c +++ b/arch/ppc/platforms/prep_pci.c @@ -43,7 +43,7 @@ static unsigned long *ProcInfo; /* Tables for known hardware */ /* Motorola PowerStackII - Utah */ -static char Utah_pci_IRQ_map[23] __prepdata = +static char Utah_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -72,7 +72,7 @@ static char Utah_pci_IRQ_map[23] __prepdata = 0, /* Slot 22 - unused */ }; -static char Utah_pci_IRQ_routes[] __prepdata = +static char Utah_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 9, /* Line 1 */ @@ -84,7 +84,7 @@ static char Utah_pci_IRQ_routes[] __prepdata = /* Motorola PowerStackII - Omaha */ /* no integrated SCSI or ethernet */ -static char Omaha_pci_IRQ_map[23] __prepdata = +static char Omaha_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -111,7 +111,7 @@ static char Omaha_pci_IRQ_map[23] __prepdata = 0, }; -static char Omaha_pci_IRQ_routes[] __prepdata = +static char Omaha_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 9, /* Line 1 */ @@ -121,7 +121,7 @@ static char Omaha_pci_IRQ_routes[] __prepdata = }; /* Motorola PowerStack */ -static char Blackhawk_pci_IRQ_map[19] __prepdata = +static char Blackhawk_pci_IRQ_map[19] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -144,7 +144,7 @@ static char Blackhawk_pci_IRQ_map[19] __prepdata = 3, /* Slot P5 */ }; -static char Blackhawk_pci_IRQ_routes[] __prepdata = +static char Blackhawk_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 9, /* Line 1 */ @@ -154,7 +154,7 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata = }; /* Motorola Mesquite */ -static char Mesquite_pci_IRQ_map[23] __prepdata = +static char Mesquite_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -182,7 +182,7 @@ static char Mesquite_pci_IRQ_map[23] __prepdata = }; /* Motorola Sitka */ -static char Sitka_pci_IRQ_map[21] __prepdata = +static char Sitka_pci_IRQ_map[21] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -208,7 +208,7 @@ static char Sitka_pci_IRQ_map[21] __prepdata = }; /* Motorola MTX */ -static char MTX_pci_IRQ_map[23] __prepdata = +static char MTX_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -237,7 +237,7 @@ static char MTX_pci_IRQ_map[23] __prepdata = /* Motorola MTX Plus */ /* Secondary bus interrupt routing is not supported yet */ -static char MTXplus_pci_IRQ_map[23] __prepdata = +static char MTXplus_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -264,13 +264,13 @@ static char MTXplus_pci_IRQ_map[23] __prepdata = 0, /* Slot 22 - unused */ }; -static char Raven_pci_IRQ_routes[] __prepdata = +static char Raven_pci_IRQ_routes[] = { 0, /* This is a dummy structure */ }; /* Motorola MVME16xx */ -static char Genesis_pci_IRQ_map[16] __prepdata = +static char Genesis_pci_IRQ_map[16] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -290,7 +290,7 @@ static char Genesis_pci_IRQ_map[16] __prepdata = 0, /* Slot 15 - unused */ }; -static char Genesis_pci_IRQ_routes[] __prepdata = +static char Genesis_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 10, /* Line 1 */ @@ -299,7 +299,7 @@ static char Genesis_pci_IRQ_routes[] __prepdata = 15 /* Line 4 */ }; -static char Genesis2_pci_IRQ_map[23] __prepdata = +static char Genesis2_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -327,7 +327,7 @@ static char Genesis2_pci_IRQ_map[23] __prepdata = }; /* Motorola Series-E */ -static char Comet_pci_IRQ_map[23] __prepdata = +static char Comet_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -354,7 +354,7 @@ static char Comet_pci_IRQ_map[23] __prepdata = 0, }; -static char Comet_pci_IRQ_routes[] __prepdata = +static char Comet_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 10, /* Line 1 */ @@ -364,7 +364,7 @@ static char Comet_pci_IRQ_routes[] __prepdata = }; /* Motorola Series-EX */ -static char Comet2_pci_IRQ_map[23] __prepdata = +static char Comet2_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -391,7 +391,7 @@ static char Comet2_pci_IRQ_map[23] __prepdata = 0, }; -static char Comet2_pci_IRQ_routes[] __prepdata = +static char Comet2_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 10, /* Line 1 */ @@ -405,7 +405,7 @@ static char Comet2_pci_IRQ_routes[] __prepdata = * This is actually based on the Carolina motherboard * -- Cort */ -static char ibm8xx_pci_IRQ_map[23] __prepdata = { +static char ibm8xx_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ 0, /* Slot 2 - unused */ @@ -431,7 +431,7 @@ static char ibm8xx_pci_IRQ_map[23] __prepdata = { 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ }; -static char ibm8xx_pci_IRQ_routes[] __prepdata = { +static char ibm8xx_pci_IRQ_routes[] = { 0, /* Line 0 - unused */ 15, /* Line 1 */ 15, /* Line 2 */ @@ -443,7 +443,7 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { * a 6015 ibm board * -- Cort */ -static char ibm6015_pci_IRQ_map[23] __prepdata = { +static char ibm6015_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ 0, /* Slot 2 - unused */ @@ -469,7 +469,7 @@ static char ibm6015_pci_IRQ_map[23] __prepdata = { 2, /* Slot 22 - */ }; -static char ibm6015_pci_IRQ_routes[] __prepdata = { +static char ibm6015_pci_IRQ_routes[] = { 0, /* Line 0 - unused */ 13, /* Line 1 */ 15, /* Line 2 */ @@ -479,7 +479,7 @@ static char ibm6015_pci_IRQ_routes[] __prepdata = { /* IBM Nobis and Thinkpad 850 */ -static char Nobis_pci_IRQ_map[23] __prepdata ={ +static char Nobis_pci_IRQ_map[23] ={ 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ 0, /* Slot 2 - unused */ @@ -498,7 +498,7 @@ static char Nobis_pci_IRQ_map[23] __prepdata ={ 0, /* Slot 15 - unused */ }; -static char Nobis_pci_IRQ_routes[] __prepdata = { +static char Nobis_pci_IRQ_routes[] = { 0, /* Line 0 - Unused */ 13, /* Line 1 */ 13, /* Line 2 */ @@ -510,7 +510,7 @@ static char Nobis_pci_IRQ_routes[] __prepdata = { * IBM RS/6000 43p/140 -- paulus * XXX we should get all this from the residual data */ -static char ibm43p_pci_IRQ_map[23] __prepdata = { +static char ibm43p_pci_IRQ_map[23] = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ 0, /* Slot 2 - unused */ @@ -536,7 +536,7 @@ static char ibm43p_pci_IRQ_map[23] __prepdata = { 1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ }; -static char ibm43p_pci_IRQ_routes[] __prepdata = { +static char ibm43p_pci_IRQ_routes[] = { 0, /* Line 0 - unused */ 15, /* Line 1 */ 15, /* Line 2 */ @@ -559,7 +559,7 @@ struct powerplus_irq_list * are routed to OpenPIC inputs 5-8. These values are offset by * 16 in the table to reflect the Linux kernel interrupt value. */ -struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata = +struct powerplus_irq_list Powerplus_pci_IRQ_list = { {25, 26, 27, 28}, {21, 22, 23, 24} @@ -572,7 +572,7 @@ struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata = * are routed to OpenPIC inputs 12-15. These values are offset by * 16 in the table to reflect the Linux kernel interrupt value. */ -struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata = +struct powerplus_irq_list Mesquite_pci_IRQ_list = { {24, 25, 26, 27}, {28, 29, 30, 31} @@ -582,7 +582,7 @@ struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata = * This table represents the standard PCI swizzle defined in the * PCI bus specification. */ -static unsigned char prep_pci_intpins[4][4] __prepdata = +static unsigned char prep_pci_intpins[4][4] = { { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */ { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */ @@ -622,7 +622,7 @@ static unsigned char prep_pci_intpins[4][4] __prepdata = #define MIN_DEVNR 11 #define MAX_DEVNR 22 -static int __prep +static int prep_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -652,7 +652,7 @@ prep_read_config(struct pci_bus *bus, unsigned int devfn, int offset, return PCIBIOS_SUCCESSFUL; } -static int __prep +static int prep_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { @@ -804,7 +804,7 @@ struct mot_info { void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */ struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */ unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */ -} mot_info[] __prepdata = { +} mot_info[] = { {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00}, diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index bc926be95472..fccafbcd4b58 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -173,7 +173,7 @@ prep_carolina_enable_l2(void) } /* cpuinfo code common to all IBM PReP */ -static void __prep +static void prep_ibm_cpuinfo(struct seq_file *m) { unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); @@ -209,14 +209,14 @@ prep_ibm_cpuinfo(struct seq_file *m) } } -static int __prep +static int prep_gen_cpuinfo(struct seq_file *m) { prep_ibm_cpuinfo(m); return 0; } -static int __prep +static int prep_sandalfoot_cpuinfo(struct seq_file *m) { unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); @@ -243,7 +243,7 @@ prep_sandalfoot_cpuinfo(struct seq_file *m) return 0; } -static int __prep +static int prep_thinkpad_cpuinfo(struct seq_file *m) { unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); @@ -314,7 +314,7 @@ prep_thinkpad_cpuinfo(struct seq_file *m) return 0; } -static int __prep +static int prep_carolina_cpuinfo(struct seq_file *m) { unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); @@ -350,7 +350,7 @@ prep_carolina_cpuinfo(struct seq_file *m) return 0; } -static int __prep +static int prep_tiger1_cpuinfo(struct seq_file *m) { unsigned int l2_reg = inb(PREP_IBM_L2INFO); @@ -393,7 +393,7 @@ prep_tiger1_cpuinfo(struct seq_file *m) /* Used by all Motorola PReP */ -static int __prep +static int prep_mot_cpuinfo(struct seq_file *m) { unsigned int cachew = *((unsigned char *)CACHECRBA); @@ -454,7 +454,7 @@ prep_mot_cpuinfo(struct seq_file *m) return 0; } -static void __prep +static void prep_restart(char *cmd) { #define PREP_SP92 0x92 /* Special Port 92 */ @@ -473,7 +473,7 @@ prep_restart(char *cmd) #undef PREP_SP92 } -static void __prep +static void prep_halt(void) { local_irq_disable(); /* no interrupts */ @@ -488,7 +488,7 @@ prep_halt(void) /* Carrera is the power manager in the Thinkpads. Unfortunately not much is * known about it, so we can't power down. */ -static void __prep +static void prep_carrera_poweroff(void) { prep_halt(); @@ -501,7 +501,7 @@ prep_carrera_poweroff(void) * somewhat in the IBM Carolina Technical Specification. * -Hollis */ -static void __prep +static void utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value) { /* @@ -539,7 +539,7 @@ utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value) udelay(100); /* important: let controller recover */ } -static void __prep +static void prep_sig750_poweroff(void) { /* tweak the power manager found in most IBM PRePs (except Thinkpads) */ @@ -554,7 +554,7 @@ prep_sig750_poweroff(void) /* not reached */ } -static int __prep +static int prep_show_percpuinfo(struct seq_file *m, int i) { /* PREP's without residual data will give incorrect values here */ @@ -700,12 +700,12 @@ prep_set_bat(void) /* * IBM 3-digit status LED */ -static unsigned int ibm_statusled_base __prepdata; +static unsigned int ibm_statusled_base; -static void __prep +static void ibm_statusled_progress(char *s, unsigned short hex); -static int __prep +static int ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2, void * dummy3) { @@ -713,13 +713,13 @@ ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2, return NOTIFY_DONE; } -static struct notifier_block ibm_statusled_block __prepdata = { +static struct notifier_block ibm_statusled_block = { ibm_statusled_panic, NULL, INT_MAX /* try to do it first */ }; -static void __prep +static void ibm_statusled_progress(char *s, unsigned short hex) { static int notifier_installed; @@ -945,7 +945,7 @@ prep_calibrate_decr(void) todc_calibrate_decr(); } -static unsigned int __prep +static unsigned int prep_irq_canonicalize(u_int irq) { if (irq == 2) @@ -996,7 +996,7 @@ prep_init_IRQ(void) /* * IDE stuff. */ -static int __prep +static int prep_ide_default_irq(unsigned long base) { switch (base) { @@ -1010,7 +1010,7 @@ prep_ide_default_irq(unsigned long base) } } -static unsigned long __prep +static unsigned long prep_ide_default_io_base(int index) { switch (index) { @@ -1055,7 +1055,7 @@ smp_prep_setup_cpu(int cpu_nr) do_openpic_setup_cpu(); } -static struct smp_ops_t prep_smp_ops __prepdata = { +static struct smp_ops_t prep_smp_ops = { smp_openpic_message_pass, smp_prep_probe, smp_prep_kick_cpu, diff --git a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c index 0f84ca603612..c9911601cfdf 100644 --- a/arch/ppc/platforms/residual.c +++ b/arch/ppc/platforms/residual.c @@ -47,7 +47,7 @@ #include -unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; +unsigned char __res[sizeof(RESIDUAL)] = {0,}; RESIDUAL *res = (RESIDUAL *)&__res; char * PnP_BASE_TYPES[] __initdata = { diff --git a/arch/ppc/syslib/btext.c b/arch/ppc/syslib/btext.c index 7734f6836174..12fa83e6774a 100644 --- a/arch/ppc/syslib/btext.c +++ b/arch/ppc/syslib/btext.c @@ -53,8 +53,8 @@ extern char *klimit; * chrp only uses it during early boot. */ #ifdef CONFIG_XMON -#define BTEXT __pmac -#define BTDATA __pmacdata +#define BTEXT +#define BTDATA #else #define BTEXT __init #define BTDATA __initdata @@ -187,7 +187,7 @@ btext_setup_display(int width, int height, int depth, int pitch, * changes. */ -void __openfirmware +void map_boot_text(void) { unsigned long base, offset, size; diff --git a/arch/ppc/syslib/prep_nvram.c b/arch/ppc/syslib/prep_nvram.c index 8599850ca772..2c6364d9641f 100644 --- a/arch/ppc/syslib/prep_nvram.c +++ b/arch/ppc/syslib/prep_nvram.c @@ -22,14 +22,14 @@ static char nvramData[MAX_PREP_NVRAM]; static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0]; -unsigned char __prep prep_nvram_read_val(int addr) +unsigned char prep_nvram_read_val(int addr) { outb(addr, PREP_NVRAM_AS0); outb(addr>>8, PREP_NVRAM_AS1); return inb(PREP_NVRAM_DATA); } -void __prep prep_nvram_write_val(int addr, +void prep_nvram_write_val(int addr, unsigned char val) { outb(addr, PREP_NVRAM_AS0); @@ -81,8 +81,7 @@ void __init init_prep_nvram(void) } } -__prep -char __prep *prep_nvram_get_var(const char *name) +char *prep_nvram_get_var(const char *name) { char *cp; int namelen; @@ -101,8 +100,7 @@ char __prep *prep_nvram_get_var(const char *name) return NULL; } -__prep -char __prep *prep_nvram_first_var(void) +char *prep_nvram_first_var(void) { if (nvram->Header.GELength == 0) { return NULL; @@ -112,8 +110,7 @@ char __prep *prep_nvram_first_var(void) } } -__prep -char __prep *prep_nvram_next_var(char *name) +char *prep_nvram_next_var(char *name) { char *cp; diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c index 2c64ed627475..278da6ee62ea 100644 --- a/arch/ppc/syslib/prom.c +++ b/arch/ppc/syslib/prom.c @@ -89,7 +89,7 @@ extern char cmd_line[512]; /* XXX */ extern boot_infos_t *boot_infos; unsigned long dev_tree_size; -void __openfirmware +void phys_call_rtas(int service, int nargs, int nret, ...) { va_list list; @@ -862,7 +862,7 @@ find_type_devices(const char *type) /* * Returns all nodes linked together */ -struct device_node * __openfirmware +struct device_node * find_all_nodes(void) { struct device_node *head, **prevp, *np; @@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp) /* * Add a property to a node */ -void __openfirmware +void prom_add_property(struct device_node* np, struct property* prop) { struct property **next = &np->properties; @@ -1177,7 +1177,7 @@ prom_add_property(struct device_node* np, struct property* prop) } /* I quickly hacked that one, check against spec ! */ -static inline unsigned long __openfirmware +static inline unsigned long bus_space_to_resource_flags(unsigned int bus_space) { u8 space = (bus_space >> 24) & 0xf; @@ -1194,7 +1194,7 @@ bus_space_to_resource_flags(unsigned int bus_space) } } -static struct resource* __openfirmware +static struct resource* find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) { unsigned long mask; @@ -1224,7 +1224,7 @@ find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) * or other nodes attached to the root node. Ultimately, put some * link to resources in the OF node. */ -struct resource* __openfirmware +struct resource* request_OF_resource(struct device_node* node, int index, const char* name_postfix) { struct pci_dev* pcidev; @@ -1280,7 +1280,7 @@ request_OF_resource(struct device_node* node, int index, const char* name_postfi return NULL; } -int __openfirmware +int release_OF_resource(struct device_node* node, int index) { struct pci_dev* pcidev; @@ -1346,7 +1346,7 @@ release_OF_resource(struct device_node* node, int index) } #if 0 -void __openfirmware +void print_properties(struct device_node *np) { struct property *pp; @@ -1400,7 +1400,7 @@ print_properties(struct device_node *np) static DEFINE_SPINLOCK(rtas_lock); /* this can be called after setup -- Cort */ -int __openfirmware +int call_rtas(const char *service, int nargs, int nret, unsigned long *outputs, ...) { From aacaf9bd9646f6f611a08fca976411b6e5ddefe2 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 17 Sep 2005 10:36:54 -0500 Subject: [PATCH 0062/1939] [PATCH] powerpc: Remove sections use from ppc64 and drivers Here is a new patch that removes all notion of the pmac, prep, chrp and openfirmware initialization sections, and then unifies the sections.h files without those __pmac, etc, sections identifiers cluttering things up. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/pmac_feature.c | 60 +++++++------- arch/ppc64/kernel/pmac_nvram.c | 30 +++---- arch/ppc64/kernel/pmac_pci.c | 12 +-- arch/ppc64/kernel/pmac_setup.c | 10 +-- arch/ppc64/kernel/pmac_smp.c | 2 +- arch/ppc64/kernel/pmac_time.c | 4 +- drivers/ide/ppc/pmac.c | 80 +++++++++---------- drivers/macintosh/ans-lcd.c | 10 +-- drivers/macintosh/mediabay.c | 56 +++++++------- drivers/macintosh/via-cuda.c | 1 - drivers/macintosh/via-pmu.c | 129 +++++++++++++++---------------- drivers/macintosh/via-pmu68k.c | 15 ++-- 12 files changed, 203 insertions(+), 206 deletions(-) diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c index eb4e6c3f694d..26075f11db77 100644 --- a/arch/ppc64/kernel/pmac_feature.c +++ b/arch/ppc64/kernel/pmac_feature.c @@ -53,7 +53,7 @@ * We use a single global lock to protect accesses. Each driver has * to take care of its own locking */ -static DEFINE_SPINLOCK(feature_lock __pmacdata); +static DEFINE_SPINLOCK(feature_lock); #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); @@ -62,9 +62,9 @@ static DEFINE_SPINLOCK(feature_lock __pmacdata); /* * Instance of some macio stuffs */ -struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; +struct macio_chip macio_chips[MAX_MACIO_CHIPS] ; -struct macio_chip* __pmac macio_find(struct device_node* child, int type) +struct macio_chip* macio_find(struct device_node* child, int type) { while(child) { int i; @@ -79,7 +79,7 @@ struct macio_chip* __pmac macio_find(struct device_node* child, int type) } EXPORT_SYMBOL_GPL(macio_find); -static const char* macio_names[] __pmacdata = +static const char* macio_names[] = { "Unknown", "Grand Central", @@ -106,9 +106,9 @@ static const char* macio_names[] __pmacdata = #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) -static struct device_node* uninorth_node __pmacdata; -static u32* uninorth_base __pmacdata; -static u32 uninorth_rev __pmacdata; +static struct device_node* uninorth_node; +static u32* uninorth_base; +static u32 uninorth_rev; static void *u3_ht; extern struct device_node *k2_skiplist[2]; @@ -133,14 +133,14 @@ struct pmac_mb_def struct feature_table_entry* features; unsigned long board_flags; }; -static struct pmac_mb_def pmac_mb __pmacdata; +static struct pmac_mb_def pmac_mb; /* * Here are the chip specific feature functions */ -static long __pmac g5_read_gpio(struct device_node* node, long param, long value) +static long g5_read_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -148,7 +148,7 @@ static long __pmac g5_read_gpio(struct device_node* node, long param, long value } -static long __pmac g5_write_gpio(struct device_node* node, long param, long value) +static long g5_write_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -156,7 +156,7 @@ static long __pmac g5_write_gpio(struct device_node* node, long param, long valu return 0; } -static long __pmac g5_gmac_enable(struct device_node* node, long param, long value) +static long g5_gmac_enable(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; unsigned long flags; @@ -181,7 +181,7 @@ static long __pmac g5_gmac_enable(struct device_node* node, long param, long val return 0; } -static long __pmac g5_fw_enable(struct device_node* node, long param, long value) +static long g5_fw_enable(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; unsigned long flags; @@ -206,7 +206,7 @@ static long __pmac g5_fw_enable(struct device_node* node, long param, long value return 0; } -static long __pmac g5_mpic_enable(struct device_node* node, long param, long value) +static long g5_mpic_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -220,7 +220,7 @@ static long __pmac g5_mpic_enable(struct device_node* node, long param, long val return 0; } -static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value) +static long g5_eth_phy_reset(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; struct device_node *phy; @@ -250,7 +250,7 @@ static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long v return 0; } -static long __pmac g5_i2s_enable(struct device_node *node, long param, long value) +static long g5_i2s_enable(struct device_node *node, long param, long value) { /* Very crude implementation for now */ struct macio_chip* macio = &macio_chips[0]; @@ -275,7 +275,7 @@ static long __pmac g5_i2s_enable(struct device_node *node, long param, long valu #ifdef CONFIG_SMP -static long __pmac g5_reset_cpu(struct device_node* node, long param, long value) +static long g5_reset_cpu(struct device_node* node, long param, long value) { unsigned int reset_io = 0; unsigned long flags; @@ -320,12 +320,12 @@ static long __pmac g5_reset_cpu(struct device_node* node, long param, long value * This takes the second CPU off the bus on dual CPU machines * running UP */ -void __pmac g5_phy_disable_cpu1(void) +void g5_phy_disable_cpu1(void) { UN_OUT(U3_API_PHY_CONFIG_1, 0); } -static long __pmac generic_get_mb_info(struct device_node* node, long param, long value) +static long generic_get_mb_info(struct device_node* node, long param, long value) { switch(param) { case PMAC_MB_INFO_MODEL: @@ -347,14 +347,14 @@ static long __pmac generic_get_mb_info(struct device_node* node, long param, lon /* Used on any machine */ -static struct feature_table_entry any_features[] __pmacdata = { +static struct feature_table_entry any_features[] = { { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, { 0, NULL } }; /* G5 features */ -static struct feature_table_entry g5_features[] __pmacdata = { +static struct feature_table_entry g5_features[] = { { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, { PMAC_FTR_1394_ENABLE, g5_fw_enable }, { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, @@ -368,7 +368,7 @@ static struct feature_table_entry g5_features[] __pmacdata = { { 0, NULL } }; -static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { +static struct pmac_mb_def pmac_mb_defs[] = { { "PowerMac7,2", "PowerMac G5", PMAC_TYPE_POWERMAC_G5, g5_features, 0, @@ -394,7 +394,7 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* * The toplevel feature_call callback */ -long __pmac pmac_do_feature_call(unsigned int selector, ...) +long pmac_do_feature_call(unsigned int selector, ...) { struct device_node* node; long param, value; @@ -706,8 +706,8 @@ void __init pmac_check_ht_link(void) * Early video resume hook */ -static void (*pmac_early_vresume_proc)(void *data) __pmacdata; -static void *pmac_early_vresume_data __pmacdata; +static void (*pmac_early_vresume_proc)(void *data); +static void *pmac_early_vresume_data; void pmac_set_early_video_resume(void (*proc)(void *data), void *data) { @@ -725,11 +725,11 @@ EXPORT_SYMBOL(pmac_set_early_video_resume); * AGP related suspend/resume code */ -static struct pci_dev *pmac_agp_bridge __pmacdata; -static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata; -static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata; +static struct pci_dev *pmac_agp_bridge; +static int (*pmac_agp_suspend)(struct pci_dev *bridge); +static int (*pmac_agp_resume)(struct pci_dev *bridge); -void __pmac pmac_register_agp_pm(struct pci_dev *bridge, +void pmac_register_agp_pm(struct pci_dev *bridge, int (*suspend)(struct pci_dev *bridge), int (*resume)(struct pci_dev *bridge)) { @@ -746,7 +746,7 @@ void __pmac pmac_register_agp_pm(struct pci_dev *bridge, } EXPORT_SYMBOL(pmac_register_agp_pm); -void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev) +void pmac_suspend_agp_for_card(struct pci_dev *dev) { if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) return; @@ -756,7 +756,7 @@ void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev) } EXPORT_SYMBOL(pmac_suspend_agp_for_card); -void __pmac pmac_resume_agp_for_card(struct pci_dev *dev) +void pmac_resume_agp_for_card(struct pci_dev *dev) { if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) return; diff --git a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c index e32a902236e3..11586d535f81 100644 --- a/arch/ppc64/kernel/pmac_nvram.c +++ b/arch/ppc64/kernel/pmac_nvram.c @@ -82,10 +82,10 @@ extern int system_running; static int (*core99_write_bank)(int bank, u8* datas); static int (*core99_erase_bank)(int bank); -static char *nvram_image __pmacdata; +static char *nvram_image; -static ssize_t __pmac core99_nvram_read(char *buf, size_t count, loff_t *index) +static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index) { int i; @@ -103,7 +103,7 @@ static ssize_t __pmac core99_nvram_read(char *buf, size_t count, loff_t *index) return count; } -static ssize_t __pmac core99_nvram_write(char *buf, size_t count, loff_t *index) +static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index) { int i; @@ -121,14 +121,14 @@ static ssize_t __pmac core99_nvram_write(char *buf, size_t count, loff_t *index) return count; } -static ssize_t __pmac core99_nvram_size(void) +static ssize_t core99_nvram_size(void) { if (nvram_image == NULL) return -ENODEV; return NVRAM_SIZE; } -static u8 __pmac chrp_checksum(struct chrp_header* hdr) +static u8 chrp_checksum(struct chrp_header* hdr) { u8 *ptr; u16 sum = hdr->signature; @@ -139,7 +139,7 @@ static u8 __pmac chrp_checksum(struct chrp_header* hdr) return sum; } -static u32 __pmac core99_calc_adler(u8 *buffer) +static u32 core99_calc_adler(u8 *buffer) { int cnt; u32 low, high; @@ -161,7 +161,7 @@ static u32 __pmac core99_calc_adler(u8 *buffer) return (high << 16) | low; } -static u32 __pmac core99_check(u8* datas) +static u32 core99_check(u8* datas) { struct core99_header* hdr99 = (struct core99_header*)datas; @@ -180,7 +180,7 @@ static u32 __pmac core99_check(u8* datas) return hdr99->generation; } -static int __pmac sm_erase_bank(int bank) +static int sm_erase_bank(int bank) { int stat, i; unsigned long timeout; @@ -212,7 +212,7 @@ static int __pmac sm_erase_bank(int bank) return 0; } -static int __pmac sm_write_bank(int bank, u8* datas) +static int sm_write_bank(int bank, u8* datas) { int i, stat = 0; unsigned long timeout; @@ -247,7 +247,7 @@ static int __pmac sm_write_bank(int bank, u8* datas) return 0; } -static int __pmac amd_erase_bank(int bank) +static int amd_erase_bank(int bank) { int i, stat = 0; unsigned long timeout; @@ -294,7 +294,7 @@ static int __pmac amd_erase_bank(int bank) return 0; } -static int __pmac amd_write_bank(int bank, u8* datas) +static int amd_write_bank(int bank, u8* datas) { int i, stat = 0; unsigned long timeout; @@ -341,7 +341,7 @@ static int __pmac amd_write_bank(int bank, u8* datas) } -static int __pmac core99_nvram_sync(void) +static int core99_nvram_sync(void) { struct core99_header* hdr99; unsigned long flags; @@ -431,7 +431,7 @@ int __init pmac_nvram_init(void) return 0; } -int __pmac pmac_get_partition(int partition) +int pmac_get_partition(int partition) { struct nvram_partition *part; const char *name; @@ -459,7 +459,7 @@ int __pmac pmac_get_partition(int partition) return part->index; } -u8 __pmac pmac_xpram_read(int xpaddr) +u8 pmac_xpram_read(int xpaddr) { int offset = pmac_get_partition(pmac_nvram_XPRAM); loff_t index; @@ -476,7 +476,7 @@ u8 __pmac pmac_xpram_read(int xpaddr) return buf; } -void __pmac pmac_xpram_write(int xpaddr, u8 data) +void pmac_xpram_write(int xpaddr, u8 data) { int offset = pmac_get_partition(pmac_nvram_XPRAM); loff_t index; diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index dc40a0cad0b4..1f61aa4746ec 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -121,7 +121,7 @@ static void __init fixup_bus_range(struct device_node *bridge) |(((unsigned long)(off)) & 0xFCUL) \ |1UL) -static unsigned long __pmac macrisc_cfg_access(struct pci_controller* hose, +static unsigned long macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) { unsigned int caddr; @@ -142,7 +142,7 @@ static unsigned long __pmac macrisc_cfg_access(struct pci_controller* hose, return ((unsigned long)hose->cfg_data) + offset; } -static int __pmac macrisc_read_config(struct pci_bus *bus, unsigned int devfn, +static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { struct pci_controller *hose; @@ -173,7 +173,7 @@ static int __pmac macrisc_read_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } -static int __pmac macrisc_write_config(struct pci_bus *bus, unsigned int devfn, +static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose; @@ -265,7 +265,7 @@ static int u3_ht_skip_device(struct pci_controller *hose, + (((unsigned long)bus) << 16) \ + 0x01000000UL) -static unsigned long __pmac u3_ht_cfg_access(struct pci_controller* hose, +static unsigned long u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset) { if (bus == hose->first_busno) { @@ -277,7 +277,7 @@ static unsigned long __pmac u3_ht_cfg_access(struct pci_controller* hose, return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); } -static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, +static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { struct pci_controller *hose; @@ -327,7 +327,7 @@ static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } -static int __pmac u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, +static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose; diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 325426c7bed0..1f5118078f7d 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL(smu_cmdbuf_abs); extern void udbg_init_scc(struct device_node *np); -static void __pmac pmac_show_cpuinfo(struct seq_file *m) +static void pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; char *pp; @@ -210,7 +210,7 @@ static int pmac_late_init(void) late_initcall(pmac_late_init); /* can't be __init - can be called whenever a disk is first accessed */ -void __pmac note_bootable_part(dev_t dev, int part, int goodness) +void note_bootable_part(dev_t dev, int part, int goodness) { extern dev_t boot_dev; char *p; @@ -231,7 +231,7 @@ void __pmac note_bootable_part(dev_t dev, int part, int goodness) } } -static void __pmac pmac_restart(char *cmd) +static void pmac_restart(char *cmd) { switch(sys_ctrler) { #ifdef CONFIG_ADB_PMU @@ -250,7 +250,7 @@ static void __pmac pmac_restart(char *cmd) } } -static void __pmac pmac_power_off(void) +static void pmac_power_off(void) { switch(sys_ctrler) { #ifdef CONFIG_ADB_PMU @@ -268,7 +268,7 @@ static void __pmac pmac_power_off(void) } } -static void __pmac pmac_halt(void) +static void pmac_halt(void) { pmac_power_off(); } diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index a23de37227bf..9fd23ea55bc9 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -310,7 +310,7 @@ static void __init smp_core99_setup_cpu(int cpu_nr) } } -struct smp_ops_t core99_smp_ops __pmacdata = { +struct smp_ops_t core99_smp_ops = { .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index 3059edb09cc8..6c8c99295e7a 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -51,7 +51,7 @@ extern struct timezone sys_tz; extern void to_tm(int tim, struct rtc_time * tm); -void __pmac pmac_get_rtc_time(struct rtc_time *tm) +void pmac_get_rtc_time(struct rtc_time *tm) { switch(sys_ctrler) { #ifdef CONFIG_ADB_PMU @@ -92,7 +92,7 @@ void __pmac pmac_get_rtc_time(struct rtc_time *tm) } } -int __pmac pmac_set_rtc_time(struct rtc_time *tm) +int pmac_set_rtc_time(struct rtc_time *tm) { switch(sys_ctrler) { #ifdef CONFIG_ADB_PMU diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 87d1f8a1f41e..d8c3d8ebad30 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -81,7 +81,7 @@ typedef struct pmac_ide_hwif { } pmac_ide_hwif_t; -static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata; +static pmac_ide_hwif_t pmac_ide[MAX_HWIFS]; static int pmac_ide_count; enum { @@ -242,7 +242,7 @@ struct mdma_timings_t { int cycleTime; }; -struct mdma_timings_t mdma_timings_33[] __pmacdata = +struct mdma_timings_t mdma_timings_33[] = { { 240, 240, 480 }, { 180, 180, 360 }, @@ -255,7 +255,7 @@ struct mdma_timings_t mdma_timings_33[] __pmacdata = { 0, 0, 0 } }; -struct mdma_timings_t mdma_timings_33k[] __pmacdata = +struct mdma_timings_t mdma_timings_33k[] = { { 240, 240, 480 }, { 180, 180, 360 }, @@ -268,7 +268,7 @@ struct mdma_timings_t mdma_timings_33k[] __pmacdata = { 0, 0, 0 } }; -struct mdma_timings_t mdma_timings_66[] __pmacdata = +struct mdma_timings_t mdma_timings_66[] = { { 240, 240, 480 }, { 180, 180, 360 }, @@ -286,7 +286,7 @@ struct { int addrSetup; /* ??? */ int rdy2pause; int wrDataSetup; -} kl66_udma_timings[] __pmacdata = +} kl66_udma_timings[] = { { 0, 180, 120 }, /* Mode 0 */ { 0, 150, 90 }, /* 1 */ @@ -301,7 +301,7 @@ struct kauai_timing { u32 timing_reg; }; -static struct kauai_timing kauai_pio_timings[] __pmacdata = +static struct kauai_timing kauai_pio_timings[] = { { 930 , 0x08000fff }, { 600 , 0x08000a92 }, @@ -316,7 +316,7 @@ static struct kauai_timing kauai_pio_timings[] __pmacdata = { 120 , 0x04000148 } }; -static struct kauai_timing kauai_mdma_timings[] __pmacdata = +static struct kauai_timing kauai_mdma_timings[] = { { 1260 , 0x00fff000 }, { 480 , 0x00618000 }, @@ -330,7 +330,7 @@ static struct kauai_timing kauai_mdma_timings[] __pmacdata = { 0 , 0 }, }; -static struct kauai_timing kauai_udma_timings[] __pmacdata = +static struct kauai_timing kauai_udma_timings[] = { { 120 , 0x000070c0 }, { 90 , 0x00005d80 }, @@ -341,7 +341,7 @@ static struct kauai_timing kauai_udma_timings[] __pmacdata = { 0 , 0 }, }; -static struct kauai_timing shasta_pio_timings[] __pmacdata = +static struct kauai_timing shasta_pio_timings[] = { { 930 , 0x08000fff }, { 600 , 0x0A000c97 }, @@ -356,7 +356,7 @@ static struct kauai_timing shasta_pio_timings[] __pmacdata = { 120 , 0x0400010a } }; -static struct kauai_timing shasta_mdma_timings[] __pmacdata = +static struct kauai_timing shasta_mdma_timings[] = { { 1260 , 0x00fff000 }, { 480 , 0x00820800 }, @@ -370,7 +370,7 @@ static struct kauai_timing shasta_mdma_timings[] __pmacdata = { 0 , 0 }, }; -static struct kauai_timing shasta_udma133_timings[] __pmacdata = +static struct kauai_timing shasta_udma133_timings[] = { { 120 , 0x00035901, }, { 90 , 0x000348b1, }, @@ -522,7 +522,7 @@ pmu_hd_blink_init(void) * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. */ -void __pmac +void pmac_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq) @@ -559,7 +559,7 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw, * timing register when selecting that unit. This version is for * ASICs with a single timing register */ -static void __pmac +static void pmac_ide_selectproc(ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -579,7 +579,7 @@ pmac_ide_selectproc(ide_drive_t *drive) * timing register when selecting that unit. This version is for * ASICs with a dual timing register (Kauai) */ -static void __pmac +static void pmac_ide_kauai_selectproc(ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -600,7 +600,7 @@ pmac_ide_kauai_selectproc(ide_drive_t *drive) /* * Force an update of controller timing values for a given drive */ -static void __pmac +static void pmac_ide_do_update_timings(ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -633,7 +633,7 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port) * to sort that out sooner or later and see if I can finally get the * common version to work properly in all cases */ -static int __pmac +static int pmac_ide_do_setfeature(ide_drive_t *drive, u8 command) { ide_hwif_t *hwif = HWIF(drive); @@ -710,7 +710,7 @@ pmac_ide_do_setfeature(ide_drive_t *drive, u8 command) /* * Old tuning functions (called on hdparm -p), sets up drive PIO timings */ -static void __pmac +static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) { ide_pio_data_t d; @@ -801,7 +801,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) /* * Calculate KeyLargo ATA/66 UDMA timings */ -static int __pmac +static int set_timings_udma_ata4(u32 *timings, u8 speed) { unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; @@ -829,7 +829,7 @@ set_timings_udma_ata4(u32 *timings, u8 speed) /* * Calculate Kauai ATA/100 UDMA timings */ -static int __pmac +static int set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) { struct ide_timing *t = ide_timing_find_mode(speed); @@ -849,7 +849,7 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) /* * Calculate Shasta ATA/133 UDMA timings */ -static int __pmac +static int set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) { struct ide_timing *t = ide_timing_find_mode(speed); @@ -869,7 +869,7 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) /* * Calculate MDMA timings for all cells */ -static int __pmac +static int set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, u8 speed, int drive_cycle_time) { @@ -1014,7 +1014,7 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, * our dedicated function is more precise as it uses the drive provided * cycle time value. We should probably fix this one to deal with that too... */ -static int __pmac +static int pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) { int unit = (drive->select.b.unit & 0x01); @@ -1092,7 +1092,7 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) * Blast some well known "safe" values to the timing registers at init or * wakeup from sleep time, before we do real calculation */ -static void __pmac +static void sanitize_timings(pmac_ide_hwif_t *pmif) { unsigned int value, value2 = 0; @@ -1123,13 +1123,13 @@ sanitize_timings(pmac_ide_hwif_t *pmif) pmif->timings[2] = pmif->timings[3] = value2; } -unsigned long __pmac +unsigned long pmac_ide_get_base(int index) { return pmac_ide[index].regbase; } -int __pmac +int pmac_ide_check_base(unsigned long base) { int ix; @@ -1140,7 +1140,7 @@ pmac_ide_check_base(unsigned long base) return -1; } -int __pmac +int pmac_ide_get_irq(unsigned long base) { int ix; @@ -1151,7 +1151,7 @@ pmac_ide_get_irq(unsigned long base) return 0; } -static int ide_majors[] __pmacdata = { 3, 22, 33, 34, 56, 57 }; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; dev_t __init pmac_find_ide_boot(char *bootdevice, int n) @@ -1701,7 +1701,7 @@ pmac_ide_probe(void) * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */ -static int __pmac +static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) { struct dbdma_cmd *table; @@ -1785,7 +1785,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) } /* Teardown mappings after DMA has completed. */ -static void __pmac +static void pmac_ide_destroy_dmatable (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; @@ -1802,7 +1802,7 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive) /* * Pick up best MDMA timing for the drive and apply it */ -static int __pmac +static int pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode) { ide_hwif_t *hwif = HWIF(drive); @@ -1859,7 +1859,7 @@ pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode) /* * Pick up best UDMA timing for the drive and apply it */ -static int __pmac +static int pmac_ide_udma_enable(ide_drive_t *drive, u16 mode) { ide_hwif_t *hwif = HWIF(drive); @@ -1915,7 +1915,7 @@ pmac_ide_udma_enable(ide_drive_t *drive, u16 mode) * Check what is the best DMA timing setting for the drive and * call appropriate functions to apply it. */ -static int __pmac +static int pmac_ide_dma_check(ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -1967,7 +1967,7 @@ pmac_ide_dma_check(ide_drive_t *drive) * Prepare a DMA transfer. We build the DMA table, adjust the timings for * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion */ -static int __pmac +static int pmac_ide_dma_setup(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -1997,7 +1997,7 @@ pmac_ide_dma_setup(ide_drive_t *drive) return 0; } -static void __pmac +static void pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) { /* issue cmd to drive */ @@ -2008,7 +2008,7 @@ pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) * Kick the DMA controller into life after the DMA command has been issued * to the drive. */ -static void __pmac +static void pmac_ide_dma_start(ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -2024,7 +2024,7 @@ pmac_ide_dma_start(ide_drive_t *drive) /* * After a DMA transfer, make sure the controller is stopped */ -static int __pmac +static int pmac_ide_dma_end (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -2052,7 +2052,7 @@ pmac_ide_dma_end (ide_drive_t *drive) * that's not implemented yet), on the other hand, we don't have shared interrupts * so it's not really a problem */ -static int __pmac +static int pmac_ide_dma_test_irq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -2108,19 +2108,19 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) return 1; } -static int __pmac +static int pmac_ide_dma_host_off (ide_drive_t *drive) { return 0; } -static int __pmac +static int pmac_ide_dma_host_on (ide_drive_t *drive) { return 0; } -static int __pmac +static int pmac_ide_dma_lostirq (ide_drive_t *drive) { pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index 5e0811dc6536..2b8a6e821d44 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -27,7 +27,7 @@ static volatile unsigned char __iomem *anslcd_ptr; #undef DEBUG -static void __pmac +static void anslcd_write_byte_ctrl ( unsigned char c ) { #ifdef DEBUG @@ -43,14 +43,14 @@ anslcd_write_byte_ctrl ( unsigned char c ) } } -static void __pmac +static void anslcd_write_byte_data ( unsigned char c ) { out_8(anslcd_ptr + ANSLCD_DATA_IX, c); udelay(anslcd_short_delay); } -static ssize_t __pmac +static ssize_t anslcd_write( struct file * file, const char __user * buf, size_t count, loff_t *ppos ) { @@ -73,7 +73,7 @@ anslcd_write( struct file * file, const char __user * buf, return p - buf; } -static int __pmac +static int anslcd_ioctl( struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) { @@ -115,7 +115,7 @@ anslcd_ioctl( struct inode * inode, struct file * file, } } -static int __pmac +static int anslcd_open( struct inode * inode, struct file * file ) { return 0; diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index c0712a1ea5af..b856bb67169c 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -167,19 +167,19 @@ enum { * Functions for polling content of media bay */ -static u8 __pmac +static u8 ohare_mb_content(struct media_bay_info *bay) { return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; } -static u8 __pmac +static u8 heathrow_mb_content(struct media_bay_info *bay) { return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; } -static u8 __pmac +static u8 keylargo_mb_content(struct media_bay_info *bay) { int new_gpio; @@ -205,7 +205,7 @@ keylargo_mb_content(struct media_bay_info *bay) * into reset state as well */ -static void __pmac +static void ohare_mb_power(struct media_bay_info* bay, int on_off) { if (on_off) { @@ -224,7 +224,7 @@ ohare_mb_power(struct media_bay_info* bay, int on_off) MB_BIC(bay, OHARE_MBCR, 0x00000F00); } -static void __pmac +static void heathrow_mb_power(struct media_bay_info* bay, int on_off) { if (on_off) { @@ -243,7 +243,7 @@ heathrow_mb_power(struct media_bay_info* bay, int on_off) MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); } -static void __pmac +static void keylargo_mb_power(struct media_bay_info* bay, int on_off) { if (on_off) { @@ -267,7 +267,7 @@ keylargo_mb_power(struct media_bay_info* bay, int on_off) * enable the related busses */ -static int __pmac +static int ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) { switch(device_id) { @@ -287,7 +287,7 @@ ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) return -ENODEV; } -static int __pmac +static int heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) { switch(device_id) { @@ -307,7 +307,7 @@ heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) return -ENODEV; } -static int __pmac +static int keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) { switch(device_id) { @@ -330,43 +330,43 @@ keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) * Functions for tweaking resets */ -static void __pmac +static void ohare_mb_un_reset(struct media_bay_info* bay) { MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); } -static void __pmac keylargo_mb_init(struct media_bay_info *bay) +static void keylargo_mb_init(struct media_bay_info *bay) { MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); } -static void __pmac heathrow_mb_un_reset(struct media_bay_info* bay) +static void heathrow_mb_un_reset(struct media_bay_info* bay) { MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); } -static void __pmac keylargo_mb_un_reset(struct media_bay_info* bay) +static void keylargo_mb_un_reset(struct media_bay_info* bay) { MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); } -static void __pmac ohare_mb_un_reset_ide(struct media_bay_info* bay) +static void ohare_mb_un_reset_ide(struct media_bay_info* bay) { MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); } -static void __pmac heathrow_mb_un_reset_ide(struct media_bay_info* bay) +static void heathrow_mb_un_reset_ide(struct media_bay_info* bay) { MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); } -static void __pmac keylargo_mb_un_reset_ide(struct media_bay_info* bay) +static void keylargo_mb_un_reset_ide(struct media_bay_info* bay) { MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); } -static inline void __pmac set_mb_power(struct media_bay_info* bay, int onoff) +static inline void set_mb_power(struct media_bay_info* bay, int onoff) { /* Power up up and assert the bay reset line */ if (onoff) { @@ -382,7 +382,7 @@ static inline void __pmac set_mb_power(struct media_bay_info* bay, int onoff) bay->timer = msecs_to_jiffies(MB_POWER_DELAY); } -static void __pmac poll_media_bay(struct media_bay_info* bay) +static void poll_media_bay(struct media_bay_info* bay) { int id = bay->ops->content(bay); @@ -415,7 +415,7 @@ static void __pmac poll_media_bay(struct media_bay_info* bay) } } -int __pmac check_media_bay(struct device_node *which_bay, int what) +int check_media_bay(struct device_node *which_bay, int what) { #ifdef CONFIG_BLK_DEV_IDE int i; @@ -432,7 +432,7 @@ int __pmac check_media_bay(struct device_node *which_bay, int what) } EXPORT_SYMBOL(check_media_bay); -int __pmac check_media_bay_by_base(unsigned long base, int what) +int check_media_bay_by_base(unsigned long base, int what) { #ifdef CONFIG_BLK_DEV_IDE int i; @@ -449,7 +449,7 @@ int __pmac check_media_bay_by_base(unsigned long base, int what) return -ENODEV; } -int __pmac media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, +int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, int irq, int index) { #ifdef CONFIG_BLK_DEV_IDE @@ -489,7 +489,7 @@ int __pmac media_bay_set_ide_infos(struct device_node* which_bay, unsigned long return -ENODEV; } -static void __pmac media_bay_step(int i) +static void media_bay_step(int i) { struct media_bay_info* bay = &media_bays[i]; @@ -619,7 +619,7 @@ static void __pmac media_bay_step(int i) * with the IDE driver. It needs to be a thread because * ide_register can't be called from interrupt context. */ -static int __pmac media_bay_task(void *x) +static int media_bay_task(void *x) { int i; @@ -704,7 +704,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de } -static int __pmac media_bay_suspend(struct macio_dev *mdev, pm_message_t state) +static int media_bay_suspend(struct macio_dev *mdev, pm_message_t state) { struct media_bay_info *bay = macio_get_drvdata(mdev); @@ -719,7 +719,7 @@ static int __pmac media_bay_suspend(struct macio_dev *mdev, pm_message_t state) return 0; } -static int __pmac media_bay_resume(struct macio_dev *mdev) +static int media_bay_resume(struct macio_dev *mdev) { struct media_bay_info *bay = macio_get_drvdata(mdev); @@ -760,7 +760,7 @@ static int __pmac media_bay_resume(struct macio_dev *mdev) /* Definitions of "ops" structures. */ -static struct mb_ops ohare_mb_ops __pmacdata = { +static struct mb_ops ohare_mb_ops = { .name = "Ohare", .content = ohare_mb_content, .power = ohare_mb_power, @@ -769,7 +769,7 @@ static struct mb_ops ohare_mb_ops __pmacdata = { .un_reset_ide = ohare_mb_un_reset_ide, }; -static struct mb_ops heathrow_mb_ops __pmacdata = { +static struct mb_ops heathrow_mb_ops = { .name = "Heathrow", .content = heathrow_mb_content, .power = heathrow_mb_power, @@ -778,7 +778,7 @@ static struct mb_ops heathrow_mb_ops __pmacdata = { .un_reset_ide = heathrow_mb_un_reset_ide, }; -static struct mb_ops keylargo_mb_ops __pmacdata = { +static struct mb_ops keylargo_mb_ops = { .name = "KeyLargo", .init = keylargo_mb_init, .content = keylargo_mb_content, diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 417deb5de108..d843a6c9c6df 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -37,7 +37,6 @@ static DEFINE_SPINLOCK(cuda_lock); #ifdef CONFIG_MAC #define CUDA_IRQ IRQ_MAC_ADB -#define __openfirmware #define eieio() #else #define CUDA_IRQ vias->intrs[0].line diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 645a2e5c70ab..76719451e384 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -244,7 +244,7 @@ int pmu_wink(struct adb_request *req); * - the number of response bytes which the PMU will return, or * -1 if it will send a length byte. */ -static const s8 pmu_data_len[256][2] __openfirmwaredata = { +static const s8 pmu_data_len[256][2] = { /* 0 1 2 3 4 5 6 7 */ /*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, @@ -295,7 +295,7 @@ static struct backlight_controller pmu_backlight_controller = { }; #endif /* CONFIG_PMAC_BACKLIGHT */ -int __openfirmware +int find_via_pmu(void) { if (via != 0) @@ -374,7 +374,7 @@ find_via_pmu(void) } #ifdef CONFIG_ADB -static int __openfirmware +static int pmu_probe(void) { return vias == NULL? -ENODEV: 0; @@ -520,7 +520,7 @@ static int __init via_pmu_dev_init(void) device_initcall(via_pmu_dev_init); -static int __openfirmware +static int init_pmu(void) { int timeout; @@ -625,7 +625,7 @@ static void pmu_set_server_mode(int server_mode) /* This new version of the code for 2400/3400/3500 powerbooks * is inspired from the implementation in gkrellm-pmu */ -static void __pmac +static void done_battery_state_ohare(struct adb_request* req) { /* format: @@ -713,7 +713,7 @@ done_battery_state_ohare(struct adb_request* req) clear_bit(0, &async_req_locks); } -static void __pmac +static void done_battery_state_smart(struct adb_request* req) { /* format: @@ -791,7 +791,7 @@ done_battery_state_smart(struct adb_request* req) clear_bit(0, &async_req_locks); } -static void __pmac +static void query_battery_state(void) { if (test_and_set_bit(0, &async_req_locks)) @@ -804,7 +804,7 @@ query_battery_state(void) 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); } -static int __pmac +static int proc_get_info(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -819,7 +819,7 @@ proc_get_info(char *page, char **start, off_t off, return p - page; } -static int __pmac +static int proc_get_irqstats(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -846,7 +846,7 @@ proc_get_irqstats(char *page, char **start, off_t off, return p - page; } -static int __pmac +static int proc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -870,7 +870,7 @@ proc_get_batt(char *page, char **start, off_t off, return p - page; } -static int __pmac +static int proc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -887,7 +887,7 @@ proc_read_options(char *page, char **start, off_t off, return p - page; } -static int __pmac +static int proc_write_options(struct file *file, const char __user *buffer, unsigned long count, void *data) { @@ -934,7 +934,7 @@ proc_write_options(struct file *file, const char __user *buffer, #ifdef CONFIG_ADB /* Send an ADB command */ -static int __pmac +static int pmu_send_request(struct adb_request *req, int sync) { int i, ret; @@ -1014,7 +1014,7 @@ pmu_send_request(struct adb_request *req, int sync) } /* Enable/disable autopolling */ -static int __pmac +static int pmu_adb_autopoll(int devs) { struct adb_request req; @@ -1037,7 +1037,7 @@ pmu_adb_autopoll(int devs) } /* Reset the ADB bus */ -static int __pmac +static int pmu_adb_reset_bus(void) { struct adb_request req; @@ -1072,7 +1072,7 @@ pmu_adb_reset_bus(void) #endif /* CONFIG_ADB */ /* Construct and send a pmu request */ -int __openfirmware +int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...) { @@ -1098,7 +1098,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *), return pmu_queue_request(req); } -int __pmac +int pmu_queue_request(struct adb_request *req) { unsigned long flags; @@ -1190,7 +1190,7 @@ pmu_done(struct adb_request *req) (*done)(req); } -static void __pmac +static void pmu_start(void) { struct adb_request *req; @@ -1214,7 +1214,7 @@ pmu_start(void) send_byte(req->data[0]); } -void __openfirmware +void pmu_poll(void) { if (!via) @@ -1224,7 +1224,7 @@ pmu_poll(void) via_pmu_interrupt(0, NULL, NULL); } -void __openfirmware +void pmu_poll_adb(void) { if (!via) @@ -1239,7 +1239,7 @@ pmu_poll_adb(void) || req_awaiting_reply)); } -void __openfirmware +void pmu_wait_complete(struct adb_request *req) { if (!via) @@ -1253,7 +1253,7 @@ pmu_wait_complete(struct adb_request *req) * This is done to avoid spurrious shutdowns when we know we'll have * interrupts switched off for a long time */ -void __openfirmware +void pmu_suspend(void) { unsigned long flags; @@ -1293,7 +1293,7 @@ pmu_suspend(void) } while (1); } -void __openfirmware +void pmu_resume(void) { unsigned long flags; @@ -1323,7 +1323,7 @@ pmu_resume(void) } /* Interrupt data could be the result data from an ADB cmd */ -static void __pmac +static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) { unsigned char ints, pirq; @@ -1435,7 +1435,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) goto next; } -static struct adb_request* __pmac +static struct adb_request* pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; @@ -1541,7 +1541,7 @@ pmu_sr_intr(struct pt_regs *regs) return NULL; } -static irqreturn_t __pmac +static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { unsigned long flags; @@ -1629,7 +1629,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) return IRQ_RETVAL(handled); } -void __pmac +void pmu_unlock(void) { unsigned long flags; @@ -1642,7 +1642,7 @@ pmu_unlock(void) } -static irqreturn_t __pmac +static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { unsigned long flags; @@ -1663,12 +1663,12 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) } #ifdef CONFIG_PMAC_BACKLIGHT -static int backlight_to_bright[] __pmacdata = { +static int backlight_to_bright[] = { 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e }; -static int __openfirmware +static int pmu_set_backlight_enable(int on, int level, void* data) { struct adb_request req; @@ -1688,7 +1688,7 @@ pmu_set_backlight_enable(int on, int level, void* data) return 0; } -static void __openfirmware +static void pmu_bright_complete(struct adb_request *req) { if (req == &bright_req_1) @@ -1697,7 +1697,7 @@ pmu_bright_complete(struct adb_request *req) clear_bit(2, &async_req_locks); } -static int __openfirmware +static int pmu_set_backlight_level(int level, void* data) { if (vias == NULL) @@ -1717,7 +1717,7 @@ pmu_set_backlight_level(int level, void* data) } #endif /* CONFIG_PMAC_BACKLIGHT */ -void __pmac +void pmu_enable_irled(int on) { struct adb_request req; @@ -1732,7 +1732,7 @@ pmu_enable_irled(int on) pmu_wait_complete(&req); } -void __pmac +void pmu_restart(void) { struct adb_request req; @@ -1757,7 +1757,7 @@ pmu_restart(void) ; } -void __pmac +void pmu_shutdown(void) { struct adb_request req; @@ -2076,7 +2076,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) } /* Sleep is broadcast last-to-first */ -static int __pmac +static int broadcast_sleep(int when, int fallback) { int ret = PBOOK_SLEEP_OK; @@ -2101,7 +2101,7 @@ broadcast_sleep(int when, int fallback) } /* Wake is broadcast first-to-last */ -static int __pmac +static int broadcast_wake(void) { int ret = PBOOK_SLEEP_OK; @@ -2132,7 +2132,7 @@ static struct pci_save { } *pbook_pci_saves; static int pbook_npci_saves; -static void __pmac +static void pbook_alloc_pci_save(void) { int npci; @@ -2149,7 +2149,7 @@ pbook_alloc_pci_save(void) pbook_npci_saves = npci; } -static void __pmac +static void pbook_free_pci_save(void) { if (pbook_pci_saves == NULL) @@ -2159,7 +2159,7 @@ pbook_free_pci_save(void) pbook_npci_saves = 0; } -static void __pmac +static void pbook_pci_save(void) { struct pci_save *ps = pbook_pci_saves; @@ -2190,7 +2190,7 @@ pbook_pci_save(void) * during boot, it will be in the pci dev list. If it's disabled at this point * (and it will probably be), then you can't access it's config space. */ -static void __pmac +static void pbook_pci_restore(void) { u16 cmd; @@ -2238,7 +2238,7 @@ pbook_pci_restore(void) #ifdef DEBUG_SLEEP /* N.B. This doesn't work on the 3400 */ -void __pmac +void pmu_blink(int n) { struct adb_request req; @@ -2277,9 +2277,9 @@ pmu_blink(int n) * Put the powerbook to sleep. */ -static u32 save_via[8] __pmacdata; +static u32 save_via[8]; -static void __pmac +static void save_via_state(void) { save_via[0] = in_8(&via[ANH]); @@ -2291,7 +2291,7 @@ save_via_state(void) save_via[6] = in_8(&via[T1CL]); save_via[7] = in_8(&via[T1CH]); } -static void __pmac +static void restore_via_state(void) { out_8(&via[ANH], save_via[0]); @@ -2307,7 +2307,7 @@ restore_via_state(void) out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } -static int __pmac +static int pmac_suspend_devices(void) { int ret; @@ -2397,7 +2397,7 @@ pmac_suspend_devices(void) return 0; } -static int __pmac +static int pmac_wakeup_devices(void) { mdelay(100); @@ -2436,7 +2436,7 @@ pmac_wakeup_devices(void) #define GRACKLE_NAP (1<<4) #define GRACKLE_SLEEP (1<<3) -int __pmac +int powerbook_sleep_grackle(void) { unsigned long save_l2cr; @@ -2520,7 +2520,7 @@ powerbook_sleep_grackle(void) return 0; } -static int __pmac +static int powerbook_sleep_Core99(void) { unsigned long save_l2cr; @@ -2620,7 +2620,7 @@ powerbook_sleep_Core99(void) #define PB3400_MEM_CTRL 0xf8000000 #define PB3400_MEM_CTRL_SLEEP 0x70 -static int __pmac +static int powerbook_sleep_3400(void) { int ret, i, x; @@ -2720,9 +2720,9 @@ struct pmu_private { }; static LIST_HEAD(all_pmu_pvt); -static DEFINE_SPINLOCK(all_pvt_lock __pmacdata); +static DEFINE_SPINLOCK(all_pvt_lock); -static void __pmac +static void pmu_pass_intr(unsigned char *data, int len) { struct pmu_private *pp; @@ -2751,7 +2751,7 @@ pmu_pass_intr(unsigned char *data, int len) spin_unlock_irqrestore(&all_pvt_lock, flags); } -static int __pmac +static int pmu_open(struct inode *inode, struct file *file) { struct pmu_private *pp; @@ -2773,7 +2773,7 @@ pmu_open(struct inode *inode, struct file *file) return 0; } -static ssize_t __pmac +static ssize_t pmu_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -2825,14 +2825,14 @@ pmu_read(struct file *file, char __user *buf, return ret; } -static ssize_t __pmac +static ssize_t pmu_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { return 0; } -static unsigned int __pmac +static unsigned int pmu_fpoll(struct file *filp, poll_table *wait) { struct pmu_private *pp = filp->private_data; @@ -2849,7 +2849,7 @@ pmu_fpoll(struct file *filp, poll_table *wait) return mask; } -static int __pmac +static int pmu_release(struct inode *inode, struct file *file) { struct pmu_private *pp = file->private_data; @@ -2874,8 +2874,7 @@ pmu_release(struct inode *inode, struct file *file) return 0; } -/* Note: removed __openfirmware here since it causes link errors */ -static int __pmac +static int pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { @@ -2957,7 +2956,7 @@ pmu_ioctl(struct inode * inode, struct file *filp, return error; } -static struct file_operations pmu_device_fops __pmacdata = { +static struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, @@ -2966,7 +2965,7 @@ static struct file_operations pmu_device_fops __pmacdata = { .release = pmu_release, }; -static struct miscdevice pmu_device __pmacdata = { +static struct miscdevice pmu_device = { PMU_MINOR, "pmu", &pmu_device_fops }; @@ -2982,7 +2981,7 @@ device_initcall(pmu_device_init); #ifdef DEBUG_SLEEP -static inline void __pmac +static inline void polled_handshake(volatile unsigned char __iomem *via) { via[B] &= ~TREQ; eieio(); @@ -2993,7 +2992,7 @@ polled_handshake(volatile unsigned char __iomem *via) ; } -static inline void __pmac +static inline void polled_send_byte(volatile unsigned char __iomem *via, int x) { via[ACR] |= SR_OUT | SR_EXT; eieio(); @@ -3001,7 +3000,7 @@ polled_send_byte(volatile unsigned char __iomem *via, int x) polled_handshake(via); } -static inline int __pmac +static inline int polled_recv_byte(volatile unsigned char __iomem *via) { int x; @@ -3013,7 +3012,7 @@ polled_recv_byte(volatile unsigned char __iomem *via) return x; } -int __pmac +int pmu_polled_request(struct adb_request *req) { unsigned long flags; diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 820dc52e30bc..6f80d76ac17c 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -835,7 +835,7 @@ static struct pci_save { } *pbook_pci_saves; static int n_pbook_pci_saves; -static inline void __openfirmware +static inline void pbook_pci_save(void) { int npci; @@ -863,7 +863,7 @@ pbook_pci_save(void) } } -static inline void __openfirmware +static inline void pbook_pci_restore(void) { u16 cmd; @@ -902,7 +902,7 @@ pbook_pci_restore(void) #define IRQ_ENABLE ((unsigned int *)0xf3000024) #define MEM_CTRL ((unsigned int *)0xf8000070) -int __openfirmware powerbook_sleep(void) +int powerbook_sleep(void) { int ret, i, x; static int save_backlight; @@ -1001,25 +1001,24 @@ int __openfirmware powerbook_sleep(void) /* * Support for /dev/pmu device */ -static int __openfirmware pmu_open(struct inode *inode, struct file *file) +static int pmu_open(struct inode *inode, struct file *file) { return 0; } -static ssize_t __openfirmware pmu_read(struct file *file, char *buf, +static ssize_t pmu_read(struct file *file, char *buf, size_t count, loff_t *ppos) { return 0; } -static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, +static ssize_t pmu_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { return 0; } -/* Note: removed __openfirmware here since it causes link errors */ -static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp, +static int pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { int error; From 6c45ab992e4299c869fb26427944a8f8ea177024 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 17 Sep 2005 10:38:23 -0500 Subject: [PATCH 0063/1939] [PATCH] powerpc: Remove section free() and linker script bits Here is a new patch that removes all notion of the pmac, prep, chrp and openfirmware initialization sections, and then unifies the sections.h files without those __pmac, etc, sections identifiers cluttering things up. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/vmlinux.lds.S | 26 -------------------------- arch/ppc/mm/init.c | 12 ------------ 2 files changed, 38 deletions(-) diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 17d2db7e537d..09c6525cfa61 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -149,32 +149,6 @@ SECTIONS . = ALIGN(4096); _sextratext = .; - __pmac_begin = .; - .pmac.text : { *(.pmac.text) } - .pmac.data : { *(.pmac.data) } - . = ALIGN(4096); - __pmac_end = .; - - . = ALIGN(4096); - __prep_begin = .; - .prep.text : { *(.prep.text) } - .prep.data : { *(.prep.data) } - . = ALIGN(4096); - __prep_end = .; - - . = ALIGN(4096); - __chrp_begin = .; - .chrp.text : { *(.chrp.text) } - .chrp.data : { *(.chrp.data) } - . = ALIGN(4096); - __chrp_end = .; - - . = ALIGN(4096); - __openfirmware_begin = .; - .openfirmware.text : { *(.openfirmware.text) } - .openfirmware.data : { *(.openfirmware.data) } - . = ALIGN(4096); - __openfirmware_end = .; _eextratext = .; __bss_start = .; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index f421a4b337f6..5e9ef23b4671 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -74,10 +74,6 @@ unsigned long agp_special_page; extern char _end[]; extern char etext[], _stext[]; extern char __init_begin, __init_end; -extern char __prep_begin, __prep_end; -extern char __chrp_begin, __chrp_end; -extern char __pmac_begin, __pmac_end; -extern char __openfirmware_begin, __openfirmware_end; #ifdef CONFIG_HIGHMEM pte_t *kmap_pte; @@ -167,14 +163,6 @@ void free_initmem(void) printk ("Freeing unused kernel memory:"); FREESEC(init); - if (_machine != _MACH_Pmac) - FREESEC(pmac); - if (_machine != _MACH_chrp) - FREESEC(chrp); - if (_machine != _MACH_prep) - FREESEC(prep); - if (!have_of) - FREESEC(openfirmware); printk("\n"); ppc_md.progress = NULL; #undef FREESEC From fbcd54b1e67ffa27f2b2ce087ee300138828d730 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 17 Sep 2005 10:39:46 -0500 Subject: [PATCH 0064/1939] [PATCH] powerpc: Merge simplified sections.h into asm-powerpc Here is a new patch that removes all notion of the pmac, prep, chrp and openfirmware initialization sections, and then unifies the sections.h files without those __pmac, etc, sections identifiers cluttering things up. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/sections.h | 21 ++++-------- include/asm-ppc/sections.h | 33 ------------------- 2 files changed, 6 insertions(+), 48 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/sections.h (51%) delete mode 100644 include/asm-ppc/sections.h diff --git a/include/asm-ppc64/sections.h b/include/asm-powerpc/sections.h similarity index 51% rename from include/asm-ppc64/sections.h rename to include/asm-powerpc/sections.h index 308ca6f5ced2..47be2ac2a925 100644 --- a/include/asm-ppc64/sections.h +++ b/include/asm-powerpc/sections.h @@ -1,22 +1,11 @@ -#ifndef _PPC64_SECTIONS_H -#define _PPC64_SECTIONS_H - -extern char _end[]; +#ifndef _ASM_POWERPC_SECTIONS_H +#define _ASM_POWERPC_SECTIONS_H #include -#define __pmac -#define __pmacdata - -#define __prep -#define __prepdata - -#define __chrp -#define __chrpdata - -#define __openfirmware -#define __openfirmwaredata +#ifdef __powerpc64__ +extern char _end[]; static inline int in_kernel_text(unsigned long addr) { @@ -27,3 +16,5 @@ static inline int in_kernel_text(unsigned long addr) } #endif + +#endif /* _ASM_POWERPC_SECTIONS_H */ diff --git a/include/asm-ppc/sections.h b/include/asm-ppc/sections.h deleted file mode 100644 index ba8f43ac9bf3..000000000000 --- a/include/asm-ppc/sections.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _PPC_SECTIONS_H -#define _PPC_SECTIONS_H - -#include - -#define __pmac __attribute__ ((__section__ (".pmac.text"))) -#define __pmacdata __attribute__ ((__section__ (".pmac.data"))) -#define __pmacfunc(__argpmac) \ - __argpmac __pmac; \ - __argpmac - -#define __prep __attribute__ ((__section__ (".prep.text"))) -#define __prepdata __attribute__ ((__section__ (".prep.data"))) -#define __prepfunc(__argprep) \ - __argprep __prep; \ - __argprep - -#define __chrp __attribute__ ((__section__ (".chrp.text"))) -#define __chrpdata __attribute__ ((__section__ (".chrp.data"))) -#define __chrpfunc(__argchrp) \ - __argchrp __chrp; \ - __argchrp - -/* this is actually just common chrp/pmac code, not OF code -- Cort */ -#define __openfirmware __attribute__ ((__section__ (".openfirmware.text"))) -#define __openfirmwaredata __attribute__ ((__section__ (".openfirmware.data"))) -#define __openfirmwarefunc(__argopenfirmware) \ - __argopenfirmware __openfirmware; \ - __argopenfirmware - -#endif /* _PPC_SECTIONS_H */ -#endif /* __KERNEL__ */ From df0d3cecc4bd03ea911d7c3302510984388c8a76 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sun, 18 Sep 2005 13:02:03 -0500 Subject: [PATCH 0065/1939] [PATCH] ppc32: Allow user to individual select CHRP/PMAC/PREP config Made the CHRP/PMAC/PREP config options selectable by the user. This allows us to build kernels specifically for one of the platforms thus reducing code size. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 776941c75672..96b574c0e44a 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -747,12 +747,13 @@ config CPM2 on it (826x, 827x, 8560). config PPC_CHRP + bool " Common Hardware Reference Platform (CHRP) based machines" bool depends on PPC_MULTIPLATFORM default y config PPC_PMAC - bool + bool " Apple PowerMac based machines" depends on PPC_MULTIPLATFORM default y @@ -762,6 +763,7 @@ config PPC_PMAC64 default y config PPC_PREP + bool " PowerPC Reference Platform (PREP) based machines" bool depends on PPC_MULTIPLATFORM default y From be379124c0a5abfbe57dab2823fe8a71ce797aee Mon Sep 17 00:00:00 2001 From: Khalid Aziz Date: Mon, 19 Sep 2005 15:42:36 -0700 Subject: [PATCH 0066/1939] [IA64] include EFI memory information in /proc/iomem User mode kexec tools expect to find information about physical memory in /proc/iomem (as they do on x86) to validate the addresses that the new kernel will use. Signed-off-by: Khalid Aziz Signed-off-by: Tony Luck --- arch/ia64/kernel/efi.c | 87 ++++++++++++++++++++++++++++++++++++++++ arch/ia64/kernel/setup.c | 29 ++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 1291db581721..f72ea6aebcb1 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -923,3 +923,90 @@ efi_memmap_init(unsigned long *s, unsigned long *e) *s = (u64)kern_memmap; *e = (u64)++k; } + +void +efi_initialize_iomem_resources(struct resource *code_resource, + struct resource *data_resource) +{ + struct resource *res; + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + char *name; + unsigned long flags; + + 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; + + res = NULL; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + + if (md->num_pages == 0) /* should not happen */ + continue; + + flags = IORESOURCE_MEM; + switch (md->type) { + + case EFI_MEMORY_MAPPED_IO: + case EFI_MEMORY_MAPPED_IO_PORT_SPACE: + continue; + + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_CONVENTIONAL_MEMORY: + if (md->attribute & EFI_MEMORY_WP) { + name = "System ROM"; + flags |= IORESOURCE_READONLY; + } else { + name = "System RAM"; + } + break; + + case EFI_ACPI_MEMORY_NVS: + name = "ACPI Non-volatile Storage"; + flags |= IORESOURCE_BUSY; + break; + + case EFI_UNUSABLE_MEMORY: + name = "reserved"; + flags |= IORESOURCE_BUSY | IORESOURCE_DISABLED; + break; + + case EFI_RESERVED_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_ACPI_RECLAIM_MEMORY: + default: + name = "reserved"; + flags |= IORESOURCE_BUSY; + break; + } + + if ((res = kcalloc(1, sizeof(struct resource), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "failed to alocate resource for iomem\n"); + return; + } + + res->name = name; + res->start = md->phys_addr; + res->end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; + res->flags = flags; + + if (insert_resource(&iomem_resource, res) < 0) + kfree(res); + else { + /* + * We don't know which region contains + * kernel data so we try it repeatedly and + * let the resource manager test it. + */ + insert_resource(res, code_resource); + insert_resource(res, data_resource); + } + } +} diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 1658d687b79c..83b37c410ccd 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -78,6 +78,19 @@ struct screen_info screen_info; unsigned long vga_console_iobase; unsigned long vga_console_membase; +static struct resource data_resource = { + .name = "Kernel data", + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +static struct resource code_resource = { + .name = "Kernel code", + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; +extern void efi_initialize_iomem_resources(struct resource *, + struct resource *); +extern char _text[], _edata[], _etext[]; + unsigned long ia64_max_cacheline_size; unsigned long ia64_iobase; /* virtual address for I/O accesses */ EXPORT_SYMBOL(ia64_iobase); @@ -171,6 +184,22 @@ sort_regions (struct rsvd_region *rsvd_region, int max) } } +/* + * Request address space for all standard resources + */ +static int __init register_memory(void) +{ + code_resource.start = ia64_tpa(_text); + code_resource.end = ia64_tpa(_etext) - 1; + data_resource.start = ia64_tpa(_etext); + data_resource.end = ia64_tpa(_edata) - 1; + efi_initialize_iomem_resources(&code_resource, &data_resource); + + return 0; +} + +__initcall(register_memory); + /** * reserve_memory - setup reserved memory areas * From 44c451208da397438e7062393aeb3a19ddb76a60 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 16 Sep 2005 11:43:10 -0600 Subject: [PATCH 0067/1939] [IA64] ia64: add ar.k0 usage note Update comment about how ar.k0 is used. Make the initialization the same as in start_secondary() (no functional change, just make it look more similar). Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/kernel/setup.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 1f5c26dbe705..e256b114bf4e 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -244,28 +244,31 @@ find_initrd (void) static void __init io_port_init (void) { - extern unsigned long ia64_iobase; unsigned long phys_iobase; /* - * Set `iobase' to the appropriate address in region 6 (uncached access range). + * Set `iobase' based on the EFI memory map or, failing that, the + * value firmware left in ar.k0. * - * The EFI memory map is the "preferred" location to get the I/O port space base, - * rather the relying on AR.KR0. This should become more clear in future SAL - * specs. We'll fall back to getting it out of AR.KR0 if no appropriate entry is - * found in the memory map. + * Note that in ia32 mode, IN/OUT instructions use ar.k0 to compute + * the port's virtual address, so ia32_load_state() loads it with a + * user virtual address. But in ia64 mode, glibc uses the + * *physical* address in ar.k0 to mmap the appropriate area from + * /dev/mem, and the inX()/outX() interfaces use MMIO. In both + * cases, user-mode can only use the legacy 0-64K I/O port space. + * + * ar.k0 is not involved in kernel I/O port accesses, which can use + * any of the I/O port spaces and are done via MMIO using the + * virtual mmio_base from the appropriate io_space[]. */ phys_iobase = efi_get_iobase(); - if (phys_iobase) - /* set AR.KR0 since this is all we use it for anyway */ - ia64_set_kr(IA64_KR_IO_BASE, phys_iobase); - else { + if (!phys_iobase) { phys_iobase = ia64_get_kr(IA64_KR_IO_BASE); - printk(KERN_INFO "No I/O port range found in EFI memory map, falling back " - "to AR.KR0\n"); - printk(KERN_INFO "I/O port base = 0x%lx\n", phys_iobase); + printk(KERN_INFO "No I/O port range found in EFI memory map, " + "falling back to AR.KR0 (0x%lx)\n", phys_iobase); } ia64_iobase = (unsigned long) ioremap(phys_iobase, 0); + ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); /* setup legacy IO port space */ io_space[0].mmio_base = ia64_iobase; From 650316f1228c0dc5e45c17765caef30db62468cd Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 16 Sep 2005 11:43:45 -0600 Subject: [PATCH 0068/1939] [IA64] move ACPI IOSAPIC locality domain mapping from pci.c to acpi.c Move acpi_map_iosapics() from pci.c to acpi.c, since it doesn't have anything to do with PCI. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/kernel/acpi.c | 13 +++++++++++-- arch/ia64/pci/pci.c | 23 ----------------------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 7e926471e4ec..9ad94ddf6687 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -838,7 +838,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ #ifdef CONFIG_ACPI_NUMA -acpi_status __devinit +static acpi_status __devinit acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -890,7 +890,16 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret) map_iosapic_to_node(gsi_base, node); return AE_OK; } -#endif /* CONFIG_NUMA */ + +static int __init +acpi_map_iosapics (void) +{ + acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL); + return 0; +} + +fs_initcall(acpi_map_iosapics); +#endif /* CONFIG_ACPI_NUMA */ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) { diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 9b5de589b82f..6bf48d7842c6 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -120,29 +120,6 @@ struct pci_ops pci_root_ops = { .write = pci_write, }; -#ifdef CONFIG_NUMA -extern acpi_status acpi_map_iosapic(acpi_handle, u32, void *, void **); -static void acpi_map_iosapics(void) -{ - acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL); -} -#else -static void acpi_map_iosapics(void) -{ - return; -} -#endif /* CONFIG_NUMA */ - -static int __init -pci_acpi_init (void) -{ - acpi_map_iosapics(); - - return 0; -} - -subsys_initcall(pci_acpi_init); - /* Called by ACPI when it finds a new root bus. */ static struct pci_controller * __devinit From a21ead3239c6a7a1220b45df0a7b537882afff16 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 21 Sep 2005 18:47:00 +1000 Subject: [PATCH 0069/1939] Revert "[PATCH] ppc32: Allow user to individual select CHRP/PMAC/PREP config" This reverts df0d3cecc4bd03ea911d7c3302510984388c8a76 commit. --- arch/ppc/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 96b574c0e44a..776941c75672 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -747,13 +747,12 @@ config CPM2 on it (826x, 827x, 8560). config PPC_CHRP - bool " Common Hardware Reference Platform (CHRP) based machines" bool depends on PPC_MULTIPLATFORM default y config PPC_PMAC - bool " Apple PowerMac based machines" + bool depends on PPC_MULTIPLATFORM default y @@ -763,7 +762,6 @@ config PPC_PMAC64 default y config PPC_PREP - bool " PowerPC Reference Platform (PREP) based machines" bool depends on PPC_MULTIPLATFORM default y From c707ffcf3a44914f30e5f2fd53089ad5586c9e42 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 20 Sep 2005 13:45:41 +1000 Subject: [PATCH 0070/1939] [PATCH] ppc64: Updated Olof iommu updates 1/3 Split out the implementation-specific parts of include/asm-ppc64/iommu.h to separate include files (tce.h and dart.h respectively). The generic iommu code really doesn't care about the underlying implementation, and the TCE and DART stuff is completely different. Signed-off-by: Olof Johansson Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/iSeries_iommu.c | 1 + arch/ppc64/kernel/iSeries_vio.c | 1 + arch/ppc64/kernel/pSeries_iommu.c | 1 + arch/ppc64/kernel/pSeries_vio.c | 1 + arch/ppc64/kernel/u3_iommu.c | 29 +--------------- include/asm-ppc64/dart.h | 55 +++++++++++++++++++++++++++++ include/asm-ppc64/iommu.h | 36 +------------------ include/asm-ppc64/tce.h | 57 +++++++++++++++++++++++++++++++ 8 files changed, 118 insertions(+), 63 deletions(-) create mode 100644 include/asm-ppc64/dart.h create mode 100644 include/asm-ppc64/tce.h diff --git a/arch/ppc64/kernel/iSeries_iommu.c b/arch/ppc64/kernel/iSeries_iommu.c index f8ff1bb054dc..287db32d9867 100644 --- a/arch/ppc64/kernel/iSeries_iommu.c +++ b/arch/ppc64/kernel/iSeries_iommu.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c index 6b754b0c8344..c0f7d2e9153f 100644 --- a/arch/ppc64/kernel/iSeries_vio.c +++ b/arch/ppc64/kernel/iSeries_vio.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index f0fd7fbd6531..7f7947c3e12f 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "pci.h" #define DBG(fmt...) diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c index e0ae06f58f86..866379b80c09 100644 --- a/arch/ppc64/kernel/pSeries_vio.c +++ b/arch/ppc64/kernel/pSeries_vio.c @@ -22,6 +22,7 @@ #include #include #include +#include extern struct subsystem devices_subsys; /* needed for vio_find_name() */ diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c index 41ea09cb9ac7..115cbdf3b13b 100644 --- a/arch/ppc64/kernel/u3_iommu.c +++ b/arch/ppc64/kernel/u3_iommu.c @@ -44,39 +44,12 @@ #include #include #include +#include #include "pci.h" extern int iommu_force_on; -/* physical base of DART registers */ -#define DART_BASE 0xf8033000UL - -/* Offset from base to control register */ -#define DARTCNTL 0 -/* Offset from base to exception register */ -#define DARTEXCP 0x10 -/* Offset from base to TLB tag registers */ -#define DARTTAG 0x1000 - - -/* Control Register fields */ - -/* base address of table (pfn) */ -#define DARTCNTL_BASE_MASK 0xfffff -#define DARTCNTL_BASE_SHIFT 12 - -#define DARTCNTL_FLUSHTLB 0x400 -#define DARTCNTL_ENABLE 0x200 - -/* size of table in pages */ -#define DARTCNTL_SIZE_MASK 0x1ff -#define DARTCNTL_SIZE_SHIFT 0 - -/* DART table fields */ -#define DARTMAP_VALID 0x80000000 -#define DARTMAP_RPNMASK 0x00ffffff - /* Physical base address and size of the DART table */ unsigned long dart_tablebase; /* exported to htab_initialize */ static unsigned long dart_tablesize; diff --git a/include/asm-ppc64/dart.h b/include/asm-ppc64/dart.h new file mode 100644 index 000000000000..306799a31a5d --- /dev/null +++ b/include/asm-ppc64/dart.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004 Olof Johansson , 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 + */ + +#ifndef _ASM_DART_H +#define _ASM_DART_H + + +/* physical base of DART registers */ +#define DART_BASE 0xf8033000UL + +/* Offset from base to control register */ +#define DARTCNTL 0 +/* Offset from base to exception register */ +#define DARTEXCP 0x10 +/* Offset from base to TLB tag registers */ +#define DARTTAG 0x1000 + + +/* Control Register fields */ + +/* base address of table (pfn) */ +#define DARTCNTL_BASE_MASK 0xfffff +#define DARTCNTL_BASE_SHIFT 12 + +#define DARTCNTL_FLUSHTLB 0x400 +#define DARTCNTL_ENABLE 0x200 + +/* size of table in pages */ +#define DARTCNTL_SIZE_MASK 0x1ff +#define DARTCNTL_SIZE_SHIFT 0 + + +/* DART table fields */ + +#define DARTMAP_VALID 0x80000000 +#define DARTMAP_RPNMASK 0x00ffffff + + + +#endif diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h index 72dcf8116b04..a6a173d49506 100644 --- a/include/asm-ppc64/iommu.h +++ b/include/asm-ppc64/iommu.h @@ -1,5 +1,4 @@ /* - * iommu.h * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation * Rewrite, cleanup: * Copyright (C) 2004 Olof Johansson , IBM Corporation @@ -29,44 +28,11 @@ /* * IOMAP_MAX_ORDER defines the largest contiguous block - * of dma (tce) space we can get. IOMAP_MAX_ORDER = 13 + * of dma space we can get. IOMAP_MAX_ORDER = 13 * allows up to 2**12 pages (4096 * 4096) = 16 MB */ #define IOMAP_MAX_ORDER 13 -/* - * Tces come in two formats, one for the virtual bus and a different - * format for PCI - */ -#define TCE_VB 0 -#define TCE_PCI 1 - -/* 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 -}; - - struct iommu_table { unsigned long it_busno; /* Bus number this table belongs to */ unsigned long it_size; /* Size of iommu table in entries */ diff --git a/include/asm-ppc64/tce.h b/include/asm-ppc64/tce.h new file mode 100644 index 000000000000..636504c62c88 --- /dev/null +++ b/include/asm-ppc64/tce.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * Rewrite, cleanup: + * Copyright (C) 2004 Olof Johansson , 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 + */ + +#ifndef _ASM_TCE_H +#define _ASM_TCE_H + +/* + * Tces come in two formats, one for the virtual bus and a different + * format for PCI + */ +#define TCE_VB 0 +#define TCE_PCI 1 + +/* 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 +}; + + +#endif From d0035c62d9145a2ce3057c8182a7ff0b4921a41c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 20 Sep 2005 13:46:44 +1000 Subject: [PATCH 0071/1939] [PATCH] ppc64: Updated Olof iommu updates 2/3 There are potential cases in the future where the IOMMU might be mapping smaller pages than the regular MMU is using. Keep the allocator working on MMU pagesizes, but the low-level mapping functions need to map more than one TCE entry per page to deal with this. Signed-off-by: Olof Johansson Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/pSeries_iommu.c | 25 ++++++++++++++++++++----- arch/ppc64/kernel/u3_iommu.c | 18 ++++++++++++------ include/asm-ppc64/dart.h | 4 ++++ include/asm-ppc64/tce.h | 7 +++++++ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 7f7947c3e12f..2b5e622732f4 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -60,6 +60,9 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, union tce_entry t; union tce_entry *tp; + index <<= TCE_PAGE_FACTOR; + npages <<= TCE_PAGE_FACTOR; + t.te_word = 0; t.te_rdwr = 1; // Read allowed @@ -70,11 +73,11 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, while (npages--) { /* can't move this out since we might cross LMB boundary */ - t.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; tp->te_word = t.te_word; - uaddr += PAGE_SIZE; + uaddr += TCE_PAGE_SIZE; tp++; } } @@ -85,6 +88,9 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) union tce_entry t; union tce_entry *tp; + npages <<= TCE_PAGE_FACTOR; + index <<= TCE_PAGE_FACTOR; + t.te_word = 0; tp = ((union tce_entry *)tbl->it_base) + index; @@ -104,7 +110,7 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, union tce_entry tce; tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; tce.te_rdwr = 1; if (direction != DMA_TO_DEVICE) tce.te_pciwr = 1; @@ -137,6 +143,9 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, union tce_entry tce, *tcep; long l, limit; + tcenum <<= TCE_PAGE_FACTOR; + npages <<= TCE_PAGE_FACTOR; + if (npages == 1) return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction); @@ -156,7 +165,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, } tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; + tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; tce.te_rdwr = 1; if (direction != DMA_TO_DEVICE) tce.te_pciwr = 1; @@ -167,7 +176,7 @@ 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, PAGE_SIZE/sizeof(union tce_entry)); + limit = min_t(long, npages, 4096/sizeof(union tce_entry)); for (l = 0; l < limit; l++) { tcep[l] = tce; @@ -197,6 +206,9 @@ 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--) { @@ -222,6 +234,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n 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, diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c index 115cbdf3b13b..df9c775f4955 100644 --- a/arch/ppc64/kernel/u3_iommu.c +++ b/arch/ppc64/kernel/u3_iommu.c @@ -125,18 +125,21 @@ static void dart_build(struct iommu_table *tbl, long index, DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr); + index <<= DART_PAGE_FACTOR; + npages <<= DART_PAGE_FACTOR; + dp = ((unsigned int*)tbl->it_base) + index; /* On U3, all memory is contigous, so we can move this * out of the loop. */ while (npages--) { - rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; + rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); rpn++; - uaddr += PAGE_SIZE; + uaddr += DART_PAGE_SIZE; } dart_dirty = 1; @@ -154,6 +157,9 @@ static void dart_free(struct iommu_table *tbl, long index, long npages) DBG("dart: free at: %lx, %lx\n", index, npages); + index <<= DART_PAGE_FACTOR; + npages <<= DART_PAGE_FACTOR; + dp = ((unsigned int *)tbl->it_base) + index; while (npages--) @@ -182,10 +188,10 @@ static int dart_init(struct device_node *dart_node) * that to work around what looks like a problem with the HT bridge * prefetching into invalid pages and corrupting data */ - tmp = lmb_alloc(PAGE_SIZE, PAGE_SIZE); + tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); if (!tmp) panic("U3-DART: Cannot allocate spare page!"); - dart_emptyval = DARTMAP_VALID | ((tmp >> PAGE_SHIFT) & DARTMAP_RPNMASK); + dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK); /* Map in DART registers. FIXME: Use device node to get base address */ dart = ioremap(DART_BASE, 0x7000); @@ -196,8 +202,8 @@ static int dart_init(struct device_node *dart_node) * table size and enable bit */ regword = DARTCNTL_ENABLE | - ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | - (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) + ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | + (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK) << DARTCNTL_SIZE_SHIFT); dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); diff --git a/include/asm-ppc64/dart.h b/include/asm-ppc64/dart.h index 306799a31a5d..a9000de8a2e3 100644 --- a/include/asm-ppc64/dart.h +++ b/include/asm-ppc64/dart.h @@ -51,5 +51,9 @@ #define DARTMAP_RPNMASK 0x00ffffff +#define DART_SHIFT 12 +#define DART_PAGE_SIZE (1 << DART_SHIFT) +#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_SHIFT) + #endif diff --git a/include/asm-ppc64/tce.h b/include/asm-ppc64/tce.h index 636504c62c88..d40b6b42ab35 100644 --- a/include/asm-ppc64/tce.h +++ b/include/asm-ppc64/tce.h @@ -28,6 +28,13 @@ #define TCE_VB 0 #define TCE_PCI 1 +/* TCE page size is 4096 bytes (1 << 12) */ + +#define TCE_SHIFT 12 +#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. From 637a6ff6ce525d8495df944550efea0f023dd521 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 20 Sep 2005 13:47:41 +1000 Subject: [PATCH 0072/1939] [PATCH] ppc64: Updated Olof misc updates 3/3 Replace some of the hard-coded constants with PAGE_SIZE/SHIFT/ORDER where appropriate. Likewise, in a couple of places it doesn't make sense to base some allocations on page size when all that's required is a constant 4K, etc. Signed-off-by: Olof Johansson Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/head.S | 2 +- arch/ppc64/kernel/misc.S | 2 +- arch/ppc64/kernel/vmlinux.lds.S | 16 ++++++++++------ include/asm-ppc64/elf.h | 3 ++- include/asm-ppc64/mmu.h | 2 +- include/asm-ppc64/thread_info.h | 6 +++--- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 72c61041151a..22a5ee07e1ea 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1992,7 +1992,7 @@ _GLOBAL(smp_release_cpus) */ .section ".bss" - .align 12 + .align PAGE_SHIFT .globl empty_zero_page empty_zero_page: diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index e7241ad80a08..a25b59759ddb 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -329,7 +329,7 @@ _GLOBAL(__flush_dcache_icache) /* Flush the dcache */ ld r7,PPC64_CACHES@toc(r2) - clrrdi r3,r3,12 /* Page align */ + clrrdi r3,r3,PAGE_SHIFT /* Page align */ lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ mr r6,r3 diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S index 0306510bc4ff..f34d514432ac 100644 --- a/arch/ppc64/kernel/vmlinux.lds.S +++ b/arch/ppc64/kernel/vmlinux.lds.S @@ -1,3 +1,4 @@ +#include #include OUTPUT_ARCH(powerpc:common64) @@ -17,7 +18,7 @@ SECTIONS LOCK_TEXT KPROBES_TEXT *(.fixup) - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _etext = .; } @@ -43,7 +44,7 @@ SECTIONS /* will be freed after init */ - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __init_begin = .; .init.text : { @@ -83,7 +84,7 @@ SECTIONS SECURITY_INIT - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .init.ramfs : { __initramfs_start = .; *(.init.ramfs) @@ -96,18 +97,21 @@ SECTIONS __per_cpu_end = .; } + . = ALIGN(PAGE_SIZE); . = ALIGN(16384); __init_end = .; /* freed after init ends here */ /* Read/write sections */ + . = ALIGN(PAGE_SIZE); . = ALIGN(16384); /* The initial task and kernel stack */ .data.init_task : { *(.data.init_task) } + . = ALIGN(PAGE_SIZE); .data.page_aligned : { *(.data.page_aligned) } @@ -129,18 +133,18 @@ SECTIONS __toc_start = .; *(.got) *(.toc) - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _edata = .; } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .bss : { __bss_start = .; *(.bss) __bss_stop = .; } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _end = . ; } diff --git a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h index c919a89343db..e27c2942953c 100644 --- a/include/asm-ppc64/elf.h +++ b/include/asm-ppc64/elf.h @@ -5,6 +5,7 @@ #include #include #include +#include /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 @@ -146,7 +147,7 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32]; #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH) #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE PAGE_SIZE /* This is the location that an ET_DYN program is loaded if exec'ed. Typical use of this is to invoke "./ld.so someprog" to test out a new version of diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h index 737e85a5ce3c..d2b0b796d35e 100644 --- a/include/asm-ppc64/mmu.h +++ b/include/asm-ppc64/mmu.h @@ -30,7 +30,7 @@ /* Location of cpu0's segment table */ #define STAB0_PAGE 0x6 -#define STAB0_PHYS_ADDR (STAB0_PAGE< Date: Tue, 20 Sep 2005 13:52:50 +1000 Subject: [PATCH 0073/1939] [PATCH] ppc64: Store virtual address in TLB flush batches This patch slightly change the TLB flush batch mecanism so that we store the full vaddr (including vsid) when adding an entry to the batch so that the flush part doesn't have to get to the context. This cleans it a bit, and paves the way to future updates like dynamic vsids. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/pSeries_lpar.c | 5 ++--- arch/ppc64/mm/hash_native.c | 13 +++---------- arch/ppc64/mm/hash_utils.c | 21 +++++++-------------- arch/ppc64/mm/tlb.c | 25 ++++++++++++------------- include/asm-ppc64/machdep.h | 5 ++--- include/asm-ppc64/tlbflush.h | 7 ++----- 6 files changed, 28 insertions(+), 48 deletions(-) diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index a6de83f2078f..268d8362dde7 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -486,8 +486,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie * lock. */ -void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, - int local) +void pSeries_lpar_flush_hash_range(unsigned long number, int local) { int i; unsigned long flags = 0; @@ -498,7 +497,7 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); for (i = 0; i < number; i++) - flush_hash_page(context, batch->addr[i], batch->pte[i], local); + flush_hash_page(batch->vaddr[i], batch->pte[i], local); if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index 7626bb59954d..29b074505d3e 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c @@ -335,10 +335,9 @@ static void native_hpte_clear(void) local_irq_restore(flags); } -static void native_flush_hash_range(unsigned long context, - unsigned long number, int local) +static void native_flush_hash_range(unsigned long number, int local) { - unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn; + unsigned long va, vpn, hash, secondary, slot, flags, avpn; int i, j; hpte_t *hptep; unsigned long hpte_v; @@ -351,13 +350,7 @@ static void native_flush_hash_range(unsigned long context, j = 0; for (i = 0; i < number; i++) { - if (batch->addr[i] < KERNELBASE) - vsid = get_vsid(context, batch->addr[i]); - else - vsid = get_kernel_vsid(batch->addr[i]); - - va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); - batch->vaddr[j] = va; + va = batch->vaddr[j]; if (large) vpn = va >> HPAGE_SHIFT; else diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 09475c8edf7c..36cf474b3d36 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -355,18 +355,11 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) return ret; } -void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte, - int local) +void flush_hash_page(unsigned long va, pte_t pte, int local) { - unsigned long vsid, vpn, va, hash, secondary, slot; + unsigned long vpn, hash, secondary, slot; unsigned long huge = pte_huge(pte); - if (ea < KERNELBASE) - vsid = get_vsid(context, ea); - else - vsid = get_kernel_vsid(ea); - - va = (vsid << 28) | (ea & 0x0fffffff); if (huge) vpn = va >> HPAGE_SHIFT; else @@ -381,17 +374,17 @@ void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte, ppc_md.hpte_invalidate(slot, va, huge, local); } -void flush_hash_range(unsigned long context, unsigned long number, int local) +void flush_hash_range(unsigned long number, int local) { if (ppc_md.flush_hash_range) { - ppc_md.flush_hash_range(context, number, local); + ppc_md.flush_hash_range(number, local); } else { int i; - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = + &__get_cpu_var(ppc64_tlb_batch); for (i = 0; i < number; i++) - flush_hash_page(context, batch->addr[i], batch->pte[i], - local); + flush_hash_page(batch->vaddr[i], batch->pte[i], local); } } diff --git a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c index d8a6593a13f0..31afd95bf870 100644 --- a/arch/ppc64/mm/tlb.c +++ b/arch/ppc64/mm/tlb.c @@ -128,12 +128,10 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) void hpte_update(struct mm_struct *mm, unsigned long addr, unsigned long pte, int wrprot) { - int i; - unsigned long context = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + unsigned long vsid; + int i; - if (REGION_ID(addr) == USER_REGION_ID) - context = mm->context.id; i = batch->index; /* @@ -143,17 +141,19 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, * up scanning and resetting referenced bits then our batch context * will change mid stream. */ - if (unlikely(i != 0 && context != batch->context)) { + if (unlikely(i != 0 && mm != batch->mm)) { flush_tlb_pending(); i = 0; } - - if (i == 0) { - batch->context = context; + if (i == 0) batch->mm = mm; - } + if (addr < KERNELBASE) { + vsid = get_vsid(mm->context.id, addr); + WARN_ON(vsid == 0); + } else + vsid = get_kernel_vsid(addr); + batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff); batch->pte[i] = __pte(pte); - batch->addr[i] = addr; batch->index = ++i; if (i >= PPC64_TLB_BATCH_NR) flush_tlb_pending(); @@ -175,10 +175,9 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) local = 1; if (i == 1) - flush_hash_page(batch->context, batch->addr[0], batch->pte[0], - local); + flush_hash_page(batch->vaddr[0], batch->pte[0], local); else - flush_hash_range(batch->context, i, local); + flush_hash_range(i, local); batch->index = 0; put_cpu(); } diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 8027160ec96d..d35d9d3e44cf 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -56,9 +56,8 @@ struct machdep_calls { unsigned long vflags, unsigned long rflags); long (*hpte_remove)(unsigned long hpte_group); - void (*flush_hash_range)(unsigned long context, - unsigned long number, - int local); + void (*flush_hash_range)(unsigned long number, int local); + /* special for kexec, to be called in real mode, linar mapping is * destroyed as well */ void (*hpte_clear_all)(void); diff --git a/include/asm-ppc64/tlbflush.h b/include/asm-ppc64/tlbflush.h index 45411a67e082..800bc0010cfb 100644 --- a/include/asm-ppc64/tlbflush.h +++ b/include/asm-ppc64/tlbflush.h @@ -20,10 +20,8 @@ struct mm_struct; struct ppc64_tlb_batch { unsigned long index; - unsigned long context; struct mm_struct *mm; pte_t pte[PPC64_TLB_BATCH_NR]; - unsigned long addr[PPC64_TLB_BATCH_NR]; unsigned long vaddr[PPC64_TLB_BATCH_NR]; }; DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); @@ -47,8 +45,7 @@ static inline void flush_tlb_pending(void) #define flush_tlb_kernel_range(start, end) flush_tlb_pending() #define flush_tlb_pgtables(mm, start, end) do { } while (0) -extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte, - int local); -void flush_hash_range(unsigned long context, unsigned long number, int local); +extern void flush_hash_page(unsigned long va, pte_t pte, int local); +void flush_hash_range(unsigned long number, int local); #endif /* _PPC64_TLBFLUSH_H */ From da0825fd201a03294dbf7f8f030676d608da122c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sun, 18 Sep 2005 21:33:18 -0500 Subject: [PATCH 0074/1939] [PATCH] ppc32: Allow user to individual select CHRP/PMAC/PREP config Made the CHRP/PMAC/PREP config options selectable by the user. This allows us to build kernels specifically for one of the platforms thus reducing code size. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 776941c75672..f9285210475f 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -747,12 +747,12 @@ config CPM2 on it (826x, 827x, 8560). config PPC_CHRP - bool + bool " Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM default y config PPC_PMAC - bool + bool " Apple PowerMac based machines" depends on PPC_MULTIPLATFORM default y @@ -762,7 +762,7 @@ config PPC_PMAC64 default y config PPC_PREP - bool + bool " PowerPC Reference Platform (PReP) based machines" depends on PPC_MULTIPLATFORM default y From 17b1dc07aebdef9ee43c06525bee702d5f0e9db1 Mon Sep 17 00:00:00 2001 From: "jdl@freescale.com" Date: Fri, 9 Sep 2005 16:43:52 -0500 Subject: [PATCH 0075/1939] [PATCH] powerpc: Merge asm-ppc*/posix_types.h Merge asm-ppc/posix_types.h and asm-ppc64/posix_types.h. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- .../{asm-ppc64 => asm-powerpc}/posix_types.h | 40 ++++--- include/asm-ppc/posix_types.h | 111 ------------------ 2 files changed, 25 insertions(+), 126 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/posix_types.h (88%) delete mode 100644 include/asm-ppc/posix_types.h diff --git a/include/asm-ppc64/posix_types.h b/include/asm-powerpc/posix_types.h similarity index 88% rename from include/asm-ppc64/posix_types.h rename to include/asm-powerpc/posix_types.h index 516de7201b5d..c6391077224f 100644 --- a/include/asm-ppc64/posix_types.h +++ b/include/asm-powerpc/posix_types.h @@ -1,44 +1,54 @@ -#ifndef _PPC64_POSIX_TYPES_H -#define _PPC64_POSIX_TYPES_H +#ifndef _ASM_POWERPC_POSIX_TYPES_H +#define _ASM_POWERPC_POSIX_TYPES_H /* * This file is generally used by user-level software, so you need to * be a little careful about namespace pollution etc. Also, we cannot * assume GCC is being used. - * - * 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. */ typedef unsigned long __kernel_ino_t; -typedef unsigned long __kernel_nlink_t; typedef unsigned int __kernel_mode_t; typedef long __kernel_off_t; -typedef long long __kernel_loff_t; typedef int __kernel_pid_t; -typedef int __kernel_ipc_pid_t; typedef unsigned int __kernel_uid_t; typedef unsigned int __kernel_gid_t; -typedef unsigned long __kernel_size_t; -typedef long __kernel_ssize_t; typedef long __kernel_ptrdiff_t; typedef long __kernel_time_t; +typedef long __kernel_clock_t; typedef int __kernel_timer_t; typedef int __kernel_clockid_t; typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; typedef int __kernel_daddr_t; typedef char * __kernel_caddr_t; typedef unsigned short __kernel_uid16_t; typedef unsigned short __kernel_gid16_t; typedef unsigned int __kernel_uid32_t; typedef unsigned int __kernel_gid32_t; - typedef unsigned int __kernel_old_uid_t; typedef unsigned int __kernel_old_gid_t; + +#ifdef __powerpc64__ +typedef unsigned long __kernel_nlink_t; +typedef int __kernel_ipc_pid_t; +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; typedef unsigned long __kernel_old_dev_t; +#else +typedef unsigned short __kernel_nlink_t; +typedef short __kernel_ipc_pid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef unsigned int __kernel_old_dev_t; +#endif + +#ifdef __powerpc64__ +typedef long long __kernel_loff_t; +#else +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif +#endif typedef struct { int val[2]; @@ -116,4 +126,4 @@ static __inline__ void __FD_ZERO(__kernel_fd_set *p) #endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ #endif /* __GNUC__ */ -#endif /* _PPC64_POSIX_TYPES_H */ +#endif /* _ASM_POWERPC_POSIX_TYPES_H */ diff --git a/include/asm-ppc/posix_types.h b/include/asm-ppc/posix_types.h deleted file mode 100644 index a14a82abe8d2..000000000000 --- a/include/asm-ppc/posix_types.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _PPC_POSIX_TYPES_H -#define _PPC_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned int __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned int __kernel_uid_t; -typedef unsigned int __kernel_gid_t; -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef long __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_timer_t; -typedef int __kernel_clockid_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned int __kernel_old_uid_t; -typedef unsigned int __kernel_old_gid_t; -typedef unsigned int __kernel_old_dev_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { - int val[2]; -} __kernel_fsid_t; - -#ifndef __GNUC__ - -#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) -#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) -#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) -#define __FD_ZERO(set) \ - ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set))) - -#else /* __GNUC__ */ - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \ - || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) -/* With GNU C, use inline functions instead so args are evaluated only once: */ - -#undef __FD_SET -static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] |= (1UL<<_rem); -} - -#undef __FD_CLR -static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); -} - -#undef __FD_ISSET -static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; -} - -/* - * This will unroll the loop for the normal constant case (8 ints, - * for a 256-bit fd_set) - */ -#undef __FD_ZERO -static __inline__ void __FD_ZERO(__kernel_fd_set *p) -{ - unsigned int *tmp = (unsigned int *)p->fds_bits; - int i; - - if (__builtin_constant_p(__FDSET_LONGS)) { - switch (__FDSET_LONGS) { - case 8: - tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; - tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; - return; - } - } - i = __FDSET_LONGS; - while (i) { - i--; - *tmp = 0; - tmp++; - } -} - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ -#endif /* __GNUC__ */ -#endif /* _PPC_POSIX_TYPES_H */ From 564ee7a5668e8b6d3b369fd807c75c77285c88d4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 17:33:25 +1000 Subject: [PATCH 0076/1939] [PATCH] powerpc: Move arch/ppc*/kernel/vecemu.c to arch/powerpc This file is the same in both architectures so create arch/powerpc/kernel and move it there. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/{ppc => powerpc}/kernel/vecemu.c | 0 arch/ppc/kernel/Makefile | 2 + arch/ppc64/kernel/Makefile | 3 + arch/ppc64/kernel/vecemu.c | 346 -------------------------- 4 files changed, 5 insertions(+), 346 deletions(-) rename arch/{ppc => powerpc}/kernel/vecemu.c (100%) delete mode 100644 arch/ppc64/kernel/vecemu.c diff --git a/arch/ppc/kernel/vecemu.c b/arch/powerpc/kernel/vecemu.c similarity index 100% rename from arch/ppc/kernel/vecemu.c rename to arch/powerpc/kernel/vecemu.c diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 1fb92f16acd6..abf10dcb787b 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -36,3 +36,5 @@ ifndef CONFIG_MATH_EMULATION obj-$(CONFIG_8xx) += softemu8xx.o endif +# These are here while we do the architecture merge +vecemu-y += ../../powerpc/kernel/vecemu.o diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index ae60eb1193c6..813718df4f82 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -83,3 +83,6 @@ ifeq ($(CONFIG_PPC_ISERIES),y) arch/ppc64/kernel/head.o: arch/ppc64/kernel/lparmap.s AFLAGS_head.o += -Iarch/ppc64/kernel endif + +# These are here while we do the architecture merge +vecemu-y += ../../powerpc/kernel/vecemu.o diff --git a/arch/ppc64/kernel/vecemu.c b/arch/ppc64/kernel/vecemu.c deleted file mode 100644 index cb207629f21f..000000000000 --- a/arch/ppc64/kernel/vecemu.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Routines to emulate some Altivec/VMX instructions, specifically - * those that can trap when given denormalized operands in Java mode. - */ -#include -#include -#include -#include -#include -#include - -/* Functions in vector.S */ -extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b); -extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b); -extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); -extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); -extern void vrefp(vector128 *dst, vector128 *src); -extern void vrsqrtefp(vector128 *dst, vector128 *src); -extern void vexptep(vector128 *dst, vector128 *src); - -static unsigned int exp2s[8] = { - 0x800000, - 0x8b95c2, - 0x9837f0, - 0xa5fed7, - 0xb504f3, - 0xc5672a, - 0xd744fd, - 0xeac0c7 -}; - -/* - * Computes an estimate of 2^x. The `s' argument is the 32-bit - * single-precision floating-point representation of x. - */ -static unsigned int eexp2(unsigned int s) -{ - int exp, pwr; - unsigned int mant, frac; - - /* extract exponent field from input */ - exp = ((s >> 23) & 0xff) - 127; - if (exp > 7) { - /* check for NaN input */ - if (exp == 128 && (s & 0x7fffff) != 0) - return s | 0x400000; /* return QNaN */ - /* 2^-big = 0, 2^+big = +Inf */ - return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */ - } - if (exp < -23) - return 0x3f800000; /* 1.0 */ - - /* convert to fixed point integer in 9.23 representation */ - pwr = (s & 0x7fffff) | 0x800000; - if (exp > 0) - pwr <<= exp; - else - pwr >>= -exp; - if (s & 0x80000000) - pwr = -pwr; - - /* extract integer part, which becomes exponent part of result */ - exp = (pwr >> 23) + 126; - if (exp >= 254) - return 0x7f800000; - if (exp < -23) - return 0; - - /* table lookup on top 3 bits of fraction to get mantissa */ - mant = exp2s[(pwr >> 20) & 7]; - - /* linear interpolation using remaining 20 bits of fraction */ - asm("mulhwu %0,%1,%2" : "=r" (frac) - : "r" (pwr << 12), "r" (0x172b83ff)); - asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant)); - mant += frac; - - if (exp >= 0) - return mant + (exp << 23); - - /* denormalized result */ - exp = -exp; - mant += 1 << (exp - 1); - return mant >> exp; -} - -/* - * Computes an estimate of log_2(x). The `s' argument is the 32-bit - * single-precision floating-point representation of x. - */ -static unsigned int elog2(unsigned int s) -{ - int exp, mant, lz, frac; - - exp = s & 0x7f800000; - mant = s & 0x7fffff; - if (exp == 0x7f800000) { /* Inf or NaN */ - if (mant != 0) - s |= 0x400000; /* turn NaN into QNaN */ - return s; - } - if ((exp | mant) == 0) /* +0 or -0 */ - return 0xff800000; /* return -Inf */ - - if (exp == 0) { - /* denormalized */ - asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant)); - mant <<= lz - 8; - exp = (-118 - lz) << 23; - } else { - mant |= 0x800000; - exp -= 127 << 23; - } - - if (mant >= 0xb504f3) { /* 2^0.5 * 2^23 */ - exp |= 0x400000; /* 0.5 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xb504f334)); /* 2^-0.5 * 2^32 */ - } - if (mant >= 0x9837f0) { /* 2^0.25 * 2^23 */ - exp |= 0x200000; /* 0.25 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xd744fccb)); /* 2^-0.25 * 2^32 */ - } - if (mant >= 0x8b95c2) { /* 2^0.125 * 2^23 */ - exp |= 0x100000; /* 0.125 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xeac0c6e8)); /* 2^-0.125 * 2^32 */ - } - if (mant > 0x800000) { /* 1.0 * 2^23 */ - /* calculate (mant - 1) * 1.381097463 */ - /* 1.381097463 == 0.125 / (2^0.125 - 1) */ - asm("mulhwu %0,%1,%2" : "=r" (frac) - : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a)); - exp += frac; - } - s = exp & 0x80000000; - if (exp != 0) { - if (s) - exp = -exp; - asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp)); - lz = 8 - lz; - if (lz > 0) - exp >>= lz; - else if (lz < 0) - exp <<= -lz; - s += ((lz + 126) << 23) + exp; - } - return s; -} - -#define VSCR_SAT 1 - -static int ctsxs(unsigned int x, int scale, unsigned int *vscrp) -{ - int exp, mant; - - exp = (x >> 23) & 0xff; - mant = x & 0x7fffff; - if (exp == 255 && mant != 0) - return 0; /* NaN -> 0 */ - exp = exp - 127 + scale; - if (exp < 0) - return 0; /* round towards zero */ - if (exp >= 31) { - /* saturate, unless the result would be -2^31 */ - if (x + (scale << 23) != 0xcf000000) - *vscrp |= VSCR_SAT; - return (x & 0x80000000)? 0x80000000: 0x7fffffff; - } - mant |= 0x800000; - mant = (mant << 7) >> (30 - exp); - return (x & 0x80000000)? -mant: mant; -} - -static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp) -{ - int exp; - unsigned int mant; - - exp = (x >> 23) & 0xff; - mant = x & 0x7fffff; - if (exp == 255 && mant != 0) - return 0; /* NaN -> 0 */ - exp = exp - 127 + scale; - if (exp < 0) - return 0; /* round towards zero */ - if (x & 0x80000000) { - /* negative => saturate to 0 */ - *vscrp |= VSCR_SAT; - return 0; - } - if (exp >= 32) { - /* saturate */ - *vscrp |= VSCR_SAT; - return 0xffffffff; - } - mant |= 0x800000; - mant = (mant << 8) >> (31 - exp); - return mant; -} - -/* Round to floating integer, towards 0 */ -static unsigned int rfiz(unsigned int x) -{ - int exp; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if (exp < 0) - return x & 0x80000000; /* |x| < 1.0 rounds to 0 */ - return x & ~(0x7fffff >> exp); -} - -/* Round to floating integer, towards +/- Inf */ -static unsigned int rfii(unsigned int x) -{ - int exp, mask; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if ((x & 0x7fffffff) == 0) - return x; /* +/-0 -> +/-0 */ - if (exp < 0) - /* 0 < |x| < 1.0 rounds to +/- 1.0 */ - return (x & 0x80000000) | 0x3f800000; - mask = 0x7fffff >> exp; - /* mantissa overflows into exponent - that's OK, - it can't overflow into the sign bit */ - return (x + mask) & ~mask; -} - -/* Round to floating integer, to nearest */ -static unsigned int rfin(unsigned int x) -{ - int exp, half; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if (exp < -1) - return x & 0x80000000; /* |x| < 0.5 -> +/-0 */ - if (exp == -1) - /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */ - return (x & 0x80000000) | 0x3f800000; - half = 0x400000 >> exp; - /* add 0.5 to the magnitude and chop off the fraction bits */ - return (x + half) & ~(0x7fffff >> exp); -} - -int -emulate_altivec(struct pt_regs *regs) -{ - unsigned int instr, i; - unsigned int va, vb, vc, vd; - vector128 *vrs; - - if (get_user(instr, (unsigned int __user *) regs->nip)) - return -EFAULT; - if ((instr >> 26) != 4) - return -EINVAL; /* not an altivec instruction */ - vd = (instr >> 21) & 0x1f; - va = (instr >> 16) & 0x1f; - vb = (instr >> 11) & 0x1f; - vc = (instr >> 6) & 0x1f; - - vrs = current->thread.vr; - switch (instr & 0x3f) { - case 10: - switch (vc) { - case 0: /* vaddfp */ - vaddfp(&vrs[vd], &vrs[va], &vrs[vb]); - break; - case 1: /* vsubfp */ - vsubfp(&vrs[vd], &vrs[va], &vrs[vb]); - break; - case 4: /* vrefp */ - vrefp(&vrs[vd], &vrs[vb]); - break; - case 5: /* vrsqrtefp */ - vrsqrtefp(&vrs[vd], &vrs[vb]); - break; - case 6: /* vexptefp */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = eexp2(vrs[vb].u[i]); - break; - case 7: /* vlogefp */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = elog2(vrs[vb].u[i]); - break; - case 8: /* vrfin */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = rfin(vrs[vb].u[i]); - break; - case 9: /* vrfiz */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = rfiz(vrs[vb].u[i]); - break; - case 10: /* vrfip */ - for (i = 0; i < 4; ++i) { - u32 x = vrs[vb].u[i]; - x = (x & 0x80000000)? rfiz(x): rfii(x); - vrs[vd].u[i] = x; - } - break; - case 11: /* vrfim */ - for (i = 0; i < 4; ++i) { - u32 x = vrs[vb].u[i]; - x = (x & 0x80000000)? rfii(x): rfiz(x); - vrs[vd].u[i] = x; - } - break; - case 14: /* vctuxs */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va, - ¤t->thread.vscr.u[3]); - break; - case 15: /* vctsxs */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va, - ¤t->thread.vscr.u[3]); - break; - default: - return -EINVAL; - } - break; - case 46: /* vmaddfp */ - vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); - break; - case 47: /* vnmsubfp */ - vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); - break; - default: - return -EINVAL; - } - - return 0; -} From 5bfc82652ab913606c91d74f7337cbd94627a797 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 17:50:21 +1000 Subject: [PATCH 0077/1939] [PATCH] powerpc: Merge include/asm-ppc*/a.out.h into include/asm-powerpc Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/a.out.h | 21 ++++++++--------- include/asm-ppc/a.out.h | 26 ---------------------- 2 files changed, 9 insertions(+), 38 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/a.out.h (69%) delete mode 100644 include/asm-ppc/a.out.h diff --git a/include/asm-ppc64/a.out.h b/include/asm-powerpc/a.out.h similarity index 69% rename from include/asm-ppc64/a.out.h rename to include/asm-powerpc/a.out.h index 3871e252a6f1..c7393a977364 100644 --- a/include/asm-ppc64/a.out.h +++ b/include/asm-powerpc/a.out.h @@ -1,14 +1,5 @@ -#ifndef __PPC64_A_OUT_H__ -#define __PPC64_A_OUT_H__ - -/* - * c 2001 PPC 64 Team, 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. - */ +#ifndef _ASM_POWERPC_A_OUT_H +#define _ASM_POWERPC_A_OUT_H struct exec { @@ -27,6 +18,7 @@ struct exec #define N_SYMSIZE(a) ((a).a_syms) #ifdef __KERNEL__ +#ifdef __powerpc64__ #define STACK_TOP_USER64 TASK_SIZE_USER64 #define STACK_TOP_USER32 TASK_SIZE_USER32 @@ -34,6 +26,11 @@ struct exec #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ STACK_TOP_USER32 : STACK_TOP_USER64) +#else /* __powerpc64__ */ + +#define STACK_TOP TASK_SIZE + +#endif /* __powerpc64__ */ #endif /* __KERNEL__ */ -#endif /* __PPC64_A_OUT_H__ */ +#endif /* _ASM_POWERPC_A_OUT_H */ diff --git a/include/asm-ppc/a.out.h b/include/asm-ppc/a.out.h deleted file mode 100644 index 8979a94c4a81..000000000000 --- a/include/asm-ppc/a.out.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __PPC_A_OUT_H__ -#define __PPC_A_OUT_H__ - -/* grabbed from the intel stuff */ -#define STACK_TOP TASK_SIZE - - -struct exec -{ - unsigned long a_info; /* Use macros N_MAGIC, etc for access */ - unsigned a_text; /* length of text, in bytes */ - unsigned a_data; /* length of data, in bytes */ - unsigned a_bss; /* length of uninitialized data area for file, in bytes */ - unsigned a_syms; /* length of symbol table data in file, in bytes */ - unsigned a_entry; /* start address */ - unsigned a_trsize; /* length of relocation info for text, in bytes */ - unsigned a_drsize; /* length of relocation info for data, in bytes */ -}; - - -#define N_TRSIZE(a) ((a).a_trsize) -#define N_DRSIZE(a) ((a).a_drsize) -#define N_SYMSIZE(a) ((a).a_syms) - - -#endif From bcdd1ea350feb7ee28d4f425c312e9fdf681acfb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:13:24 +1000 Subject: [PATCH 0078/1939] [PATCH] powerpc: Move arch/ppc*/oprofile/Kconfig to arch/powerpc These files are identical. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/{ppc => powerpc}/oprofile/Kconfig | 0 arch/ppc/Kconfig | 2 +- arch/ppc64/Kconfig | 2 +- arch/ppc64/oprofile/Kconfig | 23 ----------------------- 4 files changed, 2 insertions(+), 25 deletions(-) rename arch/{ppc => powerpc}/oprofile/Kconfig (100%) delete mode 100644 arch/ppc64/oprofile/Kconfig diff --git a/arch/ppc/oprofile/Kconfig b/arch/powerpc/oprofile/Kconfig similarity index 100% rename from arch/ppc/oprofile/Kconfig rename to arch/powerpc/oprofile/Kconfig diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index f9285210475f..ed9c9727d75f 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -1368,7 +1368,7 @@ endmenu source "lib/Kconfig" -source "arch/ppc/oprofile/Kconfig" +source "arch/powerpc/oprofile/Kconfig" source "arch/ppc/Kconfig.debug" diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index c658650af429..32951bfc7f65 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -461,7 +461,7 @@ config VIOPATH depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || VETH default y -source "arch/ppc64/oprofile/Kconfig" +source "arch/powerpc/oprofile/Kconfig" source "arch/ppc64/Kconfig.debug" diff --git a/arch/ppc64/oprofile/Kconfig b/arch/ppc64/oprofile/Kconfig deleted file mode 100644 index 5ade19801b97..000000000000 --- a/arch/ppc64/oprofile/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - -config PROFILING - bool "Profiling support (EXPERIMENTAL)" - help - Say Y here to enable the extended profiling support mechanisms used - by profilers such as OProfile. - - -config OPROFILE - tristate "OProfile system profiling (EXPERIMENTAL)" - depends on PROFILING - help - OProfile is a profiling system capable of profiling the - whole system, include the kernel, kernel modules, libraries, - and applications. - - If unsure, say N. - -endmenu - From d9e5b83b120dea9f306de06f7dead55103ab2d46 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:15:51 +1000 Subject: [PATCH 0079/1939] [PATCH] Merge arch/ppc*/oprofile/Makefile into arch/powerpc/oprofile Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/oprofile/Makefile | 11 +++++++++++ arch/ppc/oprofile/Makefile | 15 +-------------- arch/ppc64/oprofile/Makefile | 10 +--------- 3 files changed, 13 insertions(+), 23 deletions(-) create mode 100644 arch/powerpc/oprofile/Makefile diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile new file mode 100644 index 000000000000..0782d0cca89c --- /dev/null +++ b/arch/powerpc/oprofile/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) common.o +oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o +oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o diff --git a/arch/ppc/oprofile/Makefile b/arch/ppc/oprofile/Makefile index e2218d32a4eb..4bf75b776c5b 100644 --- a/arch/ppc/oprofile/Makefile +++ b/arch/ppc/oprofile/Makefile @@ -1,14 +1 @@ -obj-$(CONFIG_OPROFILE) += oprofile.o - -DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ - oprof.o cpu_buffer.o buffer_sync.o \ - event_buffer.o oprofile_files.o \ - oprofilefs.o oprofile_stats.o \ - timer_int.o ) - -oprofile-y := $(DRIVER_OBJS) common.o - -ifeq ($(CONFIG_FSL_BOOKE),y) - oprofile-y += op_model_fsl_booke.o -endif - +include arch/powerpc/oprofile/Makefile diff --git a/arch/ppc64/oprofile/Makefile b/arch/ppc64/oprofile/Makefile index 162dbf06c142..4bf75b776c5b 100644 --- a/arch/ppc64/oprofile/Makefile +++ b/arch/ppc64/oprofile/Makefile @@ -1,9 +1 @@ -obj-$(CONFIG_OPROFILE) += oprofile.o - -DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ - oprof.o cpu_buffer.o buffer_sync.o \ - event_buffer.o oprofile_files.o \ - oprofilefs.o oprofile_stats.o \ - timer_int.o ) - -oprofile-y := $(DRIVER_OBJS) common.o op_model_rs64.o op_model_power4.o +include arch/powerpc/oprofile/Makefile From a3e48c10cca3287a845435dd8ca58ecbde72d847 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:18:31 +1000 Subject: [PATCH 0080/1939] [PATCH] powerpc: rename op_ppc{32,64}_model to op_powerpc_model Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/ppc/oprofile/common.c | 2 +- arch/ppc/oprofile/op_impl.h | 2 +- arch/ppc/oprofile/op_model_fsl_booke.c | 2 +- arch/ppc64/oprofile/common.c | 2 +- arch/ppc64/oprofile/op_model_power4.c | 2 +- arch/ppc64/oprofile/op_model_rs64.c | 2 +- include/asm-ppc/perfmon.h | 2 +- include/asm-ppc64/cputable.h | 4 ++-- include/asm-ppc64/oprofile_impl.h | 6 +++--- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/ppc/oprofile/common.c b/arch/ppc/oprofile/common.c index 3169c67abea7..a67d438a7144 100644 --- a/arch/ppc/oprofile/common.c +++ b/arch/ppc/oprofile/common.c @@ -25,7 +25,7 @@ #include "op_impl.h" -static struct op_ppc32_model *model; +static struct op_powerpc_model *model; static struct op_counter_config ctr[OP_MAX_COUNTER]; static struct op_system_config sys; diff --git a/arch/ppc/oprofile/op_impl.h b/arch/ppc/oprofile/op_impl.h index bc336dc971e3..297f3097d2d9 100644 --- a/arch/ppc/oprofile/op_impl.h +++ b/arch/ppc/oprofile/op_impl.h @@ -31,7 +31,7 @@ struct op_system_config { }; /* Per-arch configuration */ -struct op_ppc32_model { +struct op_powerpc_model { void (*reg_setup) (struct op_counter_config *, struct op_system_config *, int num_counters); diff --git a/arch/ppc/oprofile/op_model_fsl_booke.c b/arch/ppc/oprofile/op_model_fsl_booke.c index fc9c859358c6..8fc60f6055ab 100644 --- a/arch/ppc/oprofile/op_model_fsl_booke.c +++ b/arch/ppc/oprofile/op_model_fsl_booke.c @@ -176,7 +176,7 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs, pmc_start_ctrs(1); } -struct op_ppc32_model op_model_fsl_booke = { +struct op_powerpc_model op_model_fsl_booke = { .reg_setup = fsl_booke_reg_setup, .start = fsl_booke_start, .stop = fsl_booke_stop, diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c index e5f572710aa0..ff9361a07d39 100644 --- a/arch/ppc64/oprofile/common.c +++ b/arch/ppc64/oprofile/common.c @@ -19,7 +19,7 @@ #include #include -static struct op_ppc64_model *model; +static struct op_powerpc_model *model; static struct op_counter_config ctr[OP_MAX_COUNTER]; static struct op_system_config sys; diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c index 32b2bb5625fe..886449315847 100644 --- a/arch/ppc64/oprofile/op_model_power4.c +++ b/arch/ppc64/oprofile/op_model_power4.c @@ -300,7 +300,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, mtspr(SPRN_MMCR0, mmcr0); } -struct op_ppc64_model op_model_power4 = { +struct op_powerpc_model op_model_power4 = { .reg_setup = power4_reg_setup, .cpu_setup = power4_cpu_setup, .start = power4_start, diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c index 08c5b333f5c4..e010b85996e8 100644 --- a/arch/ppc64/oprofile/op_model_rs64.c +++ b/arch/ppc64/oprofile/op_model_rs64.c @@ -209,7 +209,7 @@ static void rs64_handle_interrupt(struct pt_regs *regs, mtspr(SPRN_MMCR0, mmcr0); } -struct op_ppc64_model op_model_rs64 = { +struct op_powerpc_model op_model_rs64 = { .reg_setup = rs64_reg_setup, .cpu_setup = rs64_cpu_setup, .start = rs64_start, diff --git a/include/asm-ppc/perfmon.h b/include/asm-ppc/perfmon.h index 5e7a89c47b5b..e9692a603cff 100644 --- a/include/asm-ppc/perfmon.h +++ b/include/asm-ppc/perfmon.h @@ -16,7 +16,7 @@ void pmc_start_ctrs(int enable); void pmc_stop_ctrs(void); void dump_pmcs(void); -extern struct op_ppc32_model op_model_fsl_booke; +extern struct op_powerpc_model op_model_fsl_booke; #endif #endif /* __PERFMON_H */ diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h index 35121408ed1c..3eef40efd082 100644 --- a/include/asm-ppc64/cputable.h +++ b/include/asm-ppc64/cputable.h @@ -36,7 +36,7 @@ * via the mkdefs mechanism. */ struct cpu_spec; -struct op_ppc64_model; +struct op_powerpc_model; typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec); @@ -65,7 +65,7 @@ struct cpu_spec { char *oprofile_cpu_type; /* Processor specific oprofile operations */ - struct op_ppc64_model *oprofile_model; + struct op_powerpc_model *oprofile_model; }; extern struct cpu_spec cpu_specs[]; diff --git a/include/asm-ppc64/oprofile_impl.h b/include/asm-ppc64/oprofile_impl.h index b04f1dfb1421..50420e715f05 100644 --- a/include/asm-ppc64/oprofile_impl.h +++ b/include/asm-ppc64/oprofile_impl.h @@ -37,7 +37,7 @@ struct op_system_config { }; /* Per-arch configuration */ -struct op_ppc64_model { +struct op_powerpc_model { void (*reg_setup) (struct op_counter_config *, struct op_system_config *, int num_counters); @@ -49,8 +49,8 @@ struct op_ppc64_model { int num_counters; }; -extern struct op_ppc64_model op_model_rs64; -extern struct op_ppc64_model op_model_power4; +extern struct op_powerpc_model op_model_rs64; +extern struct op_powerpc_model op_model_power4; static inline unsigned int ctr_read(unsigned int i) { From 654810ec899ea5f2fc2138fca1793b603d481ff4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:21:15 +1000 Subject: [PATCH 0081/1939] [PATCH] powerpc: merge oprofile headers Merge include/asm-ppc64/oprofile_ipml.h and arch/ppc/oprofile/op_impl.h into include/asm-powerpc/oprofile_ipml.h Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/ppc/oprofile/common.c | 3 +- arch/ppc/oprofile/op_impl.h | 45 ------------------- arch/ppc/oprofile/op_model_fsl_booke.c | 3 +- .../oprofile_impl.h | 18 ++++++-- 4 files changed, 17 insertions(+), 52 deletions(-) delete mode 100644 arch/ppc/oprofile/op_impl.h rename include/{asm-ppc64 => asm-powerpc}/oprofile_impl.h (88%) diff --git a/arch/ppc/oprofile/common.c b/arch/ppc/oprofile/common.c index a67d438a7144..f63bee23f20c 100644 --- a/arch/ppc/oprofile/common.c +++ b/arch/ppc/oprofile/common.c @@ -22,8 +22,7 @@ #include #include #include - -#include "op_impl.h" +#include static struct op_powerpc_model *model; diff --git a/arch/ppc/oprofile/op_impl.h b/arch/ppc/oprofile/op_impl.h deleted file mode 100644 index 297f3097d2d9..000000000000 --- a/arch/ppc/oprofile/op_impl.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2004 Anton Blanchard , IBM - * - * Based on alpha version. - * - * 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 OP_IMPL_H -#define OP_IMPL_H 1 - -#define OP_MAX_COUNTER 8 - -/* Per-counter configuration as set via oprofilefs. */ -struct op_counter_config { - unsigned long enabled; - unsigned long event; - unsigned long count; - unsigned long kernel; - unsigned long user; - unsigned long unit_mask; -}; - -/* System-wide configuration as set via oprofilefs. */ -struct op_system_config { - unsigned long enable_kernel; - unsigned long enable_user; -}; - -/* Per-arch configuration */ -struct op_powerpc_model { - void (*reg_setup) (struct op_counter_config *, - struct op_system_config *, - int num_counters); - void (*start) (struct op_counter_config *); - void (*stop) (void); - void (*handle_interrupt) (struct pt_regs *, - struct op_counter_config *); - int num_counters; -}; - -#endif /* OP_IMPL_H */ diff --git a/arch/ppc/oprofile/op_model_fsl_booke.c b/arch/ppc/oprofile/op_model_fsl_booke.c index 8fc60f6055ab..1917f8df8a8b 100644 --- a/arch/ppc/oprofile/op_model_fsl_booke.c +++ b/arch/ppc/oprofile/op_model_fsl_booke.c @@ -25,8 +25,7 @@ #include #include #include - -#include "op_impl.h" +#include static unsigned long reset_value[OP_MAX_COUNTER]; diff --git a/include/asm-ppc64/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h similarity index 88% rename from include/asm-ppc64/oprofile_impl.h rename to include/asm-powerpc/oprofile_impl.h index 50420e715f05..8013cd273ced 100644 --- a/include/asm-ppc64/oprofile_impl.h +++ b/include/asm-powerpc/oprofile_impl.h @@ -9,31 +9,39 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef OP_IMPL_H -#define OP_IMPL_H 1 +#ifndef _ASM_POWERPC_OPROFILE_IMPL_H +#define _ASM_POWERPC_OPROFILE_IMPL_H #define OP_MAX_COUNTER 8 /* Per-counter configuration as set via oprofilefs. */ struct op_counter_config { +#ifdef __powerpc64__ unsigned long valid; +#endif unsigned long enabled; unsigned long event; unsigned long count; unsigned long kernel; +#ifdef __powerpc64__ /* We dont support per counter user/kernel selection */ +#endif unsigned long user; unsigned long unit_mask; }; /* System-wide configuration as set via oprofilefs. */ struct op_system_config { +#ifdef __powerpc64__ unsigned long mmcr0; unsigned long mmcr1; unsigned long mmcra; +#endif unsigned long enable_kernel; unsigned long enable_user; +#ifdef __powerpc64__ unsigned long backtrace_spinlocks; +#endif }; /* Per-arch configuration */ @@ -41,7 +49,9 @@ struct op_powerpc_model { void (*reg_setup) (struct op_counter_config *, struct op_system_config *, int num_counters); +#ifdef __powerpc64__ void (*cpu_setup) (void *); +#endif void (*start) (struct op_counter_config *); void (*stop) (void); void (*handle_interrupt) (struct pt_regs *, @@ -49,6 +59,7 @@ struct op_powerpc_model { int num_counters; }; +#ifdef __powerpc64__ extern struct op_powerpc_model op_model_rs64; extern struct op_powerpc_model op_model_power4; @@ -107,5 +118,6 @@ static inline void ctr_write(unsigned int i, unsigned int val) break; } } +#endif /* __powerpc64__ */ -#endif +#endif /* _ASM_POWERPC_OPROFILE_IMPL_H */ From 86a5cddbd9676b129cfa2ed7a1a11759d3b2b512 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:24:08 +1000 Subject: [PATCH 0082/1939] [PATCH] powerpc: merge the rest of arch/ppc*/oprofile - merge common.c - move model specific files - remove stub Makefiles - clean up arch/ppc*/Makefile Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/{ppc64 => powerpc}/oprofile/common.c | 101 +++++++++-- .../oprofile/op_model_fsl_booke.c | 0 .../oprofile/op_model_power4.c | 0 .../oprofile/op_model_rs64.c | 0 arch/ppc/Makefile | 2 +- arch/ppc/oprofile/Makefile | 1 - arch/ppc/oprofile/common.c | 160 ------------------ arch/ppc64/Makefile | 2 +- arch/ppc64/oprofile/Makefile | 1 - 9 files changed, 87 insertions(+), 180 deletions(-) rename arch/{ppc64 => powerpc}/oprofile/common.c (56%) rename arch/{ppc => powerpc}/oprofile/op_model_fsl_booke.c (100%) rename arch/{ppc64 => powerpc}/oprofile/op_model_power4.c (100%) rename arch/{ppc64 => powerpc}/oprofile/op_model_rs64.c (100%) delete mode 100644 arch/ppc/oprofile/Makefile delete mode 100644 arch/ppc/oprofile/common.c delete mode 100644 arch/ppc64/oprofile/Makefile diff --git a/arch/ppc64/oprofile/common.c b/arch/powerpc/oprofile/common.c similarity index 56% rename from arch/ppc64/oprofile/common.c rename to arch/powerpc/oprofile/common.c index ff9361a07d39..486314a0defd 100644 --- a/arch/ppc64/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -1,5 +1,9 @@ /* + * PPC 64 oprofile support: * Copyright (C) 2004 Anton Blanchard , IBM + * PPC 32 oprofile support: (based on PPC 64 support) + * Copyright (C) Freescale Semiconductor, Inc 2004 + * Author: Andy Fleming * * Based on alpha version. * @@ -10,12 +14,19 @@ */ #include +#ifndef __powerpc64__ +#include +#endif /* ! __powerpc64__ */ #include #include #include #include #include +#ifdef __powerpc64__ #include +#else /* __powerpc64__ */ +#include +#endif /* __powerpc64__ */ #include #include @@ -24,59 +35,84 @@ static struct op_powerpc_model *model; static struct op_counter_config ctr[OP_MAX_COUNTER]; static struct op_system_config sys; +#ifndef __powerpc64__ +static char *cpu_type; +#endif /* ! __powerpc64__ */ + static void op_handle_interrupt(struct pt_regs *regs) { model->handle_interrupt(regs, ctr); } -static int op_ppc64_setup(void) +static int op_powerpc_setup(void) { +#ifdef __powerpc64__ int err; /* Grab the hardware */ err = reserve_pmc_hardware(op_handle_interrupt); if (err) return err; +#else /* __powerpc64__ */ + /* Install our interrupt handler into the existing hook. */ + if (request_perfmon_irq(&op_handle_interrupt)) + return -EBUSY; + mb(); +#endif /* __powerpc64__ */ /* Pre-compute the values to stuff in the hardware registers. */ model->reg_setup(ctr, &sys, model->num_counters); /* Configure the registers on all cpus. */ +#ifdef __powerpc64__ on_each_cpu(model->cpu_setup, NULL, 0, 1); +#else /* __powerpc64__ */ +#if 0 + /* FIXME: Make multi-cpu work */ + on_each_cpu(model->reg_setup, NULL, 0, 1); +#endif +#endif /* __powerpc64__ */ return 0; } -static void op_ppc64_shutdown(void) +static void op_powerpc_shutdown(void) { +#ifdef __powerpc64__ release_pmc_hardware(); +#else /* __powerpc64__ */ + mb(); + /* Remove our interrupt handler. We may be removing this module. */ + free_perfmon_irq(); +#endif /* __powerpc64__ */ } -static void op_ppc64_cpu_start(void *dummy) +static void op_powerpc_cpu_start(void *dummy) { model->start(ctr); } -static int op_ppc64_start(void) +static int op_powerpc_start(void) { - on_each_cpu(op_ppc64_cpu_start, NULL, 0, 1); + on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1); return 0; } -static inline void op_ppc64_cpu_stop(void *dummy) +static inline void op_powerpc_cpu_stop(void *dummy) { model->stop(); } -static void op_ppc64_stop(void) +static void op_powerpc_stop(void) { - on_each_cpu(op_ppc64_cpu_stop, NULL, 0, 1); + on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1); } -static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) +static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) { int i; +#ifdef __powerpc64__ /* * There is one mmcr0, mmcr1 and mmcra for setting the events for * all of the counters. @@ -84,6 +120,7 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); +#endif /* __powerpc64__ */ for (i = 0; i < model->num_counters; ++i) { struct dentry *dir; @@ -95,44 +132,72 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); +#ifdef __powerpc64__ /* * We dont support per counter user/kernel selection, but * we leave the entries because userspace expects them */ +#endif /* __powerpc64__ */ oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); + +#ifndef __powerpc64__ + /* FIXME: Not sure if this is used */ +#endif /* ! __powerpc64__ */ oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); } oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); +#ifdef __powerpc64__ oprofilefs_create_ulong(sb, root, "backtrace_spinlocks", &sys.backtrace_spinlocks); +#endif /* __powerpc64__ */ /* Default to tracing both kernel and user */ sys.enable_kernel = 1; sys.enable_user = 1; - +#ifdef __powerpc64__ /* Turn on backtracing through spinlocks by default */ sys.backtrace_spinlocks = 1; +#endif /* __powerpc64__ */ return 0; } int __init oprofile_arch_init(struct oprofile_operations *ops) { +#ifndef __powerpc64__ + int cpu_id = smp_processor_id(); + +#ifdef CONFIG_FSL_BOOKE + model = &op_model_fsl_booke; +#else + return -ENODEV; +#endif + + cpu_type = kmalloc(32, GFP_KERNEL); + if (NULL == cpu_type) + return -ENOMEM; + + sprintf(cpu_type, "ppc/%s", cur_cpu_spec[cpu_id]->cpu_name); + + model->num_counters = cur_cpu_spec[cpu_id]->num_pmcs; + + ops->cpu_type = cpu_type; +#else /* __powerpc64__ */ if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type) return -ENODEV; - model = cur_cpu_spec->oprofile_model; model->num_counters = cur_cpu_spec->num_pmcs; ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; - ops->create_files = op_ppc64_create_files; - ops->setup = op_ppc64_setup; - ops->shutdown = op_ppc64_shutdown; - ops->start = op_ppc64_start; - ops->stop = op_ppc64_stop; +#endif /* __powerpc64__ */ + ops->create_files = op_powerpc_create_files; + ops->setup = op_powerpc_setup; + ops->shutdown = op_powerpc_shutdown; + ops->start = op_powerpc_start; + ops->stop = op_powerpc_stop; printk(KERN_INFO "oprofile: using %s performance monitoring.\n", ops->cpu_type); @@ -142,4 +207,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) void oprofile_arch_exit(void) { +#ifndef __powerpc64__ + kfree(cpu_type); + cpu_type = NULL; +#endif /* ! __powerpc64__ */ } diff --git a/arch/ppc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c similarity index 100% rename from arch/ppc/oprofile/op_model_fsl_booke.c rename to arch/powerpc/oprofile/op_model_fsl_booke.c diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c similarity index 100% rename from arch/ppc64/oprofile/op_model_power4.c rename to arch/powerpc/oprofile/op_model_power4.c diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c similarity index 100% rename from arch/ppc64/oprofile/op_model_rs64.c rename to arch/powerpc/oprofile/op_model_rs64.c diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 16e2675f3270..90c750227ed9 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -71,7 +71,7 @@ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/ -drivers-$(CONFIG_OPROFILE) += arch/ppc/oprofile/ +drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm diff --git a/arch/ppc/oprofile/Makefile b/arch/ppc/oprofile/Makefile deleted file mode 100644 index 4bf75b776c5b..000000000000 --- a/arch/ppc/oprofile/Makefile +++ /dev/null @@ -1 +0,0 @@ -include arch/powerpc/oprofile/Makefile diff --git a/arch/ppc/oprofile/common.c b/arch/ppc/oprofile/common.c deleted file mode 100644 index f63bee23f20c..000000000000 --- a/arch/ppc/oprofile/common.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * PPC 32 oprofile support - * Based on PPC64 oprofile support - * Copyright (C) 2004 Anton Blanchard , IBM - * - * Copyright (C) Freescale Semiconductor, Inc 2004 - * - * Author: Andy Fleming - * - * 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 - -static struct op_powerpc_model *model; - -static struct op_counter_config ctr[OP_MAX_COUNTER]; -static struct op_system_config sys; - -static void op_handle_interrupt(struct pt_regs *regs) -{ - model->handle_interrupt(regs, ctr); -} - -static int op_ppc32_setup(void) -{ - /* Install our interrupt handler into the existing hook. */ - if(request_perfmon_irq(&op_handle_interrupt)) - return -EBUSY; - - mb(); - - /* Pre-compute the values to stuff in the hardware registers. */ - model->reg_setup(ctr, &sys, model->num_counters); - -#if 0 - /* FIXME: Make multi-cpu work */ - /* Configure the registers on all cpus. */ - on_each_cpu(model->reg_setup, NULL, 0, 1); -#endif - - return 0; -} - -static void op_ppc32_shutdown(void) -{ - mb(); - - /* Remove our interrupt handler. We may be removing this module. */ - free_perfmon_irq(); -} - -static void op_ppc32_cpu_start(void *dummy) -{ - model->start(ctr); -} - -static int op_ppc32_start(void) -{ - on_each_cpu(op_ppc32_cpu_start, NULL, 0, 1); - return 0; -} - -static inline void op_ppc32_cpu_stop(void *dummy) -{ - model->stop(); -} - -static void op_ppc32_stop(void) -{ - on_each_cpu(op_ppc32_cpu_stop, NULL, 0, 1); -} - -static int op_ppc32_create_files(struct super_block *sb, struct dentry *root) -{ - int i; - - for (i = 0; i < model->num_counters; ++i) { - struct dentry *dir; - char buf[3]; - - snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); - - /* FIXME: Not sure if this is used */ - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); - } - - oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); - - /* Default to tracing both kernel and user */ - sys.enable_kernel = 1; - sys.enable_user = 1; - - return 0; -} - -static struct oprofile_operations oprof_ppc32_ops = { - .create_files = op_ppc32_create_files, - .setup = op_ppc32_setup, - .shutdown = op_ppc32_shutdown, - .start = op_ppc32_start, - .stop = op_ppc32_stop, - .cpu_type = NULL /* To be filled in below. */ -}; - -int __init oprofile_arch_init(struct oprofile_operations *ops) -{ - char *name; - int cpu_id = smp_processor_id(); - -#ifdef CONFIG_FSL_BOOKE - model = &op_model_fsl_booke; -#else - return -ENODEV; -#endif - - name = kmalloc(32, GFP_KERNEL); - - if (NULL == name) - return -ENOMEM; - - sprintf(name, "ppc/%s", cur_cpu_spec[cpu_id]->cpu_name); - - oprof_ppc32_ops.cpu_type = name; - - model->num_counters = cur_cpu_spec[cpu_id]->num_pmcs; - - *ops = oprof_ppc32_ops; - - printk(KERN_INFO "oprofile: using %s performance monitoring.\n", - oprof_ppc32_ops.cpu_type); - - return 0; -} - -void oprofile_arch_exit(void) -{ - kfree(oprof_ppc32_ops.cpu_type); - oprof_ppc32_ops.cpu_type = NULL; -} diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 17d2c1eac3b8..a8877881bb48 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -85,7 +85,7 @@ libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ core-y += arch/ppc64/mm/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ -drivers-$(CONFIG_OPROFILE) += arch/ppc64/oprofile/ +drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ boot := arch/ppc64/boot diff --git a/arch/ppc64/oprofile/Makefile b/arch/ppc64/oprofile/Makefile deleted file mode 100644 index 4bf75b776c5b..000000000000 --- a/arch/ppc64/oprofile/Makefile +++ /dev/null @@ -1 +0,0 @@ -include arch/powerpc/oprofile/Makefile From 82cd02c16be99cba6a97d38488aee8807580a202 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 19 Sep 2005 23:28:21 +1000 Subject: [PATCH 0083/1939] [PATCH] powerpc: reduce oprofile/common.c differences Rename and slightly modify {request,free}_perfmon_irq in the ppc code. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/oprofile/common.c | 13 ------------- arch/ppc/kernel/perfmon.c | 10 +++++----- include/asm-ppc/perfmon.h | 4 ++-- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 486314a0defd..88b4118fd0c5 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -46,19 +46,12 @@ static void op_handle_interrupt(struct pt_regs *regs) static int op_powerpc_setup(void) { -#ifdef __powerpc64__ int err; /* Grab the hardware */ err = reserve_pmc_hardware(op_handle_interrupt); if (err) return err; -#else /* __powerpc64__ */ - /* Install our interrupt handler into the existing hook. */ - if (request_perfmon_irq(&op_handle_interrupt)) - return -EBUSY; - mb(); -#endif /* __powerpc64__ */ /* Pre-compute the values to stuff in the hardware registers. */ model->reg_setup(ctr, &sys, model->num_counters); @@ -78,13 +71,7 @@ static int op_powerpc_setup(void) static void op_powerpc_shutdown(void) { -#ifdef __powerpc64__ release_pmc_hardware(); -#else /* __powerpc64__ */ - mb(); - /* Remove our interrupt handler. We may be removing this module. */ - free_perfmon_irq(); -#endif /* __powerpc64__ */ } static void op_powerpc_cpu_start(void *dummy) diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c index fa1dad96b830..91e2786ea097 100644 --- a/arch/ppc/kernel/perfmon.c +++ b/arch/ppc/kernel/perfmon.c @@ -61,7 +61,7 @@ void (*perf_irq)(struct pt_regs *) = dummy_perf; /* Grab the interrupt, if it's free. * Returns 0 on success, -1 if the interrupt is taken already */ -int request_perfmon_irq(void (*handler)(struct pt_regs *)) +int reserve_pmc_hardware(void (*handler)(struct pt_regs *)) { int err = 0; @@ -71,7 +71,7 @@ int request_perfmon_irq(void (*handler)(struct pt_regs *)) perf_irq = handler; else { pr_info("perfmon irq already handled by %p\n", perf_irq); - err = -1; + err = -EBUSY; } spin_unlock(&perfmon_lock); @@ -79,7 +79,7 @@ int request_perfmon_irq(void (*handler)(struct pt_regs *)) return err; } -void free_perfmon_irq(void) +void release_pmc_hardware(void) { spin_lock(&perfmon_lock); @@ -89,5 +89,5 @@ void free_perfmon_irq(void) } EXPORT_SYMBOL(perf_irq); -EXPORT_SYMBOL(request_perfmon_irq); -EXPORT_SYMBOL(free_perfmon_irq); +EXPORT_SYMBOL(reserve_pmc_hardware); +EXPORT_SYMBOL(release_pmc_hardware); diff --git a/include/asm-ppc/perfmon.h b/include/asm-ppc/perfmon.h index e9692a603cff..2ae031594a4e 100644 --- a/include/asm-ppc/perfmon.h +++ b/include/asm-ppc/perfmon.h @@ -3,8 +3,8 @@ extern void (*perf_irq)(struct pt_regs *); -int request_perfmon_irq(void (*handler)(struct pt_regs *)); -void free_perfmon_irq(void); +int reserve_pmc_hardware(void (*handler)(struct pt_regs *)); +void release_pmc_hardware(void); #ifdef CONFIG_FSL_BOOKE void init_pmc_stop(int ctr); From c7aeffc4d38f0573b05bf5ebd2f037997ec9d075 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 19 Sep 2005 09:30:27 -0500 Subject: [PATCH 0084/1939] [PATCH] powerpc: unified signature of timer_interrupt() between ppc32/ppc64 On ppc64 timer_interrupt() returned a value that was never used. Changed the ppc64 version of timer_interrupt() to no longer return a value so that the signatures between ppc32 & ppc64 match. This will simplify future merging of arch/powerpc. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/time.c | 4 +--- include/asm-ppc64/hw_irq.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 9939c206afa4..fb4bf0ad8f32 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -319,7 +319,7 @@ unsigned long tb_last_stamp __cacheline_aligned_in_smp; * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. */ -int timer_interrupt(struct pt_regs * regs) +void timer_interrupt(struct pt_regs * regs) { int next_dec; unsigned long cur_tb; @@ -377,8 +377,6 @@ int timer_interrupt(struct pt_regs * regs) } irq_exit(); - - return 1; } /* diff --git a/include/asm-ppc64/hw_irq.h b/include/asm-ppc64/hw_irq.h index baea40e695ec..c483897b8757 100644 --- a/include/asm-ppc64/hw_irq.h +++ b/include/asm-ppc64/hw_irq.h @@ -16,7 +16,7 @@ #include #include -int timer_interrupt(struct pt_regs *); +extern void timer_interrupt(struct pt_regs *); extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); #ifdef CONFIG_PPC_ISERIES From 3e57615bb5a8b6208627049884ee441f6d05905e Mon Sep 17 00:00:00 2001 From: "linuxppc@jdl.com" Date: Mon, 19 Sep 2005 09:32:07 -0500 Subject: [PATCH 0085/1939] [PATCH] powerpc: Revised merge asm-ppc*/hardirq.h This is a revised patch to merge asm-ppc*/hardirq.h. It removes some unnecessary #includes, but then requires the addition of #include in PPC32's hw_irq.h much like ppc64 already does. Furthermore, several unnecessary #includes were removed from some ppc32 boards in order to break resulting bad #include cycles. Builds pSeries_defconfig and all ppc32 platforms except the already b0rken bseip. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/platforms/83xx/mpc834x_sys.h | 1 - arch/ppc/platforms/85xx/mpc85xx_ads_common.h | 1 - arch/ppc/platforms/85xx/stx_gp3.h | 1 - include/{asm-ppc => asm-powerpc}/hardirq.h | 15 +++-------- include/asm-ppc/hw_irq.h | 1 + include/asm-ppc64/hardirq.h | 27 -------------------- 6 files changed, 5 insertions(+), 41 deletions(-) rename include/{asm-ppc => asm-powerpc}/hardirq.h (67%) delete mode 100644 include/asm-ppc64/hardirq.h diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h index 1584cd77a9ef..58e44c042535 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.h +++ b/arch/ppc/platforms/83xx/mpc834x_sys.h @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h index 3875e839cff7..84acf6e8d45e 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h @@ -19,7 +19,6 @@ #include #include -#include #include #define BOARD_CCSRBAR ((uint)0xe0000000) diff --git a/arch/ppc/platforms/85xx/stx_gp3.h b/arch/ppc/platforms/85xx/stx_gp3.h index 7bcc6c35a417..95fdf4b0680b 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.h +++ b/arch/ppc/platforms/85xx/stx_gp3.h @@ -21,7 +21,6 @@ #include #include -#include #include #define BOARD_CCSRBAR ((uint)0xe0000000) diff --git a/include/asm-ppc/hardirq.h b/include/asm-powerpc/hardirq.h similarity index 67% rename from include/asm-ppc/hardirq.h rename to include/asm-powerpc/hardirq.h index 94f1411b1a93..2c0a31b1008d 100644 --- a/include/asm-ppc/hardirq.h +++ b/include/asm-powerpc/hardirq.h @@ -1,11 +1,5 @@ -#ifdef __KERNEL__ -#ifndef __ASM_HARDIRQ_H -#define __ASM_HARDIRQ_H - -#include -#include -#include -#include +#ifndef _ASM_POWERPC_HARDIRQ_H +#define _ASM_POWERPC_HARDIRQ_H /* The __last_jiffy_stamp field is needed to ensure that no decrementer * interrupt is lost on SMP machines. Since on most CPUs it is in the same @@ -13,7 +7,7 @@ * for uniformity. */ typedef struct { - unsigned long __softirq_pending; /* set_bit is used on this */ + unsigned int __softirq_pending; /* set_bit is used on this */ unsigned int __last_jiffy_stamp; } ____cacheline_aligned irq_cpustat_t; @@ -27,5 +21,4 @@ static inline void ack_bad_irq(int irq) BUG(); } -#endif /* __ASM_HARDIRQ_H */ -#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_HARDIRQ_H */ diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h index 51a1d7ef5253..da0fa940adb3 100644 --- a/include/asm-ppc/hw_irq.h +++ b/include/asm-ppc/hw_irq.h @@ -7,6 +7,7 @@ #include #include +#include extern void timer_interrupt(struct pt_regs *); diff --git a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h deleted file mode 100644 index 4ee72bb1fd48..000000000000 --- a/include/asm-ppc64/hardirq.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __ASM_HARDIRQ_H -#define __ASM_HARDIRQ_H - -/* - * 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 - -typedef struct { - unsigned int __softirq_pending; -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ - -static inline void ack_bad_irq(int irq) -{ - printk(KERN_CRIT "illegal vector %d received!\n", irq); - BUG(); -} - -#endif /* __ASM_HARDIRQ_H */ From 25433b123ce1a3da78ddd9b848484bca91cbb7a1 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Mon, 19 Sep 2005 17:01:54 -0500 Subject: [PATCH 0086/1939] [PATCH] powerpc: Merge bug.h ppc32/ppc64: Merge bug.h into include/asm-powerpc This patch merges bug.h into include/asm-powerpc. Changed the data structure for bug_entry such that line is always an int on both 32 and 64-bit platforms; removed casts to int from the 64-bit trap code to reflect this. Signed-off-by: Kumar Gala Signed-off-by: Becky Bruce Signed-off-by: Paul Mackerras --- arch/ppc/kernel/traps.c | 2 +- arch/ppc64/kernel/traps.c | 4 +- include/{asm-ppc64 => asm-powerpc}/bug.h | 38 ++++++++++------ include/asm-ppc/bug.h | 58 ------------------------ 4 files changed, 28 insertions(+), 74 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/bug.h (62%) delete mode 100644 include/asm-ppc/bug.h diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 961ede87be72..82e4d70e6dbb 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -575,7 +575,7 @@ extern struct bug_entry __start___bug_table[], __stop___bug_table[]; #define module_find_bug(x) NULL #endif -static struct bug_entry *find_bug(unsigned long bugaddr) +struct bug_entry *find_bug(unsigned long bugaddr) { struct bug_entry *bug; diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index 7467ae508e6e..5c4647b2c5f3 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -390,12 +390,12 @@ check_bug_trap(struct pt_regs *regs) /* this is a WARN_ON rather than BUG/BUG_ON */ printk(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, - (unsigned int)bug->line & ~BUG_WARNING_TRAP); + bug->line & ~BUG_WARNING_TRAP); show_stack(current, (void *)regs->gpr[1]); return 1; } printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", - bug->function, bug->file, (unsigned int)bug->line); + bug->function, bug->file, bug->line); return 0; } diff --git a/include/asm-ppc64/bug.h b/include/asm-powerpc/bug.h similarity index 62% rename from include/asm-ppc64/bug.h rename to include/asm-powerpc/bug.h index 160178278861..e4d028e87020 100644 --- a/include/asm-ppc64/bug.h +++ b/include/asm-powerpc/bug.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_BUG_H -#define _PPC64_BUG_H +#ifndef _ASM_POWERPC_BUG_H +#define _ASM_POWERPC_BUG_H /* * Define an illegal instr to trap on the bug. @@ -11,9 +11,21 @@ #ifndef __ASSEMBLY__ +#ifdef __powerpc64__ +#define BUG_TABLE_ENTRY(label, line, file, func) \ + ".llong " #label "\n .long " #line "\n .llong " #file ", " #func "\n" +#define TRAP_OP(ra, rb) "1: tdnei " #ra ", " #rb "\n" +#define DATA_TYPE long long +#else +#define BUG_TABLE_ENTRY(label, line, file, func) \ + ".long " #label ", " #line ", " #file ", " #func "\n" +#define TRAP_OP(ra, rb) "1: twnei " #ra ", " #rb "\n" +#define DATA_TYPE int +#endif /* __powerpc64__ */ + struct bug_entry { unsigned long bug_addr; - long line; + int line; const char *file; const char *function; }; @@ -32,28 +44,28 @@ struct bug_entry *find_bug(unsigned long bugaddr); __asm__ __volatile__( \ "1: twi 31,0,0\n" \ ".section __bug_table,\"a\"\n\t" \ - " .llong 1b,%0,%1,%2\n" \ + BUG_TABLE_ENTRY(1b,%0,%1,%2) \ ".previous" \ : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) #define BUG_ON(x) do { \ __asm__ __volatile__( \ - "1: tdnei %0,0\n" \ + TRAP_OP(%0,0) \ ".section __bug_table,\"a\"\n\t" \ - " .llong 1b,%1,%2,%3\n" \ + BUG_TABLE_ENTRY(1b,%1,%2,%3) \ ".previous" \ - : : "r" ((long long)(x)), "i" (__LINE__), \ + : : "r" ((DATA_TYPE)(x)), "i" (__LINE__), \ "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) #define WARN_ON(x) do { \ __asm__ __volatile__( \ - "1: tdnei %0,0\n" \ + TRAP_OP(%0,0) \ ".section __bug_table,\"a\"\n\t" \ - " .llong 1b,%1,%2,%3\n" \ + BUG_TABLE_ENTRY(1b,%1,%2,%3) \ ".previous" \ - : : "r" ((long long)(x)), \ + : : "r" ((DATA_TYPE)(x)), \ "i" (__LINE__ + BUG_WARNING_TRAP), \ "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) @@ -61,9 +73,9 @@ struct bug_entry *find_bug(unsigned long bugaddr); #define HAVE_ARCH_BUG #define HAVE_ARCH_BUG_ON #define HAVE_ARCH_WARN_ON -#endif -#endif +#endif /* CONFIG_BUG */ +#endif /* __ASSEMBLY __ */ #include -#endif +#endif /* _ASM_POWERPC_BUG_H */ diff --git a/include/asm-ppc/bug.h b/include/asm-ppc/bug.h deleted file mode 100644 index 8b34fd682b0d..000000000000 --- a/include/asm-ppc/bug.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _PPC_BUG_H -#define _PPC_BUG_H - -struct bug_entry { - unsigned long bug_addr; - int line; - const char *file; - const char *function; -}; - -/* - * If this bit is set in the line number it means that the trap - * is for WARN_ON rather than BUG or BUG_ON. - */ -#define BUG_WARNING_TRAP 0x1000000 - -#ifdef CONFIG_BUG -#define BUG() do { \ - __asm__ __volatile__( \ - "1: twi 31,0,0\n" \ - ".section __bug_table,\"a\"\n\t" \ - " .long 1b,%0,%1,%2\n" \ - ".previous" \ - : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ -} while (0) - -#define BUG_ON(x) do { \ - if (!__builtin_constant_p(x) || (x)) { \ - __asm__ __volatile__( \ - "1: twnei %0,0\n" \ - ".section __bug_table,\"a\"\n\t" \ - " .long 1b,%1,%2,%3\n" \ - ".previous" \ - : : "r" (x), "i" (__LINE__), "i" (__FILE__), \ - "i" (__FUNCTION__)); \ - } \ -} while (0) - -#define WARN_ON(x) do { \ - if (!__builtin_constant_p(x) || (x)) { \ - __asm__ __volatile__( \ - "1: twnei %0,0\n" \ - ".section __bug_table,\"a\"\n\t" \ - " .long 1b,%1,%2,%3\n" \ - ".previous" \ - : : "r" (x), "i" (__LINE__ + BUG_WARNING_TRAP), \ - "i" (__FILE__), "i" (__FUNCTION__)); \ - } \ -} while (0) - -#define HAVE_ARCH_BUG -#define HAVE_ARCH_BUG_ON -#define HAVE_ARCH_WARN_ON -#endif - -#include - -#endif From a99eb2ef452ce685e40a433ceb187276ba0871f4 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Mon, 19 Sep 2005 19:17:27 -0500 Subject: [PATCH 0087/1939] [PATCH] powerpc: Merge elf.h ppc/ppc64: Merge elf.h into include/asm-powerpc Merge elf.h into a single include file for 32 and 64-bit ppc platforms. This patch has been tested on 32-bit and built on 64-bit platforms. Signed-off-by: Kumar Gala Signed-off-by: Becky Bruce Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/elf.h | 97 +++++++++------ include/asm-ppc/elf.h | 151 ----------------------- 2 files changed, 62 insertions(+), 186 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/elf.h (87%) delete mode 100644 include/asm-ppc/elf.h diff --git a/include/asm-ppc64/elf.h b/include/asm-powerpc/elf.h similarity index 87% rename from include/asm-ppc64/elf.h rename to include/asm-powerpc/elf.h index e27c2942953c..36b9d5cec50c 100644 --- a/include/asm-ppc64/elf.h +++ b/include/asm-powerpc/elf.h @@ -1,5 +1,5 @@ -#ifndef __PPC64_ELF_H -#define __PPC64_ELF_H +#ifndef _ASM_POWERPC_ELF_H +#define _ASM_POWERPC_ELF_H #include #include @@ -76,7 +76,7 @@ #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ -/* Keep this the last entry. */ +/* keep this the last entry. */ #define R_PPC_NUM 95 /* @@ -91,8 +91,6 @@ #define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ #define ELF_NFPREG 33 /* includes fpscr */ -#define ELF_NVRREG32 33 /* includes vscr & vrsave stuffed together */ -#define ELF_NVRREG 34 /* includes vscr & vrsave in split vectors */ typedef unsigned long elf_greg_t64; typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; @@ -101,8 +99,21 @@ typedef unsigned int elf_greg_t32; typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG]; /* - * These are used to set parameters in the core dumps. + * ELF_ARCH, CLASS, and DATA are used to set parameters in the core dumps. */ +#ifdef __powerpc64__ +# define ELF_NVRREG32 33 /* includes vscr & vrsave stuffed together */ +# define ELF_NVRREG 34 /* includes vscr & vrsave in split vectors */ +# define ELF_GREG_TYPE elf_greg_t64 +#else +# define ELF_NEVRREG 34 /* includes acc (as 2) */ +# define ELF_NVRREG 33 /* includes vscr */ +# define ELF_GREG_TYPE elf_greg_t32 +# define ELF_ARCH EM_PPC +# define ELF_CLASS ELFCLASS32 +# define ELF_DATA ELFDATA2MSB +#endif /* __powerpc64__ */ + #ifndef ELF_ARCH # define ELF_ARCH EM_PPC64 # define ELF_CLASS ELFCLASS64 @@ -115,8 +126,9 @@ typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG]; typedef elf_greg_t32 elf_greg_t; typedef elf_gregset_t32 elf_gregset_t; # define elf_addr_t u32 -#endif +#endif /* ELF_ARCH */ +/* Floating point registers */ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; @@ -126,7 +138,9 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; * The entry with index 32 contains the vscr as the last word (offset 12) * within the quadword. This allows the vscr to be stored as either a * quadword (since it must be copied via a vector register to/from storage) - * or as a word. The entry with index 33 contains the vrsave as the first + * or as a word. + * + * 64-bit kernel notes: The entry at index 33 contains the vrsave as the first * word (offset 0) within the quadword. * * This definition of the VMX state is compatible with the current PPC32 @@ -139,7 +153,9 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; */ typedef __vector128 elf_vrreg_t; typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG]; +#ifdef __powerpc64__ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32]; +#endif /* * This is used to ensure we don't load something for the wrong architecture. @@ -159,26 +175,30 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32]; #ifdef __KERNEL__ /* Common routine for both 32-bit and 64-bit processes */ -static inline void ppc64_elf_core_copy_regs(elf_gregset_t elf_regs, +static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs, struct pt_regs *regs) { int i; - int gprs = sizeof(struct pt_regs)/sizeof(elf_greg_t64); + int gprs = sizeof(struct pt_regs)/sizeof(ELF_GREG_TYPE); if (gprs > ELF_NGREG) gprs = ELF_NGREG; for (i=0; i < gprs; i++) - elf_regs[i] = (elf_greg_t)((elf_greg_t64 *)regs)[i]; + elf_regs[i] = (elf_greg_t)((ELF_GREG_TYPE *)regs)[i]; + + memset((char *)(elf_regs) + sizeof(struct pt_regs), 0, \ + sizeof(elf_gregset_t) - sizeof(struct pt_regs)); + } -#define ELF_CORE_COPY_REGS(gregs, regs) ppc64_elf_core_copy_regs(gregs, regs); +#define ELF_CORE_COPY_REGS(gregs, regs) ppc_elf_core_copy_regs(gregs, regs); static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *elf_regs) { struct pt_regs *regs = tsk->thread.regs; if (regs) - ppc64_elf_core_copy_regs(*elf_regs, regs); + ppc_elf_core_copy_regs(*elf_regs, regs); return 1; } @@ -187,15 +207,21 @@ static inline int dump_task_regs(struct task_struct *tsk, extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) -/* XXX Should we define the XFPREGS using altivec ??? */ +#endif /* __KERNEL__ */ -#endif - -/* This yields a mask that user programs can use to figure out what +/* ELF_HWCAP yields a mask that user programs can use to figure out what instruction set this cpu supports. This could be done in userspace, but it's not easy, and we've already done it here. */ - -#define ELF_HWCAP (cur_cpu_spec->cpu_user_features) +#ifdef __powerpc64__ +# define ELF_HWCAP (cur_cpu_spec->cpu_user_features) +# define ELF_PLAT_INIT(_r, load_addr) do { \ + memset(_r->gpr, 0, sizeof(_r->gpr)); \ + _r->ctr = _r->link = _r->xer = _r->ccr = 0; \ + _r->gpr[2] = load_addr; \ +} while (0) +#else +# define ELF_HWCAP (cur_cpu_spec[0]->cpu_user_features) +#endif /* __powerpc64__ */ /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in @@ -206,14 +232,10 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); #define ELF_PLATFORM (NULL) -#define ELF_PLAT_INIT(_r, load_addr) do { \ - memset(_r->gpr, 0, sizeof(_r->gpr)); \ - _r->ctr = _r->link = _r->xer = _r->ccr = 0; \ - _r->gpr[2] = load_addr; \ -} while (0) - #ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) \ + +#ifdef __powerpc64__ +# define SET_PERSONALITY(ex, ibcs2) \ do { \ unsigned long new_flags = 0; \ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ @@ -226,7 +248,6 @@ do { \ if (personality(current->personality) != PER_LINUX32) \ set_personality(PER_LINUX); \ } while (0) - /* * An executable for which elf_read_implies_exec() returns TRUE will * have the READ_IMPLIES_EXEC personality flag set automatically. This @@ -234,19 +255,26 @@ do { \ * the 64bit ABI has never had these issues dont enable the workaround * even if we have an executable stack. */ -#define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \ +# define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \ (exec_stk != EXSTACK_DISABLE_X) : 0) +#else +# define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#endif /* __powerpc64__ */ -#endif +#endif /* __KERNEL__ */ extern int dcache_bsize; extern int icache_bsize; extern int ucache_bsize; -/* We do have an arch_setup_additional_pages for vDSO matters */ -#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +#ifdef __powerpc64__ struct linux_binprm; +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES /* vDSO has arch_setup_additional_pages */ extern int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack); +#define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b); +#else +#define VDSO_AUX_ENT(a,b) +#endif /* __powerpc64__ */ /* * The requirements here are: @@ -266,9 +294,8 @@ do { \ NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ - /* vDSO base */ \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base); \ - } while (0) + VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base) \ +} while (0) /* PowerPC64 relocations defined by the ABIs */ #define R_PPC64_NONE R_PPC_NONE @@ -385,4 +412,4 @@ do { \ /* Keep this the last entry. */ #define R_PPC64_NUM 107 -#endif /* __PPC64_ELF_H */ +#endif /* _ASM_POWERPC_ELF_H */ diff --git a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h deleted file mode 100644 index c25cc35e6ab5..000000000000 --- a/include/asm-ppc/elf.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef __PPC_ELF_H -#define __PPC_ELF_H - -/* - * ELF register definitions.. - */ -#include -#include -#include -#include - -/* PowerPC relocations defined by the ABIs */ -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 /* 32bit absolute address */ -#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ -#define R_PPC_ADDR16 3 /* 16bit absolute address */ -#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ -#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ -#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ -#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 /* PC relative 26 bit */ -#define R_PPC_REL14 11 /* PC relative 16 bit */ -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 -/* Keep this the last entry. */ -#define R_PPC_NUM 37 - -#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ -#define ELF_NFPREG 33 /* includes fpscr */ -#define ELF_NVRREG 33 /* includes vscr */ -#define ELF_NEVRREG 34 /* includes acc (as 2) */ - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_ARCH EM_PPC -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB - -/* General registers */ -typedef unsigned long elf_greg_t; -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* Floating point registers */ -typedef double elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; - -/* Altivec registers */ -typedef __vector128 elf_vrreg_t; -typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG]; - -#ifdef __KERNEL__ - -struct task_struct; - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ - -#define elf_check_arch(x) ((x)->e_machine == EM_PPC) - -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (0x08000000) - -#define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 - -#define ELF_CORE_COPY_REGS(gregs, regs) \ - memcpy((gregs), (regs), sizeof(struct pt_regs)); \ - memset((char *)(gregs) + sizeof(struct pt_regs), 0, \ - sizeof(elf_gregset_t) - sizeof(struct pt_regs)); - -#define ELF_CORE_COPY_TASK_REGS(t, elfregs) \ - ((t)->thread.regs? \ - ({ ELF_CORE_COPY_REGS((elfregs), (t)->thread.regs); 1; }): 0) - -extern int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpu); -#define ELF_CORE_COPY_FPREGS(t, fpu) dump_task_fpu((t), (fpu)) - -/* This yields a mask that user programs can use to figure out what - instruction set this cpu supports. This could be done in userspace, - but it's not easy, and we've already done it here. */ - -#define ELF_HWCAP (cur_cpu_spec[0]->cpu_user_features) - -/* This yields a string that ld.so will use to load implementation - specific libraries for optimization. This is more specific in - intent than poking at uname or /proc/cpuinfo. - - For the moment, we have only optimizations for the Intel generations, - but that could change... */ - -#define ELF_PLATFORM (NULL) - -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) - -extern int dcache_bsize; -extern int icache_bsize; -extern int ucache_bsize; - -/* - * The requirements here are: - * - keep the final alignment of sp (sp & 0xf) - * - make sure the 32-bit value at the first 16 byte aligned position of - * AUXV is greater than 16 for glibc compatibility. - * AT_IGNOREPPC is used for that. - * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, - * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. - */ -#define ARCH_DLINFO \ -do { \ - /* Handle glibc compatibility. */ \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - /* Cache size items */ \ - NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ - NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ - NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ - } while (0) - -#endif /* __KERNEL__ */ -#endif From 8b22cc010599075806b84cfe2955ab87ab07172c Mon Sep 17 00:00:00 2001 From: "linuxppc@jdl.com" Date: Tue, 20 Sep 2005 14:32:37 -0500 Subject: [PATCH 0088/1939] [PATCH] powerpc: Merge asm-ppc*/vga.h Merge asm-ppc*/vga.h Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/vga.h | 20 ++++++----- include/asm-ppc/vga.h | 46 ------------------------ 2 files changed, 12 insertions(+), 54 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/vga.h (74%) delete mode 100644 include/asm-ppc/vga.h diff --git a/include/asm-ppc64/vga.h b/include/asm-powerpc/vga.h similarity index 74% rename from include/asm-ppc64/vga.h rename to include/asm-powerpc/vga.h index c09849743f45..f8d350aabf1a 100644 --- a/include/asm-ppc64/vga.h +++ b/include/asm-powerpc/vga.h @@ -1,16 +1,14 @@ +#ifndef _ASM_POWERPC_VGA_H_ +#define _ASM_POWERPC_VGA_H_ + +#ifdef __KERNEL__ + /* * Access to VGA videoram * * (c) 1998 Martin Mares - * - * 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 _LINUX_ASM_VGA_H_ -#define _LINUX_ASM_VGA_H_ #include @@ -42,9 +40,15 @@ static inline u16 scr_readw(volatile const u16 *addr) #endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */ extern unsigned long vgacon_remap_base; + +#ifdef __powerpc64__ #define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0)) +#else +#define VGA_MAP_MEM(x) (x + vgacon_remap_base) +#endif #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) -#endif +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_VGA_H_ */ diff --git a/include/asm-ppc/vga.h b/include/asm-ppc/vga.h deleted file mode 100644 index c5864734e3e1..000000000000 --- a/include/asm-ppc/vga.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Access to VGA videoram - * - * (c) 1998 Martin Mares - */ - -#ifdef __KERNEL__ -#ifndef _LINUX_ASM_VGA_H_ -#define _LINUX_ASM_VGA_H_ - -#include - -#include - -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE) - -#define VT_BUF_HAVE_RW -/* - * These are only needed for supporting VGA or MDA text mode, which use little - * endian byte ordering. - * In other cases, we can optimize by using native byte ordering and - * has already done the right job for us. - */ - -extern inline void scr_writew(u16 val, volatile u16 *addr) -{ - st_le16(addr, val); -} - -extern inline u16 scr_readw(volatile const u16 *addr) -{ - return ld_le16(addr); -} - -#define VT_BUF_HAVE_MEMCPYW -#define scr_memcpyw memcpy - -#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */ - -extern unsigned long vgacon_remap_base; -#define VGA_MAP_MEM(x) (x + vgacon_remap_base) -#define vga_readb(x) (*(x)) -#define vga_writeb(x,y) (*(y) = (x)) - -#endif -#endif /* __KERNEL__ */ From 3f58542f476f9a77d5c59b62165e67290d7f55ed Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Sep 2005 15:45:26 -0500 Subject: [PATCH 0089/1939] [PATCH] powerpc: merge include/asm-ppc*/auxvec.h into include/asm-powerpc/auxvec.h Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/auxvec.h | 6 +++--- include/asm-ppc/auxvec.h | 14 -------------- 2 files changed, 3 insertions(+), 17 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/auxvec.h (84%) delete mode 100644 include/asm-ppc/auxvec.h diff --git a/include/asm-ppc64/auxvec.h b/include/asm-powerpc/auxvec.h similarity index 84% rename from include/asm-ppc64/auxvec.h rename to include/asm-powerpc/auxvec.h index ac6381a106e1..19a099b62cd6 100644 --- a/include/asm-ppc64/auxvec.h +++ b/include/asm-powerpc/auxvec.h @@ -1,5 +1,5 @@ -#ifndef __PPC64_AUXVEC_H -#define __PPC64_AUXVEC_H +#ifndef _ASM_POWERPC_AUXVEC_H +#define _ASM_POWERPC_AUXVEC_H /* * We need to put in some extra aux table entries to tell glibc what @@ -16,4 +16,4 @@ */ #define AT_SYSINFO_EHDR 33 -#endif /* __PPC64_AUXVEC_H */ +#endif diff --git a/include/asm-ppc/auxvec.h b/include/asm-ppc/auxvec.h deleted file mode 100644 index 172358df29c8..000000000000 --- a/include/asm-ppc/auxvec.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __PPC_AUXVEC_H -#define __PPC_AUXVEC_H - -/* - * We need to put in some extra aux table entries to tell glibc what - * the cache block size is, so it can use the dcbz instruction safely. - */ -#define AT_DCACHEBSIZE 19 -#define AT_ICACHEBSIZE 20 -#define AT_UCACHEBSIZE 21 -/* A special ignored type value for PPC, for glibc compatibility. */ -#define AT_IGNOREPPC 22 - -#endif From 8a4a10ae996b67c622b9f3f6a4dfea5de4500a11 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Sep 2005 16:33:54 -0500 Subject: [PATCH 0090/1939] [PATCH] powerpc: merge include/asm-ppc*/spinlock_types.h into include/asm-powerpc/spinlock_types.h Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- .../spinlock_types.h | 4 ++-- include/asm-ppc/spinlock_types.h | 20 ------------------- 2 files changed, 2 insertions(+), 22 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/spinlock_types.h (80%) delete mode 100644 include/asm-ppc/spinlock_types.h diff --git a/include/asm-ppc64/spinlock_types.h b/include/asm-powerpc/spinlock_types.h similarity index 80% rename from include/asm-ppc64/spinlock_types.h rename to include/asm-powerpc/spinlock_types.h index a37c8eabb9f2..74236c9f05b1 100644 --- a/include/asm-ppc64/spinlock_types.h +++ b/include/asm-powerpc/spinlock_types.h @@ -1,5 +1,5 @@ -#ifndef __ASM_SPINLOCK_TYPES_H -#define __ASM_SPINLOCK_TYPES_H +#ifndef _ASM_POWERPC_SPINLOCK_TYPES_H +#define _ASM_POWERPC_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_H # error "please don't include this file directly" diff --git a/include/asm-ppc/spinlock_types.h b/include/asm-ppc/spinlock_types.h deleted file mode 100644 index 7919ccc75b8a..000000000000 --- a/include/asm-ppc/spinlock_types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_SPINLOCK_TYPES_H -#define __ASM_SPINLOCK_TYPES_H - -#ifndef __LINUX_SPINLOCK_TYPES_H -# error "please don't include this file directly" -#endif - -typedef struct { - volatile unsigned long lock; -} raw_spinlock_t; - -#define __RAW_SPIN_LOCK_UNLOCKED { 0 } - -typedef struct { - volatile signed int lock; -} raw_rwlock_t; - -#define __RAW_RW_LOCK_UNLOCKED { 0 } - -#endif From e903c5b536895fdf69970df62c5bf49ad17e6533 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Sep 2005 16:49:51 -0500 Subject: [PATCH 0091/1939] [PATCH] powerpc: merge include/asm-ppc*/statfs.h into include/asm-powerpc/statfs.h Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/statfs.h | 19 +++++++++---------- include/asm-ppc/statfs.h | 8 -------- 2 files changed, 9 insertions(+), 18 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/statfs.h (69%) delete mode 100644 include/asm-ppc/statfs.h diff --git a/include/asm-ppc64/statfs.h b/include/asm-powerpc/statfs.h similarity index 69% rename from include/asm-ppc64/statfs.h rename to include/asm-powerpc/statfs.h index 3c985e5246a7..67024026c10d 100644 --- a/include/asm-ppc64/statfs.h +++ b/include/asm-powerpc/statfs.h @@ -1,12 +1,11 @@ -#ifndef _PPC64_STATFS_H -#define _PPC64_STATFS_H +#ifndef _ASM_POWERPC_STATFS_H +#define _ASM_POWERPC_STATFS_H -/* - * 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. - */ +/* For ppc32 we just use the generic definitions, not so simple on ppc64 */ + +#ifndef __powerpc64__ +#include +#else #ifndef __KERNEL_STRICT_NAMES #include @@ -57,5 +56,5 @@ struct compat_statfs64 { __u32 f_frsize; __u32 f_spare[5]; }; - -#endif /* _PPC64_STATFS_H */ +#endif /* ! __powerpc64__ */ +#endif diff --git a/include/asm-ppc/statfs.h b/include/asm-ppc/statfs.h deleted file mode 100644 index 807c69954a1b..000000000000 --- a/include/asm-ppc/statfs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _PPC_STATFS_H -#define _PPC_STATFS_H - -#include -#endif - - - From 99a4b232b6682a847c70d877e4a3c15e9138c8f6 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:25 -0500 Subject: [PATCH 0092/1939] [PATCH] ieee80211: Updated ipw2100 to be compatible with ieee80211_hdr changes tree 992b203395c50342f1cced415acae6177344e270 parent c59bb604a2ff4e40232ff0422e7adc44e3b007a0 author James Ketrenos 1126714006 -0500 committer James Ketrenos 1127315910 -0500 Updated ipw2100 to be compatible with ieee80211_hdr changes. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2100.c | 4 ++-- drivers/net/wireless/ipw2100.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index e5cdb5bfabc8..8dc80f806c34 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -2948,7 +2948,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) int next = txq->next; int i = 0; struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; while (!list_empty(&priv->tx_pend_list)) { /* if there isn't enough space in TBD queue, then @@ -2984,7 +2984,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) packet->index = txq->next; ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb-> + hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 2a3cdbd50168..c9e99ce15d66 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -808,7 +808,7 @@ struct ipw2100_priv { struct ipw2100_rx { union { unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; u32 status; struct ipw2100_notification notification; struct ipw2100_cmd_header command; From 3a5becf720d6346ffca2d6be6473f603b39322a2 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:37 -0500 Subject: [PATCH 0093/1939] [PATCH] ieee80211: Updated ipw2100 to be compatible with ieee80211's hard_start_xmit change tree ee48cbe413b795d6be454b9baf4f3bd3d74814cb parent 49856b147763bd6847e0d8f53aee1ddd61385638 author James Ketrenos 1126716634 -0500 committer James Ketrenos 1127316024 -0500 Updated ipw2100 to be compatible with ieee80211's hard_start_xmit change. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 8dc80f806c34..ad7f8cd76db9 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -3269,7 +3269,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data, return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev) +static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, + int pri) { struct ipw2100_priv *priv = ieee80211_priv(dev); struct list_head *element; From 0dacca1f0a53938dd7d5ba35c692bd1a3356d504 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:41 -0500 Subject: [PATCH 0094/1939] [PATCH] ieee80211: Updated ipw2200 to be compatible with ieee80211_hdr changes tree 9f86c7b4f59249c05c96c360dfaa817995e8a44f parent 9b09701b2c6254f2fddb009004a14eb5a908714f author James Ketrenos 1126714305 -0500 committer James Ketrenos 1127316074 -0500 Updated ipw2200 to be compatible with ieee80211_hdr changes. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2200.c | 9 +++++---- drivers/net/wireless/ipw2200.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 86feef732dbb..34f005229ddb 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4904,7 +4904,7 @@ static void ipw_rx(struct ipw_priv *priv) { struct ipw_rx_mem_buffer *rxb; struct ipw_rx_packet *pkt; - struct ieee80211_hdr *header; + struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; @@ -4967,8 +4967,9 @@ static void ipw_rx(struct ipw_priv *priv) #endif header = - (struct ieee80211_hdr *)(rxb->skb->data + - IPW_RX_FRAME_SIZE); + (struct ieee80211_hdr_4addr *)(rxb->skb-> + data + + IPW_RX_FRAME_SIZE); /* TODO: Check Ad-Hoc dest/source and make sure * that we are actually parsing these packets * correctly -- we should probably use the @@ -6325,7 +6326,7 @@ we need to heavily modify the ieee80211_skb_to_txb. static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) + struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 5b00882133f9..e9cf32bf3e31 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1654,12 +1654,12 @@ static const long ipw_frequencies[] = { #define IPW_MAX_CONFIG_RETRIES 10 -static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr) +static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr) { u32 retval; u16 fc; - retval = sizeof(struct ieee80211_hdr); + retval = sizeof(struct ieee80211_hdr_3addr); fc = le16_to_cpu(hdr->frame_ctl); /* From c8d42d1ae4518091a20f7212b0591a0f4b0e8ca0 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:43 -0500 Subject: [PATCH 0095/1939] [PATCH] ieee80211: Updated ipw2200 to be compatible with ieee80211's hard_start_xmit change. tree 713b6ff3311decfe42d5209f7b2508736d144b85 parent 6465beff0e89779330450dffc2a5e6dc5154eebf author James Ketrenos 1126716726 -0500 committer James Ketrenos 1127316162 -0500 Updated ipw2200 to be compatible with ieee80211's hard_start_xmit change. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 34f005229ddb..7ea9bd58f65f 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6449,7 +6449,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) } static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, - struct net_device *dev) + struct net_device *dev, int pri) { struct ipw_priv *priv = ieee80211_priv(dev); unsigned long flags; From 4ca5253d573d7b3785dbb2f123f948fdca6ee235 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:46 -0500 Subject: [PATCH 0096/1939] [PATCH] ieee80211: Updated atmel to be compatible with ieee80211_hdr changes tree d7be83000b058b14450d76f99c432b1fb2a1c177 parent 322201093e03830fceedfc24931420b1ea855a8c author James Ketrenos 1127316330 -0500 committer James Ketrenos 1127316330 -0500 Updated atmel to be compatible with ieee80211_hdr changes. Change accomplished via: sed -i -e "s:ieee80211_hdr\([^_]\):ieee80211_hdr_4addr\1:g" \ drivers/net/wireless/atmel.c Compile tested only. CC: simon@thekelleys.org.uk Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/atmel.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 587869d86eee..d57011028b72 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv); static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l static int start_tx (struct sk_buff *skb, struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; @@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, + struct ieee80211_hdr_4addr *header, u8 *body, int body_len) { u16 buff; @@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); } -static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -990,7 +990,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) return (crc ^ 0xffffffff) == netcrc; } -static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { u8 mac4[6]; @@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *heade static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -2650,7 +2650,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) { - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct auth_body auth; header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); @@ -2688,7 +2688,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct ass_req_format { u16 capability; u16 listen_interval; @@ -2738,7 +2738,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); } -static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header) +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header) { if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; @@ -2788,7 +2788,7 @@ static int retrieve_bss(struct atmel_private *priv) } -static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header, +static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3072,7 +3072,7 @@ static void atmel_smooth_qual(struct atmel_private *priv) } /* deals with incoming managment frames. */ -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi) { u16 subtype; From 20d64713ae71c0b0aa06084acbef2244021baaca Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:53:43 -0500 Subject: [PATCH 0097/1939] [PATCH] ieee80211: Fixed a kernel oops on module unload tree 367069f24fc38b4aa910e86ff40094d2078d8aa7 parent a33a1982012e9070736e3717231714dc9892303b author James Ketrenos 1124430800 -0500 committer James Ketrenos 1127310571 -0500 Fixed a kernel oops on module unload by adding spin lock protection to ieee80211's crypt handlers (thanks to Zhu Yi) Modified scan result logic to report WPA and RSN IEs if set (vs.being based on wpa_enabled) Added ieee80211_device as the first parameter to the crypt init() method. TKIP modified to use that structure for determining whether to countermeasures are active. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 + include/net/ieee80211_crypt.h | 2 +- net/ieee80211/ieee80211_crypt.c | 9 ++++---- net/ieee80211/ieee80211_crypt_ccmp.c | 2 +- net/ieee80211/ieee80211_crypt_tkip.c | 31 +++++++++++++++++++++++++--- net/ieee80211/ieee80211_crypt_wep.c | 2 +- net/ieee80211/ieee80211_rx.c | 11 ---------- net/ieee80211/ieee80211_tx.c | 14 ------------- net/ieee80211/ieee80211_wx.c | 6 +++--- 9 files changed, 40 insertions(+), 38 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 2d9c679cf6b6..ed06a9454edc 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -434,6 +434,7 @@ struct ieee80211_device; #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) #define SEC_KEY_4 (1<<3) +#define SEC_KEY_MASK (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4) #define SEC_ACTIVE_KEY (1<<4) #define SEC_AUTH_MODE (1<<5) #define SEC_UNICAST_GROUP (1<<6) diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 93bf91fda82e..e2064edb957d 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -31,7 +31,7 @@ struct ieee80211_crypto_ops { /* init new crypto context (e.g., allocate private data space, * select IV, etc.); returns NULL on failure or pointer to allocated * private data on success */ - void *(*init) (int keyidx); + void *(*init) (struct ieee80211_device * ieee, int keyidx); /* deinitialize crypto context and free allocated private data */ void (*deinit) (void *priv); diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index dc835f68edd3..0c366299db0f 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -41,7 +41,9 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) { struct list_head *ptr, *n; struct ieee80211_crypt_data *entry; + unsigned long flags; + spin_lock_irqsave(&ieee->lock, flags); for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { entry = list_entry(ptr, struct ieee80211_crypt_data, list); @@ -57,14 +59,13 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) } kfree(entry); } + spin_unlock_irqrestore(&ieee->lock, flags); } void ieee80211_crypt_deinit_handler(unsigned long data) { struct ieee80211_device *ieee = (struct ieee80211_device *)data; - unsigned long flags; - spin_lock_irqsave(&ieee->lock, flags); ieee80211_crypt_deinit_entries(ieee, 0); if (!list_empty(&ieee->crypt_deinit_list)) { printk(KERN_DEBUG "%s: entries remaining in delayed crypt " @@ -72,7 +73,6 @@ void ieee80211_crypt_deinit_handler(unsigned long data) ieee->crypt_deinit_timer.expires = jiffies + HZ; add_timer(&ieee->crypt_deinit_timer); } - spin_unlock_irqrestore(&ieee->lock, flags); } @@ -182,7 +182,8 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) return NULL; } -static void *ieee80211_crypt_null_init(int keyidx) +static void *ieee80211_crypt_null_init(struct ieee80211_device *ieee, + int keyidx) { return (void *)1; } diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 7b6290885e7d..1e6644b133dc 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -74,7 +74,7 @@ static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); } -static void *ieee80211_ccmp_init(int key_idx) +static void *ieee80211_ccmp_init(struct ieee80211_device *ieee, int key_idx) { struct ieee80211_ccmp_data *priv; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index dca380e57454..0c495f07e718 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -59,9 +59,11 @@ struct ieee80211_tkip_data { /* scratch buffers for virt_to_page() (crypto API) */ u8 rx_hdr[16], tx_hdr[16]; + + struct ieee80211_device *ieee; }; -static void *ieee80211_tkip_init(int key_idx) +static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx) { struct ieee80211_tkip_data *priv; @@ -69,6 +71,9 @@ static void *ieee80211_tkip_init(int key_idx) if (priv == NULL) goto fail; memset(priv, 0, sizeof(*priv)); + + priv->ieee = ieee; + priv->key_idx = key_idx; priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); @@ -264,11 +269,21 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) u32 crc; struct scatterlist sg; + hdr = (struct ieee80211_hdr *)skb->data; + + if (tkey->ieee->tkip_countermeasures) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "TX packet to " MAC_FMT "\n", + tkey->ieee->dev->name, MAC_ARG(hdr->addr1)); + } + return -1; + } + if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || skb->len < hdr_len) return -1; - hdr = (struct ieee80211_hdr *)skb->data; if (!tkey->tx_phase1_done) { tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, tkey->tx_iv32); @@ -325,10 +340,20 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) struct scatterlist sg; int plen; + hdr = (struct ieee80211_hdr *)skb->data; + + if (tkey->ieee->tkip_countermeasures) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "received packet from " MAC_FMT "\n", + tkey->ieee->dev->name, MAC_ARG(hdr->addr2)); + } + return -1; + } + if (skb->len < hdr_len + 8 + 4) return -1; - hdr = (struct ieee80211_hdr *)skb->data; pos = skb->data + hdr_len; keyidx = pos[3]; if (!(keyidx & (1 << 5))) { diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index ebe16155e792..63e783fa5173 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -37,7 +37,7 @@ struct prism2_wep_data { struct crypto_tfm *tfm; }; -static void *prism2_wep_init(int keyidx) +static void *prism2_wep_init(struct ieee80211_device *ieee, int keyidx) { struct prism2_wep_data *priv; diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index e0337c8fcde8..9a125d45289a 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -280,17 +280,6 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); -#ifdef CONFIG_IEEE80211_CRYPT_TKIP - if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - ieee->dev->name, MAC_ARG(hdr->addr2)); - } - return -1; - } -#endif - atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 1a09448016ed..435ef5a73d75 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -157,20 +157,6 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; int res; -#ifdef CONFIG_IEEE80211_CRYPT_TKIP - struct ieee80211_hdr *header; - - if (ieee->tkip_countermeasures && - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { - header = (struct ieee80211_hdr *)frag->data; - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - ieee->dev->name, MAC_ARG(header->addr1)); - } - return -1; - } -#endif /* To encrypt, frame format is: * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 04f0897b0653..fc4e1377aba7 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -182,7 +182,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); - if (ieee->wpa_enabled && network->wpa_ie_len) { + if (network->wpa_ie_len) { char buf[MAX_WPA_IE_LEN * 2 + 30]; u8 *p = buf; @@ -197,7 +197,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, start = iwe_stream_add_point(start, stop, &iwe, buf); } - if (ieee->wpa_enabled && network->rsn_ie_len) { + if (network->rsn_ie_len) { char buf[MAX_WPA_IE_LEN * 2 + 30]; u8 *p = buf; @@ -351,7 +351,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(key); + new_crypt->priv = new_crypt->ops->init(ieee, key); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); From f1bf6638af9e9bbbb6fb0b769054fb7db1ae652f Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:53:54 -0500 Subject: [PATCH 0098/1939] [PATCH] ieee80211: Hardware crypto and fragmentation offload support tree 5322d496af90d03ffbec27292dc1a6268a746ede parent 6c9364386ccb786e4a84427ab3ad712f0b7b8904 author James Ketrenos 1124432367 -0500 committer James Ketrenos 1127311810 -0500 Hardware crypto and fragmentation offload support added (Zhu Yi) Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 42 ++++++++++++++++------------- net/ieee80211/ieee80211_tx.c | 27 ++++++++++++++----- net/ieee80211/ieee80211_wx.c | 52 +++++++++++++++++++++--------------- 3 files changed, 74 insertions(+), 47 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index ed06a9454edc..fa14360dbc9d 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -430,31 +430,34 @@ struct ieee80211_device; #include "ieee80211_crypt.h" -#define SEC_KEY_1 (1<<0) -#define SEC_KEY_2 (1<<1) -#define SEC_KEY_3 (1<<2) -#define SEC_KEY_4 (1<<3) -#define SEC_KEY_MASK (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4) -#define SEC_ACTIVE_KEY (1<<4) -#define SEC_AUTH_MODE (1<<5) -#define SEC_UNICAST_GROUP (1<<6) -#define SEC_LEVEL (1<<7) -#define SEC_ENABLED (1<<8) +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_TGI_KEY_RESET (1<<9) -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 struct ieee80211_security { u16 active_key:2, - enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1; + enabled:1, + auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][WEP_KEY_LEN]; + u8 keys[WEP_KEYS][SCM_KEY_LEN]; u8 level; u16 flags; } __attribute__ ((packed)); @@ -636,6 +639,7 @@ enum ieee80211_state { struct ieee80211_device { struct net_device *dev; + struct ieee80211_security sec; /* Bookkeeping structures */ struct net_device_stats stats; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 435ef5a73d75..785e76f7e4e9 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; unsigned long flags; struct net_device_stats *stats = &ieee->stats; - int ether_type, encrypt; + int ether_type, encrypt, host_encrypt; int bytes, fc, hdr_len; struct sk_buff *skb_frag; struct ieee80211_hdr header = { /* Ensure zero initialized */ @@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) crypt = ieee->crypt[ieee->tx_keyidx]; encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && - ieee->host_encrypt && crypt && crypt->ops; + ieee->sec.encrypt; + host_encrypt = ieee->host_encrypt && encrypt; if (!encrypt && ieee->ieee802_1x && ieee->drop_unencrypted && ether_type != ETH_P_PAE) { @@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Determine total amount of storage required for TXB packets */ bytes = skb->len + SNAP_SIZE + sizeof(u16); - if (encrypt) + if (host_encrypt) fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_PROTECTED; else @@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) bytes_per_frag -= IEEE80211_FCS_LEN; /* Each fragment may need to have room for encryptiong pre/postfix */ - if (encrypt) + if (host_encrypt) bytes_per_frag -= crypt->ops->extra_prefix_len + crypt->ops->extra_postfix_len; @@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) for (i = 0; i < nr_frags; i++) { skb_frag = txb->fragments[i]; - if (encrypt) + if (host_encrypt) skb_reserve(skb_frag, crypt->ops->extra_prefix_len); frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); @@ -380,8 +381,22 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Encryption routine will move the header forward in order * to insert the IV between the header and the payload */ - if (encrypt) + if (host_encrypt) ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + + /* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */ + if (!ieee->host_encrypt && encrypt && + (ieee->sec.level == SEC_LEVEL_2) && + crypt && crypt->ops && crypt->ops->encrypt_msdu) { + int res = 0; + res = crypt->ops->encrypt_msdu(skb_frag, hdr_len, + crypt->priv); + if (res < 0) { + IEEE80211_ERROR("TKIP MIC encryption failed\n"); + goto failed; + } + } + if (ieee->config & (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) skb_put(skb_frag, 4); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index fc4e1377aba7..f88c8116a23c 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, }; int i, key, key_provided, len; struct ieee80211_crypt_data **crypt; + int host_crypto = ieee->host_encrypt || ieee->host_decrypt; IEEE80211_DEBUG_WX("SET_ENCODE\n"); @@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, if (i == WEP_KEYS) { sec.enabled = 0; + sec.encrypt = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL; } @@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, } sec.enabled = 1; + sec.encrypt = 1; sec.flags |= SEC_ENABLED; if (*crypt != NULL && (*crypt)->ops != NULL && @@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ieee80211_crypt_delayed_deinit(ieee, crypt); } - if (*crypt == NULL) { + if (*crypt == NULL && host_crypto) { struct ieee80211_crypt_data *new_crypt; /* take WEP into use */ @@ -375,31 +378,34 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, key, escape_essid(sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; - (*crypt)->ops->set_key(sec.keys[key], len, NULL, - (*crypt)->priv); + if (*crypt) + (*crypt)->ops->set_key(sec.keys[key], len, NULL, + (*crypt)->priv); sec.flags |= (1 << key); /* This ensures a key will be activated if no key is * explicitely set */ if (key == sec.active_key) sec.flags |= SEC_ACTIVE_KEY; - } else { - len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, - NULL, (*crypt)->priv); - if (len == 0) { - /* Set a default key of all 0 */ - IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", - key); - memset(sec.keys[key], 0, 13); - (*crypt)->ops->set_key(sec.keys[key], 13, NULL, - (*crypt)->priv); - sec.key_sizes[key] = 13; - sec.flags |= (1 << key); - } + } else { + if (host_crypto) { + len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, + NULL, (*crypt)->priv); + if (len == 0) { + /* Set a default key of all 0 */ + IEEE80211_DEBUG_WX("Setting key %d to all " + "zero.\n", key); + memset(sec.keys[key], 0, 13); + (*crypt)->ops->set_key(sec.keys[key], 13, NULL, + (*crypt)->priv); + sec.key_sizes[key] = 13; + sec.flags |= (1 << key); + } + } /* No key data - just set the default TX key index */ if (key_provided) { - IEEE80211_DEBUG_WX - ("Setting key %d to default Tx key.\n", key); + IEEE80211_DEBUG_WX("Setting key %d to default Tx " + "key.\n", key); ieee->tx_keyidx = key; sec.active_key = key; sec.flags |= SEC_ACTIVE_KEY; @@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, struct iw_point *erq = &(wrqu->encoding); int len, key; struct ieee80211_crypt_data *crypt; + struct ieee80211_security *sec = &ieee->sec; IEEE80211_DEBUG_WX("GET_ENCODE\n"); @@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, crypt = ieee->crypt[key]; erq->flags = key + 1; - if (crypt == NULL || crypt->ops == NULL) { + if (!sec->enabled) { erq->length = 0; erq->flags |= IW_ENCODE_DISABLED; return 0; } - if (strcmp(crypt->ops->name, "WEP") != 0) { + if (sec->level != SEC_LEVEL_1) { /* only WEP is supported with wireless extensions, so just * report that encryption is used */ erq->length = 0; @@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } - len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); - erq->length = (len >= 0 ? len : 0); + len = sec->key_sizes[key]; + memcpy(keybuf, sec->keys[key], len); + erq->length = (len >= 0 ? len : 0); erq->flags |= IW_ENCODE_ENABLED; if (ieee->open_wep) From 42e349fd10d471d9ae6955a7f12523291c0193e6 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:07 -0500 Subject: [PATCH 0099/1939] [PATCH] ieee80211: Fix time calculation, switching to use jiffies_to_msecs tree b9cdd7058b787807655ea6f125e2adbf8d26c863 parent 85d9b2bddfcf3ed2eb4d061947c25c6a832891ab author Zhu Yi 1124435212 -0500 committer James Ketrenos 1127312152 -0500 Fix time calculation, switching to use jiffies_to_msecs. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_wx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index f88c8116a23c..df64bf3716b7 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -217,8 +218,8 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, iwe.cmd = IWEVCUSTOM; p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - " Last beacon: %lums ago", - (jiffies - network->last_scanned) / (HZ / 100)); + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - network->last_scanned)); iwe.u.data.length = p - custom; if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); @@ -248,13 +249,13 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ev = ipw2100_translate_scan(ieee, ev, stop, network); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" - MAC_FMT ")' due to age (%lums).\n", + MAC_FMT ")' due to age (%dms).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - (jiffies - - network->last_scanned) / (HZ / - 100)); + jiffies_to_msecs(jiffies - + network-> + last_scanned)); } spin_unlock_irqrestore(&ieee->lock, flags); From 0ad0c3c64484b1458b51167bd3e614d8d9d070f8 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:15 -0500 Subject: [PATCH 0100/1939] [PATCH] ieee80211: Fix kernel Oops when module unload tree b69e983266840983183a00f5ac02c66d5270ca47 parent cdd6372949b76694622ed74fe36e1dd17a92eb71 author Zhu Yi 1124435425 -0500 committer James Ketrenos 1127312421 -0500 Fix kernel Oops when module unload. Export a new function ieee80211_crypt_quiescing from ieee80211. Device drivers call it to make the host crypto stack enter the quiescence state, which means "process existing requests, but don't accept new ones". This is usually called during a driver's host crypto data structure free (module unload) path. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 + include/net/ieee80211_crypt.h | 1 + net/ieee80211/ieee80211_crypt.c | 33 ++++++++++++++++++++++++++------ net/ieee80211/ieee80211_module.c | 2 ++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index fa14360dbc9d..6cc0674e5606 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -684,6 +684,7 @@ struct ieee80211_device { struct ieee80211_crypt_data *crypt[WEP_KEYS]; int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ struct timer_list crypt_deinit_timer; + int crypt_quiesced; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index e2064edb957d..536e9a9e6718 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -82,5 +82,6 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); void ieee80211_crypt_deinit_handler(unsigned long); void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, struct ieee80211_crypt_data **crypt); +void ieee80211_crypt_quiescing(struct ieee80211_device *ieee); #endif diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 0c366299db0f..60d3166facce 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -44,6 +44,10 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) unsigned long flags; spin_lock_irqsave(&ieee->lock, flags); + + if (list_empty(&ieee->crypt_deinit_list)) + goto unlock; + for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { entry = list_entry(ptr, struct ieee80211_crypt_data, list); @@ -59,21 +63,35 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) } kfree(entry); } + unlock: + spin_unlock_irqrestore(&ieee->lock, flags); +} + +/* After this, crypt_deinit_list won't accept new members */ +void ieee80211_crypt_quiescing(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + ieee->crypt_quiesced = 1; spin_unlock_irqrestore(&ieee->lock, flags); } void ieee80211_crypt_deinit_handler(unsigned long data) { struct ieee80211_device *ieee = (struct ieee80211_device *)data; + unsigned long flags; ieee80211_crypt_deinit_entries(ieee, 0); - if (!list_empty(&ieee->crypt_deinit_list)) { + + spin_lock_irqsave(&ieee->lock, flags); + if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) { printk(KERN_DEBUG "%s: entries remaining in delayed crypt " "deletion list\n", ieee->dev->name); ieee->crypt_deinit_timer.expires = jiffies + HZ; add_timer(&ieee->crypt_deinit_timer); } - + spin_unlock_irqrestore(&ieee->lock, flags); } void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, @@ -93,10 +111,12 @@ void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, * locking. */ spin_lock_irqsave(&ieee->lock, flags); - list_add(&tmp->list, &ieee->crypt_deinit_list); - if (!timer_pending(&ieee->crypt_deinit_timer)) { - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); + if (!ieee->crypt_quiesced) { + list_add(&tmp->list, &ieee->crypt_deinit_list); + if (!timer_pending(&ieee->crypt_deinit_timer)) { + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } } spin_unlock_irqrestore(&ieee->lock, flags); } @@ -250,6 +270,7 @@ static void __exit ieee80211_crypto_deinit(void) EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); +EXPORT_SYMBOL(ieee80211_crypt_quiescing); EXPORT_SYMBOL(ieee80211_register_crypto_ops); EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 4b43ae1235f9..82a4fd713b28 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -138,6 +138,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) init_timer(&ieee->crypt_deinit_timer); ieee->crypt_deinit_timer.data = (unsigned long)ieee; ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; + ieee->crypt_quiesced = 0; spin_lock_init(&ieee->lock); @@ -161,6 +162,7 @@ void free_ieee80211(struct net_device *dev) int i; + ieee80211_crypt_quiescing(ieee); del_timer_sync(&ieee->crypt_deinit_timer); ieee80211_crypt_deinit_entries(ieee, 1); From 259bf1fd8a7cc0f6b47fd8a9ac5e2dfc33182a3d Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:22 -0500 Subject: [PATCH 0101/1939] [PATCH] ieee80211: Allow drivers to fix an issue when using wpa_supplicant with WEP tree 898fedef6ca1b5b58b8bdf7e6d8894a78bbde4cd parent 8720fff53090ae428d2159332b6f4b2749dea10f author Zhu Yi 1124435746 -0500 committer James Ketrenos 1127312509 -0500 Allow drivers to fix an issue when using wpa_supplicant with WEP. The problem is introduced by the hwcrypto patch. We changed indicator of the encryption request from the upper layer (i.e. wpa_supplicant): In the original host based crypto the driver could use: crypt && crypt->ops. In the new hardware based crypto, the driver should use the flags specified in ieee->sec.encrypt. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 +- net/ieee80211/ieee80211_wx.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 6cc0674e5606..c7ab7cd9de13 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -439,7 +439,7 @@ struct ieee80211_device; #define SEC_UNICAST_GROUP (1<<6) #define SEC_LEVEL (1<<7) #define SEC_ENABLED (1<<8) -#define SEC_TGI_KEY_RESET (1<<9) +#define SEC_ENCRYPT (1<<9) #define SEC_LEVEL_0 0 /* None */ #define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index df64bf3716b7..49afea7989d0 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -322,7 +322,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.enabled = 0; sec.encrypt = 0; sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; + sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT; } goto done; @@ -330,7 +330,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.enabled = 1; sec.encrypt = 1; - sec.flags |= SEC_ENABLED; + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { @@ -412,8 +412,6 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.flags |= SEC_ACTIVE_KEY; } } - - done: ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; sec.flags |= SEC_AUTH_MODE; @@ -425,6 +423,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + done: if (ieee->set_security) ieee->set_security(dev, &sec); From e0d369d1d969fc9e4fd08a20f6dad04d369aceea Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:30 -0500 Subject: [PATCH 0102/1939] [PATCH] ieee82011: Added WE-18 support to default wireless extension handler tree 1536f39c18756698d033da72c49300a561be1289 parent 07172d7c9f10ee3d05d6f6489ba6d6ee2628da06 author Liu Hong 1124436225 -0500 committer James Ketrenos 1127312664 -0500 Added WE-18 support to default wireless extension handler in ieee80211 subsystem. Updated patch since last send to account for ieee80211_device parameter being added to the crypto init method. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 14 +++ net/ieee80211/ieee80211_wx.c | 238 +++++++++++++++++++++++++++++++++-- 2 files changed, 244 insertions(+), 8 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index c7ab7cd9de13..dfc5d65cc6c1 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -447,6 +447,11 @@ struct ieee80211_device; #define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ #define SEC_LEVEL_3 4 /* Level 2 + CCMP */ +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 3 + #define WEP_KEYS 4 #define WEP_KEY_LEN 13 #define SCM_KEY_LEN 32 @@ -456,6 +461,7 @@ struct ieee80211_security { u16 active_key:2, enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; + u8 encode_alg[WEP_KEYS]; u8 key_sizes[WEP_KEYS]; u8 keys[WEP_KEYS][SCM_KEY_LEN]; u8 level; @@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *key); +#if WIRELESS_EXT > 17 +extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +#endif extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 49afea7989d0..db66217699d5 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, * TODO: When WPA is added this is one place that needs to change */ sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + sec.encode_alg[key] = SEC_ALG_WEP; done: if (ieee->set_security) @@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } - if (sec->level != SEC_LEVEL_1) { - /* only WEP is supported with wireless extensions, so just - * report that encryption is used */ - erq->length = 0; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - len = sec->key_sizes[key]; memcpy(keybuf, sec->keys[key], len); @@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } +#if WIRELESS_EXT > 17 +int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct net_device *dev = ieee->dev; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int i, idx, ret = 0; + const char *alg, *module; + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->tx_keyidx; + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + crypt = &ieee->crypt[idx]; + else { + if (idx != 0) + return -EINVAL; + if (ieee->iw_mode == IW_MODE_INFRA) + crypt = &ieee->crypt[idx]; + else + return -EINVAL; + } + + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + if (*crypt) + ieee80211_crypt_delayed_deinit(ieee, crypt); + + for (i = 0; i < WEP_KEYS; i++) + if (ieee->crypt[i] != NULL) + break; + + if (i == WEP_KEYS) { + sec.enabled = 0; + sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_LEVEL; + } + goto done; + } + + sec.enabled = 1; + sec.encrypt = 1; + + if (!(ieee->host_encrypt || ieee->host_decrypt)) + goto skip_host_crypt; + + switch (ext->alg) { + case IW_ENCODE_ALG_WEP: + alg = "WEP"; + module = "ieee80211_crypt_wep"; + break; + case IW_ENCODE_ALG_TKIP: + alg = "TKIP"; + module = "ieee80211_crypt_tkip"; + break; + case IW_ENCODE_ALG_CCMP: + alg = "CCMP"; + module = "ieee80211_crypt_ccmp"; + break; + default: + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + + ops = ieee80211_get_crypto_ops(alg); + if (ops == NULL) { + request_module(module); + ops = ieee80211_get_crypto_ops(alg); + } + if (ops == NULL) { + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + + new_crypt = (struct ieee80211_crypt_data *) + kmalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(ieee, idx); + if (new_crypt->priv == NULL) { + kfree(new_crypt); + ret = -EINVAL; + goto done; + } + *crypt = new_crypt; + } + + if (ext->key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, + (*crypt)->priv) < 0) { + IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + ret = -EINVAL; + goto done; + } + + skip_host_crypt: + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + ieee->tx_keyidx = idx; + sec.active_key = idx; + sec.flags |= SEC_ACTIVE_KEY; + } + + if (ext->alg != IW_ENCODE_ALG_NONE) { + memcpy(sec.keys[idx], ext->key, ext->key_len); + sec.key_sizes[idx] = ext->key_len; + sec.flags |= (1 << idx); + if (ext->alg == IW_ENCODE_ALG_WEP) { + sec.encode_alg[idx] = SEC_ALG_WEP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (ext->alg == IW_ENCODE_ALG_TKIP) { + sec.encode_alg[idx] = SEC_ALG_TKIP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (ext->alg == IW_ENCODE_ALG_CCMP) { + sec.encode_alg[idx] = SEC_ALG_CCMP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* + * Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. + */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + return -EINVAL; + } + + return ret; +} + +int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct ieee80211_security *sec = &ieee->sec; + int idx, max_key_len; + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->tx_keyidx; + + if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) + return -EINVAL; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + if (!sec->enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + } else { + if (sec->encode_alg[idx] == SEC_ALG_WEP) + ext->alg = IW_ENCODE_ALG_WEP; + else if (sec->encode_alg[idx] == SEC_ALG_TKIP) + ext->alg = IW_ENCODE_ALG_TKIP; + else if (sec->encode_alg[idx] == SEC_ALG_CCMP) + ext->alg = IW_ENCODE_ALG_CCMP; + else + return -EINVAL; + + ext->key_len = sec->key_sizes[idx]; + memcpy(ext->key, sec->keys[idx], ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + if (ext->key_len && + (ext->alg == IW_ENCODE_ALG_TKIP || + ext->alg == IW_ENCODE_ALG_CCMP)) + ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; + + } + + return 0; +} + +EXPORT_SYMBOL(ieee80211_wx_set_encodeext); +EXPORT_SYMBOL(ieee80211_wx_get_encodeext); +#endif + EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_set_encode); EXPORT_SYMBOL(ieee80211_wx_get_encode); From ee34af37c095482b9dba254b9cd7cb5e65e9a25e Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:36 -0500 Subject: [PATCH 0103/1939] [PATCH] ieee80211: Renamed ieee80211_hdr to ieee80211_hdr_3addr tree e9c18b2c8e5ad446a4d213243c2dcf9fd1652a7b parent 4e97ad6ae7084a4f741e94e76c41c68bc7c5a76a author James Ketrenos 1124444315 -0500 committer James Ketrenos 1127312922 -0500 Renamed ieee80211_hdr to ieee80211_hdr_3addr and modified ieee80211_hdr to just contain the frame_ctrl and duration_id. Changed uses of ieee80211_hdr to ieee80211_hdr_4addr or ieee80211_hdr_3addr based on what was expected for that portion of code. NOTE: This requires changes to ipw2100, ipw2200, hostap, and atmel drivers. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 117 ++++++++++++++++++++------- net/ieee80211/ieee80211_crypt_ccmp.c | 10 +-- net/ieee80211/ieee80211_crypt_tkip.c | 27 ++++--- net/ieee80211/ieee80211_rx.c | 32 ++++---- net/ieee80211/ieee80211_tx.c | 7 +- 5 files changed, 129 insertions(+), 64 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index dfc5d65cc6c1..ebe7e41e5eaf 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -33,33 +33,13 @@ represents the 2304 bytes of real data, plus a possible 8 bytes of WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ -#define IEEE80211_HLEN 30 -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -struct ieee80211_hdr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; -} __attribute__ ((packed)); - #define IEEE80211_1ADDR_LEN 10 #define IEEE80211_2ADDR_LEN 16 #define IEEE80211_3ADDR_LEN 24 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_FCS_LEN 4 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) #define MIN_FRAG_THRESHOLD 256U #define MAX_FRAG_THRESHOLD 2346U @@ -515,6 +495,51 @@ enum ieee80211_mfie { MFIE_TYPE_GENERIC = 221, }; +/* Minimal header; can be used for passing 802.11 frames with sufficient + * information to determine what type of underlying data type is actually + * stored in the data. */ +struct ieee80211_hdr { + u16 frame_ctl; + u16 duration_id; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_1addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_2addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + struct ieee80211_info_element { u8 id; u8 len; @@ -538,7 +563,7 @@ struct ieee80211_info_element { u16 status; */ -struct ieee80211_authentication { +struct ieee80211_auth { struct ieee80211_hdr_3addr header; __le16 algorithm; __le16 transaction; @@ -546,6 +571,17 @@ struct ieee80211_authentication { struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); +struct ieee80211_disassoc { + struct ieee80211_hdr_3addr header; + u16 reason_code; + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_probe_request { + struct ieee80211_hdr_3addr header; + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + struct ieee80211_probe_response { struct ieee80211_hdr_3addr header; u32 time_stamp[2]; @@ -554,14 +590,25 @@ struct ieee80211_probe_response { struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); -struct ieee80211_assoc_request_frame { +/* Alias beacon for probe_response */ +#define ieee80211_beacon ieee80211_probe_response + +struct ieee80211_assoc_request { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 listen_interval; + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_reassoc_request { + struct ieee80211_hdr_3addr header; __le16 capability; __le16 listen_interval; u8 current_ap[ETH_ALEN]; struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); -struct ieee80211_assoc_response_frame { +struct ieee80211_assoc_response { struct ieee80211_hdr_3addr header; __le16 capability; __le16 status; @@ -572,7 +619,8 @@ struct ieee80211_assoc_response_frame { struct ieee80211_txb { u8 nr_frags; u8 encrypted; - u16 reserved; + u8 rts_included; + u8 reserved; u16 frag_size; u16 payload_size; struct sk_buff *fragments[0]; @@ -803,6 +851,21 @@ extern inline int ieee80211_get_hdrlen(u16 fc) return hdrlen; } +extern inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) +{ + switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { + case IEEE80211_1ADDR_LEN: + return ((struct ieee80211_hdr_1addr *)hdr)->payload; + case IEEE80211_2ADDR_LEN: + return ((struct ieee80211_hdr_2addr *)hdr)->payload; + case IEEE80211_3ADDR_LEN: + return ((struct ieee80211_hdr_3addr *)hdr)->payload; + case IEEE80211_4ADDR_LEN: + return ((struct ieee80211_hdr_4addr *)hdr)->payload; + } + +} + /* ieee80211.c */ extern void free_ieee80211(struct net_device *dev); extern struct net_device *alloc_ieee80211(int sizeof_priv); @@ -817,7 +880,7 @@ extern void ieee80211_txb_free(struct ieee80211_txb *); extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr *header, + struct ieee80211_hdr_4addr *header, struct ieee80211_rx_stats *stats); /* ieee80211_wx.c */ diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 1e6644b133dc..d3b5cdee69ef 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -119,7 +119,7 @@ static inline void xor_block(u8 * b, u8 * a, size_t len) } static void ccmp_init_blocks(struct crypto_tfm *tfm, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0) { u8 *pos, qc = 0; @@ -196,7 +196,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) struct ieee80211_ccmp_data *key = priv; int data_len, i, blocks, last, len; u8 *pos, *mic; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 *b0 = key->tx_b0; u8 *b = key->tx_b; u8 *e = key->tx_e; @@ -229,7 +229,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) *pos++ = key->tx_pn[1]; *pos++ = key->tx_pn[0]; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; @@ -258,7 +258,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_ccmp_data *key = priv; u8 keyidx, *pos; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 *b0 = key->rx_b0; u8 *b = key->rx_b; u8 *a = key->rx_a; @@ -272,7 +272,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; } - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; pos = skb->data + hdr_len; keyidx = pos[3]; if (!(keyidx & (1 << 5))) { diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 0c495f07e718..f091aacd4297 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -265,11 +265,11 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) struct ieee80211_tkip_data *tkey = priv; int len; u8 rc4key[16], *pos, *icv; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u32 crc; struct scatterlist sg; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; if (tkey->ieee->tkip_countermeasures) { if (net_ratelimit()) { @@ -334,13 +334,13 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 keyidx, *pos; u32 iv32; u16 iv16; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 icv[4]; u32 crc; struct scatterlist sg; int plen; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; if (tkey->ieee->tkip_countermeasures) { if (net_ratelimit()) { @@ -466,9 +466,9 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) { - struct ieee80211_hdr *hdr11; + struct ieee80211_hdr_4addr *hdr11; - hdr11 = (struct ieee80211_hdr *)skb->data; + hdr11 = (struct ieee80211_hdr_4addr *)skb->data; switch (le16_to_cpu(hdr11->frame_ctl) & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_TODS: @@ -517,7 +517,8 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, #if WIRELESS_EXT >= 18 static void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr *hdr, int keyidx) + struct ieee80211_hdr_4addr *hdr, + int keyidx) { union iwreq_data wrqu; struct iw_michaelmicfailure ev; @@ -537,7 +538,8 @@ static void ieee80211_michael_mic_failure(struct net_device *dev, } #elif WIRELESS_EXT >= 15 static void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr *hdr, int keyidx) + struct ieee80211_hdr_4addr *hdr, + int keyidx) { union iwreq_data wrqu; char buf[128]; @@ -551,9 +553,8 @@ static void ieee80211_michael_mic_failure(struct net_device *dev, wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); } #else /* WIRELESS_EXT >= 15 */ -static inline void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr *hdr, - int keyidx) +static inline void ieee80211_michael_mic_failure(struct net_device *dev, struct ieee80211_hdr_4addr + *hdr, int keyidx) { } #endif /* WIRELESS_EXT >= 15 */ @@ -572,8 +573,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) return -1; if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { - struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr_4addr *hdr; + hdr = (struct ieee80211_hdr_4addr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " "MSDU from " MAC_FMT " keyidx=%d\n", skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 9a125d45289a..71d14c7d915c 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -87,7 +87,7 @@ static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct /* Called only as a tasklet (software IRQ) */ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; @@ -101,7 +101,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(ieee->dev->mtu + - sizeof(struct ieee80211_hdr) + + sizeof(struct ieee80211_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */ ); @@ -138,7 +138,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, /* Called only as a tasklet (software IRQ) */ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { u16 sc; unsigned int seq; @@ -176,7 +176,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ieee->dev->name); return 0; /* - hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) + hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) skb->data);*/ } @@ -232,13 +232,13 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, { struct net_device *dev = ieee->dev; u16 fc, ethertype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_3addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -271,13 +271,13 @@ static inline int ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_3addr *)skb->data; hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); @@ -303,13 +303,13 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, struct sk_buff *skb, int keyidx, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_3addr *)skb->data; hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); @@ -332,7 +332,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; struct net_device_stats *stats; @@ -352,7 +352,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; if (skb->len < 10) { @@ -552,7 +552,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ // PR: FIXME: hostap has additional conditions in the "if" below: @@ -606,7 +606,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; ieee80211_frag_cache_invalidate(ieee, hdr); } @@ -616,7 +616,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr_4addr *)skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { if ( /*ieee->ieee802_1x && */ ieee80211_is_eapol_frame(ieee, skb)) { @@ -1148,7 +1148,7 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device } void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr *header, + struct ieee80211_hdr_4addr *header, struct ieee80211_rx_stats *stats) { switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 785e76f7e4e9..29770cfefc3d 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -227,14 +227,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_txb *txb = NULL; - struct ieee80211_hdr *frag_hdr; + struct ieee80211_hdr_3addr *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; unsigned long flags; struct net_device_stats *stats = &ieee->stats; int ether_type, encrypt, host_encrypt; int bytes, fc, hdr_len; struct sk_buff *skb_frag; - struct ieee80211_hdr header = { /* Ensure zero initialized */ + struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ .duration_id = 0, .seq_ctl = 0 }; @@ -352,7 +352,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (host_encrypt) skb_reserve(skb_frag, crypt->ops->extra_prefix_len); - frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); + frag_hdr = + (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); memcpy(frag_hdr, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS From 3cdd00c5827621cd0b1bb0665aa62ef9a724297d Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:43 -0500 Subject: [PATCH 0104/1939] [PATCH] ieee80211: adds support for the creation of RTS packets tree b45c9c1017fd23216bfbe71e441aed9aa297fc84 parent 04aacdd71e904656a304d923bdcf57ad3bd2b254 author Ivo van Doorn 1124445405 -0500 committer James Ketrenos 1127313029 -0500 This patch adds support for the creation of RTS packets when the config flag CFG_IEEE80211_RTS has been set. Signed-Off-By: Ivo van Doorn Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 ++ net/ieee80211/ieee80211_module.c | 1 + net/ieee80211/ieee80211_tx.c | 41 +++++++++++++++++++++++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index ebe7e41e5eaf..5e11ccf8a763 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -690,6 +690,7 @@ enum ieee80211_state { #define CFG_IEEE80211_RESERVE_FCS (1<<0) #define CFG_IEEE80211_COMPUTE_FCS (1<<1) +#define CFG_IEEE80211_RTS (1<<2) struct ieee80211_device { struct net_device *dev; @@ -747,6 +748,7 @@ struct ieee80211_device { struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; unsigned int frag_next_idx; u16 fts; /* Fragmentation Threshold */ + u16 rts; /* RTS threshold */ /* Association info */ u8 bssid[ETH_ALEN]; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 82a4fd713b28..67d6bdd2e3f2 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -126,6 +126,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; + ieee->rts = DEFAULT_FTS; ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ieee->open_wep = 1; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 29770cfefc3d..cdee41cefb26 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -222,13 +222,15 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -/* SKBs are added to the ieee->tx_queue. */ +/* Incoming skb is converted to a txb which consist of + * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_txb *txb = NULL; struct ieee80211_hdr_3addr *frag_hdr; - int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, + rts_required; unsigned long flags; struct net_device_stats *stats = &ieee->stats; int ether_type, encrypt, host_encrypt; @@ -334,6 +336,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) else bytes_last_frag = bytes_per_frag; + rts_required = (frag_size > ieee->rts + && ieee->config & CFG_IEEE80211_RTS); + if (rts_required) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ @@ -346,7 +355,33 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) txb->encrypted = encrypt; txb->payload_size = bytes; - for (i = 0; i < nr_frags; i++) { + if (rts_required) { + skb_frag = txb->fragments[0]; + frag_hdr = + (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); + + /* + * Set header frame_ctl to the RTS. + */ + header.frame_ctl = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); + memcpy(frag_hdr, &header, hdr_len); + + /* + * Restore header frame_ctl to the original data setting. + */ + header.frame_ctl = cpu_to_le16(fc); + + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + + txb->rts_included = 1; + i = 1; + } else + i = 0; + + for (; i < nr_frags; i++) { skb_frag = txb->fragments[i]; if (host_encrypt) From 3f552bbf8614d2d26f488ca0d3e188bdec484bf4 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:47 -0500 Subject: [PATCH 0105/1939] [PATCH] ieee82011: Added ieee80211_tx_frame to convert generic 802.11 data frames, and callbacks tree 40adc78b623ae70d56074934ec6334eb4f0ae6a5 parent db43d847bcebaa3df6414e26d0008eb21690e8cf author James Ketrenos 1124445938 -0500 committer James Ketrenos 1127313102 -0500 Added ieee80211_tx_frame to convert generic 802.11 data frames into txbs for transmission. Added several purpose specific callbacks (handle_assoc, handle_auth, etc.) which the driver can register with for being notified on reception of variouf frame elements. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 23 +++++++++++++ net/ieee80211/ieee80211_rx.c | 58 +++++++++++++++++++++++-------- net/ieee80211/ieee80211_tx.c | 66 +++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 5e11ccf8a763..43cf2e577191 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -769,6 +769,27 @@ struct ieee80211_device { int (*hard_start_xmit) (struct ieee80211_txb * txb, struct net_device * dev); int (*reset_port) (struct net_device * dev); + int (*is_queue_full) (struct net_device * dev, int pri); + + /* Typical STA methods */ + int (*handle_auth) (struct net_device * dev, + struct ieee80211_auth * auth); + int (*handle_disassoc) (struct net_device * dev, + struct ieee80211_disassoc * assoc); + int (*handle_beacon) (struct net_device * dev, + struct ieee80211_beacon * beacon, + struct ieee80211_network * network); + int (*handle_probe_response) (struct net_device * dev, + struct ieee80211_probe_response * resp, + struct ieee80211_network * network); + int (*handle_assoc_response) (struct net_device * dev, + struct ieee80211_assoc_response * resp, + struct ieee80211_network * network); + + /* Typical AP methods */ + int (*handle_assoc_request) (struct net_device * dev); + int (*handle_reassoc_request) (struct net_device * dev, + struct ieee80211_reassoc_request * req); /* This must be the last item so that it points to the data * allocated beyond this structure by alloc_ieee80211 */ @@ -877,6 +898,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee); /* ieee80211_tx.c */ extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); +extern int ieee80211_tx_frame(struct ieee80211_device *ieee, + struct ieee80211_hdr *frame, int len); /* ieee80211_rx.c */ extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 71d14c7d915c..d1ae28280d7e 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1029,12 +1029,18 @@ static inline void update_network(struct ieee80211_network *dst, /* dst->last_associate is not overwritten */ } +static inline int is_beacon(int fc) +{ + return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); +} + static inline void ieee80211_process_probe_response(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_rx_stats *stats) { + struct net_device *dev = ieee->dev; struct ieee80211_network network; struct ieee80211_network *target; struct ieee80211_network *oldest = NULL; @@ -1070,11 +1076,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(info_element->data, info_element->len), MAC_ARG(beacon->header.addr3), - WLAN_FC_GET_STYPE(le16_to_cpu - (beacon->header. - frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); + is_beacon(le16_to_cpu + (beacon->header. + frame_ctl)) ? + "BEACON" : "PROBE RESPONSE"); return; } @@ -1123,11 +1128,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(network.ssid, network.ssid_len), MAC_ARG(network.bssid), - WLAN_FC_GET_STYPE(le16_to_cpu - (beacon->header. - frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); + is_beacon(le16_to_cpu + (beacon->header. + frame_ctl)) ? + "BEACON" : "PROBE RESPONSE"); #endif memcpy(target, &network, sizeof(*target)); list_add_tail(&target->list, &ieee->network_list); @@ -1136,15 +1140,22 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device escape_essid(target->ssid, target->ssid_len), MAC_ARG(target->bssid), - WLAN_FC_GET_STYPE(le16_to_cpu - (beacon->header. - frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); + is_beacon(le16_to_cpu + (beacon->header. + frame_ctl)) ? + "BEACON" : "PROBE RESPONSE"); update_network(target, &network); } spin_unlock_irqrestore(&ieee->lock, flags); + + if (is_beacon(le16_to_cpu(beacon->header.frame_ctl))) { + if (ieee->handle_beacon != NULL) + ieee->handle_beacon(dev, beacon, &network); + } else { + if (ieee->handle_probe_response != NULL) + ieee->handle_probe_response(dev, beacon, &network); + } } void ieee80211_rx_mgt(struct ieee80211_device *ieee, @@ -1185,6 +1196,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, ieee80211_probe_response *) header, stats); break; + case IEEE80211_STYPE_AUTH: + + IEEE80211_DEBUG_MGMT("recieved auth (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + if (ieee->handle_auth != NULL) + ieee->handle_auth(ieee->dev, + (struct ieee80211_auth *)header); + break; + + case IEEE80211_STYPE_DISASSOC: + if (ieee->handle_disassoc != NULL) + ieee->handle_disassoc(ieee->dev, + (struct ieee80211_disassoc *) + header); + break; default: IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index cdee41cefb26..f505aa127e21 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -459,7 +459,71 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); stats->tx_errors++; return 1; - } +/* Incoming 802.11 strucure is converted to a TXB + * a block of 802.11 fragment packets (stored as skbs) */ +int ieee80211_tx_frame(struct ieee80211_device *ieee, + struct ieee80211_hdr *frame, int len) +{ + struct ieee80211_txb *txb = NULL; + unsigned long flags; + struct net_device_stats *stats = &ieee->stats; + struct sk_buff *skb_frag; + + spin_lock_irqsave(&ieee->lock, flags); + + /* If there is no driver handler to take the TXB, dont' bother + * creating it... */ + if (!ieee->hard_start_xmit) { + printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); + goto success; + } + + if (unlikely(len < 24)) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, len); + goto success; + } + + /* When we allocate the TXB we allocate enough space for the reserve + * and full fragment bytes (bytes_per_frag doesn't include prefix, + * postfix, header, FCS, etc.) */ + txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + txb->encrypted = 0; + txb->payload_size = len; + + skb_frag = txb->fragments[0]; + + memcpy(skb_put(skb_frag, len), frame, len); + + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + + success: + spin_unlock_irqrestore(&ieee->lock, flags); + + if (txb) { + if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) { + stats->tx_packets++; + stats->tx_bytes += txb->payload_size; + return 0; + } + ieee80211_txb_free(txb); + } + return 0; + + failed: + spin_unlock_irqrestore(&ieee->lock, flags); + stats->tx_errors++; + return 1; +} + +EXPORT_SYMBOL(ieee80211_tx_frame); EXPORT_SYMBOL(ieee80211_txb_free); From 1264fc0498e1e20f97b1ab690e523e7a7fc50eab Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:53 -0500 Subject: [PATCH 0106/1939] [PATCH] ieee80211: Fix TKIP, repeated fragmentation problem, and payload_size reporting tree 8428e9f510e6ad6c77baec89cb57374842abf733 parent d78bfd3ddae9c422dd350159110f9c4d7cfc50de author Liu Hong 1124446520 -0500 committer James Ketrenos 1127313183 -0500 Fix TKIP, repeated fragmentation problem, and payload_size reporting 1. TKIP encryption Originally, TKIP encryption issues msdu + mpdu encryption on every fragment. Change the behavior to msdu encryption on the whole packet, then mpdu encryption on every fragment. 2. Avoid repeated fragmentation when !host_encrypt. We only need do fragmentation when using host encryption. Otherwise we only need pass the whole packet to driver, letting driver do the fragmentation. 3. change the txb->payload_size to correct value FW will use this value to determine whether to do fragmentation. If we pass the wrong value, fw may cut on the wrong bound which will make decryption fail when we do host encryption. NOTE: This requires changing drivers (hostap) that have extra_prefix_len used within them (structure member name change). Signed-off-by: Hong Liu Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 + include/net/ieee80211_crypt.h | 3 +- net/ieee80211/ieee80211_crypt.c | 4 +- net/ieee80211/ieee80211_crypt_ccmp.c | 4 +- net/ieee80211/ieee80211_crypt_tkip.c | 5 +- net/ieee80211/ieee80211_crypt_wep.c | 4 +- net/ieee80211/ieee80211_module.c | 7 +- net/ieee80211/ieee80211_tx.c | 146 +++++++++++++++------------ 8 files changed, 101 insertions(+), 74 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 43cf2e577191..46466f5a2b45 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -724,7 +724,9 @@ struct ieee80211_device { /* If the host performs {en,de}cryption, then set to 1 */ int host_encrypt; + int host_encrypt_msdu; int host_decrypt; + int host_open_frag; int ieee802_1x; /* is IEEE 802.1X used */ /* WPA data */ diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 536e9a9e6718..24e4912a263a 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -63,7 +63,8 @@ struct ieee80211_crypto_ops { * extra_postfix_len; encrypt need not use all this space, but * the result must start at the beginning of the buffer and correct * length must be returned */ - int extra_prefix_len, extra_postfix_len; + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; struct module *owner; }; diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 60d3166facce..e26bcc918032 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -221,8 +221,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_null = { .decrypt_msdu = NULL, .set_key = NULL, .get_key = NULL, - .extra_prefix_len = 0, - .extra_postfix_len = 0, + .extra_mpdu_prefix_len = 0, + .extra_mpdu_postfix_len = 0, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index d3b5cdee69ef..a3dc5712b98b 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -436,8 +436,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { .set_key = ieee80211_ccmp_set_key, .get_key = ieee80211_ccmp_get_key, .print_stats = ieee80211_ccmp_print_stats, - .extra_prefix_len = CCMP_HDR_LEN, - .extra_postfix_len = CCMP_MIC_LEN, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index f091aacd4297..f973d6cb8248 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -690,8 +690,9 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { .set_key = ieee80211_tkip_set_key, .get_key = ieee80211_tkip_get_key, .print_stats = ieee80211_tkip_print_stats, - .extra_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 63e783fa5173..2aaeac1e02d7 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -239,8 +239,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = { .set_key = prism2_wep_set_key, .get_key = prism2_wep_get_key, .print_stats = prism2_wep_print_stats, - .extra_prefix_len = 4, /* IV */ - .extra_postfix_len = 4, /* ICV */ + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 67d6bdd2e3f2..dddc61647390 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -133,6 +133,12 @@ struct net_device *alloc_ieee80211(int sizeof_priv) /* Default to enabling full open WEP with host based encrypt/decrypt */ ieee->host_encrypt = 1; ieee->host_decrypt = 1; + /* Host fragementation in Open mode. Default is enabled. + * Note: host fragmentation is always enabled if host encryption + * is enabled. For cards can do hardware encryption, they must do + * hardware fragmentation as well. So we don't need a variable + * like host_enc_frag. */ + ieee->host_open_frag = 1; ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ INIT_LIST_HEAD(&ieee->crypt_deinit_list); @@ -147,7 +153,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->tkip_countermeasures = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; - ieee->ieee802_1x = 1; return dev; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index f505aa127e21..23a1f88de7cb 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -128,7 +128,7 @@ payload of each frame is reduced to 492 bytes. static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -static inline int ieee80211_put_snap(u8 * data, u16 h_proto) +static inline int ieee80211_copy_snap(u8 * data, u16 h_proto) { struct ieee80211_snap_hdr *snap; u8 *oui; @@ -159,15 +159,9 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, /* To encrypt, frame format is: * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ - - // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ atomic_inc(&crypt->refcnt); res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) + if (crypt->ops->encrypt_mpdu) res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); atomic_dec(&crypt->refcnt); @@ -222,7 +216,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -/* Incoming skb is converted to a txb which consist of +/* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -233,7 +227,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) rts_required; unsigned long flags; struct net_device_stats *stats = &ieee->stats; - int ether_type, encrypt, host_encrypt; + int ether_type, encrypt, host_encrypt, host_encrypt_msdu; int bytes, fc, hdr_len; struct sk_buff *skb_frag; struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ @@ -241,8 +235,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) .seq_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt; + int snapped = 0; spin_lock_irqsave(&ieee->lock, flags); @@ -266,6 +260,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ieee->sec.encrypt; host_encrypt = ieee->host_encrypt && encrypt; + host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt; if (!encrypt && ieee->ieee802_1x && ieee->drop_unencrypted && ether_type != ETH_P_PAE) { @@ -291,14 +286,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (ieee->iw_mode == IW_MODE_INFRA) { fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, - Addr3 = DA */ + /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ memcpy(header.addr1, ieee->bssid, ETH_ALEN); memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, dest, ETH_ALEN); } else if (ieee->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, - Addr3 = BSSID */ + /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ memcpy(header.addr1, dest, ETH_ALEN); memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN); @@ -306,42 +299,75 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) header.frame_ctl = cpu_to_le16(fc); hdr_len = IEEE80211_3ADDR_LEN; - /* Determine fragmentation size based on destination (multicast - * and broadcast are not fragmented) */ - if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) - frag_size = MAX_FRAG_THRESHOLD; - else - frag_size = ieee->fts; + /* Encrypt msdu first on the whole data packet. */ + if ((host_encrypt || host_encrypt_msdu) && + crypt && crypt->ops && crypt->ops->encrypt_msdu) { + int res = 0; + int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + struct sk_buff *skb_new = dev_alloc_skb(len); + if (unlikely(!skb_new)) + goto failed; + skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); + memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); + snapped = 1; + ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), + ether_type); + memcpy(skb_put(skb_new, skb->len), skb->data, skb->len); + res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); + if (res < 0) { + IEEE80211_ERROR("msdu encryption failed\n"); + dev_kfree_skb_any(skb_new); + goto failed; + } + dev_kfree_skb_any(skb); + skb = skb_new; + bytes += crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + skb_pull(skb, hdr_len); + } - /* Determine amount of payload per fragment. Regardless of if - * this stack is providing the full 802.11 header, one will - * eventually be affixed to this fragment -- so we must account for - * it when determining the amount of payload space. */ - bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; + if (host_encrypt || ieee->host_open_frag) { + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ + if (is_multicast_ether_addr(dest)) + frag_size = MAX_FRAG_THRESHOLD; + else + frag_size = ieee->fts; - /* Each fragment may need to have room for encryptiong pre/postfix */ - if (host_encrypt) - bytes_per_frag -= crypt->ops->extra_prefix_len + - crypt->ops->extra_postfix_len; + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account + * for it when determining the amount of payload space. */ + bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; - /* Number of fragments is the total bytes_per_frag / - * payload_per_fragment */ - nr_frags = bytes / bytes_per_frag; - bytes_last_frag = bytes % bytes_per_frag; - if (bytes_last_frag) - nr_frags++; - else - bytes_last_frag = bytes_per_frag; + /* Each fragment may need to have room for encryptiong + * pre/postfix */ + if (host_encrypt) + bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_mpdu_postfix_len; + + /* Number of fragments is the total + * bytes_per_frag / payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + } else { + nr_frags = 1; + bytes_per_frag = bytes_last_frag = bytes; + frag_size = bytes + IEEE80211_3ADDR_LEN; + } rts_required = (frag_size > ieee->rts && ieee->config & CFG_IEEE80211_RTS); if (rts_required) nr_frags++; - else - bytes_last_frag = bytes_per_frag; /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, @@ -353,7 +379,11 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) goto failed; } txb->encrypted = encrypt; - txb->payload_size = bytes; + if (host_encrypt) + txb->payload_size = frag_size * (nr_frags - 1) + + bytes_last_frag; + else + txb->payload_size = bytes; if (rts_required) { skb_frag = txb->fragments[0]; @@ -385,7 +415,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag = txb->fragments[i]; if (host_encrypt) - skb_reserve(skb_frag, crypt->ops->extra_prefix_len); + skb_reserve(skb_frag, + crypt->ops->extra_mpdu_prefix_len); frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); @@ -402,11 +433,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) bytes = bytes_last_frag; } - /* Put a SNAP header on the first fragment */ - if (i == 0) { - ieee80211_put_snap(skb_put - (skb_frag, SNAP_SIZE + sizeof(u16)), - ether_type); + if (i == 0 && !snapped) { + ieee80211_copy_snap(skb_put + (skb_frag, SNAP_SIZE + sizeof(u16)), + ether_type); bytes -= SNAP_SIZE + sizeof(u16); } @@ -420,19 +450,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (host_encrypt) ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); - /* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */ - if (!ieee->host_encrypt && encrypt && - (ieee->sec.level == SEC_LEVEL_2) && - crypt && crypt->ops && crypt->ops->encrypt_msdu) { - int res = 0; - res = crypt->ops->encrypt_msdu(skb_frag, hdr_len, - crypt->priv); - if (res < 0) { - IEEE80211_ERROR("TKIP MIC encryption failed\n"); - goto failed; - } - } - if (ieee->config & (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) skb_put(skb_frag, 4); @@ -444,7 +461,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); if (txb) { - if ((*ieee->hard_start_xmit) (txb, dev) == 0) { + int ret = (*ieee->hard_start_xmit) (txb, dev); + if (ret == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; return 0; From 2c0aa2a5c2dfa1293ae3a07517d0b7de149358a1 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:56:27 -0500 Subject: [PATCH 0107/1939] [PATCH] ieee80211: Return NETDEV_TX_BUSY when QoS buffer full tree ba6509c7cd1dd4244a2f285f2da5d632e7ffbb25 parent 7b5f9f2ddcabdaea214527a895e6e8445cafdd80 author James Ketrenos 1124447000 -0500 committer James Ketrenos 1127313383 -0500 Per the conversations with folks at OLS, the QoS layer in 802.11 drivers can now result in NETDEV_TX_BUSY being returned when the queue a packet is targetted for is full. To implement this, ieee80211_xmit will now call the driver's is_queue_full to determine if the current priority queue is full. If so, NETDEV_TX_BUSY is returned to the kernel and no processing is done on the frame. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_tx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 23a1f88de7cb..e9efdd42ba37 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -236,8 +236,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) }; u8 dest[ETH_ALEN], src[ETH_ALEN]; struct ieee80211_crypt_data *crypt; + int priority = skb->priority; int snapped = 0; + if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority)) + return NETDEV_TX_BUSY; + spin_lock_irqsave(&ieee->lock, flags); /* If there is no driver handler to take the TXB, dont' bother @@ -467,6 +471,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_bytes += txb->payload_size; return 0; } + + if (ret == NETDEV_TX_BUSY) { + printk(KERN_ERR "%s: NETDEV_TX_BUSY returned; " + "driver should report queue full via " + "ieee_device->is_queue_full.\n", + ieee->dev->name); + } + ieee80211_txb_free(txb); } From 9e8571affd1c54b9638b4ff9844e47aae07310f6 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:56:33 -0500 Subject: [PATCH 0108/1939] [PATCH] ieee80211: Add QoS (WME) support to the ieee80211 subsystem tree a3ad796273e98036eb0e9fc063225070fa24508a parent 1b9c0aeb377abf8e4a43a86cff42382f74ca0259 author Mohamed Abbas 1124447069 -0500 committer James Ketrenos 1127313435 -0500 Add QoS (WME) support to the ieee80211 subsystem. NOTE: This requires drivers that use the ieee80211 hard_start_xmit (ipw2100 and ipw2200) to add the priority parameter to their callback. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 103 ++++++++++- net/ieee80211/ieee80211_rx.c | 334 +++++++++++++++++++++++++++++++++-- net/ieee80211/ieee80211_tx.c | 5 +- 3 files changed, 417 insertions(+), 25 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 46466f5a2b45..72bd2b17eeb4 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -92,6 +92,7 @@ #define IEEE80211_STYPE_CFACK 0x0050 #define IEEE80211_STYPE_CFPOLL 0x0060 #define IEEE80211_STYPE_CFACKPOLL 0x0070 +#define IEEE80211_STYPE_QOS_DATA 0x0080 #define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_SEQ 0xFFF0 @@ -153,6 +154,7 @@ const char *escape_essid(const char *essid, u8 essid_len); #define IEEE80211_DL_TX (1<<8) #define IEEE80211_DL_RX (1<<9) +#define IEEE80211_DL_QOS (1<<31) #define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) #define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) @@ -166,6 +168,7 @@ const char *escape_essid(const char *essid, u8 essid_len); #define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) #define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) #define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) #include #include #include /* ARPHRD_ETHER */ @@ -493,6 +496,7 @@ enum ieee80211_mfie { MFIE_TYPE_RSN = 48, MFIE_TYPE_RATES_EX = 50, MFIE_TYPE_GENERIC = 221, + MFIE_TYPE_QOS_PARAMETER = 222, }; /* Minimal header; can be used for passing 802.11 frames with sufficient @@ -540,6 +544,29 @@ struct ieee80211_hdr_4addr { u8 payload[0]; } __attribute__ ((packed)); +struct ieee80211_hdr_3addrqos { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 payload[0]; + u16 qos_ctl; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addrqos { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; + u16 qos_ctl; +} __attribute__ ((packed)); + struct ieee80211_info_element { u8 id; u8 len; @@ -641,9 +668,68 @@ struct ieee80211_txb { #define MAX_WPA_IE_LEN 64 -#define NETWORK_EMPTY_ESSID (1<<0) -#define NETWORK_HAS_OFDM (1<<1) -#define NETWORK_HAS_CCK (1<<2) +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | NETWORK_HAS_QOS_INFORMATION) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 + +struct ieee80211_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __attribute__ ((packed)); + +struct ieee80211_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + u16 tx_op_limit; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameter_info { + struct ieee80211_qos_information_element info_element; + u8 reserved; + struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameters { + u16 cw_min[QOS_QUEUE_NUM]; + u16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + u16 tx_op_limit[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_data { + struct ieee80211_qos_parameters parameters; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct ieee80211_tim_parameters { + u8 tim_count; + u8 tim_period; +} __attribute__ ((packed)); + +/*******************************************************/ struct ieee80211_network { /* These entries are used to identify a unique network */ @@ -653,6 +739,8 @@ struct ieee80211_network { u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid_len; + struct ieee80211_qos_data qos_data; + /* These are network statistics */ struct ieee80211_rx_stats stats; u16 capability; @@ -672,6 +760,7 @@ struct ieee80211_network { size_t wpa_ie_len; u8 rsn_ie[MAX_WPA_IE_LEN]; size_t rsn_ie_len; + struct ieee80211_tim_parameters tim; struct list_head list; }; @@ -769,10 +858,13 @@ struct ieee80211_device { void (*set_security) (struct net_device * dev, struct ieee80211_security * sec); int (*hard_start_xmit) (struct ieee80211_txb * txb, - struct net_device * dev); + struct net_device * dev, int pri); int (*reset_port) (struct net_device * dev); int (*is_queue_full) (struct net_device * dev, int pri); + int (*handle_management) (struct net_device * dev, + struct ieee80211_network * network, u16 type); + /* Typical STA methods */ int (*handle_auth) (struct net_device * dev, struct ieee80211_auth * auth); @@ -854,11 +946,14 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, extern inline int ieee80211_get_hdrlen(u16 fc) { int hdrlen = IEEE80211_3ADDR_LEN; + u16 stype = WLAN_FC_GET_STYPE(fc); switch (WLAN_FC_GET_TYPE(fc)) { case IEEE80211_FTYPE_DATA: if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) hdrlen = IEEE80211_4ADDR_LEN; + if (stype & IEEE80211_STYPE_QOS_DATA) + hdrlen += 2; break; case IEEE80211_FTYPE_CTL: switch (WLAN_FC_GET_STYPE(fc)) { diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index d1ae28280d7e..2c4613527dfd 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -534,6 +534,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* Nullfunc frames may have PS-bit set, so they must be passed to * hostap_handle_sta_rx() before being dropped here. */ + + stype &= ~IEEE80211_STYPE_QOS_DATA; + if (stype != IEEE80211_STYPE_DATA && stype != IEEE80211_STYPE_DATA_CFACK && stype != IEEE80211_STYPE_DATA_CFPOLL && @@ -758,6 +761,264 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +/* +* Make ther structure we read from the beacon packet has +* the right values +*/ +static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element + *info_element, int sub_type) +{ + + if (info_element->qui_subtype != sub_type) + return -1; + if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) + return -1; + if (info_element->qui_type != QOS_OUI_TYPE) + return -1; + if (info_element->version != QOS_VERSION_1) + return -1; + + return 0; +} + +/* + * Parse a QoS parameter element + */ +static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info + *element_param, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; + + if ((info_element == NULL) || (element_param == NULL)) + return -1; + + if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { + memcpy(element_param->info_element.qui, info_element->data, + info_element->len); + element_param->info_element.elementID = info_element->id; + element_param->info_element.length = info_element->len; + } else + ret = -1; + if (ret == 0) + ret = ieee80211_verify_qos_info(&element_param->info_element, + QOS_OUI_PARAM_SUB_TYPE); + return ret; +} + +/* + * Parse a QoS information element + */ +static int ieee80211_read_qos_info_element(struct + ieee80211_qos_information_element + *element_info, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_information_element) - 2; + + if (element_info == NULL) + return -1; + if (info_element == NULL) + return -1; + + if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { + memcpy(element_info->qui, info_element->data, + info_element->len); + element_info->elementID = info_element->id; + element_info->length = info_element->len; + } else + ret = -1; + + if (ret == 0) + ret = ieee80211_verify_qos_info(element_info, + QOS_OUI_INFO_SUB_TYPE); + return ret; +} + +/* + * Write QoS parameters from the ac parameters. + */ +static int ieee80211_qos_convert_ac_to_parameters(struct + ieee80211_qos_parameter_info + *param_elm, struct + ieee80211_qos_parameters + *qos_param) +{ + int rc = 0; + int i; + struct ieee80211_qos_ac_parameter *ac_params; + u32 txop; + u8 cw_min; + u8 cw_max; + + for (i = 0; i < QOS_QUEUE_NUM; i++) { + ac_params = &(param_elm->ac_params_record[i]); + + qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F; + qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2; + + cw_min = ac_params->ecw_min_max & 0x0F; + qos_param->cw_min[i] = (u16) ((1 << cw_min) - 1); + + cw_max = (ac_params->ecw_min_max & 0xF0) >> 4; + qos_param->cw_max[i] = (u16) ((1 << cw_max) - 1); + + qos_param->flag[i] = + (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; + + txop = le16_to_cpu(ac_params->tx_op_limit) * 32; + qos_param->tx_op_limit[i] = (u16) txop; + } + return rc; +} + +/* + * we have a generic data element which it may contain QoS information or + * parameters element. check the information element length to decide + * which type to read + */ +static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element + *info_element, + struct ieee80211_network *network) +{ + int rc = 0; + struct ieee80211_qos_parameters *qos_param = NULL; + struct ieee80211_qos_information_element qos_info_element; + + rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); + + if (rc == 0) { + network->qos_data.param_count = qos_info_element.ac_info & 0x0F; + network->flags |= NETWORK_HAS_QOS_INFORMATION; + } else { + struct ieee80211_qos_parameter_info param_element; + + rc = ieee80211_read_qos_param_element(¶m_element, + info_element); + if (rc == 0) { + qos_param = &(network->qos_data.parameters); + ieee80211_qos_convert_ac_to_parameters(¶m_element, + qos_param); + network->flags |= NETWORK_HAS_QOS_PARAMETERS; + network->qos_data.param_count = + param_element.info_element.ac_info & 0x0F; + } + } + + if (rc == 0) { + IEEE80211_DEBUG_QOS("QoS is supported\n"); + network->qos_data.supported = 1; + } + return rc; +} + +static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response + *frame, struct ieee80211_rx_stats *stats) +{ + struct ieee80211_network network_resp; + struct ieee80211_network *network = &network_resp; + struct ieee80211_info_element *info_element; + struct net_device *dev = ieee->dev; + u16 left; + + network->flags = 0; + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; + + //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); + network->atim_window = le16_to_cpu(frame->aid); + network->listen_interval = le16_to_cpu(frame->status); + + info_element = frame->info_element; + left = stats->len - sizeof(*frame); + + while (left >= sizeof(struct ieee80211_info_element)) { + if (sizeof(struct ieee80211_info_element) + + info_element->len > left) { + IEEE80211_DEBUG_QOS("ASSOC RESP: parse failed: " + "info_element->len + 2 > left : " + "info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(struct + ieee80211_info_element), + left, info_element->id); + return 1; + } + + switch (info_element->id) { + case MFIE_TYPE_SSID: + if (ieee80211_is_empty_essid(info_element->data, + info_element->len)) { + network->flags |= NETWORK_EMPTY_ESSID; + break; + } + + network->ssid_len = min(info_element->len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(network->ssid, info_element->data, + network->ssid_len); + if (network->ssid_len < IW_ESSID_MAX_SIZE) + memset(network->ssid + network->ssid_len, 0, + IW_ESSID_MAX_SIZE - network->ssid_len); + + IEEE80211_DEBUG_QOS("MFIE_TYPE_SSID: '%s' len=%d.\n", + network->ssid, network->ssid_len); + break; + + case MFIE_TYPE_TIM: + IEEE80211_DEBUG_QOS("MFIE_TYPE_TIM: ignored\n"); + break; + + case MFIE_TYPE_IBSS_SET: + IEEE80211_DEBUG_QOS("MFIE_TYPE_IBSS_SET: ignored\n"); + break; + + case MFIE_TYPE_CHALLENGE: + IEEE80211_DEBUG_QOS("MFIE_TYPE_CHALLENGE: ignored\n"); + break; + + case MFIE_TYPE_GENERIC: + IEEE80211_DEBUG_QOS("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + ieee80211_parse_qos_info_param_IE(info_element, + network); + break; + + case MFIE_TYPE_RSN: + IEEE80211_DEBUG_QOS("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + break; + + case MFIE_TYPE_QOS_PARAMETER: + printk("QoS Error need to parse QOS_PARAMETER IE\n"); + break; + + default: + IEEE80211_DEBUG_QOS("unsupported IE %d\n", + info_element->id); + break; + } + + left -= sizeof(struct ieee80211_info_element) + + info_element->len; + info_element = (struct ieee80211_info_element *) + &info_element->data[info_element->len]; + } + + if (ieee->handle_assoc_response != NULL) + ieee->handle_assoc_response(dev, frame, network); + + return 0; +} + +/***************************************************/ + static inline int ieee80211_is_ofdm_rate(u8 rate) { switch (rate & ~IEEE80211_BASIC_RATE_MASK) { @@ -786,6 +1047,9 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i struct ieee80211_info_element *info_element; u16 left; u8 i; + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; /* Pull out fixed field data */ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); @@ -813,13 +1077,11 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i info_element = beacon->info_element; left = stats->len - sizeof(*beacon); - while (left >= sizeof(struct ieee80211_info_element)) { - if (sizeof(struct ieee80211_info_element) + info_element->len > - left) { + while (left >= sizeof(*info_element)) { + if (sizeof(*info_element) + info_element->len > left) { IEEE80211_DEBUG_SCAN ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", - info_element->len + - sizeof(struct ieee80211_info_element), left); + info_element->len + sizeof(*info_element), left); return 1; } @@ -847,15 +1109,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i #ifdef CONFIG_IEEE80211_DEBUG p = rates_str; #endif - network->rates_len = - min(info_element->len, MAX_RATES_LENGTH); + network->rates_len = min(info_element->len, + MAX_RATES_LENGTH); for (i = 0; i < network->rates_len; i++) { network->rates[i] = info_element->data[i]; #ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, - sizeof(rates_str) - (p - - rates_str), - "%02X ", network->rates[i]); + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); #endif if (ieee80211_is_ofdm_rate (info_element->data[i])) { @@ -875,15 +1136,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i #ifdef CONFIG_IEEE80211_DEBUG p = rates_str; #endif - network->rates_ex_len = - min(info_element->len, MAX_RATES_EX_LENGTH); + network->rates_ex_len = min(info_element->len, + MAX_RATES_EX_LENGTH); for (i = 0; i < network->rates_ex_len; i++) { network->rates_ex[i] = info_element->data[i]; #ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, - sizeof(rates_str) - (p - - rates_str), - "%02X ", network->rates[i]); + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); #endif if (ieee80211_is_ofdm_rate (info_element->data[i])) { @@ -929,6 +1189,10 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i case MFIE_TYPE_GENERIC: IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len); + if (!ieee80211_parse_qos_info_param_IE(info_element, + network)) + break; + if (info_element->len >= 4 && info_element->data[0] == 0x00 && info_element->data[1] == 0x50 && @@ -950,14 +1214,18 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->rsn_ie_len); break; + case MFIE_TYPE_QOS_PARAMETER: + printk(KERN_ERR + "QoS Error need to parse QOS_PARAMETER IE\n"); + break; + default: IEEE80211_DEBUG_SCAN("unsupported IE %d\n", info_element->id); break; } - left -= sizeof(struct ieee80211_info_element) + - info_element->len; + left -= sizeof(*info_element) + info_element->len; info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len]; } @@ -1004,6 +1272,9 @@ static inline int is_same_network(struct ieee80211_network *src, static inline void update_network(struct ieee80211_network *dst, struct ieee80211_network *src) { + int qos_active; + u8 old_param; + memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); dst->capability = src->capability; memcpy(dst->rates, src->rates, src->rates_len); @@ -1026,6 +1297,28 @@ static inline void update_network(struct ieee80211_network *dst, dst->rsn_ie_len = src->rsn_ie_len; dst->last_scanned = jiffies; + qos_active = src->qos_data.active; + old_param = dst->qos_data.old_param_count; + if (dst->flags & NETWORK_HAS_QOS_MASK) + memcpy(&dst->qos_data, &src->qos_data, + sizeof(struct ieee80211_qos_data)); + else { + dst->qos_data.supported = src->qos_data.supported; + dst->qos_data.param_count = src->qos_data.param_count; + } + + if (dst->qos_data.supported == 1) { + if (dst->ssid_len) + IEEE80211_DEBUG_QOS + ("QoS the network %s is QoS supported\n", + dst->ssid); + else + IEEE80211_DEBUG_QOS + ("QoS the network is QoS supported\n"); + } + dst->qos_data.active = qos_active; + dst->qos_data.old_param_count = old_param; + /* dst->last_associate is not overwritten */ } @@ -1167,6 +1460,9 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); + ieee80211_handle_assoc_resp(ieee, + (struct ieee80211_assoc_response *) + header, stats); break; case IEEE80211_STYPE_REASSOC_RESP: diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index e9efdd42ba37..aba72f9880a1 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -465,7 +465,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); if (txb) { - int ret = (*ieee->hard_start_xmit) (txb, dev); + int ret = (*ieee->hard_start_xmit) (txb, dev, priority); if (ret == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; @@ -500,6 +500,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, unsigned long flags; struct net_device_stats *stats = &ieee->stats; struct sk_buff *skb_frag; + int priority = -1; spin_lock_irqsave(&ieee->lock, flags); @@ -540,7 +541,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, spin_unlock_irqrestore(&ieee->lock, flags); if (txb) { - if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) { + if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; return 0; From 02cda6ae01814f58422c45259fb48136fbd7bcc1 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:56:38 -0500 Subject: [PATCH 0109/1939] [PATCH] ieee80211: Added ieee80211_geo to provide helper functions tree 385b391fc0d7c124cd0547fdb6183e9a0c333391 parent 97d7a47f76e72bedde7f402785559ed4c7a8e8e8 author James Ketrenos 1124447590 -0500 committer James Ketrenos 1127313735 -0500 Added ieee80211_geo to provide helper functions to drivers for implementing supported channel maps. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 46 +++++++++++ net/ieee80211/Makefile | 3 +- net/ieee80211/ieee80211_geo.c | 141 ++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 net/ieee80211/ieee80211_geo.c diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 72bd2b17eeb4..b3815fd810c8 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -781,6 +781,38 @@ enum ieee80211_state { #define CFG_IEEE80211_COMPUTE_FCS (1<<1) #define CFG_IEEE80211_RTS (1<<2) +#define IEEE80211_24GHZ_MIN_CHANNEL 1 +#define IEEE80211_24GHZ_MAX_CHANNEL 14 +#define IEEE80211_24GHZ_CHANNELS 14 + +#define IEEE80211_52GHZ_MIN_CHANNEL 36 +#define IEEE80211_52GHZ_MAX_CHANNEL 165 +#define IEEE80211_52GHZ_CHANNELS 32 + +enum { + IEEE80211_CH_PASSIVE_ONLY = (1 << 0), + IEEE80211_CH_B_ONLY = (1 << 2), + IEEE80211_CH_NO_IBSS = (1 << 3), + IEEE80211_CH_UNIFORM_SPREADING = (1 << 4), + IEEE80211_CH_RADAR_DETECT = (1 << 5), + IEEE80211_CH_INVALID = (1 << 6), +}; + +struct ieee80211_channel { + u16 freq; + u8 channel; + u8 flags; + u8 max_power; +}; + +struct ieee80211_geo { + u8 name[4]; + u8 bg_channels; + u8 a_channels; + struct ieee80211_channel bg[IEEE80211_24GHZ_CHANNELS]; + struct ieee80211_channel a[IEEE80211_52GHZ_CHANNELS]; +}; + struct ieee80211_device { struct net_device *dev; struct ieee80211_security sec; @@ -789,6 +821,8 @@ struct ieee80211_device { struct net_device_stats stats; struct ieee80211_stats ieee_stats; + struct ieee80211_geo geo; + /* Probe / Beacon management */ struct list_head network_free_list; struct list_head network_list; @@ -1005,6 +1039,18 @@ extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr_4addr *header, struct ieee80211_rx_stats *stats); +/* ieee80211_geo.c */ +extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device + *ieee); +extern int ieee80211_set_geo(struct ieee80211_device *ieee, + const struct ieee80211_geo *geo); + +extern int ieee80211_is_valid_channel(struct ieee80211_device *ieee, + u8 channel); +extern int ieee80211_channel_to_index(struct ieee80211_device *ieee, + u8 channel); +extern u8 ieee80211_freq_to_channel(struct ieee80211_device *ieee, u32 freq); + /* ieee80211_wx.c */ extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, struct iw_request_info *info, diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile index a6ccac5baea8..f988417121da 100644 --- a/net/ieee80211/Makefile +++ b/net/ieee80211/Makefile @@ -7,5 +7,6 @@ ieee80211-objs := \ ieee80211_module.o \ ieee80211_tx.o \ ieee80211_rx.o \ - ieee80211_wx.o + ieee80211_wx.o \ + ieee80211_geo.o diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c new file mode 100644 index 000000000000..c4b54ef8f6d5 --- /dev/null +++ b/net/ieee80211/ieee80211_geo.c @@ -0,0 +1,141 @@ +/****************************************************************************** + + Copyright(c) 2005 Intel Corporation. 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 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 full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + /* NOTE: If G mode is currently supported but + * this is a B only channel, we don't see it + * as valid. */ + if ((ieee->geo.bg[i].channel == channel) && + (!(ieee->mode & IEEE_G) || + !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) + return IEEE80211_24GHZ_BAND; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].channel == channel) + return IEEE80211_52GHZ_BAND; + + return 0; +} + +int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].channel == channel) + return i; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].channel == channel) + return i; + + return -1; +} + +u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + freq /= 100000; + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].freq == freq) + return ieee->geo.bg[i].channel; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].freq == freq) + return ieee->geo.a[i].channel; + + return 0; +} + +int ieee80211_set_geo(struct ieee80211_device *ieee, + const struct ieee80211_geo *geo) +{ + memcpy(ieee->geo.name, geo->name, 3); + ieee->geo.name[3] = '\0'; + ieee->geo.bg_channels = geo->bg_channels; + ieee->geo.a_channels = geo->a_channels; + memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * + sizeof(struct ieee80211_channel)); + memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * + sizeof(struct ieee80211_channel)); + return 0; +} + +const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee) +{ + return &ieee->geo; +} + +EXPORT_SYMBOL(ieee80211_is_valid_channel); +EXPORT_SYMBOL(ieee80211_freq_to_channel); +EXPORT_SYMBOL(ieee80211_channel_to_index); +EXPORT_SYMBOL(ieee80211_set_geo); +EXPORT_SYMBOL(ieee80211_get_geo); From 3905ec4561b7b049e9c2e27311d072c356dbdee2 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:56:42 -0500 Subject: [PATCH 0110/1939] [PATCH] ieee80211: Added ieee80211_radiotap.h tree 383c59b2516a61f2683f02dfebbed0caf6ee5dc3 parent a04948f63fd96c4b875a43f78afad1a0874cc441 author Mike Kershaw 1124447833 -0500 committer James Ketrenos 1127313883 -0500 Added ieee80211_radiotap.h to enhance statistic reporting to user space from wireless drivers. Signed-off-by: Mike Kershaw Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/linux/if_arp.h | 1 + include/net/ieee80211_radiotap.h | 231 +++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 include/net/ieee80211_radiotap.h diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 0856548a2a08..a8b1a2071838 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -84,6 +84,7 @@ #define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ +#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h new file mode 100644 index 000000000000..429b73892a5f --- /dev/null +++ b/include/net/ieee80211_radiotap.h @@ -0,0 +1,231 @@ +/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ +/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ + +/*- + * Copyright (c) 2003, 2004 David Young. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of David Young may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID + * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +#ifndef IEEE80211RADIOTAP_H +#define IEEE80211RADIOTAP_H + +#include +#include + +/* Radiotap header version (from official NetBSD feed) */ +#define IEEE80211RADIOTAP_VERSION "1.5" +/* Base version of the radiotap packet header data */ +#define PKTHDR_RADIOTAP_VERSION 0 + +/* A generic radio capture format is desirable. There is one for + * Linux, but it is neither rigidly defined (there were not even + * units given for some fields) nor easily extensible. + * + * I suggest the following extensible radio capture format. It is + * based on a bitmap indicating which fields are present. + * + * I am trying to describe precisely what the application programmer + * should expect in the following, and for that reason I tell the + * units and origin of each measurement (where it applies), or else I + * use sufficiently weaselly language ("is a monotonically nondecreasing + * function of...") that I cannot set false expectations for lawyerly + * readers. + */ + +/* XXX tcpdump/libpcap do not tolerate variable-length headers, + * yet, so we pad every radiotap header to 64 bytes. Ugh. + */ +#define IEEE80211_RADIOTAP_HDRLEN 64 + +/* The radio capture header precedes the 802.11 header. */ +struct ieee80211_radiotap_header { + u8 it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + u8 it_pad; + u16 it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + u32 it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ +}; + +/* Name Data type Units + * ---- --------- ----- + * + * IEEE80211_RADIOTAP_TSFT u64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x u16 MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * + * IEEE80211_RADIOTAP_FHSS u16 see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE u8 500kb/s + * + * Tx/Rx data rate + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY u16 unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + * + * IEEE80211_RADIOTAP_TX_ATTENUATION u16 unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u16 decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + * + * IEEE80211_RADIOTAP_FLAGS u8 bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA u8 antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_FCS u32 data + * + * FCS from frame in network byte order. + */ +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_EXT = 31, +}; + +/* Channel flags. */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ + +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ + +/* Ugly macro to convert literal channel numbers into their mhz equivalents + * There are certianly some conditions that will break this (like feeding it '30') + * but they shouldn't arise since nothing talks on channel 30. */ +#define ieee80211chan2mhz(x) \ + (((x) <= 14) ? \ + (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ + ((x) + 1000) * 5) + +#endif /* IEEE80211_RADIOTAP_H */ From cdcfc210820b8e043cb606eddc145906185c6743 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:56:49 -0500 Subject: [PATCH 0111/1939] [PATCH] ieee80211: Additional fixes for endian-aware types tree 589bbb92ce7cdf7c2ae820b0ebd3f8fbf1baeee9 parent c6ce9081e79e8836a11e86e3d38297521a2420be author Jiri Benc 1125015310 -0400 committer James Ketrenos 1127313914 -0500 Additional fixes for endian-aware types Based on the application of __le16/__be16 changes already made w/ a prior patch by Michael Wu Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index b3815fd810c8..372a173d36df 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -503,68 +503,68 @@ enum ieee80211_mfie { * information to determine what type of underlying data type is actually * stored in the data. */ struct ieee80211_hdr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 payload[0]; } __attribute__ ((packed)); struct ieee80211_hdr_1addr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 payload[0]; } __attribute__ ((packed)); struct ieee80211_hdr_2addr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 payload[0]; } __attribute__ ((packed)); struct ieee80211_hdr_3addr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 payload[0]; } __attribute__ ((packed)); struct ieee80211_hdr_4addr { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; u8 payload[0]; } __attribute__ ((packed)); struct ieee80211_hdr_3addrqos { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 payload[0]; - u16 qos_ctl; + __le16 qos_ctl; } __attribute__ ((packed)); struct ieee80211_hdr_4addrqos { - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; u8 payload[0]; - u16 qos_ctl; + __le16 qos_ctl; } __attribute__ ((packed)); struct ieee80211_info_element { @@ -600,7 +600,7 @@ struct ieee80211_auth { struct ieee80211_disassoc { struct ieee80211_hdr_3addr header; - u16 reason_code; + __le16 reason_code; struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -622,8 +622,8 @@ struct ieee80211_probe_response { struct ieee80211_assoc_request { struct ieee80211_hdr_3addr header; - u16 capability; - u16 listen_interval; + __le16 capability; + __le16 listen_interval; struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -648,8 +648,8 @@ struct ieee80211_txb { u8 encrypted; u8 rts_included; u8 reserved; - u16 frag_size; - u16 payload_size; + __le16 frag_size; + __le16 payload_size; struct sk_buff *fragments[0]; }; @@ -699,7 +699,7 @@ struct ieee80211_qos_information_element { struct ieee80211_qos_ac_parameter { u8 aci_aifsn; u8 ecw_min_max; - u16 tx_op_limit; + __le16 tx_op_limit; } __attribute__ ((packed)); struct ieee80211_qos_parameter_info { @@ -709,11 +709,11 @@ struct ieee80211_qos_parameter_info { } __attribute__ ((packed)); struct ieee80211_qos_parameters { - u16 cw_min[QOS_QUEUE_NUM]; - u16 cw_max[QOS_QUEUE_NUM]; + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; u8 aifs[QOS_QUEUE_NUM]; u8 flag[QOS_QUEUE_NUM]; - u16 tx_op_limit[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; } __attribute__ ((packed)); struct ieee80211_qos_data { From 9ba7e0d1579485ce231594651b39c169029f5d67 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:24 -0500 Subject: [PATCH 0112/1939] [PATCH] ieee80211: "extern inline" to "static inline" tree bce04549ce0a8239d8083d8da5c3d12f7e1aecd9 parent b15a5153d5f1c75d9435d5ce19b52287059d5d54 author Adrian Bunk 1125026386 -0500 committer James Ketrenos 1127313953 -0500 "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 372a173d36df..9310b2e01d41 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -929,12 +929,12 @@ struct ieee80211_device { #define IEEE_G (1<<2) #define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) -extern inline void *ieee80211_priv(struct net_device *dev) +static inline void *ieee80211_priv(struct net_device *dev) { return ((struct ieee80211_device *)netdev_priv(dev))->priv; } -extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) +static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ if (essid_len == 1 && essid[0] == ' ') @@ -950,7 +950,7 @@ extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) return 1; } -extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, +static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) { /* @@ -977,7 +977,7 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, return 0; } -extern inline int ieee80211_get_hdrlen(u16 fc) +static inline int ieee80211_get_hdrlen(u16 fc) { int hdrlen = IEEE80211_3ADDR_LEN; u16 stype = WLAN_FC_GET_STYPE(fc); @@ -1005,7 +1005,7 @@ extern inline int ieee80211_get_hdrlen(u16 fc) return hdrlen; } -extern inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) +static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) { switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { case IEEE80211_1ADDR_LEN: @@ -1070,12 +1070,12 @@ extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, union iwreq_data *wrqu, char *extra); #endif -extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { ieee->scans++; } -extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +static inline int ieee80211_get_scans(struct ieee80211_device *ieee) { return ieee->scans; } From 42c94e43be27f8b9be9b5be491bae8af05e54dbd Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:29 -0500 Subject: [PATCH 0113/1939] [PATCH] ieee80211: Type-o, capbility definition for QoS, and ERP parsing tree 3ac0dd07b9972dfd68fee47ec2152d3d378de000 parent 9ada1d971d9829c34a14d98840080b7e69fdff6b author Mohamed Abbad 1126054379 -0500 committer James Ketrenos 1127314340 -0500 Type-o, capbility definition for QoS, and ERP parsing Added WLAN_CAPABILITY_QOS Fixed type-o WLAN_CAPABILITY_OSSS_OFDM -> WLAN_CAPABILITY_DSSS_OFDM Added ERP IE parsing to ieee80211_rx Added handle_probe_request callback. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 7 ++++++- net/ieee80211/ieee80211_rx.c | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 9310b2e01d41..931737eec6c6 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -225,8 +225,9 @@ struct ieee80211_snap_hdr { #define WLAN_CAPABILITY_PBCC (1<<6) #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_QOS (1<<9) #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) -#define WLAN_CAPABILITY_OSSS_OFDM (1<<13) +#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) /* Status codes */ enum ieee80211_statuscode { @@ -756,6 +757,7 @@ struct ieee80211_network { u16 beacon_interval; u16 listen_interval; u16 atim_window; + u8 erp_value; u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; u8 rsn_ie[MAX_WPA_IE_LEN]; @@ -910,6 +912,9 @@ struct ieee80211_device { int (*handle_probe_response) (struct net_device * dev, struct ieee80211_probe_response * resp, struct ieee80211_network * network); + int (*handle_probe_request) (struct net_device * dev, + struct ieee80211_probe_request * req, + struct ieee80211_rx_stats * stats); int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response * resp, struct ieee80211_network * network); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 2c4613527dfd..8bcdbabae3a1 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1065,6 +1065,8 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->ssid_len = 0; network->flags = 0; network->atim_window = 0; + network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? + 0x3 : 0x0; if (stats->freq == IEEE80211_52GHZ_BAND) { /* for A band (No DS info) */ @@ -1178,8 +1180,16 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n"); break; + case MFIE_TYPE_ERP_INFO: + network->erp_value = info_element->data[0]; + IEEE80211_DEBUG_SCAN("MFIE_TYPE_ERP_SET: %d\n", + network->erp_value); + break; + case MFIE_TYPE_IBSS_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); + network->atim_window = info_element->data[0]; + IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: %d\n", + network->atim_window); break; case MFIE_TYPE_CHALLENGE: @@ -1290,6 +1300,7 @@ static inline void update_network(struct ieee80211_network *dst, dst->beacon_interval = src->beacon_interval; dst->listen_interval = src->listen_interval; dst->atim_window = src->atim_window; + dst->erp_value = src->erp_value; memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); dst->wpa_ie_len = src->wpa_ie_len; @@ -1471,6 +1482,18 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, (header->frame_ctl))); break; + case IEEE80211_STYPE_PROBE_REQ: + IEEE80211_DEBUG_MGMT("recieved auth (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + if (ieee->handle_probe_request != NULL) + ieee->handle_probe_request(ieee->dev, + (struct + ieee80211_probe_request *) + header, stats); + break; + case IEEE80211_STYPE_PROBE_RESP: IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu From ccd0fda3a6d9186d067893114f65b8df758d5a1f Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:32 -0500 Subject: [PATCH 0114/1939] [PATCH] ieee80211: Mixed PTK/GTK CCMP/TKIP support tree 5c7559a1216ae1121487f6aed94a6017490729b3 parent c1ff4c22e5622c8987bf96c09158c4924cde98c2 author Hong Liu 1125482767 +0800 committer James Ketrenos 1127314427 -0500 Mixed PTK/GTK CCMP/TKIP support. Signed-off-by: Hong Liu Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 3 +++ net/ieee80211/ieee80211_module.c | 2 ++ net/ieee80211/ieee80211_rx.c | 5 +++-- net/ieee80211/ieee80211_wx.c | 13 ++++++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 931737eec6c6..ef85a96fce49 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -851,6 +851,9 @@ struct ieee80211_device { int host_encrypt; int host_encrypt_msdu; int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + int host_open_frag; int ieee802_1x; /* is IEEE 802.1X used */ diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index dddc61647390..941f1a13fafa 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -133,6 +133,8 @@ struct net_device *alloc_ieee80211(int sizeof_priv) /* Default to enabling full open WEP with host based encrypt/decrypt */ ieee->host_encrypt = 1; ieee->host_decrypt = 1; + ieee->host_mc_decrypt = 1; + /* Host fragementation in Open mode. Default is enabled. * Note: host fragmentation is always enabled if host encryption * is enabled. For cards can do hardware encryption, they must do diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 8bcdbabae3a1..65315bcd6e0a 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -409,7 +409,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 1; } - if (ieee->host_decrypt) { + if (is_multicast_ether_addr(hdr->addr1) ? ieee->host_mc_decrypt : + ieee->host_decrypt) { int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; @@ -1066,7 +1067,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->flags = 0; network->atim_window = 0; network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? - 0x3 : 0x0; + 0x3 : 0x0; if (stats->freq == IEEE80211_52GHZ_BAND) { /* for A band (No DS info) */ diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index db66217699d5..d710f47c4bd5 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -493,6 +493,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int i, idx, ret = 0; + int group_key = 0; const char *alg, *module; struct ieee80211_crypto_ops *ops; struct ieee80211_crypt_data **crypt; @@ -509,9 +510,10 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, } else idx = ieee->tx_keyidx; - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { crypt = &ieee->crypt[idx]; - else { + group_key = 1; + } else { if (idx != 0) return -EINVAL; if (ieee->iw_mode == IW_MODE_INFRA) @@ -542,7 +544,9 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, sec.enabled = 1; sec.encrypt = 1; - if (!(ieee->host_encrypt || ieee->host_decrypt)) + if (group_key ? !ieee->host_mc_decrypt : + !(ieee->host_encrypt || ieee->host_decrypt || + ieee->host_encrypt_msdu)) goto skip_host_crypt; switch (ext->alg) { @@ -632,6 +636,9 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_3; } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; } done: if (ieee->set_security) From 7dc888fefc053996354ca40602159e0ce5669f86 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:38 -0500 Subject: [PATCH 0115/1939] [PATCH] ieee80211: Keep auth mode unchanged after iwconfig key off/on cycle tree 2e6f6e7dc4f4eeb8e3dc265020016dd53e40578a parent ba2075794a089430b3dd7c90ff46ce1b67e9c7cc author Zhu Yi 1125551043 +0800 committer James Ketrenos 1127314475 -0500 [Bug 768] Keep auth mode unchanged after iwconfig key off/on cycle. Signed-off-by: Zhu Yi Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_wx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index d710f47c4bd5..65aa96da730d 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -412,11 +412,15 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.flags |= SEC_ACTIVE_KEY; } } - ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); - sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; - sec.flags |= SEC_AUTH_MODE; - IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? - "OPEN" : "SHARED KEY"); + if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { + ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); + sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : + WLAN_AUTH_SHARED_KEY; + sec.flags |= SEC_AUTH_MODE; + IEEE80211_DEBUG_WX("Auth: %s\n", + sec.auth_mode == WLAN_AUTH_OPEN ? + "OPEN" : "SHARED KEY"); + } /* For now we just support WEP, so only set that security level... * TODO: When WPA is added this is one place that needs to change */ From ebeaddcc02fd47d1dbb7f25318d046461d90e4af Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:43 -0500 Subject: [PATCH 0116/1939] [PATCH] ieee80211: Updated copyright dates tree 0d3e41e574fcb41b9da7f0b7e1d27ec350726654 parent dbe2885fe2f454d538eaaabefc741ded1026f476 author James Ketrenos 1126720499 -0500 committer James Ketrenos 1127314531 -0500 Updated copyright dates. NOTE: This is a split out of just the copyright updates from patch 24/29 in the prior series. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 +- net/ieee80211/ieee80211_module.c | 2 +- net/ieee80211/ieee80211_rx.c | 2 +- net/ieee80211/ieee80211_tx.c | 2 +- net/ieee80211/ieee80211_wx.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index ef85a96fce49..53809482a7e4 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -11,7 +11,7 @@ * * Adaption to a generic IEEE 802.11 stack by James Ketrenos * - * Copyright (c) 2004, Intel Corporation + * Copyright (c) 2004-2005, Intel Corporation * * 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 diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 941f1a13fafa..0ae91c9917cf 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(c) 2004 Intel Corporation. All rights reserved. + Copyright(c) 2004-2005 Intel Corporation. All rights reserved. Portions of this file are based on the WEP enablement code provided by the Host AP project hostap-drivers v0.1.3 diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 65315bcd6e0a..256d5524445c 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -5,7 +5,7 @@ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * * Copyright (c) 2002-2003, Jouni Malinen - * Copyright (c) 2004, Intel Corporation + * Copyright (c) 2004-2005, Intel Corporation * * 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 diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index aba72f9880a1..24ade5f68e02 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2005 Intel Corporation. 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 as diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 65aa96da730d..e28648e70cf1 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2004 Intel Corporation. All rights reserved. + Copyright(c) 2004-2005 Intel Corporation. All rights reserved. Portions of this file are based on the WEP enablement code provided by the Host AP project hostap-drivers v0.1.3 From d041674d62e1ad565f2fb6d53ae80b31d6656033 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:49 -0500 Subject: [PATCH 0117/1939] [PATCH] ieee80211: Updated hostap to be compatible with ieee80211_hdr changes tree 8ec97d9056ceaf0f845ed51175dd842b700baadd parent 329128457008ace3110c96971addf85a767dd5af author James Ketrenos 1126714484 -0500 committer James Ketrenos 1127316636 -0500 Updated hostap to be compatible with ieee80211_hdr changes. Change accomplished via: for i in hostap_ap.{c,h} hostap_80211_{t,r}x.c; do sed -i -e "s:ieee80211_hdr\([^_]\):ieee80211_hdr_4addr\1:g" \ drivers/net/wireless/hostap/$i done CC: Jouni Malinen Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_80211_rx.c | 40 +++++------ drivers/net/wireless/hostap/hostap_80211_tx.c | 20 +++--- drivers/net/wireless/hostap/hostap_ap.c | 66 +++++++++---------- drivers/net/wireless/hostap/hostap_ap.h | 6 +- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index b0501243b175..42e61c68c325 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -6,10 +6,10 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " "jiffies=%ld\n", @@ -51,7 +51,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, int hdrlen, phdrlen, head_need, tail_need; u16 fc; int prism_header, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -70,7 +70,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, phdrlen = 0; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { @@ -215,7 +215,7 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq, /* Called only as a tasklet (software IRQ) */ static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) +prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; @@ -229,7 +229,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + + sizeof(struct ieee80211_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */); @@ -267,7 +267,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) /* Called only as a tasklet (software IRQ) */ static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { u16 sc; unsigned int seq; @@ -441,7 +441,7 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, u16 stype) { if (local->iw_mode == IW_MODE_MASTER) { - hostap_update_sta_ps(local, (struct ieee80211_hdr *) + hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *) skb->data); } @@ -520,7 +520,7 @@ static inline struct net_device *prism2_rx_get_wds(local_info_t *local, static inline int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, +hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { /* FIX: is this really supposed to accept WDS frames only in Master @@ -579,13 +579,13 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) { struct net_device *dev = local->dev; u16 fc, ethertype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -619,13 +619,13 @@ static inline int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); if (local->tkip_countermeasures && @@ -658,13 +658,13 @@ static inline int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, int keyidx, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); @@ -689,7 +689,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; struct net_device *wds = NULL; @@ -716,7 +716,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, dev = local->ddev; iface = netdev_priv(dev); - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; stats = hostap_get_stats(dev); if (skb->len < 10) @@ -889,7 +889,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ @@ -941,7 +941,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; prism2_frag_cache_invalidate(local, hdr); } @@ -952,7 +952,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { if (local->ieee_802_1x && hostap_is_eapol_frame(local, skb)) { diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6358015f6526..6db45430288c 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,9 +1,9 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", name, skb->len, jiffies); @@ -41,7 +41,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; + struct ieee80211_hdr_4addr hdr; u16 fc, ethertype = 0; enum { WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME @@ -244,7 +244,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; iface = netdev_priv(dev); @@ -266,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) meta->iface = iface; if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { @@ -289,7 +289,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; int hdr_len, res; @@ -303,7 +303,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (local->tkip_countermeasures && crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " "TX packet to " MACSTR "\n", @@ -325,7 +325,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, return NULL; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); hdr_len = hostap_80211_get_hdrlen(fc); @@ -360,7 +360,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) ap_tx_ret tx_ret; struct hostap_skb_tx_data *meta; int no_encrypt = 0; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -403,7 +403,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_ret = hostap_handle_sta_tx(local, &tx); skb = tx.skb; meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); switch (tx_ret) { case AP_TX_CONTINUE: diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 930cef8367f2..070f7032edb5 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -591,14 +591,14 @@ static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (!ap->local->hostapd || !ap->local->apdev) { dev_kfree_skb(skb); return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* Pass the TX callback frame to the hostapd; use 802.11 header version @@ -623,7 +623,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -633,7 +633,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || @@ -692,7 +692,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -702,7 +702,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && @@ -757,12 +757,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; if (skb->len < 24) goto fail; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (ok) { spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); @@ -918,7 +918,7 @@ static void prism2_send_mgmt(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; struct sk_buff *skb; struct hostap_skb_tx_data *meta; @@ -944,7 +944,7 @@ static void prism2_send_mgmt(struct net_device *dev, fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(fc); - hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen); if (body) memcpy(skb_put(skb, body_len), body, body_len); @@ -1285,7 +1285,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; size_t hdrlen; struct ap_data *ap = local->ap; char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; @@ -1498,7 +1498,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int reassoc) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char body[12], *p, *lpos; int len, left; u16 *pos; @@ -1705,7 +1705,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); int len; u16 reason_code, *pos; @@ -1746,7 +1746,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len; u16 reason_code, *pos; @@ -1784,7 +1784,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; @@ -1801,7 +1801,7 @@ static void ap_handle_data_nullfunc(local_info_t *local, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; struct sta_info *sta; @@ -1860,7 +1860,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, /* Called only as a scheduled task for pending AP frames. */ static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; @@ -1979,7 +1979,7 @@ static void handle_wds_oper_queue(void *data) static void handle_beacon(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len, left; u16 *pos, beacon_int, capability; @@ -2137,11 +2137,11 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, struct net_device *dev = local->dev; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); @@ -2258,7 +2258,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, struct hostap_interface *iface; local_info_t *local; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -2268,7 +2268,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, local->stats.rx_packets++; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && @@ -2289,7 +2289,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, static void schedule_packet_send(local_info_t *local, struct sta_info *sta) { struct sk_buff *skb; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; if (skb_queue_empty(&sta->tx_buf)) @@ -2302,7 +2302,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) return; } - hdr = (struct ieee80211_hdr *) skb_put(skb, 16); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_ctl = __constant_cpu_to_le16( @@ -2685,7 +2685,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) struct sta_info *sta = NULL; struct sk_buff *skb = tx->skb; int set_tim, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; meta = (struct hostap_skb_tx_data *) skb->cb; @@ -2694,7 +2694,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) meta->iface->type == HOSTAP_INTERFACE_STA) goto out; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (hdr->addr1[0] & 0x01) { /* broadcast/multicast frame - no AP related processing */ @@ -2821,10 +2821,10 @@ void hostap_handle_sta_release(void *ptr) void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) { struct sta_info *sta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; spin_lock(&local->ap->sta_table_lock); @@ -2892,7 +2892,7 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, /* Called only as a tasklet (software IRQ). Called for each RX frame to update * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sta_info *sta; u16 fc; @@ -2925,12 +2925,12 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, int ret; struct sta_info *sta; u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (local->ap == NULL) return AP_RX_CONTINUE; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); @@ -3058,7 +3058,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr) { @@ -3160,7 +3160,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) /* Called only as a tasklet (software IRQ) */ int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct sta_info *sta; diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 816a52bcea8f..6d00df69c2e3 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -233,7 +233,7 @@ struct hostap_tx_data { ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); void hostap_handle_sta_release(void *ptr); void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr); typedef enum { AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED } ap_rx_ret; @@ -241,13 +241,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, +int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, +int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats); void hostap_update_rates(local_info_t *local); void hostap_add_wds_links(local_info_t *local); From 5bfc819b53ed67c76f33f969ab627070e85d87c1 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 12:23:51 -0500 Subject: [PATCH 0118/1939] [PATCH] ieee80211: Updated hostap to be compatible with extra_prefix_len changes tree 8c1676c8a15c08e6d4c718fc7cd42d9bf4cd8235 parent 0ccc3dd6469ed492578c184f47dde2baccde3593 author James Ketrenos 1126715240 -0500 committer James Ketrenos 1127316717 -0500 Updated hostap to be compatible with extra_prefix_len changes. Accomplished via: for i in hostap_ap.c hostap_80211_tx.c; do sed -i -e "s:\([.>]\)extra_prefix_len:\1extra_mpdu_prefix_len:g" \ -e "s:\([.>]\)extra_postfix_len:\1extra_mpdu_postfix_len:g" \ drivers/net/wireless/hostap/$i done CC: Jouni Malinen Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_80211_tx.c | 8 ++++---- drivers/net/wireless/hostap/hostap_ap.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6db45430288c..9d24f8a38ac5 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -317,10 +317,10 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (skb == NULL) return NULL; - if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || - skb_tailroom(skb) < crypt->ops->extra_postfix_len) && - pskb_expand_head(skb, crypt->ops->extra_prefix_len, - crypt->ops->extra_postfix_len, GFP_ATOMIC)) { + if ((skb_headroom(skb) < crypt->ops->extra_mpdu_prefix_len || + skb_tailroom(skb) < crypt->ops->extra_mpdu_postfix_len) && + pskb_expand_head(skb, crypt->ops->extra_mpdu_prefix_len, + crypt->ops->extra_mpdu_postfix_len, GFP_ATOMIC)) { kfree_skb(skb); return NULL; } diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 070f7032edb5..087d9269af34 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -1256,14 +1256,14 @@ static char * ap_auth_make_challenge(struct ap_data *ap) } skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_prefix_len + - ap->crypt->extra_postfix_len); + ap->crypt->extra_mpdu_prefix_len + + ap->crypt->extra_mpdu_postfix_len); if (skb == NULL) { kfree(tmpbuf); return NULL; } - skb_reserve(skb, ap->crypt->extra_prefix_len); + skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { @@ -1272,7 +1272,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap) return NULL; } - memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, + memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len, WLAN_AUTH_CHALLENGE_LEN); dev_kfree_skb(skb); From 9a01c16bd49071b2e7904d222cae71d5f8bf6bb5 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 14:33:32 -0500 Subject: [PATCH 0119/1939] [PATCH] ieee82011: Remove WIRELESS_EXT ifdefs Remove old WIRELESS_EXT version compatibility In-tree doesn't need to maintain backward compatibility. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 -- net/ieee80211/ieee80211_crypt_tkip.c | 23 ----------------------- net/ieee80211/ieee80211_wx.c | 2 -- 3 files changed, 27 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 53809482a7e4..61a23d38b429 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -1069,14 +1069,12 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *key); -#if WIRELESS_EXT > 17 extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); -#endif static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index f973d6cb8248..21022f195bab 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -515,7 +515,6 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, return 0; } -#if WIRELESS_EXT >= 18 static void ieee80211_michael_mic_failure(struct net_device *dev, struct ieee80211_hdr_4addr *hdr, int keyidx) @@ -536,28 +535,6 @@ static void ieee80211_michael_mic_failure(struct net_device *dev, wrqu.data.length = sizeof(ev); wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); } -#elif WIRELESS_EXT >= 15 -static void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr_4addr *hdr, - int keyidx) -{ - union iwreq_data wrqu; - char buf[128]; - - /* TODO: needed parameters: count, keyid, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" - MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); -} -#else /* WIRELESS_EXT >= 15 */ -static inline void ieee80211_michael_mic_failure(struct net_device *dev, struct ieee80211_hdr_4addr - *hdr, int keyidx) -{ -} -#endif /* WIRELESS_EXT >= 15 */ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, int hdr_len, void *priv) diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index e28648e70cf1..3dd2bbae0c24 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -488,7 +488,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } -#if WIRELESS_EXT > 17 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -722,7 +721,6 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, EXPORT_SYMBOL(ieee80211_wx_set_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_encodeext); -#endif EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_set_encode); From 8a4ae7f2e24bf99b61082ca45de8e54e70300b9d Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Wed, 21 Sep 2005 23:22:10 -0400 Subject: [PATCH 0120/1939] forcedeth: add hardware tx checksumming Recent forcedeth nics support checksum offloading for tx. The attached patch, written by Ayaz Abdulla, adds the support to the driver. It also cleans up the handling of the three dma ring entry formats that are supported by the driver. Signed-off-By: Manfred Spraul Signed-off-By: Jeff Garzik --- drivers/net/forcedeth.c | 71 +++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 6e042ecf6965..e5f480203675 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -95,6 +95,7 @@ * of nv_remove * 0.42: 06 Aug 2005: Fix lack of link speed initialization * in the second (and later) nv_open call + * 0.43: 10 Aug 2005: Add support for tx checksum. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -106,7 +107,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.41" +#define FORCEDETH_VERSION "0.43" #define DRV_NAME "forcedeth" #include @@ -145,6 +146,7 @@ #define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ enum { NvRegIrqStatus = 0x000, @@ -241,6 +243,9 @@ enum { #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 +#define NVREG_TXRXCTL_DESC_1 0 +#define NVREG_TXRXCTL_DESC_2 0x02100 +#define NVREG_TXRXCTL_DESC_3 0x02200 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -335,6 +340,8 @@ typedef union _ring_type { /* error and valid are the same for both */ #define NV_TX2_ERROR (1<<30) #define NV_TX2_VALID (1<<31) +#define NV_TX2_CHECKSUM_L3 (1<<27) +#define NV_TX2_CHECKSUM_L4 (1<<26) #define NV_RX_DESCRIPTORVALID (1<<16) #define NV_RX_MISSEDFRAME (1<<17) @@ -417,14 +424,14 @@ typedef union _ring_type { /* * desc_ver values: - * This field has two purposes: - * - Newer nics uses a different ring layout. The layout is selected by - * comparing np->desc_ver with DESC_VER_xy. - * - It contains bits that are forced on when writing to NvRegTxRxControl. + * The nic supports three different descriptor types: + * - DESC_VER_1: Original + * - DESC_VER_2: support for jumbo frames. + * - DESC_VER_3: 64-bit format. */ -#define DESC_VER_1 0x0 -#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) -#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_1 1 +#define DESC_VER_2 2 +#define DESC_VER_3 3 /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -491,6 +498,7 @@ struct fe_priv { u32 orig_mac[2]; u32 irqmask; u32 desc_ver; + u32 txrxctl_bits; void __iomem *base; @@ -786,10 +794,10 @@ static void nv_txrx_reset(struct net_device *dev) u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); - writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); - writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); } @@ -961,6 +969,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int nr = np->next_tx % TX_RING; + u32 tx_checksum = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); np->tx_skbuff[nr] = skb; np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, @@ -976,10 +985,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&np->lock); wmb(); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum); else - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum); + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission\n", dev->name, np->next_tx); { int j; @@ -997,7 +1006,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) netif_stop_queue(dev); spin_unlock_irq(&np->lock); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); return 0; } @@ -1408,7 +1417,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); pci_push(base); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(base); /* restart rx engine */ @@ -2115,9 +2124,9 @@ static int nv_open(struct net_device *dev) /* 5) continue setup */ writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); - writel(np->desc_ver, base + NvRegTxRxControl); + writel(np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); - writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); @@ -2315,18 +2324,26 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); } + np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_2; } else { /* original packet format */ np->desc_ver = DESC_VER_1; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_1; } np->pkt_limit = NV_PKTLIMIT_1; if (id->driver_data & DEV_HAS_LARGEDESC) np->pkt_limit = NV_PKTLIMIT_2; + if (id->driver_data & DEV_HAS_CHECKSUM) { + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + dev->features |= NETIF_F_HW_CSUM; + } + err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) @@ -2527,35 +2544,35 @@ static struct pci_device_id pci_tbl[] = { }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), @@ -2567,11 +2584,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, {0,}, }; From b8f114db84dac709080198e08a5564976afd6579 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Wed, 21 Sep 2005 14:54:51 -0500 Subject: [PATCH 0121/1939] [PATCH] powerpc: Merge asm-ppc*/dma.h This merges the asm-ppc*/dma.h files. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/setup.c | 3 +- include/{asm-ppc => asm-powerpc}/dma.h | 91 ++++--- include/asm-ppc64/dma.h | 329 ------------------------- 3 files changed, 57 insertions(+), 366 deletions(-) rename include/{asm-ppc => asm-powerpc}/dma.h (86%) delete mode 100644 include/asm-ppc64/dma.h diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 8b06b8e00332..77fecfbabe88 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -71,7 +71,8 @@ struct ide_machdep_calls ppc_ide_md; unsigned long boot_mem_size; unsigned long ISA_DMA_THRESHOLD; -unsigned long DMA_MODE_READ, DMA_MODE_WRITE; +unsigned int DMA_MODE_READ; +unsigned int DMA_MODE_WRITE; #ifdef CONFIG_PPC_MULTIPLATFORM int _machine = 0; diff --git a/include/asm-ppc/dma.h b/include/asm-powerpc/dma.h similarity index 86% rename from include/asm-ppc/dma.h rename to include/asm-powerpc/dma.h index cc8e5cd8c9d2..926378d2cd94 100644 --- a/include/asm-ppc/dma.h +++ b/include/asm-powerpc/dma.h @@ -1,18 +1,14 @@ +#ifndef _ASM_POWERPC_DMA_H +#define _ASM_POWERPC_DMA_H + /* - * include/asm-ppc/dma.h: Defines for using and allocating dma channels. + * Defines for using and allocating dma channels. * Written by Hennus Bergman, 1992. * High DMA channel support & info by Hannu Savolainen * and John Boyd, Nov. 1992. * Changes for ppc sound by Christoph Nadig */ -#ifdef __KERNEL__ - -#include -#include -#include -#include - /* * Note: Adapted for PowerPC by Gary Thomas * Modified by Cort Dougan @@ -25,8 +21,10 @@ * with a grain of salt. */ -#ifndef _ASM_DMA_H -#define _ASM_DMA_H +#include +#include +#include +#include #ifndef MAX_DMA_CHANNELS #define MAX_DMA_CHANNELS 8 @@ -34,11 +32,9 @@ /* The maximum address that we can perform a DMA transfer to on this platform */ /* Doesn't really apply... */ -#define MAX_DMA_ADDRESS 0xFFFFFFFF +#define MAX_DMA_ADDRESS (~0UL) -/* in arch/ppc/kernel/setup.c -- Cort */ -extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ; -extern unsigned long ISA_DMA_THRESHOLD; +#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER #define dma_outb outb_p @@ -171,7 +167,18 @@ extern long ppc_cs4232_dma, ppc_cs4232_dma2; #define DMA1_EXT_REG 0x40B #define DMA2_EXT_REG 0x4D6 +#ifndef __powerpc64__ + /* in arch/ppc/kernel/setup.c -- Cort */ + extern unsigned int DMA_MODE_WRITE; + extern unsigned int DMA_MODE_READ; + extern unsigned long ISA_DMA_THRESHOLD; +#else + #define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ + #define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#endif + #define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + #define DMA_AUTOINIT 0x10 extern spinlock_t dma_spin_lock; @@ -200,8 +207,9 @@ static __inline__ void enable_dma(unsigned int dmanr) if (dmanr <= 3) { dma_outb(dmanr, DMA1_MASK_REG); dma_outb(ucDmaCmd, DMA1_CMD_REG); /* Enable group */ - } else + } else { dma_outb(dmanr & 3, DMA2_MASK_REG); + } } static __inline__ void disable_dma(unsigned int dmanr) @@ -290,19 +298,26 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr) static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys) { if (dmanr <= 3) { - dma_outb(phys & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE); - dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE); + dma_outb(phys & 0xff, + ((dmanr & 3) << 1) + IO_DMA1_BASE); + dma_outb((phys >> 8) & 0xff, + ((dmanr & 3) << 1) + IO_DMA1_BASE); } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) { - dma_outb(phys & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE); - dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE); + dma_outb(phys & 0xff, + ((dmanr & 3) << 2) + IO_DMA2_BASE); + dma_outb((phys >> 8) & 0xff, + ((dmanr & 3) << 2) + IO_DMA2_BASE); dma_outb((dmanr & 3), DMA2_EXT_REG); } else { - dma_outb((phys >> 1) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE); - dma_outb((phys >> 9) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE); + dma_outb((phys >> 1) & 0xff, + ((dmanr & 3) << 2) + IO_DMA2_BASE); + dma_outb((phys >> 9) & 0xff, + ((dmanr & 3) << 2) + IO_DMA2_BASE); } set_dma_page(dmanr, phys >> 16); } + /* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for * a specific DMA channel. * You must ensure the parameters are valid. @@ -315,21 +330,24 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) { count--; if (dmanr <= 3) { - dma_outb(count & 0xff, ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE); - dma_outb((count >> 8) & 0xff, ((dmanr & 3) << 1) + 1 + - IO_DMA1_BASE); + dma_outb(count & 0xff, + ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE); + dma_outb((count >> 8) & 0xff, + ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE); } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) { - dma_outb(count & 0xff, ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); - dma_outb((count >> 8) & 0xff, ((dmanr & 3) << 2) + 2 + - IO_DMA2_BASE); + dma_outb(count & 0xff, + ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); + dma_outb((count >> 8) & 0xff, + ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); } else { - dma_outb((count >> 1) & 0xff, ((dmanr & 3) << 2) + 2 + - IO_DMA2_BASE); - dma_outb((count >> 9) & 0xff, ((dmanr & 3) << 2) + 2 + - IO_DMA2_BASE); + dma_outb((count >> 1) & 0xff, + ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); + dma_outb((count >> 9) & 0xff, + ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); } } + /* Get DMA residue count. After a DMA transfer, this * should return zero. Reading this while a DMA transfer is * still in progress will return unpredictable results. @@ -340,8 +358,8 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) */ static __inline__ int get_dma_residue(unsigned int dmanr) { - unsigned int io_port = (dmanr <= 3) ? - ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE + unsigned int io_port = (dmanr <= 3) + ? ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE : ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE; /* using short to get 16-bit wrap around */ @@ -352,7 +370,6 @@ static __inline__ int get_dma_residue(unsigned int dmanr) return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2) ? count : (count << 1); - } /* These are in kernel/dma.c: */ @@ -367,5 +384,7 @@ extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) #endif -#endif /* _ASM_DMA_H */ -#endif /* __KERNEL__ */ + +#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ + +#endif /* _ASM_POWERPC_DMA_H */ diff --git a/include/asm-ppc64/dma.h b/include/asm-ppc64/dma.h deleted file mode 100644 index dfd1f69059ba..000000000000 --- a/include/asm-ppc64/dma.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - * Written by Hennus Bergman, 1992. - * High DMA channel support & info by Hannu Savolainen - * and John Boyd, Nov. 1992. - * Changes for ppc sound by Christoph Nadig - * - * 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_DMA_H -#define _ASM_DMA_H - -#include -#include -#include -#include - -#ifndef MAX_DMA_CHANNELS -#define MAX_DMA_CHANNELS 8 -#endif - -/* The maximum address that we can perform a DMA transfer to on this platform */ -/* Doesn't really apply... */ -#define MAX_DMA_ADDRESS (~0UL) - -#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) - -#define dma_outb outb -#define dma_inb inb - -/* - * NOTES about DMA transfers: - * - * controller 1: channels 0-3, byte operations, ports 00-1F - * controller 2: channels 4-7, word operations, ports C0-DF - * - * - ALL registers are 8 bits only, regardless of transfer size - * - channel 4 is not used - cascades 1 into 2. - * - channels 0-3 are byte - addresses/counts are for physical bytes - * - channels 5-7 are word - addresses/counts are for physical words - * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries - * - transfer count loaded to registers is 1 less than actual count - * - controller 2 offsets are all even (2x offsets for controller 1) - * - page registers for 5-7 don't use data bit 0, represent 128K pages - * - page registers for 0-3 use bit 0, represent 64K pages - * - * On PReP, DMA transfers are limited to the lower 16MB of _physical_ memory. - * On CHRP, the W83C553F (and VLSI Tollgate?) support full 32 bit addressing. - * Note that addresses loaded into registers must be _physical_ addresses, - * not logical addresses (which may differ if paging is active). - * - * Address mapping for channels 0-3: - * - * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * P7 ... P0 A7 ... A0 A7 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Address mapping for channels 5-7: - * - * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) - * | ... | \ \ ... \ \ \ ... \ \ - * | ... | \ \ ... \ \ \ ... \ (not used) - * | ... | \ \ ... \ \ \ ... \ - * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses - * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at - * the hardware level, so odd-byte transfers aren't possible). - * - * Transfer count (_not # bytes_) is limited to 64K, represented as actual - * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, - * and up to 128K bytes may be transferred on channels 5-7 in one operation. - * - */ - -/* 8237 DMA controllers */ -#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ -#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ - -/* DMA controller registers */ -#define DMA1_CMD_REG 0x08 /* command register (w) */ -#define DMA1_STAT_REG 0x08 /* status register (r) */ -#define DMA1_REQ_REG 0x09 /* request register (w) */ -#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ -#define DMA1_MODE_REG 0x0B /* mode register (w) */ -#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ -#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ -#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ - -#define DMA2_CMD_REG 0xD0 /* command register (w) */ -#define DMA2_STAT_REG 0xD0 /* status register (r) */ -#define DMA2_REQ_REG 0xD2 /* request register (w) */ -#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ -#define DMA2_MODE_REG 0xD6 /* mode register (w) */ -#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ -#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ -#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ - -#define DMA_ADDR_0 0x00 /* DMA address registers */ -#define DMA_ADDR_1 0x02 -#define DMA_ADDR_2 0x04 -#define DMA_ADDR_3 0x06 -#define DMA_ADDR_4 0xC0 -#define DMA_ADDR_5 0xC4 -#define DMA_ADDR_6 0xC8 -#define DMA_ADDR_7 0xCC - -#define DMA_CNT_0 0x01 /* DMA count registers */ -#define DMA_CNT_1 0x03 -#define DMA_CNT_2 0x05 -#define DMA_CNT_3 0x07 -#define DMA_CNT_4 0xC2 -#define DMA_CNT_5 0xC6 -#define DMA_CNT_6 0xCA -#define DMA_CNT_7 0xCE - -#define DMA_LO_PAGE_0 0x87 /* DMA page registers */ -#define DMA_LO_PAGE_1 0x83 -#define DMA_LO_PAGE_2 0x81 -#define DMA_LO_PAGE_3 0x82 -#define DMA_LO_PAGE_5 0x8B -#define DMA_LO_PAGE_6 0x89 -#define DMA_LO_PAGE_7 0x8A - -#define DMA_HI_PAGE_0 0x487 /* DMA page registers */ -#define DMA_HI_PAGE_1 0x483 -#define DMA_HI_PAGE_2 0x481 -#define DMA_HI_PAGE_3 0x482 -#define DMA_HI_PAGE_5 0x48B -#define DMA_HI_PAGE_6 0x489 -#define DMA_HI_PAGE_7 0x48A - -#define DMA1_EXT_REG 0x40B -#define DMA2_EXT_REG 0x4D6 - -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ -#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ - -#define DMA_AUTOINIT 0x10 - -extern spinlock_t dma_spin_lock; - -static __inline__ unsigned long claim_dma_lock(void) -{ - unsigned long flags; - spin_lock_irqsave(&dma_spin_lock, flags); - return flags; -} - -static __inline__ void release_dma_lock(unsigned long flags) -{ - spin_unlock_irqrestore(&dma_spin_lock, flags); -} - -/* enable/disable a specific DMA channel */ -static __inline__ void enable_dma(unsigned int dmanr) -{ - unsigned char ucDmaCmd=0x00; - - if (dmanr != 4) - { - dma_outb(0, DMA2_MASK_REG); /* This may not be enabled */ - dma_outb(ucDmaCmd, DMA2_CMD_REG); /* Enable group */ - } - if (dmanr<=3) - { - dma_outb(dmanr, DMA1_MASK_REG); - dma_outb(ucDmaCmd, DMA1_CMD_REG); /* Enable group */ - } else - { - dma_outb(dmanr & 3, DMA2_MASK_REG); - } -} - -static __inline__ void disable_dma(unsigned int dmanr) -{ - if (dmanr<=3) - dma_outb(dmanr | 4, DMA1_MASK_REG); - else - dma_outb((dmanr & 3) | 4, DMA2_MASK_REG); -} - -/* Clear the 'DMA Pointer Flip Flop'. - * Write 0 for LSB/MSB, 1 for MSB/LSB access. - * Use this once to initialize the FF to a known state. - * After that, keep track of it. :-) - * --- In order to do that, the DMA routines below should --- - * --- only be used while interrupts are disabled! --- - */ -static __inline__ void clear_dma_ff(unsigned int dmanr) -{ - if (dmanr<=3) - dma_outb(0, DMA1_CLEAR_FF_REG); - else - dma_outb(0, DMA2_CLEAR_FF_REG); -} - -/* set mode (above) for a specific DMA channel */ -static __inline__ void set_dma_mode(unsigned int dmanr, char mode) -{ - if (dmanr<=3) - dma_outb(mode | dmanr, DMA1_MODE_REG); - else - dma_outb(mode | (dmanr&3), DMA2_MODE_REG); -} - -/* Set only the page register bits of the transfer address. - * This is used for successive transfers when we know the contents of - * the lower 16 bits of the DMA current address register, but a 64k boundary - * may have been crossed. - */ -static __inline__ void set_dma_page(unsigned int dmanr, int pagenr) -{ - switch(dmanr) { - case 0: - dma_outb(pagenr, DMA_LO_PAGE_0); - dma_outb(pagenr>>8, DMA_HI_PAGE_0); - break; - case 1: - dma_outb(pagenr, DMA_LO_PAGE_1); - dma_outb(pagenr>>8, DMA_HI_PAGE_1); - break; - case 2: - dma_outb(pagenr, DMA_LO_PAGE_2); - dma_outb(pagenr>>8, DMA_HI_PAGE_2); - break; - case 3: - dma_outb(pagenr, DMA_LO_PAGE_3); - dma_outb(pagenr>>8, DMA_HI_PAGE_3); - break; - case 5: - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5); - dma_outb(pagenr>>8, DMA_HI_PAGE_5); - break; - case 6: - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6); - dma_outb(pagenr>>8, DMA_HI_PAGE_6); - break; - case 7: - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7); - dma_outb(pagenr>>8, DMA_HI_PAGE_7); - break; - } -} - - -/* Set transfer address & page bits for specific DMA channel. - * Assumes dma flipflop is clear. - */ -static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys) -{ - if (dmanr <= 3) { - dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - } else { - dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - } - set_dma_page(dmanr, phys>>16); -} - - -/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for - * a specific DMA channel. - * You must ensure the parameters are valid. - * NOTE: from a manual: "the number of transfers is one more - * than the initial word count"! This is taken into account. - * Assumes dma flip-flop is clear. - * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. - */ -static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) -{ - count--; - if (dmanr <= 3) { - dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - } else { - dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - } -} - - -/* Get DMA residue count. After a DMA transfer, this - * should return zero. Reading this while a DMA transfer is - * still in progress will return unpredictable results. - * If called before the channel has been used, it may return 1. - * Otherwise, it returns the number of _bytes_ left to transfer. - * - * Assumes DMA flip-flop is clear. - */ -static __inline__ int get_dma_residue(unsigned int dmanr) -{ - unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE - : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; - - /* using short to get 16-bit wrap around */ - unsigned short count; - - count = 1 + dma_inb(io_port); - count += dma_inb(io_port) << 8; - - return (dmanr <= 3)? count : (count<<1); -} - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it again */ - -#ifdef CONFIG_PCI -extern int isa_dma_bridge_buggy; -#else -#define isa_dma_bridge_buggy (0) -#endif -#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ -#endif /* _ASM_DMA_H */ From fa2ac7a25f1b11c4a695c9288339d0476ecfaf38 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 21 Sep 2005 15:44:11 -0500 Subject: [PATCH 0122/1939] [PATCH] powerpc: Fix compiling of ppc32 The merging of auxvec.h into asm-powerpc introduced the AT_SYSINFO_EHDR into the ppc32 build that is used for VDSO. However, we dont have VDSO support in the ppc32 tree at this time. Introducing this define causes a number of other things to get built with the assumption of VDSO, thus causing the compile errors for ppc32. Until we have VDSO on ppc32 we will leave AT_SYSINFO_EHDR a ppc64 only define. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- include/asm-powerpc/auxvec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-powerpc/auxvec.h b/include/asm-powerpc/auxvec.h index 19a099b62cd6..79d8c4732309 100644 --- a/include/asm-powerpc/auxvec.h +++ b/include/asm-powerpc/auxvec.h @@ -14,6 +14,8 @@ /* The vDSO location. We have to use the same value as x86 for glibc's * sake :-) */ +#ifdef __powerpc64__ #define AT_SYSINFO_EHDR 33 +#endif #endif From b671ad2befe37131af380183760862d5cbad858d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 21 Sep 2005 16:52:55 -0500 Subject: [PATCH 0123/1939] [PATCH] powerpc: merged hw_irq.h Merged hw_irq.h between ppc32 & ppc64. Added support to use the Book-E wrtee[i] instructions that allow modifying MSR[EE] atomically. Additionally, added get_irq_desc() macros to ppc32 to allow mask_irq(), unmask_irq(), and ack_irq() to be common between ppc32 & ppc64. Note: because 64-bit Book-E implementations only have a 32-bit MSR the macro's for Book-E need to come before the PPC64 macro's to ensure the right thing happends for 64-bit Book-E processors. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/hw_irq.h | 63 ++++++++++++--------- include/asm-ppc/hw_irq.h | 59 ------------------- include/asm-ppc/irq.h | 6 ++ 3 files changed, 43 insertions(+), 85 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/hw_irq.h (66%) delete mode 100644 include/asm-ppc/hw_irq.h diff --git a/include/asm-ppc64/hw_irq.h b/include/asm-powerpc/hw_irq.h similarity index 66% rename from include/asm-ppc64/hw_irq.h rename to include/asm-powerpc/hw_irq.h index c483897b8757..605a65e42063 100644 --- a/include/asm-ppc64/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h @@ -1,19 +1,15 @@ /* * Copyright (C) 1999 Cort Dougan - * - * Use inline IRQs where possible - Anton Blanchard - * - * 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_HW_IRQ_H +#define _ASM_POWERPC_HW_IRQ_H + #ifdef __KERNEL__ -#ifndef _PPC64_HW_IRQ_H -#define _PPC64_HW_IRQ_H #include #include +#include +#include #include extern void timer_interrupt(struct pt_regs *); @@ -33,45 +29,60 @@ extern void local_irq_restore(unsigned long); #else -#define local_save_flags(flags) ((flags) = mfmsr()) +#if defined(CONFIG_BOOKE) +#define SET_MSR_EE(x) mtmsr(x) +#define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") +#elif defined(__powerpc64__) +#define SET_MSR_EE(x) __mtmsrd(x, 1) #define local_irq_restore(flags) do { \ __asm__ __volatile__("": : :"memory"); \ __mtmsrd((flags), 1); \ } while(0) +#else +#define SET_MSR_EE(x) mtmsr(x) +#define local_irq_restore(flags) mtmsr(flags) +#endif static inline void local_irq_disable(void) { +#ifdef CONFIG_BOOKE + __asm__ __volatile__("wrteei 0": : :"memory"); +#else unsigned long msr; - msr = mfmsr(); - __mtmsrd(msr & ~MSR_EE, 1); __asm__ __volatile__("": : :"memory"); + msr = mfmsr(); + SET_MSR_EE(msr & ~MSR_EE); +#endif } static inline void local_irq_enable(void) { +#ifdef CONFIG_BOOKE + __asm__ __volatile__("wrteei 1": : :"memory"); +#else unsigned long msr; __asm__ __volatile__("": : :"memory"); msr = mfmsr(); - __mtmsrd(msr | MSR_EE, 1); + SET_MSR_EE(msr | MSR_EE); +#endif } -static inline void __do_save_and_cli(unsigned long *flags) +static inline void local_irq_save_ptr(unsigned long *flags) { unsigned long msr; msr = mfmsr(); *flags = msr; - __mtmsrd(msr & ~MSR_EE, 1); +#ifdef CONFIG_BOOKE + __asm__ __volatile__("wrteei 0": : :"memory"); +#else + SET_MSR_EE(msr & ~MSR_EE); +#endif __asm__ __volatile__("": : :"memory"); } -#define local_irq_save(flags) __do_save_and_cli(&flags) - -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - !(flags & MSR_EE); \ -}) +#define local_save_flags(flags) ((flags) = mfmsr()) +#define local_irq_save(flags) local_irq_save_ptr(&flags) +#define irqs_disabled() ((mfmsr() & MSR_EE) == 0) #endif /* CONFIG_PPC_ISERIES */ @@ -99,6 +110,6 @@ static inline void __do_save_and_cli(unsigned long *flags) */ struct hw_interrupt_type; static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} - -#endif /* _PPC64_HW_IRQ_H */ -#endif /* __KERNEL__ */ + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_HW_IRQ_H */ diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h deleted file mode 100644 index da0fa940adb3..000000000000 --- a/include/asm-ppc/hw_irq.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 1999 Cort Dougan - */ -#ifdef __KERNEL__ -#ifndef _PPC_HW_IRQ_H -#define _PPC_HW_IRQ_H - -#include -#include -#include - -extern void timer_interrupt(struct pt_regs *); - -#define irqs_disabled() ((mfmsr() & MSR_EE) == 0) - -static inline void local_irq_disable(void) -{ - unsigned long msr; - msr = mfmsr(); - mtmsr(msr & ~MSR_EE); - __asm__ __volatile__("": : :"memory"); -} - -static inline void local_irq_enable(void) -{ - unsigned long msr; - __asm__ __volatile__("": : :"memory"); - msr = mfmsr(); - mtmsr(msr | MSR_EE); -} - -static inline void local_irq_save_ptr(unsigned long *flags) -{ - unsigned long msr; - msr = mfmsr(); - *flags = msr; - mtmsr(msr & ~MSR_EE); - __asm__ __volatile__("": : :"memory"); -} - -#define local_save_flags(flags) ((flags) = mfmsr()) -#define local_irq_save(flags) local_irq_save_ptr(&flags) -#define local_irq_restore(flags) mtmsr(flags) - -extern void do_lost_interrupts(unsigned long); - -#define mask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->disable) irq_desc[irq].handler->disable(irq);}) -#define unmask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->enable) irq_desc[irq].handler->enable(irq);}) -#define ack_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->ack) irq_desc[irq].handler->ack(irq);}) - -/* Should we handle this via lost interrupts and IPIs or should we don't care like - * we do now ? --BenH. - */ -struct hw_interrupt_type; -static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} - - -#endif /* _PPC_HW_IRQ_H */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index bd9674807f05..137ea0cf34d3 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -24,6 +24,12 @@ */ #define ARCH_HAS_IRQ_PER_CPU +#define get_irq_desc(irq) (&irq_desc[(irq)]) + +/* Define a way to iterate across irqs. */ +#define for_each_irq(i) \ + for ((i) = 0; (i) < NR_IRQS; ++(i)) + #if defined(CONFIG_40x) #include From 31696160c7415b5a7efa650c7f1ca5c9623f5d8f Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:46 -0500 Subject: [PATCH 0124/1939] [PATCH] ieee80211: Added subsystem version string and reporting via MODULE_VERSION tree c1b50ac5d2d1f9b727c39c6bd86a7872f25a1127 parent 1bb997a3ac7dd1941e02426d2f70bd28993a82b7 author James Ketrenos 1126720779 -0500 committer James Ketrenos 1127314674 -0500 Added subsystem version string and reporting via MODULE_VERSION and pritnk during load. NOTE: This is the version support split out from patch 24/29 of the prior series. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 7 +++++++ net/ieee80211/ieee80211_module.c | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 61a23d38b429..4a1340b8341c 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -17,6 +17,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. + * + * API Version History + * 1.0.x -- Initial version + * 1.1.x -- Added radiotap, QoS, TIM, ieee80211_geo APIs, + * various structure changes, and crypto API init method */ #ifndef IEEE80211_H #define IEEE80211_H @@ -24,6 +29,8 @@ #include /* ARRAY_SIZE */ #include +#define IEEE80211_VERSION "git-1.1.5" + #define IEEE80211_DATA_LEN 2304 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section 6.2.1.1.2. diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 0ae91c9917cf..319312564167 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -53,12 +53,15 @@ #include -MODULE_DESCRIPTION("802.11 data/management/control stack"); -MODULE_AUTHOR - ("Copyright (C) 2004 Intel Corporation "); -MODULE_LICENSE("GPL"); +#define DRV_DESCRIPTION "802.11 data/management/control stack" +#define DRV_NAME "ieee80211" +#define DRV_VERSION IEEE80211_VERSION +#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation " -#define DRV_NAME "ieee80211" +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) { @@ -220,9 +223,11 @@ static int store_debug_level(struct file *file, const char __user * buffer, return strnlen(buf, len); } +#endif /* CONFIG_IEEE80211_DEBUG */ static int __init ieee80211_init(void) { +#ifdef CONFIG_IEEE80211_DEBUG struct proc_dir_entry *e; ieee80211_debug_level = debug; @@ -242,26 +247,33 @@ static int __init ieee80211_init(void) e->read_proc = show_debug_level; e->write_proc = store_debug_level; e->data = NULL; +#endif /* CONFIG_IEEE80211_DEBUG */ + + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); return 0; } static void __exit ieee80211_exit(void) { +#ifdef CONFIG_IEEE80211_DEBUG if (ieee80211_proc) { remove_proc_entry("debug_level", ieee80211_proc); remove_proc_entry(DRV_NAME, proc_net); ieee80211_proc = NULL; } +#endif /* CONFIG_IEEE80211_DEBUG */ } +#ifdef CONFIG_IEEE80211_DEBUG #include module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); +#endif /* CONFIG_IEEE80211_DEBUG */ module_exit(ieee80211_exit); module_init(ieee80211_init); -#endif const char *escape_essid(const char *essid, u8 essid_len) { From 31b59eaee8f8ec29d8cb6ac0c8eed086689d8030 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:49 -0500 Subject: [PATCH 0125/1939] [PATCH] ieee80211: Added handle_deauth() callback, enhanced tkip/ccmp support of varying hw/sw offload tree de81b55e78e85997642c651ea677078d0554a14f parent c8030da8c159f8b82712172a6748a42523aea83a author James Ketrenos 1127104380 -0500 committer James Ketrenos 1127315225 -0500 Added handle_deauth() callback. Enhanced crypt_{tkip,ccmp} to support varying splits of HW/SW offload. Changed channel freq to u32 from u16. Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 5 ++- include/net/ieee80211_crypt.h | 2 + net/ieee80211/ieee80211_crypt_ccmp.c | 41 +++++++++++++------ net/ieee80211/ieee80211_crypt_tkip.c | 60 +++++++++++++++++++--------- net/ieee80211/ieee80211_rx.c | 6 +++ net/ieee80211/ieee80211_tx.c | 18 ++++++++- 6 files changed, 99 insertions(+), 33 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4a1340b8341c..220a9e3c91fa 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -808,7 +808,7 @@ enum { }; struct ieee80211_channel { - u16 freq; + u32 freq; u8 channel; u8 flags; u8 max_power; @@ -862,6 +862,7 @@ struct ieee80211_device { int host_mc_decrypt; int host_open_frag; + int host_build_iv; int ieee802_1x; /* is IEEE 802.1X used */ /* WPA data */ @@ -914,6 +915,8 @@ struct ieee80211_device { /* Typical STA methods */ int (*handle_auth) (struct net_device * dev, struct ieee80211_auth * auth); + int (*handle_deauth) (struct net_device * dev, + struct ieee80211_auth * auth); int (*handle_disassoc) (struct net_device * dev, struct ieee80211_disassoc * assoc); int (*handle_beacon) (struct net_device * dev, diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 24e4912a263a..daf3b2c6b038 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -36,6 +36,8 @@ struct ieee80211_crypto_ops { /* deinitialize crypto context and free allocated private data */ void (*deinit) (void *priv); + int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv); + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return * value from decrypt_mpdu is passed as the keyidx value for * decrypt_msdu. skb must have enough head and tail room for the diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index a3dc5712b98b..081d8575dbb1 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -191,26 +191,18 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm, ieee80211_ccmp_aes_encrypt(tfm, b0, s0); } -static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_ccmp_data *key = priv; - int data_len, i, blocks, last, len; - u8 *pos, *mic; - struct ieee80211_hdr_4addr *hdr; - u8 *b0 = key->tx_b0; - u8 *b = key->tx_b; - u8 *e = key->tx_e; - u8 *s0 = key->tx_s0; + int i; + u8 *pos; - if (skb_headroom(skb) < CCMP_HDR_LEN || - skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) + if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) return -1; - data_len = skb->len - hdr_len; pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdr_len); pos += hdr_len; - mic = skb_put(skb, CCMP_MIC_LEN); i = CCMP_PN_LEN - 1; while (i >= 0) { @@ -229,6 +221,30 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) *pos++ = key->tx_pn[1]; *pos++ = key->tx_pn[0]; + return CCMP_HDR_LEN; +} + +static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_ccmp_data *key = priv; + int data_len, i, blocks, last, len; + u8 *pos, *mic; + struct ieee80211_hdr_4addr *hdr; + u8 *b0 = key->tx_b0; + u8 *b = key->tx_b; + u8 *e = key->tx_e; + u8 *s0 = key->tx_s0; + + if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + len = ieee80211_ccmp_hdr(skb, hdr_len, priv); + if (len < 0) + return -1; + + pos = skb->data + hdr_len + CCMP_HDR_LEN; + mic = skb_put(skb, CCMP_MIC_LEN); hdr = (struct ieee80211_hdr_4addr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); @@ -429,6 +445,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { .name = "CCMP", .init = ieee80211_ccmp_init, .deinit = ieee80211_ccmp_deinit, + .build_iv = ieee80211_ccmp_hdr, .encrypt_mpdu = ieee80211_ccmp_encrypt, .decrypt_mpdu = ieee80211_ccmp_decrypt, .encrypt_msdu = NULL, diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 21022f195bab..e0733050ae71 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -260,35 +260,27 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, #endif } -static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_tkip_data *tkey = priv; int len; - u8 rc4key[16], *pos, *icv; + u8 *rc4key, *pos, *icv; struct ieee80211_hdr_4addr *hdr; u32 crc; - struct scatterlist sg; hdr = (struct ieee80211_hdr_4addr *)skb->data; - if (tkey->ieee->tkip_countermeasures) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - tkey->ieee->dev->name, MAC_ARG(hdr->addr1)); - } - return -1; - } - - if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || - skb->len < hdr_len) - return -1; + if (skb_headroom(skb) < 8 || skb->len < hdr_len) + return NULL; if (!tkey->tx_phase1_done) { tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, tkey->tx_iv32); tkey->tx_phase1_done = 1; } + rc4key = kmalloc(16, GFP_ATOMIC); + if (!rc4key) + return NULL; tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); len = skb->len - hdr_len; @@ -297,9 +289,9 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += hdr_len; icv = skb_put(skb, 4); - *pos++ = rc4key[0]; - *pos++ = rc4key[1]; - *pos++ = rc4key[2]; + *pos++ = *rc4key; + *pos++ = *(rc4key + 1); + *pos++ = *(rc4key + 2); *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; *pos++ = tkey->tx_iv32 & 0xff; *pos++ = (tkey->tx_iv32 >> 8) & 0xff; @@ -312,6 +304,38 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; + return rc4key; +} + +static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + int len; + const u8 *rc4key; + u8 *pos; + struct scatterlist sg; + + if (tkey->ieee->tkip_countermeasures) { + if (net_ratelimit()) { + struct ieee80211_hdr_4addr *hdr = + (struct ieee80211_hdr_4addr *)skb->data; + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "TX packet to " MAC_FMT "\n", + tkey->ieee->dev->name, MAC_ARG(hdr->addr1)); + } + return -1; + } + + if (skb_tailroom(skb) < 4 || skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb->data + hdr_len; + + rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv); + if (!rc4key) + return -1; + crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 256d5524445c..fcf05bf677b8 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1534,6 +1534,12 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, header); break; + case IEEE80211_STYPE_DEAUTH: + printk("DEAUTH from AP\n"); + if (ieee->handle_deauth != NULL) + ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *) + header); + break; default: IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 24ade5f68e02..8d87897d7eb7 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -227,7 +227,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) rts_required; unsigned long flags; struct net_device_stats *stats = &ieee->stats; - int ether_type, encrypt, host_encrypt, host_encrypt_msdu; + int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; int bytes, fc, hdr_len; struct sk_buff *skb_frag; struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ @@ -263,8 +263,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ieee->sec.encrypt; + host_encrypt = ieee->host_encrypt && encrypt; host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt; + host_build_iv = ieee->host_build_iv && encrypt; if (!encrypt && ieee->ieee802_1x && ieee->drop_unencrypted && ether_type != ETH_P_PAE) { @@ -310,8 +312,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len + crypt->ops->extra_msdu_postfix_len; struct sk_buff *skb_new = dev_alloc_skb(len); + if (unlikely(!skb_new)) goto failed; + skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); snapped = 1; @@ -418,7 +422,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) for (; i < nr_frags; i++) { skb_frag = txb->fragments[i]; - if (host_encrypt) + if (host_encrypt || host_build_iv) skb_reserve(skb_frag, crypt->ops->extra_mpdu_prefix_len); @@ -453,6 +457,16 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) * to insert the IV between the header and the payload */ if (host_encrypt) ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + else if (host_build_iv) { + struct ieee80211_crypt_data *crypt; + + crypt = ieee->crypt[ieee->tx_keyidx]; + atomic_inc(&crypt->refcnt); + if (crypt->ops->build_iv) + crypt->ops->build_iv(skb_frag, hdr_len, + crypt->priv); + atomic_dec(&crypt->refcnt); + } if (ieee->config & (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) From e5658d3e8a347f4393a9403b0cec8d43fa6214b1 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:56 -0500 Subject: [PATCH 0126/1939] [PATCH] ieee80211: added IE comments, reason_code to reason, removed info_element from ieee80211_disassoc tree 0254e7c97cece038cd11b47a16027c6379e464fe parent a84f7713dc87ca1b51c6d53b391087663425a080 author James Ketrenos 1126661324 -0500 committer James Ketrenos 1127319069 -0500 Updated based on Michael Wu's patch and comments sent to netdev. Added IE comments to ieee80211_* frame structures. Changed reason_code to reason (consistency) Removed info_element from ieee80211_disassoc Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 220a9e3c91fa..4a381a074fdd 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -603,17 +603,21 @@ struct ieee80211_auth { __le16 algorithm; __le16 transaction; __le16 status; + /* challenge */ struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); struct ieee80211_disassoc { struct ieee80211_hdr_3addr header; - __le16 reason_code; - struct ieee80211_info_element info_element[0]; + __le16 reason; } __attribute__ ((packed)); +/* Alias deauth for disassoc */ +#define ieee82011_deauth ieee80211_disassoc + struct ieee80211_probe_request { struct ieee80211_hdr_3addr header; + /* SSID, supported rates */ struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -622,6 +626,8 @@ struct ieee80211_probe_response { u32 time_stamp[2]; __le16 beacon_interval; __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN */ struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -632,6 +638,7 @@ struct ieee80211_assoc_request { struct ieee80211_hdr_3addr header; __le16 capability; __le16 listen_interval; + /* SSID, supported rates, RSN */ struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); @@ -648,7 +655,8 @@ struct ieee80211_assoc_response { __le16 capability; __le16 status; __le16 aid; - struct ieee80211_info_element info_element[0]; /* supported rates */ + /* supported rates */ + struct ieee80211_info_element info_element[0]; } __attribute__ ((packed)); struct ieee80211_txb { From 6eb6edf04acd09e3cea09456913e8da59323b89e Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 22 Sep 2005 10:34:15 +0000 Subject: [PATCH 0127/1939] [PATCH] ieee80211: in-tree driver updates to sync with latest ieee80211 series Changed crypto method from requiring a struct ieee80211_device reference to the init handler. Instead we now have a get/set flags method for each crypto component. Setting of TKIP countermeasures can now be done via set_flags(IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 - include/net/ieee80211_crypt.h | 10 +++++++- net/ieee80211/ieee80211_crypt.c | 3 +-- net/ieee80211/ieee80211_crypt_ccmp.c | 2 +- net/ieee80211/ieee80211_crypt_tkip.c | 34 ++++++++++++++++++++-------- net/ieee80211/ieee80211_crypt_wep.c | 2 +- net/ieee80211/ieee80211_module.c | 1 - net/ieee80211/ieee80211_wx.c | 4 ++-- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4a381a074fdd..4851756202c5 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -876,7 +876,6 @@ struct ieee80211_device { /* WPA data */ int wpa_enabled; int drop_unencrypted; - int tkip_countermeasures; int privacy_invoked; size_t wpa_ie_len; u8 *wpa_ie; diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index daf3b2c6b038..0c9d859d912e 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -25,13 +25,17 @@ #include +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1<<0), +}; + struct ieee80211_crypto_ops { const char *name; /* init new crypto context (e.g., allocate private data space, * select IV, etc.); returns NULL on failure or pointer to allocated * private data on success */ - void *(*init) (struct ieee80211_device * ieee, int keyidx); + void *(*init) (int keyidx); /* deinitialize crypto context and free allocated private data */ void (*deinit) (void *priv); @@ -60,6 +64,10 @@ struct ieee80211_crypto_ops { * statistics */ char *(*print_stats) (char *p, void *priv); + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags)(void *priv); + unsigned long (*set_flags)(unsigned long flags, void *priv); + /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and * extra_postfix_len; encrypt need not use all this space, but diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index e26bcc918032..f3b6aa3be638 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -202,8 +202,7 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) return NULL; } -static void *ieee80211_crypt_null_init(struct ieee80211_device *ieee, - int keyidx) +static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; } diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 081d8575dbb1..05a853c13012 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -74,7 +74,7 @@ static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); } -static void *ieee80211_ccmp_init(struct ieee80211_device *ieee, int key_idx) +static void *ieee80211_ccmp_init(int key_idx) { struct ieee80211_ccmp_data *priv; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index e0733050ae71..2e34f29b7956 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -60,10 +60,24 @@ struct ieee80211_tkip_data { /* scratch buffers for virt_to_page() (crypto API) */ u8 rx_hdr[16], tx_hdr[16]; - struct ieee80211_device *ieee; + unsigned long flags; }; -static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx) +static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; + unsigned long old_flags = _priv->flags; + _priv->flags = flags; + return old_flags; +} + +static unsigned long ieee80211_tkip_get_flags(void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; + return _priv->flags; +} + +static void *ieee80211_tkip_init(int key_idx) { struct ieee80211_tkip_data *priv; @@ -72,8 +86,6 @@ static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx) goto fail; memset(priv, 0, sizeof(*priv)); - priv->ieee = ieee; - priv->key_idx = key_idx; priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); @@ -315,13 +327,13 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 *pos; struct scatterlist sg; - if (tkey->ieee->tkip_countermeasures) { + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + printk(KERN_DEBUG "TKIP countermeasures: dropped " "TX packet to " MAC_FMT "\n", - tkey->ieee->dev->name, MAC_ARG(hdr->addr1)); + MAC_ARG(hdr->addr1)); } return -1; } @@ -366,11 +378,11 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) hdr = (struct ieee80211_hdr_4addr *)skb->data; - if (tkey->ieee->tkip_countermeasures) { + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + printk(KERN_DEBUG "TKIP countermeasures: dropped " "received packet from " MAC_FMT "\n", - tkey->ieee->dev->name, MAC_ARG(hdr->addr2)); + MAC_ARG(hdr->addr2)); } return -1; } @@ -694,6 +706,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ .extra_mpdu_postfix_len = 4, /* ICV */ .extra_msdu_postfix_len = 8, /* MIC */ + .get_flags = ieee80211_tkip_get_flags, + .set_flags = ieee80211_tkip_set_flags, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 2aaeac1e02d7..7c08ed2f2628 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -37,7 +37,7 @@ struct prism2_wep_data { struct crypto_tfm *tfm; }; -static void *prism2_wep_init(struct ieee80211_device *ieee, int keyidx) +static void *prism2_wep_init(int keyidx) { struct prism2_wep_data *priv; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 319312564167..5714692e82b4 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -155,7 +155,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) spin_lock_init(&ieee->lock); ieee->wpa_enabled = 0; - ieee->tkip_countermeasures = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 3dd2bbae0c24..ee7a70a13250 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -355,7 +355,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(ieee, key); + new_crypt->priv = new_crypt->ops->init(key); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); @@ -598,7 +598,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); new_crypt->ops = ops; if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(ieee, idx); + new_crypt->priv = new_crypt->ops->init(idx); if (new_crypt->priv == NULL) { kfree(new_crypt); ret = -EINVAL; From af9288a707b609cdb1069cfe5bde0d6567c12c31 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 22 Sep 2005 15:43:07 -0400 Subject: [PATCH 0128/1939] ieee80211: update orinoco, wl3501 drivers for latest struct naming --- drivers/net/wireless/orinoco.c | 2 +- drivers/net/wireless/wl3501.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 77e93a225530..fc2fa4dc3a08 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -636,7 +636,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) /* Read the frame header */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(struct hermes_tx_descriptor) + - sizeof(struct ieee80211_hdr), + sizeof(struct ieee80211_hdr_4addr), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 7fcbe589c3f2..4303c50c2ab6 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; + struct ieee80211_hdr_4addr mac_hdr; } __attribute__ ((packed)); /* From 9f497581fda5fd804e9ebd7d8f6d80c3a0e9f883 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:10:59 +1000 Subject: [PATCH 0129/1939] ppc64 iSeries: Move iSeries ppc_md functions into a machdep_calls struct Move the iSeries machine specific calls into a machdep_calls struct like other platforms, rather than setting members of ppc_md explicitly. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 57 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 3ffefbbc6623..b5dcb08547bd 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -76,6 +76,8 @@ extern void ppcdbg_initialize(void); static void build_iSeries_Memory_Map(void); static void setup_iSeries_cache_sizes(void); static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); +static int iseries_shared_idle(void); +static int iseries_dedicated_idle(void); #ifdef CONFIG_PCI extern void iSeries_pci_final_fixup(void); #else @@ -695,6 +697,14 @@ static void __init iSeries_setup_arch(void) { unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; + if (get_paca()->lppaca.shared_proc) { + ppc_md.idle_loop = iseries_shared_idle; + printk(KERN_INFO "Using shared processor idle loop\n"); + } else { + ppc_md.idle_loop = iseries_dedicated_idle; + printk(KERN_INFO "Using dedicated idle loop\n"); + } + /* Add an eye catcher and the systemcfg layout version number */ strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); systemcfg->version.major = SYSTEMCFG_MAJOR; @@ -942,36 +952,25 @@ static int iseries_dedicated_idle(void) void __init iSeries_init_IRQ(void) { } #endif +struct machdep_calls __initdata iseries_md = { + .setup_arch = iSeries_setup_arch, + .get_cpuinfo = iSeries_get_cpuinfo, + .init_IRQ = iSeries_init_IRQ, + .get_irq = iSeries_get_irq, + .init_early = iSeries_init_early, + .pcibios_fixup = iSeries_pci_final_fixup, + .restart = iSeries_restart, + .power_off = iSeries_power_off, + .halt = iSeries_halt, + .get_boot_time = iSeries_get_boot_time, + .set_rtc_time = iSeries_set_rtc_time, + .get_rtc_time = iSeries_get_rtc_time, + .calibrate_decr = iSeries_calibrate_decr, + .progress = iSeries_progress, + /* XXX Implement enable_pmcs for iSeries */ +}; + void __init iSeries_early_setup(void) { iSeries_fixup_klimit(); - - ppc_md.setup_arch = iSeries_setup_arch; - ppc_md.get_cpuinfo = iSeries_get_cpuinfo; - ppc_md.init_IRQ = iSeries_init_IRQ; - ppc_md.get_irq = iSeries_get_irq; - ppc_md.init_early = iSeries_init_early, - - ppc_md.pcibios_fixup = iSeries_pci_final_fixup; - - ppc_md.restart = iSeries_restart; - ppc_md.power_off = iSeries_power_off; - ppc_md.halt = iSeries_halt; - - ppc_md.get_boot_time = iSeries_get_boot_time; - ppc_md.set_rtc_time = iSeries_set_rtc_time; - ppc_md.get_rtc_time = iSeries_get_rtc_time; - ppc_md.calibrate_decr = iSeries_calibrate_decr; - ppc_md.progress = iSeries_progress; - - /* XXX Implement enable_pmcs for iSeries */ - - if (get_paca()->lppaca.shared_proc) { - ppc_md.idle_loop = iseries_shared_idle; - printk(KERN_INFO "Using shared processor idle loop\n"); - } else { - ppc_md.idle_loop = iseries_dedicated_idle; - printk(KERN_INFO "Using dedicated idle loop\n"); - } } - From ba293fff085fde5b9f1b5a57c8abb1a8098d0c59 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:43:22 +1000 Subject: [PATCH 0130/1939] ppc46 iSeries: Make some generic irq code compile for iSeries In order to call finish_device_tree() on iSeries we need to define virt_irq_create_mapping(). We also need to set ppc64_interrupt_controller to something other than zero. If we want to do interrupt setup via the device tree on iSeries this code will need some serious work, but it's harmless to have it there as long as the nodes in the iSeries device tree don't cause it to be invoked. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_irq.c | 13 +++++++++++++ arch/ppc64/kernel/iSeries_setup.c | 2 ++ include/asm-ppc64/processor.h | 1 + 3 files changed, 16 insertions(+) diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c index 77376c1bd611..0170682a8ca5 100644 --- a/arch/ppc64/kernel/iSeries_irq.c +++ b/arch/ppc64/kernel/iSeries_irq.c @@ -351,3 +351,16 @@ int __init iSeries_allocate_IRQ(HvBusNumber busNumber, irq_desc[virtirq].handler = &iSeries_IRQ_handler; return virtirq; } + +int virt_irq_create_mapping(unsigned int real_irq) +{ + BUG(); /* Don't call this on iSeries, yet */ + + return 0; +} + +void virt_irq_init(void) +{ + return; +} + diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index b5dcb08547bd..75d8db4eaac6 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -321,6 +321,8 @@ static void __init iSeries_init_early(void) ppcdbg_initialize(); + ppc64_interrupt_controller = IC_ISERIES; + #if defined(CONFIG_BLK_DEV_INITRD) /* * If the init RAM disk has been configured and there is diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 4146189006e3..fe5cd2f5868a 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -291,6 +291,7 @@ #define IC_OPEN_PIC 1 #define IC_PPC_XIC 2 #define IC_BPA_IIC 3 +#define IC_ISERIES 4 #define XGLUE(a,b) a##b #define GLUE(a,b) XGLUE(a,b) From 4c55130b2aa93370f1bf52d2304394e91cf8ee39 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:47:58 +1000 Subject: [PATCH 0131/1939] ppc64 iSeries: Update create_pte_mapping to replace iSeries_bolt_kernel() early_setup() calls htab_initialize() which is similar, but not identical to iSeries_bolt_kernel(). On iSeries the Hypervisor has already inserted some ptes for us, and we simply have to detect that and bolt them. iSeries_hpte_bolt_or_insert() implements that logic. For the case of a non-existing pte we just call iSeries_hpte_insert(). This appears to work, although it's not entirely equivalent to the old code in iSeries_make_pte() which panicked if we got a secondary slot. Not sure if that's important. Finally we call iSeries_hpte_bolt_or_insert() from create_pte_mapping(), which is called from htab_initialize() for each lmb region. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_htab.c | 19 ++++++++++ arch/ppc64/kernel/iSeries_setup.c | 60 ------------------------------- arch/ppc64/mm/hash_utils.c | 15 +++++--- include/asm-ppc64/mmu.h | 4 +++ 4 files changed, 34 insertions(+), 64 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c index 2192055a90a0..9a2be3abf349 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/ppc64/kernel/iSeries_htab.c @@ -84,6 +84,25 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, return (secondary << 3) | (slot & 7); } +long iSeries_hpte_bolt_or_insert(unsigned long hpte_group, + unsigned long va, unsigned long prpn, unsigned long vflags, + unsigned long rflags) +{ + long slot; + hpte_t lhpte; + + slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT); + + if (lhpte.v & HPTE_V_VALID) { + /* Bolt the existing HPTE */ + HvCallHpt_setSwBits(slot, 0x10, 0); + HvCallHpt_setPp(slot, PP_RWXX); + return 0; + } + + return iSeries_hpte_insert(hpte_group, va, prpn, vflags, rflags); +} + static unsigned long iSeries_hpte_getword0(unsigned long slot) { hpte_t hpte; diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 75d8db4eaac6..49d0f9999682 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -75,7 +75,6 @@ extern void ppcdbg_initialize(void); static void build_iSeries_Memory_Map(void); static void setup_iSeries_cache_sizes(void); -static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); static int iseries_shared_idle(void); static int iseries_dedicated_idle(void); #ifdef CONFIG_PCI @@ -383,9 +382,6 @@ static void __init iSeries_init_early(void) } } - /* Bolt kernel mappings for all of memory (or just a bit if we've got a limit) */ - iSeries_bolt_kernel(0, systemcfg->physicalMemorySize); - lmb_init(); lmb_add(0, systemcfg->physicalMemorySize); lmb_analyze(); @@ -636,62 +632,6 @@ static void __init setup_iSeries_cache_sizes(void) (unsigned int)ppc64_caches.iline_size); } -/* - * Create a pte. Used during initialization only. - */ -static void iSeries_make_pte(unsigned long va, unsigned long pa, - int mode) -{ - hpte_t local_hpte, rhpte; - unsigned long hash, vpn; - long slot; - - vpn = va >> PAGE_SHIFT; - hash = hpt_hash(vpn, 0); - - local_hpte.r = pa | mode; - local_hpte.v = ((va >> 23) << HPTE_V_AVPN_SHIFT) - | HPTE_V_BOLTED | HPTE_V_VALID; - - slot = HvCallHpt_findValid(&rhpte, vpn); - if (slot < 0) { - /* Must find space in primary group */ - panic("hash_page: hpte already exists\n"); - } - HvCallHpt_addValidate(slot, 0, &local_hpte); -} - -/* - * Bolt the kernel addr space into the HPT - */ -static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) -{ - unsigned long pa; - unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; - hpte_t hpte; - - for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) { - unsigned long ea = (unsigned long)__va(pa); - unsigned long vsid = get_kernel_vsid(ea); - unsigned long va = (vsid << 28) | (pa & 0xfffffff); - unsigned long vpn = va >> PAGE_SHIFT; - unsigned long slot = HvCallHpt_findValid(&hpte, vpn); - - /* Make non-kernel text non-executable */ - if (!in_kernel_text(ea)) - mode_rw |= HW_NO_EXEC; - - if (hpte.v & HPTE_V_VALID) { - /* HPTE exists, so just bolt it */ - HvCallHpt_setSwBits(slot, 0x10, 0); - /* And make sure the pp bits are correct */ - HvCallHpt_setPp(slot, PP_RWXX); - } else - /* No HPTE exists, so create a new bolted one */ - iSeries_make_pte(va, phys_to_abs(pa), mode_rw); - } -} - /* * Document me. */ diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 36cf474b3d36..83507438d6a0 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -90,7 +90,6 @@ static inline void loop_forever(void) ; } -#ifdef CONFIG_PPC_MULTIPLATFORM static inline void create_pte_mapping(unsigned long start, unsigned long end, unsigned long mode, int large) { @@ -111,7 +110,7 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end, unsigned long vpn, hash, hpteg; unsigned long vsid = get_kernel_vsid(addr); unsigned long va = (vsid << 28) | (addr & 0xfffffff); - int ret; + int ret = -1; if (large) vpn = va >> HPAGE_SHIFT; @@ -129,16 +128,25 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end, hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); +#ifdef CONFIG_PPC_ISERIES + if (systemcfg->platform & PLATFORM_ISERIES_LPAR) + ret = iSeries_hpte_bolt_or_insert(hpteg, va, + virt_to_abs(addr) >> PAGE_SHIFT, + vflags, tmp_mode); + else +#endif #ifdef CONFIG_PPC_PSERIES if (systemcfg->platform & PLATFORM_LPAR) ret = pSeries_lpar_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, vflags, tmp_mode); else -#endif /* CONFIG_PPC_PSERIES */ +#endif +#ifdef CONFIG_PPC_MULTIPLATFORM ret = native_hpte_insert(hpteg, va, virt_to_abs(addr) >> PAGE_SHIFT, vflags, tmp_mode); +#endif if (ret == -1) { ppc64_terminate_msg(0x20, "create_pte_mapping"); @@ -261,7 +269,6 @@ void __init htab_initialize(void) } #undef KB #undef MB -#endif /* CONFIG_PPC_MULTIPLATFORM */ /* * Called by asm hashtable.S for doing lazy icache flush diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h index d2b0b796d35e..e0505acb77d9 100644 --- a/include/asm-ppc64/mmu.h +++ b/include/asm-ppc64/mmu.h @@ -206,6 +206,10 @@ extern long native_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, unsigned long vflags, unsigned long rflags); +extern long iSeries_hpte_bolt_or_insert(unsigned long hpte_group, + unsigned long va, unsigned long prpn, + unsigned long vflags, unsigned long rflags); + extern void stabs_alloc(void); #endif /* __ASSEMBLY__ */ From 7c6f947f2477f7c0017be1af458eb5e0b96b7f40 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:50:25 +1000 Subject: [PATCH 0132/1939] ppc64 iSeries: Make stab_initialize() work on iSeries We don't need to call stab_initialize() for the boot cpu on iSeries, so we hack around it so that early_setup() can be called on iSeries. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/setup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 5ac48bd64891..ca8acf671e46 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -58,6 +58,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -401,7 +402,8 @@ void __init early_setup(unsigned long dt_ptr) /* * Initialize stab / SLB management */ - stab_initialize(lpaca->stab_real); + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + stab_initialize(lpaca->stab_real); /* * Initialize the MMU Hash table and create the linear mapping From f6ab9c68406dfcd1fcd0a5352244fcb932b113b1 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:54:37 +1000 Subject: [PATCH 0133/1939] ppc64 iSeries: Make smp_release_cpus() callable on iSeries We don't need to call smp_release_cpus() on iSeries but it's harmless if we do and it removes another #ifdef ISERIES. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/head.S | 6 ++++-- arch/ppc64/kernel/setup.c | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 22a5ee07e1ea..b1d0edff0c04 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1970,20 +1970,22 @@ _GLOBAL(hmt_start_secondary) blr #endif -#if defined(CONFIG_KEXEC) || (defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)) +#if defined(CONFIG_KEXEC) || defined(CONFIG_SMP) _GLOBAL(smp_release_cpus) /* All secondary cpus are spinning on a common * spinloop, release them all now so they can start * to spin on their individual paca spinloops. * For non SMP kernels, the secondary cpus never * get out of the common spinloop. + * XXX This does nothing useful on iSeries, secondaries are + * already waiting on their paca. */ li r3,1 LOADADDR(r5,__secondary_hold_spinloop) std r3,0(r5) sync blr -#endif /* CONFIG_SMP && !CONFIG_PPC_ISERIES */ +#endif /* CONFIG_SMP */ /* diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index ca8acf671e46..acf826043e39 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -154,7 +154,7 @@ struct screen_info screen_info = { .orig_video_points = 16 }; -#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) +#ifdef CONFIG_SMP static int smt_enabled_cmdline; @@ -307,7 +307,7 @@ static void __init setup_cpu_maps(void) systemcfg->processorCount = num_present_cpus(); } -#endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ +#endif /* CONFIG_SMP */ #ifdef CONFIG_PPC_MULTIPLATFORM @@ -611,7 +611,7 @@ void __init setup_system(void) parse_early_param(); #endif /* !CONFIG_PPC_ISERIES */ -#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) +#ifdef CONFIG_SMP /* * iSeries has already initialized the cpu maps at this point. */ @@ -621,7 +621,7 @@ void __init setup_system(void) * we can map physical -> logical CPU ids */ smp_release_cpus(); -#endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ +#endif printk("Starting Linux PPC64 %s\n", system_utsname.version); From c0a59491daca7db11d49edad1a1cefaaa7120a9e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:56:09 +1000 Subject: [PATCH 0134/1939] ppc64 iSeries: Create a fake flat device tree on iSeries This patch adds infrastructure for creating a fake flattened device tree on iSeries. We also need to build prom.o for iSeries which means we'll always need it. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 137 ++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 49d0f9999682..99e4307affd6 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -912,7 +912,144 @@ struct machdep_calls __initdata iseries_md = { /* XXX Implement enable_pmcs for iSeries */ }; +struct blob { + unsigned char data[PAGE_SIZE]; + unsigned long next; +}; + +struct iseries_flat_dt { + struct boot_param_header header; + u64 reserve_map[2]; + struct blob dt; + struct blob strings; +}; + +struct iseries_flat_dt iseries_dt; + +void dt_init(struct iseries_flat_dt *dt) +{ + dt->header.off_mem_rsvmap = + offsetof(struct iseries_flat_dt, reserve_map); + dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt); + dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings); + dt->header.totalsize = sizeof(struct iseries_flat_dt); + dt->header.dt_strings_size = sizeof(struct blob); + + /* There is no notion of hardware cpu id on iSeries */ + dt->header.boot_cpuid_phys = smp_processor_id(); + + dt->dt.next = (unsigned long)&dt->dt.data; + dt->strings.next = (unsigned long)&dt->strings.data; + + dt->header.magic = OF_DT_HEADER; + dt->header.version = 0x10; + dt->header.last_comp_version = 0x10; + + dt->reserve_map[0] = 0; + dt->reserve_map[1] = 0; +} + +void dt_check_blob(struct blob *b) +{ + if (b->next >= (unsigned long)&b->next) { + DBG("Ran out of space in flat device tree blob!\n"); + BUG(); + } +} + +void dt_push_u32(struct iseries_flat_dt *dt, u32 value) +{ + *((u32*)dt->dt.next) = value; + dt->dt.next += sizeof(u32); + + dt_check_blob(&dt->dt); +} + +void dt_push_u64(struct iseries_flat_dt *dt, u64 value) +{ + *((u64*)dt->dt.next) = value; + dt->dt.next += sizeof(u64); + + dt_check_blob(&dt->dt); +} + +unsigned long dt_push_bytes(struct blob *blob, char *data, int len) +{ + unsigned long start = blob->next - (unsigned long)blob->data; + + memcpy((char *)blob->next, data, len); + blob->next = _ALIGN(blob->next + len, 4); + + dt_check_blob(blob); + + return start; +} + +void dt_start_node(struct iseries_flat_dt *dt, char *name) +{ + dt_push_u32(dt, OF_DT_BEGIN_NODE); + dt_push_bytes(&dt->dt, name, strlen(name) + 1); +} + +#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) + +void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len) +{ + unsigned long offset; + + dt_push_u32(dt, OF_DT_PROP); + + /* Length of the data */ + dt_push_u32(dt, len); + + /* Put the property name in the string blob. */ + offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1); + + /* The offset of the properties name in the string blob. */ + dt_push_u32(dt, (u32)offset); + + /* The actual data. */ + dt_push_bytes(&dt->dt, data, len); +} + +void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data) +{ + dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */ +} + +void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data) +{ + dt_prop(dt, name, (char *)&data, sizeof(u32)); +} + +void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data) +{ + dt_prop(dt, name, (char *)&data, sizeof(u64)); +} + +void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n) +{ + dt_prop(dt, name, (char *)data, sizeof(u64) * n); +} + +void dt_prop_empty(struct iseries_flat_dt *dt, char *name) +{ + dt_prop(dt, name, NULL, 0); +} + +void build_flat_dt(struct iseries_flat_dt *dt) +{ + dt_init(dt); + + dt_start_node(dt, ""); + dt_end_node(dt); + + dt_push_u32(dt, OF_DT_END); +} + void __init iSeries_early_setup(void) { iSeries_fixup_klimit(); + + build_flat_dt(&iseries_dt); } From 4762713a93fa8706c31b0897c1340e7dc282d8fb Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 14:59:04 +1000 Subject: [PATCH 0135/1939] ppc64 iSeries: Call early_setup() on iSeries Misc steps to incorporate the flat device tree on iSeries. - define iseries_probe() - call build_iSeries_Memory_Map() earlier - return __pa() of the flat device tree from iSeries_early_setup() - actually call early_setup() for iSeries - add iseries_md to machdep_calls - build prom.o for iSeries - enable /proc/device-tree for iSeries Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/Kconfig | 1 - arch/ppc64/kernel/Makefile | 4 ++-- arch/ppc64/kernel/head.S | 1 + arch/ppc64/kernel/iSeries_setup.c | 22 +++++++++++++++------- arch/ppc64/kernel/setup.c | 9 ++++----- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 32951bfc7f65..246212115a48 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -357,7 +357,6 @@ config HOTPLUG_CPU config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" - depends on !PPC_ISERIES help This option adds a device-tree directory under /proc which contains an image of the device tree that the kernel copies from Open diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 813718df4f82..afadb6e4a6dc 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -11,7 +11,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ - iommu.o sysfs.o vdso.o pmc.o firmware.o + iommu.o sysfs.o vdso.o pmc.o firmware.o prom.o obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o @@ -27,7 +27,7 @@ obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o -obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index b1d0edff0c04..eb526c480b6c 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1364,6 +1364,7 @@ _STATIC(__start_initialization_iSeries) addi r2,r2,0x4000 bl .iSeries_early_setup + bl .early_setup /* relocation is on at this point */ diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 99e4307affd6..27faf4f0967a 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -359,12 +359,6 @@ static void __init iSeries_init_early(void) */ iommu_init_early_iSeries(); - /* - * Initialize the table which translate Linux physical addresses to - * AS/400 absolute addresses - */ - build_iSeries_Memory_Map(); - iSeries_get_cmdline(); /* Save unparsed command line copy for /proc/cmdline */ @@ -894,6 +888,11 @@ static int iseries_dedicated_idle(void) void __init iSeries_init_IRQ(void) { } #endif +static int __init iseries_probe(int platform) +{ + return PLATFORM_ISERIES_LPAR == platform; +} + struct machdep_calls __initdata iseries_md = { .setup_arch = iSeries_setup_arch, .get_cpuinfo = iSeries_get_cpuinfo, @@ -909,6 +908,7 @@ struct machdep_calls __initdata iseries_md = { .get_rtc_time = iSeries_get_rtc_time, .calibrate_decr = iSeries_calibrate_decr, .progress = iSeries_progress, + .probe = iseries_probe, /* XXX Implement enable_pmcs for iSeries */ }; @@ -1047,9 +1047,17 @@ void build_flat_dt(struct iseries_flat_dt *dt) dt_push_u32(dt, OF_DT_END); } -void __init iSeries_early_setup(void) +void * __init iSeries_early_setup(void) { iSeries_fixup_klimit(); + /* + * Initialize the table which translate Linux physical addresses to + * AS/400 absolute addresses + */ + build_iSeries_Memory_Map(); + build_flat_dt(&iseries_dt); + + return (void *) __pa(&iseries_dt); } diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index acf826043e39..6c1cd3bab28e 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -309,13 +309,11 @@ static void __init setup_cpu_maps(void) } #endif /* CONFIG_SMP */ - -#ifdef CONFIG_PPC_MULTIPLATFORM - extern struct machdep_calls pSeries_md; extern struct machdep_calls pmac_md; extern struct machdep_calls maple_md; extern struct machdep_calls bpa_md; +extern struct machdep_calls iseries_md; /* Ultimately, stuff them in an elf section like initcalls... */ static struct machdep_calls __initdata *machines[] = { @@ -330,6 +328,9 @@ static struct machdep_calls __initdata *machines[] = { #endif /* CONFIG_PPC_MAPLE */ #ifdef CONFIG_PPC_BPA &bpa_md, +#endif +#ifdef CONFIG_PPC_ISERIES + &iseries_md, #endif NULL }; @@ -534,8 +535,6 @@ static void __init check_for_initrd(void) #endif /* CONFIG_BLK_DEV_INITRD */ } -#endif /* CONFIG_PPC_MULTIPLATFORM */ - /* * Do some initial setup of the system. The parameters are those which * were passed in from the bootloader. From 3ab42407fe0628c7880b21eff057566390865319 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 15:00:20 +1000 Subject: [PATCH 0136/1939] ppc64 iSeries: Move memory setup into iSeries device tree This patch adds the required nodes to the iSeries device tree to allow early_init_devtree() to do the lmb setup for us. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 27faf4f0967a..639f400d6b0c 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -376,11 +376,6 @@ static void __init iSeries_init_early(void) } } - lmb_init(); - lmb_add(0, systemcfg->physicalMemorySize); - lmb_analyze(); - lmb_reserve(0, __pa(klimit)); - /* Initialize machine-dependency vectors */ #ifdef CONFIG_SMP smp_init_iSeries(); @@ -1039,9 +1034,24 @@ void dt_prop_empty(struct iseries_flat_dt *dt, char *name) void build_flat_dt(struct iseries_flat_dt *dt) { + u64 tmp[2]; + dt_init(dt); dt_start_node(dt, ""); + + dt_prop_u32(dt, "#address-cells", 2); + dt_prop_u32(dt, "#size-cells", 2); + + /* /memory */ + dt_start_node(dt, "memory@0"); + dt_prop_str(dt, "name", "memory"); + dt_prop_str(dt, "device_type", "memory"); + tmp[0] = 0; + tmp[1] = systemcfg->physicalMemorySize; + dt_prop_u64_list(dt, "reg", tmp, 2); + dt_end_node(dt); + dt_end_node(dt); dt_push_u32(dt, OF_DT_END); From 47db360328582000a7a46390cfa385b8df07b44f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 15:01:49 +1000 Subject: [PATCH 0137/1939] ppc64 iSeries: Move setup of systemcfg->platform into iSeries device tree Add /chosen/linux,platform to the device tree so we can remove iSeries specific code in setup_system() to set systemcfg->platform. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 5 +++++ arch/ppc64/kernel/setup.c | 9 --------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 639f400d6b0c..4895f674a4ba 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -1052,6 +1052,11 @@ void build_flat_dt(struct iseries_flat_dt *dt) dt_prop_u64_list(dt, "reg", tmp, 2); dt_end_node(dt); + /* /chosen */ + dt_start_node(dt, "chosen"); + dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR); + dt_end_node(dt); + dt_end_node(dt); dt_push_u32(dt, OF_DT_END); diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 6c1cd3bab28e..776b55b45e1b 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -543,14 +543,6 @@ void __init setup_system(void) { DBG(" -> setup_system()\n"); -#ifdef CONFIG_PPC_ISERIES - /* pSeries systems are identified in prom.c via OF. */ - if (itLpNaca.xLparInstalled == 1) - systemcfg->platform = PLATFORM_ISERIES_LPAR; - - ppc_md.init_early(); -#else /* CONFIG_PPC_ISERIES */ - /* * Unflatten the device-tree passed by prom_init or kexec */ @@ -608,7 +600,6 @@ void __init setup_system(void) strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); parse_early_param(); -#endif /* !CONFIG_PPC_ISERIES */ #ifdef CONFIG_SMP /* From 95b293800859886b602e31c8926a840530a82971 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Sep 2005 15:03:10 +1000 Subject: [PATCH 0138/1939] ppc64 iSeries: Define /cpus in iSeries device tree Add the /cpus node and nodes for each cpu, as well as cache size properties, reg propery, "linux,boot-cpu", and timebase/clock frequency. With those properties in place we can remove: - setup_iSeries_cache_sizes() - code in iSeries_setup_arch() to calculate timebase etc. - iSeries_calibrate_decr() - smp_iSeries_numProcs() and simplify smp_iSeries_probe() Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 178 +++++++++--------------------- arch/ppc64/kernel/iSeries_smp.c | 30 +---- arch/ppc64/kernel/time.c | 2 +- 3 files changed, 57 insertions(+), 153 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 4895f674a4ba..cadfc623a838 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -74,7 +74,6 @@ extern void hvlog(char *fmt, ...); extern void ppcdbg_initialize(void); static void build_iSeries_Memory_Map(void); -static void setup_iSeries_cache_sizes(void); static int iseries_shared_idle(void); static int iseries_dedicated_idle(void); #ifdef CONFIG_PCI @@ -84,14 +83,6 @@ static void iSeries_pci_final_fixup(void) { } #endif /* Global Variables */ -static unsigned long procFreqHz; -static unsigned long procFreqMhz; -static unsigned long procFreqMhzHundreths; - -static unsigned long tbFreqHz; -static unsigned long tbFreqMhz; -static unsigned long tbFreqMhzHundreths; - int piranha_simulator; extern int rd_size; /* Defined in drivers/block/rd.c */ @@ -343,12 +334,6 @@ static void __init iSeries_init_early(void) iSeries_recal_tb = get_tb(); iSeries_recal_titan = HvCallXm_loadTod(); - /* - * Cache sizes must be initialized before hpte_init_iSeries is called - * as the later need them for flush_icache_range() - */ - setup_iSeries_cache_sizes(); - /* * Initialize the hash table management pointers */ @@ -580,47 +565,6 @@ static void __init build_iSeries_Memory_Map(void) systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk); } -/* - * Set up the variables that describe the cache line sizes - * for this machine. - */ -static void __init setup_iSeries_cache_sizes(void) -{ - unsigned int i, n; - unsigned int procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; - - systemcfg->icache_size = - ppc64_caches.isize = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024; - systemcfg->icache_line_size = - ppc64_caches.iline_size = - xIoHriProcessorVpd[procIx].xInstCacheOperandSize; - systemcfg->dcache_size = - ppc64_caches.dsize = - xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024; - systemcfg->dcache_line_size = - ppc64_caches.dline_size = - xIoHriProcessorVpd[procIx].xDataCacheOperandSize; - ppc64_caches.ilines_per_page = PAGE_SIZE / ppc64_caches.iline_size; - ppc64_caches.dlines_per_page = PAGE_SIZE / ppc64_caches.dline_size; - - i = ppc64_caches.iline_size; - n = 0; - while ((i = (i / 2))) - ++n; - ppc64_caches.log_iline_size = n; - - i = ppc64_caches.dline_size; - n = 0; - while ((i = (i / 2))) - ++n; - ppc64_caches.log_dline_size = n; - - printk("D-cache line size = %d\n", - (unsigned int)ppc64_caches.dline_size); - printk("I-cache line size = %d\n", - (unsigned int)ppc64_caches.iline_size); -} - /* * Document me. */ @@ -636,36 +580,14 @@ static void __init iSeries_setup_arch(void) printk(KERN_INFO "Using dedicated idle loop\n"); } - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); - systemcfg->version.major = SYSTEMCFG_MAJOR; - systemcfg->version.minor = SYSTEMCFG_MINOR; - /* Setup the Lp Event Queue */ setup_hvlpevent_queue(); - /* Compute processor frequency */ - procFreqHz = ((1UL << 34) * 1000000) / - xIoHriProcessorVpd[procIx].xProcFreq; - procFreqMhz = procFreqHz / 1000000; - procFreqMhzHundreths = (procFreqHz / 10000) - (procFreqMhz * 100); - ppc_proc_freq = procFreqHz; - - /* Compute time base frequency */ - tbFreqHz = ((1UL << 32) * 1000000) / - xIoHriProcessorVpd[procIx].xTimeBaseFreq; - tbFreqMhz = tbFreqHz / 1000000; - tbFreqMhzHundreths = (tbFreqHz / 10000) - (tbFreqMhz * 100); - ppc_tb_freq = tbFreqHz; - printk("Max logical processors = %d\n", itVpdAreas.xSlicMaxLogicalProcs); printk("Max physical processors = %d\n", itVpdAreas.xSlicMaxPhysicalProcs); - printk("Processor frequency = %lu.%02lu\n", procFreqMhz, - procFreqMhzHundreths); - printk("Time base frequency = %lu.%02lu\n", tbFreqMhz, - tbFreqMhzHundreths); + systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; printk("Processor version = %x\n", systemcfg->processor); } @@ -709,49 +631,6 @@ static void iSeries_halt(void) mf_power_off(); } -/* - * void __init iSeries_calibrate_decr() - * - * Description: - * This routine retrieves the internal processor frequency from the VPD, - * and sets up the kernel timer decrementer based on that value. - * - */ -static void __init iSeries_calibrate_decr(void) -{ - unsigned long cyclesPerUsec; - struct div_result divres; - - /* Compute decrementer (and TB) frequency in cycles/sec */ - cyclesPerUsec = ppc_tb_freq / 1000000; - - /* - * Set the amount to refresh the decrementer by. This - * is the number of decrementer ticks it takes for - * 1/HZ seconds. - */ - tb_ticks_per_jiffy = ppc_tb_freq / HZ; - -#if 0 - /* TEST CODE FOR ADJTIME */ - tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000; - /* END OF TEST CODE */ -#endif - - /* - * tb_ticks_per_sec = freq; would give better accuracy - * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures - * that jiffies (and xtime) will match the time returned - * by do_gettimeofday. - */ - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = cyclesPerUsec; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); - div128_by_32(1024 * 1024, 0, tb_ticks_per_sec, &divres); - tb_to_xs = divres.result_low; - setup_default_decr(); -} - static void __init iSeries_progress(char * st, unsigned short code) { printk("Progress: [%04x] - %s\n", (unsigned)code, st); @@ -901,7 +780,7 @@ struct machdep_calls __initdata iseries_md = { .get_boot_time = iSeries_get_boot_time, .set_rtc_time = iSeries_set_rtc_time, .get_rtc_time = iSeries_get_rtc_time, - .calibrate_decr = iSeries_calibrate_decr, + .calibrate_decr = generic_calibrate_decr, .progress = iSeries_progress, .probe = iseries_probe, /* XXX Implement enable_pmcs for iSeries */ @@ -1032,6 +911,57 @@ void dt_prop_empty(struct iseries_flat_dt *dt, char *name) dt_prop(dt, name, NULL, 0); } +void dt_cpus(struct iseries_flat_dt *dt) +{ + unsigned char buf[32]; + unsigned char *p; + unsigned int i, index; + struct IoHriProcessorVpd *d; + + /* yuck */ + snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); + p = strchr(buf, ' '); + if (!p) p = buf + strlen(buf); + + dt_start_node(dt, "cpus"); + dt_prop_u32(dt, "#address-cells", 1); + dt_prop_u32(dt, "#size-cells", 0); + + for (i = 0; i < NR_CPUS; i++) { + if (paca[i].lppaca.dyn_proc_status >= 2) + continue; + + snprintf(p, 32 - (p - buf), "@%d", i); + dt_start_node(dt, buf); + + dt_prop_str(dt, "device_type", "cpu"); + + index = paca[i].lppaca.dyn_hv_phys_proc_index; + d = &xIoHriProcessorVpd[index]; + + dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); + dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); + + dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); + dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); + + /* magic conversions to Hz copied from old code */ + dt_prop_u32(dt, "clock-frequency", + ((1UL << 34) * 1000000) / d->xProcFreq); + dt_prop_u32(dt, "timebase-frequency", + ((1UL << 32) * 1000000) / d->xTimeBaseFreq); + + dt_prop_u32(dt, "reg", i); + + if (dt->header.boot_cpuid_phys == i) + dt_prop_empty(dt, "linux,boot-cpu"); + + dt_end_node(dt); + } + + dt_end_node(dt); +} + void build_flat_dt(struct iseries_flat_dt *dt) { u64 tmp[2]; @@ -1057,6 +987,8 @@ void build_flat_dt(struct iseries_flat_dt *dt) dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR); dt_end_node(dt); + dt_cpus(dt); + dt_end_node(dt); dt_push_u32(dt, OF_DT_END); diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/ppc64/kernel/iSeries_smp.c index f74386e31638..f982e5b805f4 100644 --- a/arch/ppc64/kernel/iSeries_smp.c +++ b/arch/ppc64/kernel/iSeries_smp.c @@ -82,35 +82,9 @@ static void smp_iSeries_message_pass(int target, int msg) } } -static int smp_iSeries_numProcs(void) -{ - unsigned np, i; - - np = 0; - for (i=0; i < NR_CPUS; ++i) { - if (paca[i].lppaca.dyn_proc_status < 2) { - cpu_set(i, cpu_possible_map); - cpu_set(i, cpu_present_map); - cpu_set(i, cpu_sibling_map[i]); - ++np; - } - } - return np; -} - static int smp_iSeries_probe(void) { - unsigned i; - unsigned np = 0; - - for (i=0; i < NR_CPUS; ++i) { - if (paca[i].lppaca.dyn_proc_status < 2) { - /*paca[i].active = 1;*/ - ++np; - } - } - - return np; + return cpus_weight(cpu_possible_map); } static void smp_iSeries_kick_cpu(int nr) @@ -144,6 +118,4 @@ static struct smp_ops_t iSeries_smp_ops = { void __init smp_init_iSeries(void) { smp_ops = &iSeries_smp_ops; - systemcfg->processorCount = smp_iSeries_numProcs(); } - diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index fb4bf0ad8f32..7f63755eddfd 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -465,7 +465,7 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) || defined(CONFIG_PPC_ISERIES) void __init generic_calibrate_decr(void) { struct device_node *cpu; From 3d8a66cc9ec475baaf22de139deff67ffe8e7cf2 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 23 Sep 2005 15:17:30 +1000 Subject: [PATCH 0139/1939] ppc64 iSeries: Don't create linux,boot-cpu This is obsolete. Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/iSeries_setup.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index cadfc623a838..9daf734adbd5 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -953,9 +953,6 @@ void dt_cpus(struct iseries_flat_dt *dt) dt_prop_u32(dt, "reg", i); - if (dt->header.boot_cpuid_phys == i) - dt_prop_empty(dt, "linux,boot-cpu"); - dt_end_node(dt); } From ef846bf04f4c9e1a68ab841e89931f8c26100874 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:07 -0400 Subject: [PATCH 0140/1939] [PATCH] orinoco: Remove inneeded system includes. Signed-off-by: Pavel Roskin Remove inneeded system includes. Most system includes are not needed. In particular, the hardware backends don't need anything network related. Some includes have been moved from local headers to the C files where they are actually used. Includes that have to be in the local headers are no longer from the C sources. Signed-off-by: Jeff Garzik --- drivers/net/wireless/airport.c | 19 +------------------ drivers/net/wireless/hermes.c | 11 ++--------- drivers/net/wireless/hermes.h | 3 +-- drivers/net/wireless/orinoco.c | 12 ------------ drivers/net/wireless/orinoco.h | 2 -- drivers/net/wireless/orinoco_cs.c | 16 +--------------- drivers/net/wireless/orinoco_nortel.c | 18 +----------------- drivers/net/wireless/orinoco_pci.c | 18 +----------------- drivers/net/wireless/orinoco_plx.c | 18 +----------------- drivers/net/wireless/orinoco_tmd.c | 18 +----------------- drivers/net/wireless/spectrum_cs.c | 16 +--------------- 11 files changed, 10 insertions(+), 141 deletions(-) diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 9d496703c465..7b321f7cf358 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -15,28 +15,11 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include #include -#include -#include #include "orinoco.h" diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 21c3d0d227e6..eba0d9d2b7c5 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -39,17 +39,10 @@ */ #include - #include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include #include "hermes.h" diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 8c9e874c9118..786613aaa58a 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -30,9 +30,8 @@ * access to the hermes_t structure, and to the hardware */ -#include #include -#include +#include /* * Limits and constants diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index fc2fa4dc3a08..f76fe3d10248 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -77,28 +77,16 @@ #define DRIVER_NAME "orinoco" #include - #include #include #include -#include -#include -#include -#include -#include #include -#include #include #include #include #include #include -#include -#include -#include - -#include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index c800563034a7..32530d435afb 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -9,8 +9,6 @@ #define DRIVER_VERSION "0.15rc2" -#include -#include #include #include #include diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 80920b1c6fcf..195c530f209f 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -14,30 +14,16 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include #include #include #include #include -#include -#include -#include - #include "orinoco.h" /********************************************************************/ diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 86fa58e5cfac..d48ec24539f1 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -40,29 +40,13 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include - #include -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 42e03438291b..5362c214fc8e 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -93,28 +93,12 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include - -#include "hermes.h" #include "orinoco.h" /* All the magic there is from wlan-ng */ diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 7ab05b89fb3f..210e73776545 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -117,29 +117,13 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include - #include -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 85893f42445b..5e68b7026186 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -53,29 +53,13 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include - #include -#include "hermes.h" #include "orinoco.h" #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 63e00422d1a0..61199543aeb7 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -22,31 +22,17 @@ #define PFX DRIVER_NAME ": " #include - #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include - #include #include #include #include #include -#include -#include -#include - #include "orinoco.h" static unsigned char *primsym; From 4c08202547111e503eca4031ae9443159a79e2b2 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0141/1939] [PATCH] orinoco: Make nortel_pci_hw_init() static. Signed-off-by: Pavel Roskin Make nortel_pci_hw_init() static. Found by sparse. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco_nortel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index d48ec24539f1..d8afd51ff8a5 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -92,7 +92,7 @@ static int nortel_pci_cor_reset(struct orinoco_private *priv) return 0; } -int nortel_pci_hw_init(struct nortel_pci_card *card) +static int nortel_pci_hw_init(struct nortel_pci_card *card) { int i; u32 reg; From f3cb4cc120177090b0ccc9fb20a12010de39ac8a Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0142/1939] [PATCH] orinoco: Fix memory leak and unneeded unlock in orinoco_join_ap() Signed-off-by: Pavel Roskin Fix memory leak and unneeded unlock in orinoco_join_ap() If orinoco_lock() fails, the code would still run orinoco_unlock(), instead of freeing the allocated memory. Found by sparse. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index f76fe3d10248..8b93b44291d4 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1046,7 +1046,7 @@ static void orinoco_join_ap(struct net_device *dev) return; if (orinoco_lock(priv, &flags) != 0) - goto out; + goto fail_lock; /* Sanity checks in case user changed something in the meantime */ if (! priv->bssid_fixed) @@ -1091,8 +1091,10 @@ static void orinoco_join_ap(struct net_device *dev) printk(KERN_ERR "%s: Error issuing join request\n", dev->name); out: - kfree(buf); orinoco_unlock(priv, &flags); + + fail_lock: + kfree(buf); } /* Send new BSSID to userspace */ From 8aeabc375041a5fe9c9be315472497b2e0547eed Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0143/1939] [PATCH] orinoco: orinoco_send_wevents() could return without unlocking. Signed-off-by: Pavel Roskin orinoco_send_wevents() could return without unlocking. Failure to read BSSID from the hardware would cause orinoco_send_wevents() to return with lock held. Found by sparse. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 8b93b44291d4..29cb5d81b67e 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1112,12 +1112,14 @@ static void orinoco_send_wevents(struct net_device *dev) err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) - return; + goto out; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + + out: orinoco_unlock(priv, &flags); } From 393da59834eef526fc6fd0df321e94344d7c49e3 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0144/1939] [PATCH] orinoco: Remove unneeded forward declarations. Signed-off-by: Pavel Roskin Remove unneeded forward declarations. Also reorder struct pcmcia_driver initialization to keep attach and detach together. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco_cs.c | 15 +++------------ drivers/net/wireless/spectrum_cs.c | 15 +++------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 195c530f209f..dc1128a00971 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -80,17 +80,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int orinoco_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void orinoco_cs_config(dev_link_t * link); -static void orinoco_cs_release(dev_link_t * link); -static int orinoco_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *orinoco_cs_attach(void); -static void orinoco_cs_detach(dev_link_t *); +static void orinoco_cs_release(dev_link_t *link); +static void orinoco_cs_detach(dev_link_t *link); /********************************************************************/ /* Device methods */ @@ -675,8 +666,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, - .event = orinoco_cs_event, .detach = orinoco_cs_detach, + .event = orinoco_cs_event, .id_table = orinoco_cs_ids, }; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 61199543aeb7..ceed0241adcd 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -89,17 +89,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int spectrum_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void spectrum_cs_config(dev_link_t * link); -static void spectrum_cs_release(dev_link_t * link); -static int spectrum_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *spectrum_cs_attach(void); -static void spectrum_cs_detach(dev_link_t *); +static void spectrum_cs_release(dev_link_t *link); +static void spectrum_cs_detach(dev_link_t *link); /********************************************************************/ /* Firmware downloader */ @@ -1058,8 +1049,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = spectrum_cs_attach, - .event = spectrum_cs_event, .detach = spectrum_cs_detach, + .event = spectrum_cs_event, .id_table = spectrum_cs_ids, }; From d133ae4cd6a3c75c31b1630f906cc9979a11077f Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0145/1939] [PATCH] orinoco: Annotate endianess of variables and structure members. Signed-off-by: Pavel Roskin Annotate endianess of variables and structure members. Don't reuse variables for both host-endian and little-endian data. Minor comment changes in affected structures. Signed-off-by: Jeff Garzik --- drivers/net/wireless/hermes.h | 108 ++++++++++++++--------------- drivers/net/wireless/orinoco.c | 62 +++++++++-------- drivers/net/wireless/orinoco.h | 6 +- drivers/net/wireless/spectrum_cs.c | 20 +++--- 4 files changed, 99 insertions(+), 97 deletions(-) diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 786613aaa58a..ad28e3294360 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -191,13 +191,13 @@ #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ struct hermes_tx_descriptor { - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; } __attribute__ ((packed)); #define HERMES_TXSTAT_RETRYERR (0x0001) @@ -221,60 +221,60 @@ struct hermes_tx_descriptor { #define HERMES_INQ_SEC_STAT_AGERE (0xF202) struct hermes_tallies_frame { - u16 TxUnicastFrames; - u16 TxMulticastFrames; - u16 TxFragments; - u16 TxUnicastOctets; - u16 TxMulticastOctets; - u16 TxDeferredTransmissions; - u16 TxSingleRetryFrames; - u16 TxMultipleRetryFrames; - u16 TxRetryLimitExceeded; - u16 TxDiscards; - u16 RxUnicastFrames; - u16 RxMulticastFrames; - u16 RxFragments; - u16 RxUnicastOctets; - u16 RxMulticastOctets; - u16 RxFCSErrors; - u16 RxDiscards_NoBuffer; - u16 TxDiscardsWrongSA; - u16 RxWEPUndecryptable; - u16 RxMsgInMsgFragments; - u16 RxMsgInBadMsgFragments; + __le16 TxUnicastFrames; + __le16 TxMulticastFrames; + __le16 TxFragments; + __le16 TxUnicastOctets; + __le16 TxMulticastOctets; + __le16 TxDeferredTransmissions; + __le16 TxSingleRetryFrames; + __le16 TxMultipleRetryFrames; + __le16 TxRetryLimitExceeded; + __le16 TxDiscards; + __le16 RxUnicastFrames; + __le16 RxMulticastFrames; + __le16 RxFragments; + __le16 RxUnicastOctets; + __le16 RxMulticastOctets; + __le16 RxFCSErrors; + __le16 RxDiscards_NoBuffer; + __le16 TxDiscardsWrongSA; + __le16 RxWEPUndecryptable; + __le16 RxMsgInMsgFragments; + __le16 RxMsgInBadMsgFragments; /* Those last are probably not available in very old firmwares */ - u16 RxDiscards_WEPICVError; - u16 RxDiscards_WEPExcluded; + __le16 RxDiscards_WEPICVError; + __le16 RxDiscards_WEPExcluded; } __attribute__ ((packed)); /* Grabbed from wlan-ng - Thanks Mark... - Jean II * This is the result of a scan inquiry command */ /* Structure describing info about an Access Point */ struct prism2_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ - u16 essid_len; /* ESSID length */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ u8 rates[10]; /* Bit rate supported */ - u16 proberesp_rate; /* Data rate of the response frame */ - u16 atim; /* ATIM window time, Kus (hostscan only) */ + __le16 proberesp_rate; /* Data rate of the response frame */ + __le16 atim; /* ATIM window time, Kus (hostscan only) */ } __attribute__ ((packed)); /* Same stuff for the Lucent/Agere card. * Thanks to h1kari - Jean II */ struct agere_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ } __attribute__ ((packed)); @@ -282,16 +282,16 @@ struct agere_scan_apinfo { struct symbol_scan_apinfo { u8 channel; /* Channel where the AP sits */ u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ - u16 rates[5]; /* Bit rate supported */ - u16 basic_rates; /* Basic rates bitmask */ + __le16 rates[5]; /* Bit rate supported */ + __le16 basic_rates; /* Basic rates bitmask */ u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ } __attribute__ ((packed)); @@ -311,7 +311,7 @@ union hermes_scan_info { #define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) struct hermes_linkstatus { - u16 linkstatus; /* Link status */ + __le16 linkstatus; /* Link status */ } __attribute__ ((packed)); struct hermes_response { @@ -320,8 +320,8 @@ struct hermes_response { /* "ID" structure - used for ESSID and station nickname */ struct hermes_idstring { - u16 len; - u16 val[16]; + __le16 len; + __le16 val[16]; } __attribute__ ((packed)); struct hermes_multicast { @@ -446,7 +446,7 @@ static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) { - u16 rec; + __le16 rec; int err; err = HERMES_READ_RECORD(hw, bap, rid, &rec); @@ -456,7 +456,7 @@ static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) { - u16 rec = cpu_to_le16(word); + __le16 rec = cpu_to_le16(word); return HERMES_WRITE_RECORD(hw, bap, rid, &rec); } diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 29cb5d81b67e..1ae301c62281 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -202,31 +202,32 @@ static struct { /********************************************************************/ /* Used in Event handling. - * We avoid nested structres as they break on ARM -- Moustafa */ + * We avoid nested structures as they break on ARM -- Moustafa */ struct hermes_tx_descriptor_802_11 { /* hermes_tx_descriptor */ - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; - /* ieee802_11_hdr */ - u16 frame_ctl; - u16 duration_id; + /* ieee80211_hdr */ + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; - u16 data_len; + + __le16 data_len; /* ethhdr */ - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ + u8 h_dest[ETH_ALEN]; /* destination eth addr */ + u8 h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ /* p8022_hdr */ u8 dsap; @@ -234,31 +235,31 @@ struct hermes_tx_descriptor_802_11 { u8 ctrl; u8 oui[3]; - u16 ethertype; + __be16 ethertype; } __attribute__ ((packed)); /* Rx frame header except compatibility 802.3 header */ struct hermes_rx_descriptor { /* Control */ - u16 status; - u32 time; + __le16 status; + __le32 time; u8 silence; u8 signal; u8 rate; u8 rxflow; - u32 reserved; + __le32 reserved; /* 802.11 header */ - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; /* Data length */ - u16 data_len; + __le16 data_len; } __attribute__ ((packed)); /********************************************************************/ @@ -389,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) } } else { struct { - u16 qual, signal, noise; + __le16 qual, signal, noise; } __attribute__ ((packed)) cq; err = HERMES_READ_RECORD(hw, USER_BAP, @@ -615,6 +616,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); + u16 status; struct hermes_tx_descriptor_802_11 hdr; int err = 0; @@ -644,8 +646,8 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ - hdr.status = le16_to_cpu(hdr.status); - if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { + status = le16_to_cpu(hdr.status); + if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { union iwreq_data wrqu; /* Copy 802.11 dest address. @@ -1031,7 +1033,7 @@ static void orinoco_join_ap(struct net_device *dev) unsigned long flags; struct join_req { u8 bssid[ETH_ALEN]; - u16 channel; + __le16 channel; } __attribute__ ((packed)) req; const int atom_len = offsetof(struct prism2_scan_apinfo, atim); struct prism2_scan_apinfo *atom = NULL; @@ -1128,8 +1130,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); u16 infofid; struct { - u16 len; - u16 type; + __le16 len; + __le16 type; } __attribute__ ((packed)) info; int len, type; int err; @@ -3905,7 +3907,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, HERMES_HOSTSCAN_SYMBOL_BCAST); break; case FIRMWARE_TYPE_INTERSIL: { - u16 req[3]; + __le16 req[3]; req[0] = cpu_to_le16(0x3fff); /* All channels */ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ @@ -3979,7 +3981,7 @@ static inline int orinoco_translate_scan(struct net_device *dev, case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) { - atom_len = le16_to_cpup((u16 *)scan); + atom_len = le16_to_cpup((__le16 *)scan); /* Sanity check for atom_len */ if (atom_len < sizeof(struct prism2_scan_apinfo)) { printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 32530d435afb..6920ead11449 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -27,7 +27,7 @@ #define ORINOCO_MAX_KEYS 4 struct orinoco_key { - u16 len; /* always stored as little-endian */ + __le16 len; /* always stored as little-endian */ char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); @@ -35,14 +35,14 @@ struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; - u16 len; + __be16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; - u16 ethertype; + unsigned short ethertype; } __attribute__ ((packed)); typedef enum { diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index ceed0241adcd..b1bbc8e8e91f 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -138,8 +138,8 @@ static void spectrum_cs_detach(dev_link_t *link); * Each block has the following structure. */ struct dblock { - u32 _addr; /* adapter address where to write the block */ - u16 _len; /* length of the data only, in bytes */ + __le32 _addr; /* adapter address where to write the block */ + __le16 _len; /* length of the data only, in bytes */ char data[0]; /* data to be written */ } __attribute__ ((packed)); @@ -149,9 +149,9 @@ struct dblock { * items with matching ID should be written. */ struct pdr { - u32 _id; /* record ID */ - u32 _addr; /* adapter address where to write the data */ - u32 _len; /* expected length of the data, in bytes */ + __le32 _id; /* record ID */ + __le32 _addr; /* adapter address where to write the data */ + __le32 _len; /* expected length of the data, in bytes */ char next[0]; /* next PDR starts here */ } __attribute__ ((packed)); @@ -162,8 +162,8 @@ struct pdr { * be plugged into the secondary firmware. */ struct pdi { - u16 _len; /* length of ID and data, in words */ - u16 _id; /* record ID */ + __le16 _len; /* length of ID and data, in words */ + __le16 _id; /* record ID */ char data[0]; /* plug data */ } __attribute__ ((packed));; @@ -370,7 +370,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) /* Read PDA from the adapter */ static int -spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) +spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) { int ret; int pda_size; @@ -401,7 +401,7 @@ spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) /* Parse PDA and write the records into the adapter */ static int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - u16 *pda) + __le16 *pda) { int ret; struct pdi *pdi; @@ -467,7 +467,7 @@ spectrum_dl_image(hermes_t *hw, dev_link_t *link, const struct dblock *first_block; /* Plug Data Area (PDA) */ - u16 pda[PDA_WORDS]; + __le16 pda[PDA_WORDS]; /* Binary block begins after the 0x1A marker */ ptr = image; From 48ca703807eba616ad5e384b40e27514bd341a3d Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0146/1939] [PATCH] orinoco: Read only needed data in __orinoco_ev_txexc(). Signed-off-by: Pavel Roskin Read only needed data in __orinoco_ev_txexc(). Don't read the 802.11 header beyond addr1. The rest of the frame is not used currently. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 1ae301c62281..78afbc7f08be 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -623,10 +623,10 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) if (fid == DUMMY_FID) return; /* Nothing's really happened */ - /* Read the frame header */ + /* Read part of the frame header - we need status and addr1 */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_tx_descriptor) + - sizeof(struct ieee80211_hdr_4addr), + offsetof(struct hermes_tx_descriptor_802_11, + addr2), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); From acc4b985a6f8f22a0e826692894a4af234764001 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 04:18:06 -0400 Subject: [PATCH 0147/1939] [PATCH] orinoco: Bump version to 0.15rc3. Signed-off-by: Pavel Roskin Bump version to 0.15rc3. Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 6920ead11449..7a17bb31fc89 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -7,7 +7,7 @@ #ifndef _ORINOCO_H #define _ORINOCO_H -#define DRIVER_VERSION "0.15rc2" +#define DRIVER_VERSION "0.15rc3" #include #include From 20509f1bc553ed7fafa88fa8d01c6212d1876d9f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 25 Aug 2005 16:25:34 -0700 Subject: [PATCH 0148/1939] NFS: Drop inode after rename When doing a rename on top of an existing file that is not in use, the inode of the overwritten file will remain in the icache. The fix is to decrement i_nlink of the overwritten inode, like we do for unlink, rmdir etc already. Problem diagnosed by Olaf Kirch. This patch is a slight variation on his fix. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2df639f143e8..94a7fcee0624 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1539,7 +1539,8 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, #endif goto out; } - } + } else + new_inode->i_nlink--; go_ahead: /* From 449231d6ddf50ca46b7fb2f76ecf790135222913 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Thu, 25 Aug 2005 16:25:35 -0700 Subject: [PATCH 0149/1939] From: Olaf Kirch [PATCH] Fix miscompare in __posix_lock_file If an application requests the same lock twice, the kernel should just leave the existing lock in place. Currently, it will install a second lock of the same type. Signed-off-by: Olaf Kirch Signed-off-by: Trond Myklebust --- fs/locks.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index f7daa5f48949..7eb1d77b9204 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -829,12 +829,16 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) /* Detect adjacent or overlapping regions (if same lock type) */ if (request->fl_type == fl->fl_type) { + /* In all comparisons of start vs end, use + * "start - 1" rather than "end + 1". If end + * is OFFSET_MAX, end + 1 will become negative. + */ if (fl->fl_end < request->fl_start - 1) goto next_lock; /* If the next lock in the list has entirely bigger * addresses than the new one, insert the lock here. */ - if (fl->fl_start > request->fl_end + 1) + if (fl->fl_start - 1 > request->fl_end) break; /* If we come here, the new and old lock are of the From 9aa48b7e270d13c8781414dce081a42cae20a80d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 25 Aug 2005 16:25:35 -0700 Subject: [PATCH 0150/1939] NFS: Don't expose internal READDIR errors to userspace Fixes a condition whereby the kernel is returning the non-POSIX error EBADCOOKIE to userspace. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 94a7fcee0624..c70eabd6d179 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -565,8 +565,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } } unlock_kernel(); - if (desc->error < 0) - return desc->error; if (res < 0) return res; return 0; From 23475d66bd8600e0c5353f86c1b74f68df27bdb5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:08 -0400 Subject: [PATCH 0151/1939] [PATCH] RPC: Report connection errors properly when mounting with "soft" Fix up xprt_connect_status: the soft timeout logic was clobbering tk_status, so TCP connect errors were not properly reported on soft mounts. Test-plan: Destructive testing (unplugging the network temporarily). Connectathon with UDP and TCP. Version: Thu, 11 Aug 2005 16:01:28 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 3c654e06b084..b28ea0cc0cb7 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -592,24 +592,33 @@ xprt_connect_status(struct rpc_task *task) return; } - /* if soft mounted, just cause this RPC to fail */ - if (RPC_IS_SOFT(task)) - task->tk_status = -EIO; - switch (task->tk_status) { case -ECONNREFUSED: case -ECONNRESET: + dprintk("RPC: %4d xprt_connect_status: server %s refused connection\n", + task->tk_pid, task->tk_client->cl_server); + break; case -ENOTCONN: - return; + dprintk("RPC: %4d xprt_connect_status: connection broken\n", + task->tk_pid); + break; case -ETIMEDOUT: - dprintk("RPC: %4d xprt_connect_status: timed out\n", + dprintk("RPC: %4d xprt_connect_status: connect attempt timed out\n", task->tk_pid); break; default: - printk(KERN_ERR "RPC: error %d connecting to server %s\n", - -task->tk_status, task->tk_client->cl_server); + dprintk("RPC: %4d xprt_connect_status: error %d connecting to server %s\n", + task->tk_pid, -task->tk_status, task->tk_client->cl_server); + xprt_release_write(xprt, task); + task->tk_status = -EIO; + return; + } + + /* if soft mounted, just cause this RPC to fail */ + if (RPC_IS_SOFT(task)) { + xprt_release_write(xprt, task); + task->tk_status = -EIO; } - xprt_release_write(xprt, task); } /* From da35187801732397a7e05fb9e77f3700cc35f5db Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:11 -0400 Subject: [PATCH 0152/1939] [PATCH] RPC: proper soft timeout behavior for rpcbind Implement a best practice: for soft mounts, an rpcbind timeout should cause an RPC request to fail. This also provides an FSM hook for retrying an rpcbind with a different rpcbind protocol version. We'll use this later to try multiple rpcbind protocol versions when binding. To enable this, expose the RPC error code returned during a portmap request to the FSM so it can make some decision about how to report, retry, or fail the request. Test-plan: Hundreds of passes with connectathon NFSv3 locking suite, on the client and server. Version: Thu, 11 Aug 2005 16:01:53 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 97 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 20 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f17e6153b688..2d3cf0a52d82 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -53,6 +53,7 @@ static void call_allocate(struct rpc_task *task); static void call_encode(struct rpc_task *task); static void call_decode(struct rpc_task *task); static void call_bind(struct rpc_task *task); +static void call_bind_status(struct rpc_task *task); static void call_transmit(struct rpc_task *task); static void call_status(struct rpc_task *task); static void call_refresh(struct rpc_task *task); @@ -734,43 +735,94 @@ static void call_bind(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = clnt->cl_xprt; - dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid, - xprt, (xprt_connected(xprt) ? "is" : "is not")); - - task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect; + dprintk("RPC: %4d call_bind (status %d)\n", + task->tk_pid, task->tk_status); + task->tk_action = call_connect; if (!clnt->cl_port) { - task->tk_action = call_connect; + task->tk_action = call_bind_status; task->tk_timeout = RPC_CONNECT_TIMEOUT; rpc_getport(task, clnt); } } /* - * 4a. Connect to the RPC server (TCP case) + * 4a. Sort out bind result + */ +static void +call_bind_status(struct rpc_task *task) +{ + int status = -EACCES; + + if (task->tk_status >= 0) { + dprintk("RPC: %4d call_bind_status (status %d)\n", + task->tk_pid, task->tk_status); + task->tk_status = 0; + task->tk_action = call_connect; + return; + } + + switch (task->tk_status) { + case -EACCES: + dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", + task->tk_pid); + break; + case -ETIMEDOUT: + dprintk("RPC: %4d rpcbind request timed out\n", + task->tk_pid); + if (RPC_IS_SOFT(task)) { + status = -EIO; + break; + } + goto retry_bind; + case -EPFNOSUPPORT: + dprintk("RPC: %4d remote rpcbind service unavailable\n", + task->tk_pid); + break; + case -EPROTONOSUPPORT: + dprintk("RPC: %4d remote rpcbind version 2 unavailable\n", + task->tk_pid); + break; + default: + dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", + task->tk_pid, -task->tk_status); + status = -EIO; + break; + } + + rpc_exit(task, status); + return; + +retry_bind: + task->tk_status = 0; + task->tk_action = call_bind; + return; +} + +/* + * 4b. Connect to the RPC server */ static void call_connect(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; + struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d call_connect status %d\n", - task->tk_pid, task->tk_status); + dprintk("RPC: %4d call_connect xprt %p %s connected\n", + task->tk_pid, xprt, + (xprt_connected(xprt) ? "is" : "is not")); - if (xprt_connected(clnt->cl_xprt)) { - task->tk_action = call_transmit; - return; + task->tk_action = call_transmit; + if (!xprt_connected(xprt)) { + task->tk_action = call_connect_status; + if (task->tk_status < 0) + return; + xprt_connect(task); } - task->tk_action = call_connect_status; - if (task->tk_status < 0) - return; - xprt_connect(task); } /* - * 4b. Sort out connect result + * 4c. Sort out connect result */ static void call_connect_status(struct rpc_task *task) @@ -778,6 +830,9 @@ call_connect_status(struct rpc_task *task) struct rpc_clnt *clnt = task->tk_client; int status = task->tk_status; + dprintk("RPC: %5u call_connect_status (status %d)\n", + task->tk_pid, task->tk_status); + task->tk_status = 0; if (status >= 0) { clnt->cl_stats->netreconn++; @@ -785,17 +840,19 @@ call_connect_status(struct rpc_task *task) return; } - /* Something failed: we may have to rebind */ + /* Something failed: remote service port may have changed */ if (clnt->cl_autobind) clnt->cl_port = 0; + switch (status) { case -ENOTCONN: case -ETIMEDOUT: case -EAGAIN: - task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect; + task->tk_action = call_bind; break; default: rpc_exit(task, -EIO); + break; } } From eab5c084b858fd95a873fc2b97de9a9ad937b4ed Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:14 -0400 Subject: [PATCH 0153/1939] [PATCH] NFS: use a constant value for TCP retransmit timeouts Implement a best practice: don't use exponential backoff when computing retransmit timeout values on TCP connections, but simply retransmit at regular intervals. This also fixes a bug introduced when xprt_reset_majortimeo() was added. Test-plan: Enable RPC debugging and watch timeout behavior on a NFS/TCP mount. Version: Thu, 11 Aug 2005 16:02:19 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 73 +++++++++++++++++++++++------------------------ net/sunrpc/xprt.c | 4 +-- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6922469d6fc5..b6a1ca508e60 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -358,6 +358,35 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) return no_root_error; } +static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans) +{ + to->to_initval = timeo * HZ / 10; + to->to_retries = retrans; + if (!to->to_retries) + to->to_retries = 2; + + switch (proto) { + case IPPROTO_TCP: + if (!to->to_initval) + to->to_initval = 60 * HZ; + if (to->to_initval > RPC_MAX_TCP_TIMEOUT) + to->to_initval = RPC_MAX_TCP_TIMEOUT; + to->to_increment = to->to_initval; + to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); + to->to_exponential = 0; + break; + case IPPROTO_UDP: + default: + if (!to->to_initval) + to->to_initval = 11 * HZ / 10; + if (to->to_initval > RPC_MAX_UDP_TIMEOUT) + to->to_initval = RPC_MAX_UDP_TIMEOUT; + to->to_maxval = RPC_MAX_UDP_TIMEOUT; + to->to_exponential = 1; + break; + } +} + /* * Create an RPC client handle. */ @@ -367,22 +396,12 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) struct rpc_timeout timeparms; struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; - int tcp = (data->flags & NFS_MOUNT_TCP); + int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; - /* Initialize timeout values */ - timeparms.to_initval = data->timeo * HZ / 10; - timeparms.to_retries = data->retrans; - timeparms.to_maxval = tcp ? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT; - timeparms.to_exponential = 1; - - if (!timeparms.to_initval) - timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10; - if (!timeparms.to_retries) - timeparms.to_retries = 5; + nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); /* create transport and client */ - xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, - &server->addr, &timeparms); + xprt = xprt_create_proto(proto, &server->addr, &timeparms); if (IS_ERR(xprt)) { dprintk("%s: cannot create RPC transport. Error = %ld\n", __FUNCTION__, PTR_ERR(xprt)); @@ -1674,7 +1693,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, struct rpc_clnt *clnt = NULL; struct rpc_timeout timeparms; rpc_authflavor_t authflavour; - int proto, err = -EIO; + int err = -EIO; sb->s_blocksize_bits = 0; sb->s_blocksize = 0; @@ -1692,30 +1711,8 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, server->acdirmax = data->acdirmax*HZ; server->rpc_ops = &nfs_v4_clientops; - /* Initialize timeout values */ - timeparms.to_initval = data->timeo * HZ / 10; - timeparms.to_retries = data->retrans; - timeparms.to_exponential = 1; - if (!timeparms.to_retries) - timeparms.to_retries = 5; - - proto = data->proto; - /* Which IP protocol do we use? */ - switch (proto) { - case IPPROTO_TCP: - timeparms.to_maxval = RPC_MAX_TCP_TIMEOUT; - if (!timeparms.to_initval) - timeparms.to_initval = 600 * HZ / 10; - break; - case IPPROTO_UDP: - timeparms.to_maxval = RPC_MAX_UDP_TIMEOUT; - if (!timeparms.to_initval) - timeparms.to_initval = 11 * HZ / 10; - break; - default: - return -EINVAL; - } + nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); clp = nfs4_get_client(&server->addr.sin_addr); if (!clp) { @@ -1740,7 +1737,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, down_write(&clp->cl_sem); if (IS_ERR(clp->cl_rpcclient)) { - xprt = xprt_create_proto(proto, &server->addr, &timeparms); + xprt = xprt_create_proto(data->proto, &server->addr, &timeparms); if (IS_ERR(xprt)) { up_write(&clp->cl_sem); err = PTR_ERR(xprt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index b28ea0cc0cb7..0e4ffdaa0129 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1453,7 +1453,7 @@ xprt_default_timeout(struct rpc_timeout *to, int proto) if (proto == IPPROTO_UDP) xprt_set_timeout(to, 5, 5 * HZ); else - xprt_set_timeout(to, 5, 60 * HZ); + xprt_set_timeout(to, 2, 60 * HZ); } /* @@ -1464,7 +1464,7 @@ xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) { to->to_initval = to->to_increment = incr; - to->to_maxval = incr * retr; + to->to_maxval = to->to_initval + (incr * retr); to->to_retries = retr; to->to_exponential = 0; } From 602f83273c89fdd25f24757564d8001cf723e740 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:17 -0400 Subject: [PATCH 0154/1939] [PATCH] RPC: portmapper doesn't need a reserved port The in-kernel portmapper does not require a reserved port for making bind queries. Test-plan: Tens of runs of the Connectathon locking suite with TCP and UDP against several other NFS server implementations using NFSv3, not NFSv4 (which doesn't require rpcbind). Version: Thu, 11 Aug 2005 16:02:43 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/pmap_clnt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 4e81f2766923..d8e3f220002b 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -208,6 +208,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) if (IS_ERR(xprt)) return (struct rpc_clnt *)xprt; xprt->addr.sin_port = htons(RPC_PMAP_PORT); + xprt->resvport = 0; /* printk("pmap: create clnt\n"); */ clnt = rpc_new_client(xprt, hostname, From 094bb20b9fcab3a1652a77741caba6b78097d622 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:20 -0400 Subject: [PATCH 0155/1939] [PATCH] RPC: extract socket logic common to both client and server Clean-up: Move some code that is common to both RPC client- and server-side socket transports into its own source file, net/sunrpc/socklib.c. Test-plan: Compile kernel with CONFIG_NFS enabled. Millions of fsx operations over UDP, client and server. Connectathon over UDP. Version: Thu, 11 Aug 2005 16:03:09 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 1 + net/sunrpc/Makefile | 2 +- net/sunrpc/socklib.c | 175 +++++++++++++++++++++++++++++++++++++ net/sunrpc/svcsock.c | 3 - net/sunrpc/xdr.c | 75 ---------------- net/sunrpc/xprt.c | 64 -------------- 6 files changed, 177 insertions(+), 143 deletions(-) create mode 100644 net/sunrpc/socklib.c diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 23448d0fb5bc..d8b7656bca41 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -161,6 +161,7 @@ typedef struct { typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); +extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 46a2ce00a29b..f0a955627177 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_SUNRPC) += sunrpc.o obj-$(CONFIG_SUNRPC_GSS) += auth_gss/ -sunrpc-y := clnt.o xprt.o sched.o \ +sunrpc-y := clnt.o xprt.o socklib.o sched.o \ auth.o auth_null.o auth_unix.o \ svc.o svcsock.o svcauth.o svcauth_unix.o \ pmap_clnt.o timer.o xdr.o \ diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c new file mode 100644 index 000000000000..8f97e90f36c8 --- /dev/null +++ b/net/sunrpc/socklib.c @@ -0,0 +1,175 @@ +/* + * linux/net/sunrpc/socklib.c + * + * Common socket helper routines for RPC client and server + * + * Copyright (C) 1995, 1996 Olaf Kirch + */ + +#include +#include +#include +#include + + +/** + * skb_read_bits - copy some data bits from skb to internal buffer + * @desc: sk_buff copy helper + * @to: copy destination + * @len: number of bytes to copy + * + * Possibly called several times to iterate over an sk_buff and copy + * data out of it. + */ +static size_t skb_read_bits(skb_reader_t *desc, void *to, size_t len) +{ + if (len > desc->count) + len = desc->count; + if (skb_copy_bits(desc->skb, desc->offset, to, len)) + return 0; + desc->count -= len; + desc->offset += len; + return len; +} + +/** + * skb_read_and_csum_bits - copy and checksum from skb to buffer + * @desc: sk_buff copy helper + * @to: copy destination + * @len: number of bytes to copy + * + * Same as skb_read_bits, but calculate a checksum at the same time. + */ +static size_t skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) +{ + unsigned int csum2, pos; + + if (len > desc->count) + len = desc->count; + pos = desc->offset; + csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0); + desc->csum = csum_block_add(desc->csum, csum2, pos); + desc->count -= len; + desc->offset += len; + return len; +} + +/** + * xdr_partial_copy_from_skb - copy data out of an skb + * @xdr: target XDR buffer + * @base: starting offset + * @desc: sk_buff copy helper + * @copy_actor: virtual method for copying data + * + */ +ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, skb_reader_t *desc, skb_read_actor_t copy_actor) +{ + struct page **ppage = xdr->pages; + unsigned int len, pglen = xdr->page_len; + ssize_t copied = 0; + int ret; + + len = xdr->head[0].iov_len; + if (base < len) { + len -= base; + ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); + copied += ret; + if (ret != len || !desc->count) + goto out; + base = 0; + } else + base -= len; + + if (unlikely(pglen == 0)) + goto copy_tail; + if (unlikely(base >= pglen)) { + base -= pglen; + goto copy_tail; + } + if (base || xdr->page_base) { + pglen -= base; + base += xdr->page_base; + ppage += base >> PAGE_CACHE_SHIFT; + base &= ~PAGE_CACHE_MASK; + } + do { + char *kaddr; + + /* ACL likes to be lazy in allocating pages - ACLs + * are small by default but can get huge. */ + if (unlikely(*ppage == NULL)) { + *ppage = alloc_page(GFP_ATOMIC); + if (unlikely(*ppage == NULL)) { + if (copied == 0) + copied = -ENOMEM; + goto out; + } + } + + len = PAGE_CACHE_SIZE; + kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); + if (base) { + len -= base; + if (pglen < len) + len = pglen; + ret = copy_actor(desc, kaddr + base, len); + base = 0; + } else { + if (pglen < len) + len = pglen; + ret = copy_actor(desc, kaddr, len); + } + flush_dcache_page(*ppage); + kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); + copied += ret; + if (ret != len || !desc->count) + goto out; + ppage++; + } while ((pglen -= len) != 0); +copy_tail: + len = xdr->tail[0].iov_len; + if (base < len) + copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); +out: + return copied; +} + +/** + * csum_partial_copy_to_xdr - checksum and copy data + * @xdr: target XDR buffer + * @skb: source skb + * + * We have set things up such that we perform the checksum of the UDP + * packet in parallel with the copies into the RPC client iovec. -DaveM + */ +int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) +{ + skb_reader_t desc; + + desc.skb = skb; + desc.offset = sizeof(struct udphdr); + desc.count = skb->len - desc.offset; + + if (skb->ip_summed == CHECKSUM_UNNECESSARY) + goto no_checksum; + + desc.csum = csum_partial(skb->data, desc.offset, skb->csum); + if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) + return -1; + if (desc.offset != skb->len) { + unsigned int csum2; + csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); + desc.csum = csum_block_add(desc.csum, csum2, desc.offset); + } + if (desc.count) + return -1; + if ((unsigned short)csum_fold(desc.csum)) + return -1; + return 0; +no_checksum: + if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) + return -1; + if (desc.count) + return -1; + return 0; +} diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 30ec3efc48a6..130f2b5d93dd 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -548,9 +548,6 @@ svc_write_space(struct sock *sk) /* * Receive a datagram from a UDP socket. */ -extern int -csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb); - static int svc_udp_recvfrom(struct svc_rqst *rqstp) { diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index fde16f40a581..9cc12aeed22c 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -176,81 +176,6 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, xdr->buflen += len; } -ssize_t -xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, - skb_reader_t *desc, - skb_read_actor_t copy_actor) -{ - struct page **ppage = xdr->pages; - unsigned int len, pglen = xdr->page_len; - ssize_t copied = 0; - int ret; - - len = xdr->head[0].iov_len; - if (base < len) { - len -= base; - ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); - copied += ret; - if (ret != len || !desc->count) - goto out; - base = 0; - } else - base -= len; - - if (pglen == 0) - goto copy_tail; - if (base >= pglen) { - base -= pglen; - goto copy_tail; - } - if (base || xdr->page_base) { - pglen -= base; - base += xdr->page_base; - ppage += base >> PAGE_CACHE_SHIFT; - base &= ~PAGE_CACHE_MASK; - } - do { - char *kaddr; - - /* ACL likes to be lazy in allocating pages - ACLs - * are small by default but can get huge. */ - if (unlikely(*ppage == NULL)) { - *ppage = alloc_page(GFP_ATOMIC); - if (unlikely(*ppage == NULL)) { - if (copied == 0) - copied = -ENOMEM; - goto out; - } - } - - len = PAGE_CACHE_SIZE; - kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); - if (base) { - len -= base; - if (pglen < len) - len = pglen; - ret = copy_actor(desc, kaddr + base, len); - base = 0; - } else { - if (pglen < len) - len = pglen; - ret = copy_actor(desc, kaddr, len); - } - flush_dcache_page(*ppage); - kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); - copied += ret; - if (ret != len || !desc->count) - goto out; - ppage++; - } while ((pglen -= len) != 0); -copy_tail: - len = xdr->tail[0].iov_len; - if (base < len) - copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); -out: - return copied; -} - int xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 0e4ffdaa0129..67444f494fea 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -691,70 +691,6 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) return; } -static size_t -skb_read_bits(skb_reader_t *desc, void *to, size_t len) -{ - if (len > desc->count) - len = desc->count; - if (skb_copy_bits(desc->skb, desc->offset, to, len)) - return 0; - desc->count -= len; - desc->offset += len; - return len; -} - -static size_t -skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) -{ - unsigned int csum2, pos; - - if (len > desc->count) - len = desc->count; - pos = desc->offset; - csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0); - desc->csum = csum_block_add(desc->csum, csum2, pos); - desc->count -= len; - desc->offset += len; - return len; -} - -/* - * We have set things up such that we perform the checksum of the UDP - * packet in parallel with the copies into the RPC client iovec. -DaveM - */ -int -csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) -{ - skb_reader_t desc; - - desc.skb = skb; - desc.offset = sizeof(struct udphdr); - desc.count = skb->len - desc.offset; - - if (skb->ip_summed == CHECKSUM_UNNECESSARY) - goto no_checksum; - - desc.csum = csum_partial(skb->data, desc.offset, skb->csum); - if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) - return -1; - if (desc.offset != skb->len) { - unsigned int csum2; - csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); - desc.csum = csum_block_add(desc.csum, csum2, desc.offset); - } - if (desc.count) - return -1; - if ((unsigned short)csum_fold(desc.csum)) - return -1; - return 0; -no_checksum: - if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) - return -1; - if (desc.count) - return -1; - return 0; -} - /* * Input handler for RPC replies. Called from a bottom half and hence * atomic. From a246b0105bbd9a70a698f69baae2042996f2a0e9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:23 -0400 Subject: [PATCH 0156/1939] [PATCH] RPC: introduce client-side transport switch Move the bulk of client-side socket-specific code into a separate source file, net/sunrpc/xprtsock.c. Test-plan: Millions of fsx operations. Performance characterization such as "sio" or "iozone". Destructive testing (unplugging the network temporarily, server reboots). Connectathon with v2, v3, and v4. Version: Thu, 11 Aug 2005 16:03:38 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 5 - include/linux/sunrpc/xprt.h | 38 +- net/sunrpc/Makefile | 2 +- net/sunrpc/clnt.c | 3 +- net/sunrpc/sysctl.c | 3 + net/sunrpc/xdr.c | 102 +--- net/sunrpc/xprt.c | 916 ++----------------------------- net/sunrpc/xprtsock.c | 1021 +++++++++++++++++++++++++++++++++++ 8 files changed, 1101 insertions(+), 989 deletions(-) create mode 100644 net/sunrpc/xprtsock.c diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index d8b7656bca41..5da968729cf8 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -165,11 +165,6 @@ extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); -struct socket; -struct sockaddr; -extern int xdr_sendpages(struct socket *, struct sockaddr *, int, - struct xdr_buf *, unsigned int, int); - extern int xdr_encode_word(struct xdr_buf *, int, u32); extern int xdr_decode_word(struct xdr_buf *, int, u32 *); diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index e618c1649814..d82b47ab73cb 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -59,7 +59,13 @@ extern unsigned int xprt_tcp_slot_table_entries; */ #define RPC_REESTABLISH_TIMEOUT (15*HZ) -/* RPC call and reply header size as number of 32bit words (verifier +/* + * RPC transport idle timeout. + */ +#define RPC_IDLE_DISCONNECT_TIMEOUT (5*60*HZ) + +/* + * RPC call and reply header size as number of 32bit words (verifier * size computed separately) */ #define RPC_CALLHDRSIZE 6 @@ -121,12 +127,19 @@ struct rpc_rqst { #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len -#define XPRT_LAST_FRAG (1 << 0) -#define XPRT_COPY_RECM (1 << 1) -#define XPRT_COPY_XID (1 << 2) -#define XPRT_COPY_DATA (1 << 3) +struct rpc_task; +struct rpc_xprt; + +struct rpc_xprt_ops { + void (*set_buffer_size)(struct rpc_xprt *xprt); + void (*connect)(struct rpc_task *task); + int (*send_request)(struct rpc_task *task); + void (*close)(struct rpc_xprt *xprt); + void (*destroy)(struct rpc_xprt *xprt); +}; struct rpc_xprt { + struct rpc_xprt_ops * ops; /* transport methods */ struct socket * sock; /* BSD socket layer */ struct sock * inet; /* INET layer */ @@ -199,14 +212,22 @@ struct rpc_xprt { wait_queue_head_t cong_wait; }; +#define XPRT_LAST_FRAG (1 << 0) +#define XPRT_COPY_RECM (1 << 1) +#define XPRT_COPY_XID (1 << 2) +#define XPRT_COPY_DATA (1 << 3) + #ifdef __KERNEL__ struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, struct rpc_timeout *toparms); +void xprt_disconnect(struct rpc_xprt *); int xprt_destroy(struct rpc_xprt *); void xprt_set_timeout(struct rpc_timeout *, unsigned int, unsigned long); - +struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *, u32); +void xprt_complete_rqst(struct rpc_xprt *, + struct rpc_rqst *, int); void xprt_reserve(struct rpc_task *); int xprt_prepare_transmit(struct rpc_task *); void xprt_transmit(struct rpc_task *); @@ -214,7 +235,10 @@ void xprt_receive(struct rpc_task *); int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release(struct rpc_task *); void xprt_connect(struct rpc_task *); -void xprt_sock_setbufsize(struct rpc_xprt *); +int xs_setup_udp(struct rpc_xprt *, + struct rpc_timeout *); +int xs_setup_tcp(struct rpc_xprt *, + struct rpc_timeout *); #define XPRT_LOCKED 0 #define XPRT_CONNECT 1 diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index f0a955627177..cdcab9ca4c60 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_SUNRPC) += sunrpc.o obj-$(CONFIG_SUNRPC_GSS) += auth_gss/ -sunrpc-y := clnt.o xprt.o socklib.o sched.o \ +sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ auth.o auth_null.o auth_unix.o \ svc.o svcsock.o svcauth.o svcauth_unix.o \ pmap_clnt.o timer.o xdr.o \ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 2d3cf0a52d82..ab50c3c9e6a8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -525,8 +525,7 @@ rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize xprt->rcvsize = 0; if (rcvsize) xprt->rcvsize = rcvsize + RPC_SLACK_SPACE; - if (xprt_connected(xprt)) - xprt_sock_setbufsize(xprt); + xprt->ops->set_buffer_size(xprt); } /* diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 1b9616a12e24..ef483262f17f 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -119,6 +119,9 @@ proc_dodebug(ctl_table *table, int write, struct file *file, return 0; } +unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; +unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; + static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 9cc12aeed22c..32df43372ee9 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -6,15 +6,12 @@ * Copyright (C) 1995, 1996 Olaf Kirch */ +#include #include -#include #include #include #include #include -#include -#include -#include #include #include @@ -177,103 +174,6 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, } -int -xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, - struct xdr_buf *xdr, unsigned int base, int msgflags) -{ - struct page **ppage = xdr->pages; - unsigned int len, pglen = xdr->page_len; - int err, ret = 0; - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); - - len = xdr->head[0].iov_len; - if (base < len || (addr != NULL && base == 0)) { - struct kvec iov = { - .iov_base = xdr->head[0].iov_base + base, - .iov_len = len - base, - }; - struct msghdr msg = { - .msg_name = addr, - .msg_namelen = addrlen, - .msg_flags = msgflags, - }; - if (xdr->len > len) - msg.msg_flags |= MSG_MORE; - - if (iov.iov_len != 0) - err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); - else - err = kernel_sendmsg(sock, &msg, NULL, 0, 0); - if (ret == 0) - ret = err; - else if (err > 0) - ret += err; - if (err != iov.iov_len) - goto out; - base = 0; - } else - base -= len; - - if (pglen == 0) - goto copy_tail; - if (base >= pglen) { - base -= pglen; - goto copy_tail; - } - if (base || xdr->page_base) { - pglen -= base; - base += xdr->page_base; - ppage += base >> PAGE_CACHE_SHIFT; - base &= ~PAGE_CACHE_MASK; - } - - sendpage = sock->ops->sendpage ? : sock_no_sendpage; - do { - int flags = msgflags; - - len = PAGE_CACHE_SIZE; - if (base) - len -= base; - if (pglen < len) - len = pglen; - - if (pglen != len || xdr->tail[0].iov_len != 0) - flags |= MSG_MORE; - - /* Hmm... We might be dealing with highmem pages */ - if (PageHighMem(*ppage)) - sendpage = sock_no_sendpage; - err = sendpage(sock, *ppage, base, len, flags); - if (ret == 0) - ret = err; - else if (err > 0) - ret += err; - if (err != len) - goto out; - base = 0; - ppage++; - } while ((pglen -= len) != 0); -copy_tail: - len = xdr->tail[0].iov_len; - if (base < len) { - struct kvec iov = { - .iov_base = xdr->tail[0].iov_base + base, - .iov_len = len - base, - }; - struct msghdr msg = { - .msg_flags = msgflags, - }; - err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); - if (ret == 0) - ret = err; - else if (err > 0) - ret += err; - } -out: - return ret; -} - - /* * Helper routines for doing 'memmove' like operations on a struct xdr_buf * diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 67444f494fea..4342acf4d1cd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -32,37 +32,16 @@ * tasks that rely on callbacks. * * Copyright (C) 1995-1997, Olaf Kirch - * - * TCP callback races fixes (C) 1998 Red Hat Software - * TCP send fixes (C) 1998 Red Hat Software - * TCP NFS related read + write fixes - * (C) 1999 Dave Airlie, University of Limerick, Ireland - * - * Rewrite of larges part of the code in order to stabilize TCP stuff. - * Fix behaviour when socket buffer is full. - * (C) 1999 Trond Myklebust */ +#include + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#include -#include -#include -#include +#include /* * Local variables @@ -74,64 +53,17 @@ #endif #define XPRT_MAX_BACKOFF (8) -#define XPRT_IDLE_TIMEOUT (5*60*HZ) -#define XPRT_MAX_RESVPORT (800) /* * Local functions */ static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static inline void do_xprt_reserve(struct rpc_task *); -static void xprt_disconnect(struct rpc_xprt *); static void xprt_connect_status(struct rpc_task *task); -static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, - struct rpc_timeout *to); -static struct socket *xprt_create_socket(struct rpc_xprt *, int, int); -static void xprt_bind_socket(struct rpc_xprt *, struct socket *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); static int xprt_clear_backlog(struct rpc_xprt *xprt); -#ifdef RPC_DEBUG_DATA -/* - * Print the buffer contents (first 128 bytes only--just enough for - * diropres return). - */ -static void -xprt_pktdump(char *msg, u32 *packet, unsigned int count) -{ - u8 *buf = (u8 *) packet; - int j; - - dprintk("RPC: %s\n", msg); - for (j = 0; j < count && j < 128; j += 4) { - if (!(j & 31)) { - if (j) - dprintk("\n"); - dprintk("0x%04x ", j); - } - dprintk("%02x%02x%02x%02x ", - buf[j], buf[j+1], buf[j+2], buf[j+3]); - } - dprintk("\n"); -} -#else -static inline void -xprt_pktdump(char *msg, u32 *packet, unsigned int count) -{ - /* NOP */ -} -#endif - -/* - * Look up RPC transport given an INET socket - */ -static inline struct rpc_xprt * -xprt_from_sock(struct sock *sk) -{ - return (struct rpc_xprt *) sk->sk_user_data; -} - /* * Serialize write access to sockets, in order to prevent different * requests from interfering with each other. @@ -234,62 +166,6 @@ xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) spin_unlock_bh(&xprt->sock_lock); } -/* - * Write data to socket. - */ -static inline int -xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) -{ - struct socket *sock = xprt->sock; - struct xdr_buf *xdr = &req->rq_snd_buf; - struct sockaddr *addr = NULL; - int addrlen = 0; - unsigned int skip; - int result; - - if (!sock) - return -ENOTCONN; - - xprt_pktdump("packet data:", - req->rq_svec->iov_base, - req->rq_svec->iov_len); - - /* For UDP, we need to provide an address */ - if (!xprt->stream) { - addr = (struct sockaddr *) &xprt->addr; - addrlen = sizeof(xprt->addr); - } - /* Dont repeat bytes */ - skip = req->rq_bytes_sent; - - clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); - result = xdr_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); - - dprintk("RPC: xprt_sendmsg(%d) = %d\n", xdr->len - skip, result); - - if (result >= 0) - return result; - - switch (result) { - case -ECONNREFUSED: - /* When the server has died, an ICMP port unreachable message - * prompts ECONNREFUSED. - */ - case -EAGAIN: - break; - case -ECONNRESET: - case -ENOTCONN: - case -EPIPE: - /* connection broken */ - if (xprt->stream) - result = -ENOTCONN; - break; - default: - printk(KERN_NOTICE "RPC: sendmsg returned error %d\n", -result); - } - return result; -} - /* * Van Jacobson congestion avoidance. Check if the congestion window * overflowed. Put the task to sleep if this is the case. @@ -405,48 +281,20 @@ int xprt_adjust_timeout(struct rpc_rqst *req) return status; } -/* - * Close down a transport socket - */ -static void -xprt_close(struct rpc_xprt *xprt) -{ - struct socket *sock = xprt->sock; - struct sock *sk = xprt->inet; - - if (!sk) - return; - - write_lock_bh(&sk->sk_callback_lock); - xprt->inet = NULL; - xprt->sock = NULL; - - sk->sk_user_data = NULL; - sk->sk_data_ready = xprt->old_data_ready; - sk->sk_state_change = xprt->old_state_change; - sk->sk_write_space = xprt->old_write_space; - write_unlock_bh(&sk->sk_callback_lock); - - sk->sk_no_check = 0; - - sock_release(sock); -} - static void xprt_socket_autoclose(void *args) { struct rpc_xprt *xprt = (struct rpc_xprt *)args; xprt_disconnect(xprt); - xprt_close(xprt); + xprt->ops->close(xprt); xprt_release_write(xprt, NULL); } /* * Mark a transport as disconnected */ -static void -xprt_disconnect(struct rpc_xprt *xprt) +void xprt_disconnect(struct rpc_xprt *xprt) { dprintk("RPC: disconnected transport %p\n", xprt); spin_lock_bh(&xprt->sock_lock); @@ -479,57 +327,6 @@ xprt_init_autodisconnect(unsigned long data) spin_unlock(&xprt->sock_lock); } -static void xprt_socket_connect(void *args) -{ - struct rpc_xprt *xprt = (struct rpc_xprt *)args; - struct socket *sock = xprt->sock; - int status = -EIO; - - if (xprt->shutdown || xprt->addr.sin_port == 0) - goto out; - - /* - * Start by resetting any existing state - */ - xprt_close(xprt); - sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport); - if (sock == NULL) { - /* couldn't create socket or bind to reserved port; - * this is likely a permanent error, so cause an abort */ - goto out; - } - xprt_bind_socket(xprt, sock); - xprt_sock_setbufsize(xprt); - - status = 0; - if (!xprt->stream) - goto out; - - /* - * Tell the socket layer to start connecting... - */ - status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, - sizeof(xprt->addr), O_NONBLOCK); - dprintk("RPC: %p connect status %d connected %d sock state %d\n", - xprt, -status, xprt_connected(xprt), sock->sk->sk_state); - if (status < 0) { - switch (status) { - case -EINPROGRESS: - case -EALREADY: - goto out_clear; - } - } -out: - if (status < 0) - rpc_wake_up_status(&xprt->pending, status); - else - rpc_wake_up(&xprt->pending); -out_clear: - smp_mb__before_clear_bit(); - clear_bit(XPRT_CONNECTING, &xprt->sockstate); - smp_mb__after_clear_bit(); -} - /* * Attempt to connect a TCP socket. * @@ -552,30 +349,16 @@ void xprt_connect(struct rpc_task *task) if (!xprt_lock_write(xprt, task)) return; if (xprt_connected(xprt)) - goto out_write; + xprt_release_write(xprt, task); + else { + if (task->tk_rqstp) + task->tk_rqstp->rq_bytes_sent = 0; - if (task->tk_rqstp) - task->tk_rqstp->rq_bytes_sent = 0; - - task->tk_timeout = RPC_CONNECT_TIMEOUT; - rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); - if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { - /* Note: if we are here due to a dropped connection - * we delay reconnecting by RPC_REESTABLISH_TIMEOUT/HZ - * seconds - */ - if (xprt->sock != NULL) - schedule_delayed_work(&xprt->sock_connect, - RPC_REESTABLISH_TIMEOUT); - else { - schedule_work(&xprt->sock_connect); - if (!RPC_IS_ASYNC(task)) - flush_scheduled_work(); - } + task->tk_timeout = RPC_CONNECT_TIMEOUT; + rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); + xprt->ops->connect(task); } return; - out_write: - xprt_release_write(xprt, task); } /* @@ -624,8 +407,7 @@ xprt_connect_status(struct rpc_task *task) /* * Look up the RPC request corresponding to a reply, and then lock it. */ -static inline struct rpc_rqst * -xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) +struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) { struct list_head *pos; struct rpc_rqst *req = NULL; @@ -644,8 +426,7 @@ xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) * Complete reply received. * The TCP code relies on us to remove the request from xprt->pending. */ -static void -xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) +void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) { struct rpc_task *task = req->rq_task; struct rpc_clnt *clnt = task->tk_client; @@ -691,409 +472,6 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) return; } -/* - * Input handler for RPC replies. Called from a bottom half and hence - * atomic. - */ -static void -udp_data_ready(struct sock *sk, int len) -{ - struct rpc_task *task; - struct rpc_xprt *xprt; - struct rpc_rqst *rovr; - struct sk_buff *skb; - int err, repsize, copied; - u32 _xid, *xp; - - read_lock(&sk->sk_callback_lock); - dprintk("RPC: udp_data_ready...\n"); - if (!(xprt = xprt_from_sock(sk))) { - printk("RPC: udp_data_ready request not found!\n"); - goto out; - } - - dprintk("RPC: udp_data_ready client %p\n", xprt); - - if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) - goto out; - - if (xprt->shutdown) - goto dropit; - - repsize = skb->len - sizeof(struct udphdr); - if (repsize < 4) { - printk("RPC: impossible RPC reply size %d!\n", repsize); - goto dropit; - } - - /* Copy the XID from the skb... */ - xp = skb_header_pointer(skb, sizeof(struct udphdr), - sizeof(_xid), &_xid); - if (xp == NULL) - goto dropit; - - /* Look up and lock the request corresponding to the given XID */ - spin_lock(&xprt->sock_lock); - rovr = xprt_lookup_rqst(xprt, *xp); - if (!rovr) - goto out_unlock; - task = rovr->rq_task; - - dprintk("RPC: %4d received reply\n", task->tk_pid); - - if ((copied = rovr->rq_private_buf.buflen) > repsize) - copied = repsize; - - /* Suck it into the iovec, verify checksum if not done by hw. */ - if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) - goto out_unlock; - - /* Something worked... */ - dst_confirm(skb->dst); - - xprt_complete_rqst(xprt, rovr, copied); - - out_unlock: - spin_unlock(&xprt->sock_lock); - dropit: - skb_free_datagram(sk, skb); - out: - read_unlock(&sk->sk_callback_lock); -} - -/* - * Copy from an skb into memory and shrink the skb. - */ -static inline size_t -tcp_copy_data(skb_reader_t *desc, void *p, size_t len) -{ - if (len > desc->count) - len = desc->count; - if (skb_copy_bits(desc->skb, desc->offset, p, len)) { - dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", - len, desc->count); - return 0; - } - desc->offset += len; - desc->count -= len; - dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", - len, desc->count); - return len; -} - -/* - * TCP read fragment marker - */ -static inline void -tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) -{ - size_t len, used; - char *p; - - p = ((char *) &xprt->tcp_recm) + xprt->tcp_offset; - len = sizeof(xprt->tcp_recm) - xprt->tcp_offset; - used = tcp_copy_data(desc, p, len); - xprt->tcp_offset += used; - if (used != len) - return; - xprt->tcp_reclen = ntohl(xprt->tcp_recm); - if (xprt->tcp_reclen & 0x80000000) - xprt->tcp_flags |= XPRT_LAST_FRAG; - else - xprt->tcp_flags &= ~XPRT_LAST_FRAG; - xprt->tcp_reclen &= 0x7fffffff; - xprt->tcp_flags &= ~XPRT_COPY_RECM; - xprt->tcp_offset = 0; - /* Sanity check of the record length */ - if (xprt->tcp_reclen < 4) { - printk(KERN_ERR "RPC: Invalid TCP record fragment length\n"); - xprt_disconnect(xprt); - } - dprintk("RPC: reading TCP record fragment of length %d\n", - xprt->tcp_reclen); -} - -static void -tcp_check_recm(struct rpc_xprt *xprt) -{ - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); - if (xprt->tcp_offset == xprt->tcp_reclen) { - xprt->tcp_flags |= XPRT_COPY_RECM; - xprt->tcp_offset = 0; - if (xprt->tcp_flags & XPRT_LAST_FRAG) { - xprt->tcp_flags &= ~XPRT_COPY_DATA; - xprt->tcp_flags |= XPRT_COPY_XID; - xprt->tcp_copied = 0; - } - } -} - -/* - * TCP read xid - */ -static inline void -tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) -{ - size_t len, used; - char *p; - - len = sizeof(xprt->tcp_xid) - xprt->tcp_offset; - dprintk("RPC: reading XID (%Zu bytes)\n", len); - p = ((char *) &xprt->tcp_xid) + xprt->tcp_offset; - used = tcp_copy_data(desc, p, len); - xprt->tcp_offset += used; - if (used != len) - return; - xprt->tcp_flags &= ~XPRT_COPY_XID; - xprt->tcp_flags |= XPRT_COPY_DATA; - xprt->tcp_copied = 4; - dprintk("RPC: reading reply for XID %08x\n", - ntohl(xprt->tcp_xid)); - tcp_check_recm(xprt); -} - -/* - * TCP read and complete request - */ -static inline void -tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) -{ - struct rpc_rqst *req; - struct xdr_buf *rcvbuf; - size_t len; - ssize_t r; - - /* Find and lock the request corresponding to this xid */ - spin_lock(&xprt->sock_lock); - req = xprt_lookup_rqst(xprt, xprt->tcp_xid); - if (!req) { - xprt->tcp_flags &= ~XPRT_COPY_DATA; - dprintk("RPC: XID %08x request not found!\n", - ntohl(xprt->tcp_xid)); - spin_unlock(&xprt->sock_lock); - return; - } - - rcvbuf = &req->rq_private_buf; - len = desc->count; - if (len > xprt->tcp_reclen - xprt->tcp_offset) { - skb_reader_t my_desc; - - len = xprt->tcp_reclen - xprt->tcp_offset; - memcpy(&my_desc, desc, sizeof(my_desc)); - my_desc.count = len; - r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, - &my_desc, tcp_copy_data); - desc->count -= r; - desc->offset += r; - } else - r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, - desc, tcp_copy_data); - - if (r > 0) { - xprt->tcp_copied += r; - xprt->tcp_offset += r; - } - if (r != len) { - /* Error when copying to the receive buffer, - * usually because we weren't able to allocate - * additional buffer pages. All we can do now - * is turn off XPRT_COPY_DATA, so the request - * will not receive any additional updates, - * and time out. - * Any remaining data from this record will - * be discarded. - */ - xprt->tcp_flags &= ~XPRT_COPY_DATA; - dprintk("RPC: XID %08x truncated request\n", - ntohl(xprt->tcp_xid)); - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); - goto out; - } - - dprintk("RPC: XID %08x read %Zd bytes\n", - ntohl(xprt->tcp_xid), r); - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); - - if (xprt->tcp_copied == req->rq_private_buf.buflen) - xprt->tcp_flags &= ~XPRT_COPY_DATA; - else if (xprt->tcp_offset == xprt->tcp_reclen) { - if (xprt->tcp_flags & XPRT_LAST_FRAG) - xprt->tcp_flags &= ~XPRT_COPY_DATA; - } - -out: - if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { - dprintk("RPC: %4d received reply complete\n", - req->rq_task->tk_pid); - xprt_complete_rqst(xprt, req, xprt->tcp_copied); - } - spin_unlock(&xprt->sock_lock); - tcp_check_recm(xprt); -} - -/* - * TCP discard extra bytes from a short read - */ -static inline void -tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) -{ - size_t len; - - len = xprt->tcp_reclen - xprt->tcp_offset; - if (len > desc->count) - len = desc->count; - desc->count -= len; - desc->offset += len; - xprt->tcp_offset += len; - dprintk("RPC: discarded %Zu bytes\n", len); - tcp_check_recm(xprt); -} - -/* - * TCP record receive routine - * We first have to grab the record marker, then the XID, then the data. - */ -static int -tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, - unsigned int offset, size_t len) -{ - struct rpc_xprt *xprt = rd_desc->arg.data; - skb_reader_t desc = { - .skb = skb, - .offset = offset, - .count = len, - .csum = 0 - }; - - dprintk("RPC: tcp_data_recv\n"); - do { - /* Read in a new fragment marker if necessary */ - /* Can we ever really expect to get completely empty fragments? */ - if (xprt->tcp_flags & XPRT_COPY_RECM) { - tcp_read_fraghdr(xprt, &desc); - continue; - } - /* Read in the xid if necessary */ - if (xprt->tcp_flags & XPRT_COPY_XID) { - tcp_read_xid(xprt, &desc); - continue; - } - /* Read in the request data */ - if (xprt->tcp_flags & XPRT_COPY_DATA) { - tcp_read_request(xprt, &desc); - continue; - } - /* Skip over any trailing bytes on short reads */ - tcp_read_discard(xprt, &desc); - } while (desc.count); - dprintk("RPC: tcp_data_recv done\n"); - return len - desc.count; -} - -static void tcp_data_ready(struct sock *sk, int bytes) -{ - struct rpc_xprt *xprt; - read_descriptor_t rd_desc; - - read_lock(&sk->sk_callback_lock); - dprintk("RPC: tcp_data_ready...\n"); - if (!(xprt = xprt_from_sock(sk))) { - printk("RPC: tcp_data_ready socket info not found!\n"); - goto out; - } - if (xprt->shutdown) - goto out; - - /* We use rd_desc to pass struct xprt to tcp_data_recv */ - rd_desc.arg.data = xprt; - rd_desc.count = 65536; - tcp_read_sock(sk, &rd_desc, tcp_data_recv); -out: - read_unlock(&sk->sk_callback_lock); -} - -static void -tcp_state_change(struct sock *sk) -{ - struct rpc_xprt *xprt; - - read_lock(&sk->sk_callback_lock); - if (!(xprt = xprt_from_sock(sk))) - goto out; - dprintk("RPC: tcp_state_change client %p...\n", xprt); - dprintk("RPC: state %x conn %d dead %d zapped %d\n", - sk->sk_state, xprt_connected(xprt), - sock_flag(sk, SOCK_DEAD), - sock_flag(sk, SOCK_ZAPPED)); - - switch (sk->sk_state) { - case TCP_ESTABLISHED: - spin_lock_bh(&xprt->sock_lock); - if (!xprt_test_and_set_connected(xprt)) { - /* Reset TCP record info */ - xprt->tcp_offset = 0; - xprt->tcp_reclen = 0; - xprt->tcp_copied = 0; - xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - rpc_wake_up(&xprt->pending); - } - spin_unlock_bh(&xprt->sock_lock); - break; - case TCP_SYN_SENT: - case TCP_SYN_RECV: - break; - default: - xprt_disconnect(xprt); - break; - } - out: - read_unlock(&sk->sk_callback_lock); -} - -/* - * Called when more output buffer space is available for this socket. - * We try not to wake our writers until they can make "significant" - * progress, otherwise we'll waste resources thrashing sock_sendmsg - * with a bunch of small requests. - */ -static void -xprt_write_space(struct sock *sk) -{ - struct rpc_xprt *xprt; - struct socket *sock; - - read_lock(&sk->sk_callback_lock); - if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) - goto out; - if (xprt->shutdown) - goto out; - - /* Wait until we have enough socket memory */ - if (xprt->stream) { - /* from net/core/stream.c:sk_stream_write_space */ - if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk)) - goto out; - } else { - /* from net/core/sock.c:sock_def_write_space */ - if (!sock_writeable(sk)) - goto out; - } - - if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) - goto out; - - spin_lock_bh(&xprt->sock_lock); - if (xprt->snd_task) - rpc_wake_up_task(xprt->snd_task); - spin_unlock_bh(&xprt->sock_lock); -out: - read_unlock(&sk->sk_callback_lock); -} - /* * RPC receive timeout handler. */ @@ -1161,19 +539,10 @@ xprt_transmit(struct rpc_task *task) struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - int status, retry = 0; - + int status; dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); - /* set up everything as needed. */ - /* Write the record marker */ - if (xprt->stream) { - u32 *marker = req->rq_svec[0].iov_base; - - *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); - } - smp_rmb(); if (!req->rq_received) { if (list_empty(&req->rq_list)) { @@ -1191,41 +560,9 @@ xprt_transmit(struct rpc_task *task) } else if (!req->rq_bytes_sent) return; - /* Continue transmitting the packet/record. We must be careful - * to cope with writespace callbacks arriving _after_ we have - * called xprt_sendmsg(). - */ - while (1) { - req->rq_xtime = jiffies; - status = xprt_sendmsg(xprt, req); - - if (status < 0) - break; - - if (xprt->stream) { - req->rq_bytes_sent += status; - - /* If we've sent the entire packet, immediately - * reset the count of bytes sent. */ - if (req->rq_bytes_sent >= req->rq_slen) { - req->rq_bytes_sent = 0; - goto out_receive; - } - } else { - if (status >= req->rq_slen) - goto out_receive; - status = -EAGAIN; - break; - } - - dprintk("RPC: %4d xmit incomplete (%d left of %d)\n", - task->tk_pid, req->rq_slen - req->rq_bytes_sent, - req->rq_slen); - - status = -EAGAIN; - if (retry++ > 50) - break; - } + status = xprt->ops->send_request(task); + if (!status) + goto out_receive; /* Note: at this point, task->tk_sleeping has not yet been set, * hence there is no danger of the waking up task being put on @@ -1234,26 +571,10 @@ xprt_transmit(struct rpc_task *task) task->tk_status = status; switch (status) { - case -EAGAIN: - if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { - /* Protect against races with xprt_write_space */ - spin_lock_bh(&xprt->sock_lock); - /* Don't race with disconnect */ - if (!xprt_connected(xprt)) - task->tk_status = -ENOTCONN; - else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { - task->tk_timeout = req->rq_timeout; - rpc_sleep_on(&xprt->pending, task, NULL, NULL); - } - spin_unlock_bh(&xprt->sock_lock); - return; - } - /* Keep holding the socket if it is blocked */ - rpc_delay(task, HZ>>4); - return; case -ECONNREFUSED: task->tk_timeout = RPC_REESTABLISH_TIMEOUT; rpc_sleep_on(&xprt->sending, task, NULL, NULL); + case -EAGAIN: case -ENOTCONN: return; default: @@ -1367,7 +688,8 @@ xprt_release(struct rpc_task *task) list_del(&req->rq_list); xprt->last_used = jiffies; if (list_empty(&xprt->recv) && !xprt->shutdown) - mod_timer(&xprt->timer, xprt->last_used + XPRT_IDLE_TIMEOUT); + mod_timer(&xprt->timer, + xprt->last_used + RPC_IDLE_DISCONNECT_TIMEOUT); spin_unlock_bh(&xprt->sock_lock); task->tk_rqstp = NULL; memset(req, 0, sizeof(*req)); /* mark unused */ @@ -1380,18 +702,6 @@ xprt_release(struct rpc_task *task) spin_unlock(&xprt->xprt_lock); } -/* - * Set default timeout parameters - */ -static void -xprt_default_timeout(struct rpc_timeout *to, int proto) -{ - if (proto == IPPROTO_UDP) - xprt_set_timeout(to, 5, 5 * HZ); - else - xprt_set_timeout(to, 2, 60 * HZ); -} - /* * Set constant timeout */ @@ -1405,68 +715,51 @@ xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) to->to_exponential = 0; } -unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; -unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; - /* * Initialize an RPC client */ static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) { + int result; struct rpc_xprt *xprt; - unsigned int entries; - size_t slot_table_size; struct rpc_rqst *req; - dprintk("RPC: setting up %s transport...\n", - proto == IPPROTO_UDP? "UDP" : "TCP"); - - entries = (proto == IPPROTO_TCP)? - xprt_tcp_slot_table_entries : xprt_udp_slot_table_entries; - if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) return ERR_PTR(-ENOMEM); memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */ - xprt->max_reqs = entries; - slot_table_size = entries * sizeof(xprt->slot[0]); - xprt->slot = kmalloc(slot_table_size, GFP_KERNEL); - if (xprt->slot == NULL) { - kfree(xprt); - return ERR_PTR(-ENOMEM); - } - memset(xprt->slot, 0, slot_table_size); xprt->addr = *ap; - xprt->prot = proto; - xprt->stream = (proto == IPPROTO_TCP)? 1 : 0; - if (xprt->stream) { - xprt->cwnd = RPC_MAXCWND(xprt); - xprt->nocong = 1; - xprt->max_payload = (1U << 31) - 1; - } else { - xprt->cwnd = RPC_INITCWND; - xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); + + switch (proto) { + case IPPROTO_UDP: + result = xs_setup_udp(xprt, to); + break; + case IPPROTO_TCP: + result = xs_setup_tcp(xprt, to); + break; + default: + printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", + proto); + result = -EIO; + break; } + if (result) { + kfree(xprt); + return ERR_PTR(result); + } + spin_lock_init(&xprt->sock_lock); spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait); INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); - INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; xprt->last_used = jiffies; - xprt->port = XPRT_MAX_RESVPORT; - - /* Set timeout parameters */ - if (to) { - xprt->timeout = *to; - } else - xprt_default_timeout(&xprt->timeout, xprt->prot); rpc_init_wait_queue(&xprt->pending, "xprt_pending"); rpc_init_wait_queue(&xprt->sending, "xprt_sending"); @@ -1474,134 +767,17 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); /* initialize free list */ - for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--) + for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--) list_add(&req->rq_list, &xprt->free); xprt_init_xid(xprt); - /* Check whether we want to use a reserved port */ - xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; - dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); return xprt; } -/* - * Bind to a reserved port - */ -static inline int xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock) -{ - struct sockaddr_in myaddr = { - .sin_family = AF_INET, - }; - int err, port; - - /* Were we already bound to a given port? Try to reuse it */ - port = xprt->port; - do { - myaddr.sin_port = htons(port); - err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, - sizeof(myaddr)); - if (err == 0) { - xprt->port = port; - return 0; - } - if (--port == 0) - port = XPRT_MAX_RESVPORT; - } while (err == -EADDRINUSE && port != xprt->port); - - printk("RPC: Can't bind to reserved port (%d).\n", -err); - return err; -} - -static void -xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (xprt->inet) - return; - - write_lock_bh(&sk->sk_callback_lock); - sk->sk_user_data = xprt; - xprt->old_data_ready = sk->sk_data_ready; - xprt->old_state_change = sk->sk_state_change; - xprt->old_write_space = sk->sk_write_space; - if (xprt->prot == IPPROTO_UDP) { - sk->sk_data_ready = udp_data_ready; - sk->sk_no_check = UDP_CSUM_NORCV; - xprt_set_connected(xprt); - } else { - tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ - sk->sk_data_ready = tcp_data_ready; - sk->sk_state_change = tcp_state_change; - xprt_clear_connected(xprt); - } - sk->sk_write_space = xprt_write_space; - - /* Reset to new socket */ - xprt->sock = sock; - xprt->inet = sk; - write_unlock_bh(&sk->sk_callback_lock); - - return; -} - -/* - * Set socket buffer length - */ -void -xprt_sock_setbufsize(struct rpc_xprt *xprt) -{ - struct sock *sk = xprt->inet; - - if (xprt->stream) - return; - if (xprt->rcvsize) { - sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs * 2; - } - if (xprt->sndsize) { - sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - sk->sk_sndbuf = xprt->sndsize * xprt->max_reqs * 2; - sk->sk_write_space(sk); - } -} - -/* - * Datastream sockets are created here, but xprt_connect will create - * and connect stream sockets. - */ -static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport) -{ - struct socket *sock; - int type, err; - - dprintk("RPC: xprt_create_socket(%s %d)\n", - (proto == IPPROTO_UDP)? "udp" : "tcp", proto); - - type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; - - if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { - printk("RPC: can't create socket (%d).\n", -err); - return NULL; - } - - /* If the caller has the capability, bind to a reserved port */ - if (resvport && xprt_bindresvport(xprt, sock) < 0) { - printk("RPC: can't bind to reserved port.\n"); - goto failed; - } - - return sock; - -failed: - sock_release(sock); - return NULL; -} - /* * Create an RPC client transport given the protocol and peer address. */ @@ -1631,10 +807,6 @@ xprt_shutdown(struct rpc_xprt *xprt) rpc_wake_up(&xprt->backlog); wake_up(&xprt->cong_wait); del_timer_sync(&xprt->timer); - - /* synchronously wait for connect worker to finish */ - cancel_delayed_work(&xprt->sock_connect); - flush_scheduled_work(); } /* @@ -1655,9 +827,7 @@ xprt_destroy(struct rpc_xprt *xprt) { dprintk("RPC: destroying transport %p\n", xprt); xprt_shutdown(xprt); - xprt_disconnect(xprt); - xprt_close(xprt); - kfree(xprt->slot); + xprt->ops->destroy(xprt); kfree(xprt); return 0; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c new file mode 100644 index 000000000000..fa1180ac4823 --- /dev/null +++ b/net/sunrpc/xprtsock.c @@ -0,0 +1,1021 @@ +/* + * linux/net/sunrpc/xprtsock.c + * + * Client-side transport implementation for sockets. + * + * TCP callback races fixes (C) 1998 Red Hat Software + * TCP send fixes (C) 1998 Red Hat Software + * TCP NFS related read + write fixes + * (C) 1999 Dave Airlie, University of Limerick, Ireland + * + * Rewrite of larges part of the code in order to stabilize TCP stuff. + * Fix behaviour when socket buffer is full. + * (C) 1999 Trond Myklebust + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# undef RPC_DEBUG_DATA +# define RPCDBG_FACILITY RPCDBG_XPRT +#endif + +#define XPRT_MAX_RESVPORT (800) + +#ifdef RPC_DEBUG_DATA +/* + * Print the buffer contents (first 128 bytes only--just enough for + * diropres return). + */ +static void +xprt_pktdump(char *msg, u32 *packet, unsigned int count) +{ + u8 *buf = (u8 *) packet; + int j; + + dprintk("RPC: %s\n", msg); + for (j = 0; j < count && j < 128; j += 4) { + if (!(j & 31)) { + if (j) + dprintk("\n"); + dprintk("0x%04x ", j); + } + dprintk("%02x%02x%02x%02x ", + buf[j], buf[j+1], buf[j+2], buf[j+3]); + } + dprintk("\n"); +} +#else +static inline void +xprt_pktdump(char *msg, u32 *packet, unsigned int count) +{ + /* NOP */ +} +#endif + +/* + * Look up RPC transport given an INET socket + */ +static inline struct rpc_xprt * +xprt_from_sock(struct sock *sk) +{ + return (struct rpc_xprt *) sk->sk_user_data; +} + +static int +xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, + struct xdr_buf *xdr, unsigned int base, int msgflags) +{ + struct page **ppage = xdr->pages; + unsigned int len, pglen = xdr->page_len; + int err, ret = 0; + ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); + + len = xdr->head[0].iov_len; + if (base < len || (addr != NULL && base == 0)) { + struct kvec iov = { + .iov_base = xdr->head[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_name = addr, + .msg_namelen = addrlen, + .msg_flags = msgflags, + }; + if (xdr->len > len) + msg.msg_flags |= MSG_MORE; + + if (iov.iov_len != 0) + err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); + else + err = kernel_sendmsg(sock, &msg, NULL, 0, 0); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + if (err != iov.iov_len) + goto out; + base = 0; + } else + base -= len; + + if (pglen == 0) + goto copy_tail; + if (base >= pglen) { + base -= pglen; + goto copy_tail; + } + if (base || xdr->page_base) { + pglen -= base; + base += xdr->page_base; + ppage += base >> PAGE_CACHE_SHIFT; + base &= ~PAGE_CACHE_MASK; + } + + sendpage = sock->ops->sendpage ? : sock_no_sendpage; + do { + int flags = msgflags; + + len = PAGE_CACHE_SIZE; + if (base) + len -= base; + if (pglen < len) + len = pglen; + + if (pglen != len || xdr->tail[0].iov_len != 0) + flags |= MSG_MORE; + + /* Hmm... We might be dealing with highmem pages */ + if (PageHighMem(*ppage)) + sendpage = sock_no_sendpage; + err = sendpage(sock, *ppage, base, len, flags); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + if (err != len) + goto out; + base = 0; + ppage++; + } while ((pglen -= len) != 0); +copy_tail: + len = xdr->tail[0].iov_len; + if (base < len) { + struct kvec iov = { + .iov_base = xdr->tail[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_flags = msgflags, + }; + err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + } +out: + return ret; +} + +/* + * Write data to socket. + */ +static inline int +xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) +{ + struct socket *sock = xprt->sock; + struct xdr_buf *xdr = &req->rq_snd_buf; + struct sockaddr *addr = NULL; + int addrlen = 0; + unsigned int skip; + int result; + + if (!sock) + return -ENOTCONN; + + xprt_pktdump("packet data:", + req->rq_svec->iov_base, + req->rq_svec->iov_len); + + /* For UDP, we need to provide an address */ + if (!xprt->stream) { + addr = (struct sockaddr *) &xprt->addr; + addrlen = sizeof(xprt->addr); + } + /* Dont repeat bytes */ + skip = req->rq_bytes_sent; + + clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); + result = xdr_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); + + dprintk("RPC: xprt_sendmsg(%d) = %d\n", xdr->len - skip, result); + + if (result >= 0) + return result; + + switch (result) { + case -ECONNREFUSED: + /* When the server has died, an ICMP port unreachable message + * prompts ECONNREFUSED. + */ + case -EAGAIN: + break; + case -ECONNRESET: + case -ENOTCONN: + case -EPIPE: + /* connection broken */ + if (xprt->stream) + result = -ENOTCONN; + break; + default: + printk(KERN_NOTICE "RPC: sendmsg returned error %d\n", -result); + } + return result; +} + +static int +xprt_send_request(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + int status, retry = 0; + + /* set up everything as needed. */ + /* Write the record marker */ + if (xprt->stream) { + u32 *marker = req->rq_svec[0].iov_base; + + *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); + } + + /* Continue transmitting the packet/record. We must be careful + * to cope with writespace callbacks arriving _after_ we have + * called xprt_sendmsg(). + */ + while (1) { + req->rq_xtime = jiffies; + status = xprt_sendmsg(xprt, req); + + if (status < 0) + break; + + if (xprt->stream) { + req->rq_bytes_sent += status; + + /* If we've sent the entire packet, immediately + * reset the count of bytes sent. */ + if (req->rq_bytes_sent >= req->rq_slen) { + req->rq_bytes_sent = 0; + return 0; + } + } else { + if (status >= req->rq_slen) + return 0; + status = -EAGAIN; + break; + } + + dprintk("RPC: %4d xmit incomplete (%d left of %d)\n", + task->tk_pid, req->rq_slen - req->rq_bytes_sent, + req->rq_slen); + + status = -EAGAIN; + if (retry++ > 50) + break; + } + + if (status == -EAGAIN) { + if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { + /* Protect against races with xprt_write_space */ + spin_lock_bh(&xprt->sock_lock); + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { + task->tk_timeout = req->rq_timeout; + rpc_sleep_on(&xprt->pending, task, NULL, NULL); + } + spin_unlock_bh(&xprt->sock_lock); + return status; + } + /* Keep holding the socket if it is blocked */ + rpc_delay(task, HZ>>4); + } + return status; +} + +/* + * Close down a transport socket + */ +static void +xprt_close(struct rpc_xprt *xprt) +{ + struct socket *sock = xprt->sock; + struct sock *sk = xprt->inet; + + if (!sk) + return; + + write_lock_bh(&sk->sk_callback_lock); + xprt->inet = NULL; + xprt->sock = NULL; + + sk->sk_user_data = NULL; + sk->sk_data_ready = xprt->old_data_ready; + sk->sk_state_change = xprt->old_state_change; + sk->sk_write_space = xprt->old_write_space; + write_unlock_bh(&sk->sk_callback_lock); + + sk->sk_no_check = 0; + + sock_release(sock); +} + +static void xprt_socket_destroy(struct rpc_xprt *xprt) +{ + cancel_delayed_work(&xprt->sock_connect); + flush_scheduled_work(); + + xprt_disconnect(xprt); + xprt_close(xprt); + kfree(xprt->slot); +} + +/* + * Input handler for RPC replies. Called from a bottom half and hence + * atomic. + */ +static void +udp_data_ready(struct sock *sk, int len) +{ + struct rpc_task *task; + struct rpc_xprt *xprt; + struct rpc_rqst *rovr; + struct sk_buff *skb; + int err, repsize, copied; + u32 _xid, *xp; + + read_lock(&sk->sk_callback_lock); + dprintk("RPC: udp_data_ready...\n"); + if (!(xprt = xprt_from_sock(sk))) { + printk("RPC: udp_data_ready request not found!\n"); + goto out; + } + + dprintk("RPC: udp_data_ready client %p\n", xprt); + + if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) + goto out; + + if (xprt->shutdown) + goto dropit; + + repsize = skb->len - sizeof(struct udphdr); + if (repsize < 4) { + printk("RPC: impossible RPC reply size %d!\n", repsize); + goto dropit; + } + + /* Copy the XID from the skb... */ + xp = skb_header_pointer(skb, sizeof(struct udphdr), + sizeof(_xid), &_xid); + if (xp == NULL) + goto dropit; + + /* Look up and lock the request corresponding to the given XID */ + spin_lock(&xprt->sock_lock); + rovr = xprt_lookup_rqst(xprt, *xp); + if (!rovr) + goto out_unlock; + task = rovr->rq_task; + + dprintk("RPC: %4d received reply\n", task->tk_pid); + + if ((copied = rovr->rq_private_buf.buflen) > repsize) + copied = repsize; + + /* Suck it into the iovec, verify checksum if not done by hw. */ + if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) + goto out_unlock; + + /* Something worked... */ + dst_confirm(skb->dst); + + xprt_complete_rqst(xprt, rovr, copied); + + out_unlock: + spin_unlock(&xprt->sock_lock); + dropit: + skb_free_datagram(sk, skb); + out: + read_unlock(&sk->sk_callback_lock); +} + +/* + * Copy from an skb into memory and shrink the skb. + */ +static inline size_t +tcp_copy_data(skb_reader_t *desc, void *p, size_t len) +{ + if (len > desc->count) + len = desc->count; + if (skb_copy_bits(desc->skb, desc->offset, p, len)) { + dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", + len, desc->count); + return 0; + } + desc->offset += len; + desc->count -= len; + dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", + len, desc->count); + return len; +} + +/* + * TCP read fragment marker + */ +static inline void +tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) +{ + size_t len, used; + char *p; + + p = ((char *) &xprt->tcp_recm) + xprt->tcp_offset; + len = sizeof(xprt->tcp_recm) - xprt->tcp_offset; + used = tcp_copy_data(desc, p, len); + xprt->tcp_offset += used; + if (used != len) + return; + xprt->tcp_reclen = ntohl(xprt->tcp_recm); + if (xprt->tcp_reclen & 0x80000000) + xprt->tcp_flags |= XPRT_LAST_FRAG; + else + xprt->tcp_flags &= ~XPRT_LAST_FRAG; + xprt->tcp_reclen &= 0x7fffffff; + xprt->tcp_flags &= ~XPRT_COPY_RECM; + xprt->tcp_offset = 0; + /* Sanity check of the record length */ + if (xprt->tcp_reclen < 4) { + printk(KERN_ERR "RPC: Invalid TCP record fragment length\n"); + xprt_disconnect(xprt); + } + dprintk("RPC: reading TCP record fragment of length %d\n", + xprt->tcp_reclen); +} + +static void +tcp_check_recm(struct rpc_xprt *xprt) +{ + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); + if (xprt->tcp_offset == xprt->tcp_reclen) { + xprt->tcp_flags |= XPRT_COPY_RECM; + xprt->tcp_offset = 0; + if (xprt->tcp_flags & XPRT_LAST_FRAG) { + xprt->tcp_flags &= ~XPRT_COPY_DATA; + xprt->tcp_flags |= XPRT_COPY_XID; + xprt->tcp_copied = 0; + } + } +} + +/* + * TCP read xid + */ +static inline void +tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) +{ + size_t len, used; + char *p; + + len = sizeof(xprt->tcp_xid) - xprt->tcp_offset; + dprintk("RPC: reading XID (%Zu bytes)\n", len); + p = ((char *) &xprt->tcp_xid) + xprt->tcp_offset; + used = tcp_copy_data(desc, p, len); + xprt->tcp_offset += used; + if (used != len) + return; + xprt->tcp_flags &= ~XPRT_COPY_XID; + xprt->tcp_flags |= XPRT_COPY_DATA; + xprt->tcp_copied = 4; + dprintk("RPC: reading reply for XID %08x\n", + ntohl(xprt->tcp_xid)); + tcp_check_recm(xprt); +} + +/* + * TCP read and complete request + */ +static inline void +tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) +{ + struct rpc_rqst *req; + struct xdr_buf *rcvbuf; + size_t len; + ssize_t r; + + /* Find and lock the request corresponding to this xid */ + spin_lock(&xprt->sock_lock); + req = xprt_lookup_rqst(xprt, xprt->tcp_xid); + if (!req) { + xprt->tcp_flags &= ~XPRT_COPY_DATA; + dprintk("RPC: XID %08x request not found!\n", + ntohl(xprt->tcp_xid)); + spin_unlock(&xprt->sock_lock); + return; + } + + rcvbuf = &req->rq_private_buf; + len = desc->count; + if (len > xprt->tcp_reclen - xprt->tcp_offset) { + skb_reader_t my_desc; + + len = xprt->tcp_reclen - xprt->tcp_offset; + memcpy(&my_desc, desc, sizeof(my_desc)); + my_desc.count = len; + r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + &my_desc, tcp_copy_data); + desc->count -= r; + desc->offset += r; + } else + r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + desc, tcp_copy_data); + + if (r > 0) { + xprt->tcp_copied += r; + xprt->tcp_offset += r; + } + if (r != len) { + /* Error when copying to the receive buffer, + * usually because we weren't able to allocate + * additional buffer pages. All we can do now + * is turn off XPRT_COPY_DATA, so the request + * will not receive any additional updates, + * and time out. + * Any remaining data from this record will + * be discarded. + */ + xprt->tcp_flags &= ~XPRT_COPY_DATA; + dprintk("RPC: XID %08x truncated request\n", + ntohl(xprt->tcp_xid)); + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); + goto out; + } + + dprintk("RPC: XID %08x read %Zd bytes\n", + ntohl(xprt->tcp_xid), r); + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); + + if (xprt->tcp_copied == req->rq_private_buf.buflen) + xprt->tcp_flags &= ~XPRT_COPY_DATA; + else if (xprt->tcp_offset == xprt->tcp_reclen) { + if (xprt->tcp_flags & XPRT_LAST_FRAG) + xprt->tcp_flags &= ~XPRT_COPY_DATA; + } + +out: + if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { + dprintk("RPC: %4d received reply complete\n", + req->rq_task->tk_pid); + xprt_complete_rqst(xprt, req, xprt->tcp_copied); + } + spin_unlock(&xprt->sock_lock); + tcp_check_recm(xprt); +} + +/* + * TCP discard extra bytes from a short read + */ +static inline void +tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) +{ + size_t len; + + len = xprt->tcp_reclen - xprt->tcp_offset; + if (len > desc->count) + len = desc->count; + desc->count -= len; + desc->offset += len; + xprt->tcp_offset += len; + dprintk("RPC: discarded %Zu bytes\n", len); + tcp_check_recm(xprt); +} + +/* + * TCP record receive routine + * We first have to grab the record marker, then the XID, then the data. + */ +static int +tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, + unsigned int offset, size_t len) +{ + struct rpc_xprt *xprt = rd_desc->arg.data; + skb_reader_t desc = { + .skb = skb, + .offset = offset, + .count = len, + .csum = 0 + }; + + dprintk("RPC: tcp_data_recv\n"); + do { + /* Read in a new fragment marker if necessary */ + /* Can we ever really expect to get completely empty fragments? */ + if (xprt->tcp_flags & XPRT_COPY_RECM) { + tcp_read_fraghdr(xprt, &desc); + continue; + } + /* Read in the xid if necessary */ + if (xprt->tcp_flags & XPRT_COPY_XID) { + tcp_read_xid(xprt, &desc); + continue; + } + /* Read in the request data */ + if (xprt->tcp_flags & XPRT_COPY_DATA) { + tcp_read_request(xprt, &desc); + continue; + } + /* Skip over any trailing bytes on short reads */ + tcp_read_discard(xprt, &desc); + } while (desc.count); + dprintk("RPC: tcp_data_recv done\n"); + return len - desc.count; +} + +static void tcp_data_ready(struct sock *sk, int bytes) +{ + struct rpc_xprt *xprt; + read_descriptor_t rd_desc; + + read_lock(&sk->sk_callback_lock); + dprintk("RPC: tcp_data_ready...\n"); + if (!(xprt = xprt_from_sock(sk))) { + printk("RPC: tcp_data_ready socket info not found!\n"); + goto out; + } + if (xprt->shutdown) + goto out; + + /* We use rd_desc to pass struct xprt to tcp_data_recv */ + rd_desc.arg.data = xprt; + rd_desc.count = 65536; + tcp_read_sock(sk, &rd_desc, tcp_data_recv); +out: + read_unlock(&sk->sk_callback_lock); +} + +static void +tcp_state_change(struct sock *sk) +{ + struct rpc_xprt *xprt; + + read_lock(&sk->sk_callback_lock); + if (!(xprt = xprt_from_sock(sk))) + goto out; + dprintk("RPC: tcp_state_change client %p...\n", xprt); + dprintk("RPC: state %x conn %d dead %d zapped %d\n", + sk->sk_state, xprt_connected(xprt), + sock_flag(sk, SOCK_DEAD), + sock_flag(sk, SOCK_ZAPPED)); + + switch (sk->sk_state) { + case TCP_ESTABLISHED: + spin_lock_bh(&xprt->sock_lock); + if (!xprt_test_and_set_connected(xprt)) { + /* Reset TCP record info */ + xprt->tcp_offset = 0; + xprt->tcp_reclen = 0; + xprt->tcp_copied = 0; + xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; + rpc_wake_up(&xprt->pending); + } + spin_unlock_bh(&xprt->sock_lock); + break; + case TCP_SYN_SENT: + case TCP_SYN_RECV: + break; + default: + xprt_disconnect(xprt); + break; + } + out: + read_unlock(&sk->sk_callback_lock); +} + +/* + * Called when more output buffer space is available for this socket. + * We try not to wake our writers until they can make "significant" + * progress, otherwise we'll waste resources thrashing sock_sendmsg + * with a bunch of small requests. + */ +static void +xprt_write_space(struct sock *sk) +{ + struct rpc_xprt *xprt; + struct socket *sock; + + read_lock(&sk->sk_callback_lock); + if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) + goto out; + if (xprt->shutdown) + goto out; + + /* Wait until we have enough socket memory */ + if (xprt->stream) { + /* from net/core/stream.c:sk_stream_write_space */ + if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk)) + goto out; + } else { + /* from net/core/sock.c:sock_def_write_space */ + if (!sock_writeable(sk)) + goto out; + } + + if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) + goto out; + + spin_lock_bh(&xprt->sock_lock); + if (xprt->snd_task) + rpc_wake_up_task(xprt->snd_task); + spin_unlock_bh(&xprt->sock_lock); +out: + read_unlock(&sk->sk_callback_lock); +} + +/* + * Set socket buffer length + */ +static void +xprt_sock_setbufsize(struct rpc_xprt *xprt) +{ + struct sock *sk = xprt->inet; + + if (xprt->stream) + return; + if (xprt->rcvsize) { + sk->sk_userlocks |= SOCK_RCVBUF_LOCK; + sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs * 2; + } + if (xprt->sndsize) { + sk->sk_userlocks |= SOCK_SNDBUF_LOCK; + sk->sk_sndbuf = xprt->sndsize * xprt->max_reqs * 2; + sk->sk_write_space(sk); + } +} + +/* + * Bind to a reserved port + */ +static inline int xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock) +{ + struct sockaddr_in myaddr = { + .sin_family = AF_INET, + }; + int err, port; + + /* Were we already bound to a given port? Try to reuse it */ + port = xprt->port; + do { + myaddr.sin_port = htons(port); + err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, + sizeof(myaddr)); + if (err == 0) { + xprt->port = port; + return 0; + } + if (--port == 0) + port = XPRT_MAX_RESVPORT; + } while (err == -EADDRINUSE && port != xprt->port); + + printk("RPC: Can't bind to reserved port (%d).\n", -err); + return err; +} + +static void +xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (xprt->inet) + return; + + write_lock_bh(&sk->sk_callback_lock); + sk->sk_user_data = xprt; + xprt->old_data_ready = sk->sk_data_ready; + xprt->old_state_change = sk->sk_state_change; + xprt->old_write_space = sk->sk_write_space; + if (xprt->prot == IPPROTO_UDP) { + sk->sk_data_ready = udp_data_ready; + sk->sk_no_check = UDP_CSUM_NORCV; + xprt_set_connected(xprt); + } else { + tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ + sk->sk_data_ready = tcp_data_ready; + sk->sk_state_change = tcp_state_change; + xprt_clear_connected(xprt); + } + sk->sk_write_space = xprt_write_space; + + /* Reset to new socket */ + xprt->sock = sock; + xprt->inet = sk; + write_unlock_bh(&sk->sk_callback_lock); + + return; +} + +/* + * Datastream sockets are created here, but xprt_connect will create + * and connect stream sockets. + */ +static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport) +{ + struct socket *sock; + int type, err; + + dprintk("RPC: xprt_create_socket(%s %d)\n", + (proto == IPPROTO_UDP)? "udp" : "tcp", proto); + + type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; + + if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { + printk("RPC: can't create socket (%d).\n", -err); + return NULL; + } + + /* If the caller has the capability, bind to a reserved port */ + if (resvport && xprt_bindresvport(xprt, sock) < 0) { + printk("RPC: can't bind to reserved port.\n"); + goto failed; + } + + return sock; + +failed: + sock_release(sock); + return NULL; +} + +static void xprt_socket_connect(void *args) +{ + struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct socket *sock = xprt->sock; + int status = -EIO; + + if (xprt->shutdown || xprt->addr.sin_port == 0) + goto out; + + /* + * Start by resetting any existing state + */ + xprt_close(xprt); + sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport); + if (sock == NULL) { + /* couldn't create socket or bind to reserved port; + * this is likely a permanent error, so cause an abort */ + goto out; + } + xprt_bind_socket(xprt, sock); + xprt_sock_setbufsize(xprt); + + status = 0; + if (!xprt->stream) + goto out; + + /* + * Tell the socket layer to start connecting... + */ + status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, + sizeof(xprt->addr), O_NONBLOCK); + dprintk("RPC: %p connect status %d connected %d sock state %d\n", + xprt, -status, xprt_connected(xprt), sock->sk->sk_state); + if (status < 0) { + switch (status) { + case -EINPROGRESS: + case -EALREADY: + goto out_clear; + } + } +out: + if (status < 0) + rpc_wake_up_status(&xprt->pending, status); + else + rpc_wake_up(&xprt->pending); +out_clear: + smp_mb__before_clear_bit(); + clear_bit(XPRT_CONNECTING, &xprt->sockstate); + smp_mb__after_clear_bit(); +} + +static void +xprt_connect_sock(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + + if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { + /* Note: if we are here due to a dropped connection + * we delay reconnecting by RPC_REESTABLISH_TIMEOUT/HZ + * seconds + */ + if (xprt->sock != NULL) + schedule_delayed_work(&xprt->sock_connect, + RPC_REESTABLISH_TIMEOUT); + else { + schedule_work(&xprt->sock_connect); + /* flush_scheduled_work can sleep... */ + if (!RPC_IS_ASYNC(task)) + flush_scheduled_work(); + } + } +} + +/* + * Set default timeout parameters + */ +static void +xprt_default_timeout(struct rpc_timeout *to, int proto) +{ + if (proto == IPPROTO_UDP) + xprt_set_timeout(to, 5, 5 * HZ); + else + xprt_set_timeout(to, 2, 60 * HZ); +} + +static struct rpc_xprt_ops xprt_socket_ops = { + .set_buffer_size = xprt_sock_setbufsize, + .connect = xprt_connect_sock, + .send_request = xprt_send_request, + .close = xprt_close, + .destroy = xprt_socket_destroy, +}; + +extern unsigned int xprt_udp_slot_table_entries; +extern unsigned int xprt_tcp_slot_table_entries; + +int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) +{ + size_t slot_table_size; + + dprintk("RPC: setting up udp-ipv4 transport...\n"); + + xprt->max_reqs = xprt_udp_slot_table_entries; + slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); + xprt->slot = kmalloc(slot_table_size, GFP_KERNEL); + if (xprt->slot == NULL) + return -ENOMEM; + memset(xprt->slot, 0, slot_table_size); + + xprt->prot = IPPROTO_UDP; + xprt->port = XPRT_MAX_RESVPORT; + xprt->stream = 0; + xprt->nocong = 0; + xprt->cwnd = RPC_INITCWND; + xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; + /* XXX: header size can vary due to auth type, IPv6, etc. */ + xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); + + INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); + + xprt->ops = &xprt_socket_ops; + + if (to) + xprt->timeout = *to; + else + xprt_default_timeout(to, xprt->prot); + + return 0; +} + +int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) +{ + size_t slot_table_size; + + dprintk("RPC: setting up tcp-ipv4 transport...\n"); + + xprt->max_reqs = xprt_tcp_slot_table_entries; + slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); + xprt->slot = kmalloc(slot_table_size, GFP_KERNEL); + if (xprt->slot == NULL) + return -ENOMEM; + memset(xprt->slot, 0, slot_table_size); + + xprt->prot = IPPROTO_TCP; + xprt->port = XPRT_MAX_RESVPORT; + xprt->stream = 1; + xprt->nocong = 1; + xprt->cwnd = RPC_MAXCWND(xprt); + xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; + xprt->max_payload = (1U << 31) - 1; + + INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); + + xprt->ops = &xprt_socket_ops; + + if (to) + xprt->timeout = *to; + else + xprt_default_timeout(to, xprt->prot); + + return 0; +} From 9903cd1c27a1f30e8efea75e125be3b2002f7cb9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:26 -0400 Subject: [PATCH 0157/1939] [PATCH] RPC: transport switch function naming Introduce block header comments and a function naming convention to the socket transport implementation. Provide a debug setting for transports that is separate from RPCDBG_XPRT. Eliminate xprt_default_timeout(). Provide block comments for exposed interfaces in xprt.c, and eliminate the useless obvious comments. Convert printk's to dprintk's. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:04:04 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/debug.h | 1 + net/sunrpc/xprt.c | 147 ++++++----- net/sunrpc/xprtsock.c | 466 ++++++++++++++++++----------------- 3 files changed, 312 insertions(+), 302 deletions(-) diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index eadb31e3c198..42d299747956 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -32,6 +32,7 @@ #define RPCDBG_AUTH 0x0010 #define RPCDBG_PMAP 0x0020 #define RPCDBG_SCHED 0x0040 +#define RPCDBG_TRANS 0x0080 #define RPCDBG_SVCSOCK 0x0100 #define RPCDBG_SVCDSP 0x0200 #define RPCDBG_MISC 0x0400 diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 4342acf4d1cd..589195e630ef 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -227,9 +227,6 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) xprt->cwnd = cwnd; } -/* - * Reset the major timeout value - */ static void xprt_reset_majortimeo(struct rpc_rqst *req) { struct rpc_timeout *to = &req->rq_xprt->timeout; @@ -244,8 +241,10 @@ static void xprt_reset_majortimeo(struct rpc_rqst *req) req->rq_majortimeo += jiffies; } -/* - * Adjust timeout values etc for next retransmit +/** + * xprt_adjust_timeout - adjust timeout values for next retransmit + * @req: RPC request containing parameters to use for the adjustment + * */ int xprt_adjust_timeout(struct rpc_rqst *req) { @@ -291,8 +290,10 @@ xprt_socket_autoclose(void *args) xprt_release_write(xprt, NULL); } -/* - * Mark a transport as disconnected +/** + * xprt_disconnect - mark a transport as disconnected + * @xprt: transport to flag for disconnect + * */ void xprt_disconnect(struct rpc_xprt *xprt) { @@ -303,9 +304,6 @@ void xprt_disconnect(struct rpc_xprt *xprt) spin_unlock_bh(&xprt->sock_lock); } -/* - * Used to allow disconnection when we've been idle - */ static void xprt_init_autodisconnect(unsigned long data) { @@ -327,8 +325,9 @@ xprt_init_autodisconnect(unsigned long data) spin_unlock(&xprt->sock_lock); } -/* - * Attempt to connect a TCP socket. +/** + * xprt_connect - schedule a transport connect operation + * @task: RPC task that is requesting the connect * */ void xprt_connect(struct rpc_task *task) @@ -361,11 +360,7 @@ void xprt_connect(struct rpc_task *task) return; } -/* - * We arrive here when awoken from waiting on connection establishment. - */ -static void -xprt_connect_status(struct rpc_task *task) +static void xprt_connect_status(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; @@ -404,8 +399,11 @@ xprt_connect_status(struct rpc_task *task) } } -/* - * Look up the RPC request corresponding to a reply, and then lock it. +/** + * xprt_lookup_rqst - find an RPC request corresponding to an XID + * @xprt: transport on which the original request was transmitted + * @xid: RPC XID of incoming reply + * */ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) { @@ -422,9 +420,12 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) return req; } -/* - * Complete reply received. - * The TCP code relies on us to remove the request from xprt->pending. +/** + * xprt_complete_rqst - called when reply processing is complete + * @xprt: controlling transport + * @req: RPC request that just completed + * @copied: actual number of bytes received from the transport + * */ void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) { @@ -498,12 +499,12 @@ xprt_timer(struct rpc_task *task) spin_unlock(&xprt->sock_lock); } -/* - * Place the actual RPC call. - * We have to copy the iovec because sendmsg fiddles with its contents. +/** + * xprt_prepare_transmit - reserve the transport before sending a request + * @task: RPC task about to send a request + * */ -int -xprt_prepare_transmit(struct rpc_task *task) +int xprt_prepare_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; @@ -533,8 +534,13 @@ xprt_prepare_transmit(struct rpc_task *task) return err; } -void -xprt_transmit(struct rpc_task *task) +/** + * xprt_transmit - send an RPC request on a transport + * @task: controlling RPC task + * + * We have to copy the iovec because sendmsg fiddles with its contents. + */ +void xprt_transmit(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; @@ -604,11 +610,7 @@ xprt_transmit(struct rpc_task *task) spin_unlock_bh(&xprt->sock_lock); } -/* - * Reserve an RPC call slot. - */ -static inline void -do_xprt_reserve(struct rpc_task *task) +static inline void do_xprt_reserve(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; @@ -628,8 +630,14 @@ do_xprt_reserve(struct rpc_task *task) rpc_sleep_on(&xprt->backlog, task, NULL, NULL); } -void -xprt_reserve(struct rpc_task *task) +/** + * xprt_reserve - allocate an RPC request slot + * @task: RPC task requesting a slot allocation + * + * If no more slots are available, place the task on the transport's + * backlog queue. + */ +void xprt_reserve(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; @@ -641,9 +649,6 @@ xprt_reserve(struct rpc_task *task) } } -/* - * Allocate a 'unique' XID - */ static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt) { return xprt->xid++; @@ -654,11 +659,7 @@ static inline void xprt_init_xid(struct rpc_xprt *xprt) get_random_bytes(&xprt->xid, sizeof(xprt->xid)); } -/* - * Initialize RPC request - */ -static void -xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) +static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) { struct rpc_rqst *req = task->tk_rqstp; @@ -670,11 +671,12 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) req, ntohl(req->rq_xid)); } -/* - * Release an RPC call slot +/** + * xprt_release - release an RPC request slot + * @task: task which is finished with the slot + * */ -void -xprt_release(struct rpc_task *task) +void xprt_release(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req; @@ -702,11 +704,14 @@ xprt_release(struct rpc_task *task) spin_unlock(&xprt->xprt_lock); } -/* - * Set constant timeout +/** + * xprt_set_timeout - set constant RPC timeout + * @to: RPC timeout parameters to set up + * @retr: number of retries + * @incr: amount of increase after each retry + * */ -void -xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) +void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) { to->to_initval = to->to_increment = incr; @@ -715,11 +720,7 @@ xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) to->to_exponential = 0; } -/* - * Initialize an RPC client - */ -static struct rpc_xprt * -xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) +static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) { int result; struct rpc_xprt *xprt; @@ -778,11 +779,14 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) return xprt; } -/* - * Create an RPC client transport given the protocol and peer address. +/** + * xprt_create_proto - create an RPC client transport + * @proto: requested transport protocol + * @sap: remote peer's address + * @to: timeout parameters for new transport + * */ -struct rpc_xprt * -xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) +struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) { struct rpc_xprt *xprt; @@ -794,11 +798,7 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) return xprt; } -/* - * Prepare for transport shutdown. - */ -static void -xprt_shutdown(struct rpc_xprt *xprt) +static void xprt_shutdown(struct rpc_xprt *xprt) { xprt->shutdown = 1; rpc_wake_up(&xprt->sending); @@ -809,21 +809,18 @@ xprt_shutdown(struct rpc_xprt *xprt) del_timer_sync(&xprt->timer); } -/* - * Clear the xprt backlog queue - */ -static int -xprt_clear_backlog(struct rpc_xprt *xprt) { +static int xprt_clear_backlog(struct rpc_xprt *xprt) { rpc_wake_up_next(&xprt->backlog); wake_up(&xprt->cong_wait); return 1; } -/* - * Destroy an RPC transport, killing off all requests. +/** + * xprt_destroy - destroy an RPC transport, killing off all requests. + * @xprt: transport to destroy + * */ -int -xprt_destroy(struct rpc_xprt *xprt) +int xprt_destroy(struct rpc_xprt *xprt) { dprintk("RPC: destroying transport %p\n", xprt); xprt_shutdown(xprt); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index fa1180ac4823..80222de3afa4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -33,23 +33,21 @@ #include #include +/* + * Maximum port number to use when requesting a reserved port. + */ +#define XS_MAX_RESVPORT (800U) + #ifdef RPC_DEBUG # undef RPC_DEBUG_DATA -# define RPCDBG_FACILITY RPCDBG_XPRT +# define RPCDBG_FACILITY RPCDBG_TRANS #endif -#define XPRT_MAX_RESVPORT (800) - #ifdef RPC_DEBUG_DATA -/* - * Print the buffer contents (first 128 bytes only--just enough for - * diropres return). - */ -static void -xprt_pktdump(char *msg, u32 *packet, unsigned int count) +static void xs_pktdump(char *msg, u32 *packet, unsigned int count) { - u8 *buf = (u8 *) packet; - int j; + u8 *buf = (u8 *) packet; + int j; dprintk("RPC: %s\n", msg); for (j = 0; j < count && j < 128; j += 4) { @@ -64,25 +62,22 @@ xprt_pktdump(char *msg, u32 *packet, unsigned int count) dprintk("\n"); } #else -static inline void -xprt_pktdump(char *msg, u32 *packet, unsigned int count) +static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) { /* NOP */ } #endif -/* - * Look up RPC transport given an INET socket +/** + * xs_sendpages - write pages directly to a socket + * @sock: socket to send on + * @addr: UDP only -- address of destination + * @addrlen: UDP only -- length of destination address + * @xdr: buffer containing this request + * @base: starting position in the buffer + * */ -static inline struct rpc_xprt * -xprt_from_sock(struct sock *sk) -{ - return (struct rpc_xprt *) sk->sk_user_data; -} - -static int -xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, - struct xdr_buf *xdr, unsigned int base, int msgflags) +static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, int msgflags) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; @@ -125,7 +120,7 @@ xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, } if (base || xdr->page_base) { pglen -= base; - base += xdr->page_base; + base += xdr->page_base; ppage += base >> PAGE_CACHE_SHIFT; base &= ~PAGE_CACHE_MASK; } @@ -176,23 +171,25 @@ xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, return ret; } -/* - * Write data to socket. +/** + * xs_sendmsg - write an RPC request to a socket + * @xprt: generic transport + * @req: the RPC request to write + * */ -static inline int -xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) +static int xs_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) { - struct socket *sock = xprt->sock; - struct xdr_buf *xdr = &req->rq_snd_buf; + struct socket *sock = xprt->sock; + struct xdr_buf *xdr = &req->rq_snd_buf; struct sockaddr *addr = NULL; int addrlen = 0; - unsigned int skip; - int result; + unsigned int skip; + int result; if (!sock) return -ENOTCONN; - xprt_pktdump("packet data:", + xs_pktdump("packet data:", req->rq_svec->iov_base, req->rq_svec->iov_len); @@ -201,13 +198,13 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) addr = (struct sockaddr *) &xprt->addr; addrlen = sizeof(xprt->addr); } - /* Dont repeat bytes */ + /* Don't repeat bytes */ skip = req->rq_bytes_sent; clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); - result = xdr_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); + result = xs_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); - dprintk("RPC: xprt_sendmsg(%d) = %d\n", xdr->len - skip, result); + dprintk("RPC: xs_sendmsg(%d) = %d\n", xdr->len - skip, result); if (result >= 0) return result; @@ -215,8 +212,7 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) switch (result) { case -ECONNREFUSED: /* When the server has died, an ICMP port unreachable message - * prompts ECONNREFUSED. - */ + * prompts ECONNREFUSED. */ case -EAGAIN: break; case -ECONNRESET: @@ -227,13 +223,25 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) result = -ENOTCONN; break; default: - printk(KERN_NOTICE "RPC: sendmsg returned error %d\n", -result); + break; } return result; } -static int -xprt_send_request(struct rpc_task *task) +/** + * xs_send_request - write an RPC request to a socket + * @task: address of RPC task that manages the state of an RPC request + * + * Return values: + * 0: The request has been sent + * EAGAIN: The socket was blocked, please call again later to + * complete the request + * other: Some other error occured, the request was not sent + * + * XXX: In the case of soft timeouts, should we eventually give up + * if the socket is not able to make progress? + */ +static int xs_send_request(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; @@ -242,18 +250,18 @@ xprt_send_request(struct rpc_task *task) /* set up everything as needed. */ /* Write the record marker */ if (xprt->stream) { - u32 *marker = req->rq_svec[0].iov_base; + u32 *marker = req->rq_svec[0].iov_base; *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); } /* Continue transmitting the packet/record. We must be careful * to cope with writespace callbacks arriving _after_ we have - * called xprt_sendmsg(). + * called sendmsg(). */ while (1) { req->rq_xtime = jiffies; - status = xprt_sendmsg(xprt, req); + status = xs_sendmsg(xprt, req); if (status < 0) break; @@ -285,7 +293,7 @@ xprt_send_request(struct rpc_task *task) if (status == -EAGAIN) { if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { - /* Protect against races with xprt_write_space */ + /* Protect against races with xs_write_space */ spin_lock_bh(&xprt->sock_lock); /* Don't race with disconnect */ if (!xprt_connected(xprt)) @@ -303,65 +311,77 @@ xprt_send_request(struct rpc_task *task) return status; } -/* - * Close down a transport socket +/** + * xs_close - close a socket + * @xprt: transport + * */ -static void -xprt_close(struct rpc_xprt *xprt) +static void xs_close(struct rpc_xprt *xprt) { - struct socket *sock = xprt->sock; - struct sock *sk = xprt->inet; + struct socket *sock = xprt->sock; + struct sock *sk = xprt->inet; if (!sk) return; + dprintk("RPC: xs_close xprt %p\n", xprt); + write_lock_bh(&sk->sk_callback_lock); xprt->inet = NULL; xprt->sock = NULL; - sk->sk_user_data = NULL; - sk->sk_data_ready = xprt->old_data_ready; + sk->sk_user_data = NULL; + sk->sk_data_ready = xprt->old_data_ready; sk->sk_state_change = xprt->old_state_change; - sk->sk_write_space = xprt->old_write_space; + sk->sk_write_space = xprt->old_write_space; write_unlock_bh(&sk->sk_callback_lock); - sk->sk_no_check = 0; + sk->sk_no_check = 0; sock_release(sock); } -static void xprt_socket_destroy(struct rpc_xprt *xprt) +/** + * xs_destroy - prepare to shutdown a transport + * @xprt: doomed transport + * + */ +static void xs_destroy(struct rpc_xprt *xprt) { + dprintk("RPC: xs_destroy xprt %p\n", xprt); + cancel_delayed_work(&xprt->sock_connect); flush_scheduled_work(); xprt_disconnect(xprt); - xprt_close(xprt); + xs_close(xprt); kfree(xprt->slot); } -/* - * Input handler for RPC replies. Called from a bottom half and hence - * atomic. - */ -static void -udp_data_ready(struct sock *sk, int len) +static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) { - struct rpc_task *task; - struct rpc_xprt *xprt; + return (struct rpc_xprt *) sk->sk_user_data; +} + +/** + * xs_udp_data_ready - "data ready" callback for UDP sockets + * @sk: socket with data to read + * @len: how much data to read + * + */ +static void xs_udp_data_ready(struct sock *sk, int len) +{ + struct rpc_task *task; + struct rpc_xprt *xprt; struct rpc_rqst *rovr; - struct sk_buff *skb; + struct sk_buff *skb; int err, repsize, copied; u32 _xid, *xp; read_lock(&sk->sk_callback_lock); - dprintk("RPC: udp_data_ready...\n"); - if (!(xprt = xprt_from_sock(sk))) { - printk("RPC: udp_data_ready request not found!\n"); + dprintk("RPC: xs_udp_data_ready...\n"); + if (!(xprt = xprt_from_sock(sk))) goto out; - } - - dprintk("RPC: udp_data_ready client %p\n", xprt); if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) goto out; @@ -371,7 +391,7 @@ udp_data_ready(struct sock *sk, int len) repsize = skb->len - sizeof(struct udphdr); if (repsize < 4) { - printk("RPC: impossible RPC reply size %d!\n", repsize); + dprintk("RPC: impossible RPC reply size %d!\n", repsize); goto dropit; } @@ -410,11 +430,7 @@ udp_data_ready(struct sock *sk, int len) read_unlock(&sk->sk_callback_lock); } -/* - * Copy from an skb into memory and shrink the skb. - */ -static inline size_t -tcp_copy_data(skb_reader_t *desc, void *p, size_t len) +static inline size_t xs_tcp_copy_data(skb_reader_t *desc, void *p, size_t len) { if (len > desc->count) len = desc->count; @@ -430,18 +446,14 @@ tcp_copy_data(skb_reader_t *desc, void *p, size_t len) return len; } -/* - * TCP read fragment marker - */ -static inline void -tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) { size_t len, used; char *p; p = ((char *) &xprt->tcp_recm) + xprt->tcp_offset; len = sizeof(xprt->tcp_recm) - xprt->tcp_offset; - used = tcp_copy_data(desc, p, len); + used = xs_tcp_copy_data(desc, p, len); xprt->tcp_offset += used; if (used != len) return; @@ -455,15 +467,15 @@ tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) xprt->tcp_offset = 0; /* Sanity check of the record length */ if (xprt->tcp_reclen < 4) { - printk(KERN_ERR "RPC: Invalid TCP record fragment length\n"); + dprintk("RPC: invalid TCP record fragment length\n"); xprt_disconnect(xprt); + return; } dprintk("RPC: reading TCP record fragment of length %d\n", xprt->tcp_reclen); } -static void -tcp_check_recm(struct rpc_xprt *xprt) +static void xs_tcp_check_recm(struct rpc_xprt *xprt) { dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); @@ -478,11 +490,7 @@ tcp_check_recm(struct rpc_xprt *xprt) } } -/* - * TCP read xid - */ -static inline void -tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) { size_t len, used; char *p; @@ -490,7 +498,7 @@ tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) len = sizeof(xprt->tcp_xid) - xprt->tcp_offset; dprintk("RPC: reading XID (%Zu bytes)\n", len); p = ((char *) &xprt->tcp_xid) + xprt->tcp_offset; - used = tcp_copy_data(desc, p, len); + used = xs_tcp_copy_data(desc, p, len); xprt->tcp_offset += used; if (used != len) return; @@ -499,14 +507,10 @@ tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) xprt->tcp_copied = 4; dprintk("RPC: reading reply for XID %08x\n", ntohl(xprt->tcp_xid)); - tcp_check_recm(xprt); + xs_tcp_check_recm(xprt); } -/* - * TCP read and complete request - */ -static inline void -tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) { struct rpc_rqst *req; struct xdr_buf *rcvbuf; @@ -533,12 +537,12 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) memcpy(&my_desc, desc, sizeof(my_desc)); my_desc.count = len; r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, - &my_desc, tcp_copy_data); + &my_desc, xs_tcp_copy_data); desc->count -= r; desc->offset += r; } else r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, - desc, tcp_copy_data); + desc, xs_tcp_copy_data); if (r > 0) { xprt->tcp_copied += r; @@ -581,14 +585,10 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) xprt_complete_rqst(xprt, req, xprt->tcp_copied); } spin_unlock(&xprt->sock_lock); - tcp_check_recm(xprt); + xs_tcp_check_recm(xprt); } -/* - * TCP discard extra bytes from a short read - */ -static inline void -tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) { size_t len; @@ -599,16 +599,10 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) desc->offset += len; xprt->tcp_offset += len; dprintk("RPC: discarded %Zu bytes\n", len); - tcp_check_recm(xprt); + xs_tcp_check_recm(xprt); } -/* - * TCP record receive routine - * We first have to grab the record marker, then the XID, then the data. - */ -static int -tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, - unsigned int offset, size_t len) +static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len) { struct rpc_xprt *xprt = rd_desc->arg.data; skb_reader_t desc = { @@ -616,64 +610,72 @@ tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, .offset = offset, .count = len, .csum = 0 - }; + }; - dprintk("RPC: tcp_data_recv\n"); + dprintk("RPC: xs_tcp_data_recv started\n"); do { /* Read in a new fragment marker if necessary */ /* Can we ever really expect to get completely empty fragments? */ if (xprt->tcp_flags & XPRT_COPY_RECM) { - tcp_read_fraghdr(xprt, &desc); + xs_tcp_read_fraghdr(xprt, &desc); continue; } /* Read in the xid if necessary */ if (xprt->tcp_flags & XPRT_COPY_XID) { - tcp_read_xid(xprt, &desc); + xs_tcp_read_xid(xprt, &desc); continue; } /* Read in the request data */ if (xprt->tcp_flags & XPRT_COPY_DATA) { - tcp_read_request(xprt, &desc); + xs_tcp_read_request(xprt, &desc); continue; } /* Skip over any trailing bytes on short reads */ - tcp_read_discard(xprt, &desc); + xs_tcp_read_discard(xprt, &desc); } while (desc.count); - dprintk("RPC: tcp_data_recv done\n"); + dprintk("RPC: xs_tcp_data_recv done\n"); return len - desc.count; } -static void tcp_data_ready(struct sock *sk, int bytes) +/** + * xs_tcp_data_ready - "data ready" callback for TCP sockets + * @sk: socket with data to read + * @bytes: how much data to read + * + */ +static void xs_tcp_data_ready(struct sock *sk, int bytes) { struct rpc_xprt *xprt; read_descriptor_t rd_desc; read_lock(&sk->sk_callback_lock); - dprintk("RPC: tcp_data_ready...\n"); - if (!(xprt = xprt_from_sock(sk))) { - printk("RPC: tcp_data_ready socket info not found!\n"); + dprintk("RPC: xs_tcp_data_ready...\n"); + if (!(xprt = xprt_from_sock(sk))) goto out; - } if (xprt->shutdown) goto out; - /* We use rd_desc to pass struct xprt to tcp_data_recv */ + /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ rd_desc.arg.data = xprt; rd_desc.count = 65536; - tcp_read_sock(sk, &rd_desc, tcp_data_recv); + tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); out: read_unlock(&sk->sk_callback_lock); } -static void -tcp_state_change(struct sock *sk) +/** + * xs_tcp_state_change - callback to handle TCP socket state changes + * @sk: socket whose state has changed + * + */ +static void xs_tcp_state_change(struct sock *sk) { - struct rpc_xprt *xprt; + struct rpc_xprt *xprt; read_lock(&sk->sk_callback_lock); if (!(xprt = xprt_from_sock(sk))) goto out; - dprintk("RPC: tcp_state_change client %p...\n", xprt); + dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); dprintk("RPC: state %x conn %d dead %d zapped %d\n", sk->sk_state, xprt_connected(xprt), sock_flag(sk, SOCK_DEAD), @@ -703,17 +705,20 @@ tcp_state_change(struct sock *sk) read_unlock(&sk->sk_callback_lock); } -/* +/** + * xs_write_space - callback invoked when socket buffer space becomes + * available + * @sk: socket whose state has changed + * * Called when more output buffer space is available for this socket. * We try not to wake our writers until they can make "significant" * progress, otherwise we'll waste resources thrashing sock_sendmsg * with a bunch of small requests. */ -static void -xprt_write_space(struct sock *sk) +static void xs_write_space(struct sock *sk) { - struct rpc_xprt *xprt; - struct socket *sock; + struct rpc_xprt *xprt; + struct socket *sock; read_lock(&sk->sk_callback_lock); if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) @@ -743,11 +748,15 @@ xprt_write_space(struct sock *sk) read_unlock(&sk->sk_callback_lock); } -/* - * Set socket buffer length +/** + * xs_set_buffer_size - set send and receive limits + * @xprt: generic transport + * + * Set socket send and receive limits based on the + * sndsize and rcvsize fields in the generic transport + * structure. This applies only to UDP sockets. */ -static void -xprt_sock_setbufsize(struct rpc_xprt *xprt) +static void xs_set_buffer_size(struct rpc_xprt *xprt) { struct sock *sk = xprt->inet; @@ -764,15 +773,12 @@ xprt_sock_setbufsize(struct rpc_xprt *xprt) } } -/* - * Bind to a reserved port - */ -static inline int xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock) +static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) { struct sockaddr_in myaddr = { .sin_family = AF_INET, }; - int err, port; + int err, port; /* Were we already bound to a given port? Try to reuse it */ port = xprt->port; @@ -782,20 +788,47 @@ static inline int xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock) sizeof(myaddr)); if (err == 0) { xprt->port = port; + dprintk("RPC: xs_bindresvport bound to port %u\n", + port); return 0; } if (--port == 0) - port = XPRT_MAX_RESVPORT; + port = XS_MAX_RESVPORT; } while (err == -EADDRINUSE && port != xprt->port); - printk("RPC: Can't bind to reserved port (%d).\n", -err); + dprintk("RPC: can't bind to reserved port (%d).\n", -err); return err; } -static void -xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) +static struct socket *xs_create(struct rpc_xprt *xprt, int proto, int resvport) { - struct sock *sk = sock->sk; + struct socket *sock; + int type, err; + + dprintk("RPC: xs_create(%s %d)\n", + (proto == IPPROTO_UDP)? "udp" : "tcp", proto); + + type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; + + if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { + dprintk("RPC: can't create socket (%d).\n", -err); + return NULL; + } + + /* If the caller has the capability, bind to a reserved port */ + if (resvport && xs_bindresvport(xprt, sock) < 0) + goto failed; + + return sock; + +failed: + sock_release(sock); + return NULL; +} + +static void xs_bind(struct rpc_xprt *xprt, struct socket *sock) +{ + struct sock *sk = sock->sk; if (xprt->inet) return; @@ -806,16 +839,16 @@ xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) xprt->old_state_change = sk->sk_state_change; xprt->old_write_space = sk->sk_write_space; if (xprt->prot == IPPROTO_UDP) { - sk->sk_data_ready = udp_data_ready; + sk->sk_data_ready = xs_udp_data_ready; sk->sk_no_check = UDP_CSUM_NORCV; xprt_set_connected(xprt); } else { tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ - sk->sk_data_ready = tcp_data_ready; - sk->sk_state_change = tcp_state_change; + sk->sk_data_ready = xs_tcp_data_ready; + sk->sk_state_change = xs_tcp_state_change; xprt_clear_connected(xprt); } - sk->sk_write_space = xprt_write_space; + sk->sk_write_space = xs_write_space; /* Reset to new socket */ xprt->sock = sock; @@ -825,39 +858,13 @@ xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) return; } -/* - * Datastream sockets are created here, but xprt_connect will create - * and connect stream sockets. +/** + * xs_connect_worker - try to connect a socket to a remote endpoint + * @args: RPC transport to connect + * + * Invoked by a work queue tasklet. */ -static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport) -{ - struct socket *sock; - int type, err; - - dprintk("RPC: xprt_create_socket(%s %d)\n", - (proto == IPPROTO_UDP)? "udp" : "tcp", proto); - - type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; - - if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { - printk("RPC: can't create socket (%d).\n", -err); - return NULL; - } - - /* If the caller has the capability, bind to a reserved port */ - if (resvport && xprt_bindresvport(xprt, sock) < 0) { - printk("RPC: can't bind to reserved port.\n"); - goto failed; - } - - return sock; - -failed: - sock_release(sock); - return NULL; -} - -static void xprt_socket_connect(void *args) +static void xs_connect_worker(void *args) { struct rpc_xprt *xprt = (struct rpc_xprt *)args; struct socket *sock = xprt->sock; @@ -866,18 +873,20 @@ static void xprt_socket_connect(void *args) if (xprt->shutdown || xprt->addr.sin_port == 0) goto out; + dprintk("RPC: xs_connect_worker xprt %p\n", xprt); + /* * Start by resetting any existing state */ - xprt_close(xprt); - sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport); + xs_close(xprt); + sock = xs_create(xprt, xprt->prot, xprt->resvport); if (sock == NULL) { /* couldn't create socket or bind to reserved port; * this is likely a permanent error, so cause an abort */ goto out; } - xprt_bind_socket(xprt, sock); - xprt_sock_setbufsize(xprt); + xs_bind(xprt, sock); + xs_set_buffer_size(xprt); status = 0; if (!xprt->stream) @@ -908,20 +917,23 @@ static void xprt_socket_connect(void *args) smp_mb__after_clear_bit(); } -static void -xprt_connect_sock(struct rpc_task *task) +/** + * xs_connect - connect a socket to a remote endpoint + * @task: address of RPC task that manages state of connect request + * + * TCP: If the remote end dropped the connection, delay reconnecting. + */ +static void xs_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { - /* Note: if we are here due to a dropped connection - * we delay reconnecting by RPC_REESTABLISH_TIMEOUT/HZ - * seconds - */ - if (xprt->sock != NULL) + if (xprt->sock != NULL) { + dprintk("RPC: xs_connect delayed xprt %p\n", xprt); schedule_delayed_work(&xprt->sock_connect, RPC_REESTABLISH_TIMEOUT); - else { + } else { + dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); schedule_work(&xprt->sock_connect); /* flush_scheduled_work can sleep... */ if (!RPC_IS_ASYNC(task)) @@ -930,29 +942,23 @@ xprt_connect_sock(struct rpc_task *task) } } -/* - * Set default timeout parameters - */ -static void -xprt_default_timeout(struct rpc_timeout *to, int proto) -{ - if (proto == IPPROTO_UDP) - xprt_set_timeout(to, 5, 5 * HZ); - else - xprt_set_timeout(to, 2, 60 * HZ); -} - -static struct rpc_xprt_ops xprt_socket_ops = { - .set_buffer_size = xprt_sock_setbufsize, - .connect = xprt_connect_sock, - .send_request = xprt_send_request, - .close = xprt_close, - .destroy = xprt_socket_destroy, +static struct rpc_xprt_ops xs_ops = { + .set_buffer_size = xs_set_buffer_size, + .connect = xs_connect, + .send_request = xs_send_request, + .close = xs_close, + .destroy = xs_destroy, }; extern unsigned int xprt_udp_slot_table_entries; extern unsigned int xprt_tcp_slot_table_entries; +/** + * xs_setup_udp - Set up transport to use a UDP socket + * @xprt: transport to set up + * @to: timeout parameters + * + */ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) { size_t slot_table_size; @@ -967,7 +973,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) memset(xprt->slot, 0, slot_table_size); xprt->prot = IPPROTO_UDP; - xprt->port = XPRT_MAX_RESVPORT; + xprt->port = XS_MAX_RESVPORT; xprt->stream = 0; xprt->nocong = 0; xprt->cwnd = RPC_INITCWND; @@ -975,18 +981,24 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); + INIT_WORK(&xprt->sock_connect, xs_connect_worker, xprt); - xprt->ops = &xprt_socket_ops; + xprt->ops = &xs_ops; if (to) xprt->timeout = *to; else - xprt_default_timeout(to, xprt->prot); + xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); return 0; } +/** + * xs_setup_tcp - Set up transport to use a TCP socket + * @xprt: transport to set up + * @to: timeout parameters + * + */ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) { size_t slot_table_size; @@ -1001,21 +1013,21 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) memset(xprt->slot, 0, slot_table_size); xprt->prot = IPPROTO_TCP; - xprt->port = XPRT_MAX_RESVPORT; + xprt->port = XS_MAX_RESVPORT; xprt->stream = 1; xprt->nocong = 1; xprt->cwnd = RPC_MAXCWND(xprt); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = (1U << 31) - 1; - INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); + INIT_WORK(&xprt->sock_connect, xs_connect_worker, xprt); - xprt->ops = &xprt_socket_ops; + xprt->ops = &xs_ops; if (to) xprt->timeout = *to; else - xprt_default_timeout(to, xprt->prot); + xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); return 0; } From b4b5cc85ed4ecbe4adbfbc4df028850de67a9f09 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:29 -0400 Subject: [PATCH 0158/1939] [PATCH] RPC: Reduce stack utilization in xs_sendpages Reduce stack utilization of the RPC socket transport's send path. A couple of unlikely()s are added to ensure the compiler places the tail processing at the end of the csect. Test-plan: Millions of fsx operations. Performance characterization such as "sio" or "iozone". Version: Thu, 11 Aug 2005 16:04:30 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 73 +++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 80222de3afa4..a5a04203a6b0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -68,6 +68,41 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) } #endif +#define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) + +static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len) +{ + struct kvec iov = { + .iov_base = xdr->head[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_name = addr, + .msg_namelen = addrlen, + .msg_flags = XS_SENDMSG_FLAGS, + }; + + if (xdr->len > len) + msg.msg_flags |= MSG_MORE; + + if (likely(iov.iov_len)) + return kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); + return kernel_sendmsg(sock, &msg, NULL, 0, 0); +} + +static int xs_send_tail(struct socket *sock, struct xdr_buf *xdr, unsigned int base, unsigned int len) +{ + struct kvec iov = { + .iov_base = xdr->tail[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_flags = XS_SENDMSG_FLAGS, + }; + + return kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); +} + /** * xs_sendpages - write pages directly to a socket * @sock: socket to send on @@ -77,7 +112,7 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) * @base: starting position in the buffer * */ -static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, int msgflags) +static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; @@ -86,35 +121,20 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, len = xdr->head[0].iov_len; if (base < len || (addr != NULL && base == 0)) { - struct kvec iov = { - .iov_base = xdr->head[0].iov_base + base, - .iov_len = len - base, - }; - struct msghdr msg = { - .msg_name = addr, - .msg_namelen = addrlen, - .msg_flags = msgflags, - }; - if (xdr->len > len) - msg.msg_flags |= MSG_MORE; - - if (iov.iov_len != 0) - err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); - else - err = kernel_sendmsg(sock, &msg, NULL, 0, 0); + err = xs_send_head(sock, addr, addrlen, xdr, base, len); if (ret == 0) ret = err; else if (err > 0) ret += err; - if (err != iov.iov_len) + if (err != (len - base)) goto out; base = 0; } else base -= len; - if (pglen == 0) + if (unlikely(pglen == 0)) goto copy_tail; - if (base >= pglen) { + if (unlikely(base >= pglen)) { base -= pglen; goto copy_tail; } @@ -127,7 +147,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, sendpage = sock->ops->sendpage ? : sock_no_sendpage; do { - int flags = msgflags; + int flags = XS_SENDMSG_FLAGS; len = PAGE_CACHE_SIZE; if (base) @@ -154,14 +174,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, copy_tail: len = xdr->tail[0].iov_len; if (base < len) { - struct kvec iov = { - .iov_base = xdr->tail[0].iov_base + base, - .iov_len = len - base, - }; - struct msghdr msg = { - .msg_flags = msgflags, - }; - err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); + err = xs_send_tail(sock, xdr, base, len); if (ret == 0) ret = err; else if (err > 0) @@ -202,7 +215,7 @@ static int xs_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) skip = req->rq_bytes_sent; clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); - result = xs_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); + result = xs_sendpages(sock, addr, addrlen, xdr, skip); dprintk("RPC: xs_sendmsg(%d) = %d\n", xdr->len - skip, result); From 4a0f8c04f2ece949d54a0c4fd7490259cf23a58a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:32 -0400 Subject: [PATCH 0159/1939] [PATCH] RPC: Rename sock_lock Clean-up: replace a name reference to sockets in the generic parts of the RPC client by renaming sock_lock in the rpc_xprt structure. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:05:00 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/xprt.c | 44 ++++++++++++++++++------------------- net/sunrpc/xprtsock.c | 22 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index d82b47ab73cb..c4f903f0e17c 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -198,7 +198,7 @@ struct rpc_xprt { /* * Send stuff */ - spinlock_t sock_lock; /* lock socket info */ + spinlock_t transport_lock; /* lock transport info */ spinlock_t xprt_lock; /* lock xprt info */ struct rpc_task * snd_task; /* Task blocked in send */ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 589195e630ef..1f0da8c1a3b0 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -106,9 +106,9 @@ xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { int retval; - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); retval = __xprt_lock_write(xprt, task); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); return retval; } @@ -161,9 +161,9 @@ __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) { - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); __xprt_release_write(xprt, task); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); } /* @@ -266,9 +266,9 @@ int xprt_adjust_timeout(struct rpc_rqst *req) req->rq_retries = 0; xprt_reset_majortimeo(req); /* Reset the RTT counters == "slow start" */ - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); pprintk("RPC: %lu timeout\n", jiffies); status = -ETIMEDOUT; } @@ -298,10 +298,10 @@ xprt_socket_autoclose(void *args) void xprt_disconnect(struct rpc_xprt *xprt) { dprintk("RPC: disconnected transport %p\n", xprt); - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); xprt_clear_connected(xprt); rpc_wake_up_status(&xprt->pending, -ENOTCONN); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); } static void @@ -309,12 +309,12 @@ xprt_init_autodisconnect(unsigned long data) { struct rpc_xprt *xprt = (struct rpc_xprt *)data; - spin_lock(&xprt->sock_lock); + spin_lock(&xprt->transport_lock); if (!list_empty(&xprt->recv) || xprt->shutdown) goto out_abort; if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) goto out_abort; - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); /* Let keventd close the socket */ if (test_bit(XPRT_CONNECTING, &xprt->sockstate) != 0) xprt_release_write(xprt, NULL); @@ -322,7 +322,7 @@ xprt_init_autodisconnect(unsigned long data) schedule_work(&xprt->task_cleanup); return; out_abort: - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); } /** @@ -482,7 +482,7 @@ xprt_timer(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - spin_lock(&xprt->sock_lock); + spin_lock(&xprt->transport_lock); if (req->rq_received) goto out; @@ -496,7 +496,7 @@ xprt_timer(struct rpc_task *task) out: task->tk_timeout = 0; rpc_wake_up_task(task); - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); } /** @@ -515,7 +515,7 @@ int xprt_prepare_transmit(struct rpc_task *task) if (xprt->shutdown) return -EIO; - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); if (req->rq_received && !req->rq_bytes_sent) { err = req->rq_received; goto out_unlock; @@ -530,7 +530,7 @@ int xprt_prepare_transmit(struct rpc_task *task) goto out_unlock; } out_unlock: - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); return err; } @@ -552,13 +552,13 @@ void xprt_transmit(struct rpc_task *task) smp_rmb(); if (!req->rq_received) { if (list_empty(&req->rq_list)) { - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); /* Update the softirq receive buffer */ memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(req->rq_private_buf)); /* Add request to the receive list */ list_add_tail(&req->rq_list, &xprt->recv); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); @@ -592,7 +592,7 @@ void xprt_transmit(struct rpc_task *task) out_receive: dprintk("RPC: %4d xmit complete\n", task->tk_pid); /* Set the task's receive timeout value */ - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); if (!xprt->nocong) { int timer = task->tk_msg.rpc_proc->p_timer; task->tk_timeout = rpc_calc_rto(clnt->cl_rtt, timer); @@ -607,7 +607,7 @@ void xprt_transmit(struct rpc_task *task) else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); __xprt_release_write(xprt, task); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); } static inline void do_xprt_reserve(struct rpc_task *task) @@ -683,7 +683,7 @@ void xprt_release(struct rpc_task *task) if (!(req = task->tk_rqstp)) return; - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); __xprt_release_write(xprt, task); __xprt_put_cong(xprt, req); if (!list_empty(&req->rq_list)) @@ -692,7 +692,7 @@ void xprt_release(struct rpc_task *task) if (list_empty(&xprt->recv) && !xprt->shutdown) mod_timer(&xprt->timer, xprt->last_used + RPC_IDLE_DISCONNECT_TIMEOUT); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); task->tk_rqstp = NULL; memset(req, 0, sizeof(*req)); /* mark unused */ @@ -750,7 +750,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc return ERR_PTR(result); } - spin_lock_init(&xprt->sock_lock); + spin_lock_init(&xprt->transport_lock); spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a5a04203a6b0..bc90caab6088 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -307,7 +307,7 @@ static int xs_send_request(struct rpc_task *task) if (status == -EAGAIN) { if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { /* Protect against races with xs_write_space */ - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; @@ -315,7 +315,7 @@ static int xs_send_request(struct rpc_task *task) task->tk_timeout = req->rq_timeout; rpc_sleep_on(&xprt->pending, task, NULL, NULL); } - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); return status; } /* Keep holding the socket if it is blocked */ @@ -415,7 +415,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) goto dropit; /* Look up and lock the request corresponding to the given XID */ - spin_lock(&xprt->sock_lock); + spin_lock(&xprt->transport_lock); rovr = xprt_lookup_rqst(xprt, *xp); if (!rovr) goto out_unlock; @@ -436,7 +436,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) xprt_complete_rqst(xprt, rovr, copied); out_unlock: - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); dropit: skb_free_datagram(sk, skb); out: @@ -531,13 +531,13 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc ssize_t r; /* Find and lock the request corresponding to this xid */ - spin_lock(&xprt->sock_lock); + spin_lock(&xprt->transport_lock); req = xprt_lookup_rqst(xprt, xprt->tcp_xid); if (!req) { xprt->tcp_flags &= ~XPRT_COPY_DATA; dprintk("RPC: XID %08x request not found!\n", ntohl(xprt->tcp_xid)); - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); return; } @@ -597,7 +597,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc req->rq_task->tk_pid); xprt_complete_rqst(xprt, req, xprt->tcp_copied); } - spin_unlock(&xprt->sock_lock); + spin_unlock(&xprt->transport_lock); xs_tcp_check_recm(xprt); } @@ -696,7 +696,7 @@ static void xs_tcp_state_change(struct sock *sk) switch (sk->sk_state) { case TCP_ESTABLISHED: - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); if (!xprt_test_and_set_connected(xprt)) { /* Reset TCP record info */ xprt->tcp_offset = 0; @@ -705,7 +705,7 @@ static void xs_tcp_state_change(struct sock *sk) xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; rpc_wake_up(&xprt->pending); } - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); break; case TCP_SYN_SENT: case TCP_SYN_RECV: @@ -753,10 +753,10 @@ static void xs_write_space(struct sock *sk) if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) goto out; - spin_lock_bh(&xprt->sock_lock); + spin_lock_bh(&xprt->transport_lock); if (xprt->snd_task) rpc_wake_up_task(xprt->snd_task); - spin_unlock_bh(&xprt->sock_lock); + spin_unlock_bh(&xprt->transport_lock); out: read_unlock(&sk->sk_callback_lock); } From 5dc07727f86b25851e95193a0c484ea21b531c47 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:35 -0400 Subject: [PATCH 0160/1939] [PATCH] RPC: Rename xprt_lock Clean-up: Replace the xprt_lock with something more aptly named. This lock single-threads the XID and request slot reservation process. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:05:26 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/xprt.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index c4f903f0e17c..41ce296dded1 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -199,7 +199,7 @@ struct rpc_xprt { * Send stuff */ spinlock_t transport_lock; /* lock transport info */ - spinlock_t xprt_lock; /* lock xprt info */ + spinlock_t reserve_lock; /* lock slot table */ struct rpc_task * snd_task; /* Task blocked in send */ struct list_head recv; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1f0da8c1a3b0..9c45c522e3ef 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -643,9 +643,9 @@ void xprt_reserve(struct rpc_task *task) task->tk_status = -EIO; if (!xprt->shutdown) { - spin_lock(&xprt->xprt_lock); + spin_lock(&xprt->reserve_lock); do_xprt_reserve(task); - spin_unlock(&xprt->xprt_lock); + spin_unlock(&xprt->reserve_lock); } } @@ -698,10 +698,10 @@ void xprt_release(struct rpc_task *task) dprintk("RPC: %4d release request %p\n", task->tk_pid, req); - spin_lock(&xprt->xprt_lock); + spin_lock(&xprt->reserve_lock); list_add(&req->rq_list, &xprt->free); xprt_clear_backlog(xprt); - spin_unlock(&xprt->xprt_lock); + spin_unlock(&xprt->reserve_lock); } /** @@ -751,7 +751,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc } spin_lock_init(&xprt->transport_lock); - spin_lock_init(&xprt->xprt_lock); + spin_lock_init(&xprt->reserve_lock); init_waitqueue_head(&xprt->cong_wait); INIT_LIST_HEAD(&xprt->free); From 2226feb6bcd0e5e117a9be3ea3dd3ffc14f3e41e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:38 -0400 Subject: [PATCH 0161/1939] [PATCH] RPC: rename the sockstate field Clean-up: get rid of a name reference to sockets in the generic parts of the RPC client by renaming the sockstate field in the rpc_xprt structure. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:05:53 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 58 ++++++++++++++++++++++++++++++------- net/sunrpc/xprt.c | 14 ++++----- net/sunrpc/xprtsock.c | 6 ++-- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 41ce296dded1..009a3bb4f997 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -163,7 +163,7 @@ struct rpc_xprt { struct list_head free; /* free slots */ struct rpc_rqst * slot; /* slot table storage */ unsigned int max_reqs; /* total slots */ - unsigned long sockstate; /* Socket state */ + unsigned long state; /* transport state */ unsigned char shutdown : 1, /* being shut down */ nocong : 1, /* no congestion control */ resvport : 1, /* use a reserved port */ @@ -240,16 +240,54 @@ int xs_setup_udp(struct rpc_xprt *, int xs_setup_tcp(struct rpc_xprt *, struct rpc_timeout *); -#define XPRT_LOCKED 0 -#define XPRT_CONNECT 1 -#define XPRT_CONNECTING 2 +/* + * Reserved bit positions in xprt->state + */ +#define XPRT_LOCKED (0) +#define XPRT_CONNECTED (1) +#define XPRT_CONNECTING (2) -#define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate)) -#define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) -#define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) -#define xprt_test_and_clear_connected(xp) \ - (test_and_clear_bit(XPRT_CONNECT, &(xp)->sockstate)) -#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) +static inline void xprt_set_connected(struct rpc_xprt *xprt) +{ + set_bit(XPRT_CONNECTED, &xprt->state); +} + +static inline void xprt_clear_connected(struct rpc_xprt *xprt) +{ + clear_bit(XPRT_CONNECTED, &xprt->state); +} + +static inline int xprt_connected(struct rpc_xprt *xprt) +{ + return test_bit(XPRT_CONNECTED, &xprt->state); +} + +static inline int xprt_test_and_set_connected(struct rpc_xprt *xprt) +{ + return test_and_set_bit(XPRT_CONNECTED, &xprt->state); +} + +static inline int xprt_test_and_clear_connected(struct rpc_xprt *xprt) +{ + return test_and_clear_bit(XPRT_CONNECTED, &xprt->state); +} + +static inline void xprt_clear_connecting(struct rpc_xprt *xprt) +{ + smp_mb__before_clear_bit(); + clear_bit(XPRT_CONNECTING, &xprt->state); + smp_mb__after_clear_bit(); +} + +static inline int xprt_connecting(struct rpc_xprt *xprt) +{ + return test_bit(XPRT_CONNECTING, &xprt->state); +} + +static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt) +{ + return test_and_set_bit(XPRT_CONNECTING, &xprt->state); +} #endif /* __KERNEL__*/ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9c45c522e3ef..57c5e77b155e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -74,7 +74,7 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) { + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) return 1; goto out_sleep; @@ -88,7 +88,7 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) return 1; } smp_mb__before_clear_bit(); - clear_bit(XPRT_LOCKED, &xprt->sockstate); + clear_bit(XPRT_LOCKED, &xprt->state); smp_mb__after_clear_bit(); out_sleep: dprintk("RPC: %4d failed to lock socket %p\n", task->tk_pid, xprt); @@ -118,7 +118,7 @@ __xprt_lock_write_next(struct rpc_xprt *xprt) { struct rpc_task *task; - if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; if (!xprt->nocong && RPCXPRT_CONGESTED(xprt)) goto out_unlock; @@ -139,7 +139,7 @@ __xprt_lock_write_next(struct rpc_xprt *xprt) } out_unlock: smp_mb__before_clear_bit(); - clear_bit(XPRT_LOCKED, &xprt->sockstate); + clear_bit(XPRT_LOCKED, &xprt->state); smp_mb__after_clear_bit(); } @@ -152,7 +152,7 @@ __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) if (xprt->snd_task == task) { xprt->snd_task = NULL; smp_mb__before_clear_bit(); - clear_bit(XPRT_LOCKED, &xprt->sockstate); + clear_bit(XPRT_LOCKED, &xprt->state); smp_mb__after_clear_bit(); __xprt_lock_write_next(xprt); } @@ -312,11 +312,11 @@ xprt_init_autodisconnect(unsigned long data) spin_lock(&xprt->transport_lock); if (!list_empty(&xprt->recv) || xprt->shutdown) goto out_abort; - if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) goto out_abort; spin_unlock(&xprt->transport_lock); /* Let keventd close the socket */ - if (test_bit(XPRT_CONNECTING, &xprt->sockstate) != 0) + if (xprt_connecting(xprt)) xprt_release_write(xprt, NULL); else schedule_work(&xprt->task_cleanup); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index bc90caab6088..76a33b54f436 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -925,9 +925,7 @@ static void xs_connect_worker(void *args) else rpc_wake_up(&xprt->pending); out_clear: - smp_mb__before_clear_bit(); - clear_bit(XPRT_CONNECTING, &xprt->sockstate); - smp_mb__after_clear_bit(); + xprt_clear_connecting(xprt); } /** @@ -940,7 +938,7 @@ static void xs_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { + if (!xprt_test_and_set_connecting(xprt)) { if (xprt->sock != NULL) { dprintk("RPC: xs_connect delayed xprt %p\n", xprt); schedule_delayed_work(&xprt->sock_connect, From 86b9f57dfdf455763d2be73a742a9a88bb664173 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:41 -0400 Subject: [PATCH 0162/1939] [PATCH] RPC: Eliminate socket.h includes in RPC client Clean-up: get rid of unnecessary socket.h and in.h includes in the generic parts of the RPC client. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:06:23 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/auth.c | 1 - net/sunrpc/auth_gss/auth_gss.c | 2 -- net/sunrpc/auth_gss/gss_krb5_mech.c | 1 - net/sunrpc/auth_gss/gss_mech_switch.c | 1 - net/sunrpc/auth_null.c | 2 -- net/sunrpc/auth_unix.c | 2 -- net/sunrpc/clnt.c | 1 - net/sunrpc/sunrpc_syms.c | 1 - 8 files changed, 11 deletions(-) diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 505e2d4b3d62..a415d99c394d 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 2f7b867161d2..53a030acdf75 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -42,8 +42,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 606a8a82cafb..462c5b86b073 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 9dfb68377d69..58aeaddd8c79 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 9b72d3abf823..f56767aaa927 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -7,9 +7,7 @@ */ #include -#include #include -#include #include #include #include diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 4ff297a9b15b..890fb5ea0dcb 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index ab50c3c9e6a8..0d1b010a4a01 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index ed48ff022d35..2387e7b823ff 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include From 44fbac2288dfed6f1963ac00bf922c3bcd779cd1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:44 -0400 Subject: [PATCH 0163/1939] [PATCH] RPC: Add helper for waking tasks pending on a transport Clean-up: remove only reference to xprt->pending from the socket transport implementation. This makes a cleaner interface for other transport implementations as well. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:06:52 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/xprt.c | 18 ++++++++++++++++-- net/sunrpc/xprtsock.c | 7 ++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 009a3bb4f997..d5223993fca9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -232,6 +232,7 @@ void xprt_reserve(struct rpc_task *); int xprt_prepare_transmit(struct rpc_task *); void xprt_transmit(struct rpc_task *); void xprt_receive(struct rpc_task *); +void xprt_wake_pending_tasks(struct rpc_xprt *, int); int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release(struct rpc_task *); void xprt_connect(struct rpc_task *); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 57c5e77b155e..2f9cd468b953 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -227,6 +227,20 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) xprt->cwnd = cwnd; } +/** + * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue + * @xprt: transport with waiting tasks + * @status: result code to plant in each task before waking it + * + */ +void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status) +{ + if (status < 0) + rpc_wake_up_status(&xprt->pending, status); + else + rpc_wake_up(&xprt->pending); +} + static void xprt_reset_majortimeo(struct rpc_rqst *req) { struct rpc_timeout *to = &req->rq_xprt->timeout; @@ -300,7 +314,7 @@ void xprt_disconnect(struct rpc_xprt *xprt) dprintk("RPC: disconnected transport %p\n", xprt); spin_lock_bh(&xprt->transport_lock); xprt_clear_connected(xprt); - rpc_wake_up_status(&xprt->pending, -ENOTCONN); + xprt_wake_pending_tasks(xprt, -ENOTCONN); spin_unlock_bh(&xprt->transport_lock); } @@ -803,7 +817,7 @@ static void xprt_shutdown(struct rpc_xprt *xprt) xprt->shutdown = 1; rpc_wake_up(&xprt->sending); rpc_wake_up(&xprt->resend); - rpc_wake_up(&xprt->pending); + xprt_wake_pending_tasks(xprt, -EIO); rpc_wake_up(&xprt->backlog); wake_up(&xprt->cong_wait); del_timer_sync(&xprt->timer); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 76a33b54f436..182da2edf61c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -703,7 +703,7 @@ static void xs_tcp_state_change(struct sock *sk) xprt->tcp_reclen = 0; xprt->tcp_copied = 0; xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - rpc_wake_up(&xprt->pending); + xprt_wake_pending_tasks(xprt, 0); } spin_unlock_bh(&xprt->transport_lock); break; @@ -920,10 +920,7 @@ static void xs_connect_worker(void *args) } } out: - if (status < 0) - rpc_wake_up_status(&xprt->pending, status); - else - rpc_wake_up(&xprt->pending); + xprt_wake_pending_tasks(xprt, status); out_clear: xprt_clear_connecting(xprt); } From 55aa4f58aa43dc9a51fb80010630d94b96053a2e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:47 -0400 Subject: [PATCH 0164/1939] [PATCH] RPC: client-side transport switch cleanup Clean-up: change some comments to reflect the realities of the new RPC transport switch mechanism. Get rid of unused xprt_receive() prototype. Also, organize function prototypes in xprt.h by usage and scope. Test-plan: Compile kernel with CONFIG_NFS enabled. Version: Thu, 11 Aug 2005 16:07:21 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 61 +++++++++++++++++++++---------------- net/sunrpc/clnt.c | 2 +- net/sunrpc/xprt.c | 26 ++++++++-------- net/sunrpc/xprtsock.c | 12 +++++--- 4 files changed, 55 insertions(+), 46 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index d5223993fca9..bfbc492ae36d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/sunrpc/clnt_xprt.h + * linux/include/linux/sunrpc/xprt.h * * Declarations for the RPC transport interface. * @@ -150,8 +150,8 @@ struct rpc_xprt { unsigned long cong; /* current congestion */ unsigned long cwnd; /* congestion window */ - unsigned int rcvsize, /* socket receive buffer size */ - sndsize; /* socket send buffer size */ + unsigned int rcvsize, /* transport rcv buffer size */ + sndsize; /* transport send buffer size */ size_t max_payload; /* largest RPC payload size, in bytes */ @@ -184,12 +184,12 @@ struct rpc_xprt { unsigned long tcp_copied, /* copied to request */ tcp_flags; /* - * Connection of sockets + * Connection of transports */ - struct work_struct sock_connect; + struct work_struct connect_worker; unsigned short port; /* - * Disconnection of idle sockets + * Disconnection of idle transports */ struct work_struct task_cleanup; struct timer_list timer; @@ -219,27 +219,36 @@ struct rpc_xprt { #ifdef __KERNEL__ -struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, - struct rpc_timeout *toparms); -void xprt_disconnect(struct rpc_xprt *); -int xprt_destroy(struct rpc_xprt *); -void xprt_set_timeout(struct rpc_timeout *, unsigned int, - unsigned long); -struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *, u32); -void xprt_complete_rqst(struct rpc_xprt *, - struct rpc_rqst *, int); -void xprt_reserve(struct rpc_task *); -int xprt_prepare_transmit(struct rpc_task *); -void xprt_transmit(struct rpc_task *); -void xprt_receive(struct rpc_task *); -void xprt_wake_pending_tasks(struct rpc_xprt *, int); +/* + * Transport operations used by ULPs + */ +struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, struct rpc_timeout *to); +void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr); + +/* + * Generic internal transport functions + */ +void xprt_connect(struct rpc_task *task); +void xprt_reserve(struct rpc_task *task); +int xprt_prepare_transmit(struct rpc_task *task); +void xprt_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); -void xprt_release(struct rpc_task *); -void xprt_connect(struct rpc_task *); -int xs_setup_udp(struct rpc_xprt *, - struct rpc_timeout *); -int xs_setup_tcp(struct rpc_xprt *, - struct rpc_timeout *); +void xprt_release(struct rpc_task *task); +int xprt_destroy(struct rpc_xprt *xprt); + +/* + * Transport switch helper functions + */ +void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); +struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); +void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied); +void xprt_disconnect(struct rpc_xprt *xprt); + +/* + * Socket transport setup operations + */ +int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to); +int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to); /* * Reserved bit positions in xprt->state diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0d1b010a4a01..4677959d2834 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1,5 +1,5 @@ /* - * linux/net/sunrpc/rpcclnt.c + * linux/net/sunrpc/clnt.c * * This file contains the high-level RPC interface. * It is modeled as a finite state machine to support both synchronous diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 2f9cd468b953..247fa1ec870c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -10,12 +10,12 @@ * one is available. Otherwise, it sleeps on the backlog queue * (xprt_reserve). * - Next, the caller puts together the RPC message, stuffs it into - * the request struct, and calls xprt_call(). - * - xprt_call transmits the message and installs the caller on the - * socket's wait list. At the same time, it installs a timer that + * the request struct, and calls xprt_transmit(). + * - xprt_transmit sends the message and installs the caller on the + * transport's wait list. At the same time, it installs a timer that * is run after the packet's timeout has expired. * - When a packet arrives, the data_ready handler walks the list of - * pending requests for that socket. If a matching XID is found, the + * pending requests for that transport. If a matching XID is found, the * caller is woken up, and the timer removed. * - When no reply arrives within the timeout interval, the timer is * fired by the kernel and runs xprt_timer(). It either adjusts the @@ -32,6 +32,8 @@ * tasks that rely on callbacks. * * Copyright (C) 1995-1997, Olaf Kirch + * + * Transport switch API copyright (C) 2005, Chuck Lever */ #include @@ -52,8 +54,6 @@ # define RPCDBG_FACILITY RPCDBG_XPRT #endif -#define XPRT_MAX_BACKOFF (8) - /* * Local functions */ @@ -65,9 +65,9 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); static int xprt_clear_backlog(struct rpc_xprt *xprt); /* - * Serialize write access to sockets, in order to prevent different + * Serialize write access to transports, in order to prevent different * requests from interfering with each other. - * Also prevents TCP socket connects from colliding with writes. + * Also prevents transport connects from colliding with writes. */ static int __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) @@ -91,7 +91,7 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) clear_bit(XPRT_LOCKED, &xprt->state); smp_mb__after_clear_bit(); out_sleep: - dprintk("RPC: %4d failed to lock socket %p\n", task->tk_pid, xprt); + dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; if (req && req->rq_ntrans) @@ -144,7 +144,7 @@ __xprt_lock_write_next(struct rpc_xprt *xprt) } /* - * Releases the socket for use by other requests. + * Releases the transport for use by other requests. */ static void __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) @@ -294,8 +294,7 @@ int xprt_adjust_timeout(struct rpc_rqst *req) return status; } -static void -xprt_socket_autoclose(void *args) +static void xprt_autoclose(void *args) { struct rpc_xprt *xprt = (struct rpc_xprt *)args; @@ -329,7 +328,6 @@ xprt_init_autodisconnect(unsigned long data) if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) goto out_abort; spin_unlock(&xprt->transport_lock); - /* Let keventd close the socket */ if (xprt_connecting(xprt)) xprt_release_write(xprt, NULL); else @@ -770,7 +768,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); - INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt); + INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 182da2edf61c..7f0b9f7f167b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -11,6 +11,8 @@ * Rewrite of larges part of the code in order to stabilize TCP stuff. * Fix behaviour when socket buffer is full. * (C) 1999 Trond Myklebust + * + * IP socket transport implementation, (C) 2005 Chuck Lever */ #include @@ -363,7 +365,7 @@ static void xs_destroy(struct rpc_xprt *xprt) { dprintk("RPC: xs_destroy xprt %p\n", xprt); - cancel_delayed_work(&xprt->sock_connect); + cancel_delayed_work(&xprt->connect_worker); flush_scheduled_work(); xprt_disconnect(xprt); @@ -938,11 +940,11 @@ static void xs_connect(struct rpc_task *task) if (!xprt_test_and_set_connecting(xprt)) { if (xprt->sock != NULL) { dprintk("RPC: xs_connect delayed xprt %p\n", xprt); - schedule_delayed_work(&xprt->sock_connect, + schedule_delayed_work(&xprt->connect_worker, RPC_REESTABLISH_TIMEOUT); } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - schedule_work(&xprt->sock_connect); + schedule_work(&xprt->connect_worker); /* flush_scheduled_work can sleep... */ if (!RPC_IS_ASYNC(task)) flush_scheduled_work(); @@ -989,7 +991,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->sock_connect, xs_connect_worker, xprt); + INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); xprt->ops = &xs_ops; @@ -1028,7 +1030,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = (1U << 31) - 1; - INIT_WORK(&xprt->sock_connect, xs_connect_worker, xprt); + INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); xprt->ops = &xs_ops; From c7b2cae8a634015b72941ba2fc6c4bc9b8d3a129 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:50 -0400 Subject: [PATCH 0165/1939] [PATCH] RPC: separate TCP and UDP write space callbacks Split the socket write space callback function into a TCP version and UDP version, eliminating one dependence on the "xprt->stream" variable. Keep the common pieces of this path in xprt.c so other transports can use it too. Test-plan: Write-intensive workload on a single mount point. Version: Thu, 11 Aug 2005 16:07:51 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 + net/sunrpc/xprt.c | 34 +++++++++++++++ net/sunrpc/xprtsock.c | 84 +++++++++++++++++++++++-------------- 3 files changed, 89 insertions(+), 31 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index bfbc492ae36d..e73174c7e450 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -240,6 +240,8 @@ int xprt_destroy(struct rpc_xprt *xprt); * Transport switch helper functions */ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); +void xprt_wait_for_buffer_space(struct rpc_task *task); +void xprt_write_space(struct rpc_xprt *xprt); struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied); void xprt_disconnect(struct rpc_xprt *xprt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 247fa1ec870c..31ef7dc7eed6 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -241,6 +241,40 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status) rpc_wake_up(&xprt->pending); } +/** + * xprt_wait_for_buffer_space - wait for transport output buffer to clear + * @task: task to be put to sleep + * + */ +void xprt_wait_for_buffer_space(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + task->tk_timeout = req->rq_timeout; + rpc_sleep_on(&xprt->pending, task, NULL, NULL); +} + +/** + * xprt_write_space - wake the task waiting for transport output buffer space + * @xprt: transport with waiting tasks + * + * Can be called in a soft IRQ context, so xprt_write_space never sleeps. + */ +void xprt_write_space(struct rpc_xprt *xprt) +{ + if (unlikely(xprt->shutdown)) + return; + + spin_lock_bh(&xprt->transport_lock); + if (xprt->snd_task) { + dprintk("RPC: write space: waking waiting task on xprt %p\n", + xprt); + rpc_wake_up_task(xprt->snd_task); + } + spin_unlock_bh(&xprt->transport_lock); +} + static void xprt_reset_majortimeo(struct rpc_rqst *req) { struct rpc_timeout *to = &req->rq_xprt->timeout; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7f0b9f7f167b..70a772d7a796 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -308,15 +308,13 @@ static int xs_send_request(struct rpc_task *task) if (status == -EAGAIN) { if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { - /* Protect against races with xs_write_space */ + /* Protect against races with write_space */ spin_lock_bh(&xprt->transport_lock); /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; - else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { - task->tk_timeout = req->rq_timeout; - rpc_sleep_on(&xprt->pending, task, NULL, NULL); - } + else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) + xprt_wait_for_buffer_space(task); spin_unlock_bh(&xprt->transport_lock); return status; } @@ -721,45 +719,68 @@ static void xs_tcp_state_change(struct sock *sk) } /** - * xs_write_space - callback invoked when socket buffer space becomes - * available + * xs_udp_write_space - callback invoked when socket buffer space + * becomes available * @sk: socket whose state has changed * * Called when more output buffer space is available for this socket. * We try not to wake our writers until they can make "significant" - * progress, otherwise we'll waste resources thrashing sock_sendmsg + * progress, otherwise we'll waste resources thrashing kernel_sendmsg * with a bunch of small requests. */ -static void xs_write_space(struct sock *sk) +static void xs_udp_write_space(struct sock *sk) { - struct rpc_xprt *xprt; - struct socket *sock; - read_lock(&sk->sk_callback_lock); - if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) - goto out; - if (xprt->shutdown) - goto out; - /* Wait until we have enough socket memory */ - if (xprt->stream) { - /* from net/core/stream.c:sk_stream_write_space */ - if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk)) + /* from net/core/sock.c:sock_def_write_space */ + if (sock_writeable(sk)) { + struct socket *sock; + struct rpc_xprt *xprt; + + if (unlikely(!(sock = sk->sk_socket))) goto out; - } else { - /* from net/core/sock.c:sock_def_write_space */ - if (!sock_writeable(sk)) + if (unlikely(!(xprt = xprt_from_sock(sk)))) goto out; + if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) + goto out; + + xprt_write_space(xprt); } - if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) - goto out; + out: + read_unlock(&sk->sk_callback_lock); +} - spin_lock_bh(&xprt->transport_lock); - if (xprt->snd_task) - rpc_wake_up_task(xprt->snd_task); - spin_unlock_bh(&xprt->transport_lock); -out: +/** + * xs_tcp_write_space - callback invoked when socket buffer space + * becomes available + * @sk: socket whose state has changed + * + * Called when more output buffer space is available for this socket. + * We try not to wake our writers until they can make "significant" + * progress, otherwise we'll waste resources thrashing kernel_sendmsg + * with a bunch of small requests. + */ +static void xs_tcp_write_space(struct sock *sk) +{ + read_lock(&sk->sk_callback_lock); + + /* from net/core/stream.c:sk_stream_write_space */ + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { + struct socket *sock; + struct rpc_xprt *xprt; + + if (unlikely(!(sock = sk->sk_socket))) + goto out; + if (unlikely(!(xprt = xprt_from_sock(sk)))) + goto out; + if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) + goto out; + + xprt_write_space(xprt); + } + + out: read_unlock(&sk->sk_callback_lock); } @@ -855,15 +876,16 @@ static void xs_bind(struct rpc_xprt *xprt, struct socket *sock) xprt->old_write_space = sk->sk_write_space; if (xprt->prot == IPPROTO_UDP) { sk->sk_data_ready = xs_udp_data_ready; + sk->sk_write_space = xs_udp_write_space; sk->sk_no_check = UDP_CSUM_NORCV; xprt_set_connected(xprt); } else { tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ sk->sk_data_ready = xs_tcp_data_ready; sk->sk_state_change = xs_tcp_state_change; + sk->sk_write_space = xs_tcp_write_space; xprt_clear_connected(xprt); } - sk->sk_write_space = xs_write_space; /* Reset to new socket */ xprt->sock = sock; From b0d93ad511ce2f37823a07c7a3258117a431f5fb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:53 -0400 Subject: [PATCH 0166/1939] [PATCH] RPC: separate TCP and UDP transport connection logic Create separate connection worker functions for managing UDP and TCP transport sockets. This eliminates several dependencies on "xprt->stream". Test-plan: Destructive testing (unplugging the network temporarily). Connectathon with v2, v3, and v4. Version: Thu, 11 Aug 2005 16:08:18 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 198 +++++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 90 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 70a772d7a796..f91529787b9b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -836,102 +836,118 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) return err; } -static struct socket *xs_create(struct rpc_xprt *xprt, int proto, int resvport) -{ - struct socket *sock; - int type, err; - - dprintk("RPC: xs_create(%s %d)\n", - (proto == IPPROTO_UDP)? "udp" : "tcp", proto); - - type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; - - if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { - dprintk("RPC: can't create socket (%d).\n", -err); - return NULL; - } - - /* If the caller has the capability, bind to a reserved port */ - if (resvport && xs_bindresvport(xprt, sock) < 0) - goto failed; - - return sock; - -failed: - sock_release(sock); - return NULL; -} - -static void xs_bind(struct rpc_xprt *xprt, struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (xprt->inet) - return; - - write_lock_bh(&sk->sk_callback_lock); - sk->sk_user_data = xprt; - xprt->old_data_ready = sk->sk_data_ready; - xprt->old_state_change = sk->sk_state_change; - xprt->old_write_space = sk->sk_write_space; - if (xprt->prot == IPPROTO_UDP) { - sk->sk_data_ready = xs_udp_data_ready; - sk->sk_write_space = xs_udp_write_space; - sk->sk_no_check = UDP_CSUM_NORCV; - xprt_set_connected(xprt); - } else { - tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ - sk->sk_data_ready = xs_tcp_data_ready; - sk->sk_state_change = xs_tcp_state_change; - sk->sk_write_space = xs_tcp_write_space; - xprt_clear_connected(xprt); - } - - /* Reset to new socket */ - xprt->sock = sock; - xprt->inet = sk; - write_unlock_bh(&sk->sk_callback_lock); - - return; -} - /** - * xs_connect_worker - try to connect a socket to a remote endpoint + * xs_udp_connect_worker - set up a UDP socket * @args: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_connect_worker(void *args) +static void xs_udp_connect_worker(void *args) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = (struct rpc_xprt *) args; struct socket *sock = xprt->sock; - int status = -EIO; + int err, status = -EIO; if (xprt->shutdown || xprt->addr.sin_port == 0) goto out; - dprintk("RPC: xs_connect_worker xprt %p\n", xprt); + dprintk("RPC: xs_udp_connect_worker for xprt %p\n", xprt); - /* - * Start by resetting any existing state - */ + /* Start by resetting any existing state */ xs_close(xprt); - sock = xs_create(xprt, xprt->prot, xprt->resvport); - if (sock == NULL) { - /* couldn't create socket or bind to reserved port; - * this is likely a permanent error, so cause an abort */ + + if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { + dprintk("RPC: can't create UDP transport socket (%d).\n", -err); goto out; } - xs_bind(xprt, sock); - xs_set_buffer_size(xprt); + if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { + sock_release(sock); + goto out; + } + + if (!xprt->inet) { + struct sock *sk = sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + + sk->sk_user_data = xprt; + xprt->old_data_ready = sk->sk_data_ready; + xprt->old_state_change = sk->sk_state_change; + xprt->old_write_space = sk->sk_write_space; + sk->sk_data_ready = xs_udp_data_ready; + sk->sk_write_space = xs_udp_write_space; + sk->sk_no_check = UDP_CSUM_NORCV; + + xprt_set_connected(xprt); + + /* Reset to new socket */ + xprt->sock = sock; + xprt->inet = sk; + + write_unlock_bh(&sk->sk_callback_lock); + } + xs_set_buffer_size(xprt); status = 0; - if (!xprt->stream) +out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); +} + +/** + * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint + * @args: RPC transport to connect + * + * Invoked by a work queue tasklet. + */ +static void xs_tcp_connect_worker(void *args) +{ + struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct socket *sock = xprt->sock; + int err, status = -EIO; + + if (xprt->shutdown || xprt->addr.sin_port == 0) goto out; - /* - * Tell the socket layer to start connecting... - */ + dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt); + + /* Start by resetting any existing socket state */ + xs_close(xprt); + + if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { + dprintk("RPC: can't create TCP transport socket (%d).\n", -err); + goto out; + } + + if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { + sock_release(sock); + goto out; + } + + if (!xprt->inet) { + struct sock *sk = sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + + sk->sk_user_data = xprt; + xprt->old_data_ready = sk->sk_data_ready; + xprt->old_state_change = sk->sk_state_change; + xprt->old_write_space = sk->sk_write_space; + sk->sk_data_ready = xs_tcp_data_ready; + sk->sk_state_change = xs_tcp_state_change; + sk->sk_write_space = xs_tcp_write_space; + tcp_sk(sk)->nonagle = 1; + + xprt_clear_connected(xprt); + + /* Reset to new socket */ + xprt->sock = sock; + xprt->inet = sk; + + write_unlock_bh(&sk->sk_callback_lock); + } + + /* Tell the socket layer to start connecting... */ status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, sizeof(xprt->addr), O_NONBLOCK); dprintk("RPC: %p connect status %d connected %d sock state %d\n", @@ -959,18 +975,20 @@ static void xs_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - if (!xprt_test_and_set_connecting(xprt)) { - if (xprt->sock != NULL) { - dprintk("RPC: xs_connect delayed xprt %p\n", xprt); - schedule_delayed_work(&xprt->connect_worker, + if (xprt_test_and_set_connecting(xprt)) + return; + + if (xprt->sock != NULL) { + dprintk("RPC: xs_connect delayed xprt %p\n", xprt); + schedule_delayed_work(&xprt->connect_worker, RPC_REESTABLISH_TIMEOUT); - } else { - dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - schedule_work(&xprt->connect_worker); - /* flush_scheduled_work can sleep... */ - if (!RPC_IS_ASYNC(task)) - flush_scheduled_work(); - } + } else { + dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); + schedule_work(&xprt->connect_worker); + + /* flush_scheduled_work can sleep... */ + if (!RPC_IS_ASYNC(task)) + flush_scheduled_work(); } } @@ -1013,7 +1031,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); + INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); xprt->ops = &xs_ops; @@ -1052,7 +1070,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = (1U << 31) - 1; - INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); + INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); xprt->ops = &xs_ops; From 262965f53defd312a294b45366ea17907b6a616b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 Aug 2005 16:25:56 -0400 Subject: [PATCH 0167/1939] [PATCH] RPC: separate TCP and UDP socket write paths Split the RPC client's main socket write path into a TCP version and a UDP version to eliminate another dependency on the "xprt->stream" variable. Compiler optimization removes unneeded code from xs_sendpages, as this function is now called with some constant arguments. We can now cleanly perform transport protocol-specific return code testing and error recovery in each path. Test-plan: Millions of fsx operations. Performance characterization such as "sio" or "iozone". Examine oprofile results for any changes before and after this patch is applied. Version: Thu, 11 Aug 2005 16:08:46 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 215 +++++++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 87 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index f91529787b9b..57988300640a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -40,6 +40,12 @@ */ #define XS_MAX_RESVPORT (800U) +/* + * How many times to try sending a request on a socket before waiting + * for the socket buffer to clear. + */ +#define XS_SENDMSG_RETRY (10U) + #ifdef RPC_DEBUG # undef RPC_DEBUG_DATA # define RPCDBG_FACILITY RPCDBG_TRANS @@ -114,13 +120,18 @@ static int xs_send_tail(struct socket *sock, struct xdr_buf *xdr, unsigned int b * @base: starting position in the buffer * */ -static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) +static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; int err, ret = 0; ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); + if (unlikely(!sock)) + return -ENOTCONN; + + clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); + len = xdr->head[0].iov_len; if (base < len || (addr != NULL && base == 0)) { err = xs_send_head(sock, addr, addrlen, xdr, base, len); @@ -187,140 +198,162 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, } /** - * xs_sendmsg - write an RPC request to a socket - * @xprt: generic transport - * @req: the RPC request to write + * xs_nospace - place task on wait queue if transmit was incomplete + * @task: task to put to sleep * */ -static int xs_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) +static void xs_nospace(struct rpc_task *task) { - struct socket *sock = xprt->sock; - struct xdr_buf *xdr = &req->rq_snd_buf; - struct sockaddr *addr = NULL; - int addrlen = 0; - unsigned int skip; - int result; + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; - if (!sock) - return -ENOTCONN; + dprintk("RPC: %4d xmit incomplete (%u left of %u)\n", + task->tk_pid, req->rq_slen - req->rq_bytes_sent, + req->rq_slen); + + if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { + /* Protect against races with write_space */ + spin_lock_bh(&xprt->transport_lock); + + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) + xprt_wait_for_buffer_space(task); + + spin_unlock_bh(&xprt->transport_lock); + } else + /* Keep holding the socket if it is blocked */ + rpc_delay(task, HZ>>4); +} + +/** + * xs_udp_send_request - write an RPC request to a UDP socket + * @task: address of RPC task that manages the state of an RPC request + * + * Return values: + * 0: The request has been sent + * EAGAIN: The socket was blocked, please call again later to + * complete the request + * ENOTCONN: Caller needs to invoke connect logic then call again + * other: Some other error occured, the request was not sent + */ +static int xs_udp_send_request(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + struct xdr_buf *xdr = &req->rq_snd_buf; + int status; xs_pktdump("packet data:", req->rq_svec->iov_base, req->rq_svec->iov_len); - /* For UDP, we need to provide an address */ - if (!xprt->stream) { - addr = (struct sockaddr *) &xprt->addr; - addrlen = sizeof(xprt->addr); - } - /* Don't repeat bytes */ - skip = req->rq_bytes_sent; + req->rq_xtime = jiffies; + status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr, + sizeof(xprt->addr), xdr, req->rq_bytes_sent); - clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); - result = xs_sendpages(sock, addr, addrlen, xdr, skip); + dprintk("RPC: xs_udp_send_request(%u) = %d\n", + xdr->len - req->rq_bytes_sent, status); - dprintk("RPC: xs_sendmsg(%d) = %d\n", xdr->len - skip, result); + if (likely(status >= (int) req->rq_slen)) + return 0; - if (result >= 0) - return result; + /* Still some bytes left; set up for a retry later. */ + if (status > 0) + status = -EAGAIN; - switch (result) { + switch (status) { + case -ENETUNREACH: + case -EPIPE: case -ECONNREFUSED: /* When the server has died, an ICMP port unreachable message * prompts ECONNREFUSED. */ - case -EAGAIN: break; - case -ECONNRESET: - case -ENOTCONN: - case -EPIPE: - /* connection broken */ - if (xprt->stream) - result = -ENOTCONN; + case -EAGAIN: + xs_nospace(task); break; default: + dprintk("RPC: sendmsg returned unrecognized error %d\n", + -status); break; } - return result; + + return status; } /** - * xs_send_request - write an RPC request to a socket + * xs_tcp_send_request - write an RPC request to a TCP socket * @task: address of RPC task that manages the state of an RPC request * * Return values: - * 0: The request has been sent - * EAGAIN: The socket was blocked, please call again later to - * complete the request - * other: Some other error occured, the request was not sent + * 0: The request has been sent + * EAGAIN: The socket was blocked, please call again later to + * complete the request + * ENOTCONN: Caller needs to invoke connect logic then call again + * other: Some other error occured, the request was not sent * * XXX: In the case of soft timeouts, should we eventually give up - * if the socket is not able to make progress? + * if sendmsg is not able to make progress? */ -static int xs_send_request(struct rpc_task *task) +static int xs_tcp_send_request(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + struct xdr_buf *xdr = &req->rq_snd_buf; + u32 *marker = req->rq_svec[0].iov_base; int status, retry = 0; - /* set up everything as needed. */ /* Write the record marker */ - if (xprt->stream) { - u32 *marker = req->rq_svec[0].iov_base; + *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); - *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); - } + xs_pktdump("packet data:", + req->rq_svec->iov_base, + req->rq_svec->iov_len); /* Continue transmitting the packet/record. We must be careful * to cope with writespace callbacks arriving _after_ we have - * called sendmsg(). - */ + * called sendmsg(). */ while (1) { req->rq_xtime = jiffies; - status = xs_sendmsg(xprt, req); + status = xs_sendpages(xprt->sock, NULL, 0, xdr, + req->rq_bytes_sent); - if (status < 0) + dprintk("RPC: xs_tcp_send_request(%u) = %d\n", + xdr->len - req->rq_bytes_sent, status); + + if (unlikely(status < 0)) break; - if (xprt->stream) { - req->rq_bytes_sent += status; - - /* If we've sent the entire packet, immediately - * reset the count of bytes sent. */ - if (req->rq_bytes_sent >= req->rq_slen) { - req->rq_bytes_sent = 0; - return 0; - } - } else { - if (status >= req->rq_slen) - return 0; - status = -EAGAIN; - break; + /* If we've sent the entire packet, immediately + * reset the count of bytes sent. */ + req->rq_bytes_sent += status; + if (likely(req->rq_bytes_sent >= req->rq_slen)) { + req->rq_bytes_sent = 0; + return 0; } - dprintk("RPC: %4d xmit incomplete (%d left of %d)\n", - task->tk_pid, req->rq_slen - req->rq_bytes_sent, - req->rq_slen); - status = -EAGAIN; - if (retry++ > 50) + if (retry++ > XS_SENDMSG_RETRY) break; } - if (status == -EAGAIN) { - if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { - /* Protect against races with write_space */ - spin_lock_bh(&xprt->transport_lock); - /* Don't race with disconnect */ - if (!xprt_connected(xprt)) - task->tk_status = -ENOTCONN; - else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) - xprt_wait_for_buffer_space(task); - spin_unlock_bh(&xprt->transport_lock); - return status; - } - /* Keep holding the socket if it is blocked */ - rpc_delay(task, HZ>>4); + switch (status) { + case -EAGAIN: + xs_nospace(task); + break; + case -ECONNREFUSED: + case -ECONNRESET: + case -ENOTCONN: + case -EPIPE: + status = -ENOTCONN; + break; + default: + dprintk("RPC: sendmsg returned unrecognized error %d\n", + -status); + break; } + return status; } @@ -992,10 +1025,18 @@ static void xs_connect(struct rpc_task *task) } } -static struct rpc_xprt_ops xs_ops = { +static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_set_buffer_size, .connect = xs_connect, - .send_request = xs_send_request, + .send_request = xs_udp_send_request, + .close = xs_close, + .destroy = xs_destroy, +}; + +static struct rpc_xprt_ops xs_tcp_ops = { + .set_buffer_size = xs_set_buffer_size, + .connect = xs_connect, + .send_request = xs_tcp_send_request, .close = xs_close, .destroy = xs_destroy, }; @@ -1033,7 +1074,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); - xprt->ops = &xs_ops; + xprt->ops = &xs_udp_ops; if (to) xprt->timeout = *to; @@ -1072,7 +1113,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); - xprt->ops = &xs_ops; + xprt->ops = &xs_tcp_ops; if (to) xprt->timeout = *to; From 808012fbb23a52ec59352445d2076d175ad4ab26 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:49 -0700 Subject: [PATCH 0168/1939] [PATCH] RPC: skip over transport-specific heads automatically Add a generic mechanism for skipping over transport-specific headers when constructing an RPC request. This removes another "xprt->stream" dependency. Test-plan: Write-intensive workload on a single mount point (try both UDP and TCP). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/msg_prot.h | 25 +++++++++++++++++++++++++ include/linux/sunrpc/xprt.h | 7 +++++++ net/sunrpc/auth_gss/auth_gss.c | 6 ++---- net/sunrpc/clnt.c | 5 ++--- net/sunrpc/xprtsock.c | 24 +++++++++++++++++------- 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 15f115332389..f43f237360ae 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -76,5 +76,30 @@ enum rpc_auth_stat { #define RPC_MAXNETNAMELEN 256 +/* + * From RFC 1831: + * + * "A record is composed of one or more record fragments. A record + * fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of + * fragment data. The bytes encode an unsigned binary number; as with + * XDR integers, the byte order is from highest to lowest. The number + * encodes two values -- a boolean which indicates whether the fragment + * is the last fragment of the record (bit value 1 implies the fragment + * is the last fragment) and a 31-bit unsigned binary value which is the + * length in bytes of the fragment's data. The boolean value is the + * highest-order bit of the header; the length is the 31 low-order bits. + * (Note that this record specification is NOT in XDR standard form!)" + * + * The Linux RPC client always sends its requests in a single record + * fragment, limiting the maximum payload size for stream transports to + * 2GB. + */ + +typedef u32 rpc_fraghdr; + +#define RPC_LAST_STREAM_FRAGMENT (1U << 31) +#define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT) +#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1) + #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index e73174c7e450..966c456a0f6d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -155,6 +155,8 @@ struct rpc_xprt { size_t max_payload; /* largest RPC payload size, in bytes */ + unsigned int tsh_size; /* size of transport specific + header */ struct rpc_wait_queue sending; /* requests waiting to send */ struct rpc_wait_queue resend; /* requests waiting to resend */ @@ -236,6 +238,11 @@ int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release(struct rpc_task *task); int xprt_destroy(struct rpc_xprt *xprt); +static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p) +{ + return p + xprt->tsh_size; +} + /* * Transport switch helper functions */ diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 53a030acdf75..d2b08f16c257 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -844,10 +844,8 @@ gss_marshal(struct rpc_task *task, u32 *p) /* We compute the checksum for the verifier over the xdr-encoded bytes * starting with the xid and ending at the end of the credential: */ - iov.iov_base = req->rq_snd_buf.head[0].iov_base; - if (task->tk_client->cl_xprt->stream) - /* See clnt.c:call_header() */ - iov.iov_base += 4; + iov.iov_base = xprt_skip_transport_header(task->tk_xprt, + req->rq_snd_buf.head[0].iov_base); iov.iov_len = (u8 *)p - (u8 *)iov.iov_base; xdr_buf_from_iov(&iov, &verf_buf); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4677959d2834..cc1b773a79d3 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1075,13 +1075,12 @@ static u32 * call_header(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_rqst *req = task->tk_rqstp; u32 *p = req->rq_svec[0].iov_base; /* FIXME: check buffer size? */ - if (xprt->stream) - *p++ = 0; /* fill in later */ + + p = xprt_skip_transport_header(task->tk_xprt, p); *p++ = req->rq_xid; /* XID */ *p++ = htonl(RPC_CALL); /* CALL */ *p++ = htonl(RPC_VERSION); /* RPC version */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 57988300640a..aaf053b1a0c4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -282,6 +282,13 @@ static int xs_udp_send_request(struct rpc_task *task) return status; } +static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf) +{ + u32 reclen = buf->len - sizeof(rpc_fraghdr); + rpc_fraghdr *base = buf->head[0].iov_base; + *base = htonl(RPC_LAST_STREAM_FRAGMENT | reclen); +} + /** * xs_tcp_send_request - write an RPC request to a TCP socket * @task: address of RPC task that manages the state of an RPC request @@ -301,11 +308,9 @@ static int xs_tcp_send_request(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct xdr_buf *xdr = &req->rq_snd_buf; - u32 *marker = req->rq_svec[0].iov_base; int status, retry = 0; - /* Write the record marker */ - *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); + xs_encode_tcp_record_marker(&req->rq_snd_buf); xs_pktdump("packet data:", req->rq_svec->iov_base, @@ -503,16 +508,19 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc xprt->tcp_offset += used; if (used != len) return; + xprt->tcp_reclen = ntohl(xprt->tcp_recm); - if (xprt->tcp_reclen & 0x80000000) + if (xprt->tcp_reclen & RPC_LAST_STREAM_FRAGMENT) xprt->tcp_flags |= XPRT_LAST_FRAG; else xprt->tcp_flags &= ~XPRT_LAST_FRAG; - xprt->tcp_reclen &= 0x7fffffff; + xprt->tcp_reclen &= RPC_FRAGMENT_SIZE_MASK; + xprt->tcp_flags &= ~XPRT_COPY_RECM; xprt->tcp_offset = 0; + /* Sanity check of the record length */ - if (xprt->tcp_reclen < 4) { + if (unlikely(xprt->tcp_reclen < 4)) { dprintk("RPC: invalid TCP record fragment length\n"); xprt_disconnect(xprt); return; @@ -1065,6 +1073,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_UDP; xprt->port = XS_MAX_RESVPORT; + xprt->tsh_size = 0; xprt->stream = 0; xprt->nocong = 0; xprt->cwnd = RPC_INITCWND; @@ -1105,11 +1114,12 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_TCP; xprt->port = XS_MAX_RESVPORT; + xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->stream = 1; xprt->nocong = 1; xprt->cwnd = RPC_MAXCWND(xprt); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; - xprt->max_payload = (1U << 31) - 1; + xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); From 43118c29dea2b23798bd42a147015cceee7fa885 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:49 -0700 Subject: [PATCH 0169/1939] [PATCH] RPC: get rid of xprt->stream Now we can fix up the last few places that use the "xprt->stream" variable, and get rid of it from the rpc_xprt structure. Test-plan: Destructive testing (unplugging the network temporarily). Connectathon with UDP and TCP. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/lockd/host.c | 3 +-- include/linux/sunrpc/xprt.h | 3 +-- net/sunrpc/xprt.c | 3 +-- net/sunrpc/xprtsock.c | 28 ++++++++++++++++++---------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 82c77df81c5f..7901f5b8092c 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -173,11 +173,10 @@ nlm_bind_host(struct nlm_host *host) /* If we've already created an RPC client, check whether * RPC rebind is required - * Note: why keep rebinding if we're on a tcp connection? */ if ((clnt = host->h_rpcclnt) != NULL) { xprt = clnt->cl_xprt; - if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) { + if (time_after_eq(jiffies, host->h_nextrebind)) { clnt->cl_port = 0; host->h_nextrebind = jiffies + NLM_HOST_REBIND; dprintk("lockd: next rebind in %ld jiffies\n", diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 966c456a0f6d..c9477f022efb 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -168,8 +168,7 @@ struct rpc_xprt { unsigned long state; /* transport state */ unsigned char shutdown : 1, /* being shut down */ nocong : 1, /* no congestion control */ - resvport : 1, /* use a reserved port */ - stream : 1; /* TCP */ + resvport : 1; /* use a reserved port */ /* * XID diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 31ef7dc7eed6..43fef7626442 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -630,8 +630,7 @@ void xprt_transmit(struct rpc_task *task) case -ENOTCONN: return; default: - if (xprt->stream) - xprt_disconnect(xprt); + break; } xprt_release_write(xprt, task); return; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index aaf053b1a0c4..5bb6fed3df34 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -356,6 +356,7 @@ static int xs_tcp_send_request(struct rpc_task *task) default: dprintk("RPC: sendmsg returned unrecognized error %d\n", -status); + xprt_disconnect(xprt); break; } @@ -826,19 +827,17 @@ static void xs_tcp_write_space(struct sock *sk) } /** - * xs_set_buffer_size - set send and receive limits + * xs_udp_set_buffer_size - set send and receive limits * @xprt: generic transport * * Set socket send and receive limits based on the * sndsize and rcvsize fields in the generic transport - * structure. This applies only to UDP sockets. + * structure. */ -static void xs_set_buffer_size(struct rpc_xprt *xprt) +static void xs_udp_set_buffer_size(struct rpc_xprt *xprt) { struct sock *sk = xprt->inet; - if (xprt->stream) - return; if (xprt->rcvsize) { sk->sk_userlocks |= SOCK_RCVBUF_LOCK; sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs * 2; @@ -850,6 +849,17 @@ static void xs_set_buffer_size(struct rpc_xprt *xprt) } } +/** + * xs_tcp_set_buffer_size - set send and receive limits + * @xprt: generic transport + * + * Nothing to do for TCP. + */ +static void xs_tcp_set_buffer_size(struct rpc_xprt *xprt) +{ + return; +} + static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) { struct sockaddr_in myaddr = { @@ -928,7 +938,7 @@ static void xs_udp_connect_worker(void *args) write_unlock_bh(&sk->sk_callback_lock); } - xs_set_buffer_size(xprt); + xs_udp_set_buffer_size(xprt); status = 0; out: xprt_wake_pending_tasks(xprt, status); @@ -1034,7 +1044,7 @@ static void xs_connect(struct rpc_task *task) } static struct rpc_xprt_ops xs_udp_ops = { - .set_buffer_size = xs_set_buffer_size, + .set_buffer_size = xs_udp_set_buffer_size, .connect = xs_connect, .send_request = xs_udp_send_request, .close = xs_close, @@ -1042,7 +1052,7 @@ static struct rpc_xprt_ops xs_udp_ops = { }; static struct rpc_xprt_ops xs_tcp_ops = { - .set_buffer_size = xs_set_buffer_size, + .set_buffer_size = xs_tcp_set_buffer_size, .connect = xs_connect, .send_request = xs_tcp_send_request, .close = xs_close, @@ -1074,7 +1084,6 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_UDP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = 0; - xprt->stream = 0; xprt->nocong = 0; xprt->cwnd = RPC_INITCWND; xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; @@ -1115,7 +1124,6 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_TCP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); - xprt->stream = 1; xprt->nocong = 1; xprt->cwnd = RPC_MAXCWND(xprt); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; From fe3aca290f17ae4978bd73d02aa4029f1c9c024c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:50 -0700 Subject: [PATCH 0170/1939] [PATCH] RPC: add API to set transport-specific timeouts Prepare the way to remove the "xprt->nocong" variable by adding a callout to the RPC client transport switch API to handle setting RPC retransmit timeouts. Add a pair of generic helper functions that provide the ability to set a simple fixed timeout, or to set a timeout based on the state of a round- trip estimator. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 ++ net/sunrpc/xprt.c | 67 +++++++++++++++++++++++++------------ net/sunrpc/xprtsock.c | 2 ++ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index c9477f022efb..ac08e99a81cb 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -134,6 +134,7 @@ struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt); void (*connect)(struct rpc_task *task); int (*send_request)(struct rpc_task *task); + void (*set_retrans_timeout)(struct rpc_task *task); void (*close)(struct rpc_xprt *xprt); void (*destroy)(struct rpc_xprt *xprt); }; @@ -245,6 +246,8 @@ static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p) /* * Transport switch helper functions */ +void xprt_set_retrans_timeout_def(struct rpc_task *task); +void xprt_set_retrans_timeout_rtt(struct rpc_task *task); void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); void xprt_wait_for_buffer_space(struct rpc_task *task); void xprt_write_space(struct rpc_xprt *xprt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 43fef7626442..1ac2fbe05102 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -275,6 +275,38 @@ void xprt_write_space(struct rpc_xprt *xprt) spin_unlock_bh(&xprt->transport_lock); } +/** + * xprt_set_retrans_timeout_def - set a request's retransmit timeout + * @task: task whose timeout is to be set + * + * Set a request's retransmit timeout based on the transport's + * default timeout parameters. Used by transports that don't adjust + * the retransmit timeout based on round-trip time estimation. + */ +void xprt_set_retrans_timeout_def(struct rpc_task *task) +{ + task->tk_timeout = task->tk_rqstp->rq_timeout; +} + +/* + * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout + * @task: task whose timeout is to be set + * + * Set a request's retransmit timeout using the RTT estimator. + */ +void xprt_set_retrans_timeout_rtt(struct rpc_task *task) +{ + int timer = task->tk_msg.rpc_proc->p_timer; + struct rpc_rtt *rtt = task->tk_client->cl_rtt; + struct rpc_rqst *req = task->tk_rqstp; + unsigned long max_timeout = req->rq_xprt->timeout.to_maxval; + + task->tk_timeout = rpc_calc_rto(rtt, timer); + task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries; + if (task->tk_timeout > max_timeout || task->tk_timeout == 0) + task->tk_timeout = max_timeout; +} + static void xprt_reset_majortimeo(struct rpc_rqst *req) { struct rpc_timeout *to = &req->rq_xprt->timeout; @@ -588,7 +620,6 @@ int xprt_prepare_transmit(struct rpc_task *task) */ void xprt_transmit(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; int status; @@ -613,8 +644,19 @@ void xprt_transmit(struct rpc_task *task) return; status = xprt->ops->send_request(task); - if (!status) - goto out_receive; + if (status == 0) { + dprintk("RPC: %4d xmit complete\n", task->tk_pid); + spin_lock_bh(&xprt->transport_lock); + xprt->ops->set_retrans_timeout(task); + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (!req->rq_received) + rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); + __xprt_release_write(xprt, task); + spin_unlock_bh(&xprt->transport_lock); + return; + } /* Note: at this point, task->tk_sleeping has not yet been set, * hence there is no danger of the waking up task being put on @@ -634,25 +676,6 @@ void xprt_transmit(struct rpc_task *task) } xprt_release_write(xprt, task); return; - out_receive: - dprintk("RPC: %4d xmit complete\n", task->tk_pid); - /* Set the task's receive timeout value */ - spin_lock_bh(&xprt->transport_lock); - if (!xprt->nocong) { - int timer = task->tk_msg.rpc_proc->p_timer; - task->tk_timeout = rpc_calc_rto(clnt->cl_rtt, timer); - task->tk_timeout <<= rpc_ntimeo(clnt->cl_rtt, timer) + req->rq_retries; - if (task->tk_timeout > xprt->timeout.to_maxval || task->tk_timeout == 0) - task->tk_timeout = xprt->timeout.to_maxval; - } else - task->tk_timeout = req->rq_timeout; - /* Don't race with disconnect */ - if (!xprt_connected(xprt)) - task->tk_status = -ENOTCONN; - else if (!req->rq_received) - rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); - __xprt_release_write(xprt, task); - spin_unlock_bh(&xprt->transport_lock); } static inline void do_xprt_reserve(struct rpc_task *task) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 5bb6fed3df34..79433ffd1df0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1047,6 +1047,7 @@ static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, .connect = xs_connect, .send_request = xs_udp_send_request, + .set_retrans_timeout = xprt_set_retrans_timeout_rtt, .close = xs_close, .destroy = xs_destroy, }; @@ -1055,6 +1056,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { .set_buffer_size = xs_tcp_set_buffer_size, .connect = xs_connect, .send_request = xs_tcp_send_request, + .set_retrans_timeout = xprt_set_retrans_timeout_def, .close = xs_close, .destroy = xs_destroy, }; From 12a804698b29d040b7cdd92e8a44b0e75164dae9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:51 -0700 Subject: [PATCH 0171/1939] [PATCH] RPC: expose API for serializing access to RPC transports The next several patches introduce an API that allows transports to choose whether the RPC client provides congestion control or whether the transport itself provides it. The first method we abstract is the one that serializes access to the RPC transport to prevent the bytes from different requests from mingling together. This method provides proper request serialization and the opportunity to prevent new requests from being started because the transport is congested. The normal situation is for the transport to handle congestion control itself. Although NFS over UDP was first, it has been recognized after years of experience that having the transport provide congestion control is much better than doing it in the RPC client. Thus TCP, and probably every future transport implementation, will use the default method, xprt_lock_write, provided in xprt.c, which does not provide any kind of congestion control. UDP can continue using the xprt.c-provided Van Jacobson congestion avoidance implementation. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 ++ net/sunrpc/xprt.c | 66 +++++++++++++++++++++++++++++-------- net/sunrpc/xprtsock.c | 2 ++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index ac08e99a81cb..eee1c6877851 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -132,6 +132,7 @@ struct rpc_xprt; struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt); + int (*reserve_xprt)(struct rpc_task *task); void (*connect)(struct rpc_task *task); int (*send_request)(struct rpc_task *task); void (*set_retrans_timeout)(struct rpc_task *task); @@ -232,6 +233,8 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long */ void xprt_connect(struct rpc_task *task); void xprt_reserve(struct rpc_task *task); +int xprt_reserve_xprt(struct rpc_task *task); +int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1ac2fbe05102..2d1e8b83dd68 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -64,14 +64,56 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); static int xprt_clear_backlog(struct rpc_xprt *xprt); -/* - * Serialize write access to transports, in order to prevent different - * requests from interfering with each other. - * Also prevents transport connects from colliding with writes. +/** + * xprt_reserve_xprt - serialize write access to transports + * @task: task that is requesting access to the transport + * + * This prevents mixing the payload of separate requests, and prevents + * transport connects from colliding with writes. No congestion control + * is provided. */ -static int -__xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) +int xprt_reserve_xprt(struct rpc_task *task) { + struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_rqst *req = task->tk_rqstp; + + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { + if (task == xprt->snd_task) + return 1; + if (task == NULL) + return 0; + goto out_sleep; + } + xprt->snd_task = task; + if (req) { + req->rq_bytes_sent = 0; + req->rq_ntrans++; + } + return 1; + +out_sleep: + dprintk("RPC: %4d failed to lock transport %p\n", + task->tk_pid, xprt); + task->tk_timeout = 0; + task->tk_status = -EAGAIN; + if (req && req->rq_ntrans) + rpc_sleep_on(&xprt->resend, task, NULL, NULL); + else + rpc_sleep_on(&xprt->sending, task, NULL, NULL); + return 0; +} + +/* + * xprt_reserve_xprt_cong - serialize write access to transports + * @task: task that is requesting access to the transport + * + * Same as xprt_reserve_xprt, but Van Jacobson congestion control is + * integrated into the decision of whether a request is allowed to be + * woken up and given access to the transport. + */ +int xprt_reserve_xprt_cong(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req = task->tk_rqstp; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { @@ -79,7 +121,7 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) return 1; goto out_sleep; } - if (xprt->nocong || __xprt_get_cong(xprt, task)) { + if (__xprt_get_cong(xprt, task)) { xprt->snd_task = task; if (req) { req->rq_bytes_sent = 0; @@ -101,20 +143,18 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) return 0; } -static inline int -xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) +static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { int retval; spin_lock_bh(&xprt->transport_lock); - retval = __xprt_lock_write(xprt, task); + retval = xprt->ops->reserve_xprt(task); spin_unlock_bh(&xprt->transport_lock); return retval; } -static void -__xprt_lock_write_next(struct rpc_xprt *xprt) +static void __xprt_lock_write_next(struct rpc_xprt *xprt) { struct rpc_task *task; @@ -598,7 +638,7 @@ int xprt_prepare_transmit(struct rpc_task *task) err = req->rq_received; goto out_unlock; } - if (!__xprt_lock_write(xprt, task)) { + if (!xprt->ops->reserve_xprt(task)) { err = -EAGAIN; goto out_unlock; } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 79433ffd1df0..fc4fbe8ea346 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1045,6 +1045,7 @@ static void xs_connect(struct rpc_task *task) static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, + .reserve_xprt = xprt_reserve_xprt_cong, .connect = xs_connect, .send_request = xs_udp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_rtt, @@ -1054,6 +1055,7 @@ static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_tcp_ops = { .set_buffer_size = xs_tcp_set_buffer_size, + .reserve_xprt = xprt_reserve_xprt, .connect = xs_connect, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, From 49e9a89086b3cae784a4868ca852863e4f4ea3fe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:51 -0700 Subject: [PATCH 0172/1939] [PATCH] RPC: expose API for serializing access to RPC transports The next method we abstract is the one that releases a transport, allowing another task to have access to the transport. Again, one generic version of this is provided for transports that don't need the RPC client to perform congestion control, and one version is for transports that can use the original Van Jacobson implementation in xprt.c. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 ++ net/sunrpc/xprt.c | 77 ++++++++++++++++++++++++++++++------- net/sunrpc/xprtsock.c | 2 + 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index eee1c6877851..86833b725bb5 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -133,6 +133,7 @@ struct rpc_xprt; struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt); int (*reserve_xprt)(struct rpc_task *task); + void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); void (*connect)(struct rpc_task *task); int (*send_request)(struct rpc_task *task); void (*set_retrans_timeout)(struct rpc_task *task); @@ -238,6 +239,8 @@ int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); +void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); +void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release(struct rpc_task *task); int xprt_destroy(struct rpc_xprt *xprt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 2d1e8b83dd68..e92ea99dd318 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -153,14 +153,42 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) return retval; } - static void __xprt_lock_write_next(struct rpc_xprt *xprt) +{ + struct rpc_task *task; + struct rpc_rqst *req; + + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) + return; + + task = rpc_wake_up_next(&xprt->resend); + if (!task) { + task = rpc_wake_up_next(&xprt->sending); + if (!task) + goto out_unlock; + } + + req = task->tk_rqstp; + xprt->snd_task = task; + if (req) { + req->rq_bytes_sent = 0; + req->rq_ntrans++; + } + return; + +out_unlock: + smp_mb__before_clear_bit(); + clear_bit(XPRT_LOCKED, &xprt->state); + smp_mb__after_clear_bit(); +} + +static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) { struct rpc_task *task; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; - if (!xprt->nocong && RPCXPRT_CONGESTED(xprt)) + if (RPCXPRT_CONGESTED(xprt)) goto out_unlock; task = rpc_wake_up_next(&xprt->resend); if (!task) { @@ -168,7 +196,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) if (!task) goto out_unlock; } - if (xprt->nocong || __xprt_get_cong(xprt, task)) { + if (__xprt_get_cong(xprt, task)) { struct rpc_rqst *req = task->tk_rqstp; xprt->snd_task = task; if (req) { @@ -183,11 +211,14 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) smp_mb__after_clear_bit(); } -/* - * Releases the transport for use by other requests. +/** + * xprt_release_xprt - allow other requests to use a transport + * @xprt: transport with other tasks potentially waiting + * @task: task that is releasing access to the transport + * + * Note that "task" can be NULL. No congestion control is provided. */ -static void -__xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) +void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) { if (xprt->snd_task == task) { xprt->snd_task = NULL; @@ -198,11 +229,29 @@ __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) } } -static inline void -xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) +/** + * xprt_release_xprt_cong - allow other requests to use a transport + * @xprt: transport with other tasks potentially waiting + * @task: task that is releasing access to the transport + * + * Note that "task" can be NULL. Another task is awoken to use the + * transport if the transport's congestion window allows it. + */ +void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) +{ + if (xprt->snd_task == task) { + xprt->snd_task = NULL; + smp_mb__before_clear_bit(); + clear_bit(XPRT_LOCKED, &xprt->state); + smp_mb__after_clear_bit(); + __xprt_lock_write_next_cong(xprt); + } +} + +static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) { spin_lock_bh(&xprt->transport_lock); - __xprt_release_write(xprt, task); + xprt->ops->release_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); } @@ -237,7 +286,7 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) return; req->rq_cong = 0; xprt->cong -= RPC_CWNDSCALE; - __xprt_lock_write_next(xprt); + __xprt_lock_write_next_cong(xprt); } /* @@ -256,7 +305,7 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; if (cwnd > RPC_MAXCWND(xprt)) cwnd = RPC_MAXCWND(xprt); - __xprt_lock_write_next(xprt); + __xprt_lock_write_next_cong(xprt); } else if (result == -ETIMEDOUT) { cwnd >>= 1; if (cwnd < RPC_CWNDSCALE) @@ -693,7 +742,7 @@ void xprt_transmit(struct rpc_task *task) task->tk_status = -ENOTCONN; else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); - __xprt_release_write(xprt, task); + xprt->ops->release_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); return; } @@ -792,7 +841,7 @@ void xprt_release(struct rpc_task *task) if (!(req = task->tk_rqstp)) return; spin_lock_bh(&xprt->transport_lock); - __xprt_release_write(xprt, task); + xprt->ops->release_xprt(xprt, task); __xprt_put_cong(xprt, req); if (!list_empty(&req->rq_list)) list_del(&req->rq_list); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index fc4fbe8ea346..8589c1ad55e3 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1046,6 +1046,7 @@ static void xs_connect(struct rpc_task *task) static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, .reserve_xprt = xprt_reserve_xprt_cong, + .release_xprt = xprt_release_xprt_cong, .connect = xs_connect, .send_request = xs_udp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_rtt, @@ -1056,6 +1057,7 @@ static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_tcp_ops = { .set_buffer_size = xs_tcp_set_buffer_size, .reserve_xprt = xprt_reserve_xprt, + .release_xprt = xprt_release_xprt, .connect = xs_connect, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, From 46c0ee8bc4ad3743de05e8b8b20201df44dcb6d3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:52 -0700 Subject: [PATCH 0173/1939] [PATCH] RPC: separate xprt_timer implementations Allow transports to hook the retransmit timer interrupt. Some transports calculate their congestion window here so that a retransmit timeout has immediate effect on the congestion window. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/xprt.c | 45 +++++++++++++++++-------------------- net/sunrpc/xprtsock.c | 12 ++++++++++ 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 86833b725bb5..443c3f984cf9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -137,6 +137,7 @@ struct rpc_xprt_ops { void (*connect)(struct rpc_task *task); int (*send_request)(struct rpc_task *task); void (*set_retrans_timeout)(struct rpc_task *task); + void (*timer)(struct rpc_task *task); void (*close)(struct rpc_xprt *xprt); void (*destroy)(struct rpc_xprt *xprt); }; @@ -257,6 +258,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task); void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); void xprt_wait_for_buffer_space(struct rpc_task *task); void xprt_write_space(struct rpc_xprt *xprt); +void xprt_adjust_cwnd(struct rpc_task *task, int result); struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied); void xprt_disconnect(struct rpc_xprt *xprt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e92ea99dd318..ffc595592af3 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -289,16 +289,19 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) __xprt_lock_write_next_cong(xprt); } -/* - * Adjust RPC congestion window +/** + * xprt_adjust_cwnd - adjust transport congestion window + * @task: recently completed RPC request used to adjust window + * @result: result code of completed RPC request + * * We use a time-smoothed congestion estimator to avoid heavy oscillation. */ -static void -xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) +void xprt_adjust_cwnd(struct rpc_task *task, int result) { - unsigned long cwnd; + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = task->tk_xprt; + unsigned long cwnd = xprt->cwnd; - cwnd = xprt->cwnd; if (result >= 0 && cwnd <= xprt->cong) { /* The (cwnd >> 1) term makes sure * the result gets rounded properly. */ @@ -314,6 +317,7 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n", xprt->cong, xprt->cwnd, cwnd); xprt->cwnd = cwnd; + __xprt_put_cong(xprt, req); } /** @@ -602,8 +606,7 @@ void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) /* Adjust congestion window */ if (!xprt->nocong) { unsigned timer = task->tk_msg.rpc_proc->p_timer; - xprt_adjust_cwnd(xprt, copied); - __xprt_put_cong(xprt, req); + xprt_adjust_cwnd(task, copied); if (timer) { if (req->rq_ntrans == 1) rpc_update_rtt(clnt->cl_rtt, timer, @@ -640,27 +643,19 @@ void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) return; } -/* - * RPC receive timeout handler. - */ -static void -xprt_timer(struct rpc_task *task) +static void xprt_timer(struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; + struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + dprintk("RPC: %4d xprt_timer\n", task->tk_pid); + spin_lock(&xprt->transport_lock); - if (req->rq_received) - goto out; - - xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT); - __xprt_put_cong(xprt, req); - - dprintk("RPC: %4d xprt_timer (%s request)\n", - task->tk_pid, req ? "pending" : "backlogged"); - - task->tk_status = -ETIMEDOUT; -out: + if (!req->rq_received) { + if (xprt->ops->timer) + xprt->ops->timer(task); + task->tk_status = -ETIMEDOUT; + } task->tk_timeout = 0; rpc_wake_up_task(task); spin_unlock(&xprt->transport_lock); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8589c1ad55e3..c3658ff027a6 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -860,6 +860,17 @@ static void xs_tcp_set_buffer_size(struct rpc_xprt *xprt) return; } +/** + * xs_udp_timer - called when a retransmit timeout occurs on a UDP transport + * @task: task that timed out + * + * Adjust the congestion window after a retransmit timeout has occurred. + */ +static void xs_udp_timer(struct rpc_task *task) +{ + xprt_adjust_cwnd(task, -ETIMEDOUT); +} + static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) { struct sockaddr_in myaddr = { @@ -1050,6 +1061,7 @@ static struct rpc_xprt_ops xs_udp_ops = { .connect = xs_connect, .send_request = xs_udp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_rtt, + .timer = xs_udp_timer, .close = xs_close, .destroy = xs_destroy, }; From 1570c1e41eabf6b7031f3e4322a2cf1cbe319fee Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:52 -0700 Subject: [PATCH 0174/1939] [PATCH] RPC: add generic interface for adjusting the congestion window A new interface that allows transports to adjust their congestion window using the Van Jacobson implementation in xprt.c is provided. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 +- net/sunrpc/xprt.c | 62 ++++++++++++++----------------------- net/sunrpc/xprtsock.c | 13 +++----- 3 files changed, 31 insertions(+), 47 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 443c3f984cf9..2e48752d55d9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -258,9 +258,10 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task); void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); void xprt_wait_for_buffer_space(struct rpc_task *task); void xprt_write_space(struct rpc_xprt *xprt); +void xprt_update_rtt(struct rpc_task *task); void xprt_adjust_cwnd(struct rpc_task *task, int result); struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); -void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied); +void xprt_complete_rqst(struct rpc_task *task, int copied); void xprt_disconnect(struct rpc_xprt *xprt); /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ffc595592af3..707806fe1a23 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -592,55 +592,41 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) } /** - * xprt_complete_rqst - called when reply processing is complete - * @xprt: controlling transport - * @req: RPC request that just completed - * @copied: actual number of bytes received from the transport + * xprt_update_rtt - update an RPC client's RTT state after receiving a reply + * @task: RPC request that recently completed * */ -void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) +void xprt_update_rtt(struct rpc_task *task) { - struct rpc_task *task = req->rq_task; - struct rpc_clnt *clnt = task->tk_client; + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_rtt *rtt = task->tk_client->cl_rtt; + unsigned timer = task->tk_msg.rpc_proc->p_timer; - /* Adjust congestion window */ - if (!xprt->nocong) { - unsigned timer = task->tk_msg.rpc_proc->p_timer; - xprt_adjust_cwnd(task, copied); - if (timer) { - if (req->rq_ntrans == 1) - rpc_update_rtt(clnt->cl_rtt, timer, - (long)jiffies - req->rq_xtime); - rpc_set_timeo(clnt->cl_rtt, timer, req->rq_ntrans - 1); - } + if (timer) { + if (req->rq_ntrans == 1) + rpc_update_rtt(rtt, timer, + (long)jiffies - req->rq_xtime); + rpc_set_timeo(rtt, timer, req->rq_ntrans - 1); } +} -#ifdef RPC_PROFILE - /* Profile only reads for now */ - if (copied > 1024) { - static unsigned long nextstat; - static unsigned long pkt_rtt, pkt_len, pkt_cnt; +/** + * xprt_complete_rqst - called when reply processing is complete + * @task: RPC request that recently completed + * @copied: actual number of bytes received from the transport + * + * Caller holds transport lock. + */ +void xprt_complete_rqst(struct rpc_task *task, int copied) +{ + struct rpc_rqst *req = task->tk_rqstp; - pkt_cnt++; - pkt_len += req->rq_slen + copied; - pkt_rtt += jiffies - req->rq_xtime; - if (time_before(nextstat, jiffies)) { - printk("RPC: %lu %ld cwnd\n", jiffies, xprt->cwnd); - printk("RPC: %ld %ld %ld %ld stat\n", - jiffies, pkt_cnt, pkt_len, pkt_rtt); - pkt_rtt = pkt_len = pkt_cnt = 0; - nextstat = jiffies + 5 * HZ; - } - } -#endif + dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", + task->tk_pid, ntohl(req->rq_xid), copied); - dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied); list_del_init(&req->rq_list); req->rq_received = req->rq_private_buf.len = copied; - - /* ... and wake up the process. */ rpc_wake_up_task(task); - return; } static void xprt_timer(struct rpc_task *task) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index c3658ff027a6..980f26504f48 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -460,8 +460,6 @@ static void xs_udp_data_ready(struct sock *sk, int len) goto out_unlock; task = rovr->rq_task; - dprintk("RPC: %4d received reply\n", task->tk_pid); - if ((copied = rovr->rq_private_buf.buflen) > repsize) copied = repsize; @@ -472,7 +470,9 @@ static void xs_udp_data_ready(struct sock *sk, int len) /* Something worked... */ dst_confirm(skb->dst); - xprt_complete_rqst(xprt, rovr, copied); + xprt_adjust_cwnd(task, copied); + xprt_update_rtt(task); + xprt_complete_rqst(task, copied); out_unlock: spin_unlock(&xprt->transport_lock); @@ -634,11 +634,8 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc } out: - if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { - dprintk("RPC: %4d received reply complete\n", - req->rq_task->tk_pid); - xprt_complete_rqst(xprt, req, xprt->tcp_copied); - } + if (!(xprt->tcp_flags & XPRT_COPY_DATA)) + xprt_complete_rqst(req->rq_task, xprt->tcp_copied); spin_unlock(&xprt->transport_lock); xs_tcp_check_recm(xprt); } From a58dd398f5db4f73d5c581069fd70a4304cc4f0a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:53 -0700 Subject: [PATCH 0175/1939] [PATCH] RPC: add a release_rqst callout to the RPC transport switch The final place where congestion control state is adjusted is in xprt_release, where each request is finally released. Add a callout there to allow transports to perform additional processing when a request is about to be released. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/xprt.c | 14 +++++++++++++- net/sunrpc/xprtsock.c | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 2e48752d55d9..64e77658fa30 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -138,6 +138,7 @@ struct rpc_xprt_ops { int (*send_request)(struct rpc_task *task); void (*set_retrans_timeout)(struct rpc_task *task); void (*timer)(struct rpc_task *task); + void (*release_request)(struct rpc_task *task); void (*close)(struct rpc_xprt *xprt); void (*destroy)(struct rpc_xprt *xprt); }; @@ -262,6 +263,7 @@ void xprt_update_rtt(struct rpc_task *task); void xprt_adjust_cwnd(struct rpc_task *task, int result); struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); void xprt_complete_rqst(struct rpc_task *task, int copied); +void xprt_release_rqst_cong(struct rpc_task *task); void xprt_disconnect(struct rpc_xprt *xprt); /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 707806fe1a23..e8d11bd6158e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -289,6 +289,17 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) __xprt_lock_write_next_cong(xprt); } +/** + * xprt_release_rqst_cong - housekeeping when request is complete + * @task: RPC request that recently completed + * + * Useful for transports that require congestion control. + */ +void xprt_release_rqst_cong(struct rpc_task *task) +{ + __xprt_put_cong(task->tk_xprt, task->tk_rqstp); +} + /** * xprt_adjust_cwnd - adjust transport congestion window * @task: recently completed RPC request used to adjust window @@ -823,7 +834,8 @@ void xprt_release(struct rpc_task *task) return; spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); - __xprt_put_cong(xprt, req); + if (xprt->ops->release_request) + xprt->ops->release_request(task); if (!list_empty(&req->rq_list)) list_del(&req->rq_list); xprt->last_used = jiffies; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 980f26504f48..6c2f5dcea416 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1059,6 +1059,7 @@ static struct rpc_xprt_ops xs_udp_ops = { .send_request = xs_udp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_rtt, .timer = xs_udp_timer, + .release_request = xprt_release_rqst_cong, .close = xs_close, .destroy = xs_destroy, }; From ed63c003701a314c4893c11eceb9d68f8f46c662 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:53 -0700 Subject: [PATCH 0176/1939] [PATCH] RPC: remove xprt->nocong Get rid of the "xprt->nocong" variable. Test-plan: Use WAN simulation to cause sporadic bursty packet loss with UDP mounts. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/lockd/host.c | 1 - include/linux/sunrpc/xprt.h | 1 - net/sunrpc/xprtsock.c | 2 -- 3 files changed, 4 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 7901f5b8092c..c4c8601096e0 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -188,7 +188,6 @@ nlm_bind_host(struct nlm_host *host) goto forgetit; xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); - xprt->nocong = 1; /* No congestion control for NLM */ xprt->resvport = 1; /* NLM requires a reserved port */ /* Existing NLM servers accept AUTH_UNIX only */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 64e77658fa30..559fb471f6f2 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -172,7 +172,6 @@ struct rpc_xprt { unsigned int max_reqs; /* total slots */ unsigned long state; /* transport state */ unsigned char shutdown : 1, /* being shut down */ - nocong : 1, /* no congestion control */ resvport : 1; /* use a reserved port */ /* diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6c2f5dcea416..7e5e020fe78d 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1100,7 +1100,6 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_UDP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = 0; - xprt->nocong = 0; xprt->cwnd = RPC_INITCWND; xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; /* XXX: header size can vary due to auth type, IPv6, etc. */ @@ -1140,7 +1139,6 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_TCP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); - xprt->nocong = 1; xprt->cwnd = RPC_MAXCWND(xprt); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; From 555ee3af161b037865793bd4bebc06b58daafde6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:54 -0700 Subject: [PATCH 0177/1939] [PATCH] RPC: clean up after nocong was removed Clean-up: Move some macros that are specific to the Van Jacobson implementation into xprt.c. Get rid of the cong_wait field in rpc_xprt, which is no longer used. Get rid of xprt_clear_backlog. Test-plan: Compile with CONFIG_NFS enabled. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 22 ---------------------- net/sunrpc/xprt.c | 29 +++++++++++++++++++---------- net/sunrpc/xprtsock.c | 2 -- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 559fb471f6f2..dcf0326bda01 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -15,20 +15,6 @@ #include #include -/* - * The transport code maintains an estimate on the maximum number of out- - * standing RPC requests, using a smoothed version of the congestion - * avoidance implemented in 44BSD. This is basically the Van Jacobson - * congestion algorithm: If a retransmit occurs, the congestion window is - * halved; otherwise, it is incremented by 1/cwnd when - * - * - a reply is received and - * - a full number of requests are outstanding and - * - the congestion window hasn't been updated recently. - * - * Upper procedures may check whether a request would block waiting for - * a free RPC slot by using the RPC_CONGESTED() macro. - */ extern unsigned int xprt_udp_slot_table_entries; extern unsigned int xprt_tcp_slot_table_entries; @@ -36,12 +22,6 @@ extern unsigned int xprt_tcp_slot_table_entries; #define RPC_DEF_SLOT_TABLE (16U) #define RPC_MAX_SLOT_TABLE (128U) -#define RPC_CWNDSHIFT (8U) -#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT) -#define RPC_INITCWND RPC_CWNDSCALE -#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT) -#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) - /* Default timeout values */ #define RPC_MAX_UDP_TIMEOUT (60*HZ) #define RPC_MAX_TCP_TIMEOUT (600*HZ) @@ -213,8 +193,6 @@ struct rpc_xprt { void (*old_data_ready)(struct sock *, int); void (*old_state_change)(struct sock *); void (*old_write_space)(struct sock *); - - wait_queue_head_t cong_wait; }; #define XPRT_LAST_FRAG (1 << 0) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e8d11bd6158e..0458319a1bdd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -62,7 +62,23 @@ static inline void do_xprt_reserve(struct rpc_task *); static void xprt_connect_status(struct rpc_task *task); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); -static int xprt_clear_backlog(struct rpc_xprt *xprt); +/* + * The transport code maintains an estimate on the maximum number of out- + * standing RPC requests, using a smoothed version of the congestion + * avoidance implemented in 44BSD. This is basically the Van Jacobson + * congestion algorithm: If a retransmit occurs, the congestion window is + * halved; otherwise, it is incremented by 1/cwnd when + * + * - a reply is received and + * - a full number of requests are outstanding and + * - the congestion window hasn't been updated recently. + */ +#define RPC_CWNDSHIFT (8U) +#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT) +#define RPC_INITCWND RPC_CWNDSCALE +#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT) + +#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) /** * xprt_reserve_xprt - serialize write access to transports @@ -850,7 +866,7 @@ void xprt_release(struct rpc_task *task) spin_lock(&xprt->reserve_lock); list_add(&req->rq_list, &xprt->free); - xprt_clear_backlog(xprt); + rpc_wake_up_next(&xprt->backlog); spin_unlock(&xprt->reserve_lock); } @@ -902,7 +918,6 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc spin_lock_init(&xprt->transport_lock); spin_lock_init(&xprt->reserve_lock); - init_waitqueue_head(&xprt->cong_wait); INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); @@ -911,6 +926,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; xprt->last_used = jiffies; + xprt->cwnd = RPC_INITCWND; rpc_init_wait_queue(&xprt->pending, "xprt_pending"); rpc_init_wait_queue(&xprt->sending, "xprt_sending"); @@ -955,16 +971,9 @@ static void xprt_shutdown(struct rpc_xprt *xprt) rpc_wake_up(&xprt->resend); xprt_wake_pending_tasks(xprt, -EIO); rpc_wake_up(&xprt->backlog); - wake_up(&xprt->cong_wait); del_timer_sync(&xprt->timer); } -static int xprt_clear_backlog(struct rpc_xprt *xprt) { - rpc_wake_up_next(&xprt->backlog); - wake_up(&xprt->cong_wait); - return 1; -} - /** * xprt_destroy - destroy an RPC transport, killing off all requests. * @xprt: transport to destroy diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7e5e020fe78d..26402c063f00 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1100,7 +1100,6 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_UDP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = 0; - xprt->cwnd = RPC_INITCWND; xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); @@ -1139,7 +1138,6 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->prot = IPPROTO_TCP; xprt->port = XS_MAX_RESVPORT; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); - xprt->cwnd = RPC_MAXCWND(xprt); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; From 529b33c6db0120126b1381faa51406dc463acdc9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:54 -0700 Subject: [PATCH 0178/1939] [PATCH] RPC: allow RPC client's port range to be adjustable Select an RPC client source port between 650 and 1023 instead of between 1 and 800. The old range conflicts with a number of network services. Provide sysctls to allow admins to select a different port range. Note that this doesn't affect user-level RPC library behavior, which still uses 1 to 800. Based on a suggestion by Olaf Kirch . Test-plan: Repeated mount and unmount. Destructive testing. Idle timeouts. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/debug.h | 2 ++ include/linux/sunrpc/xprt.h | 17 ++++++++++++++--- net/sunrpc/sysctl.c | 29 +++++++++++++++++++++++++++++ net/sunrpc/xprtsock.c | 23 ++++++++--------------- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index 42d299747956..1a42d902bc11 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -95,6 +95,8 @@ enum { CTL_NLMDEBUG, CTL_SLOTTABLE_UDP, CTL_SLOTTABLE_TCP, + CTL_MIN_RESVPORT, + CTL_MAX_RESVPORT, }; #endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index dcf0326bda01..9d9266cf8a36 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -51,6 +51,17 @@ extern unsigned int xprt_tcp_slot_table_entries; #define RPC_CALLHDRSIZE 6 #define RPC_REPHDRSIZE 4 +/* + * Parameters for choosing a free port + */ +extern unsigned int xprt_min_resvport; +extern unsigned int xprt_max_resvport; + +#define RPC_MIN_RESVPORT (1U) +#define RPC_MAX_RESVPORT (65535U) +#define RPC_DEF_MIN_RESVPORT (650U) +#define RPC_DEF_MAX_RESVPORT (1023U) + /* * This describes a timeout strategy */ @@ -62,6 +73,9 @@ struct rpc_timeout { unsigned char to_exponential; }; +struct rpc_task; +struct rpc_xprt; + /* * This describes a complete RPC request */ @@ -107,9 +121,6 @@ struct rpc_rqst { #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len -struct rpc_task; -struct rpc_xprt; - struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt); int (*reserve_xprt)(struct rpc_task *task); diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index ef483262f17f..d0c9f460e411 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -121,9 +121,16 @@ proc_dodebug(ctl_table *table, int write, struct file *file, unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; +unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; +EXPORT_SYMBOL(xprt_min_resvport); +unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; +EXPORT_SYMBOL(xprt_max_resvport); + static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; +static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; +static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; static ctl_table debug_table[] = { { @@ -180,6 +187,28 @@ static ctl_table debug_table[] = { .extra1 = &min_slot_table_size, .extra2 = &max_slot_table_size }, + { + .ctl_name = CTL_MIN_RESVPORT, + .procname = "min_resvport", + .data = &xprt_min_resvport, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xprt_min_resvport_limit, + .extra2 = &xprt_max_resvport_limit + }, + { + .ctl_name = CTL_MAX_RESVPORT, + .procname = "max_resvport", + .data = &xprt_max_resvport, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xprt_min_resvport_limit, + .extra2 = &xprt_max_resvport_limit + }, { .ctl_name = 0 } }; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 26402c063f00..62c2e7caa345 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -35,11 +35,6 @@ #include #include -/* - * Maximum port number to use when requesting a reserved port. - */ -#define XS_MAX_RESVPORT (800U) - /* * How many times to try sending a request on a socket before waiting * for the socket buffer to clear. @@ -873,10 +868,9 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) struct sockaddr_in myaddr = { .sin_family = AF_INET, }; - int err, port; + int err; + unsigned short port = xprt->port; - /* Were we already bound to a given port? Try to reuse it */ - port = xprt->port; do { myaddr.sin_port = htons(port); err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, @@ -887,8 +881,10 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) port); return 0; } - if (--port == 0) - port = XS_MAX_RESVPORT; + if (port <= xprt_min_resvport) + port = xprt_max_resvport; + else + port--; } while (err == -EADDRINUSE && port != xprt->port); dprintk("RPC: can't bind to reserved port (%d).\n", -err); @@ -1075,9 +1071,6 @@ static struct rpc_xprt_ops xs_tcp_ops = { .destroy = xs_destroy, }; -extern unsigned int xprt_udp_slot_table_entries; -extern unsigned int xprt_tcp_slot_table_entries; - /** * xs_setup_udp - Set up transport to use a UDP socket * @xprt: transport to set up @@ -1098,7 +1091,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) memset(xprt->slot, 0, slot_table_size); xprt->prot = IPPROTO_UDP; - xprt->port = XS_MAX_RESVPORT; + xprt->port = xprt_max_resvport; xprt->tsh_size = 0; xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; /* XXX: header size can vary due to auth type, IPv6, etc. */ @@ -1136,7 +1129,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) memset(xprt->slot, 0, slot_table_size); xprt->prot = IPPROTO_TCP; - xprt->port = XS_MAX_RESVPORT; + xprt->port = xprt_max_resvport; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; From 3167e12c0c424f3c323944701615343022d86418 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:55 -0700 Subject: [PATCH 0179/1939] [PATCH] RPC: make sure to get the same local port number when reconnecting Implement a best practice: if the remote end drops our connection, try to reconnect using the same port number. This is important because the NFS server's Duplicate Reply Cache often hashes on the source port number. If the client reuses the port number when it reconnects, the server's DRC will be more effective. Based on suggestions by Mike Eisler, Olaf Kirch, and Alexey Kuznetsky. Test-plan: Destructive testing. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 65 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 62c2e7caa345..88ac71fcd335 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -362,6 +362,8 @@ static int xs_tcp_send_request(struct rpc_task *task) * xs_close - close a socket * @xprt: transport * + * This is used when all requests are complete; ie, no DRC state remains + * on the server we want to save. */ static void xs_close(struct rpc_xprt *xprt) { @@ -949,6 +951,30 @@ static void xs_udp_connect_worker(void *args) xprt_clear_connecting(xprt); } +/* + * We need to preserve the port number so the reply cache on the server can + * find our cached RPC replies when we get around to reconnecting. + */ +static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) +{ + int result; + struct socket *sock = xprt->sock; + struct sockaddr any; + + dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt); + + /* + * Disconnect the transport socket by doing a connect operation + * with AF_UNSPEC. This should return immediately... + */ + memset(&any, 0, sizeof(any)); + any.sa_family = AF_UNSPEC; + result = sock->ops->connect(sock, &any, sizeof(any), 0); + if (result) + dprintk("RPC: AF_UNSPEC connect return code %d\n", + result); +} + /** * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint * @args: RPC transport to connect @@ -966,18 +992,20 @@ static void xs_tcp_connect_worker(void *args) dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt); - /* Start by resetting any existing socket state */ - xs_close(xprt); + if (!xprt->sock) { + /* start from scratch */ + if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { + dprintk("RPC: can't create TCP transport socket (%d).\n", -err); + goto out; + } - if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { - dprintk("RPC: can't create TCP transport socket (%d).\n", -err); - goto out; - } - - if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { - sock_release(sock); - goto out; - } + if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { + sock_release(sock); + goto out; + } + } else + /* "close" the socket, preserving the local port */ + xs_tcp_reuse_connection(xprt); if (!xprt->inet) { struct sock *sk = sock->sk; @@ -991,7 +1019,12 @@ static void xs_tcp_connect_worker(void *args) sk->sk_data_ready = xs_tcp_data_ready; sk->sk_state_change = xs_tcp_state_change; sk->sk_write_space = xs_tcp_write_space; - tcp_sk(sk)->nonagle = 1; + + /* socket options */ + sk->sk_userlocks |= SOCK_BINDPORT_LOCK; + sock_reset_flag(sk, SOCK_LINGER); + tcp_sk(sk)->linger2 = 0; + tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; xprt_clear_connected(xprt); @@ -1012,6 +1045,14 @@ static void xs_tcp_connect_worker(void *args) case -EINPROGRESS: case -EALREADY: goto out_clear; + case -ECONNREFUSED: + case -ECONNRESET: + /* retry with existing socket, after a delay */ + break; + default: + /* get rid of existing socket, and retry */ + xs_close(xprt); + break; } } out: From 03bf4b707eee06706c9db343dd5c905b7ee47ed2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:55 -0700 Subject: [PATCH 0180/1939] [PATCH] RPC: parametrize various transport connect timeouts Each transport implementation can now set unique bind, connect, reestablishment, and idle timeout values. These are variables, allowing the values to be modified dynamically. This permits exponential backoff of any of these values, for instance. As an example, we implement exponential backoff for the connection reestablishment timeout. Test-plan: Destructive testing (unplugging the network temporarily). Connectathon with UDP and TCP. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 10 +++--- include/linux/nfs_fs.h | 4 +++ include/linux/sunrpc/xprt.h | 29 ++++------------ net/sunrpc/clnt.c | 2 +- net/sunrpc/xprt.c | 5 ++- net/sunrpc/xprtsock.c | 68 +++++++++++++++++++++++++++++++++++-- 6 files changed, 84 insertions(+), 34 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b6a1ca508e60..062911e7ceb5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -369,8 +369,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned case IPPROTO_TCP: if (!to->to_initval) to->to_initval = 60 * HZ; - if (to->to_initval > RPC_MAX_TCP_TIMEOUT) - to->to_initval = RPC_MAX_TCP_TIMEOUT; + if (to->to_initval > NFS_MAX_TCP_TIMEOUT) + to->to_initval = NFS_MAX_TCP_TIMEOUT; to->to_increment = to->to_initval; to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); to->to_exponential = 0; @@ -379,9 +379,9 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned default: if (!to->to_initval) to->to_initval = 11 * HZ / 10; - if (to->to_initval > RPC_MAX_UDP_TIMEOUT) - to->to_initval = RPC_MAX_UDP_TIMEOUT; - to->to_maxval = RPC_MAX_UDP_TIMEOUT; + if (to->to_initval > NFS_MAX_UDP_TIMEOUT) + to->to_initval = NFS_MAX_UDP_TIMEOUT; + to->to_maxval = NFS_MAX_UDP_TIMEOUT; to->to_exponential = 1; break; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 9a6047ff1b25..7bac2785c6e4 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -41,6 +41,10 @@ #define NFS_MAX_FILE_IO_BUFFER_SIZE 32768 #define NFS_DEF_FILE_IO_BUFFER_SIZE 4096 +/* Default timeout values */ +#define NFS_MAX_UDP_TIMEOUT (60*HZ) +#define NFS_MAX_TCP_TIMEOUT (600*HZ) + /* * superblock magic number for NFS */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 9d9266cf8a36..2543adf18551 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -22,28 +22,6 @@ extern unsigned int xprt_tcp_slot_table_entries; #define RPC_DEF_SLOT_TABLE (16U) #define RPC_MAX_SLOT_TABLE (128U) -/* Default timeout values */ -#define RPC_MAX_UDP_TIMEOUT (60*HZ) -#define RPC_MAX_TCP_TIMEOUT (600*HZ) - -/* - * Wait duration for an RPC TCP connection to be established. Solaris - * NFS over TCP uses 60 seconds, for example, which is in line with how - * long a server takes to reboot. - */ -#define RPC_CONNECT_TIMEOUT (60*HZ) - -/* - * Delay an arbitrary number of seconds before attempting to reconnect - * after an error. - */ -#define RPC_REESTABLISH_TIMEOUT (15*HZ) - -/* - * RPC transport idle timeout. - */ -#define RPC_IDLE_DISCONNECT_TIMEOUT (5*60*HZ) - /* * RPC call and reply header size as number of 32bit words (verifier * size computed separately) @@ -182,14 +160,19 @@ struct rpc_xprt { /* * Connection of transports */ + unsigned long connect_timeout, + bind_timeout, + reestablish_timeout; struct work_struct connect_worker; unsigned short port; + /* * Disconnection of idle transports */ struct work_struct task_cleanup; struct timer_list timer; - unsigned long last_used; + unsigned long last_used, + idle_timeout; /* * Send stuff diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index cc1b773a79d3..24b44e73f391 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -740,7 +740,7 @@ call_bind(struct rpc_task *task) task->tk_action = call_connect; if (!clnt->cl_port) { task->tk_action = call_bind_status; - task->tk_timeout = RPC_CONNECT_TIMEOUT; + task->tk_timeout = task->tk_xprt->bind_timeout; rpc_getport(task, clnt); } } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 0458319a1bdd..215be0d0ef6b 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -551,7 +551,7 @@ void xprt_connect(struct rpc_task *task) if (task->tk_rqstp) task->tk_rqstp->rq_bytes_sent = 0; - task->tk_timeout = RPC_CONNECT_TIMEOUT; + task->tk_timeout = xprt->connect_timeout; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); xprt->ops->connect(task); } @@ -763,7 +763,6 @@ void xprt_transmit(struct rpc_task *task) switch (status) { case -ECONNREFUSED: - task->tk_timeout = RPC_REESTABLISH_TIMEOUT; rpc_sleep_on(&xprt->sending, task, NULL, NULL); case -EAGAIN: case -ENOTCONN: @@ -857,7 +856,7 @@ void xprt_release(struct rpc_task *task) xprt->last_used = jiffies; if (list_empty(&xprt->recv) && !xprt->shutdown) mod_timer(&xprt->timer, - xprt->last_used + RPC_IDLE_DISCONNECT_TIMEOUT); + xprt->last_used + xprt->idle_timeout); spin_unlock_bh(&xprt->transport_lock); task->tk_rqstp = NULL; memset(req, 0, sizeof(*req)); /* mark unused */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 88ac71fcd335..06c2d95484e0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -41,6 +41,50 @@ */ #define XS_SENDMSG_RETRY (10U) +/* + * Time out for an RPC UDP socket connect. UDP socket connects are + * synchronous, but we set a timeout anyway in case of resource + * exhaustion on the local host. + */ +#define XS_UDP_CONN_TO (5U * HZ) + +/* + * Wait duration for an RPC TCP connection to be established. Solaris + * NFS over TCP uses 60 seconds, for example, which is in line with how + * long a server takes to reboot. + */ +#define XS_TCP_CONN_TO (60U * HZ) + +/* + * Wait duration for a reply from the RPC portmapper. + */ +#define XS_BIND_TO (60U * HZ) + +/* + * Delay if a UDP socket connect error occurs. This is most likely some + * kind of resource problem on the local host. + */ +#define XS_UDP_REEST_TO (2U * HZ) + +/* + * The reestablish timeout allows clients to delay for a bit before attempting + * to reconnect to a server that just dropped our connection. + * + * We implement an exponential backoff when trying to reestablish a TCP + * transport connection with the server. Some servers like to drop a TCP + * connection when they are overworked, so we start with a short timeout and + * increase over time if the server is down or not responding. + */ +#define XS_TCP_INIT_REEST_TO (3U * HZ) +#define XS_TCP_MAX_REEST_TO (5U * 60 * HZ) + +/* + * TCP idle timeout; client drops the transport socket if it is idle + * for this long. Note that we also timeout UDP sockets to prevent + * holding port numbers when there is no RPC traffic. + */ +#define XS_IDLE_DISC_TO (5U * 60 * HZ) + #ifdef RPC_DEBUG # undef RPC_DEBUG_DATA # define RPCDBG_FACILITY RPCDBG_TRANS @@ -739,6 +783,7 @@ static void xs_tcp_state_change(struct sock *sk) xprt->tcp_reclen = 0; xprt->tcp_copied = 0; xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; + xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; xprt_wake_pending_tasks(xprt, 0); } spin_unlock_bh(&xprt->transport_lock); @@ -1066,6 +1111,13 @@ static void xs_tcp_connect_worker(void *args) * @task: address of RPC task that manages state of connect request * * TCP: If the remote end dropped the connection, delay reconnecting. + * + * UDP socket connects are synchronous, but we use a work queue anyway + * to guarantee that even unprivileged user processes can set up a + * socket on a privileged port. + * + * If a UDP socket connect fails, the delay behavior here prevents + * retry floods (hard mounts). */ static void xs_connect(struct rpc_task *task) { @@ -1075,9 +1127,13 @@ static void xs_connect(struct rpc_task *task) return; if (xprt->sock != NULL) { - dprintk("RPC: xs_connect delayed xprt %p\n", xprt); + dprintk("RPC: xs_connect delayed xprt %p for %lu seconds\n", + xprt, xprt->reestablish_timeout / HZ); schedule_delayed_work(&xprt->connect_worker, - RPC_REESTABLISH_TIMEOUT); + xprt->reestablish_timeout); + xprt->reestablish_timeout <<= 1; + if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) + xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); schedule_work(&xprt->connect_worker); @@ -1139,6 +1195,10 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); + xprt->bind_timeout = XS_BIND_TO; + xprt->connect_timeout = XS_UDP_CONN_TO; + xprt->reestablish_timeout = XS_UDP_REEST_TO; + xprt->idle_timeout = XS_IDLE_DISC_TO; xprt->ops = &xs_udp_ops; @@ -1176,6 +1236,10 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); + xprt->bind_timeout = XS_BIND_TO; + xprt->connect_timeout = XS_TCP_CONN_TO; + xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; + xprt->idle_timeout = XS_IDLE_DISC_TO; xprt->ops = &xs_tcp_ops; From 470056c288334eb0b37be26c9ff8aee37ed1cc7a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 25 Aug 2005 16:25:56 -0700 Subject: [PATCH 0181/1939] [PATCH] RPC: rationalize set_buffer_size In fact, ->set_buffer_size should be completely functionless for non-UDP. Test-plan: Check socket buffer size on UDP sockets over time. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 4 ++-- net/sunrpc/clnt.c | 10 ++-------- net/sunrpc/xprtsock.c | 30 +++++++++++++++--------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 2543adf18551..99cad3ead81d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -100,7 +100,7 @@ struct rpc_rqst { #define rq_slen rq_snd_buf.len struct rpc_xprt_ops { - void (*set_buffer_size)(struct rpc_xprt *xprt); + void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); int (*reserve_xprt)(struct rpc_task *task); void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); void (*connect)(struct rpc_task *task); @@ -124,7 +124,7 @@ struct rpc_xprt { unsigned long cong; /* current congestion */ unsigned long cwnd; /* congestion window */ - unsigned int rcvsize, /* transport rcv buffer size */ + size_t rcvsize, /* transport rcv buffer size */ sndsize; /* transport send buffer size */ size_t max_payload; /* largest RPC payload size, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 24b44e73f391..5a8f01d726e9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -517,14 +517,8 @@ void rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) { struct rpc_xprt *xprt = clnt->cl_xprt; - - xprt->sndsize = 0; - if (sndsize) - xprt->sndsize = sndsize + RPC_SLACK_SPACE; - xprt->rcvsize = 0; - if (rcvsize) - xprt->rcvsize = rcvsize + RPC_SLACK_SPACE; - xprt->ops->set_buffer_size(xprt); + if (xprt->ops->set_buffer_size) + xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); } /* diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 06c2d95484e0..2e1529217e65 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -865,15 +865,7 @@ static void xs_tcp_write_space(struct sock *sk) read_unlock(&sk->sk_callback_lock); } -/** - * xs_udp_set_buffer_size - set send and receive limits - * @xprt: generic transport - * - * Set socket send and receive limits based on the - * sndsize and rcvsize fields in the generic transport - * structure. - */ -static void xs_udp_set_buffer_size(struct rpc_xprt *xprt) +static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) { struct sock *sk = xprt->inet; @@ -889,14 +881,23 @@ static void xs_udp_set_buffer_size(struct rpc_xprt *xprt) } /** - * xs_tcp_set_buffer_size - set send and receive limits + * xs_udp_set_buffer_size - set send and receive limits * @xprt: generic transport + * @sndsize: requested size of send buffer, in bytes + * @rcvsize: requested size of receive buffer, in bytes * - * Nothing to do for TCP. + * Set socket send and receive buffer size limits. */ -static void xs_tcp_set_buffer_size(struct rpc_xprt *xprt) +static void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize) { - return; + xprt->sndsize = 0; + if (sndsize) + xprt->sndsize = sndsize + 1024; + xprt->rcvsize = 0; + if (rcvsize) + xprt->rcvsize = rcvsize + 1024; + + xs_udp_do_set_buffer_size(xprt); } /** @@ -989,7 +990,7 @@ static void xs_udp_connect_worker(void *args) write_unlock_bh(&sk->sk_callback_lock); } - xs_udp_set_buffer_size(xprt); + xs_udp_do_set_buffer_size(xprt); status = 0; out: xprt_wake_pending_tasks(xprt, status); @@ -1158,7 +1159,6 @@ static struct rpc_xprt_ops xs_udp_ops = { }; static struct rpc_xprt_ops xs_tcp_ops = { - .set_buffer_size = xs_tcp_set_buffer_size, .reserve_xprt = xprt_reserve_xprt, .release_xprt = xprt_release_xprt, .connect = xs_connect, From 278c995c8a153bb2a9bc427e931cfb9c8034c9d7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 24 Jul 2005 23:53:01 +0100 Subject: [PATCH 0182/1939] [PATCH] RPC,NFS: new rpc_pipefs patch Currently rpc_mkdir/rpc_rmdir and rpc_mkpipe/mk_unlink have an API that's a little unfortunate. They take a path relative to the rpc_pipefs root and thus need to perform a full lookup. If you look at debugfs or usbfs they always store the dentry for directories they created and thus can pass in a dentry + single pathname component pair into their equivalents of the above functions. And in fact rpc_pipefs actually stores a dentry for all but one component so this change not only simplifies the core rpc_pipe code but also the callers. Unfortuntately this code path is only used by the NFS4 idmapper and AUTH_GSSAPI for which I don't have a test enviroment. Could someone give it a spin? It's the last bit needed before we can rework the lookup_hash API Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust --- fs/nfs/idmap.c | 10 +- include/linux/sunrpc/clnt.h | 2 +- include/linux/sunrpc/rpc_pipe_fs.h | 9 +- net/sunrpc/auth_gss/auth_gss.c | 9 +- net/sunrpc/clnt.c | 55 ++++-- net/sunrpc/rpc_pipe.c | 280 +++++++++++------------------ 6 files changed, 149 insertions(+), 216 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index ffb8df91dc34..1d0a5bf0d264 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -66,7 +66,6 @@ struct idmap_hashtable { }; struct idmap { - char idmap_path[48]; struct dentry *idmap_dentry; wait_queue_head_t idmap_wq; struct idmap_msg idmap_im; @@ -102,11 +101,8 @@ nfs_idmap_new(struct nfs4_client *clp) memset(idmap, 0, sizeof(*idmap)); - snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), - "%s/idmap", clp->cl_rpcclient->cl_pathname); - - idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, - idmap, &idmap_upcall_ops, 0); + idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, + "idmap", idmap, &idmap_upcall_ops, 0); if (IS_ERR(idmap->idmap_dentry)) { kfree(idmap); return; @@ -128,7 +124,7 @@ nfs_idmap_delete(struct nfs4_client *clp) if (!idmap) return; - rpc_unlink(idmap->idmap_path); + rpc_unlink(idmap->idmap_dentry); clp->cl_idmap = NULL; kfree(idmap); } diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index ab151bbb66df..b5b51c196690 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -59,7 +59,7 @@ struct rpc_clnt { int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME]; - char cl_pathname[30];/* Path in rpc_pipe_fs */ + struct dentry * __cl_parent_dentry; struct dentry * cl_dentry; /* inode */ struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 63929349571f..63878d05c9a9 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -41,10 +41,11 @@ RPC_I(struct inode *inode) extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); -extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); -extern int rpc_rmdir(char *); -extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); -extern int rpc_unlink(char *); +extern struct dentry *rpc_mkdir(struct dentry *, char *, struct rpc_clnt *); +extern void rpc_rmdir(struct dentry *); +extern struct dentry *rpc_mkpipe(struct dentry *, char *, void *, + struct rpc_pipe_ops *, int flags); +extern void rpc_unlink(struct dentry *); #endif #endif diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index d2b08f16c257..bd2555139fa9 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -87,7 +87,6 @@ struct gss_auth { struct list_head upcalls; struct rpc_clnt *client; struct dentry *dentry; - char path[48]; spinlock_t lock; }; @@ -690,10 +689,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) if (err) goto err_put_mech; - snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", - clnt->cl_pathname, - gss_auth->mech->gm_name); - gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); + gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, + clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); if (IS_ERR(gss_auth->dentry)) { err = PTR_ERR(gss_auth->dentry); goto err_put_mech; @@ -718,7 +715,7 @@ gss_destroy(struct rpc_auth *auth) auth, auth->au_flavor); gss_auth = container_of(auth, struct gss_auth, rpc_auth); - rpc_unlink(gss_auth->path); + rpc_unlink(gss_auth->dentry); gss_mech_put(gss_auth->mech); rpcauth_free_credcache(auth); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5a8f01d726e9..63bf591310e0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -67,26 +67,42 @@ static u32 * call_verify(struct rpc_task *task); static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { - static uint32_t clntid; + static unsigned int clntid; + char name[128]; int error; if (dir_name == NULL) return 0; - for (;;) { - snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), - "%s/clnt%x", dir_name, - (unsigned int)clntid++); - clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; - clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt); - if (!IS_ERR(clnt->cl_dentry)) - return 0; - error = PTR_ERR(clnt->cl_dentry); - if (error != -EEXIST) { - printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", - clnt->cl_pathname, error); - return error; - } + + retry_parent: + clnt->__cl_parent_dentry = rpc_mkdir(NULL, dir_name, NULL); + if (IS_ERR(clnt->__cl_parent_dentry)) { + error = PTR_ERR(clnt->__cl_parent_dentry); + if (error == -EEXIST) + goto retry_parent; /* XXX(hch): WTF? */ + + printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", + dir_name, error); + return error; } + + + retry_child: + snprintf(name, sizeof(name), "clnt%x", clntid++); + name[sizeof(name) - 1] = '\0'; + + clnt->cl_dentry = rpc_mkdir(clnt->__cl_parent_dentry, name, clnt); + if (IS_ERR(clnt->cl_dentry)) { + error = PTR_ERR(clnt->cl_dentry); + if (error == -EEXIST) + goto retry_child; + printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", + name, error); + rpc_rmdir(clnt->__cl_parent_dentry); + return error; + } + + return 0; } /* @@ -174,7 +190,8 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, return clnt; out_no_auth: - rpc_rmdir(clnt->cl_pathname); + rpc_rmdir(clnt->cl_dentry); + rpc_rmdir(clnt->__cl_parent_dentry); out_no_path: if (clnt->cl_server != clnt->cl_inline_name) kfree(clnt->cl_server); @@ -302,8 +319,10 @@ rpc_destroy_client(struct rpc_clnt *clnt) rpc_destroy_client(clnt->cl_parent); goto out_free; } - if (clnt->cl_pathname[0]) - rpc_rmdir(clnt->cl_pathname); + if (clnt->cl_dentry) + rpc_rmdir(clnt->cl_dentry); + if (clnt->__cl_parent_dentry) + rpc_rmdir(clnt->__cl_parent_dentry); if (clnt->cl_xprt) { xprt_destroy(clnt->cl_xprt); clnt->cl_xprt = NULL; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ded6c63f11ec..b382809726d8 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -414,38 +414,6 @@ rpc_put_mount(void) simple_release_fs(&rpc_mount, &rpc_mount_count); } -static int -rpc_lookup_parent(char *path, struct nameidata *nd) -{ - if (path[0] == '\0') - return -ENOENT; - if (rpc_get_mount()) { - printk(KERN_WARNING "%s: %s failed to mount " - "pseudofilesystem \n", __FILE__, __FUNCTION__); - return -ENODEV; - } - nd->mnt = mntget(rpc_mount); - nd->dentry = dget(rpc_mount->mnt_root); - nd->last_type = LAST_ROOT; - nd->flags = LOOKUP_PARENT; - nd->depth = 0; - - if (path_walk(path, nd)) { - printk(KERN_WARNING "%s: %s failed to find path %s\n", - __FILE__, __FUNCTION__, path); - rpc_put_mount(); - return -ENOENT; - } - return 0; -} - -static void -rpc_release_path(struct nameidata *nd) -{ - path_release(nd); - rpc_put_mount(); -} - static struct inode * rpc_get_inode(struct super_block *sb, int mode) { @@ -550,197 +518,149 @@ rpc_populate(struct dentry *parent, return -ENOMEM; } -static int -__rpc_mkdir(struct inode *dir, struct dentry *dentry) +struct dentry * +rpc_mkdir(struct dentry *parent, char *name, struct rpc_clnt *rpc_client) { + struct inode *dir; + struct dentry *dentry; struct inode *inode; + int error; + + if (!parent) + parent = rpc_mount->mnt_root; + + dir = parent->d_inode; + + error = rpc_get_mount(); + if (error) + return ERR_PTR(error); + + down(&dir->i_sem); + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + goto out_unlock; + if (dentry->d_inode) { + dentry = ERR_PTR(-EEXIST); + goto out_dput; + } inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); if (!inode) - goto out_err; + goto out_dput; inode->i_ino = iunique(dir->i_sb, 100); - d_instantiate(dentry, inode); dir->i_nlink++; - inode_dir_notify(dir, DN_CREATE); - rpc_get_mount(); - return 0; -out_err: - printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", - __FILE__, __FUNCTION__, dentry->d_name.name); - return -ENOMEM; -} - -static int -__rpc_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error; - - shrink_dcache_parent(dentry); - if (dentry->d_inode) { - rpc_close_pipes(dentry->d_inode); - rpc_inode_setowner(dentry->d_inode, NULL); - } - if ((error = simple_rmdir(dir, dentry)) != 0) - return error; - if (!error) { - inode_dir_notify(dir, DN_DELETE); - d_drop(dentry); - rpc_put_mount(); - } - return 0; -} - -static struct dentry * -rpc_lookup_negative(char *path, struct nameidata *nd) -{ - struct dentry *dentry; - struct inode *dir; - int error; - - if ((error = rpc_lookup_parent(path, nd)) != 0) - return ERR_PTR(error); - dir = nd->dentry->d_inode; - down(&dir->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); - if (IS_ERR(dentry)) - goto out_err; - if (dentry->d_inode) { - dput(dentry); - dentry = ERR_PTR(-EEXIST); - goto out_err; - } - return dentry; -out_err: - up(&dir->i_sem); - rpc_release_path(nd); - return dentry; -} - - -struct dentry * -rpc_mkdir(char *path, struct rpc_clnt *rpc_client) -{ - struct nameidata nd; - struct dentry *dentry; - struct inode *dir; - int error; - - dentry = rpc_lookup_negative(path, &nd); - if (IS_ERR(dentry)) - return dentry; - dir = nd.dentry->d_inode; - if ((error = __rpc_mkdir(dir, dentry)) != 0) - goto err_dput; RPC_I(dentry->d_inode)->private = rpc_client; + + d_instantiate(dentry, inode); + dget(dentry); + up(&dir->i_sem); + + inode_dir_notify(dir, DN_CREATE); + error = rpc_populate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); if (error) - goto err_depopulate; -out: - up(&dir->i_sem); - rpc_release_path(&nd); + goto out_depopulate; + return dentry; -err_depopulate: - rpc_depopulate(dentry); - __rpc_rmdir(dir, dentry); -err_dput: + + out_depopulate: + rpc_rmdir(dentry); + out_dput: dput(dentry); - printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", - __FILE__, __FUNCTION__, path, error); - dentry = ERR_PTR(error); - goto out; + out_unlock: + up(&dir->i_sem); + rpc_put_mount(); + return dentry; } -int -rpc_rmdir(char *path) +void +rpc_rmdir(struct dentry *dentry) { - struct nameidata nd; - struct dentry *dentry; - struct inode *dir; - int error; + struct dentry *parent = dentry->d_parent; - if ((error = rpc_lookup_parent(path, &nd)) != 0) - return error; - dir = nd.dentry->d_inode; - down(&dir->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - if (IS_ERR(dentry)) { - error = PTR_ERR(dentry); - goto out_release; - } rpc_depopulate(dentry); - error = __rpc_rmdir(dir, dentry); - dput(dentry); -out_release: - up(&dir->i_sem); - rpc_release_path(&nd); - return error; + + down(&parent->d_inode->i_sem); + if (dentry->d_inode) { + rpc_close_pipes(dentry->d_inode); + rpc_inode_setowner(dentry->d_inode, NULL); + simple_rmdir(parent->d_inode, dentry); + } + up(&parent->d_inode->i_sem); + + inode_dir_notify(parent->d_inode, DN_DELETE); + rpc_put_mount(); } struct dentry * -rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) +rpc_mkpipe(struct dentry *parent, char *name, void *private, + struct rpc_pipe_ops *ops, int flags) { - struct nameidata nd; + struct inode *dir = parent->d_inode; struct dentry *dentry; - struct inode *dir, *inode; + struct inode *inode; struct rpc_inode *rpci; + int error; - dentry = rpc_lookup_negative(path, &nd); + error = rpc_get_mount(); + if (error) + return ERR_PTR(error); + + down(&parent->d_inode->i_sem); + dentry = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(dentry)) - return dentry; - dir = nd.dentry->d_inode; - inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR); - if (!inode) - goto err_dput; + goto out_unlock; + if (dentry->d_inode) { + dentry = ERR_PTR(-EEXIST); + goto out_dput; + } + + inode = rpc_get_inode(parent->d_inode->i_sb, + S_IFSOCK | S_IRUSR | S_IWUSR); + if (!inode) { + dentry = ERR_PTR(-ENOMEM); + goto out_dput; + } + inode->i_ino = iunique(dir->i_sb, 100); inode->i_fop = &rpc_pipe_fops; - d_instantiate(dentry, inode); + rpci = RPC_I(inode); rpci->private = private; rpci->flags = flags; rpci->ops = ops; + + d_instantiate(dentry, inode); + dget(dentry); + up(&parent->d_inode->i_sem); + inode_dir_notify(dir, DN_CREATE); -out: - up(&dir->i_sem); - rpc_release_path(&nd); return dentry; -err_dput: + + out_dput: dput(dentry); - dentry = ERR_PTR(-ENOMEM); - printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n", - __FILE__, __FUNCTION__, path, -ENOMEM); - goto out; + out_unlock: + up(&parent->d_inode->i_sem); + rpc_put_mount(); + return dentry; } -int -rpc_unlink(char *path) +void +rpc_unlink(struct dentry *dentry) { - struct nameidata nd; - struct dentry *dentry; - struct inode *dir; - int error; + struct dentry *parent = dentry->d_parent; - if ((error = rpc_lookup_parent(path, &nd)) != 0) - return error; - dir = nd.dentry->d_inode; - down(&dir->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - if (IS_ERR(dentry)) { - error = PTR_ERR(dentry); - goto out_release; - } - d_drop(dentry); + down(&parent->d_inode->i_sem); if (dentry->d_inode) { rpc_close_pipes(dentry->d_inode); rpc_inode_setowner(dentry->d_inode, NULL); - error = simple_unlink(dir, dentry); + simple_unlink(parent->d_inode, dentry); } - dput(dentry); - inode_dir_notify(dir, DN_DELETE); -out_release: - up(&dir->i_sem); - rpc_release_path(&nd); - return error; + up(&parent->d_inode->i_sem); + + inode_dir_notify(parent->d_inode, DN_DELETE); + rpc_put_mount(); } /* From 3063d8a16643190f9e12e9c7e9f1ca56f7e7934e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 25 Aug 2005 16:25:57 -0700 Subject: [PATCH 0183/1939] NFS: Make /proc/mounts display the protocol used by NFSv4 Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 062911e7ceb5..358d8ef8c087 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -595,7 +595,6 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) { NFS_MOUNT_SOFT, ",soft", ",hard" }, { NFS_MOUNT_INTR, ",intr", "" }, { NFS_MOUNT_POSIX, ",posix", "" }, - { NFS_MOUNT_TCP, ",tcp", ",udp" }, { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, @@ -604,6 +603,8 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) }; struct proc_nfs_info *nfs_infop; struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); + char buf[12]; + char *proto; seq_printf(m, ",v%d", nfss->rpc_ops->version); seq_printf(m, ",rsize=%d", nfss->rsize); @@ -622,6 +623,18 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) else seq_puts(m, nfs_infop->nostr); } + switch (nfss->client->cl_xprt->prot) { + case IPPROTO_TCP: + proto = "tcp"; + break; + case IPPROTO_UDP: + proto = "udp"; + break; + default: + snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot); + proto = buf; + } + seq_printf(m, ",proto=%s", proto); seq_puts(m, ",addr="); seq_escape(m, nfss->hostname, " \t\n\\"); return 0; From f134585a7343d71f9be7f0cf97e2145f21dd10c6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 23 Sep 2005 11:08:25 -0400 Subject: [PATCH 0184/1939] Revert "[PATCH] RPC,NFS: new rpc_pipefs patch" This reverts 17f4e6febca160a9f9dd4bdece9784577a2f4524 commit. --- fs/nfs/idmap.c | 10 +- include/linux/sunrpc/clnt.h | 2 +- include/linux/sunrpc/rpc_pipe_fs.h | 9 +- net/sunrpc/auth_gss/auth_gss.c | 9 +- net/sunrpc/clnt.c | 53 ++---- net/sunrpc/rpc_pipe.c | 282 ++++++++++++++++++----------- 6 files changed, 216 insertions(+), 149 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 1d0a5bf0d264..ffb8df91dc34 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -66,6 +66,7 @@ struct idmap_hashtable { }; struct idmap { + char idmap_path[48]; struct dentry *idmap_dentry; wait_queue_head_t idmap_wq; struct idmap_msg idmap_im; @@ -101,8 +102,11 @@ nfs_idmap_new(struct nfs4_client *clp) memset(idmap, 0, sizeof(*idmap)); - idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, - "idmap", idmap, &idmap_upcall_ops, 0); + snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), + "%s/idmap", clp->cl_rpcclient->cl_pathname); + + idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, + idmap, &idmap_upcall_ops, 0); if (IS_ERR(idmap->idmap_dentry)) { kfree(idmap); return; @@ -124,7 +128,7 @@ nfs_idmap_delete(struct nfs4_client *clp) if (!idmap) return; - rpc_unlink(idmap->idmap_dentry); + rpc_unlink(idmap->idmap_path); clp->cl_idmap = NULL; kfree(idmap); } diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index b5b51c196690..ab151bbb66df 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -59,7 +59,7 @@ struct rpc_clnt { int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME]; - struct dentry * __cl_parent_dentry; + char cl_pathname[30];/* Path in rpc_pipe_fs */ struct dentry * cl_dentry; /* inode */ struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 63878d05c9a9..63929349571f 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -41,11 +41,10 @@ RPC_I(struct inode *inode) extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); -extern struct dentry *rpc_mkdir(struct dentry *, char *, struct rpc_clnt *); -extern void rpc_rmdir(struct dentry *); -extern struct dentry *rpc_mkpipe(struct dentry *, char *, void *, - struct rpc_pipe_ops *, int flags); -extern void rpc_unlink(struct dentry *); +extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); +extern int rpc_rmdir(char *); +extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); +extern int rpc_unlink(char *); #endif #endif diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index bd2555139fa9..d2b08f16c257 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -87,6 +87,7 @@ struct gss_auth { struct list_head upcalls; struct rpc_clnt *client; struct dentry *dentry; + char path[48]; spinlock_t lock; }; @@ -689,8 +690,10 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) if (err) goto err_put_mech; - gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, - clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); + snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", + clnt->cl_pathname, + gss_auth->mech->gm_name); + gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); if (IS_ERR(gss_auth->dentry)) { err = PTR_ERR(gss_auth->dentry); goto err_put_mech; @@ -715,7 +718,7 @@ gss_destroy(struct rpc_auth *auth) auth, auth->au_flavor); gss_auth = container_of(auth, struct gss_auth, rpc_auth); - rpc_unlink(gss_auth->dentry); + rpc_unlink(gss_auth->path); gss_mech_put(gss_auth->mech); rpcauth_free_credcache(auth); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 63bf591310e0..5a8f01d726e9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -67,42 +67,26 @@ static u32 * call_verify(struct rpc_task *task); static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { - static unsigned int clntid; - char name[128]; + static uint32_t clntid; int error; if (dir_name == NULL) return 0; - - retry_parent: - clnt->__cl_parent_dentry = rpc_mkdir(NULL, dir_name, NULL); - if (IS_ERR(clnt->__cl_parent_dentry)) { - error = PTR_ERR(clnt->__cl_parent_dentry); - if (error == -EEXIST) - goto retry_parent; /* XXX(hch): WTF? */ - - printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", - dir_name, error); - return error; - } - - - retry_child: - snprintf(name, sizeof(name), "clnt%x", clntid++); - name[sizeof(name) - 1] = '\0'; - - clnt->cl_dentry = rpc_mkdir(clnt->__cl_parent_dentry, name, clnt); - if (IS_ERR(clnt->cl_dentry)) { + for (;;) { + snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), + "%s/clnt%x", dir_name, + (unsigned int)clntid++); + clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; + clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt); + if (!IS_ERR(clnt->cl_dentry)) + return 0; error = PTR_ERR(clnt->cl_dentry); - if (error == -EEXIST) - goto retry_child; - printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", - name, error); - rpc_rmdir(clnt->__cl_parent_dentry); - return error; + if (error != -EEXIST) { + printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", + clnt->cl_pathname, error); + return error; + } } - - return 0; } /* @@ -190,8 +174,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, return clnt; out_no_auth: - rpc_rmdir(clnt->cl_dentry); - rpc_rmdir(clnt->__cl_parent_dentry); + rpc_rmdir(clnt->cl_pathname); out_no_path: if (clnt->cl_server != clnt->cl_inline_name) kfree(clnt->cl_server); @@ -319,10 +302,8 @@ rpc_destroy_client(struct rpc_clnt *clnt) rpc_destroy_client(clnt->cl_parent); goto out_free; } - if (clnt->cl_dentry) - rpc_rmdir(clnt->cl_dentry); - if (clnt->__cl_parent_dentry) - rpc_rmdir(clnt->__cl_parent_dentry); + if (clnt->cl_pathname[0]) + rpc_rmdir(clnt->cl_pathname); if (clnt->cl_xprt) { xprt_destroy(clnt->cl_xprt); clnt->cl_xprt = NULL; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b382809726d8..ded6c63f11ec 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -414,6 +414,38 @@ rpc_put_mount(void) simple_release_fs(&rpc_mount, &rpc_mount_count); } +static int +rpc_lookup_parent(char *path, struct nameidata *nd) +{ + if (path[0] == '\0') + return -ENOENT; + if (rpc_get_mount()) { + printk(KERN_WARNING "%s: %s failed to mount " + "pseudofilesystem \n", __FILE__, __FUNCTION__); + return -ENODEV; + } + nd->mnt = mntget(rpc_mount); + nd->dentry = dget(rpc_mount->mnt_root); + nd->last_type = LAST_ROOT; + nd->flags = LOOKUP_PARENT; + nd->depth = 0; + + if (path_walk(path, nd)) { + printk(KERN_WARNING "%s: %s failed to find path %s\n", + __FILE__, __FUNCTION__, path); + rpc_put_mount(); + return -ENOENT; + } + return 0; +} + +static void +rpc_release_path(struct nameidata *nd) +{ + path_release(nd); + rpc_put_mount(); +} + static struct inode * rpc_get_inode(struct super_block *sb, int mode) { @@ -518,149 +550,197 @@ rpc_populate(struct dentry *parent, return -ENOMEM; } -struct dentry * -rpc_mkdir(struct dentry *parent, char *name, struct rpc_clnt *rpc_client) +static int +__rpc_mkdir(struct inode *dir, struct dentry *dentry) { - struct inode *dir; - struct dentry *dentry; struct inode *inode; - int error; - - if (!parent) - parent = rpc_mount->mnt_root; - - dir = parent->d_inode; - - error = rpc_get_mount(); - if (error) - return ERR_PTR(error); - - down(&dir->i_sem); - dentry = lookup_one_len(name, parent, strlen(name)); - if (IS_ERR(dentry)) - goto out_unlock; - if (dentry->d_inode) { - dentry = ERR_PTR(-EEXIST); - goto out_dput; - } inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); if (!inode) - goto out_dput; + goto out_err; inode->i_ino = iunique(dir->i_sb, 100); - dir->i_nlink++; - RPC_I(dentry->d_inode)->private = rpc_client; - d_instantiate(dentry, inode); - dget(dentry); - up(&dir->i_sem); - + dir->i_nlink++; inode_dir_notify(dir, DN_CREATE); - - error = rpc_populate(dentry, authfiles, - RPCAUTH_info, RPCAUTH_EOF); - if (error) - goto out_depopulate; - - return dentry; - - out_depopulate: - rpc_rmdir(dentry); - out_dput: - dput(dentry); - out_unlock: - up(&dir->i_sem); - rpc_put_mount(); - return dentry; + rpc_get_mount(); + return 0; +out_err: + printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", + __FILE__, __FUNCTION__, dentry->d_name.name); + return -ENOMEM; } -void -rpc_rmdir(struct dentry *dentry) +static int +__rpc_rmdir(struct inode *dir, struct dentry *dentry) { - struct dentry *parent = dentry->d_parent; + int error; - rpc_depopulate(dentry); - - down(&parent->d_inode->i_sem); + shrink_dcache_parent(dentry); if (dentry->d_inode) { rpc_close_pipes(dentry->d_inode); rpc_inode_setowner(dentry->d_inode, NULL); - simple_rmdir(parent->d_inode, dentry); } - up(&parent->d_inode->i_sem); + if ((error = simple_rmdir(dir, dentry)) != 0) + return error; + if (!error) { + inode_dir_notify(dir, DN_DELETE); + d_drop(dentry); + rpc_put_mount(); + } + return 0; +} - inode_dir_notify(parent->d_inode, DN_DELETE); - rpc_put_mount(); +static struct dentry * +rpc_lookup_negative(char *path, struct nameidata *nd) +{ + struct dentry *dentry; + struct inode *dir; + int error; + + if ((error = rpc_lookup_parent(path, nd)) != 0) + return ERR_PTR(error); + dir = nd->dentry->d_inode; + down(&dir->i_sem); + dentry = lookup_hash(&nd->last, nd->dentry); + if (IS_ERR(dentry)) + goto out_err; + if (dentry->d_inode) { + dput(dentry); + dentry = ERR_PTR(-EEXIST); + goto out_err; + } + return dentry; +out_err: + up(&dir->i_sem); + rpc_release_path(nd); + return dentry; +} + + +struct dentry * +rpc_mkdir(char *path, struct rpc_clnt *rpc_client) +{ + struct nameidata nd; + struct dentry *dentry; + struct inode *dir; + int error; + + dentry = rpc_lookup_negative(path, &nd); + if (IS_ERR(dentry)) + return dentry; + dir = nd.dentry->d_inode; + if ((error = __rpc_mkdir(dir, dentry)) != 0) + goto err_dput; + RPC_I(dentry->d_inode)->private = rpc_client; + error = rpc_populate(dentry, authfiles, + RPCAUTH_info, RPCAUTH_EOF); + if (error) + goto err_depopulate; +out: + up(&dir->i_sem); + rpc_release_path(&nd); + return dentry; +err_depopulate: + rpc_depopulate(dentry); + __rpc_rmdir(dir, dentry); +err_dput: + dput(dentry); + printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", + __FILE__, __FUNCTION__, path, error); + dentry = ERR_PTR(error); + goto out; +} + +int +rpc_rmdir(char *path) +{ + struct nameidata nd; + struct dentry *dentry; + struct inode *dir; + int error; + + if ((error = rpc_lookup_parent(path, &nd)) != 0) + return error; + dir = nd.dentry->d_inode; + down(&dir->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out_release; + } + rpc_depopulate(dentry); + error = __rpc_rmdir(dir, dentry); + dput(dentry); +out_release: + up(&dir->i_sem); + rpc_release_path(&nd); + return error; } struct dentry * -rpc_mkpipe(struct dentry *parent, char *name, void *private, - struct rpc_pipe_ops *ops, int flags) +rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) { - struct inode *dir = parent->d_inode; + struct nameidata nd; struct dentry *dentry; - struct inode *inode; + struct inode *dir, *inode; struct rpc_inode *rpci; - int error; - error = rpc_get_mount(); - if (error) - return ERR_PTR(error); - - down(&parent->d_inode->i_sem); - dentry = lookup_one_len(name, parent, strlen(name)); + dentry = rpc_lookup_negative(path, &nd); if (IS_ERR(dentry)) - goto out_unlock; - if (dentry->d_inode) { - dentry = ERR_PTR(-EEXIST); - goto out_dput; - } - - inode = rpc_get_inode(parent->d_inode->i_sb, - S_IFSOCK | S_IRUSR | S_IWUSR); - if (!inode) { - dentry = ERR_PTR(-ENOMEM); - goto out_dput; - } - + return dentry; + dir = nd.dentry->d_inode; + inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR); + if (!inode) + goto err_dput; inode->i_ino = iunique(dir->i_sb, 100); inode->i_fop = &rpc_pipe_fops; - + d_instantiate(dentry, inode); rpci = RPC_I(inode); rpci->private = private; rpci->flags = flags; rpci->ops = ops; - - d_instantiate(dentry, inode); - dget(dentry); - up(&parent->d_inode->i_sem); - inode_dir_notify(dir, DN_CREATE); +out: + up(&dir->i_sem); + rpc_release_path(&nd); return dentry; - - out_dput: +err_dput: dput(dentry); - out_unlock: - up(&parent->d_inode->i_sem); - rpc_put_mount(); - return dentry; + dentry = ERR_PTR(-ENOMEM); + printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n", + __FILE__, __FUNCTION__, path, -ENOMEM); + goto out; } -void -rpc_unlink(struct dentry *dentry) +int +rpc_unlink(char *path) { - struct dentry *parent = dentry->d_parent; + struct nameidata nd; + struct dentry *dentry; + struct inode *dir; + int error; - down(&parent->d_inode->i_sem); + if ((error = rpc_lookup_parent(path, &nd)) != 0) + return error; + dir = nd.dentry->d_inode; + down(&dir->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out_release; + } + d_drop(dentry); if (dentry->d_inode) { rpc_close_pipes(dentry->d_inode); rpc_inode_setowner(dentry->d_inode, NULL); - simple_unlink(parent->d_inode, dentry); + error = simple_unlink(dir, dentry); } - up(&parent->d_inode->i_sem); - - inode_dir_notify(parent->d_inode, DN_DELETE); - rpc_put_mount(); + dput(dentry); + inode_dir_notify(dir, DN_DELETE); +out_release: + up(&dir->i_sem); + rpc_release_path(&nd); + return error; } /* From 463eb297401eeb174db3fdf37a87911b576b3993 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 23 Sep 2005 11:39:07 -0600 Subject: [PATCH 0185/1939] [IA64] respect ACPI producer/consumer flag for PCI root bridges Address space resources for ACPI devices have a producer/consumer flag. All devices "consume" the indicated address space. If the resource is marked as a "producer", the range is also passed on to child devices. We currently ignore this flag when setting up MMIO and I/O port windows for PCI root bridges, so we could mistakenly interpret a "consumed-only" range, like CSR space for the device itself, as a window that is routed to children. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/pci/pci.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 9b5de589b82f..564319e29bd5 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -191,6 +191,29 @@ add_io_space (struct acpi_resource_address64 *addr) return IO_SPACE_BASE(i); } +static acpi_status __devinit resource_to_window(struct acpi_resource *resource, + struct acpi_resource_address64 *addr) +{ + acpi_status status; + + /* + * We're only interested in _CRS descriptors that are + * - address space descriptors for memory or I/O space + * - non-zero size + * - producers, i.e., the address space is routed downstream, + * not consumed by the bridge itself + */ + status = acpi_resource_to_address64(resource, addr); + if (ACPI_SUCCESS(status) && + (addr->resource_type == ACPI_MEMORY_RANGE || + addr->resource_type == ACPI_IO_RANGE) && + addr->address_length && + addr->producer_consumer == ACPI_PRODUCER) + return AE_OK; + + return AE_ERROR; +} + static acpi_status __devinit count_window (struct acpi_resource *resource, void *data) { @@ -198,11 +221,9 @@ count_window (struct acpi_resource *resource, void *data) struct acpi_resource_address64 addr; acpi_status status; - status = acpi_resource_to_address64(resource, &addr); + status = resource_to_window(resource, &addr); if (ACPI_SUCCESS(status)) - if (addr.resource_type == ACPI_MEMORY_RANGE || - addr.resource_type == ACPI_IO_RANGE) - (*windows)++; + (*windows)++; return AE_OK; } @@ -221,13 +242,11 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data) unsigned long flags, offset = 0; struct resource *root; - status = acpi_resource_to_address64(res, &addr); + /* Return AE_OK for non-window resources to keep scanning for more */ + status = resource_to_window(res, &addr); if (!ACPI_SUCCESS(status)) return AE_OK; - if (!addr.address_length) - return AE_OK; - if (addr.resource_type == ACPI_MEMORY_RANGE) { flags = IORESOURCE_MEM; root = &iomem_resource; From 6cd7525a00f3b926e8bd2e402954ed3e09a8e924 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 22 Sep 2005 21:24:59 -0400 Subject: [PATCH 0186/1939] SUNRPC: fix bug in patch "portmapper doesn't need a reserved port" The in-kernel portmapper does in fact need a reserved port when registering new services, but not when performing bind queries. Ensure that we distinguish between the two cases. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/pmap_clnt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index d8e3f220002b..a398575f94b8 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -26,7 +26,7 @@ #define PMAP_GETPORT 3 static struct rpc_procinfo pmap_procedures[]; -static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int); +static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int); static void pmap_getport_done(struct rpc_task *); static struct rpc_program pmap_program; static DEFINE_SPINLOCK(pmap_lock); @@ -65,7 +65,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) map->pm_binding = 1; spin_unlock(&pmap_lock); - pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot); + pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0); if (IS_ERR(pmap_clnt)) { task->tk_status = PTR_ERR(pmap_clnt); goto bailout; @@ -112,7 +112,7 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); - pmap_clnt = pmap_create(hostname, sin, prot); + pmap_clnt = pmap_create(hostname, sin, prot, 0); if (IS_ERR(pmap_clnt)) return PTR_ERR(pmap_clnt); @@ -171,7 +171,7 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP); + pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); if (IS_ERR(pmap_clnt)) { error = PTR_ERR(pmap_clnt); dprintk("RPC: couldn't create pmap client. Error = %d\n", error); @@ -198,7 +198,7 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) } static struct rpc_clnt * -pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) +pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged) { struct rpc_xprt *xprt; struct rpc_clnt *clnt; @@ -208,7 +208,8 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) if (IS_ERR(xprt)) return (struct rpc_clnt *)xprt; xprt->addr.sin_port = htons(RPC_PMAP_PORT); - xprt->resvport = 0; + if (!privileged) + xprt->resvport = 0; /* printk("pmap: create clnt\n"); */ clnt = rpc_new_client(xprt, hostname, From 61b9cf7c6cf5077c40ad37480fa56f6574af3db5 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Fri, 23 Sep 2005 12:31:53 -0500 Subject: [PATCH 0187/1939] [IA64-SGI] fix sn_pci_legacy_read/fix sn_pci_legacy_write This patch adds a #define for SN_SAL_IOIF_PCI_SAFE and makes that the preferred method of implementing sn_pci_legacy_read() and sn_pci_legacy_write(). This SAL call has been present in SGI proms since version 4.10. If the SN_SAL_IOIF_PCI_SAFE call fails, revert to the previous code for compatability with older proms. Signed-off-by: Mark Maule Signed-off-by: Tony Luck --- arch/ia64/sn/pci/pci_dma.c | 46 ++++++++++++++++++++++++++++++++++++ include/asm-ia64/sn/sn_sal.h | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index 0e4b9ad9ef02..abdf6eea6ac8 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -326,6 +326,29 @@ int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) { unsigned long addr; int ret; + struct ia64_sal_retval isrv; + + /* + * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work + * around hw issues at the pci bus level. SGI proms older than + * 4.10 don't implment this. + */ + + SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, + pci_domain_nr(bus), bus->number, + 0, /* io */ + 0, /* read */ + port, size, __pa(val)); + + if (isrv.status == 0) + return size; + + /* + * If the above failed, retry using the SAL_PROBE call which should + * be present in all proms (but which cannot work round PCI chipset + * bugs). This code is retained for compatability with old + * pre-4.10 proms, and should be removed at some point in the future. + */ if (!SN_PCIBUS_BUSSOFT(bus)) return -ENODEV; @@ -349,6 +372,29 @@ int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) int ret = size; unsigned long paddr; unsigned long *addr; + struct ia64_sal_retval isrv; + + /* + * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work + * around hw issues at the pci bus level. SGI proms older than + * 4.10 don't implment this. + */ + + SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, + pci_domain_nr(bus), bus->number, + 0, /* io */ + 1, /* write */ + port, size, __pa(&val)); + + if (isrv.status == 0) + return size; + + /* + * If the above failed, retry using the SAL_PROBE call which should + * be present in all proms (but which cannot work round PCI chipset + * bugs). This code is retained for compatability with old + * pre-4.10 proms, and should be removed at some point in the future. + */ if (!SN_PCIBUS_BUSSOFT(bus)) { ret = -ENODEV; diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index fea35b33d4e4..b2d32837723f 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -67,7 +67,7 @@ #define SN_SAL_IOIF_INTERRUPT 0x0200004a #define SN_SAL_HWPERF_OP 0x02000050 // lock #define SN_SAL_IOIF_ERROR_INTERRUPT 0x02000051 - +#define SN_SAL_IOIF_PCI_SAFE 0x02000052 #define SN_SAL_IOIF_SLOT_ENABLE 0x02000053 #define SN_SAL_IOIF_SLOT_DISABLE 0x02000054 #define SN_SAL_IOIF_GET_HUBDEV_INFO 0x02000055 From bb40dcbb0fcebe1df08ba261483fcc38b307d063 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 23 Sep 2005 22:54:21 -0400 Subject: [PATCH 0188/1939] [netdrvr gianfar] use new phy layer Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 + drivers/net/Makefile | 2 +- drivers/net/gianfar.c | 412 +++++---------------- drivers/net/gianfar.h | 30 +- drivers/net/gianfar_ethtool.c | 98 +++-- drivers/net/gianfar_mii.c | 219 +++++++++++ drivers/net/gianfar_mii.h | 45 +++ drivers/net/gianfar_phy.c | 661 ---------------------------------- drivers/net/gianfar_phy.h | 213 ----------- 9 files changed, 432 insertions(+), 1250 deletions(-) create mode 100644 drivers/net/gianfar_mii.c create mode 100644 drivers/net/gianfar_mii.h delete mode 100644 drivers/net/gianfar_phy.c delete mode 100644 drivers/net/gianfar_phy.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ff3fccd7513b..4739a63601eb 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2075,6 +2075,8 @@ config SPIDER_NET config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx + select PHYLIB + select PHYCONTROL help This driver supports the Gigabit TSEC on the MPC85xx family of chips, and the FEC on the 8540 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e6acba68923a..39b17cb4f86e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o -gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o # # link order important here diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6518334b9280..ae5a2ed3b264 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -29,12 +29,7 @@ * define the configuration needed by the board are defined in a * board structure in arch/ppc/platforms (though I do not * discount the possibility that other architectures could one - * day be supported. One assumption the driver currently makes - * is that the PHY is configured in such a way to advertise all - * capabilities. This is a sensible default, and on certain - * PHYs, changing this default encounters substantial errata - * issues. Future versions may remove this requirement, but for - * now, it is best for the firmware to ensure this is the case. + * day be supported. * * The Gianfar Ethernet Controller uses a ring of buffer * descriptors. The beginning is indicated by a register @@ -47,7 +42,7 @@ * corresponding bit in the IMASK register is also set (if * interrupt coalescing is active, then the interrupt may not * happen immediately, but will wait until either a set number - * of frames or amount of time have passed.). In NAPI, the + * of frames or amount of time have passed). In NAPI, the * interrupt handler will signal there is work to be done, and * exit. Without NAPI, the packet(s) will be handled * immediately. Both methods will start at the last known empty @@ -75,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -97,9 +93,11 @@ #include #include #include +#include +#include #include "gianfar.h" -#include "gianfar_phy.h" +#include "gianfar_mii.h" #define TX_TIMEOUT (1*HZ) #define SKB_ALLOC_TIMEOUT 1000000 @@ -113,9 +111,8 @@ #endif const char gfar_driver_name[] = "Gianfar Ethernet"; -const char gfar_driver_version[] = "1.1"; +const char gfar_driver_version[] = "1.2"; -int startup_gfar(struct net_device *dev); static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_timeout(struct net_device *dev); @@ -126,17 +123,13 @@ static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void gfar_phy_change(void *data); -static void gfar_phy_timer(unsigned long data); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); static int gfar_probe(struct device *device); static int gfar_remove(struct device *device); -void free_skb_resources(struct gfar_private *priv); +static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); #ifdef CONFIG_GFAR_NAPI @@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); -static void gfar_phy_startup_timer(unsigned long data); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); @@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv) else return 0; } + +/* Set up the ethernet device structure, private data, + * and anything else we need before we start */ static int gfar_probe(struct device *device) { u32 tempval; @@ -175,7 +170,7 @@ static int gfar_probe(struct device *device) einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; - if (einfo == NULL) { + if (NULL == einfo) { printk(KERN_ERR "gfar %d: Missing additional data!\n", pdev->id); @@ -185,7 +180,7 @@ static int gfar_probe(struct device *device) /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof (*priv)); - if (dev == NULL) + if (NULL == dev) return -ENOMEM; priv = netdev_priv(dev); @@ -207,20 +202,11 @@ static int gfar_probe(struct device *device) priv->regs = (struct gfar *) ioremap(r->start, sizeof (struct gfar)); - if (priv->regs == NULL) { + if (NULL == priv->regs) { err = -ENOMEM; goto regs_fail; } - /* Set the PHY base address */ - priv->phyregs = (struct gfar *) - ioremap(einfo->phy_reg_addr, sizeof (struct gfar)); - - if (priv->phyregs == NULL) { - err = -ENOMEM; - goto phy_regs_fail; - } - spin_lock_init(&priv->lock); dev_set_drvdata(device, dev); @@ -386,12 +372,10 @@ static int gfar_probe(struct device *device) return 0; register_fail: - iounmap((void *) priv->phyregs); -phy_regs_fail: iounmap((void *) priv->regs); regs_fail: free_netdev(dev); - return -ENOMEM; + return err; } static int gfar_remove(struct device *device) @@ -402,108 +386,41 @@ static int gfar_remove(struct device *device) dev_set_drvdata(device, NULL); iounmap((void *) priv->regs); - iounmap((void *) priv->phyregs); free_netdev(dev); return 0; } -/* Configure the PHY for dev. - * returns 0 if success. -1 if failure +/* Initializes driver's PHY state, and attaches to the PHY. + * Returns 0 on success. */ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct phy_info *curphy; - unsigned int timeout = PHY_INIT_TIMEOUT; - struct gfar *phyregs = priv->phyregs; - struct gfar_mii_info *mii_info; - int err; + uint gigabit_support = + priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? + SUPPORTED_1000baseT_Full : 0; + struct phy_device *phydev; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - mii_info = kmalloc(sizeof(struct gfar_mii_info), - GFP_KERNEL); + phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0); - if(NULL == mii_info) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate mii_info\n", - dev->name); - return -ENOMEM; + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); } - mii_info->speed = SPEED_1000; - mii_info->duplex = DUPLEX_FULL; - mii_info->pause = 0; - mii_info->link = 1; + /* Remove any features not supported by the controller */ + phydev->supported &= (GFAR_SUPPORTED | gigabit_support); + phydev->advertising = phydev->supported; - mii_info->advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full); - mii_info->autoneg = 1; - - spin_lock_init(&mii_info->mdio_lock); - - mii_info->mii_id = priv->einfo->phyid; - - mii_info->dev = dev; - - mii_info->mdio_read = &read_phy_reg; - mii_info->mdio_write = &write_phy_reg; - - priv->mii_info = mii_info; - - /* Reset the management interface */ - gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); - - /* Setup the MII Mgmt clock speed */ - gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - - /* Wait until the bus is free */ - while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && - timeout--) - cpu_relax(); - - if(timeout <= 0) { - printk(KERN_ERR "%s: The MII Bus is stuck!\n", - dev->name); - err = -1; - goto bus_fail; - } - - /* get info for this PHY */ - curphy = get_phy_info(priv->mii_info); - - if (curphy == NULL) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: No PHY found\n", dev->name); - err = -1; - goto no_phy; - } - - mii_info->phyinfo = curphy; - - /* Run the commands which initialize the PHY */ - if(curphy->init) { - err = curphy->init(priv->mii_info); - - if (err) - goto phy_init_fail; - } + priv->phydev = phydev; return 0; - -phy_init_fail: -no_phy: -bus_fail: - kfree(mii_info); - - return err; } static void init_registers(struct net_device *dev) @@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev) struct gfar *regs = priv->regs; unsigned long flags; + phy_stop(priv->phydev); + /* Lock it down */ spin_lock_irqsave(&priv->lock, flags); - /* Tell the kernel the link is down */ - priv->mii_info->link = 0; - adjust_link(dev); - gfar_halt(dev); - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - /* Clear any pending interrupts */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY Interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - } - spin_unlock_irqrestore(&priv->lock, flags); /* Free the IRQs */ @@ -629,13 +535,7 @@ void stop_gfar(struct net_device *dev) free_irq(priv->interruptTransmit, dev); free_irq(priv->interruptReceive, dev); } else { - free_irq(priv->interruptTransmit, dev); - } - - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - free_irq(priv->einfo->interruptPHY, dev); - } else { - del_timer_sync(&priv->phy_info_timer); + free_irq(priv->interruptTransmit, dev); } free_skb_resources(priv); @@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev) /* If there are any tx skbs or rx skbs still around, free them. * Then free tx_skbuff and rx_skbuff */ -void free_skb_resources(struct gfar_private *priv) +static void free_skb_resources(struct gfar_private *priv) { struct rxbd8 *rxbdp; struct txbd8 *txbdp; @@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->tx_ring_size, GFP_KERNEL); - if (priv->tx_skbuff == NULL) { + if (NULL == priv->tx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", dev->name); @@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->rx_ring_size, GFP_KERNEL); - if (priv->rx_skbuff == NULL) { + if (NULL == priv->rx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", dev->name); @@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev) } } - /* Set up the PHY change work queue */ - INIT_WORK(&priv->tq, gfar_phy_change, dev); - - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_startup_timer; - priv->phy_info_timer.data = (unsigned long) priv->mii_info; - mod_timer(&priv->phy_info_timer, jiffies + HZ); + phy_start(priv->phydev); /* Configure the coalescing support */ if (priv->txcoalescing) @@ -933,11 +827,6 @@ int startup_gfar(struct net_device *dev) priv->tx_bd_base, gfar_read(®s->tbase0)); - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); - return err; } @@ -1035,7 +924,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp->status &= TXBD_WRAP; /* Set up checksumming */ - if ((dev->features & NETIF_F_IP_CSUM) + if ((dev->features & NETIF_F_IP_CSUM) && (CHECKSUM_HW == skb->ip_summed)) { fcb = gfar_add_fcb(skb, txbdp); gfar_tx_checksum(skb, fcb); @@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); stop_gfar(dev); - /* Shutdown the PHY */ - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); + /* Disconnect from the PHY */ + phy_disconnect(priv->phydev); + priv->phydev = NULL; netif_stop_queue(dev); @@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) while ((!skb) && timeout--) skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (skb == NULL) + if (NULL == skb) return NULL; /* We need the data buffer to be aligned properly. We will reserve @@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; - if (skb == NULL) { + if (NULL == skb) { if (netif_msg_rx_err(priv)) printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); priv->stats.rx_dropped++; @@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); - - /* Clear the interrupt */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - - /* Schedule the phy change */ - schedule_work(&priv->tq); - - return IRQ_HANDLED; -} - -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void gfar_phy_change(void *data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - int result = 0; - - /* Delay to give the PHY a chance to change the - * register state */ - msleep(1); - - /* Update the link, speed, duplex */ - result = priv->mii_info->phyinfo->read_status(priv->mii_info); - - /* Adjust the known status as long as the link - * isn't still coming up */ - if((0 == result) || (priv->mii_info->link == 0)) - adjust_link(dev); - - /* Reenable interrupts, if needed */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); -} - -/* Called every so often on systems that don't interrupt - * the core for PHY changes */ -static void gfar_phy_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - - schedule_work(&priv->tq); - - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - -/* Keep trying aneg for some time - * If, after GFAR_AN_TIMEOUT seconds, it has not - * finished, we switch to forced. - * Either way, once the process has completed, we either - * request the interrupt, or switch the timer over to - * using gfar_phy_timer to check status */ -static void gfar_phy_startup_timer(unsigned long data) -{ - int result; - static int secondary = GFAR_AN_TIMEOUT; - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct gfar_private *priv = netdev_priv(mii_info->dev); - - /* Configure the Auto-negotiation */ - result = mii_info->phyinfo->config_aneg(mii_info); - - /* If autonegotiation failed to start, and - * we haven't timed out, reset the timer, and return */ - if (result && secondary--) { - mod_timer(&priv->phy_info_timer, jiffies + HZ); - return; - } else if (result) { - /* Couldn't start autonegotiation. - * Try switching to forced */ - mii_info->autoneg = 0; - result = mii_info->phyinfo->config_aneg(mii_info); - - /* Forcing failed! Give up */ - if(result) { - if (netif_msg_link(priv)) - printk(KERN_ERR "%s: Forcing failed!\n", - mii_info->dev->name); - return; - } - } - - /* Kill the timer so it can be restarted */ - del_timer_sync(&priv->phy_info_timer); - - /* Grab the PHY interrupt, if necessary/possible */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - if (request_irq(priv->einfo->interruptPHY, - phy_interrupt, - SA_SHIRQ, - "phy_interrupt", - mii_info->dev) < 0) { - if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", - mii_info->dev->name, - priv->einfo->interruptPHY); - } else { - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); - return; - } - } - - /* Start the timer again, this time in order to - * handle a change in status */ - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_timer; - priv->phy_info_timer.data = (unsigned long) mii_info->dev; - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this - * information through variables in the priv structure, and this + * information through variables in the phydev structure, and this * function converts those variables into the appropriate * register values, and can bring down the device if needed. */ @@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar *regs = priv->regs; - u32 tempval; - struct gfar_mii_info *mii_info = priv->mii_info; + unsigned long flags; + struct phy_device *phydev = priv->phydev; + int new_state = 0; + + spin_lock_irqsave(&priv->lock, flags); + if (phydev->link) { + u32 tempval = gfar_read(®s->maccfg2); - if (mii_info->link) { /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (mii_info->duplex != priv->oldduplex) { - if (!(mii_info->duplex)) { - tempval = gfar_read(®s->maccfg2); + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) tempval &= ~(MACCFG2_FULL_DUPLEX); - gfar_write(®s->maccfg2, tempval); - - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Half Duplex\n", - dev->name); - } else { - tempval = gfar_read(®s->maccfg2); + else tempval |= MACCFG2_FULL_DUPLEX; - gfar_write(®s->maccfg2, tempval); - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Full Duplex\n", - dev->name); - } - - priv->oldduplex = mii_info->duplex; + priv->oldduplex = phydev->duplex; } - if (mii_info->speed != priv->oldspeed) { - switch (mii_info->speed) { + if (phydev->speed != priv->oldspeed) { + new_state = 1; + switch (phydev->speed) { case 1000: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); - gfar_write(®s->maccfg2, tempval); break; case 100: case 10: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); - gfar_write(®s->maccfg2, tempval); break; default: if (netif_msg_link(priv)) printk(KERN_WARNING - "%s: Ack! Speed (%d) is not 10/100/1000!\n", - dev->name, mii_info->speed); + "%s: Ack! Speed (%d) is not 10/100/1000!\n", + dev->name, phydev->speed); break; } - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Speed %dBT\n", dev->name, - mii_info->speed); - - priv->oldspeed = mii_info->speed; + priv->oldspeed = phydev->speed; } + gfar_write(®s->maccfg2, tempval); + if (!priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is up\n", dev->name); + new_state = 1; priv->oldlink = 1; - netif_carrier_on(dev); netif_schedule(dev); } - } else { - if (priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is down\n", - dev->name); - priv->oldlink = 0; - priv->oldspeed = 0; - priv->oldduplex = -1; - netif_carrier_off(dev); - } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; } -} + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + spin_unlock_irqrestore(&priv->lock, flags); +} /* Update the hash table based on the current list of multicast * addresses we subscribe to. Also, change the promiscuity of @@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = { static int __init gfar_init(void) { - return driver_register(&gfar_driver); + int err = gfar_mdio_init(); + + if (err) + return err; + + err = driver_register(&gfar_driver); + + if (err) + gfar_mdio_exit(); + + return err; } static void __exit gfar_exit(void) { driver_unregister(&gfar_driver); + gfar_mdio_exit(); } module_init(gfar_init); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 28af087d9fbb..c77ca6c0d04a 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -17,7 +17,6 @@ * * Still left to do: * -Add support for module parameters - * -Add support for ethtool -s * -Add patch for ethtool phys id */ #ifndef __GIANFAR_H @@ -37,7 +36,8 @@ #include #include #include -#include +#include +#include #include #include @@ -48,7 +48,8 @@ #include #include #include -#include "gianfar_phy.h" +#include +#include "gianfar_mii.h" /* The maximum number of packets to be handled in one call of gfar_poll */ #define GFAR_DEV_WEIGHT 64 @@ -73,7 +74,7 @@ #define PHY_INIT_TIMEOUT 100000 #define GFAR_PHY_CHANGE_TIME 2 -#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, " #define DRV_NAME "gfar-enet" extern const char gfar_driver_name[]; extern const char gfar_driver_version[]; @@ -578,12 +579,7 @@ struct gfar { u32 hafdup; /* 0x.50c - Half Duplex Register */ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ u8 res18[12]; - u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ - u32 miimcom; /* 0x.524 - MII Management Command Register */ - u32 miimadd; /* 0x.528 - MII Management Address Register */ - u32 miimcon; /* 0x.52c - MII Management Control Register */ - u32 miimstat; /* 0x.530 - MII Management Status Register */ - u32 miimind; /* 0x.534 - MII Management Indicator Register */ + u8 gfar_mii_regs[24]; /* See gianfar_phy.h */ u8 res19[4]; u32 ifstat; /* 0x.53c - Interface Status Register */ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ @@ -688,9 +684,6 @@ struct gfar_private { struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ u32 *hash_regs[16]; int hash_width; - struct gfar *phyregs; - struct work_struct tq; - struct timer_list phy_info_timer; struct net_device_stats stats; /* linux network statistics */ struct gfar_extra_stats extra_stats; spinlock_t lock; @@ -710,7 +703,8 @@ struct gfar_private { unsigned int interruptError; struct gianfar_platform_data *einfo; - struct gfar_mii_info *mii_info; + struct phy_device *phydev; + struct mii_bus *mii_bus; int oldspeed; int oldduplex; int oldlink; @@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val) extern struct ethtool_ops *gfar_op_array[]; +extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +extern int startup_gfar(struct net_device *dev); +extern void stop_gfar(struct net_device *dev); +extern void gfar_halt(struct net_device *dev); +extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, + int enable, u32 regnum, u32 read); +void gfar_setup_stashing(struct net_device *dev); + #endif /* __GIANFAR_H */ diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index a451de629197..68e3578e7613 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -39,17 +39,18 @@ #include #include #include +#include +#include #include "gianfar.h" #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) -extern int startup_gfar(struct net_device *dev); -extern void stop_gfar(struct net_device *dev); -extern void gfar_halt(struct net_device *dev); extern void gfar_start(struct net_device *dev); extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +#define GFAR_MAX_COAL_USECS 0xffff +#define GFAR_MAX_COAL_FRAMES 0xff static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf); static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); @@ -182,38 +183,32 @@ static void gfar_gdrvinfo(struct net_device *dev, struct drvinfo->eedump_len = 0; } + +static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + + if (NULL == phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); +} + + /* Return the current settings in the ethtool_cmd structure */ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gfar_private *priv = netdev_priv(dev); - uint gigabit_support = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - SUPPORTED_1000baseT_Full : 0; - uint gigabit_advert = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - ADVERTISED_1000baseT_Full: 0; + struct phy_device *phydev = priv->phydev; - cmd->supported = (SUPPORTED_10baseT_Half - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | gigabit_support | SUPPORTED_Autoneg); - - /* For now, we always advertise everything */ - cmd->advertising = (ADVERTISED_10baseT_Half - | ADVERTISED_100baseT_Half - | ADVERTISED_100baseT_Full - | gigabit_advert | ADVERTISED_Autoneg); - - cmd->speed = priv->mii_info->speed; - cmd->duplex = priv->mii_info->duplex; - cmd->port = PORT_MII; - cmd->phy_address = priv->mii_info->mii_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = AUTONEG_ENABLE; + if (NULL == phydev) + return -ENODEV; + cmd->maxtxpkt = priv->txcount; cmd->maxrxpkt = priv->rxcount; - return 0; + return phy_ethtool_gset(phydev, cmd); } /* Return the length of the register structure */ @@ -241,14 +236,14 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -265,14 +260,14 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -292,6 +287,9 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; + if (NULL == priv->phydev) + return -ENODEV; + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); cvals->rx_max_coalesced_frames = priv->rxcount; @@ -348,6 +346,22 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->rxcoalescing = 1; + if (NULL == priv->phydev) + return -ENODEV; + + /* Check the bounds of the values */ + if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); priv->rxcount = cvals->rx_max_coalesced_frames; @@ -358,6 +372,19 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->txcoalescing = 1; + /* Check the bounds of the values */ + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); priv->txcount = cvals->tx_max_coalesced_frames; @@ -536,6 +563,7 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data) struct ethtool_ops gfar_ethtool_ops = { .get_settings = gfar_gsettings, + .set_settings = gfar_ssettings, .get_drvinfo = gfar_gdrvinfo, .get_regs_len = gfar_reglen, .get_regs = gfar_get_regs, diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c new file mode 100644 index 000000000000..1eca1dbca7f1 --- /dev/null +++ b/drivers/net/gianfar_mii.c @@ -0,0 +1,219 @@ +/* + * drivers/net/gianfar_mii.c + * + * Gianfar Ethernet Driver -- MIIM bus implementation + * Provides Bus interface for MIIM regs + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-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. + * + */ + +#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 "gianfar.h" +#include "gianfar_mii.h" + +/* Write value to the PHY at mii_id at register regnum, + * on the bus, waiting until the write is done before returning. + * All PHY configuration is done through the TSEC1 MIIM regs */ +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) +{ + struct gfar_mii *regs = bus->priv; + + /* Set the PHY address and the register address we want to write */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Write out the value we want */ + gfar_write(®s->miimcon, value); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & MIIMIND_BUSY) + cpu_relax(); + + return 0; +} + +/* Read the bus for PHY at addr mii_id, register regnum, and + * return the value. Clears miimcom first. All PHY + * configuration has to be done through the TSEC1 MIIM regs */ +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct gfar_mii *regs = bus->priv; + u16 value; + + /* Set the PHY address and the register address we want to read */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Clear miimcom, and then initiate a read */ + gfar_write(®s->miimcom, 0); + gfar_write(®s->miimcom, MII_READ_COMMAND); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + cpu_relax(); + + /* Grab the value of the register from miimstat */ + value = gfar_read(®s->miimstat); + + return value; +} + + +/* Reset the MIIM registers, and wait for the bus to free */ +int gfar_mdio_reset(struct mii_bus *bus) +{ + struct gfar_mii *regs = bus->priv; + unsigned int timeout = PHY_INIT_TIMEOUT; + + spin_lock_bh(&bus->mdio_lock); + + /* Reset the management interface */ + gfar_write(®s->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while ((gfar_read(®s->miimind) & MIIMIND_BUSY) && + timeout--) + cpu_relax(); + + spin_unlock_bh(&bus->mdio_lock); + + if(timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", + bus->name); + return -EBUSY; + } + + return 0; +} + + +int gfar_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gianfar_mdio_data *pdata; + struct gfar_mii *regs; + struct mii_bus *new_bus; + int err = 0; + + if (NULL == dev) + return -EINVAL; + + new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + new_bus->name = "Gianfar MII Bus", + new_bus->read = &gfar_mdio_read, + new_bus->write = &gfar_mdio_write, + new_bus->reset = &gfar_mdio_reset, + new_bus->id = pdev->id; + + pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /* Set the PHY base address */ + regs = (struct gfar_mii *) ioremap(pdata->paddr, + sizeof (struct gfar_mii)); + + if (NULL == regs) { + err = -ENOMEM; + goto reg_map_fail; + } + + new_bus->priv = regs; + + new_bus->irq = pdata->irq; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + iounmap((void *) regs); +reg_map_fail: + kfree(new_bus); + + return err; +} + + +int gfar_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + + iounmap((void *) (&bus->priv)); + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver gianfar_mdio_driver = { + .name = "fsl-gianfar_mdio", + .bus = &platform_bus_type, + .probe = gfar_mdio_probe, + .remove = gfar_mdio_remove, +}; + +int __init gfar_mdio_init(void) +{ + return driver_register(&gianfar_mdio_driver); +} + +void __exit gfar_mdio_exit(void) +{ + driver_unregister(&gianfar_mdio_driver); +} diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h new file mode 100644 index 000000000000..56e5665d5c9b --- /dev/null +++ b/drivers/net/gianfar_mii.h @@ -0,0 +1,45 @@ +/* + * drivers/net/gianfar_mii.h + * + * Gianfar Ethernet Driver -- MII Management Bus Implementation + * Driver for the MDIO bus controller in the Gianfar register space + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-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 __GIANFAR_MII_H +#define __GIANFAR_MII_H + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define MII_READ_COMMAND 0x00000001 + +#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ + | SUPPORTED_100baseT_Half \ + | SUPPORTED_100baseT_Full \ + | SUPPORTED_Autoneg \ + | SUPPORTED_MII) + +struct gfar_mii { + u32 miimcfg; /* 0x.520 - MII Management Config Register */ + u32 miimcom; /* 0x.524 - MII Management Command Register */ + u32 miimadd; /* 0x.528 - MII Management Address Register */ + u32 miimcon; /* 0x.52c - MII Management Control Register */ + u32 miimstat; /* 0x.530 - MII Management Status Register */ + u32 miimind; /* 0x.534 - MII Management Indicator Register */ +}; + +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum); +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); +int __init gfar_mdio_init(void); +void __exit gfar_mdio_exit(void); +#endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c deleted file mode 100644 index 7c965f268a82..000000000000 --- a/drivers/net/gianfar_phy.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * drivers/net/gianfar_phy.c - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "gianfar.h" -#include "gianfar_phy.h" - -static void config_genmii_advert(struct gfar_mii_info *mii_info); -static void genmii_setup_forced(struct gfar_mii_info *mii_info); -static void genmii_restart_aneg(struct gfar_mii_info *mii_info); -static int gbit_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_update_link(struct gfar_mii_info *mii_info); -static int genmii_read_status(struct gfar_mii_info *mii_info); -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - - /* Set the PHY address and the register address we want to write */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Write out the value we want */ - gfar_write(®base->miimcon, value); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & MIIMIND_BUSY) - cpu_relax(); -} - -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int read_phy_reg(struct net_device *dev, int mii_id, int regnum) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - u16 value; - - /* Set the PHY address and the register address we want to read */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Clear miimcom, and then initiate a read */ - gfar_write(®base->miimcom, 0); - gfar_write(®base->miimcom, MII_READ_COMMAND); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) - cpu_relax(); - - /* Grab the value of the register from miimstat */ - value = gfar_read(®base->miimstat); - - return value; -} - -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) -{ - if(mii_info->phyinfo->ack_interrupt) - mii_info->phyinfo->ack_interrupt(mii_info); -} - - -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) -{ - mii_info->interrupts = interrupts; - if(mii_info->phyinfo->config_intr) - mii_info->phyinfo->config_intr(mii_info); -} - - -/* Writes MII_ADVERTISE with the appropriate values, after - * sanitizing advertise to make sure only supported features - * are advertised - */ -static void config_genmii_advert(struct gfar_mii_info *mii_info) -{ - u32 advertise; - u16 adv; - - /* Only allow advertising what this PHY supports */ - mii_info->advertising &= mii_info->phyinfo->features; - advertise = mii_info->advertising; - - /* Setup standard advertisement */ - adv = phy_read(mii_info, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - phy_write(mii_info, MII_ADVERTISE, adv); -} - -static void genmii_setup_forced(struct gfar_mii_info *mii_info) -{ - u16 ctrl; - u32 features = mii_info->phyinfo->features; - - ctrl = phy_read(mii_info, MII_BMCR); - - ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); - ctrl |= BMCR_RESET; - - switch(mii_info->speed) { - case SPEED_1000: - if(features & (SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full)) { - ctrl |= BMCR_SPEED1000; - break; - } - mii_info->speed = SPEED_100; - case SPEED_100: - if (features & (SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full)) { - ctrl |= BMCR_SPEED100; - break; - } - mii_info->speed = SPEED_10; - case SPEED_10: - if (features & (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full)) - break; - default: /* Unsupported speed! */ - printk(KERN_ERR "%s: Bad speed!\n", - mii_info->dev->name); - break; - } - - phy_write(mii_info, MII_BMCR, ctrl); -} - - -/* Enable and Restart Autonegotiation */ -static void genmii_restart_aneg(struct gfar_mii_info *mii_info) -{ - u16 ctl; - - ctl = phy_read(mii_info, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(mii_info, MII_BMCR, ctl); -} - - -static int gbit_config_aneg(struct gfar_mii_info *mii_info) -{ - u16 adv; - u32 advertise; - - if(mii_info->autoneg) { - /* Configure the ADVERTISE register */ - config_genmii_advert(mii_info); - advertise = mii_info->advertising; - - adv = phy_read(mii_info, MII_1000BASETCONTROL); - adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | - MII_1000BASETCONTROL_HALFDUPLEXCAP); - if (advertise & SUPPORTED_1000baseT_Half) - adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; - if (advertise & SUPPORTED_1000baseT_Full) - adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; - phy_write(mii_info, MII_1000BASETCONTROL, adv); - - /* Start/Restart aneg */ - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - -static int marvell_config_aneg(struct gfar_mii_info *mii_info) -{ - /* The Marvell PHY has an errata which requires - * that certain registers get written in order - * to restart autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_RESET); - - phy_write(mii_info, 0x1d, 0x1f); - phy_write(mii_info, 0x1e, 0x200c); - phy_write(mii_info, 0x1d, 0x5); - phy_write(mii_info, 0x1e, 0); - phy_write(mii_info, 0x1e, 0x100); - - gbit_config_aneg(mii_info); - - return 0; -} -static int genmii_config_aneg(struct gfar_mii_info *mii_info) -{ - if (mii_info->autoneg) { - config_genmii_advert(mii_info); - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - - -static int genmii_update_link(struct gfar_mii_info *mii_info) -{ - u16 status; - - /* Do a fake read */ - phy_read(mii_info, MII_BMSR); - - /* Read link and autonegotiation status */ - status = phy_read(mii_info, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - mii_info->link = 0; - else - mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return -EAGAIN; - - return 0; -} - -static int genmii_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - if (mii_info->autoneg) { - status = phy_read(mii_info, MII_LPA); - - if (status & (LPA_10FULL | LPA_100FULL)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - if (status & (LPA_100FULL | LPA_100HALF)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - mii_info->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} -static int marvell_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); - -#if 0 - /* If speed and duplex aren't resolved, - * return an error. Isn't this handled - * by checking aneg? - */ - if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) - return -EAGAIN; -#endif - - /* Get the duplexity */ - if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - /* Get the speed */ - speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; - switch(speed) { - case MII_M1011_PHY_SPEC_STATUS_1000: - mii_info->speed = SPEED_1000; - break; - case MII_M1011_PHY_SPEC_STATUS_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - mii_info->pause = 0; - } - - return 0; -} - - -static int cis820x_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - - status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); - if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - speed = status & MII_CIS8201_AUXCONSTAT_SPEED; - - switch (speed) { - case MII_CIS8201_AUXCONSTAT_GBIT: - mii_info->speed = SPEED_1000; - break; - case MII_CIS8201_AUXCONSTAT_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - } - - return 0; -} - -static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) -{ - /* Clear the interrupts by reading the reg */ - phy_read(mii_info, MII_M1011_IEVENT); - - return 0; -} - -static int marvell_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); - else - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); - - return 0; -} - -static int cis820x_init(struct gfar_mii_info *mii_info) -{ - phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, - MII_CIS8201_AUXCONSTAT_INIT); - phy_write(mii_info, MII_CIS8201_EXT_CON1, - MII_CIS8201_EXTCON1_INIT); - - return 0; -} - -static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_CIS8201_ISTAT); - - return 0; -} - -static int cis820x_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); - else - phy_write(mii_info, MII_CIS8201_IMASK, 0); - - return 0; -} - -#define DM9161_DELAY 10 - -static int dm9161_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - status = phy_read(mii_info, MII_DM9161_SCSR); - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - } - - return 0; -} - - -static int dm9161_config_aneg(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - if(0 == priv->resetdone) - return -EAGAIN; - - return 0; -} - -static void dm9161_timer(unsigned long data) -{ - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct dm9161_private *priv = mii_info->priv; - u16 status = phy_read(mii_info, MII_BMSR); - - if (status & BMSR_ANEGCOMPLETE) { - priv->resetdone = 1; - } else - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); -} - -static int dm9161_init(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv; - - /* Allocate the private data structure */ - priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); - - if (NULL == priv) - return -ENOMEM; - - mii_info->priv = priv; - - /* Reset is not done yet */ - priv->resetdone = 0; - - /* Isolate the PHY */ - phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); - - /* Do not bypass the scrambler/descrambler */ - phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); - - /* Clear 10BTCSR to default */ - phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); - - /* Reconnect the PHY, and enable Autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); - - /* Start a timer for DM9161_DELAY seconds to wait - * for the PHY to be ready */ - init_timer(&priv->timer); - priv->timer.function = &dm9161_timer; - priv->timer.data = (unsigned long) mii_info; - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); - - return 0; -} - -static void dm9161_close(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - del_timer_sync(&priv->timer); - kfree(priv); -} - -#if 0 -static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_DM9161_INTR); - - return 0; -} -#endif - -/* Cicada 820x */ -static struct phy_info phy_info_cis820x = { - 0x000fc440, - "Cicada Cis8204", - 0x000fffc0, - .features = MII_GBIT_FEATURES, - .init = &cis820x_init, - .config_aneg = &gbit_config_aneg, - .read_status = &cis820x_read_status, - .ack_interrupt = &cis820x_ack_interrupt, - .config_intr = &cis820x_config_intr, -}; - -static struct phy_info phy_info_dm9161 = { - .phy_id = 0x0181b880, - .name = "Davicom DM9161E", - .phy_id_mask = 0x0ffffff0, - .init = dm9161_init, - .config_aneg = dm9161_config_aneg, - .read_status = dm9161_read_status, - .close = dm9161_close, -}; - -static struct phy_info phy_info_marvell = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101/88E1111", - .features = MII_GBIT_FEATURES, - .config_aneg = &marvell_config_aneg, - .read_status = &marvell_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, -}; - -static struct phy_info phy_info_genmii= { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .features = MII_BASIC_FEATURES, - .config_aneg = genmii_config_aneg, - .read_status = genmii_read_status, -}; - -static struct phy_info *phy_info[] = { - &phy_info_cis820x, - &phy_info_marvell, - &phy_info_dm9161, - &phy_info_genmii, - NULL -}; - -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) -{ - u16 retval; - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); - - return retval; -} - -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) -{ - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - mii_info->mdio_write(mii_info->dev, - mii_info->mii_id, - regnum, val); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); -} - -/* Use the PHY ID registers to determine what type of PHY is attached - * to device dev. return a struct phy_info structure describing that PHY - */ -struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) -{ - u16 phy_reg; - u32 phy_ID; - int i; - struct phy_info *theInfo = NULL; - struct net_device *dev = mii_info->dev; - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read(mii_info, MII_PHYSID1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read(mii_info, MII_PHYSID2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) - if (phy_info[i]->phy_id == - (phy_ID & phy_info[i]->phy_id_mask)) { - theInfo = phy_info[i]; - break; - } - - /* This shouldn't happen, as we have generic PHY support */ - if (theInfo == NULL) { - printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); - return NULL; - } else { - printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, - phy_ID); - } - - return theInfo; -} diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h deleted file mode 100644 index 1e9b3abf1e6d..000000000000 --- a/drivers/net/gianfar_phy.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * drivers/net/gianfar_phy.h - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-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 __GIANFAR_PHY_H -#define __GIANFAR_PHY_H - -#define MII_end ((u32)-2) -#define MII_read ((u32)-1) - -#define MIIMIND_BUSY 0x00000001 -#define MIIMIND_NOTVALID 0x00000004 - -#define GFAR_AN_TIMEOUT 2000 - -/* 1000BT control (Marvell & BCM54xx at least) */ -#define MII_1000BASETCONTROL 0x09 -#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 -#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 - -/* Cicada Extended Control Register 1 */ -#define MII_CIS8201_EXT_CON1 0x17 -#define MII_CIS8201_EXTCON1_INIT 0x0000 - -/* Cicada Interrupt Mask Register */ -#define MII_CIS8201_IMASK 0x19 -#define MII_CIS8201_IMASK_IEN 0x8000 -#define MII_CIS8201_IMASK_SPEED 0x4000 -#define MII_CIS8201_IMASK_LINK 0x2000 -#define MII_CIS8201_IMASK_DUPLEX 0x1000 -#define MII_CIS8201_IMASK_MASK 0xf000 - -/* Cicada Interrupt Status Register */ -#define MII_CIS8201_ISTAT 0x1a -#define MII_CIS8201_ISTAT_STATUS 0x8000 -#define MII_CIS8201_ISTAT_SPEED 0x4000 -#define MII_CIS8201_ISTAT_LINK 0x2000 -#define MII_CIS8201_ISTAT_DUPLEX 0x1000 - -/* Cicada Auxiliary Control/Status Register */ -#define MII_CIS8201_AUX_CONSTAT 0x1c -#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MII_CIS8201_AUXCONSTAT_100 0x0008 - -/* 88E1011 PHY Status Register */ -#define MII_M1011_PHY_SPEC_STATUS 0x11 -#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 -#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 -#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 -#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 -#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 -#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 - -#define MII_M1011_IEVENT 0x13 -#define MII_M1011_IEVENT_CLEAR 0x0000 - -#define MII_M1011_IMASK 0x12 -#define MII_M1011_IMASK_INIT 0x6400 -#define MII_M1011_IMASK_CLEAR 0x0000 - -#define MII_DM9161_SCR 0x10 -#define MII_DM9161_SCR_INIT 0x0610 - -/* DM9161 Specified Configuration and Status Register */ -#define MII_DM9161_SCSR 0x11 -#define MII_DM9161_SCSR_100F 0x8000 -#define MII_DM9161_SCSR_100H 0x4000 -#define MII_DM9161_SCSR_10F 0x2000 -#define MII_DM9161_SCSR_10H 0x1000 - -/* DM9161 Interrupt Register */ -#define MII_DM9161_INTR 0x15 -#define MII_DM9161_INTR_PEND 0x8000 -#define MII_DM9161_INTR_DPLX_MASK 0x0800 -#define MII_DM9161_INTR_SPD_MASK 0x0400 -#define MII_DM9161_INTR_LINK_MASK 0x0200 -#define MII_DM9161_INTR_MASK 0x0100 -#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 -#define MII_DM9161_INTR_SPD_CHANGE 0x0008 -#define MII_DM9161_INTR_LINK_CHANGE 0x0004 -#define MII_DM9161_INTR_INIT 0x0000 -#define MII_DM9161_INTR_STOP \ -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) - -/* DM9161 10BT Configuration/Status */ -#define MII_DM9161_10BTCSR 0x12 -#define MII_DM9161_10BTCSR_INIT 0x7800 - -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ - SUPPORTED_TP | \ - SUPPORTED_MII) - -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ - SUPPORTED_1000baseT_Full) - -#define MII_READ_COMMAND 0x00000001 - -#define MII_INTERRUPT_DISABLED 0x0 -#define MII_INTERRUPT_ENABLED 0x1 -/* Taken from mii_if_info and sungem_phy.h */ -struct gfar_mii_info { - /* Information about the PHY type */ - /* And management functions */ - struct phy_info *phyinfo; - - /* forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - - /* The most recently read link state */ - int link; - - /* Enabled Interrupts */ - u32 interrupts; - - u32 advertising; - int autoneg; - int mii_id; - - /* private data pointer */ - /* For use by PHYs to maintain extra state */ - void *priv; - - /* Provided by host chip */ - struct net_device *dev; - - /* A lock to ensure that only one thing can read/write - * the MDIO bus at a time */ - spinlock_t mdio_lock; - - /* Provided by ethernet driver */ - int (*mdio_read) (struct net_device *dev, int mii_id, int reg); - void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); -}; - -/* struct phy_info: a structure which defines attributes for a PHY - * - * id will contain a number which represents the PHY. During - * startup, the driver will poll the PHY to find out what its - * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be ANDed with phy_id_mask to - * discard any bits which may change based on revision numbers - * unimportant to functionality - * - * There are 6 commands which take a gfar_mii_info structure. - * Each PHY must declare config_aneg, and read_status. - */ -struct phy_info { - u32 phy_id; - char *name; - unsigned int phy_id_mask; - u32 features; - - /* Called to initialize the PHY */ - int (*init)(struct gfar_mii_info *mii_info); - - /* Called to suspend the PHY for power */ - int (*suspend)(struct gfar_mii_info *mii_info); - - /* Reconfigures autonegotiation (or disables it) */ - int (*config_aneg)(struct gfar_mii_info *mii_info); - - /* Determines the negotiated speed and duplex */ - int (*read_status)(struct gfar_mii_info *mii_info); - - /* Clears any pending interrupts */ - int (*ack_interrupt)(struct gfar_mii_info *mii_info); - - /* Enables or disables interrupts */ - int (*config_intr)(struct gfar_mii_info *mii_info); - - /* Clears up any memory if needed */ - void (*close)(struct gfar_mii_info *mii_info); -}; - -struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); -int read_phy_reg(struct net_device *dev, int mii_id, int regnum); -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); - -struct dm9161_private { - struct timer_list timer; - int resetdone; -}; - -#endif /* GIANFAR_PHY_H */ From 8cee0cd5bec53b78dd3c43a73b27821a688133e6 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 23 Sep 2005 22:58:49 -0400 Subject: [PATCH 0189/1939] [netdrvr] delete CONFIG_PHYCONTROL --- drivers/net/Kconfig | 1 - drivers/net/phy/Kconfig | 8 -------- drivers/net/phy/phy.c | 8 -------- drivers/net/phy/phy_device.c | 3 --- 4 files changed, 20 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4739a63601eb..db8898100325 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2076,7 +2076,6 @@ config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx select PHYLIB - select PHYCONTROL help This driver supports the Gigabit TSEC on the MPC85xx family of chips, and the FEC on the 8540 diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 14f4de1a8180..c782a6329805 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -12,14 +12,6 @@ config PHYLIB devices. This option provides infrastructure for managing PHY devices. -config PHYCONTROL - bool " Support for automatically handling PHY state changes" - depends on PHYLIB - help - Adds code to perform all the work for keeping PHY link - state (speed/duplex/etc) up-to-date. Also handles - interrupts. - comment "MII PHY device drivers" depends on PHYLIB diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d9e11f93bf3a..9209da9dde0d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -242,10 +242,6 @@ EXPORT_SYMBOL(phy_sanitize_settings); * choose the next best ones from the ones selected, so we don't * care if ethtool tries to give us bad values * - * A note about the PHYCONTROL Layer. If you turn off - * CONFIG_PHYCONTROL, you will need to read the PHY status - * registers after this function completes, and update your - * controller manually. */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -380,7 +376,6 @@ int phy_start_aneg(struct phy_device *phydev) err = phydev->drv->config_aneg(phydev); -#ifdef CONFIG_PHYCONTROL if (err < 0) goto out_unlock; @@ -395,14 +390,12 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: -#endif spin_unlock(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); -#ifdef CONFIG_PHYCONTROL static void phy_change(void *data); static void phy_timer(unsigned long data); @@ -868,4 +861,3 @@ static void phy_timer(unsigned long data) mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); } -#endif /* CONFIG_PHYCONTROL */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 33f7bdb5857c..6da1aa0706a1 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -101,7 +101,6 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } -#ifdef CONFIG_PHYCONTROL /* phy_prepare_link: * * description: Tells the PHY infrastructure to handle the @@ -160,8 +159,6 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -#endif /* CONFIG_PHYCONTROL */ - /* phy_attach: * * description: Called by drivers to attach to a particular PHY From 7a716536c602be6050b4f3ece30f1fc3b64362b0 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 23 Sep 2005 21:58:58 -0700 Subject: [PATCH 0190/1939] [PATCH] hostap: Fix pci_driver name for hostap_plx and hostap_pci hostap_pci and hostap_plx drivers still use PCI driver names "prism2_pci" and "prism2_plx" respectively. This is unfriendly to linux-wlan-ng, which uses the same names. So, if e.g. hostap_pci and prism2_pci are loaded, they will "share" /sys/bus/pci/drivers/prism2_plx directory. Change PCI driver names of hostap_pci and hostap_plx to be equal to their module names. Signed-off-by: Pavel Roskin Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_pci.c | 2 +- drivers/net/wireless/hostap/hostap_plx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 025f8cdb5566..b9254f73fbaf 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -441,7 +441,7 @@ static int prism2_pci_resume(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); static struct pci_driver prism2_pci_drv_id = { - .name = "prism2_pci", + .name = "hostap_pci", .id_table = prism2_pci_id_table, .probe = prism2_pci_probe, .remove = prism2_pci_remove, diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 474ef83d813e..1abebdf48b20 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -616,7 +616,7 @@ static void prism2_plx_remove(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); static struct pci_driver prism2_plx_drv_id = { - .name = "prism2_plx", + .name = "hostap_plx", .id_table = prism2_plx_id_table, .probe = prism2_plx_probe, .remove = prism2_plx_remove, From c28df16ed70d1b6cefd12135e3c68bfccd1bb635 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Sep 2005 21:58:59 -0700 Subject: [PATCH 0191/1939] [PATCH] hostap: Add support for WE-19 This patch adds support for WE-19 to the HostAP driver. One of the major change is the use of an explicit flag to tell if iwstat is in dBm or not. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_80211_rx.c | 3 ++- drivers/net/wireless/hostap/hostap_ap.c | 6 +++--- drivers/net/wireless/hostap/hostap_ioctl.c | 9 +++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 42e61c68c325..ffac50899454 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -737,7 +737,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, struct iw_quality wstats; wstats.level = rx_stats->signal; wstats.noise = rx_stats->noise; - wstats.updated = 6; /* No qual value */ + wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, hdr->addr2, &wstats); } diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 087d9269af34..9da94ab7f05f 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -2349,7 +2349,7 @@ static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); qual[count].updated = sta->last_rx_updated; - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; count++; if (count >= buf_size) @@ -2467,7 +2467,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) } #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; /* To be continued, we should make good use of IWEVCUSTOM */ } @@ -3174,7 +3174,7 @@ int hostap_update_rx_stats(struct ap_data *ap, sta->last_rx_silence = rx_stats->noise; sta->last_rx_signal = rx_stats->signal; sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = 7; + sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; if (rx_stats->rate == 10) sta->rx_count[0]++; else if (rx_stats->rate == 20) diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index e720369a3515..dd9817261a3a 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -50,7 +50,8 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) #endif /* in_atomic */ if (update && prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | + IW_QUAL_DBM; wstats->qual.qual = local->comms_qual; wstats->qual.level = local->avg_signal; @@ -59,7 +60,7 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) wstats->qual.qual = 0; wstats->qual.level = 0; wstats->qual.noise = 0; - wstats->qual.updated = 0; + wstats->qual.updated = IW_QUAL_ALL_INVALID; } return wstats; @@ -1894,6 +1895,10 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); } + iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED + | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID + | IW_QUAL_DBM; iwe.len = IW_EV_QUAL_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); From a9d12b9a4afcfa2cb6f6e76beb4f185a9177c98e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Sep 2005 21:59:00 -0700 Subject: [PATCH 0192/1939] [PATCH] hostap: Use GFP_ATOMIC to get rid of weird might_sleep issue This is the trace I got : Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index dd9817261a3a..1764563612a8 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1935,7 +1935,7 @@ static char * __prism2_translate_scan(local_info_t *local, } /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); + buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); if (buf && scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; From 596ff2e7c8db39c700e277f0bc267244be253f5b Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Sep 2005 21:59:01 -0700 Subject: [PATCH 0193/1939] [PATCH] hostap: Remove iwe_stream_add_event kludge Now that we are compiling with -fno-strict-aliasing (this is the kernel default), we can drop the following kludge for iwe_stream_add_event(). Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_ioctl.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 1764563612a8..53f5246c40aa 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1828,13 +1828,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - /* FIX: - * I do not know how this is possible, but iwe_stream_add_event - * seems to re-order memcpy execution so that len is set only - * after copying.. Pre-setting len here "fixes" this, but real - * problems should be solved (after which these iwe.len - * settings could be removed from this function). */ - iwe.len = IW_EV_ADDR_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); @@ -1844,7 +1837,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ssid_len; iwe.u.data.flags = 1; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); memset(&iwe, 0, sizeof(iwe)); @@ -1860,7 +1852,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - iwe.len = IW_EV_UINT_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } @@ -1878,7 +1869,6 @@ static char * __prism2_translate_scan(local_info_t *local, if (chan > 0) { iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; iwe.u.freq.e = 1; - iwe.len = IW_EV_FREQ_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } @@ -1899,7 +1889,6 @@ static char * __prism2_translate_scan(local_info_t *local, | IW_QUAL_NOISE_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; - iwe.len = IW_EV_QUAL_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); } @@ -1911,7 +1900,6 @@ static char * __prism2_translate_scan(local_info_t *local, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ From e2e965072564e7aad8df963107677a6d22c41767 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 24 Sep 2005 04:05:52 -0400 Subject: [PATCH 0194/1939] Remove WIRELESS_EXT ifdefs from several wireless drivers. --- drivers/net/wireless/airo.c | 17 -- drivers/net/wireless/netwave_cs.c | 185 ---------------------- drivers/net/wireless/prism54/isl_ioctl.c | 10 +- drivers/net/wireless/prism54/islpci_dev.c | 4 - drivers/net/wireless/prism54/islpci_dev.h | 2 - drivers/net/wireless/wavelan.c | 8 - drivers/net/wireless/wavelan.p.h | 4 - drivers/net/wireless/wavelan_cs.c | 8 - drivers/net/wireless/wavelan_cs.p.h | 4 - 9 files changed, 1 insertion(+), 241 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 06998c2240d9..a6194955df2c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1046,7 +1046,6 @@ static WifiCtlHdr wifictlhdr8023 = { } }; -#ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; @@ -1067,7 +1066,6 @@ typedef struct wep_key_t { /* List of Wireless Handlers (new API) */ static const struct iw_handler_def airo_handler_def; -#endif /* WIRELESS_EXT */ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; @@ -1110,10 +1108,8 @@ static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs static int airo_thread(void *data); static void timer_func( struct net_device *dev ); static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#ifdef WIRELESS_EXT static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); static void airo_read_wireless_stats (struct airo_info *local); -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT static int readrids(struct net_device *dev, aironet_ioctl *comp); static int writerids(struct net_device *dev, aironet_ioctl *comp); @@ -1187,12 +1183,10 @@ struct airo_info { int fid; } xmit, xmit11; struct net_device *wifidev; -#ifdef WIRELESS_EXT struct iw_statistics wstats; // wireless stats unsigned long scan_timestamp; /* Time started to scan */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT */ #ifdef MICSUPPORT /* MIC stuff */ struct crypto_tfm *tfm; @@ -2647,9 +2641,7 @@ static void wifi_setup(struct net_device *dev) dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -2675,9 +2667,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, dev->priv = ethdev->priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; -#ifdef WIRELESS_EXT dev->wireless_data = ethdev->wireless_data; -#endif /* WIRELESS_EXT */ memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); err = register_netdev(dev); if (err<0) { @@ -2755,11 +2745,9 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->set_multicast_list = &airo_set_multicast_list; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; ai->wireless_data.spy_data = &ai->spy_data; dev->wireless_data = &ai->wireless_data; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -5598,7 +5586,6 @@ static void __exit airo_cleanup_module( void ) remove_proc_entry("aironet", proc_root_driver); } -#ifdef WIRELESS_EXT /* * Initial Wireless Extension code for Aironet driver by : * Jean Tourrilhes - HPL - 17 November 00 @@ -7107,8 +7094,6 @@ static const struct iw_handler_def airo_handler_def = .get_wireless_stats = airo_get_wireless_stats, }; -#endif /* WIRELESS_EXT */ - /* * This defines the configuration part of the Wireless Extensions * Note : irq and spinlock protection will occur in the subroutines @@ -7187,7 +7172,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -#ifdef WIRELESS_EXT /* * Get the Wireless stats out of the driver * Note : irq and spinlock protection will occur in the subroutines @@ -7260,7 +7244,6 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) return &local->wstats; } -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT /* diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index ca6c03c89926..92793b958e32 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -57,9 +57,7 @@ #include #ifdef CONFIG_NET_RADIO #include -#if WIRELESS_EXT > 12 #include -#endif /* WIRELESS_EXT > 12 */ #endif #include @@ -225,10 +223,7 @@ static void update_stats(struct net_device *dev); static struct net_device_stats *netwave_get_stats(struct net_device *dev); /* Wireless extensions */ -#ifdef WIRELESS_EXT static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); -#endif -static int netwave_ioctl(struct net_device *, struct ifreq *, int); static void set_multicast_list(struct net_device *dev); @@ -260,26 +255,7 @@ static dev_link_t *dev_list; because they generally can't be allocated dynamically. */ -#if WIRELESS_EXT <= 12 -/* Wireless extensions backward compatibility */ - -/* Part of iw_handler prototype we need */ -struct iw_request_info -{ - __u16 cmd; /* Wireless Extension command */ - __u16 flags; /* More to come ;-) */ -}; - -/* Wireless Extension Backward compatibility - Jean II - * If the new wireless device private ioctl range is not defined, - * default to standard device private ioctl range */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - -#else /* WIRELESS_EXT <= 12 */ static const struct iw_handler_def netwave_handler_def; -#endif /* WIRELESS_EXT <= 12 */ #define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ @@ -319,9 +295,7 @@ typedef struct netwave_private { struct timer_list watchdog; /* To avoid blocking state */ struct site_survey nss; struct net_device_stats stats; -#ifdef WIRELESS_EXT struct iw_statistics iw_stats; /* Wireless stats */ -#endif } netwave_private; #ifdef NETWAVE_STATS @@ -353,7 +327,6 @@ static inline void wait_WOC(unsigned int iobase) while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; } -#ifdef WIRELESS_EXT static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, kio_addr_t iobase) { u_short resultBuffer; @@ -376,9 +349,7 @@ static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, sizeof(struct site_survey)); } } -#endif -#ifdef WIRELESS_EXT /* * Function netwave_get_wireless_stats (dev) * @@ -411,7 +382,6 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) return &priv->iw_stats; } -#endif /* * Function netwave_attach (void) @@ -471,13 +441,7 @@ static dev_link_t *netwave_attach(void) dev->get_stats = &netwave_get_stats; dev->set_multicast_list = &set_multicast_list; /* wireless extensions */ -#if WIRELESS_EXT <= 16 - dev->get_wireless_stats = &netwave_get_wireless_stats; -#endif /* WIRELESS_EXT <= 16 */ -#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; -#endif /* WIRELESS_EXT > 12 */ - dev->do_ioctl = &netwave_ioctl; dev->tx_timeout = &netwave_watchdog; dev->watchdog_timeo = TX_TIMEOUT; @@ -576,13 +540,8 @@ static int netwave_set_nwid(struct net_device *dev, /* Disable interrupts & save flags */ spin_lock_irqsave(&priv->spinlock, flags); -#if WIRELESS_EXT > 8 if(!wrqu->nwid.disabled) { domain = wrqu->nwid.value; -#else /* WIRELESS_EXT > 8 */ - if(wrqu->nwid.on) { - domain = wrqu->nwid.nwid; -#endif /* WIRELESS_EXT > 8 */ printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); wait_WOC(iobase); @@ -606,15 +565,9 @@ static int netwave_get_nwid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { -#if WIRELESS_EXT > 8 wrqu->nwid.value = domain; wrqu->nwid.disabled = 0; wrqu->nwid.fixed = 1; -#else /* WIRELESS_EXT > 8 */ - wrqu->nwid.nwid = domain; - wrqu->nwid.on = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } @@ -657,17 +610,11 @@ static int netwave_get_scramble(struct net_device *dev, { key[1] = scramble_key & 0xff; key[0] = (scramble_key>>8) & 0xff; -#if WIRELESS_EXT > 8 wrqu->encoding.flags = IW_ENCODE_ENABLED; wrqu->encoding.length = 2; -#else /* WIRELESS_EXT > 8 */ - wrqu->encoding.method = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } -#if WIRELESS_EXT > 8 /* * Wireless Handler : get mode */ @@ -683,7 +630,6 @@ static int netwave_get_mode(struct net_device *dev, return 0; } -#endif /* WIRELESS_EXT > 8 */ /* * Wireless Handler : get range info @@ -702,11 +648,9 @@ static int netwave_get_range(struct net_device *dev, /* Set all the info we don't care or don't know about to zero */ memset(range, 0, sizeof(struct iw_range)); -#if WIRELESS_EXT > 10 /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 9; /* Nothing for us in v10 and v11 */ -#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range->throughput = 450 * 1000; /* don't argue on this ! */ @@ -720,16 +664,12 @@ static int netwave_get_range(struct net_device *dev, range->max_qual.level = 255; range->max_qual.noise = 0; -#if WIRELESS_EXT > 7 range->num_bitrates = 1; range->bitrate[0] = 1000000; /* 1 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ -#if WIRELESS_EXT > 8 range->encoding_size[0] = 2; /* 16 bits scrambling */ range->num_encoding_sizes = 1; range->max_encoding_tokens = 1; /* Only one key possible */ -#endif /* WIRELESS_EXT > 8 */ return ret; } @@ -775,8 +715,6 @@ static const struct iw_priv_args netwave_private_args[] = { "getsitesurvey" }, }; -#if WIRELESS_EXT > 12 - static const iw_handler netwave_handler[] = { NULL, /* SIOCSIWNAME */ @@ -839,131 +777,8 @@ static const struct iw_handler_def netwave_handler_def = .standard = (iw_handler *) netwave_handler, .private = (iw_handler *) netwave_private_handler, .private_args = (struct iw_priv_args *) netwave_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = netwave_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ }; -#endif /* WIRELESS_EXT > 12 */ - -/* - * Function netwave_ioctl (dev, rq, cmd) - * - * Perform ioctl : config & info stuff - * This is the stuff that are treated the wireless extensions (iwconfig) - * - */ -static int netwave_ioctl(struct net_device *dev, /* ioctl device */ - struct ifreq *rq, /* Data passed */ - int cmd) /* Ioctl number */ -{ - int ret = 0; -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - struct iwreq *wrq = (struct iwreq *) rq; -#endif -#endif - - DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); - - /* Look what is the request */ - switch(cmd) { - /* --------------- WIRELESS EXTENSIONS --------------- */ -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - case SIOCGIWNAME: - netwave_get_name(dev, NULL, &(wrq->u), NULL); - break; - case SIOCSIWNWID: - ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); - break; - case SIOCGIWNWID: - ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); - break; -#if WIRELESS_EXT > 8 /* Note : The API did change... */ - case SIOCGIWENCODE: - /* Get scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); - if(copy_to_user(wrq->u.encoding.pointer, key, 2)) - ret = -EFAULT; - } - break; - case SIOCSIWENCODE: - /* Set scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - if(copy_from_user(key, wrq->u.encoding.pointer, 2)) - { - ret = -EFAULT; - break; - } - ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); - } - break; - case SIOCGIWMODE: - /* Mode of operation */ - ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); - break; -#else /* WIRELESS_EXT > 8 */ - case SIOCGIWENCODE: - /* Get scramble key */ - ret = netwave_get_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; - case SIOCSIWENCODE: - /* Set scramble key */ - ret = netwave_set_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; -#endif /* WIRELESS_EXT > 8 */ - case SIOCGIWRANGE: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); - if (copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; - } - break; - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - /* Set the number of ioctl available */ - wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - (u_char *) netwave_private_args, - sizeof(netwave_private_args))) - ret = -EFAULT; - } - break; - case SIOCGIPSNAP: - if(wrq->u.data.pointer != (caddr_t) 0) { - char buffer[sizeof( struct site_survey)]; - ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - buffer, - sizeof( struct site_survey))) - { - printk(KERN_DEBUG "Bad buffer!\n"); - break; - } - } - break; -#endif /* WIRELESS_EXT <= 12 */ -#endif /* WIRELESS_EXT */ - default: - ret = -EOPNOTSUPP; - } - - return ret; -} /* * Function netwave_pcmcia_config (link) diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 9a8790e3580c..5c1a1adf1ff8 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -462,14 +462,12 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info, /* txpower is supported in dBm's */ range->txpower_capa = IW_TXPOW_DBM; -#if WIRELESS_EXT > 16 /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); -#endif /* WIRELESS_EXT > 16 */ if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; @@ -693,14 +691,13 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, extra + dwrq->length, &(bsslist->bsslist[i]), noise); -#if WIRELESS_EXT > 16 + /* Check if there is space for one more entry */ if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { /* Ask user space to try again with a bigger buffer */ rvalue = -E2BIG; break; } -#endif /* WIRELESS_EXT > 16 */ } kfree(bsslist); @@ -2727,12 +2724,7 @@ const struct iw_handler_def prism54_handler_def = { .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = prism54_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ -#if WIRELESS_EXT == 16 - .spy_offset = offsetof(islpci_private, spy_data), -#endif /* WIRELESS_EXT == 16 */ }; /* For wpa_supplicant */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 10cce514c15d..6c9584a9f284 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -837,13 +837,9 @@ islpci_setup(struct pci_dev *pdev) priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? priv->monitor_type : ARPHRD_ETHER; -#if WIRELESS_EXT > 16 /* Add pointers to enable iwspy support. */ priv->wireless_data.spy_data = &priv->spy_data; ndev->wireless_data = &priv->wireless_data; -#else /* WIRELESS_EXT > 16 */ - ndev->get_wireless_stats = &prism54_get_wireless_stats; -#endif /* WIRELESS_EXT > 16 */ /* save the start and end address of the PCI memory area */ ndev->mem_start = (unsigned long) priv->device_base; diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 32a1019f1b36..efbed4397951 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -100,9 +100,7 @@ typedef struct { struct iw_spy_data spy_data; /* iwspy support */ -#if WIRELESS_EXT > 16 struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT > 16 */ int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 7a5e20a17890..b0d8b5b03152 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -430,7 +430,6 @@ static void fee_read(unsigned long ioaddr, /* I/O port of the card */ } } -#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ /*------------------------------------------------------------------*/ /* @@ -514,7 +513,6 @@ static void fee_write(unsigned long ioaddr, /* I/O port of the card */ fee_wait(ioaddr, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /************************ I82586 SUBROUTINES *************************/ /* @@ -973,11 +971,9 @@ static void wv_mmc_show(struct net_device * dev) mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1499,7 +1495,6 @@ static int wavelan_set_mac_address(struct net_device * dev, void *addr) } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2473,7 +2468,6 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4194,11 +4188,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 509ff22a6caa..166e28b9a4f7 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -409,11 +409,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ /* Warning: this stuff will slow down the driver. */ #define WIRELESS_SPY /* Enable spying addresses. */ #undef HISTOGRAM /* Enable histogram of signal level. */ -#endif /****************************** DEBUG ******************************/ @@ -506,12 +504,10 @@ struct net_local u_short tx_first_free; u_short tx_first_in_use; -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless-specific statistics */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* number of intervals */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 183c4732ef65..4b3c98f5c564 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -415,7 +415,6 @@ fee_read(u_long base, /* i/o port of the card */ } } -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -500,7 +499,6 @@ fee_write(u_long base, /* i/o port of the card */ fee_wait(base, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /******************* WaveLAN Roaming routines... ********************/ @@ -1161,10 +1159,8 @@ wv_mmc_show(struct net_device * dev) mmc_read(base, 0, (u_char *)&m, sizeof(m)); mmc_out(base, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -1550,7 +1546,6 @@ wavelan_set_mac_address(struct net_device * dev, } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2793,7 +2788,6 @@ wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4679,11 +4673,9 @@ wavelan_attach(void) dev->watchdog_timeo = WATCHDOG_JIFFIES; SET_ETHTOOL_OPS(dev, &ops); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif /* Other specific data */ dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 01d882be8790..724a715089c9 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -472,11 +472,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Warning : these stuff will slow down the driver... */ #define WIRELESS_SPY /* Enable spying addresses */ #undef HISTOGRAM /* Enable histogram of sig level... */ -#endif /****************************** DEBUG ******************************/ @@ -624,12 +622,10 @@ struct net_local int rfp; /* Last DMA machine receive pointer */ int overrunning; /* Receiver overrun flag */ -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless specific stats */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* Number of intervals */ From 2759c8d536efe3b853867f345627d89fb64c37af Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 24 Sep 2005 04:09:04 -0400 Subject: [PATCH 0195/1939] [wireless airo] remove needed dma_addr_t obfuscation Fixes bus address truncation bug for certain configs. --- drivers/net/wireless/airo.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index a6194955df2c..746456c34df8 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2521,7 +2521,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, unsigned long mem_start, mem_len, aux_start, aux_len; int rc = -1; int i; - unsigned char *busaddroff,*vpackoff; + dma_addr_t busaddroff; + unsigned char *vpackoff; unsigned char __iomem *pciaddroff; mem_start = pci_resource_start(pci, 1); @@ -2564,7 +2565,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* * Setup descriptor RX, TX, CONFIG */ - busaddroff = (unsigned char *)ai->shared_dma; + busaddroff = ai->shared_dma; pciaddroff = ai->pciaux + AUX_OFFSET; vpackoff = ai->shared; @@ -2573,7 +2574,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->rxfids[i].pending = 0; ai->rxfids[i].card_ram_off = pciaddroff; ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff; + ai->rxfids[i].rx_desc.host_addr = busaddroff; ai->rxfids[i].rx_desc.valid = 1; ai->rxfids[i].rx_desc.len = PKTSIZE; ai->rxfids[i].rx_desc.rdy = 0; @@ -2588,7 +2589,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->txfids[i].card_ram_off = pciaddroff; ai->txfids[i].virtual_host_addr = vpackoff; ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff; + ai->txfids[i].tx_desc.host_addr = busaddroff; memcpy(ai->txfids[i].virtual_host_addr, &wifictlhdr8023, sizeof(wifictlhdr8023)); @@ -2601,8 +2602,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Rid descriptor setup */ ai->config_desc.card_ram_off = pciaddroff; ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff; - ai->ridbus = (dma_addr_t)busaddroff; + ai->config_desc.rid_desc.host_addr = busaddroff; + ai->ridbus = busaddroff; ai->config_desc.rid_desc.rid = 0; ai->config_desc.rid_desc.len = RIDSIZE; ai->config_desc.rid_desc.valid = 1; From 3efc333e7fdb6fab9d4eae129e2b249c6483b250 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 22 Sep 2005 10:13:31 -0500 Subject: [PATCH 0196/1939] [PATCH] powerpc: Fix building of power3 config on ppc32 The spinlock_types.h merge renamed the structure for raw_spinlock_t to match ppc64. In doing so some of the spinlock macros/functions needed to be updated to match. Apparently, this seems to only be caught when building power3. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/asm-ppc/spinlock.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h index 20edcf2a6e0c..5c64b75f0295 100644 --- a/include/asm-ppc/spinlock.h +++ b/include/asm-ppc/spinlock.h @@ -9,7 +9,7 @@ * (the type definitions are in asm/raw_spinlock_types.h) */ -#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_is_locked(x) ((x)->slock != 0) #define __raw_spin_unlock_wait(lock) \ do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) @@ -31,17 +31,17 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) bne- 2b\n\ isync" : "=&r"(tmp) - : "r"(&lock->lock), "r"(1) + : "r"(&lock->slock), "r"(1) : "cr0", "memory"); } static inline void __raw_spin_unlock(raw_spinlock_t *lock) { __asm__ __volatile__("eieio # __raw_spin_unlock": : :"memory"); - lock->lock = 0; + lock->slock = 0; } -#define __raw_spin_trylock(l) (!test_and_set_bit(0,&(l)->lock)) +#define __raw_spin_trylock(l) (!test_and_set_bit(0,(volatile unsigned long *)(&(l)->slock))) /* * Read-write spinlocks, allowing multiple readers From 2bfadee32f1501faa3184d574f6a769f17236c87 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Fri, 23 Sep 2005 08:05:03 -0500 Subject: [PATCH 0197/1939] [PATCH] powerpc: Merge asm-ppc*/seccomp.h, drop TIF_32BIT check Merge asm-ppc*/seccomp.h. Drop TIF_32BIT check. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/seccomp.h | 11 +++-------- include/asm-ppc/seccomp.h | 10 ---------- 2 files changed, 3 insertions(+), 18 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/seccomp.h (66%) delete mode 100644 include/asm-ppc/seccomp.h diff --git a/include/asm-ppc64/seccomp.h b/include/asm-powerpc/seccomp.h similarity index 66% rename from include/asm-ppc64/seccomp.h rename to include/asm-powerpc/seccomp.h index c130c334bda1..1e1cfe12882b 100644 --- a/include/asm-ppc64/seccomp.h +++ b/include/asm-powerpc/seccomp.h @@ -1,11 +1,6 @@ -#ifndef _ASM_SECCOMP_H - -#include /* already defines TIF_32BIT */ - -#ifndef TIF_32BIT -#error "unexpected TIF_32BIT on ppc64" -#endif +#ifndef _ASM_POWERPC_SECCOMP_H +#include #include #define __NR_seccomp_read __NR_read @@ -18,4 +13,4 @@ #define __NR_seccomp_exit_32 __NR_exit #define __NR_seccomp_sigreturn_32 __NR_sigreturn -#endif /* _ASM_SECCOMP_H */ +#endif /* _ASM_POWERPC_SECCOMP_H */ diff --git a/include/asm-ppc/seccomp.h b/include/asm-ppc/seccomp.h deleted file mode 100644 index 666c4da96d87..000000000000 --- a/include/asm-ppc/seccomp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASM_SECCOMP_H - -#include - -#define __NR_seccomp_read __NR_read -#define __NR_seccomp_write __NR_write -#define __NR_seccomp_exit __NR_exit -#define __NR_seccomp_sigreturn __NR_rt_sigreturn - -#endif /* _ASM_SECCOMP_H */ From feaf7cf153335fe7100b65ed6f4585c3574fe69a Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Thu, 22 Sep 2005 14:20:04 -0500 Subject: [PATCH 0198/1939] [PATCH] powerpc: merge atomic.h, memory.h powerpc: Merge atomic.h and memory.h into powerpc Merged atomic.h into include/powerpc. Moved asm-style HMT_ defines from memory.h into ppc_asm.h, where there were already HMT_defines; moved c-style HMT_ defines to processor.h. Renamed memory.h to synch.h to better reflect its contents. Signed-off-by: Kumar Gala Signed-off-by: Becky Bruce Signed-off-by: Jon Loeliger Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/atomic.h | 45 +++-- include/asm-powerpc/ppc_asm.h | 3 + include/asm-powerpc/synch.h | 51 ++++++ include/asm-ppc/io.h | 11 +- include/asm-ppc64/atomic.h | 197 ---------------------- include/asm-ppc64/bitops.h | 2 +- include/asm-ppc64/futex.h | 2 +- include/asm-ppc64/io.h | 2 +- include/asm-ppc64/memory.h | 61 ------- include/asm-ppc64/processor.h | 8 + include/asm-ppc64/system.h | 4 +- 11 files changed, 88 insertions(+), 298 deletions(-) rename include/{asm-ppc => asm-powerpc}/atomic.h (85%) create mode 100644 include/asm-powerpc/synch.h delete mode 100644 include/asm-ppc64/atomic.h delete mode 100644 include/asm-ppc64/memory.h diff --git a/include/asm-ppc/atomic.h b/include/asm-powerpc/atomic.h similarity index 85% rename from include/asm-ppc/atomic.h rename to include/asm-powerpc/atomic.h index eeafd505836e..ed4b345ed75d 100644 --- a/include/asm-ppc/atomic.h +++ b/include/asm-powerpc/atomic.h @@ -1,29 +1,20 @@ +#ifndef _ASM_POWERPC_ATOMIC_H_ +#define _ASM_POWERPC_ATOMIC_H_ + /* * PowerPC atomic operations */ -#ifndef _ASM_PPC_ATOMIC_H_ -#define _ASM_PPC_ATOMIC_H_ - typedef struct { volatile int counter; } atomic_t; #ifdef __KERNEL__ +#include -#define ATOMIC_INIT(i) { (i) } +#define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) -extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); - -#ifdef CONFIG_SMP -#define SMP_SYNC "sync" -#define SMP_ISYNC "\n\tisync" -#else -#define SMP_SYNC "" -#define SMP_ISYNC -#endif - /* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx. * The old ATOMIC_SYNC_FIX covered some but not all of this. */ @@ -53,12 +44,13 @@ static __inline__ int atomic_add_return(int a, atomic_t *v) int t; __asm__ __volatile__( + EIEIO_ON_SMP "1: lwarx %0,0,%2 # atomic_add_return\n\ add %0,%1,%0\n" PPC405_ERR77(0,%2) " stwcx. %0,0,%2 \n\ bne- 1b" - SMP_ISYNC + ISYNC_ON_SMP : "=&r" (t) : "r" (a), "r" (&v->counter) : "cc", "memory"); @@ -88,12 +80,13 @@ static __inline__ int atomic_sub_return(int a, atomic_t *v) int t; __asm__ __volatile__( + EIEIO_ON_SMP "1: lwarx %0,0,%2 # atomic_sub_return\n\ subf %0,%1,%0\n" PPC405_ERR77(0,%2) " stwcx. %0,0,%2 \n\ bne- 1b" - SMP_ISYNC + ISYNC_ON_SMP : "=&r" (t) : "r" (a), "r" (&v->counter) : "cc", "memory"); @@ -121,12 +114,13 @@ static __inline__ int atomic_inc_return(atomic_t *v) int t; __asm__ __volatile__( + EIEIO_ON_SMP "1: lwarx %0,0,%1 # atomic_inc_return\n\ addic %0,%0,1\n" PPC405_ERR77(0,%1) " stwcx. %0,0,%1 \n\ bne- 1b" - SMP_ISYNC + ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) : "cc", "memory"); @@ -164,12 +158,13 @@ static __inline__ int atomic_dec_return(atomic_t *v) int t; __asm__ __volatile__( + EIEIO_ON_SMP "1: lwarx %0,0,%1 # atomic_dec_return\n\ addic %0,%0,-1\n" PPC405_ERR77(0,%1) " stwcx. %0,0,%1\n\ bne- 1b" - SMP_ISYNC + ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) : "cc", "memory"); @@ -189,13 +184,14 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) int t; __asm__ __volatile__( + EIEIO_ON_SMP "1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ addic. %0,%0,-1\n\ blt- 2f\n" PPC405_ERR77(0,%1) " stwcx. %0,0,%1\n\ bne- 1b" - SMP_ISYNC + ISYNC_ON_SMP "\n\ 2:" : "=&r" (t) : "r" (&v->counter) @@ -204,11 +200,10 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) return t; } -#define __MB __asm__ __volatile__ (SMP_SYNC : : : "memory") -#define smp_mb__before_atomic_dec() __MB -#define smp_mb__after_atomic_dec() __MB -#define smp_mb__before_atomic_inc() __MB -#define smp_mb__after_atomic_inc() __MB +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() #endif /* __KERNEL__ */ -#endif /* _ASM_PPC_ATOMIC_H_ */ +#endif /* _ASM_POWERPC_ATOMIC_H_ */ diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 553035cda00e..4efa71878fa9 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -75,8 +75,11 @@ #define REST_32EVRS(n,s,base) REST_16EVRS(n,s,base); REST_16EVRS(n+16,s,base) /* Macros to adjust thread priority for Iseries hardware multithreading */ +#define HMT_VERY_LOW or 31,31,31 # very low priority\n" #define HMT_LOW or 1,1,1 +#define HMT_MEDIUM_LOW or 6,6,6 # medium low priority\n" #define HMT_MEDIUM or 2,2,2 +#define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority\n" #define HMT_HIGH or 3,3,3 /* handle instructions that older assemblers may not know */ diff --git a/include/asm-powerpc/synch.h b/include/asm-powerpc/synch.h new file mode 100644 index 000000000000..4660c0394a77 --- /dev/null +++ b/include/asm-powerpc/synch.h @@ -0,0 +1,51 @@ +#ifndef _ASM_POWERPC_SYNCH_H +#define _ASM_POWERPC_SYNCH_H + +#include + +#ifdef __powerpc64__ +#define __SUBARCH_HAS_LWSYNC +#endif + +#ifdef __SUBARCH_HAS_LWSYNC +# define LWSYNC lwsync +#else +# define LWSYNC sync +#endif + + +/* + * Arguably the bitops and *xchg operations don't imply any memory barrier + * or SMP ordering, but in fact a lot of drivers expect them to imply + * both, since they do on x86 cpus. + */ +#ifdef CONFIG_SMP +#define EIEIO_ON_SMP "eieio\n" +#define ISYNC_ON_SMP "\n\tisync" +#define SYNC_ON_SMP __stringify(LWSYNC) "\n" +#else +#define EIEIO_ON_SMP +#define ISYNC_ON_SMP +#define SYNC_ON_SMP +#endif + +static inline void eieio(void) +{ + __asm__ __volatile__ ("eieio" : : : "memory"); +} + +static inline void isync(void) +{ + __asm__ __volatile__ ("isync" : : : "memory"); +} + +#ifdef CONFIG_SMP +#define eieio_on_smp() eieio() +#define isync_on_smp() isync() +#else +#define eieio_on_smp() __asm__ __volatile__("": : :"memory") +#define isync_on_smp() __asm__ __volatile__("": : :"memory") +#endif + +#endif /* _ASM_POWERPC_SYNCH_H */ + diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 7eb7cf6360bd..39caf067a31b 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -8,6 +8,7 @@ #include #include +#include #include #define SIO_CONFIG_RA 0x398 @@ -440,16 +441,6 @@ extern inline void * phys_to_virt(unsigned long address) #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define page_to_bus(page) (page_to_phys(page) + PCI_DRAM_OFFSET) -/* - * Enforce In-order Execution of I/O: - * Acts as a barrier to ensure all previous I/O accesses have - * completed before any further ones are issued. - */ -extern inline void eieio(void) -{ - __asm__ __volatile__ ("eieio" : : : "memory"); -} - /* Enforce in-order execution of data I/O. * No distinction between read/write on PPC; use eieio for all three. */ diff --git a/include/asm-ppc64/atomic.h b/include/asm-ppc64/atomic.h deleted file mode 100644 index 0e5f25e83bc0..000000000000 --- a/include/asm-ppc64/atomic.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * PowerPC64 atomic operations - * - * Copyright (C) 2001 Paul Mackerras , IBM - * Copyright (C) 2001 Anton Blanchard , IBM - * - * 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_PPC64_ATOMIC_H_ -#define _ASM_PPC64_ATOMIC_H_ - -#include - -typedef struct { volatile int counter; } atomic_t; - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) - -static __inline__ void atomic_add(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%3 # atomic_add\n\ - add %0,%2,%0\n\ - stwcx. %0,0,%3\n\ - bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) - : "cc"); -} - -static __inline__ int atomic_add_return(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - EIEIO_ON_SMP -"1: lwarx %0,0,%2 # atomic_add_return\n\ - add %0,%1,%0\n\ - stwcx. %0,0,%2\n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) - -static __inline__ void atomic_sub(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%3 # atomic_sub\n\ - subf %0,%2,%0\n\ - stwcx. %0,0,%3\n\ - bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) - : "cc"); -} - -static __inline__ int atomic_sub_return(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - EIEIO_ON_SMP -"1: lwarx %0,0,%2 # atomic_sub_return\n\ - subf %0,%1,%0\n\ - stwcx. %0,0,%2\n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -static __inline__ void atomic_inc(atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%2 # atomic_inc\n\ - addic %0,%0,1\n\ - stwcx. %0,0,%2\n\ - bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) - : "cc"); -} - -static __inline__ int atomic_inc_return(atomic_t *v) -{ - int t; - - __asm__ __volatile__( - EIEIO_ON_SMP -"1: lwarx %0,0,%1 # atomic_inc_return\n\ - addic %0,%0,1\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (t) - : "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -/* - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - -static __inline__ void atomic_dec(atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%2 # atomic_dec\n\ - addic %0,%0,-1\n\ - stwcx. %0,0,%2\n\ - bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) - : "cc"); -} - -static __inline__ int atomic_dec_return(atomic_t *v) -{ - int t; - - __asm__ __volatile__( - EIEIO_ON_SMP -"1: lwarx %0,0,%1 # atomic_dec_return\n\ - addic %0,%0,-1\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (t) - : "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) -#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) - -/* - * Atomically test *v and decrement if it is greater than 0. - * The function returns the old value of *v minus 1. - */ -static __inline__ int atomic_dec_if_positive(atomic_t *v) -{ - int t; - - __asm__ __volatile__( - EIEIO_ON_SMP -"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ - addic. %0,%0,-1\n\ - blt- 2f\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - ISYNC_ON_SMP - "\n\ -2:" : "=&r" (t) - : "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - -#endif /* _ASM_PPC64_ATOMIC_H_ */ diff --git a/include/asm-ppc64/bitops.h b/include/asm-ppc64/bitops.h index a0f831224f96..dbfa42ef4a99 100644 --- a/include/asm-ppc64/bitops.h +++ b/include/asm-ppc64/bitops.h @@ -42,7 +42,7 @@ #ifdef __KERNEL__ -#include +#include /* * clear_bit doesn't imply a memory barrier diff --git a/include/asm-ppc64/futex.h b/include/asm-ppc64/futex.h index cb2640b3a408..266b460de44e 100644 --- a/include/asm-ppc64/futex.h +++ b/include/asm-ppc64/futex.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ diff --git a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h index 59c958aea4db..bd7c9532d77b 100644 --- a/include/asm-ppc64/io.h +++ b/include/asm-ppc64/io.h @@ -15,7 +15,7 @@ #ifdef CONFIG_PPC_ISERIES #include #endif -#include +#include #include #include diff --git a/include/asm-ppc64/memory.h b/include/asm-ppc64/memory.h deleted file mode 100644 index af53ffb55726..000000000000 --- a/include/asm-ppc64/memory.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _ASM_PPC64_MEMORY_H_ -#define _ASM_PPC64_MEMORY_H_ - -/* - * 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 - -/* - * Arguably the bitops and *xchg operations don't imply any memory barrier - * or SMP ordering, but in fact a lot of drivers expect them to imply - * both, since they do on x86 cpus. - */ -#ifdef CONFIG_SMP -#define EIEIO_ON_SMP "eieio\n" -#define ISYNC_ON_SMP "\n\tisync" -#define SYNC_ON_SMP "lwsync\n\t" -#else -#define EIEIO_ON_SMP -#define ISYNC_ON_SMP -#define SYNC_ON_SMP -#endif - -static inline void eieio(void) -{ - __asm__ __volatile__ ("eieio" : : : "memory"); -} - -static inline void isync(void) -{ - __asm__ __volatile__ ("isync" : : : "memory"); -} - -#ifdef CONFIG_SMP -#define eieio_on_smp() eieio() -#define isync_on_smp() isync() -#else -#define eieio_on_smp() __asm__ __volatile__("": : :"memory") -#define isync_on_smp() __asm__ __volatile__("": : :"memory") -#endif - -/* Macros for adjusting thread priority (hardware multi-threading) */ -#define HMT_very_low() asm volatile("or 31,31,31 # very low priority") -#define HMT_low() asm volatile("or 1,1,1 # low priority") -#define HMT_medium_low() asm volatile("or 6,6,6 # medium low priority") -#define HMT_medium() asm volatile("or 2,2,2 # medium priority") -#define HMT_medium_high() asm volatile("or 5,5,5 # medium high priority") -#define HMT_high() asm volatile("or 3,3,3 # high priority") - -#define HMT_VERY_LOW "\tor 31,31,31 # very low priority\n" -#define HMT_LOW "\tor 1,1,1 # low priority\n" -#define HMT_MEDIUM_LOW "\tor 6,6,6 # medium low priority\n" -#define HMT_MEDIUM "\tor 2,2,2 # medium priority\n" -#define HMT_MEDIUM_HIGH "\tor 5,5,5 # medium high priority\n" -#define HMT_HIGH "\tor 3,3,3 # high priority\n" - -#endif diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 4146189006e3..e5fc18531ec1 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -368,6 +368,14 @@ GLUE(.,name): #define mfasr() ({unsigned long rval; \ asm volatile("mfasr %0" : "=r" (rval)); rval;}) +/* Macros for adjusting thread priority (hardware multi-threading) */ +#define HMT_very_low() asm volatile("or 31,31,31 # very low priority") +#define HMT_low() asm volatile("or 1,1,1 # low priority") +#define HMT_medium_low() asm volatile("or 6,6,6 # medium low priority") +#define HMT_medium() asm volatile("or 2,2,2 # medium priority") +#define HMT_medium_high() asm volatile("or 5,5,5 # medium high priority") +#define HMT_high() asm volatile("or 3,3,3 # high priority") + static inline void set_tb(unsigned int upper, unsigned int lower) { mttbl(0); diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 375015c62f20..1fbdc9f0590c 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include /* * Memory barrier. @@ -48,7 +48,7 @@ #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() -#define smp_wmb() __asm__ __volatile__ ("eieio" : : : "memory") +#define smp_wmb() eieio() #define smp_read_barrier_depends() read_barrier_depends() #else #define smp_mb() __asm__ __volatile__("": : :"memory") From 342e73b3d6fd1321d1eaaa6a935f267a300ceebd Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Thu, 22 Sep 2005 14:55:30 -0500 Subject: [PATCH 0199/1939] [PATCH] powerpc: Merge asm-ppc*/rwsem.h Merge asm-ppc*/rwsem.h into include/asm-powerpc. Removed smp_*mb() memory barriers from the ppc32 code as they are now burried in the atomic_*() functions as suggested by Paul, implemented by Arnd, and pushed out by Becky. I am not the droid you are looking for. This patch depends on Becky's atomic.h merge patch. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/rwsem.h | 18 +-- include/asm-ppc/rwsem.h | 172 --------------------- 2 files changed, 7 insertions(+), 183 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/rwsem.h (91%) delete mode 100644 include/asm-ppc/rwsem.h diff --git a/include/asm-ppc64/rwsem.h b/include/asm-powerpc/rwsem.h similarity index 91% rename from include/asm-ppc64/rwsem.h rename to include/asm-powerpc/rwsem.h index bd5c2f093575..0a5b83a3c949 100644 --- a/include/asm-ppc64/rwsem.h +++ b/include/asm-powerpc/rwsem.h @@ -1,18 +1,14 @@ +#ifndef _ASM_POWERPC_RWSEM_H +#define _ASM_POWERPC_RWSEM_H + +#ifdef __KERNEL__ + /* * include/asm-ppc64/rwsem.h: R/W semaphores for PPC using the stuff * in lib/rwsem.c. Adapted largely from include/asm-i386/rwsem.h * by Paul Mackerras . - * - * 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 _PPC64_RWSEM_H -#define _PPC64_RWSEM_H - -#ifdef __KERNEL__ #include #include #include @@ -163,5 +159,5 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) return atomic_add_return(delta, (atomic_t *)(&sem->count)); } -#endif /* __KERNEL__ */ -#endif /* _PPC_RWSEM_XADD_H */ +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_RWSEM_H */ diff --git a/include/asm-ppc/rwsem.h b/include/asm-ppc/rwsem.h deleted file mode 100644 index 3e738f483c11..000000000000 --- a/include/asm-ppc/rwsem.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff - * in lib/rwsem.c. Adapted largely from include/asm-i386/rwsem.h - * by Paul Mackerras . - */ - -#ifndef _PPC_RWSEM_H -#define _PPC_RWSEM_H - -#ifdef __KERNEL__ -#include -#include -#include -#include - -/* - * the semaphore definition - */ -struct rw_semaphore { - /* XXX this should be able to be an atomic_t -- paulus */ - signed long count; -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) -#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS -#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) - spinlock_t wait_lock; - struct list_head wait_list; -#if RWSEM_DEBUG - int debug; -#endif -}; - -/* - * initialisation - */ -#if RWSEM_DEBUG -#define __RWSEM_DEBUG_INIT , 0 -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name) \ - { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) \ - __RWSEM_DEBUG_INIT } - -#define DECLARE_RWSEM(name) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name) - -extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -#if RWSEM_DEBUG - sem->debug = 0; -#endif -} - -/* - * lock for reading - */ -static inline void __down_read(struct rw_semaphore *sem) -{ - if (atomic_inc_return((atomic_t *)(&sem->count)) > 0) - smp_wmb(); - else - rwsem_down_read_failed(sem); -} - -static inline int __down_read_trylock(struct rw_semaphore *sem) -{ - int tmp; - - while ((tmp = sem->count) >= 0) { - if (tmp == cmpxchg(&sem->count, tmp, - tmp + RWSEM_ACTIVE_READ_BIAS)) { - smp_wmb(); - return 1; - } - } - return 0; -} - -/* - * lock for writing - */ -static inline void __down_write(struct rw_semaphore *sem) -{ - int tmp; - - tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)); - if (tmp == RWSEM_ACTIVE_WRITE_BIAS) - smp_wmb(); - else - rwsem_down_write_failed(sem); -} - -static inline int __down_write_trylock(struct rw_semaphore *sem) -{ - int tmp; - - tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, - RWSEM_ACTIVE_WRITE_BIAS); - smp_wmb(); - return tmp == RWSEM_UNLOCKED_VALUE; -} - -/* - * unlock after reading - */ -static inline void __up_read(struct rw_semaphore *sem) -{ - int tmp; - - smp_wmb(); - tmp = atomic_dec_return((atomic_t *)(&sem->count)); - if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0) - rwsem_wake(sem); -} - -/* - * unlock after writing - */ -static inline void __up_write(struct rw_semaphore *sem) -{ - smp_wmb(); - if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)) < 0) - rwsem_wake(sem); -} - -/* - * implement atomic add functionality - */ -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) -{ - atomic_add(delta, (atomic_t *)(&sem->count)); -} - -/* - * downgrade write lock to read lock - */ -static inline void __downgrade_write(struct rw_semaphore *sem) -{ - int tmp; - - smp_wmb(); - tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); - if (tmp < 0) - rwsem_downgrade_wake(sem); -} - -/* - * implement exchange and add functionality - */ -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) -{ - smp_mb(); - return atomic_add_return(delta, (atomic_t *)(&sem->count)); -} - -#endif /* __KERNEL__ */ -#endif /* _PPC_RWSEM_XADD_H */ From d6a4c847e43c851cc0ddf73087a730227223f989 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Fri, 23 Sep 2005 11:07:36 -0500 Subject: [PATCH 0200/1939] [PATCH] powerpc: merge semaphore.h powerpc: Merge semaphore.h Adopted the ppc64 version of semaphore.h. The 32-bit version used smp_wmb(), but recent updates to atomic.h mean this is no longer required. The 64-bit version made use of unlikely(), which has been retained in the combined version. This patch requires the recent atomic.h patch. Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- .../{asm-ppc64 => asm-powerpc}/semaphore.h | 6 +- include/asm-ppc/semaphore.h | 111 ------------------ 2 files changed, 3 insertions(+), 114 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/semaphore.h (95%) delete mode 100644 include/asm-ppc/semaphore.h diff --git a/include/asm-ppc64/semaphore.h b/include/asm-powerpc/semaphore.h similarity index 95% rename from include/asm-ppc64/semaphore.h rename to include/asm-powerpc/semaphore.h index aefe7753ea41..fd42fe97158f 100644 --- a/include/asm-ppc64/semaphore.h +++ b/include/asm-powerpc/semaphore.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_SEMAPHORE_H -#define _PPC64_SEMAPHORE_H +#ifndef _ASM_POWERPC_SEMAPHORE_H +#define _ASM_POWERPC_SEMAPHORE_H /* * Remove spinlock-based RW semaphores; RW semaphore definitions are @@ -95,4 +95,4 @@ static inline void up(struct semaphore * sem) #endif /* __KERNEL__ */ -#endif /* !(_PPC64_SEMAPHORE_H) */ +#endif /* _ASM_POWERPC_SEMAPHORE_H */ diff --git a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h deleted file mode 100644 index 89e6e73be08c..000000000000 --- a/include/asm-ppc/semaphore.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _PPC_SEMAPHORE_H -#define _PPC_SEMAPHORE_H - -/* - * Swiped from asm-sparc/semaphore.h and modified - * -- Cort (cort@cs.nmt.edu) - * - * Stole some rw spinlock-based semaphore stuff from asm-alpha/semaphore.h - * -- Ani Joshi (ajoshi@unixbox.com) - * - * Remove spinlock-based RW semaphores; RW semaphore definitions are - * now in rwsem.h and we use the generic lib/rwsem.c implementation. - * Rework semaphores to use atomic_dec_if_positive. - * -- Paul Mackerras (paulus@samba.org) - */ - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -struct semaphore { - /* - * Note that any negative value of count is equivalent to 0, - * but additionally indicates that some process(es) might be - * sleeping on `wait'. - */ - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __MUTEX_INITIALIZER(name) \ - __SEMAPHORE_INITIALIZER(name, 1) - -#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) -#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -extern inline void down(struct semaphore * sem) -{ - might_sleep(); - - /* - * Try to get the semaphore, take the slow path if we fail. - */ - if (atomic_dec_return(&sem->count) < 0) - __down(sem); - smp_wmb(); -} - -extern inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - - if (atomic_dec_return(&sem->count) < 0) - ret = __down_interruptible(sem); - smp_wmb(); - return ret; -} - -extern inline int down_trylock(struct semaphore * sem) -{ - int ret; - - ret = atomic_dec_if_positive(&sem->count) < 0; - smp_wmb(); - return ret; -} - -extern inline void up(struct semaphore * sem) -{ - smp_wmb(); - if (atomic_inc_return(&sem->count) <= 0) - __up(sem); -} - -#endif /* __KERNEL__ */ - -#endif /* !(_PPC_SEMAPHORE_H) */ From 14cf11af6cf608eb8c23e989ddb17a715ddce109 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 26 Sep 2005 16:04:21 +1000 Subject: [PATCH 0201/1939] powerpc: Merge enough to start building in arch/powerpc. This creates the directory structure under arch/powerpc and a bunch of Kconfig files. It does a first-cut merge of arch/powerpc/mm, arch/powerpc/lib and arch/powerpc/platforms/powermac. This is enough to build a 32-bit powermac kernel with ARCH=powerpc. For now we are getting some unmerged files from arch/ppc/kernel and arch/ppc/syslib, or arch/ppc64/kernel. This makes some minor changes to files in those directories and files outside arch/powerpc. The boot directory is still not merged. That's going to be interesting. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 861 +++++ arch/powerpc/Kconfig.debug | 73 + arch/powerpc/Makefile | 222 ++ arch/powerpc/kernel/Makefile | 18 + arch/powerpc/kernel/asm-offsets.c | 262 ++ arch/powerpc/kernel/fpu.S | 133 + arch/powerpc/kernel/head.S | 1545 +++++++++ arch/powerpc/kernel/head_44x.S | 778 +++++ arch/powerpc/kernel/head_4xx.S | 1016 ++++++ arch/powerpc/kernel/head_64.S | 2011 +++++++++++ arch/powerpc/kernel/head_8xx.S | 860 +++++ arch/powerpc/kernel/head_fsl_booke.S | 1058 ++++++ arch/powerpc/kernel/idle_6xx.S | 233 ++ arch/powerpc/kernel/process.c | 724 ++++ arch/powerpc/kernel/semaphore.c | 135 + arch/powerpc/kernel/traps.c | 1047 ++++++ arch/powerpc/kernel/vector.S | 197 ++ arch/powerpc/kernel/vmlinux.lds | 174 + arch/powerpc/kernel/vmlinux.lds.S | 172 + arch/powerpc/lib/Makefile | 9 + arch/powerpc/lib/checksum.S | 225 ++ arch/powerpc/lib/checksum64.S | 229 ++ arch/powerpc/lib/copy32.S | 543 +++ arch/powerpc/lib/copypage.S | 121 + arch/powerpc/lib/copyuser.S | 576 ++++ arch/powerpc/lib/div64.S | 58 + arch/powerpc/lib/e2a.c | 108 + arch/powerpc/lib/memcpy.S | 172 + arch/powerpc/lib/rheap.c | 693 ++++ arch/powerpc/lib/sstep.c | 141 + arch/powerpc/lib/strcase.c | 23 + arch/powerpc/lib/string.S | 203 ++ arch/powerpc/lib/usercopy.c | 41 + arch/powerpc/mm/44x_mmu.c | 120 + arch/powerpc/mm/4xx_mmu.c | 141 + arch/powerpc/mm/Makefile | 12 + arch/powerpc/mm/fault.c | 391 +++ arch/powerpc/mm/fsl_booke_mmu.c | 237 ++ arch/powerpc/mm/hash_32.S | 618 ++++ arch/powerpc/mm/init.c | 581 ++++ arch/powerpc/mm/init64.c | 385 +++ arch/powerpc/mm/mem.c | 299 ++ arch/powerpc/mm/mem64.c | 259 ++ arch/powerpc/mm/mem_pieces.c | 163 + arch/powerpc/mm/mem_pieces.h | 48 + arch/powerpc/mm/mmu_context.c | 86 + arch/powerpc/mm/mmu_context64.c | 63 + arch/powerpc/mm/mmu_decl.h | 85 + arch/powerpc/mm/pgtable.c | 470 +++ arch/powerpc/mm/pgtable64.c | 357 ++ arch/powerpc/mm/ppc_mmu.c | 296 ++ arch/powerpc/mm/tlb.c | 183 + arch/powerpc/platforms/4xx/Kconfig | 280 ++ arch/powerpc/platforms/85xx/Kconfig | 86 + arch/powerpc/platforms/8xx/Kconfig | 352 ++ arch/powerpc/platforms/apus/Kconfig | 130 + arch/powerpc/platforms/embedded6xx/Kconfig | 313 ++ arch/powerpc/platforms/iseries/Kconfig | 31 + arch/powerpc/platforms/powermac/Makefile | 9 + arch/powerpc/platforms/powermac/pmac.h | 31 + .../platforms/powermac/pmac_backlight.c | 202 ++ arch/powerpc/platforms/powermac/pmac_cache.S | 359 ++ .../powerpc/platforms/powermac/pmac_cpufreq.c | 728 ++++ .../powerpc/platforms/powermac/pmac_feature.c | 3062 +++++++++++++++++ .../powerpc/platforms/powermac/pmac_low_i2c.c | 523 +++ arch/powerpc/platforms/powermac/pmac_nvram.c | 584 ++++ arch/powerpc/platforms/powermac/pmac_pci.c | 1341 ++++++++ arch/powerpc/platforms/powermac/pmac_pic.c | 655 ++++ arch/powerpc/platforms/powermac/pmac_pic.h | 11 + arch/powerpc/platforms/powermac/pmac_setup.c | 662 ++++ arch/powerpc/platforms/powermac/pmac_sleep.S | 396 +++ arch/powerpc/platforms/powermac/pmac_smp.c | 716 ++++ arch/powerpc/platforms/powermac/pmac_time.c | 291 ++ arch/powerpc/platforms/prep/Kconfig | 22 + arch/powerpc/platforms/pseries/Kconfig | 47 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/mpic.c | 904 +++++ arch/ppc/kernel/Makefile | 21 + arch/ppc/kernel/setup.c | 8 + arch/ppc/platforms/prep_setup.c | 3 - arch/ppc/syslib/Makefile | 14 + drivers/macintosh/via-pmu.c | 2 +- fs/proc/proc_misc.c | 8 - include/asm-powerpc/kdebug.h | 42 + include/asm-powerpc/kprobes.h | 67 + include/asm-powerpc/mpic.h | 279 ++ include/asm-powerpc/reg.h | 446 +++ include/asm-powerpc/system.h | 350 ++ include/asm-ppc/smp.h | 17 +- 89 files changed, 32423 insertions(+), 25 deletions(-) create mode 100644 arch/powerpc/Kconfig create mode 100644 arch/powerpc/Kconfig.debug create mode 100644 arch/powerpc/Makefile create mode 100644 arch/powerpc/kernel/Makefile create mode 100644 arch/powerpc/kernel/asm-offsets.c create mode 100644 arch/powerpc/kernel/fpu.S create mode 100644 arch/powerpc/kernel/head.S create mode 100644 arch/powerpc/kernel/head_44x.S create mode 100644 arch/powerpc/kernel/head_4xx.S create mode 100644 arch/powerpc/kernel/head_64.S create mode 100644 arch/powerpc/kernel/head_8xx.S create mode 100644 arch/powerpc/kernel/head_fsl_booke.S create mode 100644 arch/powerpc/kernel/idle_6xx.S create mode 100644 arch/powerpc/kernel/process.c create mode 100644 arch/powerpc/kernel/semaphore.c create mode 100644 arch/powerpc/kernel/traps.c create mode 100644 arch/powerpc/kernel/vector.S create mode 100644 arch/powerpc/kernel/vmlinux.lds create mode 100644 arch/powerpc/kernel/vmlinux.lds.S create mode 100644 arch/powerpc/lib/Makefile create mode 100644 arch/powerpc/lib/checksum.S create mode 100644 arch/powerpc/lib/checksum64.S create mode 100644 arch/powerpc/lib/copy32.S create mode 100644 arch/powerpc/lib/copypage.S create mode 100644 arch/powerpc/lib/copyuser.S create mode 100644 arch/powerpc/lib/div64.S create mode 100644 arch/powerpc/lib/e2a.c create mode 100644 arch/powerpc/lib/memcpy.S create mode 100644 arch/powerpc/lib/rheap.c create mode 100644 arch/powerpc/lib/sstep.c create mode 100644 arch/powerpc/lib/strcase.c create mode 100644 arch/powerpc/lib/string.S create mode 100644 arch/powerpc/lib/usercopy.c create mode 100644 arch/powerpc/mm/44x_mmu.c create mode 100644 arch/powerpc/mm/4xx_mmu.c create mode 100644 arch/powerpc/mm/Makefile create mode 100644 arch/powerpc/mm/fault.c create mode 100644 arch/powerpc/mm/fsl_booke_mmu.c create mode 100644 arch/powerpc/mm/hash_32.S create mode 100644 arch/powerpc/mm/init.c create mode 100644 arch/powerpc/mm/init64.c create mode 100644 arch/powerpc/mm/mem.c create mode 100644 arch/powerpc/mm/mem64.c create mode 100644 arch/powerpc/mm/mem_pieces.c create mode 100644 arch/powerpc/mm/mem_pieces.h create mode 100644 arch/powerpc/mm/mmu_context.c create mode 100644 arch/powerpc/mm/mmu_context64.c create mode 100644 arch/powerpc/mm/mmu_decl.h create mode 100644 arch/powerpc/mm/pgtable.c create mode 100644 arch/powerpc/mm/pgtable64.c create mode 100644 arch/powerpc/mm/ppc_mmu.c create mode 100644 arch/powerpc/mm/tlb.c create mode 100644 arch/powerpc/platforms/4xx/Kconfig create mode 100644 arch/powerpc/platforms/85xx/Kconfig create mode 100644 arch/powerpc/platforms/8xx/Kconfig create mode 100644 arch/powerpc/platforms/apus/Kconfig create mode 100644 arch/powerpc/platforms/embedded6xx/Kconfig create mode 100644 arch/powerpc/platforms/iseries/Kconfig create mode 100644 arch/powerpc/platforms/powermac/Makefile create mode 100644 arch/powerpc/platforms/powermac/pmac.h create mode 100644 arch/powerpc/platforms/powermac/pmac_backlight.c create mode 100644 arch/powerpc/platforms/powermac/pmac_cache.S create mode 100644 arch/powerpc/platforms/powermac/pmac_cpufreq.c create mode 100644 arch/powerpc/platforms/powermac/pmac_feature.c create mode 100644 arch/powerpc/platforms/powermac/pmac_low_i2c.c create mode 100644 arch/powerpc/platforms/powermac/pmac_nvram.c create mode 100644 arch/powerpc/platforms/powermac/pmac_pci.c create mode 100644 arch/powerpc/platforms/powermac/pmac_pic.c create mode 100644 arch/powerpc/platforms/powermac/pmac_pic.h create mode 100644 arch/powerpc/platforms/powermac/pmac_setup.c create mode 100644 arch/powerpc/platforms/powermac/pmac_sleep.S create mode 100644 arch/powerpc/platforms/powermac/pmac_smp.c create mode 100644 arch/powerpc/platforms/powermac/pmac_time.c create mode 100644 arch/powerpc/platforms/prep/Kconfig create mode 100644 arch/powerpc/platforms/pseries/Kconfig create mode 100644 arch/powerpc/sysdev/Makefile create mode 100644 arch/powerpc/sysdev/mpic.c create mode 100644 include/asm-powerpc/kdebug.h create mode 100644 include/asm-powerpc/kprobes.h create mode 100644 include/asm-powerpc/mpic.h create mode 100644 include/asm-powerpc/reg.h create mode 100644 include/asm-powerpc/system.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig new file mode 100644 index 000000000000..edfac467b9e0 --- /dev/null +++ b/arch/powerpc/Kconfig @@ -0,0 +1,861 @@ +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux/PowerPC Kernel Configuration" + +config PPC64 + bool "64-bit kernel" + default n + help + This option selects whether a 32-bit or a 64-bit kernel + will be built. + +config PPC32 + bool + default y if !PPC64 + +config 64BIT + bool + default y if PPC64 + +config PPC_MERGE + def_bool y + +config MMU + bool + default y + +config UID16 + bool + +config GENERIC_HARDIRQS + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + +config RWSEM_XCHGADD_ALGORITHM + bool + default y + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config PPC + bool + default y + +config EARLY_PRINTK + bool + default y if PPC64 + +config COMPAT + bool + default y if PPC64 + +config SYSVIPC_COMPAT + bool + depends on COMPAT && SYSVIPC + default y + +# All PPC32s use generic nvram driver through ppc_md +config GENERIC_NVRAM + bool + default y if PPC32 + +config SCHED_NO_NO_OMIT_FRAME_POINTER + bool + default y + +config ARCH_MAY_HAVE_PC_FDC + bool + default y + +menu "Processor support" +choice + prompt "Processor Type" + depends on PPC32 + default 6xx + +config 6xx + bool "6xx/7xx/74xx" + select PPC_FPU + help + There are four families of PowerPC chips supported. The more common + types (601, 603, 604, 740, 750, 7400), the Motorola embedded + versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the AMCC + embedded versions (403 and 405) and the high end 64 bit Power + processors (POWER 3, POWER4, and IBM PPC970 also known as G5). + + Unless you are building a kernel for one of the embedded processor + systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx. + Note that the kernel runs in 32-bit mode even on 64-bit chips. + +config PPC_52xx + bool "Freescale 52xx" + +config PPC_82xx + bool "Freescale 82xx" + +config PPC_83xx + bool "Freescale 83xx" + +config 40x + bool "AMCC 40x" + +config 44x + bool "AMCC 44x" + +config PPC64BRIDGE + select PPC_FPU + bool "POWER3, POWER4 and PPC970 (G5)" + +config 8xx + bool "Freescale 8xx" + +config E200 + bool "Freescale e200" + +config E500 + bool "Freescale e500" +endchoice + +config POWER4_ONLY + bool "Optimize for POWER4" + depends on PPC64 || PPC64BRIDGE + default n + ---help--- + Cause the compiler to optimize for POWER4/POWER5/PPC970 processors. + The resulting binary will not work on POWER3 or RS64 processors + when compiled with binutils 2.15 or later. + +config POWER3 + bool + depends on PPC64 || PPC64BRIDGE + default y if !POWER4_ONLY + +config POWER4 + depends on PPC64 || PPC64BRIDGE + def_bool y + +config PPC_FPU + bool + default y if PPC64 + +config BOOKE + bool + depends on E200 || E500 + default y + +config FSL_BOOKE + bool + depends on E200 || E500 + default y + +config PTE_64BIT + bool + depends on 44x || E500 + default y if 44x + default y if E500 && PHYS_64BIT + +config PHYS_64BIT + bool 'Large physical address support' if E500 + depends on 44x || E500 + default y if 44x + ---help--- + This option enables kernel support for larger than 32-bit physical + addresses. This features is not be available on all e500 cores. + + If in doubt, say N here. + +config ALTIVEC + bool "AltiVec Support" + depends on 6xx || POWER4 + ---help--- + This option enables kernel support for the Altivec extensions to the + PowerPC processor. The kernel currently supports saving and restoring + altivec registers, and turning on the 'altivec enable' bit so user + processes can execute altivec instructions. + + This option is only usefully if you have a processor that supports + altivec (G4, otherwise known as 74xx series), but does not have + any affect on a non-altivec cpu (it does, however add code to the + kernel). + + If in doubt, say Y here. + +config SPE + bool "SPE Support" + depends on E200 || E500 + ---help--- + This option enables kernel support for the Signal Processing + Extensions (SPE) to the PowerPC processor. The kernel currently + supports saving and restoring SPE registers, and turning on the + 'spe enable' bit so user processes can execute SPE instructions. + + This option is only useful if you have a processor that supports + SPE (e500, otherwise known as 85xx series), but does not have any + effect on a non-spe cpu (it does, however add code to the kernel). + + If in doubt, say Y here. + +config PPC_STD_MMU + bool + depends on 6xx || POWER3 || POWER4 || PPC64 + default y + +config PPC_STD_MMU_32 + def_bool y + depends on PPC_STD_MMU && PPC32 + +config SMP + depends on PPC_STD_MMU + bool "Symmetric multi-processing support" + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, say N. If you have a system with more + than one CPU, say Y. Note that the kernel does not currently + support SMP machines with 603/603e/603ev or PPC750 ("G3") processors + since they have inadequate hardware support for multiprocessor + operation. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on single-processor machines. + On a single-processor machine, the kernel will run faster if you say + N here. + + If you don't know what to do here, say N. + +config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 128 + depends on SMP + default "32" if PPC64 + default "4" + +config NOT_COHERENT_CACHE + bool + depends on 4xx || 8xx || E200 + default y +endmenu + +source "init/Kconfig" + +menu "Platform support" + depends on PPC64 || 6xx + +choice + prompt "Machine type" + default PPC_MULTIPLATFORM + +config PPC_MULTIPLATFORM + bool "Generic desktop/server/laptop" + help + Select this option if configuring for an IBM pSeries or + RS/6000 machine, an Apple machine, or a PReP, CHRP, + Maple or Cell-based machine. + +config PPC_ISERIES + bool "IBM Legacy iSeries" + depends on PPC64 + +config EMBEDDED6xx + bool "Embedded 6xx/7xx/7xxx-based board" + depends on PPC32 + +config APUS + bool "Amiga-APUS" + depends on PPC32 && BROKEN + help + Select APUS if configuring for a PowerUP Amiga. + More information is available at: + . +endchoice + +config PPC_PSERIES + depends on PPC_MULTIPLATFORM && PPC64 + bool " IBM pSeries & new (POWER5-based) iSeries" + default y + +config PPC_CHRP + bool " Common Hardware Reference Platform (CHRP) based machines" + depends on PPC_MULTIPLATFORM && PPC32 + default y + +config PPC_PMAC + bool " Apple PowerMac based machines" + depends on PPC_MULTIPLATFORM + default y + +config PPC_PMAC64 + bool + depends on PPC_PMAC && POWER4 + default y + +config PPC_PREP + bool " PowerPC Reference Platform (PReP) based machines" + depends on PPC_MULTIPLATFORM && PPC32 + default y + +config PPC_MAPLE + depends on PPC_MULTIPLATFORM && PPC64 + bool " Maple 970FX Evaluation Board" + select U3_DART + select MPIC_BROKEN_U3 + default n + help + This option enables support for the Maple 970FX Evaluation Board. + For more informations, refer to + +config PPC_BPA + bool " Broadband Processor Architecture" + depends on PPC_MULTIPLATFORM && PPC64 + +config PPC_OF + bool + depends on PPC_MULTIPLATFORM # for now + default y + +config XICS + depends on PPC_PSERIES + bool + default y + +config U3_DART + bool + depends on PPC_MULTIPLATFORM && PPC64 + default n + +config MPIC + depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE + bool + default y + +config MPIC_BROKEN_U3 + bool + depends on PPC_MAPLE + default y + +config BPA_IIC + depends on PPC_BPA + bool + default y + +config IBMVIO + depends on PPC_PSERIES || PPC_ISERIES + bool + default y + +source "drivers/cpufreq/Kconfig" + +config CPU_FREQ_PMAC + bool "Support for Apple PowerBooks" + depends on CPU_FREQ && ADB_PMU && PPC32 + select CPU_FREQ_TABLE + help + This adds support for frequency switching on Apple PowerBooks, + this currently includes some models of iBook & Titanium + PowerBook. + +config PPC601_SYNC_FIX + bool "Workarounds for PPC601 bugs" + depends on 6xx && (PPC_PREP || PPC_PMAC) + help + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near + certain instructions, typically those that make major changes to the + CPU state. These extra instructions reduce performance slightly. + If you say N here, these extra instructions will not be included, + resulting in a kernel which will run faster but may not run at all + on some systems with the PPC601 chip. + + If in doubt, say Y here. + +config TAU + bool "Thermal Management Support" + depends on 6xx + help + G3 and G4 processors have an on-chip temperature sensor called the + 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die + temperature within 2-4 degrees Celsius. This option shows the current + on-die temperature in /proc/cpuinfo if the cpu supports it. + + Unfortunately, on some chip revisions, this sensor is very inaccurate + and in some cases, does not work at all, so don't assume the cpu + temp is actually what /proc/cpuinfo says it is. + +config TAU_INT + bool "Interrupt driven TAU driver (DANGEROUS)" + depends on TAU + ---help--- + The TAU supports an interrupt driven mode which causes an interrupt + whenever the temperature goes out of range. This is the fastest way + to get notified the temp has exceeded a range. With this option off, + a timer is used to re-check the temperature periodically. + + However, on some cpus it appears that the TAU interrupt hardware + is buggy and can cause a situation which would lead unexplained hard + lockups. + + Unless you are extending the TAU driver, or enjoy kernel/hardware + debugging, leave this option off. + +config TAU_AVERAGE + bool "Average high and low temp" + depends on TAU + ---help--- + The TAU hardware can compare the temperature to an upper and lower + bound. The default behavior is to show both the upper and lower + bound in /proc/cpuinfo. If the range is large, the temperature is + either changing a lot, or the TAU hardware is broken (likely on some + G4's). If the range is small (around 4 degrees), the temperature is + relatively stable. If you say Y here, a single temperature value, + halfway between the upper and lower bounds, will be reported in + /proc/cpuinfo. + + If in doubt, say N here. +endmenu + +source arch/powerpc/platforms/embedded6xx/Kconfig +source arch/powerpc/platforms/4xx/Kconfig +source arch/powerpc/platforms/85xx/Kconfig +source arch/powerpc/platforms/8xx/Kconfig + +menu "Kernel options" + +config HIGHMEM + bool "High memory support" + depends on PPC32 + +source kernel/Kconfig.hz +source kernel/Kconfig.preempt +source "fs/Kconfig.binfmt" + +# We optimistically allocate largepages from the VM, so make the limit +# large enough (16MB). This badly named config option is actually +# max order + 1 +config FORCE_MAX_ZONEORDER + int + depends on PPC64 + default "13" + +config MATH_EMULATION + bool "Math emulation" + depends on 4xx || 8xx || E200 || E500 + ---help--- + Some PowerPC chips designed for embedded applications do not have + a floating-point unit and therefore do not implement the + floating-point instructions in the PowerPC instruction set. If you + say Y here, the kernel will include code to emulate a floating-point + unit, which will allow programs that use floating-point + instructions to run. + +config IOMMU_VMERGE + bool "Enable IOMMU virtual merging (EXPERIMENTAL)" + depends on EXPERIMENTAL && PPC64 + default n + help + Cause IO segments sent to a device for DMA to be merged virtually + by the IOMMU when they happen to have been allocated contiguously. + This doesn't add pressure to the IOMMU allocator. However, some + drivers don't support getting large merged segments coming back + from *_map_sg(). Say Y if you know the drivers you are using are + properly handling this case. + +config HOTPLUG_CPU + bool "Support for enabling/disabling CPUs" + depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) + ---help--- + Say Y here to be able to disable and re-enable individual + CPUs at runtime on SMP machines. + + Say N if you are unsure. + +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on PPC_MULTIPLATFORM && EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config EMBEDDEDBOOT + bool + depends on 8xx || 8260 + default y + +config PC_KEYBOARD + bool "PC PS/2 style Keyboard" + depends on 4xx || CPM2 + +config PPCBUG_NVRAM + bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC + default y if PPC_PREP + +config IRQ_ALL_CPUS + bool "Distribute interrupts on all CPUs by default" + depends on SMP && !MV64360 + help + This option gives the kernel permission to distribute IRQs across + multiple CPUs. Saying N here will route all IRQs to the first + CPU. Generally saying Y is safe, although some problems have been + reported with SMP Power Macintoshes with this option enabled. + +source "arch/powerpc/platforms/pseries/Kconfig" + +config ARCH_SELECT_MEMORY_MODEL + def_bool y + depends on PPC64 + +config ARCH_FLATMEM_ENABLE + def_bool y + depends on PPC64 && !NUMA + +config ARCH_DISCONTIGMEM_ENABLE + def_bool y + depends on SMP && PPC_PSERIES + +config ARCH_DISCONTIGMEM_DEFAULT + def_bool y + depends on ARCH_DISCONTIGMEM_ENABLE + +config ARCH_FLATMEM_ENABLE + def_bool y + depends on PPC64 + +config ARCH_SPARSEMEM_ENABLE + def_bool y + depends on ARCH_DISCONTIGMEM_ENABLE + +source "mm/Kconfig" + +config HAVE_ARCH_EARLY_PFN_TO_NID + def_bool y + depends on NEED_MULTIPLE_NODES + +# Some NUMA nodes have memory ranges that span +# other nodes. Even though a pfn is valid and +# between a node's start and end pfns, it may not +# reside on that node. +# +# This is a relatively temporary hack that should +# be able to go away when sparsemem is fully in +# place + +config NODES_SPAN_OTHER_NODES + def_bool y + depends on NEED_MULTIPLE_NODES + +config NUMA + bool "NUMA support" + default y if DISCONTIGMEM || SPARSEMEM + +config SCHED_SMT + bool "SMT (Hyperthreading) scheduler support" + depends on PPC64 && SMP + default off + help + SMT scheduler support improves the CPU scheduler's decision making + when dealing with POWER5 cpus at a cost of slightly increased + overhead in some places. If unsure say N here. + +config PROC_DEVICETREE + bool "Support for Open Firmware device tree in /proc" + depends on PPC_OF && PROC_FS + help + This option adds a device-tree directory under /proc which contains + an image of the device tree that the kernel copies from Open + Firmware. If unsure, say Y here. + +source "arch/powerpc/platforms/prep/Kconfig" + +config CMDLINE_BOOL + bool "Default bootloader kernel arguments" + depends on !PPC_ISERIES + +config CMDLINE + string "Initial kernel command string" + depends on CMDLINE_BOOL + default "console=ttyS0,9600 console=tty0 root=/dev/sda2" + help + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + most cases you will need to specify the root device here. + +if !44x || BROKEN +source kernel/power/Kconfig +endif + +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc//seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + +endmenu + +config ISA_DMA_API + bool + default y + +menu "Bus options" + +config ISA + bool "Support for ISA-bus hardware" + depends on PPC_PREP || PPC_CHRP + help + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff + inside your box. If you have an Apple machine, say N here; if you + have an IBM RS/6000 or pSeries machine or a PReP machine, say Y. If + you have an embedded board, consult your board documentation. + +config GENERIC_ISA_DMA + bool + depends on PPC64 || POWER4 || 6xx && !CPM2 + default y + +config EISA + bool + +config SBUS + bool + +# Yes MCA RS/6000s exist but Linux-PPC does not currently support any +config MCA + bool + +config PCI + bool "PCI support" if 40x || CPM2 || 83xx || 85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) + default y if !40x && !CPM2 && !8xx && !APUS && !83xx && !85xx + default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS + default PCI_QSPAN if !4xx && !CPM2 && 8xx + help + Find out whether your system includes a PCI bus. PCI is the name of + a bus system, i.e. the way the CPU talks to the other stuff inside + your box. If you say Y here, the kernel will include drivers and + infrastructure code to support PCI bus devices. + +config PCI_DOMAINS + bool + default PCI + +config MPC83xx_PCI2 + bool " Supprt for 2nd PCI host controller" + depends on PCI && MPC834x + default y if MPC834x_SYS + +config PCI_QSPAN + bool "QSpan PCI" + depends on !4xx && !CPM2 && 8xx + help + Say Y here if you have a system based on a Motorola 8xx-series + embedded processor with a QSPAN PCI interface, otherwise say N. + +config PCI_8260 + bool + depends on PCI && 8260 + default y + +config 8260_PCI9 + bool " Enable workaround for MPC826x erratum PCI 9" + depends on PCI_8260 && !ADS8272 + default y + +choice + prompt " IDMA channel for PCI 9 workaround" + depends on 8260_PCI9 + +config 8260_PCI9_IDMA1 + bool "IDMA1" + +config 8260_PCI9_IDMA2 + bool "IDMA2" + +config 8260_PCI9_IDMA3 + bool "IDMA3" + +config 8260_PCI9_IDMA4 + bool "IDMA4" + +endchoice + +source "drivers/pci/Kconfig" + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Advanced setup" + depends on PPC32 + +config ADVANCED_OPTIONS + bool "Prompt for advanced kernel configuration options" + help + This option will enable prompting for a variety of advanced kernel + configuration options. These options can cause the kernel to not + work if they are set incorrectly, but can be used to optimize certain + aspects of kernel memory management. + + Unless you know what you are doing, say N here. + +comment "Default settings for advanced configuration options are used" + depends on !ADVANCED_OPTIONS + +config HIGHMEM_START_BOOL + bool "Set high memory pool address" + depends on ADVANCED_OPTIONS && HIGHMEM + help + This option allows you to set the base address of the kernel virtual + area used to map high memory pages. This can be useful in + optimizing the layout of kernel virtual memory. + + Say N here unless you know what you are doing. + +config HIGHMEM_START + hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL + default "0xfe000000" + +config LOWMEM_SIZE_BOOL + bool "Set maximum low memory" + depends on ADVANCED_OPTIONS + help + This option allows you to set the maximum amount of memory which + will be used as "low memory", that is, memory which the kernel can + access directly, without having to set up a kernel virtual mapping. + This can be useful in optimizing the layout of kernel virtual + memory. + + Say N here unless you know what you are doing. + +config LOWMEM_SIZE + hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL + default "0x30000000" + +config KERNEL_START_BOOL + bool "Set custom kernel base address" + depends on ADVANCED_OPTIONS + help + This option allows you to set the kernel virtual address at which + the kernel will map low memory (the kernel image will be linked at + this address). This can be useful in optimizing the virtual memory + layout of the system. + + Say N here unless you know what you are doing. + +config KERNEL_START + hex "Virtual address of kernel base" if KERNEL_START_BOOL + default "0xc0000000" + +config TASK_SIZE_BOOL + bool "Set custom user task size" + depends on ADVANCED_OPTIONS + help + This option allows you to set the amount of virtual address space + allocated to user tasks. This can be useful in optimizing the + virtual memory layout of the system. + + Say N here unless you know what you are doing. + +config TASK_SIZE + hex "Size of user task space" if TASK_SIZE_BOOL + default "0x80000000" + +config CONSISTENT_START_BOOL + bool "Set custom consistent memory pool address" + depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE + help + This option allows you to set the base virtual address + of the the consistent memory pool. This pool of virtual + memory is used to make consistent memory allocations. + +config CONSISTENT_START + hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL + default "0xff100000" if NOT_COHERENT_CACHE + +config CONSISTENT_SIZE_BOOL + bool "Set custom consistent memory pool size" + depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE + help + This option allows you to set the size of the the + consistent memory pool. This pool of virtual memory + is used to make consistent memory allocations. + +config CONSISTENT_SIZE + hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL + default "0x00200000" if NOT_COHERENT_CACHE + +config BOOT_LOAD_BOOL + bool "Set the boot link/load address" + depends on ADVANCED_OPTIONS && !PPC_MULTIPLATFORM + help + This option allows you to set the initial load address of the zImage + or zImage.initrd file. This can be useful if you are on a board + which has a small amount of memory. + + Say N here unless you know what you are doing. + +config BOOT_LOAD + hex "Link/load address for booting" if BOOT_LOAD_BOOL + default "0x00400000" if 40x || 8xx || 8260 + default "0x01000000" if 44x + default "0x00800000" + +config PIN_TLB + bool "Pinned Kernel TLBs (860 ONLY)" + depends on ADVANCED_OPTIONS && 8xx +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +# XXX source "arch/ppc/8xx_io/Kconfig" + +# XXX source "arch/ppc/8260_io/Kconfig" + +source "arch/powerpc/platforms/iseries/Kconfig" + +source "lib/Kconfig" + +source "arch/powerpc/oprofile/Kconfig" + +source "arch/powerpc/Kconfig.debug" + +source "security/Kconfig" + +config KEYS_COMPAT + bool + depends on COMPAT && KEYS + default y + +source "crypto/Kconfig" diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug new file mode 100644 index 000000000000..61653cb60c4e --- /dev/null +++ b/arch/powerpc/Kconfig.debug @@ -0,0 +1,73 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) + select DEBUG_INFO + help + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. See for more information. + Unless you are intending to debug the kernel, say N here. + +choice + prompt "Serial Port" + depends on KGDB + default KGDB_TTYS1 + +config KGDB_TTYS0 + bool "ttyS0" + +config KGDB_TTYS1 + bool "ttyS1" + +config KGDB_TTYS2 + bool "ttyS2" + +config KGDB_TTYS3 + bool "ttyS3" + +endchoice + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB && 8xx || CPM2 + help + If you enable this, all serial console messages will be sent + over the gdb stub. + If unsure, say N. + +config XMON + bool "Include xmon kernel debugger" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. + +config BDI_SWITCH + bool "Include BDI-2000 user context switcher" + depends on DEBUG_KERNEL + help + Include in-kernel support for the Abatron BDI2000 debugger. + Unless you are intending to debug the kernel with one of these + machines, say N here. + +config BOOTX_TEXT + bool "Support for early boot text console (BootX or OpenFirmware only)" + depends PPC_OF + help + Say Y here to see progress messages from the boot firmware in text + mode. Requires either BootX or Open Firmware. + +config SERIAL_TEXT_DEBUG + bool "Support for early boot texts over serial port" + depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \ + PPC_GEN550 || PPC_MPC52xx + +config PPC_OCP + bool + depends on IBM_OCP || XILINX_OCP + default y + +endmenu diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile new file mode 100644 index 000000000000..8a65e112211b --- /dev/null +++ b/arch/powerpc/Makefile @@ -0,0 +1,222 @@ +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture. +# +# 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) 1994 by Linus Torvalds +# Changes for PPC by Gary Thomas +# Rewritten by Cort Dougan and Paul Mackerras +# + +# This must match PAGE_OFFSET in include/asm-powerpc/page.h. +KERNELLOAD := $(CONFIG_KERNEL_START) + +HAS_BIARCH := $(call cc-option-yn, -m32) + +ifeq ($(CONFIG_PPC64),y) +SZ := 64 + +# Set default 32 bits cross compilers for vdso and boot wrapper +CROSS32_COMPILE ?= + +CROSS32CC := $(CROSS32_COMPILE)gcc +CROSS32AS := $(CROSS32_COMPILE)as +CROSS32LD := $(CROSS32_COMPILE)ld +CROSS32OBJCOPY := $(CROSS32_COMPILE)objcopy + +ifeq ($(HAS_BIARCH),y) +ifeq ($(CROSS32_COMPILE),) +CROSS32CC := $(CC) -m32 +CROSS32AS := $(AS) -a32 +CROSS32LD := $(LD) -m elf32ppc +CROSS32OBJCOPY := $(OBJCOPY) +endif +endif + +export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY + +new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) + +ifeq ($(new_nm),y) +NM := $(NM) --synthetic +endif + +else +SZ := 32 +endif + +ifeq ($(HAS_BIARCH),y) +override AS += -a$(SZ) +override LD += -m elf$(SZ)ppc +override CC += -m$(SZ) +endif + +LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic -e $(KERNELLOAD) + +# The -Iarch/$(ARCH)/include is temporary while we are merging +CPPFLAGS += -Iarch/$(ARCH) -Iarch/$(ARCH)/include +AFLAGS += -Iarch/$(ARCH) +CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe +ifeq ($(CONFIG_PPC64),y) +CFLAGS += -mminimal-toc -mtraceback=none -mcall-aixdesc +else +CFLAGS += -ffixed-r2 -mmultiple +endif +CPP = $(CC) -E $(CFLAGS) +# Temporary hack until we have migrated to asm-powerpc +LINUXINCLUDE += -Iarch/$(ARCH)/include + +CHECKFLAGS += -m$(SZ) -D__powerpc__ -D__powerpc$(SZ)__ + +ifeq ($(CONFIG_PPC64),y) +GCC_VERSION := $(call cc-version) +GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi) + +ifeq ($(CONFIG_POWER4_ONLY),y) +ifeq ($(CONFIG_ALTIVEC),y) +ifeq ($(GCC_BROKEN_VEC),y) + CFLAGS += $(call cc-option,-mcpu=970) +else + CFLAGS += $(call cc-option,-mcpu=power4) +endif +else + CFLAGS += $(call cc-option,-mcpu=power4) +endif +else + CFLAGS += $(call cc-option,-mtune=power4) +endif +endif + +# Enable unit-at-a-time mode when possible. It shrinks the +# kernel considerably. +CFLAGS += $(call cc-option,-funit-at-a-time) + +ifndef CONFIG_FSL_BOOKE +CFLAGS += -mstring +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 +cpu-as-$(CONFIG_E500) += -Wa,-me500 +cpu-as-$(CONFIG_E200) += -Wa,-me200 + +AFLAGS += $(cpu-as-y) +CFLAGS += $(cpu-as-y) + +# Default to the common case. +KBUILD_DEFCONFIG := common_defconfig + +head-y := arch/powerpc/kernel/head.o +head-$(CONFIG_PPC64) := arch/powerpc/kernel/head_64.o +head-$(CONFIG_8xx) := arch/powerpc/kernel/head_8xx.o +head-$(CONFIG_4xx) := arch/powerpc/kernel/head_4xx.o +head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o +head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o + +ifeq ($(CONFIG_PPC32),y) +head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o +head-$(CONFIG_POWER4) += arch/powerpc/kernel/idle_power4.o +head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o +endif + +core-y += arch/powerpc/kernel/ \ + arch/powerpc/mm/ \ + arch/powerpc/lib/ \ + arch/powerpc/sysdev/ +core-$(CONFIG_PPC32) += arch/ppc/kernel/ \ + arch/ppc/syslib/ +core-$(CONFIG_PPC64) += arch/ppc64/kernel/ +core-$(CONFIG_PPC_PMAC) += arch/powerpc/platforms/powermac/ +core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ +core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ +core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ +core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ +core-$(CONFIG_XMON) += arch/powerpc/xmon/ +core-$(CONFIG_APUS) += arch/ppc/amiga/ +drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ +drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ +drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/ + +drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ + +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm + +.PHONY: $(BOOT_TARGETS) + +all: uImage zImage + +CPPFLAGS_vmlinux.lds := -Upowerpc + +# All the instructions talk about "make bzImage". +bzImage: zImage + +boot := arch/$(ARCH)/boot + +$(BOOT_TARGETS): vmlinux + $(Q)$(MAKE) $(build)=$(boot) $@ + +uImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot)/images $(boot)/images/$@ + +define archhelp + @echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/images/zImage.*)' + @echo ' uImage - Create a bootable image for U-Boot / PPCBoot' + @echo ' install - Install kernel using' + @echo ' (your) ~/bin/installkernel or' + @echo ' (distribution) /sbin/installkernel or' + @echo ' install to $$(INSTALL_PATH) and run lilo' + @echo ' *_defconfig - Select default config from arch/$(ARCH)/ppc/configs' +endef + +archclean: + $(Q)$(MAKE) $(clean)=arch/ppc/boot + # Temporary hack until we have migrated to asm-powerpc + $(Q)rm -rf arch/$(ARCH)/include + +archprepare: checkbin + +# Temporary hack until we have migrated to asm-powerpc +ifeq ($(CONFIG_PPC64),y) +include/asm: arch/$(ARCH)/include/asm +arch/$(ARCH)/include/asm: + $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi + $(Q)ln -fsn $(srctree)/include/asm-ppc64 arch/$(ARCH)/include/asm +else +include/asm: arch/$(ARCH)/include/asm +arch/$(ARCH)/include/asm: + $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi + $(Q)ln -fsn $(srctree)/include/asm-ppc arch/$(ARCH)/include/asm +endif + +# Use the file '.tmp_gas_check' for binutils tests, as gas won't output +# to stdout and these checks are run even on install targets. +TOUT := .tmp_gas_check +# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec +# instructions. +# gcc-3.4 and binutils-2.14 are a fatal combination. +GCC_VERSION := $(call cc-version) + +checkbin: + @if test "$(GCC_VERSION)" = "0304" ; then \ + if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \ + echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \ + echo 'correctly with gcc-3.4 and your version of binutils.'; \ + echo '*** Please upgrade your binutils or downgrade your gcc'; \ + false; \ + fi ; \ + fi + @if ! /bin/echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; then \ + echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' ; \ + echo 'correctly with old versions of binutils.' ; \ + echo '*** Please upgrade your binutils to 2.12.1 or newer' ; \ + false ; \ + fi + +CLEAN_FILES += $(TOUT) + diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile new file mode 100644 index 000000000000..62c4a51a23d7 --- /dev/null +++ b/arch/powerpc/kernel/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for the linux kernel. +# + +extra-$(CONFIG_PPC_STD_MMU) := head.o +extra_$(CONFIG_PPC64) := head_64.o +extra-$(CONFIG_40x) := head_4xx.o +extra-$(CONFIG_44x) := head_44x.o +extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o +extra-$(CONFIG_8xx) := head_8xx.o +extra-$(CONFIG_6xx) += idle_6xx.o +extra-$(CONFIG_POWER4) += idle_power4.o +extra-$(CONFIG_PPC_FPU) += fpu.o +extra-y += vmlinux.lds + +obj-y := semaphore.o traps.o process.o + +obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c new file mode 100644 index 000000000000..16cf0b7ee2b7 --- /dev/null +++ b/arch/powerpc/kernel/asm-offsets.c @@ -0,0 +1,262 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * 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 +#ifdef CONFIG_PPC64 +#include +#include +#include +#include +#include +#include +#include +#endif + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* thread struct on stack */ + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); +#ifdef CONFIG_PPC32 + DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); +#endif +#ifdef CONFIG_PPC64 + DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); + DEFINE(THREAD_SHIFT, THREAD_SHIFT); +#endif + DEFINE(THREAD_SIZE, THREAD_SIZE); + + /* task_struct->thread */ + DEFINE(THREAD, offsetof(struct task_struct, thread)); + DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(KSP, offsetof(struct thread_struct, ksp)); + DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); + DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); + DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); + DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); + DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); + DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); + DEFINE(PT_PTRACED, PT_PTRACED); +#endif +#ifdef CONFIG_PPC64 + DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); +#endif + +#ifdef CONFIG_ALTIVEC + DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); + DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); + DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); + DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0])); + DEFINE(THREAD_ACC, offsetof(struct thread_struct, acc)); + DEFINE(THREAD_SPEFSCR, offsetof(struct thread_struct, spefscr)); + DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe)); +#endif /* CONFIG_SPE */ + /* Interrupt register frame */ + DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); +#ifndef CONFIG_PPC64 + DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); +#else + DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); + + /* 288 = # of volatile regs, int & fp, for leaf routines */ + /* which do not stack a frame. See the PPC64 ABI. */ + DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); +#endif + /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */ + DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); + DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); + DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); + DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); + DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); + DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); + DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); + DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); + DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); + DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); + DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); + DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); + DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); + DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); + DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); + DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); + DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); + DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17])); + DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18])); + DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19])); + DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); + DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); + DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); + DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); + DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24])); + DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25])); + DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26])); + DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27])); + DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28])); + DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); + DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); + DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); + /* + * Note: these symbols include _ because they overlap with special + * register names + */ + DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); + DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); + DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); + DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); + DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); + DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); + DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); + DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); + DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); + /* The PowerPC 400-class & Book-E processors have neither the DAR nor the DSISR + * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs + * for such processors. For critical interrupts we use them to + * hold SRR0 and SRR1. + */ + DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); + DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); + DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); + DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); + DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(CLONE_VM, CLONE_VM); + DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); + DEFINE(MM_PGD, offsetof(struct mm_struct, pgd)); + + /* About the CPU features table */ + DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); + DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask)); + DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value)); + DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); + DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); + +#ifdef CONFIG_PPC64 + DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); + + DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); + DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); + DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page)); + DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); + DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); + DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); + DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); + + /* paca */ + DEFINE(PACA_SIZE, sizeof(struct paca_struct)); + DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); + DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start)); + DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack)); + DEFINE(PACACURRENT, offsetof(struct paca_struct, __current)); + DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, saved_msr)); + DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real)); + DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr)); + DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); + DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); + DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); + DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); + 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_HUGETLB_PAGE + DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); + DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); +#endif /* CONFIG_HUGETLB_PAGE */ + DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); + DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); + DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); + DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); + DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); + DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); + DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); + DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); + DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); + DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); + DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); + DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); + + /* RTAS */ + DEFINE(RTASBASE, offsetof(struct rtas_t, base)); + DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); + + DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); + + /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ + DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); + DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); + + /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ + DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); + DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); + + /* systemcfg offsets for use by vdso */ + DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp)); + DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec)); + DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs)); + DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec)); + DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count)); + DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest)); + DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime)); + DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32)); + DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64)); + + /* timeval/timezone offsets for use by vdso */ + DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec)); + DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec)); + DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec)); + DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec)); + DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); + DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); +#endif + + DEFINE(pbe_address, offsetof(struct pbe, address)); + DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); + DEFINE(pbe_next, offsetof(struct pbe, next)); + + DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); + return 0; +} diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S new file mode 100644 index 000000000000..665d7d34304c --- /dev/null +++ b/arch/powerpc/kernel/fpu.S @@ -0,0 +1,133 @@ +/* + * FPU support code, moved here from head.S so that it can be used + * by chips which use other head-whatever.S files. + * + * 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 + +/* + * This task wants to use the FPU now. + * On UP, disable FP for the task which had the FPU previously, + * and save its floating-point registers in its thread_struct. + * Load up this task's FP registers from its thread_struct, + * enable the FPU for the current task and return to the task. + */ + .globl load_up_fpu +load_up_fpu: + mfmsr r5 + ori r5,r5,MSR_FP +#ifdef CONFIG_PPC64BRIDGE + clrldi r5,r5,1 /* turn off 64-bit mode */ +#endif /* CONFIG_PPC64BRIDGE */ + SYNC + MTMSRD(r5) /* enable use of fpu now */ + isync +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + */ +#ifndef CONFIG_SMP + tophys(r6,0) /* get __pa constant */ + addis r3,r6,last_task_used_math@ha + lwz r4,last_task_used_math@l(r3) + cmpwi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,THREAD /* want last_task_used_math->thread */ + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r4) + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r10,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r10 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of FP after return */ + mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ + lwz r4,THREAD_FPEXC_MODE(r5) + ori r9,r9,MSR_FP /* enable FP for current */ + or r9,r9,r4 + lfd fr0,THREAD_FPSCR-4(r5) + mtfsf 0xff,fr0 + REST_32FPRS(0, r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + sub r4,r4,r6 + stw r4,last_task_used_math@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + /* we haven't used ctr or xer or lr */ + b fast_exception_return + +/* + * FP unavailable trap from kernel - print a message, but let + * the task use FP in the kernel until it returns to user mode. + */ + .globl KernelFP +KernelFP: + lwz r3,_MSR(r1) + ori r3,r3,MSR_FP + stw r3,_MSR(r1) /* enable use of FP after return */ + lis r3,86f@h + ori r3,r3,86f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +86: .string "floating point used in kernel (task=%p, pc=%x)\n" + .align 4,0 + +/* + * giveup_fpu(tsk) + * Disable FP for the task given as the argument, + * and save the floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + */ + .globl giveup_fpu +giveup_fpu: + mfmsr r5 + ori r5,r5,MSR_FP + SYNC_601 + ISYNC_601 + MTMSRD(r5) /* enable use of fpu now */ + SYNC_601 + isync + cmpwi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpwi 0,r5,0 + SAVE_32FPRS(0, r3) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r3 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_math@ha + stw r5,last_task_used_math@l(r4) +#endif /* CONFIG_SMP */ + blr diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S new file mode 100644 index 000000000000..d05509f197d0 --- /dev/null +++ b/arch/powerpc/kernel/head.S @@ -0,0 +1,1545 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * This file contains the low-level support and setup for the + * PowerPC platform, including trap and interrupt dispatch. + * (The PPC 8xx embedded CPUs use head_8xx.S instead.) + * + * 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 + +#ifdef CONFIG_APUS +#include +#endif + +#ifdef CONFIG_PPC64BRIDGE +#define LOAD_BAT(n, reg, RA, RB) \ + ld RA,(n*32)+0(reg); \ + ld RB,(n*32)+8(reg); \ + mtspr SPRN_IBAT##n##U,RA; \ + mtspr SPRN_IBAT##n##L,RB; \ + ld RA,(n*32)+16(reg); \ + ld RB,(n*32)+24(reg); \ + mtspr SPRN_DBAT##n##U,RA; \ + mtspr SPRN_DBAT##n##L,RB; \ + +#else /* CONFIG_PPC64BRIDGE */ + +/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ +#define LOAD_BAT(n, reg, RA, RB) \ + /* see the comment for clear_bats() -- Cort */ \ + li RA,0; \ + mtspr SPRN_IBAT##n##U,RA; \ + mtspr SPRN_DBAT##n##U,RA; \ + lwz RA,(n*16)+0(reg); \ + lwz RB,(n*16)+4(reg); \ + mtspr SPRN_IBAT##n##U,RA; \ + mtspr SPRN_IBAT##n##L,RB; \ + beq 1f; \ + lwz RA,(n*16)+8(reg); \ + lwz RB,(n*16)+12(reg); \ + mtspr SPRN_DBAT##n##U,RA; \ + mtspr SPRN_DBAT##n##L,RB; \ +1: +#endif /* CONFIG_PPC64BRIDGE */ + + .text + .stabs "arch/ppc/kernel/",N_SO,0,0,0f + .stabs "head.S",N_SO,0,0,0f +0: + .globl _stext +_stext: + +/* + * _start is defined this way because the XCOFF loader in the OpenFirmware + * on the powermac expects the entry point to be a procedure descriptor. + */ + .text + .globl _start +_start: + /* + * These are here for legacy reasons, the kernel used to + * need to look like a coff function entry for the pmac + * but we're always started by some kind of bootloader now. + * -- Cort + */ + nop /* used by __secondary_hold on prep (mtx) and chrp smp */ + nop /* used by __secondary_hold on prep (mtx) and chrp smp */ + nop + +/* PMAC + * Enter here with the kernel text, data and bss loaded starting at + * 0, running with virtual == physical mapping. + * r5 points to the prom entry point (the client interface handler + * address). Address translation is turned on, with the prom + * managing the hash table. Interrupts are disabled. The stack + * pointer (r1) points to just below the end of the half-meg region + * from 0x380000 - 0x400000, which is mapped in already. + * + * If we are booted from MacOS via BootX, we enter with the kernel + * image loaded somewhere, and the following values in registers: + * r3: 'BooX' (0x426f6f58) + * r4: virtual address of boot_infos_t + * r5: 0 + * + * APUS + * r3: 'APUS' + * r4: physical address of memory base + * Linux/m68k style BootInfo structure at &_end. + * + * PREP + * This is jumped to on prep systems right after the kernel is relocated + * to its proper place in memory by the boot loader. The expected layout + * of the regs is: + * r3: ptr to residual data + * r4: initrd_start or if no initrd then 0 + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + * + * This just gets a minimal mmu environment setup so we can call + * start_here() to do the real work. + * -- Cort + */ + + .globl __start +__start: +/* + * We have to do any OF calls before we map ourselves to KERNELBASE, + * because OF may have I/O devices mapped into that area + * (particularly on CHRP). + */ + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* cpu # */ + +/* + * early_init() does the early machine identification and does + * the necessary low-level setup and clears the BSS + * -- Cort + */ + bl early_init + +/* + * On POWER4, we first need to tweak some CPU configuration registers + * like real mode cache inhibit or exception base + */ +#ifdef CONFIG_POWER4 + bl __970_cpu_preinit +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_APUS +/* On APUS the __va/__pa constants need to be set to the correct + * values before continuing. + */ + mr r4,r30 + bl fix_mem_constants +#endif /* CONFIG_APUS */ + +/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains + * the physical address we are running at, returned by early_init() + */ + bl mmu_off +__after_mmu_off: +#ifndef CONFIG_POWER4 + bl clear_bats + bl flush_tlbs + + bl initial_bats +#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) + bl setup_disp_bat +#endif +#else /* CONFIG_POWER4 */ + bl reloc_offset + bl initial_mm_power4 +#endif /* CONFIG_POWER4 */ + +/* + * Call setup_cpu for CPU 0 and initialize 6xx Idle + */ + bl reloc_offset + li r24,0 /* cpu# */ + bl call_setup_cpu /* Call setup_cpu for this CPU */ +#ifdef CONFIG_6xx + bl reloc_offset + bl init_idle_6xx +#endif /* CONFIG_6xx */ +#ifdef CONFIG_POWER4 + bl reloc_offset + bl init_idle_power4 +#endif /* CONFIG_POWER4 */ + + +#ifndef CONFIG_APUS +/* + * We need to run with _start at physical address 0. + * On CHRP, we are loaded at 0x10000 since OF on CHRP uses + * the exception vectors at 0 (and therefore this copy + * overwrites OF's exception vectors with our own). + * If the MMU is already turned on, we copy stuff to KERNELBASE, + * otherwise we copy it to 0. + */ + bl reloc_offset + mr r26,r3 + addis r4,r3,KERNELBASE@h /* current address of _start */ + cmpwi 0,r4,0 /* are we already running at 0? */ + bne relocate_kernel +#endif /* CONFIG_APUS */ +/* + * we now have the 1st 16M of ram mapped with the bats. + * prep needs the mmu to be turned on here, but pmac already has it on. + * this shouldn't bother the pmac since it just gets turned on again + * as we jump to our code at KERNELBASE. -- Cort + * Actually no, pmac doesn't have it on any more. BootX enters with MMU + * off, and in other cases, we now turn it off before changing BATs above. + */ +turn_on_mmu: + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SPRN_SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SPRN_SRR0,r0 + SYNC + RFI /* enables MMU */ + +/* + * We need __secondary_hold as a place to hold the other cpus on + * an SMP machine, even when we are running a UP kernel. + */ + . = 0xc0 /* for prep bootloader */ + li r3,1 /* MTX only has 1 cpu */ + .globl __secondary_hold +__secondary_hold: + /* tell the master we're here */ + stw r3,4(0) +#ifdef CONFIG_SMP +100: lwz r4,0(0) + /* wait until we're told to start */ + cmpw 0,r4,r3 + bne 100b + /* our cpu # was at addr 0 - go */ + mr r24,r3 /* cpu # */ + b __secondary_start +#else + b . +#endif /* CONFIG_SMP */ + +/* + * Exception entry code. This code runs with address translation + * turned off, i.e. using physical addresses. + * We assume sprg3 has the physical address of the current + * task's thread_struct. + */ +#define EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; \ + mtspr SPRN_SPRG1,r11; \ + mfcr r10; \ + EXCEPTION_PROLOG_1; \ + EXCEPTION_PROLOG_2 + +#define EXCEPTION_PROLOG_1 \ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \ + andi. r11,r11,MSR_PR; \ + tophys(r11,r1); /* use tophys(r1) if kernel */ \ + beq 1f; \ + mfspr r11,SPRN_SPRG3; \ + lwz r11,THREAD_INFO-THREAD(r11); \ + addi r11,r11,THREAD_SIZE; \ + tophys(r11,r11); \ +1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */ + + +#define EXCEPTION_PROLOG_2 \ + CLR_TOP32(r11); \ + stw r10,_CCR(r11); /* save registers */ \ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRN_SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRN_SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_SRR0; \ + mfspr r9,SPRN_SRR1; \ + stw r1,GPR1(r11); \ + stw r1,0(r11); \ + tovirt(r1,r11); /* set new kernel sp */ \ + li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ + MTMSRD(r10); /* (except for mach check in rtas) */ \ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r11, r12 (SRR0), and r9 (SRR1). + * + * Note2: once we have set r1 we are in a position to take exceptions + * again, and we could thus set MSR:RI at that point. + */ + +/* + * Exception vectors. + */ +#define EXCEPTION(n, label, hdlr, xfer) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + li r10,MSR_KERNEL; \ + copyee(r10, r9); \ + bl tfer; \ +i##n: \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \ + ret_from_except) + +/* System reset */ +/* core99 pmac starts the seconary here by changing the vector, and + putting it back to what it was (UnknownException) when done. */ +#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) + . = 0x100 + b __secondary_start_gemini +#else + EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) +#endif + +/* Machine check */ +/* + * On CHRP, this is complicated by the fact that we could get a + * machine check inside RTAS, and we have no guarantee that certain + * critical registers will have the values we expect. The set of + * registers that might have bad values includes all the GPRs + * and all the BATs. We indicate that we are in RTAS by putting + * a non-zero value, the address of the exception frame to use, + * in SPRG2. The machine check handler checks SPRG2 and uses its + * value if it is non-zero. If we ever needed to free up SPRG2, + * we could use a field in the thread_info or thread_struct instead. + * (Other exception handlers assume that r1 is a valid kernel stack + * pointer when we take an exception from supervisor mode.) + * -- paulus. + */ + . = 0x200 + mtspr SPRN_SPRG0,r10 + mtspr SPRN_SPRG1,r11 + mfcr r10 +#ifdef CONFIG_PPC_CHRP + mfspr r11,SPRN_SPRG2 + cmpwi 0,r11,0 + bne 7f +#endif /* CONFIG_PPC_CHRP */ + EXCEPTION_PROLOG_1 +7: EXCEPTION_PROLOG_2 + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef CONFIG_PPC_CHRP + mfspr r4,SPRN_SPRG2 + cmpwi cr1,r4,0 + bne cr1,1f +#endif + EXC_XFER_STD(0x200, MachineCheckException) +#ifdef CONFIG_PPC_CHRP +1: b machine_check_in_rtas +#endif + +/* Data access exception. */ + . = 0x300 +#ifdef CONFIG_PPC64BRIDGE + b DataAccess +DataAccessCont: +#else +DataAccess: + EXCEPTION_PROLOG +#endif /* CONFIG_PPC64BRIDGE */ + mfspr r10,SPRN_DSISR + andis. r0,r10,0xa470 /* weird error? */ + bne 1f /* if not, try to put a PTE */ + mfspr r4,SPRN_DAR /* into the hash table */ + rlwinm r3,r10,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */ + bl hash_page +1: stw r10,_DSISR(r11) + mr r5,r10 + mfspr r4,SPRN_DAR + EXC_XFER_EE_LITE(0x300, handle_page_fault) + +#ifdef CONFIG_PPC64BRIDGE +/* SLB fault on data access. */ + . = 0x380 + b DataSegment +#endif /* CONFIG_PPC64BRIDGE */ + +/* Instruction access exception. */ + . = 0x400 +#ifdef CONFIG_PPC64BRIDGE + b InstructionAccess +InstructionAccessCont: +#else +InstructionAccess: + EXCEPTION_PROLOG +#endif /* CONFIG_PPC64BRIDGE */ + andis. r0,r9,0x4000 /* no pte found? */ + beq 1f /* if so, try to put a PTE */ + li r3,0 /* into the hash table */ + mr r4,r12 /* SRR0 is fault address */ + bl hash_page +1: mr r4,r12 + mr r5,r9 + EXC_XFER_EE_LITE(0x400, handle_page_fault) + +#ifdef CONFIG_PPC64BRIDGE +/* SLB fault on instruction access. */ + . = 0x480 + b InstructionSegment +#endif /* CONFIG_PPC64BRIDGE */ + +/* External interrupt */ + EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) + +/* Alignment exception */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,SPRN_DAR + stw r4,_DAR(r11) + mfspr r5,SPRN_DSISR + stw r5,_DSISR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0x600, AlignmentException) + +/* Program check exception */ + EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + +/* Floating-point unavailable */ + . = 0x800 +FPUnavailable: + EXCEPTION_PROLOG + bne load_up_fpu /* if from user, just load it up */ + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x800, KernelFP) + +/* Decrementer */ + EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) + + EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + +/* System call */ + . = 0xc00 +SystemCall: + EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0xc00, DoSyscall) + +/* Single step - not used on 601 */ + EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) + +/* + * The Altivec unavailable trap is at 0x0f20. Foo. + * We effectively remap it to 0x3000. + * We include an altivec unavailable exception vector even if + * not configured for Altivec, so that you can't panic a + * non-altivec kernel running on a machine with altivec just + * by executing an altivec instruction. + */ + . = 0xf00 + b Trap_0f + + . = 0xf20 + b AltiVecUnavailable + +Trap_0f: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0xf00, UnknownException) + +/* + * Handle TLB miss for instruction on 603/603e. + * Note: we get an alternate set of r0 - r3 to use automatically. + */ + . = 0x1000 +InstructionTLBMiss: +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r3,SPRN_IMISS + lis r1,KERNELBASE@h /* check if kernel address */ + cmplw 0,r3,r1 + mfspr r2,SPRN_SPRG3 + li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ + lwz r2,PGDIR(r2) + blt+ 112f + lis r2,swapper_pg_dir@ha /* if kernel address, use */ + addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ +112: tophys(r2,r2) + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- InstructionAddressInvalid /* return if no mapping */ + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ + bne- InstructionAddressInvalid /* return if access not permitted */ + ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed bit) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r1,r1,r2 /* writable if _RW and _DIRTY */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ + ori r1,r1,0xe14 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ + mtspr SPRN_RPA,r1 + mfspr r3,SPRN_IMISS + tlbli r3 + mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi +InstructionAddressInvalid: + mfspr r3,SPRN_SRR1 + rlwinm r1,r3,9,6,6 /* Get load/store bit */ + + addis r1,r1,0x2000 + mtspr SPRN_DSISR,r1 /* (shouldn't be needed) */ + mtctr r0 /* Restore CTR */ + andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ + or r2,r2,r1 + mtspr SPRN_SRR1,r2 + mfspr r1,SPRN_IMISS /* Get failing address */ + rlwinm. r2,r2,0,31,31 /* Check for little endian access */ + rlwimi r2,r2,1,30,30 /* change 1 -> 3 */ + xor r1,r1,r2 + mtspr SPRN_DAR,r1 /* Set fault address */ + mfmsr r0 /* Restore "normal" registers */ + xoris r0,r0,MSR_TGPR>>16 + mtcrf 0x80,r3 /* Restore CR0 */ + mtmsr r0 + b InstructionAccess + +/* + * Handle TLB miss for DATA Load operation on 603/603e + */ + . = 0x1100 +DataLoadTLBMiss: +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r3,SPRN_DMISS + lis r1,KERNELBASE@h /* check if kernel address */ + cmplw 0,r3,r1 + mfspr r2,SPRN_SPRG3 + li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ + lwz r2,PGDIR(r2) + blt+ 112f + lis r2,swapper_pg_dir@ha /* if kernel address, use */ + addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ +112: tophys(r2,r2) + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- DataAddressInvalid /* return if no mapping */ + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ + bne- DataAddressInvalid /* return if access not permitted */ + ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed bit) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r1,r1,r2 /* writable if _RW and _DIRTY */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ + ori r1,r1,0xe14 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ + mtspr SPRN_RPA,r1 + mfspr r3,SPRN_DMISS + tlbld r3 + mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi +DataAddressInvalid: + mfspr r3,SPRN_SRR1 + rlwinm r1,r3,9,6,6 /* Get load/store bit */ + addis r1,r1,0x2000 + mtspr SPRN_DSISR,r1 + mtctr r0 /* Restore CTR */ + andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ + mtspr SPRN_SRR1,r2 + mfspr r1,SPRN_DMISS /* Get failing address */ + rlwinm. r2,r2,0,31,31 /* Check for little endian access */ + beq 20f /* Jump if big endian */ + xori r1,r1,3 +20: mtspr SPRN_DAR,r1 /* Set fault address */ + mfmsr r0 /* Restore "normal" registers */ + xoris r0,r0,MSR_TGPR>>16 + mtcrf 0x80,r3 /* Restore CR0 */ + mtmsr r0 + b DataAccess + +/* + * Handle TLB miss for DATA Store on 603/603e + */ + . = 0x1200 +DataStoreTLBMiss: +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r3,SPRN_DMISS + lis r1,KERNELBASE@h /* check if kernel address */ + cmplw 0,r3,r1 + mfspr r2,SPRN_SPRG3 + li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */ + lwz r2,PGDIR(r2) + blt+ 112f + lis r2,swapper_pg_dir@ha /* if kernel address, use */ + addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ +112: tophys(r2,r2) + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- DataAddressInvalid /* return if no mapping */ + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ + bne- DataAddressInvalid /* return if access not permitted */ + ori r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed/dirty bits) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + li r1,0xe15 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? 2: 0 */ + mtspr SPRN_RPA,r1 + mfspr r3,SPRN_DMISS + tlbld r3 + mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi + +#ifndef CONFIG_ALTIVEC +#define AltivecAssistException UnknownException +#endif + + EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, EXC_XFER_EE) + EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) +#ifdef CONFIG_POWER4 + EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD) +#else /* !CONFIG_POWER4 */ + EXCEPTION(0x1600, Trap_16, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) + EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) +#endif /* CONFIG_POWER4 */ + EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE) + EXCEPTION(0x2100, Trap_21, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2200, Trap_22, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2300, Trap_23, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2400, Trap_24, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2500, Trap_25, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2600, Trap_26, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2700, Trap_27, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2800, Trap_28, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2900, Trap_29, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2a00, Trap_2a, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2b00, Trap_2b, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2c00, Trap_2c, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2d00, Trap_2d, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2e00, Trap_2e, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2f00, MOLTrampoline, UnknownException, EXC_XFER_EE_LITE) + + .globl mol_trampoline + .set mol_trampoline, i0x2f00 + + . = 0x3000 + +AltiVecUnavailable: + EXCEPTION_PROLOG +#ifdef CONFIG_ALTIVEC + bne load_up_altivec /* if from user, just load it up */ +#endif /* CONFIG_ALTIVEC */ + EXC_XFER_EE_LITE(0xf20, AltivecUnavailException) + +#ifdef CONFIG_PPC64BRIDGE +DataAccess: + EXCEPTION_PROLOG + b DataAccessCont + +InstructionAccess: + EXCEPTION_PROLOG + b InstructionAccessCont + +DataSegment: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + mfspr r4,SPRN_DAR + stw r4,_DAR(r11) + EXC_XFER_STD(0x380, UnknownException) + +InstructionSegment: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_STD(0x480, UnknownException) +#endif /* CONFIG_PPC64BRIDGE */ + +#ifdef CONFIG_ALTIVEC +/* Note that the AltiVec support is closely modeled after the FP + * support. Changes to one are likely to be applicable to the + * other! */ +load_up_altivec: +/* + * Disable AltiVec for the task which had AltiVec previously, + * and save its AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + * On SMP we know the AltiVec units are free, since we give it up every + * switch. -- Kumar + */ + mfmsr r5 + oris r5,r5,MSR_VEC@h + MTMSRD(r5) /* enable use of AltiVec now */ + isync +/* + * For SMP, we don't do lazy AltiVec switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_altivec in switch_to. + */ +#ifndef CONFIG_SMP + tophys(r6,0) + addis r3,r6,last_task_used_altivec@ha + lwz r4,last_task_used_altivec@l(r3) + cmpwi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ + SAVE_32VRS(0,r10,r4) + mfvscr vr0 + li r10,THREAD_VSCR + stvx vr0,r10,r4 + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r10,MSR_VEC@h + andc r4,r4,r10 /* disable altivec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of AltiVec after return */ + oris r9,r9,MSR_VEC@h + mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ + li r4,1 + li r10,THREAD_VSCR + stw r4,THREAD_USED_VR(r5) + lvx vr0,r10,r5 + mtvscr vr0 + REST_32VRS(0,r10,r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + sub r4,r4,r6 + stw r4,last_task_used_altivec@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + /* we haven't used ctr or xer or lr */ + b fast_exception_return + +/* + * AltiVec unavailable trap from kernel - print a message, but let + * the task use AltiVec in the kernel until it returns to user mode. + */ +KernelAltiVec: + lwz r3,_MSR(r1) + oris r3,r3,MSR_VEC@h + stw r3,_MSR(r1) /* enable use of AltiVec after return */ + lis r3,87f@h + ori r3,r3,87f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +87: .string "AltiVec used in kernel (task=%p, pc=%x) \n" + .align 4,0 + +/* + * giveup_altivec(tsk) + * Disable AltiVec for the task given as the argument, + * and save the AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + */ + + .globl giveup_altivec +giveup_altivec: + mfmsr r5 + oris r5,r5,MSR_VEC@h + SYNC + MTMSRD(r5) /* enable use of AltiVec now */ + isync + cmpwi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpwi 0,r5,0 + SAVE_32VRS(0, r4, r3) + mfvscr vr0 + li r4,THREAD_VSCR + stvx vr0,r4,r3 + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_VEC@h + andc r4,r4,r3 /* disable AltiVec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_altivec@ha + stw r5,last_task_used_altivec@l(r4) +#endif /* CONFIG_SMP */ + blr +#endif /* CONFIG_ALTIVEC */ + +/* + * This code is jumped to from the startup code to copy + * the kernel image to physical address 0. + */ +relocate_kernel: + addis r9,r26,klimit@ha /* fetch klimit */ + lwz r25,klimit@l(r9) + addis r25,r25,-KERNELBASE@h + li r3,0 /* Destination base address */ + li r6,0 /* Destination offset */ + li r5,0x4000 /* # bytes of memory to copy */ + bl copy_and_flush /* copy the first 0x4000 bytes */ + addi r0,r3,4f@l /* jump to the address of 4f */ + mtctr r0 /* in copy and do the rest. */ + bctr /* jump to the copy */ +4: mr r5,r25 + bl copy_and_flush /* copy the rest */ + b turn_on_mmu + +/* + * Copy routine used to copy the kernel to start at physical address 0 + * and flush and invalidate the caches as needed. + * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset + * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. + */ +copy_and_flush: + addi r5,r5,-4 + addi r6,r6,-4 +4: li r0,L1_CACHE_LINE_SIZE/4 + mtctr r0 +3: addi r6,r6,4 /* copy a cache line */ + lwzx r0,r6,r4 + stwx r0,r6,r3 + bdnz 3b + dcbst r6,r3 /* write it to memory */ + sync + icbi r6,r3 /* flush the icache line */ + cmplw 0,r6,r5 + blt 4b + sync /* additional sync needed on g4 */ + isync + addi r5,r5,4 + addi r6,r6,4 + blr + +#ifdef CONFIG_APUS +/* + * On APUS the physical base address of the kernel is not known at compile + * time, which means the __pa/__va constants used are incorrect. In the + * __init section is recorded the virtual addresses of instructions using + * these constants, so all that has to be done is fix these before + * continuing the kernel boot. + * + * r4 = The physical address of the kernel base. + */ +fix_mem_constants: + mr r10,r4 + addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */ + neg r11,r10 /* phys_to_virt constant */ + + lis r12,__vtop_table_begin@h + ori r12,r12,__vtop_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__vtop_table_end@h + ori r13,r13,__vtop_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r10,16,16,31 /* half of vp const in low half */ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + sync /* additional sync needed on g4 */ + isync + +/* + * Map the memory where the exception handlers will + * be copied to when hash constants have been patched. + */ +#ifdef CONFIG_APUS_FAST_EXCEPT + lis r8,0xfff0 +#else + lis r8,0 +#endif + ori r8,r8,0x2 /* 128KB, supervisor */ + mtspr SPRN_DBAT3U,r8 + mtspr SPRN_DBAT3L,r8 + + lis r12,__ptov_table_begin@h + ori r12,r12,__ptov_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__ptov_table_end@h + ori r13,r13,__ptov_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r11,16,16,31 /* half of pv const in low half*/ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + + sync /* additional sync needed on g4 */ + isync /* No speculative loading until now */ + blr + +/*********************************************************************** + * Please note that on APUS the exception handlers are located at the + * physical address 0xfff0000. For this reason, the exception handlers + * cannot use relative branches to access the code below. + ***********************************************************************/ +#endif /* CONFIG_APUS */ + +#ifdef CONFIG_SMP +#ifdef CONFIG_GEMINI + .globl __secondary_start_gemini +__secondary_start_gemini: + mfspr r4,SPRN_HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr SPRN_HID0,r4 + sync + b __secondary_start +#endif /* CONFIG_GEMINI */ + + .globl __secondary_start_pmac_0 +__secondary_start_pmac_0: + /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ + li r24,0 + b 1f + li r24,1 + b 1f + li r24,2 + b 1f + li r24,3 +1: + /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0 + set to map the 0xf0000000 - 0xffffffff region */ + mfmsr r0 + rlwinm r0,r0,0,28,26 /* clear DR (0x10) */ + SYNC + mtmsr r0 + isync + + .globl __secondary_start +__secondary_start: +#ifdef CONFIG_PPC64BRIDGE + mfmsr r0 + clrldi r0,r0,1 /* make sure it's in 32-bit mode */ + SYNC + MTMSRD(r0) + isync +#endif + /* Copy some CPU settings from CPU 0 */ + bl __restore_cpu_setup + + lis r3,-KERNELBASE@h + mr r4,r24 + bl identify_cpu + bl call_setup_cpu /* Call setup_cpu for this CPU */ +#ifdef CONFIG_6xx + lis r3,-KERNELBASE@h + bl init_idle_6xx +#endif /* CONFIG_6xx */ +#ifdef CONFIG_POWER4 + lis r3,-KERNELBASE@h + bl init_idle_power4 +#endif /* CONFIG_POWER4 */ + + /* get current_thread_info and current */ + lis r1,secondary_ti@ha + tophys(r1,r1) + lwz r1,secondary_ti@l(r1) + tophys(r2,r1) + lwz r2,TI_TASK(r2) + + /* stack */ + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + tophys(r3,r1) + stw r0,0(r3) + + /* load up the MMU */ + bl load_up_mmu + + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* phys address of our thread_struct */ + CLR_TOP32(r4) + mtspr SPRN_SPRG3,r4 + li r3,0 + mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */ + + /* enable MMU and jump to start_secondary */ + li r4,MSR_KERNEL + FIX_SRR1(r4,r5) + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + SYNC + RFI +#endif /* CONFIG_SMP */ + +/* + * Those generic dummy functions are kept for CPUs not + * included in CONFIG_6xx + */ +_GLOBAL(__setup_cpu_power3) + blr +_GLOBAL(__setup_cpu_generic) + blr + +#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) +_GLOBAL(__save_cpu_setup) + blr +_GLOBAL(__restore_cpu_setup) + blr +#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */ + + +/* + * Load stuff into the MMU. Intended to be called with + * IR=0 and DR=0. + */ +load_up_mmu: + sync /* Force all PTE updates to finish */ + isync + tlbia /* Clear all TLB entries */ + sync /* wait for tlbia/tlbie to finish */ + TLBSYNC /* ... on all CPUs */ + /* Load the SDR1 register (hash table base & size) */ + lis r6,_SDR1@ha + tophys(r6,r6) + lwz r6,_SDR1@l(r6) + mtspr SPRN_SDR1,r6 +#ifdef CONFIG_PPC64BRIDGE + /* clear the ASR so we only use the pseudo-segment registers. */ + li r6,0 + mtasr r6 +#endif /* CONFIG_PPC64BRIDGE */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b +#ifndef CONFIG_POWER4 +/* Load the BAT registers with the values set up by MMU_init. + MMU_init takes care of whether we're on a 601 or not. */ + mfpvr r3 + srwi r3,r3,16 + cmpwi r3,1 + lis r3,BATS@ha + addi r3,r3,BATS@l + tophys(r3,r3) + LOAD_BAT(0,r3,r4,r5) + LOAD_BAT(1,r3,r4,r5) + LOAD_BAT(2,r3,r4,r5) + LOAD_BAT(3,r3,r4,r5) +#endif /* CONFIG_POWER4 */ + blr + +/* + * This is where the main kernel code starts. + */ +start_here: + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + /* Set up for using our exception vectors */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + CLR_TOP32(r4) + mtspr SPRN_SPRG3,r4 + li r3,0 + mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */ + + /* stack */ + lis r1,init_thread_union@ha + addi r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) +/* + * Do early bootinfo parsing, platform-specific initialization, + * and set up the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + +#ifdef CONFIG_APUS + /* Copy exception code to exception vector base on APUS. */ + lis r4,KERNELBASE@h +#ifdef CONFIG_APUS_FAST_EXCEPT + lis r3,0xfff0 /* Copy to 0xfff00000 */ +#else + lis r3,0 /* Copy to 0x00000000 */ +#endif + li r5,0x4000 /* # bytes of memory to copy */ + li r6,0 + bl copy_and_flush /* copy the first 0x4000 bytes */ +#endif /* CONFIG_APUS */ + +/* + * Go back to running unmapped so we can load up new values + * for SDR1 (hash table pointer) and the segment registers + * and change to using our exception vectors. + */ + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + FIX_SRR1(r3,r5) + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + SYNC + RFI +/* Load up the kernel context */ +2: bl load_up_mmu + +#ifdef CONFIG_BDI_SWITCH + /* Add helper information for the Abatron bdiGDB debugger. + * We do this here because we know the mmu is disabled, and + * will be enabled for real in just a few instructions. + */ + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r5, 0xf0(r0) /* This much match your Abatron config */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + tophys(r5, r5) + stw r6, 0(r5) +#endif /* CONFIG_BDI_SWITCH */ + +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + FIX_SRR1(r4,r5) + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + SYNC + RFI + +/* + * Set up the segment registers for a new context. + */ +_GLOBAL(set_context) + mulli r3,r3,897 /* multiply context by skew factor */ + rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ + addis r3,r3,0x6000 /* Set Ks, Ku bits */ + li r0,NUM_USER_SEGMENTS + mtctr r0 + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is passed as second argument. + */ + lis r5, KERNELBASE@h + lwz r5, 0xf0(r5) + stw r4, 0x4(r5) +#endif + li r4,0 + isync +3: +#ifdef CONFIG_PPC64BRIDGE + slbie r4 +#endif /* CONFIG_PPC64BRIDGE */ + mtsrin r3,r4 + addi r3,r3,0x111 /* next VSID */ + rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + sync + isync + blr + +/* + * An undocumented "feature" of 604e requires that the v bit + * be cleared before changing BAT values. + * + * Also, newer IBM firmware does not clear bat3 and 4 so + * this makes sure it's done. + * -- Cort + */ +clear_bats: + li r10,0 + mfspr r9,SPRN_PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpwi r9, 1 + beq 1f + + mtspr SPRN_DBAT0U,r10 + mtspr SPRN_DBAT0L,r10 + mtspr SPRN_DBAT1U,r10 + mtspr SPRN_DBAT1L,r10 + mtspr SPRN_DBAT2U,r10 + mtspr SPRN_DBAT2L,r10 + mtspr SPRN_DBAT3U,r10 + mtspr SPRN_DBAT3L,r10 +1: + mtspr SPRN_IBAT0U,r10 + mtspr SPRN_IBAT0L,r10 + mtspr SPRN_IBAT1U,r10 + mtspr SPRN_IBAT1L,r10 + mtspr SPRN_IBAT2U,r10 + mtspr SPRN_IBAT2L,r10 + mtspr SPRN_IBAT3U,r10 + mtspr SPRN_IBAT3L,r10 +BEGIN_FTR_SECTION + /* Here's a tweak: at this point, CPU setup have + * not been called yet, so HIGH_BAT_EN may not be + * set in HID0 for the 745x processors. However, it + * seems that doesn't affect our ability to actually + * write to these SPRs. + */ + mtspr SPRN_DBAT4U,r10 + mtspr SPRN_DBAT4L,r10 + mtspr SPRN_DBAT5U,r10 + mtspr SPRN_DBAT5L,r10 + mtspr SPRN_DBAT6U,r10 + mtspr SPRN_DBAT6L,r10 + mtspr SPRN_DBAT7U,r10 + mtspr SPRN_DBAT7L,r10 + mtspr SPRN_IBAT4U,r10 + mtspr SPRN_IBAT4L,r10 + mtspr SPRN_IBAT5U,r10 + mtspr SPRN_IBAT5L,r10 + mtspr SPRN_IBAT6U,r10 + mtspr SPRN_IBAT6L,r10 + mtspr SPRN_IBAT7U,r10 + mtspr SPRN_IBAT7L,r10 +END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) + blr + +flush_tlbs: + lis r10, 0x40 +1: addic. r10, r10, -0x1000 + tlbie r10 + blt 1b + sync + blr + +mmu_off: + addi r4, r3, __after_mmu_off - _start + mfmsr r3 + andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ + beqlr + andc r3,r3,r0 + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + sync + RFI + +#ifndef CONFIG_POWER4 +/* + * Use the first pair of BAT registers to map the 1st 16MB + * of RAM to KERNELBASE. From this point on we can't safely + * call OF any more. + */ +initial_bats: + lis r11,KERNELBASE@h +#ifndef CONFIG_PPC64BRIDGE + mfspr r9,SPRN_PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpwi 0,r9,1 + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f /* valid, block length = 8MB */ + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr SPRN_IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr SPRN_IBAT0L,r8 /* lower BAT register */ + mtspr SPRN_IBAT1U,r9 + mtspr SPRN_IBAT1L,r10 + isync + blr +#endif /* CONFIG_PPC64BRIDGE */ + +4: tophys(r8,r11) +#ifdef CONFIG_SMP + ori r8,r8,0x12 /* R/W access, M=1 */ +#else + ori r8,r8,2 /* R/W access */ +#endif /* CONFIG_SMP */ +#ifdef CONFIG_APUS + ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */ +#else + ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ +#endif /* CONFIG_APUS */ + +#ifdef CONFIG_PPC64BRIDGE + /* clear out the high 32 bits in the BAT */ + clrldi r11,r11,32 + clrldi r8,r8,32 +#endif /* CONFIG_PPC64BRIDGE */ + mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ + mtspr SPRN_IBAT0L,r8 + mtspr SPRN_IBAT0U,r11 + isync + blr + +#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) +setup_disp_bat: + /* + * setup the display bat prepared for us in prom.c + */ + mflr r8 + bl reloc_offset + mtlr r8 + addis r8,r3,disp_BAT@ha + addi r8,r8,disp_BAT@l + lwz r11,0(r8) + lwz r8,4(r8) + mfspr r9,SPRN_PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpwi 0,r9,1 + beq 1f + mtspr SPRN_DBAT3L,r8 + mtspr SPRN_DBAT3U,r11 + blr +1: mtspr SPRN_IBAT3L,r8 + mtspr SPRN_IBAT3U,r11 + blr + +#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ + +#else /* CONFIG_POWER4 */ +/* + * Load up the SDR1 and segment register values now + * since we don't have the BATs. + * Also make sure we are running in 32-bit mode. + */ + +initial_mm_power4: + addis r14,r3,_SDR1@ha /* get the value from _SDR1 */ + lwz r14,_SDR1@l(r14) /* assume hash table below 4GB */ + mtspr SPRN_SDR1,r14 + slbia + lis r4,0x2000 /* set pseudo-segment reg 12 */ + ori r5,r4,0x0ccc + mtsr 12,r5 +#if 0 + ori r5,r4,0x0888 /* set pseudo-segment reg 8 */ + mtsr 8,r5 /* (for access to serial port) */ +#endif +#ifdef CONFIG_BOOTX_TEXT + ori r5,r4,0x0999 /* set pseudo-segment reg 9 */ + mtsr 9,r5 /* (for access to screen) */ +#endif + mfmsr r0 + clrldi r0,r0,1 + sync + mtmsr r0 + isync + blr + +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_8260 +/* Jump into the system reset for the rom. + * We first disable the MMU, and then jump to the ROM reset address. + * + * r3 is the board info structure, r4 is the location for starting. + * I use this for building a small kernel that can load other kernels, + * rather than trying to write or rely on a rom monitor that can tftp load. + */ + .globl m8260_gorom +m8260_gorom: + mfmsr r0 + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + sync + mtmsr r0 + sync + mfspr r11, SPRN_HID0 + lis r10, 0 + ori r10,r10,HID0_ICE|HID0_DCE + andc r11, r11, r10 + mtspr SPRN_HID0, r11 + isync + li r5, MSR_ME|MSR_RI + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SPRN_SRR0,r6 + mtspr SPRN_SRR1,r5 + isync + sync + rfi +2: + mtlr r4 + blr +#endif + + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 + + .globl intercept_table +intercept_table: + .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700 + .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0 + .long 0, 0, 0, i0x1300, 0, 0, 0, 0 + .long 0, 0, 0, 0, 0, 0, 0, 0 + .long 0, 0, 0, 0, 0, 0, 0, 0 + .long 0, 0, 0, 0, 0, 0, 0, 0 + +/* Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S new file mode 100644 index 000000000000..599245b0407e --- /dev/null +++ b/arch/powerpc/kernel/head_44x.S @@ -0,0 +1,778 @@ +/* + * arch/ppc/kernel/head_44x.S + * + * Kernel execution entry point code. + * + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * Copyright 2002-2005 MontaVista Software, Inc. + * PowerPC 44x support, Matt Porter + * + * 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 "head_booke.h" + + +/* As with the other PowerPC ports, it is expected that when code + * execution begins here, the following registers contain valid, yet + * optional, information: + * + * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) + * r4 - Starting address of the init RAM disk + * r5 - Ending address of the init RAM disk + * r6 - Start of kernel command line string (e.g. "mem=128") + * r7 - End of kernel command line string + * + */ + .text +_GLOBAL(_stext) +_GLOBAL(_start) + /* + * Reserve a word at a fixed location to store the address + * of abatron_pteptrs + */ + nop +/* + * Save parameters we are passed + */ + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* CPU number */ + +/* + * Set up the initial MMU state + * + * We are still executing code at the virtual address + * mappings set by the firmware for the base of RAM. + * + * We first invalidate all TLB entries but the one + * we are running from. We then load the KERNELBASE + * mappings so we can begin to use kernel addresses + * natively and so the interrupt vector locations are + * permanently pinned (necessary since Book E + * implementations always have translation enabled). + * + * TODO: Use the known TLB entry we are running from to + * determine which physical region we are located + * in. This can be used to determine where in RAM + * (on a shared CPU system) or PCI memory space + * (on a DRAMless system) we are located. + * For now, we assume a perfect world which means + * we are located at the base of DRAM (physical 0). + */ + +/* + * Search TLB for entry that we are currently using. + * Invalidate all entries but the one we are using. + */ + /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ + mfspr r3,SPRN_PID /* Get PID */ + mfmsr r4 /* Get MSR */ + andi. r4,r4,MSR_IS@l /* TS=1? */ + beq wmmucr /* If not, leave STS=0 */ + oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ +wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ + sync + + bl invstr /* Find our address */ +invstr: mflr r5 /* Make it accessible */ + tlbsx r23,0,r5 /* Find entry we are in */ + li r4,0 /* Start at TLB entry 0 */ + li r3,0 /* Set PAGEID inval value */ +1: cmpw r23,r4 /* Is this our entry? */ + beq skpinv /* If so, skip the inval */ + tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ +skpinv: addi r4,r4,1 /* Increment */ + cmpwi r4,64 /* Are we done? */ + bne 1b /* If not, repeat */ + isync /* If so, context change */ + +/* + * Configure and load pinned entry into TLB slot 63. + */ + + lis r3,KERNELBASE@h /* Load the kernel virtual address */ + ori r3,r3,KERNELBASE@l + + /* Kernel is at the base of RAM */ + li r4, 0 /* Load the kernel physical address */ + + /* Load the kernel PID = 0 */ + li r0,0 + mtspr SPRN_PID,r0 + sync + + /* Initialize MMUCR */ + li r5,0 + mtspr SPRN_MMUCR,r5 + sync + + /* pageid fields */ + clrrwi r3,r3,10 /* Mask off the effective page number */ + ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M + + /* xlat fields */ + clrrwi r4,r4,10 /* Mask off the real page number */ + /* ERPN is 0 for first 4GB page */ + + /* attrib fields */ + /* Added guarded bit to protect against speculative loads/stores */ + li r5,0 + ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) + + li r0,63 /* TLB slot 63 */ + + tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ + tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ + tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + + /* Force context change */ + mfmsr r0 + mtspr SPRN_SRR1, r0 + lis r0,3f@h + ori r0,r0,3f@l + mtspr SPRN_SRR0,r0 + sync + rfi + + /* If necessary, invalidate original entry we used */ +3: cmpwi r23,63 + beq 4f + li r6,0 + tlbwe r6,r23,PPC44x_TLB_PAGEID + isync + +4: +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* + * Add temporary UART mapping for early debug. + * We can map UART registers wherever we want as long as they don't + * interfere with other system mappings (e.g. with pinned entries). + * For an example of how we handle this - see ocotea.h. --ebs + */ + /* pageid fields */ + lis r3,UART0_IO_BASE@h + ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K + + /* xlat fields */ + lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */ +#ifndef CONFIG_440EP + ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */ +#endif + + /* attrib fields */ + li r5,0 + ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) + + li r0,0 /* TLB slot 0 */ + + tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ + tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ + tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + + /* Force context change */ + isync +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + + /* Establish the interrupt vector offsets */ + SET_IVOR(0, CriticalInput); + SET_IVOR(1, MachineCheck); + SET_IVOR(2, DataStorage); + SET_IVOR(3, InstructionStorage); + SET_IVOR(4, ExternalInput); + SET_IVOR(5, Alignment); + SET_IVOR(6, Program); + SET_IVOR(7, FloatingPointUnavailable); + SET_IVOR(8, SystemCall); + SET_IVOR(9, AuxillaryProcessorUnavailable); + SET_IVOR(10, Decrementer); + SET_IVOR(11, FixedIntervalTimer); + SET_IVOR(12, WatchdogTimer); + SET_IVOR(13, DataTLBError); + SET_IVOR(14, InstructionTLBError); + SET_IVOR(15, Debug); + + /* Establish the interrupt vector base */ + lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ + mtspr SPRN_IVPR,r4 + +#ifdef CONFIG_440EP + /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */ + mfspr r2,SPRN_CCR0 + lis r3,0xffef + ori r3,r3,0xffff + and r2,r2,r3 + mtspr SPRN_CCR0,r2 + isync +#endif + + /* + * This is where the main kernel code starts. + */ + + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + + /* ptr to current thread */ + addi r4,r2,THREAD /* init task's THREAD */ + mtspr SPRN_SPRG3,r4 + + /* stack */ + lis r1,init_thread_union@h + ori r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) + + bl early_init + +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + + /* Setup PTE pointers for the Abatron bdiGDB */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + lis r4, KERNELBASE@h + ori r4, r4, KERNELBASE@l + stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ + stw r6, 0(r5) + + /* Let's move on */ + lis r4,start_kernel@h + ori r4,r4,start_kernel@l + lis r3,MSR_KERNEL@h + ori r3,r3,MSR_KERNEL@l + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + rfi /* change context and jump to start_kernel */ + +/* + * Interrupt vector entry code + * + * The Book E MMUs are always on so we don't need to handle + * interrupts in real mode as with previous PPC processors. In + * this case we handle interrupts in the kernel virtual address + * space. + * + * Interrupt vectors are dynamically placed relative to the + * interrupt prefix as determined by the address of interrupt_base. + * The interrupt vectors offsets are programmed using the labels + * for each interrupt vector entry. + * + * Interrupt vectors must be aligned on a 16 byte boundary. + * We align on a 32 byte cache line boundary for good measure. + */ + +interrupt_base: + /* Critical Input Interrupt */ + CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + + /* Machine Check Interrupt */ +#ifdef CONFIG_440A + MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#else + CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#endif + + /* Data Storage Interrupt */ + START_EXCEPTION(DataStorage) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + + /* + * Check if it was a store fault, if not then bail + * because a user tried to access a kernel or + * read-protected page. Otherwise, get the + * offending address and handle it. + */ + mfspr r10, SPRN_ESR + andis. r10, r10, ESR_ST@h + beq 2f + + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MMUCR + rlwinm r12,r12,0,0,23 /* Clear TID */ + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + + /* Load PID into MMUCR TID */ + mfspr r12,SPRN_MMUCR /* Get MMUCR */ + mfspr r13,SPRN_PID /* Get PID */ + rlwimi r12,r13,0,24,31 /* Set TID */ + +4: + mtspr SPRN_MMUCR,r12 + + rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ + lwzx r11, r12, r11 /* Get pgd/pmd entry */ + rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ + lwz r11, 4(r12) /* Get pte entry */ + + andi. r13, r11, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail if not */ + + /* Update 'changed'. + */ + ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + stw r11, 4(r12) /* Update Linux page table */ + + li r13, PPC44x_TLB_SR@l /* Set SR */ + rlwimi r13, r11, 29, 29, 29 /* SX = _PAGE_HWEXEC */ + rlwimi r13, r11, 0, 30, 30 /* SW = _PAGE_RW */ + rlwimi r13, r11, 29, 28, 28 /* UR = _PAGE_USER */ + rlwimi r12, r11, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ + rlwimi r12, r11, 29, 30, 30 /* (_PAGE_USER>>3)->r12 */ + and r12, r12, r11 /* HWEXEC/RW & USER */ + rlwimi r13, r12, 0, 26, 26 /* UX = HWEXEC & USER */ + rlwimi r13, r12, 3, 27, 27 /* UW = RW & USER */ + + rlwimi r11,r13,0,26,31 /* Insert static perms */ + + rlwinm r11,r11,0,20,15 /* Clear U0-U3 */ + + /* find the TLB index that caused the fault. It has to be here. */ + tlbsx r10, 0, r10 + + tlbwe r11, r10, PPC44x_TLB_ATTRIB /* Write ATTRIB */ + + /* Done...restore registers and get out of here. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + rfi /* Force context change */ + +2: + /* + * The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b data_access + + /* Instruction Storage Interrupt */ + INSTRUCTION_STORAGE_EXCEPTION + + /* External Input Interrupt */ + EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) + + /* Alignment Interrupt */ + ALIGNMENT_EXCEPTION + + /* Program Interrupt */ + PROGRAM_EXCEPTION + + /* Floating Point Unavailable Interrupt */ +#ifdef CONFIG_PPC_FPU + FP_UNAVAILABLE_EXCEPTION +#else + EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) +#endif + + /* System Call Interrupt */ + START_EXCEPTION(SystemCall) + NORMAL_EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0x0c00, DoSyscall) + + /* Auxillary Processor Unavailable Interrupt */ + EXCEPTION(0x2020, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + + /* Decrementer Interrupt */ + DECREMENTER_EXCEPTION + + /* Fixed Internal Timer Interrupt */ + /* TODO: Add FIT support */ + EXCEPTION(0x1010, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + + /* Watchdog Timer Interrupt */ + /* TODO: Add watchdog support */ +#ifdef CONFIG_BOOKE_WDT + CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) +#else + CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException) +#endif + + /* Data TLB Error Interrupt */ + START_EXCEPTION(DataTLBError) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MMUCR + rlwinm r12,r12,0,0,23 /* Clear TID */ + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + + /* Load PID into MMUCR TID */ + mfspr r12,SPRN_MMUCR + mfspr r13,SPRN_PID /* Get PID */ + rlwimi r12,r13,0,24,31 /* Set TID */ + +4: + mtspr SPRN_MMUCR,r12 + + rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ + lwzx r11, r12, r11 /* Get pgd/pmd entry */ + rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ + lwz r11, 4(r12) /* Get pte entry */ + andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ + beq 2f /* Bail if not present */ + + ori r11, r11, _PAGE_ACCESSED + stw r11, 4(r12) + + /* Jump to common tlb load */ + b finish_tlb_load + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b data_access + + /* Instruction TLB Error Interrupt */ + /* + * Nearly the same as above, except we get our + * information from different registers and bailout + * to a different point. + */ + START_EXCEPTION(InstructionTLBError) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + mfspr r10, SPRN_SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MMUCR + rlwinm r12,r12,0,0,23 /* Clear TID */ + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + + /* Load PID into MMUCR TID */ + mfspr r12,SPRN_MMUCR + mfspr r13,SPRN_PID /* Get PID */ + rlwimi r12,r13,0,24,31 /* Set TID */ + +4: + mtspr SPRN_MMUCR,r12 + + rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ + lwzx r11, r12, r11 /* Get pgd/pmd entry */ + rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ + lwz r11, 4(r12) /* Get pte entry */ + andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ + beq 2f /* Bail if not present */ + + ori r11, r11, _PAGE_ACCESSED + stw r11, 4(r12) + + /* Jump to common TLB load point */ + b finish_tlb_load + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b InstructionStorage + + /* Debug Interrupt */ + DEBUG_EXCEPTION + +/* + * Local functions + */ + /* + * Data TLB exceptions will bail out to this point + * if they can't resolve the lightweight TLB fault. + */ +data_access: + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r11) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + EXC_XFER_EE_LITE(0x0300, handle_page_fault) + +/* + + * Both the instruction and data TLB miss get to this + * point to load the TLB. + * r10 - EA of fault + * r11 - available to use + * r12 - Pointer to the 64-bit PTE + * r13 - available to use + * MMUCR - loaded with proper value when we get here + * Upon exit, we reload everything and RFI. + */ +finish_tlb_load: + /* + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * If shared is set, we cause a zero PID->TID load. + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + + /* Load the next available TLB index */ + lis r13, tlb_44x_index@ha + lwz r13, tlb_44x_index@l(r13) + /* Load the TLB high watermark */ + lis r11, tlb_44x_hwater@ha + lwz r11, tlb_44x_hwater@l(r11) + + /* Increment, rollover, and store TLB index */ + addi r13, r13, 1 + cmpw 0, r13, r11 /* reserve entries */ + ble 7f + li r13, 0 +7: + /* Store the next available TLB index */ + lis r11, tlb_44x_index@ha + stw r13, tlb_44x_index@l(r11) + + lwz r11, 0(r12) /* Get MS word of PTE */ + lwz r12, 4(r12) /* Get LS word of PTE */ + rlwimi r11, r12, 0, 0 , 19 /* Insert RPN */ + tlbwe r11, r13, PPC44x_TLB_XLAT /* Write XLAT */ + + /* + * Create PAGEID. This is the faulting address, + * page size, and valid flag. + */ + li r11, PPC44x_TLB_VALID | PPC44x_TLB_4K + rlwimi r10, r11, 0, 20, 31 /* Insert valid and page size */ + tlbwe r10, r13, PPC44x_TLB_PAGEID /* Write PAGEID */ + + li r10, PPC44x_TLB_SR@l /* Set SR */ + rlwimi r10, r12, 0, 30, 30 /* Set SW = _PAGE_RW */ + rlwimi r10, r12, 29, 29, 29 /* SX = _PAGE_HWEXEC */ + rlwimi r10, r12, 29, 28, 28 /* UR = _PAGE_USER */ + rlwimi r11, r12, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ + and r11, r12, r11 /* HWEXEC & USER */ + rlwimi r10, r11, 0, 26, 26 /* UX = HWEXEC & USER */ + + rlwimi r12, r10, 0, 26, 31 /* Insert static perms */ + rlwinm r12, r12, 0, 20, 15 /* Clear U0-U3 */ + tlbwe r12, r13, PPC44x_TLB_ATTRIB /* Write ATTRIB */ + + /* Done...restore registers and get out of here. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + rfi /* Force context change */ + +/* + * Global functions + */ + +/* + * extern void giveup_altivec(struct task_struct *prev) + * + * The 44x core does not have an AltiVec unit. + */ +_GLOBAL(giveup_altivec) + blr + +/* + * extern void giveup_fpu(struct task_struct *prev) + * + * The 44x core does not have an FPU. + */ +#ifndef CONFIG_PPC_FPU +_GLOBAL(giveup_fpu) + blr +#endif + +/* + * extern void abort(void) + * + * At present, this routine just applies a system reset. + */ +_GLOBAL(abort) + mfspr r13,SPRN_DBCR0 + oris r13,r13,DBCR0_RST_SYSTEM@h + mtspr SPRN_DBCR0,r13 + +_GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is the second parameter. + */ + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r4, 0x4(r5) +#endif + mtspr SPRN_PID,r3 + isync /* Force context change */ + blr + +/* + * We put a few things here that have to be page-aligned. This stuff + * goes at the beginning of the data segment, which is page-aligned. + */ + .data +_GLOBAL(sdata) +_GLOBAL(empty_zero_page) + .space 4096 + +/* + * To support >32-bit physical addresses, we use an 8KB pgdir. + */ +_GLOBAL(swapper_pg_dir) + .space 8192 + +/* Reserved 4k for the critical exception stack & 4k for the machine + * check stack per CPU for kernel mode exceptions */ + .section .bss + .align 12 +exception_stack_bottom: + .space BOOKE_EXCEPTION_STACK_SIZE +_GLOBAL(exception_stack_top) + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* + * Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 + + diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S new file mode 100644 index 000000000000..8562b807b37c --- /dev/null +++ b/arch/powerpc/kernel/head_4xx.S @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * + * + * Module name: head_4xx.S + * + * Description: + * Kernel execution entry point code. + * + * 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 + +/* As with the other PowerPC ports, it is expected that when code + * execution begins here, the following registers contain valid, yet + * optional, information: + * + * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) + * r4 - Starting address of the init RAM disk + * r5 - Ending address of the init RAM disk + * r6 - Start of kernel command line string (e.g. "mem=96m") + * r7 - End of kernel command line string + * + * This is all going to change RSN when we add bi_recs....... -- Dan + */ + .text +_GLOBAL(_stext) +_GLOBAL(_start) + + /* Save parameters we are passed. + */ + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + + /* We have to turn on the MMU right away so we get cache modes + * set correctly. + */ + bl initial_mmu + +/* We now have the lower 16 Meg mapped into TLB entries, and the caches + * ready to work. + */ +turn_on_mmu: + lis r0,MSR_KERNEL@h + ori r0,r0,MSR_KERNEL@l + mtspr SPRN_SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SPRN_SRR0,r0 + SYNC + rfi /* enables MMU */ + b . /* prevent prefetch past rfi */ + +/* + * This area is used for temporarily saving registers during the + * critical exception prolog. + */ + . = 0xc0 +crit_save: +_GLOBAL(crit_r10) + .space 4 +_GLOBAL(crit_r11) + .space 4 + +/* + * Exception vector entry code. This code runs with address translation + * turned off (i.e. using physical addresses). We assume SPRG3 has the + * physical address of the current task thread_struct. + * Note that we have to have decremented r1 before we write to any fields + * of the exception frame, since a critical interrupt could occur at any + * time, and it will write to the area immediately below the current r1. + */ +#define NORMAL_EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ + mtspr SPRN_SPRG1,r11; \ + mtspr SPRN_SPRG2,r1; \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + beq 1f; \ + mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ + lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ + addi r1,r1,THREAD_SIZE; \ +1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ + tophys(r11,r1); \ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRN_SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRN_SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r10,SPRN_SPRG2; \ + mfspr r12,SPRN_SRR0; \ + stw r10,GPR1(r11); \ + mfspr r9,SPRN_SRR1; \ + stw r10,0(r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for critical exceptions. This is a little different + * from the normal exception prolog above since a critical exception + * can potentially occur at any point during normal exception processing. + * Thus we cannot use the same SPRG registers as the normal prolog above. + * Instead we use a couple of words of memory at low physical addresses. + * This is OK since we don't support SMP on these processors. + */ +#define CRITICAL_EXCEPTION_PROLOG \ + stw r10,crit_r10@l(0); /* save two registers to work with */\ + stw r11,crit_r11@l(0); \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_SRR3; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,critical_stack_top@h; \ + ori r11,r11,critical_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + tophys(r11,r11); \ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,SPRN_SRR2; \ + stw r1,GPR1(r11); \ + mfspr r9,SPRN_SRR3; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + + /* + * State at this point: + * r9 saved in stack frame, now saved SRR3 & ~MSR_WE + * r10 saved in crit_r10 and in stack frame, trashed + * r11 saved in crit_r11 and in stack frame, + * now phys stack/exception frame pointer + * r12 saved in stack frame, now saved SRR2 + * CR saved in stack frame, CR0.EQ = !SRR3.PR + * LR, DEAR, ESR in stack frame + * r1 saved in stack frame, now virt stack/excframe pointer + * r0, r3-r8 saved in stack frame + */ + +/* + * Exception vectors. + */ +#define START_EXCEPTION(n, label) \ + . = n; \ +label: + +#define EXCEPTION(n, label, hdlr, xfer) \ + START_EXCEPTION(n, label); \ + NORMAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define CRITICAL_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(n, label); \ + CRITICAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, crit_transfer_to_handler, \ + ret_from_crit_exc) + +#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + lis r10,msr@h; \ + ori r10,r10,msr@l; \ + copyee(r10, r9); \ + bl tfer; \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ + ret_from_except) + + +/* + * 0x0100 - Critical Interrupt Exception + */ + CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, UnknownException) + +/* + * 0x0200 - Machine Check Exception + */ + CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + +/* + * 0x0300 - Data Storage Exception + * This happens for just a few reasons. U0 set (but we don't do that), + * or zone protection fault (user violation, write to protected page). + * If this is just an update of modified status, we do that quickly + * and exit. Otherwise, we call heavywight functions to do the work. + */ + START_EXCEPTION(0x0300, DataStorage) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 +#ifdef CONFIG_403GCX + stw r12, 0(r0) + stw r9, 4(r0) + mfcr r11 + mfspr r12, SPRN_PID + stw r11, 8(r0) + stw r12, 12(r0) +#else + mtspr SPRN_SPRG4, r12 + mtspr SPRN_SPRG5, r9 + mfcr r11 + mfspr r12, SPRN_PID + mtspr SPRN_SPRG7, r11 + mtspr SPRN_SPRG6, r12 +#endif + + /* First, check if it was a zone fault (which means a user + * tried to access a kernel or read-protected page - always + * a SEGV). All other faults here must be stores, so no + * need to check ESR_DST as well. */ + mfspr r10, SPRN_ESR + andis. r10, r10, ESR_DIZ@h + bne 2f + + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + li r9, 0 + mtspr SPRN_PID, r9 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) +4: + tophys(r11, r11) + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r11, 0(r11) /* Get L1 entry */ + rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + + andi. r9, r11, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail if not */ + + /* Update 'changed'. + */ + ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + stw r11, 0(r12) /* Update Linux page table */ + + /* Most of the Linux PTE is ready to load into the TLB LO. + * We set ZSEL, where only the LS-bit determines user access. + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * If shared is set, we cause a zero PID->TID load. + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + li r12, 0x0ce2 + andc r11, r11, r12 /* Make sure 20, 21 are zero */ + + /* find the TLB index that caused the fault. It has to be here. + */ + tlbsx r9, 0, r10 + + tlbwe r11, r9, TLB_DATA /* Load TLB LO */ + + /* Done...restore registers and get out of here. + */ +#ifdef CONFIG_403GCX + lwz r12, 12(r0) + lwz r11, 8(r0) + mtspr SPRN_PID, r12 + mtcr r11 + lwz r9, 4(r0) + lwz r12, 0(r0) +#else + mfspr r12, SPRN_SPRG6 + mfspr r11, SPRN_SPRG7 + mtspr SPRN_PID, r12 + mtcr r11 + mfspr r9, SPRN_SPRG5 + mfspr r12, SPRN_SPRG4 +#endif + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + PPC405_ERR77_SYNC + rfi /* Should sync shadow TLBs */ + b . /* prevent prefetch past rfi */ + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r12, 12(r0) + lwz r11, 8(r0) + mtspr SPRN_PID, r12 + mtcr r11 + lwz r9, 4(r0) + lwz r12, 0(r0) +#else + mfspr r12, SPRN_SPRG6 + mfspr r11, SPRN_SPRG7 + mtspr SPRN_PID, r12 + mtcr r11 + mfspr r9, SPRN_SPRG5 + mfspr r12, SPRN_SPRG4 +#endif + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b DataAccess + +/* + * 0x0400 - Instruction Storage Exception + * This is caused by a fetch from non-execute or guarded pages. + */ + START_EXCEPTION(0x0400, InstructionAccess) + NORMAL_EXCEPTION_PROLOG + mr r4,r12 /* Pass SRR0 as arg2 */ + li r5,0 /* Pass zero as arg3 */ + EXC_XFER_EE_LITE(0x400, handle_page_fault) + +/* 0x0500 - External Interrupt Exception */ + EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) + +/* 0x0600 - Alignment Exception */ + START_EXCEPTION(0x0600, Alignment) + NORMAL_EXCEPTION_PROLOG + mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ + stw r4,_DEAR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0x600, AlignmentException) + +/* 0x0700 - Program Exception */ + START_EXCEPTION(0x0700, ProgramCheck) + NORMAL_EXCEPTION_PROLOG + mfspr r4,SPRN_ESR /* Grab the ESR and save it */ + stw r4,_ESR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_STD(0x700, ProgramCheckException) + + EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0A00, Trap_0A, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0B00, Trap_0B, UnknownException, EXC_XFER_EE) + +/* 0x0C00 - System Call Exception */ + START_EXCEPTION(0x0C00, SystemCall) + NORMAL_EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0xc00, DoSyscall) + + EXCEPTION(0x0D00, Trap_0D, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0E00, Trap_0E, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0F00, Trap_0F, UnknownException, EXC_XFER_EE) + +/* 0x1000 - Programmable Interval Timer (PIT) Exception */ + START_EXCEPTION(0x1000, Decrementer) + NORMAL_EXCEPTION_PROLOG + lis r0,TSR_PIS@h + mtspr SPRN_TSR,r0 /* Clear the PIT exception */ + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_LITE(0x1000, timer_interrupt) + +#if 0 +/* NOTE: + * FIT and WDT handlers are not implemented yet. + */ + +/* 0x1010 - Fixed Interval Timer (FIT) Exception +*/ + STND_EXCEPTION(0x1010, FITException, UnknownException) + +/* 0x1020 - Watchdog Timer (WDT) Exception +*/ +#ifdef CONFIG_BOOKE_WDT + CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException) +#else + CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException) +#endif +#endif + +/* 0x1100 - Data TLB Miss Exception + * As the name implies, translation is not in the MMU, so search the + * page tables and fix it. The only purpose of this function is to + * load TLB entries from the page table if they exist. + */ + START_EXCEPTION(0x1100, DTLBMiss) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 +#ifdef CONFIG_403GCX + stw r12, 0(r0) + stw r9, 4(r0) + mfcr r11 + mfspr r12, SPRN_PID + stw r11, 8(r0) + stw r12, 12(r0) +#else + mtspr SPRN_SPRG4, r12 + mtspr SPRN_SPRG5, r9 + mfcr r11 + mfspr r12, SPRN_PID + mtspr SPRN_SPRG7, r11 + mtspr SPRN_SPRG6, r12 +#endif + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + li r9, 0 + mtspr SPRN_PID, r9 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) +4: + tophys(r11, r11) + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r12, 0(r11) /* Get L1 entry */ + andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + andi. r9, r11, _PAGE_PRESENT + beq 5f + + ori r11, r11, _PAGE_ACCESSED + stw r11, 0(r12) + + /* Create TLB tag. This is the faulting address plus a static + * set of bits. These are size, valid, E, U0. + */ + li r12, 0x00c0 + rlwimi r10, r12, 0, 20, 31 + + b finish_tlb_load + +2: /* Check for possible large-page pmd entry */ + rlwinm. r9, r12, 2, 22, 24 + beq 5f + + /* Create TLB tag. This is the faulting address, plus a static + * set of bits (valid, E, U0) plus the size from the PMD. + */ + ori r9, r9, 0x40 + rlwimi r10, r9, 0, 20, 31 + mr r11, r12 + + b finish_tlb_load + +5: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r12, 12(r0) + lwz r11, 8(r0) + mtspr SPRN_PID, r12 + mtcr r11 + lwz r9, 4(r0) + lwz r12, 0(r0) +#else + mfspr r12, SPRN_SPRG6 + mfspr r11, SPRN_SPRG7 + mtspr SPRN_PID, r12 + mtcr r11 + mfspr r9, SPRN_SPRG5 + mfspr r12, SPRN_SPRG4 +#endif + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b DataAccess + +/* 0x1200 - Instruction TLB Miss Exception + * Nearly the same as above, except we get our information from different + * registers and bailout to a different point. + */ + START_EXCEPTION(0x1200, ITLBMiss) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 +#ifdef CONFIG_403GCX + stw r12, 0(r0) + stw r9, 4(r0) + mfcr r11 + mfspr r12, SPRN_PID + stw r11, 8(r0) + stw r12, 12(r0) +#else + mtspr SPRN_SPRG4, r12 + mtspr SPRN_SPRG5, r9 + mfcr r11 + mfspr r12, SPRN_PID + mtspr SPRN_SPRG7, r11 + mtspr SPRN_SPRG6, r12 +#endif + mfspr r10, SPRN_SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + li r9, 0 + mtspr SPRN_PID, r9 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) +4: + tophys(r11, r11) + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r12, 0(r11) /* Get L1 entry */ + andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + andi. r9, r11, _PAGE_PRESENT + beq 5f + + ori r11, r11, _PAGE_ACCESSED + stw r11, 0(r12) + + /* Create TLB tag. This is the faulting address plus a static + * set of bits. These are size, valid, E, U0. + */ + li r12, 0x00c0 + rlwimi r10, r12, 0, 20, 31 + + b finish_tlb_load + +2: /* Check for possible large-page pmd entry */ + rlwinm. r9, r12, 2, 22, 24 + beq 5f + + /* Create TLB tag. This is the faulting address, plus a static + * set of bits (valid, E, U0) plus the size from the PMD. + */ + ori r9, r9, 0x40 + rlwimi r10, r9, 0, 20, 31 + mr r11, r12 + + b finish_tlb_load + +5: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r12, 12(r0) + lwz r11, 8(r0) + mtspr SPRN_PID, r12 + mtcr r11 + lwz r9, 4(r0) + lwz r12, 0(r0) +#else + mfspr r12, SPRN_SPRG6 + mfspr r11, SPRN_SPRG7 + mtspr SPRN_PID, r12 + mtcr r11 + mfspr r9, SPRN_SPRG5 + mfspr r12, SPRN_SPRG4 +#endif + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b InstructionAccess + + EXCEPTION(0x1300, Trap_13, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1400, Trap_14, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) +#ifdef CONFIG_IBM405_ERR51 + /* 405GP errata 51 */ + START_EXCEPTION(0x1700, Trap_17) + b DTLBMiss +#else + EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) +#endif + EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1A00, Trap_1A, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1B00, Trap_1B, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1C00, Trap_1C, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1D00, Trap_1D, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE) + +/* Check for a single step debug exception while in an exception + * handler before state has been saved. This is to catch the case + * where an instruction that we are trying to single step causes + * an exception (eg ITLB/DTLB miss) and thus the first instruction of + * the exception handler generates a single step debug exception. + * + * If we get a debug trap on the first instruction of an exception handler, + * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is + * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). + * The exception handler was handling a non-critical interrupt, so it will + * save (and later restore) the MSR via SPRN_SRR1, which will still have + * the MSR_DE bit set. + */ + /* 0x2000 - Debug Exception */ + START_EXCEPTION(0x2000, DebugTrap) + CRITICAL_EXCEPTION_PROLOG + + /* + * If this is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the SRR3 value and clearing the debug status. + */ + mfspr r10,SPRN_DBSR /* check single-step/branch taken */ + andis. r10,r10,DBSR_IC@h + beq+ 2f + + andi. r10,r9,MSR_IR|MSR_PR /* check supervisor + MMU off */ + beq 1f /* branch and fix it up */ + + mfspr r10,SPRN_SRR2 /* Faulting instruction address */ + cmplwi r10,0x2100 + bgt+ 2f /* address above exception vectors */ + + /* here it looks like we got an inappropriate debug exception. */ +1: rlwinm r9,r9,0,~MSR_DE /* clear DE in the SRR3 value */ + lis r10,DBSR_IC@h /* clear the IC event */ + mtspr SPRN_DBSR,r10 + /* restore state and get out */ + lwz r10,_CCR(r11) + lwz r0,GPR0(r11) + lwz r1,GPR1(r11) + mtcrf 0x80,r10 + mtspr SPRN_SRR2,r12 + mtspr SPRN_SRR3,r9 + lwz r9,GPR9(r11) + lwz r12,GPR12(r11) + lwz r10,crit_r10@l(0) + lwz r11,crit_r11@l(0) + PPC405_ERR77_SYNC + rfci + b . + + /* continue normal handling for a critical exception... */ +2: mfspr r4,SPRN_DBSR + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(DebugException, 0x2002, \ + (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) + +/* + * The other Data TLB exceptions bail out to this point + * if they can't resolve the lightweight TLB fault. + */ +DataAccess: + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r11) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + EXC_XFER_EE_LITE(0x300, handle_page_fault) + +/* Other PowerPC processors, namely those derived from the 6xx-series + * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. + * However, for the 4xx-series processors these are neither defined nor + * reserved. + */ + + /* Damn, I came up one instruction too many to fit into the + * exception space :-). Both the instruction and data TLB + * miss get to this point to load the TLB. + * r10 - TLB_TAG value + * r11 - Linux PTE + * r12, r9 - avilable to use + * PID - loaded with proper value when we get here + * Upon exit, we reload everything and RFI. + * Actually, it will fit now, but oh well.....a common place + * to load the TLB. + */ +tlb_4xx_index: + .long 0 +finish_tlb_load: + /* load the next available TLB index. + */ + lwz r9, tlb_4xx_index@l(0) + addi r9, r9, 1 + andi. r9, r9, (PPC4XX_TLB_SIZE-1) + stw r9, tlb_4xx_index@l(0) + +6: + /* + * Clear out the software-only bits in the PTE to generate the + * TLB_DATA value. These are the bottom 2 bits of the RPM, the + * top 3 bits of the zone field, and M. + */ + li r12, 0x0ce2 + andc r11, r11, r12 + + tlbwe r11, r9, TLB_DATA /* Load TLB LO */ + tlbwe r10, r9, TLB_TAG /* Load TLB HI */ + + /* Done...restore registers and get out of here. + */ +#ifdef CONFIG_403GCX + lwz r12, 12(r0) + lwz r11, 8(r0) + mtspr SPRN_PID, r12 + mtcr r11 + lwz r9, 4(r0) + lwz r12, 0(r0) +#else + mfspr r12, SPRN_SPRG6 + mfspr r11, SPRN_SPRG7 + mtspr SPRN_PID, r12 + mtcr r11 + mfspr r9, SPRN_SPRG5 + mfspr r12, SPRN_SPRG4 +#endif + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + PPC405_ERR77_SYNC + rfi /* Should sync shadow TLBs */ + b . /* prevent prefetch past rfi */ + +/* extern void giveup_fpu(struct task_struct *prev) + * + * The PowerPC 4xx family of processors do not have an FPU, so this just + * returns. + */ +_GLOBAL(giveup_fpu) + blr + +/* This is where the main kernel code starts. + */ +start_here: + + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + mtspr SPRN_SPRG3,r4 + + /* stack */ + lis r1,init_thread_union@ha + addi r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) + + bl early_init /* We have to do this with MMU on */ + +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + +/* Go back to running unmapped so we can load up new values + * and change to using our exception vectors. + * On the 4xx, all we have to do is invalidate the TLB to clear + * the old 16M byte TLB mappings. + */ + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + lis r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@h + ori r3,r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@l + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + rfi + b . /* prevent prefetch past rfi */ + +/* Load up the kernel context */ +2: + sync /* Flush to memory before changing TLB */ + tlbia + isync /* Flush shadow TLBs */ + + /* set up the PTE pointers for the Abatron bdiGDB. + */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r5, 0xf0(r0) /* Must match your Abatron config file */ + tophys(r5,r5) + stw r6, 0(r5) + +/* Now turn on the MMU for real! */ + lis r4,MSR_KERNEL@h + ori r4,r4,MSR_KERNEL@l + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ + b . /* prevent prefetch past rfi */ + +/* Set up the initial MMU state so we can do the first level of + * kernel initialization. This maps the first 16 MBytes of memory 1:1 + * virtual to physical and more importantly sets the cache mode. + */ +initial_mmu: + tlbia /* Invalidate all TLB entries */ + isync + + /* We should still be executing code at physical address 0x0000xxxx + * at this point. However, start_here is at virtual address + * 0xC000xxxx. So, set up a TLB mapping to cover this once + * translation is enabled. + */ + + lis r3,KERNELBASE@h /* Load the kernel virtual address */ + ori r3,r3,KERNELBASE@l + tophys(r4,r3) /* Load the kernel physical address */ + + iccci r0,r3 /* Invalidate the i-cache before use */ + + /* Load the kernel PID. + */ + li r0,0 + mtspr SPRN_PID,r0 + sync + + /* Configure and load two entries into TLB slots 62 and 63. + * In case we are pinning TLBs, these are reserved in by the + * other TLB functions. If not reserving, then it doesn't + * matter where they are loaded. + */ + clrrwi r4,r4,10 /* Mask off the real page number */ + ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ + + clrrwi r3,r3,10 /* Mask off the effective page number */ + ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) + + li r0,63 /* TLB slot 63 */ + + tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ + tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(SERIAL_DEBUG_IO_BASE) + + /* Load a TLB entry for the UART, so that ppc4xx_progress() can use + * the UARTs nice and early. We use a 4k real==virtual mapping. */ + + lis r3,SERIAL_DEBUG_IO_BASE@h + ori r3,r3,SERIAL_DEBUG_IO_BASE@l + mr r4,r3 + clrrwi r4,r4,12 + ori r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G) + + clrrwi r3,r3,12 + ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K)) + + li r0,0 /* TLB slot 0 */ + tlbwe r4,r0,TLB_DATA + tlbwe r3,r0,TLB_TAG +#endif /* CONFIG_SERIAL_DEBUG_TEXT && SERIAL_DEBUG_IO_BASE */ + + isync + + /* Establish the exception vector base + */ + lis r4,KERNELBASE@h /* EVPR only uses the high 16-bits */ + tophys(r0,r4) /* Use the physical address */ + mtspr SPRN_EVPR,r0 + + blr + +_GLOBAL(abort) + mfspr r13,SPRN_DBCR0 + oris r13,r13,DBCR0_RST_SYSTEM@h + mtspr SPRN_DBCR0,r13 + +_GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is the second parameter. + */ + lis r5, KERNELBASE@h + lwz r5, 0xf0(r5) + stw r4, 0x4(r5) +#endif + sync + mtspr SPRN_PID,r3 + isync /* Need an isync to flush shadow */ + /* TLBs after changing PID */ + blr + +/* We put a few things here that have to be page-aligned. This stuff + * goes at the beginning of the data segment, which is page-aligned. + */ + .data +_GLOBAL(sdata) +_GLOBAL(empty_zero_page) + .space 4096 +_GLOBAL(swapper_pg_dir) + .space 4096 + + +/* Stack for handling critical exceptions from kernel mode */ + .section .bss + .align 12 +exception_stack_bottom: + .space 4096 +critical_stack_top: +_GLOBAL(exception_stack_top) + +/* This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S new file mode 100644 index 000000000000..22a5ee07e1ea --- /dev/null +++ b/arch/powerpc/kernel/head_64.S @@ -0,0 +1,2011 @@ +/* + * arch/ppc64/kernel/head.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * 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 + +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + +/* + * We layout physical memory as follows: + * 0x0000 - 0x00ff : Secondary processor spin code + * 0x0100 - 0x2fff : pSeries Interrupt prologs + * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs + * 0x6000 - 0x6fff : Initial (CPU0) segment table + * 0x7000 - 0x7fff : FWNMI data area + * 0x8000 - : Early init and support code + */ + +/* + * SPRG Usage + * + * Register Definition + * + * SPRG0 reserved for hypervisor + * SPRG1 temp - used to save gpr + * SPRG2 temp - used to save gpr + * SPRG3 virt addr of paca + */ + +/* + * Entering into this code we make the following assumptions: + * For pSeries: + * 1. The MMU is off & open firmware is running in real mode. + * 2. The kernel is entered at __start + * + * For iSeries: + * 1. The MMU is on (as it always is for iSeries) + * 2. The kernel is entered at system_reset_iSeries + */ + + .text + .globl _stext +_stext: +#ifdef CONFIG_PPC_MULTIPLATFORM +_GLOBAL(__start) + /* NOP this out unconditionally */ +BEGIN_FTR_SECTION + b .__start_initialization_multiplatform +END_FTR_SECTION(0, 1) +#endif /* CONFIG_PPC_MULTIPLATFORM */ + + /* Catch branch to 0 in real mode */ + trap + +#ifdef CONFIG_PPC_ISERIES + /* + * At offset 0x20, there is a pointer to iSeries LPAR data. + * This is required by the hypervisor + */ + . = 0x20 + .llong hvReleaseData-KERNELBASE + + /* + * At offset 0x28 and 0x30 are offsets to the mschunks_map + * array (used by the iSeries LPAR debugger to do translation + * between physical addresses and absolute addresses) and + * to the pidhash table (also used by the debugger) + */ + .llong mschunks_map-KERNELBASE + .llong 0 /* pidhash-KERNELBASE SFRXXX */ + + /* Offset 0x38 - Pointer to start of embedded System.map */ + .globl embedded_sysmap_start +embedded_sysmap_start: + .llong 0 + /* Offset 0x40 - Pointer to end of embedded System.map */ + .globl embedded_sysmap_end +embedded_sysmap_end: + .llong 0 + +#endif /* CONFIG_PPC_ISERIES */ + + /* Secondary processors spin on this value until it goes to 1. */ + .globl __secondary_hold_spinloop +__secondary_hold_spinloop: + .llong 0x0 + + /* Secondary processors write this value with their cpu # */ + /* after they enter the spin loop immediately below. */ + .globl __secondary_hold_acknowledge +__secondary_hold_acknowledge: + .llong 0x0 + + . = 0x60 +/* + * The following code is used on pSeries to hold secondary processors + * in a spin loop after they have been freed from OpenFirmware, but + * before the bulk of the kernel has been relocated. This code + * is relocated to physical address 0x60 before prom_init is run. + * All of it must fit below the first exception vector at 0x100. + */ +_GLOBAL(__secondary_hold) + mfmsr r24 + ori r24,r24,MSR_RI + mtmsrd r24 /* RI on */ + + /* Grab our linux cpu number */ + mr r24,r3 + + /* Tell the master cpu we're here */ + /* Relocation is off & we are located at an address less */ + /* than 0x100, so only need to grab low order offset. */ + std r24,__secondary_hold_acknowledge@l(0) + sync + + /* All secondary cpus wait here until told to start. */ +100: ld r4,__secondary_hold_spinloop@l(0) + cmpdi 0,r4,1 + bne 100b + +#ifdef CONFIG_HMT + b .hmt_init +#else +#ifdef CONFIG_SMP + mr r3,r24 + b .pSeries_secondary_smp_init +#else + BUG_OPCODE +#endif +#endif + +/* This value is used to mark exception frames on the stack. */ + .section ".toc","aw" +exception_marker: + .tc ID_72656773_68657265[TC],0x7265677368657265 + .text + +/* + * The following macros define the code that appears as + * the prologue to each of the exception handlers. They + * are split into two parts to allow a single kernel binary + * to be used for pSeries and iSeries. + * LOL. One day... - paulus + */ + +/* + * We make as much of the exception code common between native + * exception handlers (including pSeries LPAR) and iSeries LPAR + * implementations as possible. + */ + +/* + * This is the start of the interrupt handlers for pSeries + * This code runs with relocation off. + */ +#define EX_R9 0 +#define EX_R10 8 +#define EX_R11 16 +#define EX_R12 24 +#define EX_R13 32 +#define EX_SRR0 40 +#define EX_R3 40 /* SLB miss saves R3, but not SRR0 */ +#define EX_DAR 48 +#define EX_LR 48 /* SLB miss saves LR, but not DAR */ +#define EX_DSISR 56 +#define EX_CCR 60 + +#define EXCEPTION_PROLOG_PSERIES(area, label) \ + mfspr r13,SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9; \ + clrrdi r12,r13,32; /* get high part of &label */ \ + mfmsr r10; \ + mfspr r11,SRR0; /* save SRR0 */ \ + ori r12,r12,(label)@l; /* virt addr of handler */ \ + ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ + mtspr SRR0,r12; \ + mfspr r12,SRR1; /* and SRR1 */ \ + mtspr SRR1,r10; \ + rfid; \ + b . /* prevent speculative execution */ + +/* + * This is the start of the interrupt handlers for iSeries + * This code runs with relocation on. + */ +#define EXCEPTION_PROLOG_ISERIES_1(area) \ + mfspr r13,SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9 + +#define EXCEPTION_PROLOG_ISERIES_2 \ + mfmsr r10; \ + ld r11,PACALPPACA+LPPACASRR0(r13); \ + ld r12,PACALPPACA+LPPACASRR1(r13); \ + ori r10,r10,MSR_RI; \ + mtmsrd r10,1 + +/* + * The common exception prolog is used for all except a few exceptions + * such as a segment miss on a kernel address. We have to be prepared + * to take another exception from the point where we first touch the + * kernel stack onwards. + * + * On entry r13 points to the paca, r9-r13 are saved in the paca, + * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and + * SRR1, and relocation is on. + */ +#define EXCEPTION_PROLOG_COMMON(n, area) \ + andi. r10,r12,MSR_PR; /* See if coming from user */ \ + mr r10,r1; /* Save r1 */ \ + subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ + beq- 1f; \ + ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ +1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ + bge- cr1,bad_stack; /* abort if it is */ \ + std r9,_CCR(r1); /* save CR in stackframe */ \ + std r11,_NIP(r1); /* save SRR0 in stackframe */ \ + std r12,_MSR(r1); /* save SRR1 in stackframe */ \ + std r10,0(r1); /* make stack chain pointer */ \ + std r0,GPR0(r1); /* save r0 in stackframe */ \ + std r10,GPR1(r1); /* save r1 in stackframe */ \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ + SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ + SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ + ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ + ld r10,area+EX_R10(r13); \ + std r9,GPR9(r1); \ + std r10,GPR10(r1); \ + ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \ + ld r10,area+EX_R12(r13); \ + ld r11,area+EX_R13(r13); \ + std r9,GPR11(r1); \ + std r10,GPR12(r1); \ + std r11,GPR13(r1); \ + ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ + mflr r9; /* save LR in stackframe */ \ + std r9,_LINK(r1); \ + mfctr r10; /* save CTR in stackframe */ \ + std r10,_CTR(r1); \ + mfspr r11,XER; /* save XER in stackframe */ \ + std r11,_XER(r1); \ + li r9,(n)+1; \ + std r9,_TRAP(r1); /* set trap number */ \ + li r10,0; \ + ld r11,exception_marker@toc(r2); \ + std r10,RESULT(r1); /* clear regs->result */ \ + std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION_PSERIES(n, label) \ + . = n; \ + .globl label##_pSeries; \ +label##_pSeries: \ + HMT_MEDIUM; \ + mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + +#define STD_EXCEPTION_ISERIES(n, label, area) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ + EXCEPTION_PROLOG_ISERIES_1(area); \ + EXCEPTION_PROLOG_ISERIES_2; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES(n, label) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ + EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ + lbz r10,PACAPROCENABLED(r13); \ + cmpwi 0,r10,0; \ + beq- label##_iSeries_masked; \ + EXCEPTION_PROLOG_ISERIES_2; \ + b label##_common; \ + +#ifdef DO_SOFT_DISABLE +#define DISABLE_INTS \ + lbz r10,PACAPROCENABLED(r13); \ + li r11,0; \ + std r10,SOFTE(r1); \ + mfmsr r10; \ + stb r11,PACAPROCENABLED(r13); \ + ori r10,r10,MSR_EE; \ + mtmsrd r10,1 + +#define ENABLE_INTS \ + lbz r10,PACAPROCENABLED(r13); \ + mfmsr r11; \ + std r10,SOFTE(r1); \ + ori r11,r11,MSR_EE; \ + mtmsrd r11,1 + +#else /* hard enable/disable interrupts */ +#define DISABLE_INTS + +#define ENABLE_INTS \ + ld r12,_MSR(r1); \ + mfmsr r11; \ + rlwimi r11,r12,0,MSR_EE; \ + mtmsrd r11,1 + +#endif + +#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except + +#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + DISABLE_INTS; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except_lite + +/* + * Start of pSeries system interrupt routines + */ + . = 0x100 + .globl __start_interrupts +__start_interrupts: + + STD_EXCEPTION_PSERIES(0x100, system_reset) + + . = 0x200 +_machine_check_pSeries: + HMT_MEDIUM + mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + + . = 0x300 + .globl data_access_pSeries +data_access_pSeries: + HMT_MEDIUM + mtspr SPRG1,r13 +BEGIN_FTR_SECTION + mtspr SPRG2,r12 + mfspr r13,DAR + mfspr r12,DSISR + srdi r13,r13,60 + rlwimi r13,r12,16,0x20 + mfcr r12 + cmpwi r13,0x2c + beq .do_stab_bolted_pSeries + mtcrf 0x80,r12 + mfspr r12,SPRG2 +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) + + . = 0x380 + .globl data_access_slb_pSeries +data_access_slb_pSeries: + HMT_MEDIUM + mtspr SPRG1,r13 + RUNLATCH_ON(r13) + mfspr r13,SPRG3 /* get paca address into r13 */ + std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r9,SPRG1 + std r9,PACA_EXSLB+EX_R13(r13) + mfcr r9 + mfspr r12,SRR1 /* and SRR1 */ + mfspr r3,DAR + b .do_slb_miss /* Rel. branch works in real mode */ + + STD_EXCEPTION_PSERIES(0x400, instruction_access) + + . = 0x480 + .globl instruction_access_slb_pSeries +instruction_access_slb_pSeries: + HMT_MEDIUM + mtspr SPRG1,r13 + RUNLATCH_ON(r13) + mfspr r13,SPRG3 /* get paca address into r13 */ + std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r9,SPRG1 + std r9,PACA_EXSLB+EX_R13(r13) + mfcr r9 + mfspr r12,SRR1 /* and SRR1 */ + mfspr r3,SRR0 /* SRR0 is faulting address */ + b .do_slb_miss /* Rel. branch works in real mode */ + + STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) + STD_EXCEPTION_PSERIES(0x600, alignment) + STD_EXCEPTION_PSERIES(0x700, program_check) + STD_EXCEPTION_PSERIES(0x800, fp_unavailable) + STD_EXCEPTION_PSERIES(0x900, decrementer) + STD_EXCEPTION_PSERIES(0xa00, trap_0a) + STD_EXCEPTION_PSERIES(0xb00, trap_0b) + + . = 0xc00 + .globl system_call_pSeries +system_call_pSeries: + HMT_MEDIUM + RUNLATCH_ON(r9) + mr r9,r13 + mfmsr r10 + mfspr r13,SPRG3 + mfspr r11,SRR0 + clrrdi r12,r13,32 + oris r12,r12,system_call_common@h + ori r12,r12,system_call_common@l + mtspr SRR0,r12 + ori r10,r10,MSR_IR|MSR_DR|MSR_RI + mfspr r12,SRR1 + mtspr SRR1,r10 + rfid + b . /* prevent speculative execution */ + + STD_EXCEPTION_PSERIES(0xd00, single_step) + STD_EXCEPTION_PSERIES(0xe00, trap_0e) + + /* We need to deal with the Altivec unavailable exception + * here which is at 0xf20, thus in the middle of the + * prolog code of the PerformanceMonitor one. A little + * trickery is thus necessary + */ + . = 0xf00 + b performance_monitor_pSeries + + STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable) + + STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) + STD_EXCEPTION_PSERIES(0x1700, altivec_assist) + + . = 0x3000 + +/*** pSeries interrupt support ***/ + + /* moved from 0xf00 */ + STD_EXCEPTION_PSERIES(., performance_monitor) + + .align 7 +_GLOBAL(do_stab_bolted_pSeries) + mtcrf 0x80,r12 + mfspr r12,SPRG2 + EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) + +/* + * Vectors for the FWNMI option. Share common code. + */ + .globl system_reset_fwnmi +system_reset_fwnmi: + HMT_MEDIUM + mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) + + .globl machine_check_fwnmi +machine_check_fwnmi: + HMT_MEDIUM + mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + +#ifdef CONFIG_PPC_ISERIES +/*** ISeries-LPAR interrupt handlers ***/ + + STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) + + .globl data_access_iSeries +data_access_iSeries: + mtspr SPRG1,r13 +BEGIN_FTR_SECTION + mtspr SPRG2,r12 + mfspr r13,DAR + mfspr r12,DSISR + srdi r13,r13,60 + rlwimi r13,r12,16,0x20 + mfcr r12 + cmpwi r13,0x2c + beq .do_stab_bolted_iSeries + mtcrf 0x80,r12 + mfspr r12,SPRG2 +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) + EXCEPTION_PROLOG_ISERIES_2 + b data_access_common + +.do_stab_bolted_iSeries: + mtcrf 0x80,r12 + mfspr r12,SPRG2 + EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) + EXCEPTION_PROLOG_ISERIES_2 + b .do_stab_bolted + + .globl data_access_slb_iSeries +data_access_slb_iSeries: + mtspr SPRG1,r13 /* save r13 */ + EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) + std r3,PACA_EXSLB+EX_R3(r13) + ld r12,PACALPPACA+LPPACASRR1(r13) + mfspr r3,DAR + b .do_slb_miss + + STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) + + .globl instruction_access_slb_iSeries +instruction_access_slb_iSeries: + mtspr SPRG1,r13 /* save r13 */ + EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) + std r3,PACA_EXSLB+EX_R3(r13) + ld r12,PACALPPACA+LPPACASRR1(r13) + ld r3,PACALPPACA+LPPACASRR0(r13) + b .do_slb_miss + + MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt) + STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(0x900, decrementer) + STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN) + + .globl system_call_iSeries +system_call_iSeries: + mr r9,r13 + mfspr r13,SPRG3 + EXCEPTION_PROLOG_ISERIES_2 + b system_call_common + + STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) + STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) + STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) + + .globl system_reset_iSeries +system_reset_iSeries: + mfspr r13,SPRG3 /* Get paca address */ + mfmsr r24 + ori r24,r24,MSR_RI + mtmsrd r24 /* RI on */ + lhz r24,PACAPACAINDEX(r13) /* Get processor # */ + cmpwi 0,r24,0 /* Are we processor 0? */ + beq .__start_initialization_iSeries /* Start up the first processor */ + mfspr r4,SPRN_CTRLF + li r5,CTRL_RUNLATCH /* Turn off the run light */ + andc r4,r4,r5 + mtspr SPRN_CTRLT,r4 + +1: + HMT_LOW +#ifdef CONFIG_SMP + lbz r23,PACAPROCSTART(r13) /* Test if this processor + * should start */ + sync + LOADADDR(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 + beq iSeries_secondary_smp_loop /* Loop until told to go */ + bne .__secondary_start /* Loop until told to go */ +iSeries_secondary_smp_loop: + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ +#else /* CONFIG_SMP */ + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ +#endif /* CONFIG_SMP */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRG3 /* Put r13 back ???? */ + b 1b /* If SMP not configured, secondaries + * loop forever */ + + .globl decrementer_iSeries_masked +decrementer_iSeries_masked: + li r11,1 + stb r11,PACALPPACA+LPPACADECRINT(r13) + lwz r12,PACADEFAULTDECR(r13) + mtspr SPRN_DEC,r12 + /* fall through */ + + .globl hardware_interrupt_iSeries_masked +hardware_interrupt_iSeries_masked: + mtcrf 0x80,r9 /* Restore regs */ + ld r11,PACALPPACA+LPPACASRR0(r13) + ld r12,PACALPPACA+LPPACASRR1(r13) + mtspr SRR0,r11 + mtspr SRR1,r12 + ld r9,PACA_EXGEN+EX_R9(r13) + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + ld r12,PACA_EXGEN+EX_R12(r13) + ld r13,PACA_EXGEN+EX_R13(r13) + rfid + b . /* prevent speculative execution */ +#endif /* CONFIG_PPC_ISERIES */ + +/*** Common interrupt handlers ***/ + + STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) + + /* + * Machine check is different because we use a different + * save area: PACA_EXMC instead of PACA_EXGEN. + */ + .align 7 + .globl machine_check_common +machine_check_common: + EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) + DISABLE_INTS + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_exception + b .ret_from_except + + STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) + STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) + STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) + STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) + STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) + STD_EXCEPTION_COMMON(0xf00, performance_monitor, .performance_monitor_exception) + STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) +#ifdef CONFIG_ALTIVEC + STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) +#else + STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception) +#endif + +/* + * Here we have detected that the kernel stack pointer is bad. + * R9 contains the saved CR, r13 points to the paca, + * r10 contains the (bad) kernel stack pointer, + * r11 and r12 contain the saved SRR0 and SRR1. + * We switch to using an emergency stack, save the registers there, + * and call kernel_bad_stack(), which panics. + */ +bad_stack: + ld r1,PACAEMERGSP(r13) + subi r1,r1,64+INT_FRAME_SIZE + std r9,_CCR(r1) + std r10,GPR1(r1) + std r11,_NIP(r1) + std r12,_MSR(r1) + mfspr r11,DAR + mfspr r12,DSISR + std r11,_DAR(r1) + std r12,_DSISR(r1) + mflr r10 + mfctr r11 + mfxer r12 + std r10,_LINK(r1) + std r11,_CTR(r1) + std r12,_XER(r1) + SAVE_GPR(0,r1) + SAVE_GPR(2,r1) + SAVE_4GPRS(3,r1) + SAVE_2GPRS(7,r1) + SAVE_10GPRS(12,r1) + SAVE_10GPRS(22,r1) + addi r11,r1,INT_FRAME_SIZE + std r11,0(r1) + li r12,0 + std r12,0(r11) + ld r2,PACATOC(r13) +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .kernel_bad_stack + b 1b + +/* + * Return from an exception with minimal checks. + * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. + * If interrupts have been enabled, or anything has been + * done that might have changed the scheduling status of + * any task or sent any task a signal, you should use + * ret_from_except or ret_from_except_lite instead of this. + */ +fast_exception_return: + ld r12,_MSR(r1) + ld r11,_NIP(r1) + andi. r3,r12,MSR_RI /* check if RI is set */ + beq- unrecov_fer + ld r3,_CCR(r1) + ld r4,_LINK(r1) + ld r5,_CTR(r1) + ld r6,_XER(r1) + mtcr r3 + mtlr r4 + mtctr r5 + mtxer r6 + REST_GPR(0, r1) + REST_8GPRS(2, r1) + + mfmsr r10 + clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ + mtmsrd r10,1 + + mtspr SRR1,r12 + mtspr SRR0,r11 + REST_4GPRS(10, r1) + ld r1,GPR1(r1) + rfid + b . /* prevent speculative execution */ + +unrecov_fer: + bl .save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b + +/* + * Here r13 points to the paca, r9 contains the saved CR, + * SRR0 and SRR1 are saved in r11 and r12, + * r9 - r13 are saved in paca->exgen. + */ + .align 7 + .globl data_access_common +data_access_common: + RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */ + mfspr r10,DAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,DSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) + ld r3,PACA_EXGEN+EX_DAR(r13) + lwz r4,PACA_EXGEN+EX_DSISR(r13) + li r5,0x300 + b .do_hash_page /* Try to handle as hpte fault */ + + .align 7 + .globl instruction_access_common +instruction_access_common: + EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) + ld r3,_NIP(r1) + andis. r4,r12,0x5820 + li r5,0x400 + b .do_hash_page /* Try to handle as hpte fault */ + + .align 7 + .globl hardware_interrupt_common + .globl hardware_interrupt_entry +hardware_interrupt_common: + EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) +hardware_interrupt_entry: + DISABLE_INTS + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_IRQ + b .ret_from_except_lite + + .align 7 + .globl alignment_common +alignment_common: + mfspr r10,DAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,DSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN) + ld r3,PACA_EXGEN+EX_DAR(r13) + lwz r4,PACA_EXGEN+EX_DSISR(r13) + std r3,_DAR(r1) + std r4,_DSISR(r1) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS + bl .alignment_exception + b .ret_from_except + + .align 7 + .globl program_check_common +program_check_common: + EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS + bl .program_check_exception + b .ret_from_except + + .align 7 + .globl fp_unavailable_common +fp_unavailable_common: + EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) + bne .load_up_fpu /* if from user, just load it up */ + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS + bl .kernel_fp_unavailable_exception + BUG_OPCODE + +/* + * load_up_fpu(unused, unused, tsk) + * Disable FP for the task which had the FPU previously, + * and save its floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + * On SMP we know the fpu is free, since we give it up every + * switch (ie, no lazy save of the FP registers). + * On entry: r13 == 'current' && last_task_used_math != 'current' + */ +_STATIC(load_up_fpu) + mfmsr r5 /* grab the current MSR */ + ori r5,r5,MSR_FP + mtmsrd r5 /* enable use of fpu now */ + isync +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + * + */ +#ifndef CONFIG_SMP + ld r3,last_task_used_math@got(r2) + ld r4,0(r3) + cmpdi 0,r4,0 + beq 1f + /* Save FP state to last_task_used_math's THREAD struct */ + addi r4,r4,THREAD + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,THREAD_FPSCR(r4) + /* Disable FP for last_task_used_math */ + ld r5,PT_REGS(r4) + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r6,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r6 + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of FP after return */ + ld r4,PACACURRENT(r13) + addi r5,r4,THREAD /* Get THREAD */ + ld r4,THREAD_FPEXC_MODE(r5) + ori r12,r12,MSR_FP + or r12,r12,r4 + std r12,_MSR(r1) + lfd fr0,THREAD_FPSCR(r5) + mtfsf 0xff,fr0 + REST_32FPRS(0, r5) +#ifndef CONFIG_SMP + /* Update last_task_used_math to 'current' */ + subi r4,r5,THREAD /* Back to 'current' */ + std r4,0(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + b fast_exception_return + + .align 7 + .globl altivec_unavailable_common +altivec_unavailable_common: + EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) +#ifdef CONFIG_ALTIVEC +BEGIN_FTR_SECTION + bne .load_up_altivec /* if from user, just load it up */ +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) +#endif + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS + bl .altivec_unavailable_exception + b .ret_from_except + +#ifdef CONFIG_ALTIVEC +/* + * load_up_altivec(unused, unused, tsk) + * Disable VMX for the task which had it previously, + * and save its vector registers in its thread_struct. + * Enables the VMX for use in the kernel on return. + * On SMP we know the VMX is free, since we give it up every + * switch (ie, no lazy save of the vector registers). + * On entry: r13 == 'current' && last_task_used_altivec != 'current' + */ +_STATIC(load_up_altivec) + mfmsr r5 /* grab the current MSR */ + oris r5,r5,MSR_VEC@h + mtmsrd r5 /* enable use of VMX now */ + isync + +/* + * For SMP, we don't do lazy VMX switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_altvec in switch_to. + * VRSAVE isn't dealt with here, that is done in the normal context + * switch code. Note that we could rely on vrsave value to eventually + * avoid saving all of the VREGs here... + */ +#ifndef CONFIG_SMP + ld r3,last_task_used_altivec@got(r2) + ld r4,0(r3) + cmpdi 0,r4,0 + beq 1f + /* Save VMX state to last_task_used_altivec's THREAD struct */ + addi r4,r4,THREAD + SAVE_32VRS(0,r5,r4) + mfvscr vr0 + li r10,THREAD_VSCR + stvx vr0,r10,r4 + /* Disable VMX for last_task_used_altivec */ + ld r5,PT_REGS(r4) + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r6,MSR_VEC@h + andc r4,r4,r6 + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* Hack: if we get an altivec unavailable trap with VRSAVE + * set to all zeros, we assume this is a broken application + * that fails to set it properly, and thus we switch it to + * all 1's + */ + mfspr r4,SPRN_VRSAVE + cmpdi 0,r4,0 + bne+ 1f + li r4,-1 + mtspr SPRN_VRSAVE,r4 +1: + /* enable use of VMX after return */ + ld r4,PACACURRENT(r13) + addi r5,r4,THREAD /* Get THREAD */ + oris r12,r12,MSR_VEC@h + std r12,_MSR(r1) + li r4,1 + li r10,THREAD_VSCR + stw r4,THREAD_USED_VR(r5) + lvx vr0,r10,r5 + mtvscr vr0 + REST_32VRS(0,r4,r5) +#ifndef CONFIG_SMP + /* Update last_task_used_math to 'current' */ + subi r4,r5,THREAD /* Back to 'current' */ + std r4,0(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + b fast_exception_return +#endif /* CONFIG_ALTIVEC */ + +/* + * Hash table stuff + */ + .align 7 +_GLOBAL(do_hash_page) + std r3,_DAR(r1) + std r4,_DSISR(r1) + + andis. r0,r4,0xa450 /* weird error? */ + bne- .handle_page_fault /* if not, try to insert a HPTE */ +BEGIN_FTR_SECTION + andis. r0,r4,0x0020 /* Is it a segment table fault? */ + bne- .do_ste_alloc /* If so handle it */ +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + + /* + * We need to set the _PAGE_USER bit if MSR_PR is set or if we are + * accessing a userspace segment (even from the kernel). We assume + * kernel addresses always have the high bit set. + */ + rlwinm r4,r4,32-25+9,31-9,31-9 /* DSISR_STORE -> _PAGE_RW */ + rotldi r0,r3,15 /* Move high bit into MSR_PR posn */ + orc r0,r12,r0 /* MSR_PR | ~high_bit */ + rlwimi r4,r0,32-13,30,30 /* becomes _PAGE_USER access bit */ + ori r4,r4,1 /* add _PAGE_PRESENT */ + rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */ + + /* + * On iSeries, we soft-disable interrupts here, then + * hard-enable interrupts so that the hash_page code can spin on + * the hash_table_lock without problems on a shared processor. + */ + DISABLE_INTS + + /* + * r3 contains the faulting address + * r4 contains the required access permissions + * r5 contains the trap number + * + * at return r3 = 0 for success + */ + bl .hash_page /* build HPTE if possible */ + cmpdi r3,0 /* see if hash_page succeeded */ + +#ifdef DO_SOFT_DISABLE + /* + * If we had interrupts soft-enabled at the point where the + * DSI/ISI occurred, and an interrupt came in during hash_page, + * handle it now. + * We jump to ret_from_except_lite rather than fast_exception_return + * because ret_from_except_lite will check for and handle pending + * interrupts if necessary. + */ + beq .ret_from_except_lite + /* For a hash failure, we don't bother re-enabling interrupts */ + ble- 12f + + /* + * hash_page couldn't handle it, set soft interrupt enable back + * to what it was before the trap. Note that .local_irq_restore + * handles any interrupts pending at this point. + */ + ld r3,SOFTE(r1) + bl .local_irq_restore + b 11f +#else + beq fast_exception_return /* Return from exception on success */ + ble- 12f /* Failure return from hash_page */ + + /* fall through */ +#endif + +/* Here we have a page fault that hash_page can't handle. */ +_GLOBAL(handle_page_fault) + ENABLE_INTS +11: ld r4,_DAR(r1) + ld r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_page_fault + cmpdi r3,0 + beq+ .ret_from_except_lite + bl .save_nvgprs + mr r5,r3 + addi r3,r1,STACK_FRAME_OVERHEAD + lwz r4,_DAR(r1) + bl .bad_page_fault + b .ret_from_except + +/* We have a page fault that hash_page could handle but HV refused + * the PTE insertion + */ +12: bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + lwz r4,_DAR(r1) + bl .low_hash_fault + b .ret_from_except + + /* here we have a segment miss */ +_GLOBAL(do_ste_alloc) + bl .ste_allocate /* try to insert stab entry */ + cmpdi r3,0 + beq+ fast_exception_return + b .handle_page_fault + +/* + * r13 points to the PACA, r9 contains the saved CR, + * r11 and r12 contain the saved SRR0 and SRR1. + * r9 - r13 are saved in paca->exslb. + * We assume we aren't going to take any exceptions during this procedure. + * We assume (DAR >> 60) == 0xc. + */ + .align 7 +_GLOBAL(do_stab_bolted) + stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ + std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ + + /* Hash to the primary group */ + ld r10,PACASTABVIRT(r13) + mfspr r11,DAR + srdi r11,r11,28 + rldimi r10,r11,7,52 /* r10 = first ste of the group */ + + /* Calculate VSID */ + /* This is a kernel address, so protovsid = ESID */ + ASM_VSID_SCRAMBLE(r11, r9) + rldic r9,r11,12,16 /* r9 = vsid << 12 */ + + /* Search the primary group for a free entry */ +1: ld r11,0(r10) /* Test valid bit of the current ste */ + andi. r11,r11,0x80 + beq 2f + addi r10,r10,16 + andi. r11,r10,0x70 + bne 1b + + /* Stick for only searching the primary group for now. */ + /* At least for now, we use a very simple random castout scheme */ + /* Use the TB as a random number ; OR in 1 to avoid entry 0 */ + mftb r11 + rldic r11,r11,4,57 /* r11 = (r11 << 4) & 0x70 */ + ori r11,r11,0x10 + + /* r10 currently points to an ste one past the group of interest */ + /* make it point to the randomly selected entry */ + subi r10,r10,128 + or r10,r10,r11 /* r10 is the entry to invalidate */ + + isync /* mark the entry invalid */ + ld r11,0(r10) + rldicl r11,r11,56,1 /* clear the valid bit */ + rotldi r11,r11,8 + std r11,0(r10) + sync + + clrrdi r11,r11,28 /* Get the esid part of the ste */ + slbie r11 + +2: std r9,8(r10) /* Store the vsid part of the ste */ + eieio + + mfspr r11,DAR /* Get the new esid */ + clrrdi r11,r11,28 /* Permits a full 32b of ESID */ + ori r11,r11,0x90 /* Turn on valid and kp */ + std r11,0(r10) /* Put new entry back into the stab */ + + sync + + /* All done -- return from exception. */ + lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ + ld r11,PACA_EXSLB+EX_SRR0(r13) /* get saved SRR0 */ + + andi. r10,r12,MSR_RI + beq- unrecov_slb + + mtcrf 0x80,r9 /* restore CR */ + + mfmsr r10 + clrrdi r10,r10,2 + mtmsrd r10,1 + + mtspr SRR0,r11 + mtspr SRR1,r12 + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +/* + * r13 points to the PACA, r9 contains the saved CR, + * r11 and r12 contain the saved SRR0 and SRR1. + * r3 has the faulting address + * r9 - r13 are saved in paca->exslb. + * r3 is saved in paca->slb_r3 + * We assume we aren't going to take any exceptions during this procedure. + */ +_GLOBAL(do_slb_miss) + mflr r10 + + stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ + std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ + + bl .slb_allocate /* handle it */ + + /* All done -- return from exception. */ + + ld r10,PACA_EXSLB+EX_LR(r13) + ld r3,PACA_EXSLB+EX_R3(r13) + lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ +#ifdef CONFIG_PPC_ISERIES + ld r11,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */ +#endif /* CONFIG_PPC_ISERIES */ + + mtlr r10 + + andi. r10,r12,MSR_RI /* check for unrecoverable exception */ + beq- unrecov_slb + +.machine push +.machine "power4" + mtcrf 0x80,r9 + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ +.machine pop + +#ifdef CONFIG_PPC_ISERIES + mtspr SRR0,r11 + mtspr SRR1,r12 +#endif /* CONFIG_PPC_ISERIES */ + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +unrecov_slb: + EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) + DISABLE_INTS + bl .save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b + +/* + * Space for CPU0's segment table. + * + * On iSeries, the hypervisor must fill in at least one entry before + * we get control (with relocate on). The address is give to the hv + * as a page number (see xLparMap in LparData.c), so this must be at a + * fixed address (the linker can't compute (u64)&initial_stab >> + * PAGE_SHIFT). + */ + . = STAB0_PHYS_ADDR /* 0x6000 */ + .globl initial_stab +initial_stab: + .space 4096 + +/* + * Data area reserved for FWNMI option. + * This address (0x7000) is fixed by the RPA. + */ + .= 0x7000 + .globl fwnmi_data_area +fwnmi_data_area: + + /* iSeries does not use the FWNMI stuff, so it is safe to put + * this here, even if we later allow kernels that will boot on + * both pSeries and iSeries */ +#ifdef CONFIG_PPC_ISERIES + . = LPARMAP_PHYS +#include "lparmap.s" +/* + * This ".text" is here for old compilers that generate a trailing + * .note section when compiling .c files to .s + */ + .text +#endif /* CONFIG_PPC_ISERIES */ + + . = 0x8000 + +/* + * On pSeries, secondary processors spin in the following code. + * At entry, r3 = this processor's number (physical cpu id) + */ +_GLOBAL(pSeries_secondary_smp_init) + mr r24,r3 + + /* turn on 64-bit mode */ + bl .enable_64b_mode + isync + + /* Copy some CPU settings from CPU 0 */ + bl .__restore_cpu_setup + + /* Set up a paca value for this processor. Since we have the + * physical cpu id in r24, we need to search the pacas to find + * which logical id maps to our physical one. + */ + LOADADDR(r13, paca) /* Get base vaddr of paca array */ + li r5,0 /* logical cpu id */ +1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ + cmpw r6,r24 /* Compare to our id */ + beq 2f + addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */ + addi r5,r5,1 + cmpwi r5,NR_CPUS + blt 1b + + mr r3,r24 /* not found, copy phys to r3 */ + b .kexec_wait /* next kernel might do better */ + +2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ + /* From now on, r24 is expected to be logical cpuid */ + mr r24,r5 +3: HMT_LOW + lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ + /* start. */ + sync + + /* Create a temp kernel stack for use before relocation is on. */ + ld r1,PACAEMERGSP(r13) + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 +#ifdef CONFIG_SMP + bne .__secondary_start +#endif + b 3b /* Loop until told to go */ + +#ifdef CONFIG_PPC_ISERIES +_STATIC(__start_initialization_iSeries) + /* Clear out the BSS */ + LOADADDR(r11,__bss_stop) + LOADADDR(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + LOADADDR(r1,init_thread_union) + addi r1,r1,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + LOADADDR(r3,cpu_specs) + LOADADDR(r4,cur_cpu_spec) + li r5,0 + bl .identify_cpu + + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + bl .iSeries_early_setup + + /* relocation is on at this point */ + + b .start_here_common +#endif /* CONFIG_PPC_ISERIES */ + +#ifdef CONFIG_PPC_MULTIPLATFORM + +_STATIC(__mmu_off) + mfmsr r3 + andi. r0,r3,MSR_IR|MSR_DR + beqlr + andc r3,r3,r0 + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + sync + rfid + b . /* prevent speculative execution */ + + +/* + * Here is our main kernel entry point. We support currently 2 kind of entries + * depending on the value of r5. + * + * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content + * in r3...r7 + * + * r5 == NULL -> kexec style entry. r3 is a physical pointer to the + * DT block, r4 is a physical pointer to the kernel itself + * + */ +_GLOBAL(__start_initialization_multiplatform) + /* + * Are we booted from a PROM Of-type client-interface ? + */ + cmpldi cr0,r5,0 + bne .__boot_from_prom /* yes -> prom */ + + /* Save parameters */ + mr r31,r3 + mr r30,r4 + + /* Make sure we are running in 64 bits mode */ + bl .enable_64b_mode + + /* Setup some critical 970 SPRs before switching MMU off */ + bl .__970_cpu_preinit + + /* cpu # */ + li r24,0 + + /* Switch off MMU if not already */ + LOADADDR(r4, .__after_prom_start - KERNELBASE) + add r4,r4,r30 + bl .__mmu_off + b .__after_prom_start + +_STATIC(__boot_from_prom) + /* Save parameters */ + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + + /* Make sure we are running in 64 bits mode */ + bl .enable_64b_mode + + /* put a relocation offset into r3 */ + bl .reloc_offset + + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + /* Relocate the TOC from a virt addr to a real addr */ + sub r2,r2,r3 + + /* Restore parameters */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + + /* Do all of the interaction with OF client interface */ + bl .prom_init + /* We never return */ + trap + +/* + * At this point, r3 contains the physical address we are running at, + * returned by prom_init() + */ +_STATIC(__after_prom_start) + +/* + * We need to run with __start at physical address 0. + * This will leave some code in the first 256B of + * real memory, which are reserved for software use. + * The remainder of the first page is loaded with the fixed + * interrupt vectors. The next two pages are filled with + * unknown exception placeholders. + * + * Note: This process overwrites the OF exception vectors. + * r26 == relocation offset + * r27 == KERNELBASE + */ + bl .reloc_offset + mr r26,r3 + SET_REG_TO_CONST(r27,KERNELBASE) + + li r3,0 /* target addr */ + + // XXX FIXME: Use phys returned by OF (r30) + sub r4,r27,r26 /* source addr */ + /* current address of _start */ + /* i.e. where we are running */ + /* the source addr */ + + LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */ + sub r5,r5,r27 + + li r6,0x100 /* Start offset, the first 0x100 */ + /* bytes were copied earlier. */ + + bl .copy_and_flush /* copy the first n bytes */ + /* this includes the code being */ + /* executed here. */ + + LOADADDR(r0, 4f) /* Jump to the copy of this code */ + mtctr r0 /* that we just made/relocated */ + bctr + +4: LOADADDR(r5,klimit) + sub r5,r5,r26 + ld r5,0(r5) /* get the value of klimit */ + sub r5,r5,r27 + bl .copy_and_flush /* copy the rest */ + b .start_here_multiplatform + +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +/* + * Copy routine used to copy the kernel to start at physical address 0 + * and flush and invalidate the caches as needed. + * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset + * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. + * + * Note: this routine *only* clobbers r0, r6 and lr + */ +_GLOBAL(copy_and_flush) + addi r5,r5,-8 + addi r6,r6,-8 +4: li r0,16 /* Use the least common */ + /* denominator cache line */ + /* size. This results in */ + /* extra cache line flushes */ + /* but operation is correct. */ + /* Can't get cache line size */ + /* from NACA as it is being */ + /* moved too. */ + + mtctr r0 /* put # words/line in ctr */ +3: addi r6,r6,8 /* copy a cache line */ + ldx r0,r6,r4 + stdx r0,r6,r3 + bdnz 3b + dcbst r6,r3 /* write it to memory */ + sync + icbi r6,r3 /* flush the icache line */ + cmpld 0,r6,r5 + blt 4b + sync + addi r5,r5,8 + addi r6,r6,8 + blr + +.align 8 +copy_to_here: + +#ifdef CONFIG_SMP +#ifdef CONFIG_PPC_PMAC +/* + * On PowerMac, secondary processors starts from the reset vector, which + * is temporarily turned into a call to one of the functions below. + */ + .section ".text"; + .align 2 ; + + .globl pmac_secondary_start_1 +pmac_secondary_start_1: + li r24, 1 + b .pmac_secondary_start + + .globl pmac_secondary_start_2 +pmac_secondary_start_2: + li r24, 2 + b .pmac_secondary_start + + .globl pmac_secondary_start_3 +pmac_secondary_start_3: + li r24, 3 + b .pmac_secondary_start + +_GLOBAL(pmac_secondary_start) + /* turn on 64-bit mode */ + bl .enable_64b_mode + isync + + /* Copy some CPU settings from CPU 0 */ + bl .__restore_cpu_setup + + /* pSeries do that early though I don't think we really need it */ + mfmsr r3 + ori r3,r3,MSR_RI + mtmsrd r3 /* RI on */ + + /* Set up a paca value for this processor. */ + LOADADDR(r4, paca) /* Get base vaddr of paca array */ + mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ + add r13,r13,r4 /* for this processor. */ + mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ + + /* Create a temp kernel stack for use before relocation is on. */ + ld r1,PACAEMERGSP(r13) + subi r1,r1,STACK_FRAME_OVERHEAD + + b .__secondary_start + +#endif /* CONFIG_PPC_PMAC */ + +/* + * This function is called after the master CPU has released the + * secondary processors. The execution environment is relocation off. + * The paca for this processor has the following fields initialized at + * this point: + * 1. Processor number + * 2. Segment table pointer (virtual address) + * On entry the following are set: + * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries + * r24 = cpu# (in Linux terms) + * r13 = paca virtual address + * SPRG3 = paca virtual address + */ +_GLOBAL(__secondary_start) + + HMT_MEDIUM /* Set thread priority to MEDIUM */ + + ld r2,PACATOC(r13) + li r6,0 + stb r6,PACAPROCENABLED(r13) + +#ifndef CONFIG_PPC_ISERIES + /* Initialize the page table pointer register. */ + LOADADDR(r6,_SDR1) + ld r6,0(r6) /* get the value of _SDR1 */ + mtspr SDR1,r6 /* set the htab location */ +#endif + /* Initialize the first segment table (or SLB) entry */ + ld r3,PACASTABVIRT(r13) /* get addr of segment table */ + bl .stab_initialize + + /* Initialize the kernel stack. Just a repeat for iSeries. */ + LOADADDR(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r1,r3,r28 + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + std r1,PACAKSAVE(r13) + + ld r3,PACASTABREAL(r13) /* get raddr of segment table */ + ori r4,r3,1 /* turn on valid bit */ + +#ifdef CONFIG_PPC_ISERIES + li r0,-1 /* hypervisor call */ + li r3,1 + sldi r3,r3,63 /* 0x8000000000000000 */ + ori r3,r3,4 /* 0x8000000000000004 */ + sc /* HvCall_setASR */ +#else + /* set the ASR */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) + lwz r3,PLATFORM(r3) /* r3 = platform flags */ + andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ + beq 98f /* branch if result is 0 */ + mfspr r3,PVR + srwi r3,r3,16 + cmpwi r3,0x37 /* SStar */ + beq 97f + cmpwi r3,0x36 /* IStar */ + beq 97f + cmpwi r3,0x34 /* Pulsar */ + bne 98f +97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ + HVSC /* Invoking hcall */ + b 99f +98: /* !(rpa hypervisor) || !(star) */ + mtasr r4 /* set the stab location */ +99: +#endif + li r7,0 + mtlr r7 + + /* enable MMU and jump to start_secondary */ + LOADADDR(r3,.start_secondary_prolog) + SET_REG_TO_CONST(r4, MSR_KERNEL) +#ifdef DO_SOFT_DISABLE + ori r4,r4,MSR_EE +#endif + mtspr SRR0,r3 + mtspr SRR1,r4 + rfid + b . /* prevent speculative execution */ + +/* + * Running with relocation on at this point. All we want to do is + * zero the stack back-chain pointer before going into C code. + */ +_GLOBAL(start_secondary_prolog) + li r3,0 + std r3,0(r1) /* Zero the stack frame pointer */ + bl .start_secondary +#endif + +/* + * This subroutine clobbers r11 and r12 + */ +_GLOBAL(enable_64b_mode) + mfmsr r11 /* grab the current MSR */ + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + or r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + or r11,r11,r12 + mtmsrd r11 + isync + blr + +#ifdef CONFIG_PPC_MULTIPLATFORM +/* + * This is where the main kernel code starts. + */ +_STATIC(start_here_multiplatform) + /* get a new offset, now that the kernel has moved. */ + bl .reloc_offset + mr r26,r3 + + /* Clear out the BSS. It may have been done in prom_init, + * already but that's irrelevant since prom_init will soon + * be detached from the kernel completely. Besides, we need + * to clear it now for kexec-style entry. + */ + LOADADDR(r11,__bss_stop) + LOADADDR(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + + mfmsr r6 + ori r6,r6,MSR_RI + mtmsrd r6 /* RI on */ + +#ifdef CONFIG_HMT + /* Start up the second thread on cpu 0 */ + mfspr r3,PVR + srwi r3,r3,16 + cmpwi r3,0x34 /* Pulsar */ + beq 90f + cmpwi r3,0x36 /* Icestar */ + beq 90f + cmpwi r3,0x37 /* SStar */ + beq 90f + b 91f /* HMT not supported */ +90: li r3,0 + bl .hmt_start_secondary +91: +#endif + + /* The following gets the stack and TOC set up with the regs */ + /* pointing to the real addr of the kernel stack. This is */ + /* all done to support the C function call below which sets */ + /* up the htab. This is done because we have relocated the */ + /* kernel but are still running in real mode. */ + + LOADADDR(r3,init_thread_union) + sub r3,r3,r26 + + /* set up a stack pointer (physical address) */ + addi r1,r3,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + /* set up the TOC (physical address) */ + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + sub r2,r2,r26 + + LOADADDR(r3,cpu_specs) + sub r3,r3,r26 + LOADADDR(r4,cur_cpu_spec) + sub r4,r4,r26 + mr r5,r26 + bl .identify_cpu + + /* Save some low level config HIDs of CPU0 to be copied to + * other CPUs later on, or used for suspend/resume + */ + bl .__save_cpu_setup + sync + + /* Setup a valid physical PACA pointer in SPRG3 for early_setup + * note that boot_cpuid can always be 0 nowadays since there is + * nowhere it can be initialized differently before we reach this + * code + */ + LOADADDR(r27, boot_cpuid) + sub r27,r27,r26 + lwz r27,0(r27) + + LOADADDR(r24, paca) /* Get base vaddr of paca array */ + mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ + add r13,r13,r24 /* for this processor. */ + sub r13,r13,r26 /* convert to physical addr */ + mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ + + /* Do very early kernel initializations, including initial hash table, + * stab and slb setup before we turn on relocation. */ + + /* Restore parameters passed from prom_init/kexec */ + mr r3,r31 + bl .early_setup + + /* set the ASR */ + ld r3,PACASTABREAL(r13) + ori r4,r3,1 /* turn on valid bit */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) + lwz r3,PLATFORM(r3) /* r3 = platform flags */ + andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ + beq 98f /* branch if result is 0 */ + mfspr r3,PVR + srwi r3,r3,16 + cmpwi r3,0x37 /* SStar */ + beq 97f + cmpwi r3,0x36 /* IStar */ + beq 97f + cmpwi r3,0x34 /* Pulsar */ + bne 98f +97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ + HVSC /* Invoking hcall */ + b 99f +98: /* !(rpa hypervisor) || !(star) */ + mtasr r4 /* set the stab location */ +99: + /* Set SDR1 (hash table pointer) */ + ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) + lwz r3,PLATFORM(r3) /* r3 = platform flags */ + /* Test if bit 0 is set (LPAR bit) */ + andi. r3,r3,PLATFORM_LPAR + bne 98f /* branch if result is !0 */ + LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ + sub r6,r6,r26 + ld r6,0(r6) /* get the value of _SDR1 */ + mtspr SDR1,r6 /* set the htab location */ +98: + LOADADDR(r3,.start_here_common) + SET_REG_TO_CONST(r4, MSR_KERNEL) + mtspr SRR0,r3 + mtspr SRR1,r4 + rfid + b . /* prevent speculative execution */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ + + /* This is where all platforms converge execution */ +_STATIC(start_here_common) + /* relocation is on at this point */ + + /* The following code sets up the SP and TOC now that we are */ + /* running with translation enabled. */ + + LOADADDR(r3,init_thread_union) + + /* set up the stack */ + addi r1,r3,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + /* Apply the CPUs-specific fixups (nop out sections not relevant + * to this CPU + */ + li r3,0 + bl .do_cpu_ftr_fixups + + LOADADDR(r26, boot_cpuid) + lwz r26,0(r26) + + LOADADDR(r24, paca) /* Get base vaddr of paca array */ + mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */ + add r13,r13,r24 /* for this processor. */ + mtspr SPRG3,r13 + + /* ptr to current */ + LOADADDR(r4,init_task) + std r4,PACACURRENT(r13) + + /* Load the TOC */ + ld r2,PACATOC(r13) + std r1,PACAKSAVE(r13) + + bl .setup_system + + /* Load up the kernel context */ +5: +#ifdef DO_SOFT_DISABLE + li r5,0 + stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ + mfmsr r5 + ori r5,r5,MSR_EE /* Hard Enabled */ + mtmsrd r5 +#endif + + bl .start_kernel + +_GLOBAL(hmt_init) +#ifdef CONFIG_HMT + LOADADDR(r5, hmt_thread_data) + mfspr r7,PVR + srwi r7,r7,16 + cmpwi r7,0x34 /* Pulsar */ + beq 90f + cmpwi r7,0x36 /* Icestar */ + beq 91f + cmpwi r7,0x37 /* SStar */ + beq 91f + b 101f +90: mfspr r6,PIR + andi. r6,r6,0x1f + b 92f +91: mfspr r6,PIR + andi. r6,r6,0x3ff +92: sldi r4,r24,3 + stwx r6,r5,r4 + bl .hmt_start_secondary + b 101f + +__hmt_secondary_hold: + LOADADDR(r5, hmt_thread_data) + clrldi r5,r5,4 + li r7,0 + mfspr r6,PIR + mfspr r8,PVR + srwi r8,r8,16 + cmpwi r8,0x34 + bne 93f + andi. r6,r6,0x1f + b 103f +93: andi. r6,r6,0x3f + +103: lwzx r8,r5,r7 + cmpw r8,r6 + beq 104f + addi r7,r7,8 + b 103b + +104: addi r7,r7,4 + lwzx r9,r5,r7 + mr r24,r9 +101: +#endif + mr r3,r24 + b .pSeries_secondary_smp_init + +#ifdef CONFIG_HMT +_GLOBAL(hmt_start_secondary) + LOADADDR(r4,__hmt_secondary_hold) + clrldi r4,r4,4 + mtspr NIADORM, r4 + mfspr r4, MSRDORM + li r5, -65 + and r4, r4, r5 + mtspr MSRDORM, r4 + lis r4,0xffef + ori r4,r4,0x7403 + mtspr TSC, r4 + li r4,0x1f4 + mtspr TST, r4 + mfspr r4, HID0 + ori r4, r4, 0x1 + mtspr HID0, r4 + mfspr r4, SPRN_CTRLF + oris r4, r4, 0x40 + mtspr SPRN_CTRLT, r4 + blr +#endif + +#if defined(CONFIG_KEXEC) || (defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)) +_GLOBAL(smp_release_cpus) + /* All secondary cpus are spinning on a common + * spinloop, release them all now so they can start + * to spin on their individual paca spinloops. + * For non SMP kernels, the secondary cpus never + * get out of the common spinloop. + */ + li r3,1 + LOADADDR(r5,__secondary_hold_spinloop) + std r3,0(r5) + sync + blr +#endif /* CONFIG_SMP && !CONFIG_PPC_ISERIES */ + + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the bss, which is page-aligned. + */ + .section ".bss" + + .align PAGE_SHIFT + + .globl empty_zero_page +empty_zero_page: + .space PAGE_SIZE + + .globl swapper_pg_dir +swapper_pg_dir: + .space PAGE_SIZE + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space COMMAND_LINE_SIZE diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S new file mode 100644 index 000000000000..cb1a3a54a026 --- /dev/null +++ b/arch/powerpc/kernel/head_8xx.S @@ -0,0 +1,860 @@ +/* + * arch/ppc/kernel/except_8xx.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications by Dan Malek + * Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains low-level support and setup for PowerPC 8xx + * embedded processors, including trap and interrupt dispatch. + * + * 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 + +/* Macro to make the code more readable. */ +#ifdef CONFIG_8xx_CPU6 +#define DO_8xx_CPU6(val, reg) \ + li reg, val; \ + stw reg, 12(r0); \ + lwz reg, 12(r0); +#else +#define DO_8xx_CPU6(val, reg) +#endif + .text + .globl _stext +_stext: + .text + .globl _start +_start: + +/* MPC8xx + * This port was done on an MBX board with an 860. Right now I only + * support an ELF compressed (zImage) boot from EPPC-Bug because the + * code there loads up some registers before calling us: + * r3: ptr to board info data + * r4: initrd_start or if no initrd then 0 + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + * + * I decided to use conditional compilation instead of checking PVR and + * adding more processor specific branches around code I don't need. + * Since this is an embedded processor, I also appreciate any memory + * savings I can get. + * + * The MPC8xx does not have any BATs, but it supports large page sizes. + * We first initialize the MMU to support 8M byte pages, then load one + * entry into each of the instruction and data TLBs to map the first + * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to + * the "internal" processor registers before MMU_init is called. + * + * The TLB code currently contains a major hack. Since I use the condition + * code register, I have to save and restore it. I am out of registers, so + * I just store it in memory location 0 (the TLB handlers are not reentrant). + * To avoid making any decisions, I need to use the "segment" valid bit + * in the first level table, but that would require many changes to the + * Linux page directory/table functions that I don't want to do right now. + * + * I used to use SPRG2 for a temporary register in the TLB handler, but it + * has since been put to other uses. I now use a hack to save a register + * and the CCR at memory location 0.....Someday I'll fix this..... + * -- Dan + */ + .globl __start +__start: + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + + /* We have to turn on the MMU right away so we get cache modes + * set correctly. + */ + bl initial_mmu + +/* We now have the lower 8 Meg mapped into TLB entries, and the caches + * ready to work. + */ + +turn_on_mmu: + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SPRN_SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SPRN_SRR0,r0 + SYNC + rfi /* enables MMU */ + +/* + * Exception entry code. This code runs with address translation + * turned off, i.e. using physical addresses. + * We assume sprg3 has the physical address of the current + * task's thread_struct. + */ +#define EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; \ + mtspr SPRN_SPRG1,r11; \ + mfcr r10; \ + EXCEPTION_PROLOG_1; \ + EXCEPTION_PROLOG_2 + +#define EXCEPTION_PROLOG_1 \ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \ + andi. r11,r11,MSR_PR; \ + tophys(r11,r1); /* use tophys(r1) if kernel */ \ + beq 1f; \ + mfspr r11,SPRN_SPRG3; \ + lwz r11,THREAD_INFO-THREAD(r11); \ + addi r11,r11,THREAD_SIZE; \ + tophys(r11,r11); \ +1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */ + + +#define EXCEPTION_PROLOG_2 \ + CLR_TOP32(r11); \ + stw r10,_CCR(r11); /* save registers */ \ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRN_SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRN_SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_SRR0; \ + mfspr r9,SPRN_SRR1; \ + stw r1,GPR1(r11); \ + stw r1,0(r11); \ + tovirt(r1,r11); /* set new kernel sp */ \ + li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ + MTMSRD(r10); /* (except for mach check in rtas) */ \ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r11, r12 (SRR0), and r9 (SRR1). + * + * Note2: once we have set r1 we are in a position to take exceptions + * again, and we could thus set MSR:RI at that point. + */ + +/* + * Exception vectors. + */ +#define EXCEPTION(n, label, hdlr, xfer) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + li r10,MSR_KERNEL; \ + copyee(r10, r9); \ + bl tfer; \ +i##n: \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \ + ret_from_except) + +/* System reset */ + EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) + +/* Machine check */ + . = 0x200 +MachineCheck: + EXCEPTION_PROLOG + mfspr r4,SPRN_DAR + stw r4,_DAR(r11) + mfspr r5,SPRN_DSISR + stw r5,_DSISR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_STD(0x200, MachineCheckException) + +/* Data access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x300 +DataAccess: + EXCEPTION_PROLOG + mfspr r10,SPRN_DSISR + stw r10,_DSISR(r11) + mr r5,r10 + mfspr r4,SPRN_DAR + EXC_XFER_EE_LITE(0x300, handle_page_fault) + +/* Instruction access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x400 +InstructionAccess: + EXCEPTION_PROLOG + mr r4,r12 + mr r5,r9 + EXC_XFER_EE_LITE(0x400, handle_page_fault) + +/* External interrupt */ + EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) + +/* Alignment exception */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,SPRN_DAR + stw r4,_DAR(r11) + mfspr r5,SPRN_DSISR + stw r5,_DSISR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0x600, AlignmentException) + +/* Program check exception */ + EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + +/* No FPU on MPC8xx. This exception is not supposed to happen. +*/ + EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD) + +/* Decrementer */ + EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) + + EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + +/* System call */ + . = 0xc00 +SystemCall: + EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0xc00, DoSyscall) + +/* Single step - not used on 601 */ + EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) + EXCEPTION(0xf00, Trap_0f, UnknownException, EXC_XFER_EE) + +/* On the MPC8xx, this is a software emulation interrupt. It occurs + * for all unimplemented and illegal instructions. + */ + EXCEPTION(0x1000, SoftEmu, SoftwareEmulation, EXC_XFER_STD) + + . = 0x1100 +/* + * For the MPC8xx, this is a software tablewalk to load the instruction + * TLB. It is modelled after the example in the Motorola manual. The task + * switch loads the M_TWB register with the pointer to the first level table. + * If we discover there is no second level table (value is zero) or if there + * is an invalid pte, we load that into the TLB, which causes another fault + * into the TLB Error interrupt where we can handle such problems. + * We have to use the MD_xxx registers for the tablewalk because the + * equivalent MI_xxx registers only perform the attribute functions. + */ +InstructionTLBMiss: +#ifdef CONFIG_8xx_CPU6 + stw r3, 8(r0) +#endif + DO_8xx_CPU6(0x3f80, r3) + mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ + mfcr r10 + stw r10, 0(r0) + stw r11, 4(r0) + mfspr r10, SPRN_SRR0 /* Get effective address of fault */ + DO_8xx_CPU6(0x3780, r3) + mtspr SPRN_MD_EPN, r10 /* Have to use MD_EPN for walk, MI_EPN can't */ + mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r11, r10, 0x0800 /* Address >= 0x80000000 */ + beq 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + rlwimi r10, r11, 0, 2, 19 +3: + lwz r11, 0(r10) /* Get the level 1 entry */ + rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load the MI_TWC with the attributes + * for this "segment." + */ + ori r11,r11,1 /* Set valid bit */ + DO_8xx_CPU6(0x2b80, r3) + mtspr SPRN_MI_TWC, r11 /* Set segment attributes */ + DO_8xx_CPU6(0x3b80, r3) + mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ + mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ + lwz r10, 0(r11) /* Get the pte */ + + ori r10, r10, _PAGE_ACCESSED + stw r10, 0(r11) + + /* The Linux PTE won't go exactly into the MMU TLB. + * Software indicator bits 21, 22 and 28 must be clear. + * Software indicator bits 24, 25, 26, and 27 must be + * set. All other Linux PTE bits control the behavior + * of the MMU. + */ +2: li r11, 0x00f0 + rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ + DO_8xx_CPU6(0x2d80, r3) + mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ + + mfspr r10, SPRN_M_TW /* Restore registers */ + lwz r11, 0(r0) + mtcr r11 + lwz r11, 4(r0) +#ifdef CONFIG_8xx_CPU6 + lwz r3, 8(r0) +#endif + rfi + + . = 0x1200 +DataStoreTLBMiss: +#ifdef CONFIG_8xx_CPU6 + stw r3, 8(r0) +#endif + DO_8xx_CPU6(0x3f80, r3) + mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ + mfcr r10 + stw r10, 0(r0) + stw r11, 4(r0) + mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r11, r10, 0x0800 + beq 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + rlwimi r10, r11, 0, 2, 19 +3: + lwz r11, 0(r10) /* Get the level 1 entry */ + rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load fetch the pte from the table. + */ + ori r11, r11, 1 /* Set valid bit in physical L2 page */ + DO_8xx_CPU6(0x3b80, r3) + mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ + mfspr r10, SPRN_MD_TWC /* ....and get the pte address */ + lwz r10, 0(r10) /* Get the pte */ + + /* Insert the Guarded flag into the TWC from the Linux PTE. + * It is bit 27 of both the Linux PTE and the TWC (at least + * I got that right :-). It will be better when we can put + * this into the Linux pgd/pmd and load it in the operation + * above. + */ + rlwimi r11, r10, 0, 27, 27 + DO_8xx_CPU6(0x3b80, r3) + mtspr SPRN_MD_TWC, r11 + + mfspr r11, SPRN_MD_TWC /* get the pte address again */ + ori r10, r10, _PAGE_ACCESSED + stw r10, 0(r11) + + /* The Linux PTE won't go exactly into the MMU TLB. + * Software indicator bits 21, 22 and 28 must be clear. + * Software indicator bits 24, 25, 26, and 27 must be + * set. All other Linux PTE bits control the behavior + * of the MMU. + */ +2: li r11, 0x00f0 + rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ + DO_8xx_CPU6(0x3d80, r3) + mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ + + mfspr r10, SPRN_M_TW /* Restore registers */ + lwz r11, 0(r0) + mtcr r11 + lwz r11, 4(r0) +#ifdef CONFIG_8xx_CPU6 + lwz r3, 8(r0) +#endif + rfi + +/* This is an instruction TLB error on the MPC8xx. This could be due + * to many reasons, such as executing guarded memory or illegal instruction + * addresses. There is nothing to do but handle a big time error fault. + */ + . = 0x1300 +InstructionTLBError: + b InstructionAccess + +/* This is the data TLB error on the MPC8xx. This could be due to + * many reasons, including a dirty update to a pte. We can catch that + * one here, but anything else is an error. First, we track down the + * Linux pte. If it is valid, write access is allowed, but the + * page dirty bit is not set, we will set it and reload the TLB. For + * any other case, we bail out to a higher level function that can + * handle it. + */ + . = 0x1400 +DataTLBError: +#ifdef CONFIG_8xx_CPU6 + stw r3, 8(r0) +#endif + DO_8xx_CPU6(0x3f80, r3) + mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ + mfcr r10 + stw r10, 0(r0) + stw r11, 4(r0) + + /* First, make sure this was a store operation. + */ + mfspr r10, SPRN_DSISR + andis. r11, r10, 0x0200 /* If set, indicates store op */ + beq 2f + + /* The EA of a data TLB miss is automatically stored in the MD_EPN + * register. The EA of a data TLB error is automatically stored in + * the DAR, but not the MD_EPN register. We must copy the 20 most + * significant bits of the EA from the DAR to MD_EPN before we + * start walking the page tables. We also need to copy the CASID + * value from the M_CASID register. + * Addendum: The EA of a data TLB error is _supposed_ to be stored + * in DAR, but it seems that this doesn't happen in some cases, such + * as when the error is due to a dcbi instruction to a page with a + * TLB that doesn't have the changed bit set. In such cases, there + * does not appear to be any way to recover the EA of the error + * since it is neither in DAR nor MD_EPN. As a workaround, the + * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs + * are initialized in mapin_ram(). This will avoid the problem, + * assuming we only use the dcbi instruction on kernel addresses. + */ + mfspr r10, SPRN_DAR + rlwinm r11, r10, 0, 0, 19 + ori r11, r11, MD_EVALID + mfspr r10, SPRN_M_CASID + rlwimi r11, r10, 0, 28, 31 + DO_8xx_CPU6(0x3780, r3) + mtspr SPRN_MD_EPN, r11 + + mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r11, r10, 0x0800 + beq 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + rlwimi r10, r11, 0, 2, 19 +3: + lwz r11, 0(r10) /* Get the level 1 entry */ + rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ + beq 2f /* If zero, bail */ + + /* We have a pte table, so fetch the pte from the table. + */ + ori r11, r11, 1 /* Set valid bit in physical L2 page */ + DO_8xx_CPU6(0x3b80, r3) + mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ + mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ + lwz r10, 0(r11) /* Get the pte */ + + andi. r11, r10, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail out if not */ + + /* Update 'changed', among others. + */ + ori r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + mfspr r11, SPRN_MD_TWC /* Get pte address again */ + stw r10, 0(r11) /* and update pte in table */ + + /* The Linux PTE won't go exactly into the MMU TLB. + * Software indicator bits 21, 22 and 28 must be clear. + * Software indicator bits 24, 25, 26, and 27 must be + * set. All other Linux PTE bits control the behavior + * of the MMU. + */ + li r11, 0x00f0 + rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ + DO_8xx_CPU6(0x3d80, r3) + mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ + + mfspr r10, SPRN_M_TW /* Restore registers */ + lwz r11, 0(r0) + mtcr r11 + lwz r11, 4(r0) +#ifdef CONFIG_8xx_CPU6 + lwz r3, 8(r0) +#endif + rfi +2: + mfspr r10, SPRN_M_TW /* Restore registers */ + lwz r11, 0(r0) + mtcr r11 + lwz r11, 4(r0) +#ifdef CONFIG_8xx_CPU6 + lwz r3, 8(r0) +#endif + b DataAccess + + EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) + +/* On the MPC8xx, these next four traps are used for development + * support of breakpoints and such. Someday I will get around to + * using them. + */ + EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + + . = 0x2000 + + .globl giveup_fpu +giveup_fpu: + blr + +/* + * This is where the main kernel code starts. + */ +start_here: + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + mtspr SPRN_SPRG3,r4 + li r3,0 + mtspr SPRN_SPRG2,r3 /* 0 => r1 has kernel sp */ + + /* stack */ + lis r1,init_thread_union@ha + addi r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) + + bl early_init /* We have to do this with MMU on */ + +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + +/* + * Go back to running unmapped so we can load up new values + * and change to using our exception vectors. + * On the 8xx, all we have to do is invalidate the TLB to clear + * the old 8M byte TLB mappings and load the page table base register. + */ + /* The right way to do this would be to track it down through + * init's THREAD like the context switch code does, but this is + * easier......until someone changes init's static structures. + */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + tophys(r6,r6) +#ifdef CONFIG_8xx_CPU6 + lis r4, cpu6_errata_word@h + ori r4, r4, cpu6_errata_word@l + li r3, 0x3980 + stw r3, 12(r4) + lwz r3, 12(r4) +#endif + mtspr SPRN_M_TWB, r6 + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + rfi +/* Load up the kernel context */ +2: + SYNC /* Force all PTE updates to finish */ + tlbia /* Clear all TLB entries */ + sync /* wait for tlbia/tlbie to finish */ + TLBSYNC /* ... on all CPUs */ + + /* set up the PTE pointers for the Abatron bdiGDB. + */ + tovirt(r6,r6) + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r5, 0xf0(r0) /* Must match your Abatron config file */ + tophys(r5,r5) + stw r6, 0(r5) + +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ + +/* Set up the initial MMU state so we can do the first level of + * kernel initialization. This maps the first 8 MBytes of memory 1:1 + * virtual to physical. Also, set the cache mode since that is defined + * by TLB entries and perform any additional mapping (like of the IMMR). + * If configured to pin some TLBs, we pin the first 8 Mbytes of kernel, + * 24 Mbytes of data, and the 8M IMMR space. Anything not covered by + * these mappings is mapped by page tables. + */ +initial_mmu: + tlbia /* Invalidate all TLB entries */ +#ifdef CONFIG_PIN_TLB + lis r8, MI_RSV4I@h + ori r8, r8, 0x1c00 +#else + li r8, 0 +#endif + mtspr SPRN_MI_CTR, r8 /* Set instruction MMU control */ + +#ifdef CONFIG_PIN_TLB + lis r10, (MD_RSV4I | MD_RESETVAL)@h + ori r10, r10, 0x1c00 + mr r8, r10 +#else + lis r10, MD_RESETVAL@h +#endif +#ifndef CONFIG_8xx_COPYBACK + oris r10, r10, MD_WTDEF@h +#endif + mtspr SPRN_MD_CTR, r10 /* Set data TLB control */ + + /* Now map the lower 8 Meg into the TLBs. For this quick hack, + * we can load the instruction and data TLB registers with the + * same values. + */ + lis r8, KERNELBASE@h /* Create vaddr for TLB */ + ori r8, r8, MI_EVALID /* Mark it valid */ + mtspr SPRN_MI_EPN, r8 + mtspr SPRN_MD_EPN, r8 + li r8, MI_PS8MEG /* Set 8M byte page */ + ori r8, r8, MI_SVALID /* Make it valid */ + mtspr SPRN_MI_TWC, r8 + mtspr SPRN_MD_TWC, r8 + li r8, MI_BOOTINIT /* Create RPN for address 0 */ + mtspr SPRN_MI_RPN, r8 /* Store TLB entry */ + mtspr SPRN_MD_RPN, r8 + lis r8, MI_Kp@h /* Set the protection mode */ + mtspr SPRN_MI_AP, r8 + mtspr SPRN_MD_AP, r8 + + /* Map another 8 MByte at the IMMR to get the processor + * internal registers (among other things). + */ +#ifdef CONFIG_PIN_TLB + addi r10, r10, 0x0100 + mtspr SPRN_MD_CTR, r10 +#endif + mfspr r9, 638 /* Get current IMMR */ + andis. r9, r9, 0xff80 /* Get 8Mbyte boundary */ + + mr r8, r9 /* Create vaddr for TLB */ + ori r8, r8, MD_EVALID /* Mark it valid */ + mtspr SPRN_MD_EPN, r8 + li r8, MD_PS8MEG /* Set 8M byte page */ + ori r8, r8, MD_SVALID /* Make it valid */ + mtspr SPRN_MD_TWC, r8 + mr r8, r9 /* Create paddr for TLB */ + ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ + mtspr SPRN_MD_RPN, r8 + +#ifdef CONFIG_PIN_TLB + /* Map two more 8M kernel data pages. + */ + addi r10, r10, 0x0100 + mtspr SPRN_MD_CTR, r10 + + lis r8, KERNELBASE@h /* Create vaddr for TLB */ + addis r8, r8, 0x0080 /* Add 8M */ + ori r8, r8, MI_EVALID /* Mark it valid */ + mtspr SPRN_MD_EPN, r8 + li r9, MI_PS8MEG /* Set 8M byte page */ + ori r9, r9, MI_SVALID /* Make it valid */ + mtspr SPRN_MD_TWC, r9 + li r11, MI_BOOTINIT /* Create RPN for address 0 */ + addis r11, r11, 0x0080 /* Add 8M */ + mtspr SPRN_MD_RPN, r8 + + addis r8, r8, 0x0080 /* Add 8M */ + mtspr SPRN_MD_EPN, r8 + mtspr SPRN_MD_TWC, r9 + addis r11, r11, 0x0080 /* Add 8M */ + mtspr SPRN_MD_RPN, r8 +#endif + + /* Since the cache is enabled according to the information we + * just loaded into the TLB, invalidate and enable the caches here. + * We should probably check/set other modes....later. + */ + lis r8, IDC_INVALL@h + mtspr SPRN_IC_CST, r8 + mtspr SPRN_DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr SPRN_IC_CST, r8 +#ifdef CONFIG_8xx_COPYBACK + mtspr SPRN_DC_CST, r8 +#else + /* For a debug option, I left this here to easily enable + * the write through cache mode + */ + lis r8, DC_SFWT@h + mtspr SPRN_DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr SPRN_DC_CST, r8 +#endif + blr + + +/* + * Set up to use a given MMU context. + * r3 is context number, r4 is PGD pointer. + * + * We place the physical address of the new task page directory loaded + * into the MMU base register, and set the ASID compare register with + * the new "context." + */ +_GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is passed as second argument. + */ + lis r5, KERNELBASE@h + lwz r5, 0xf0(r5) + stw r4, 0x4(r5) +#endif + +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + tophys (r4, r4) + li r7, 0x3980 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr SPRN_M_TWB, r4 /* Update MMU base address */ + li r7, 0x3380 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr SPRN_M_CASID, r3 /* Update context */ +#else + mtspr SPRN_M_CASID,r3 /* Update context */ + tophys (r4, r4) + mtspr SPRN_M_TWB, r4 /* and pgd */ +#endif + SYNC + blr + +#ifdef CONFIG_8xx_CPU6 +/* It's here because it is unique to the 8xx. + * It is important we get called with interrupts disabled. I used to + * do that, but it appears that all code that calls this already had + * interrupt disabled. + */ + .globl set_dec_cpu6 +set_dec_cpu6: + lis r7, cpu6_errata_word@h + ori r7, r7, cpu6_errata_word@l + li r4, 0x2c00 + stw r4, 8(r7) + lwz r4, 8(r7) + mtspr 22, r3 /* Update Decrementer */ + SYNC + blr +#endif + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 + +/* Room for two PTE table poiners, usually the kernel and current user + * pointer to their respective root page table (pgdir). + */ +abatron_pteptrs: + .space 8 + +#ifdef CONFIG_8xx_CPU6 + .globl cpu6_errata_word +cpu6_errata_word: + .space 16 +#endif + diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S new file mode 100644 index 000000000000..eba5a5f8ff08 --- /dev/null +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -0,0 +1,1058 @@ +/* + * arch/ppc/kernel/head_fsl_booke.S + * + * Kernel execution entry point code. + * + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * Copyright 2002-2004 MontaVista Software, Inc. + * PowerPC 44x support, Matt Porter + * Copyright 2004 Freescale Semiconductor, Inc + * PowerPC e500 modifications, Kumar Gala + * + * 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 "head_booke.h" + +/* As with the other PowerPC ports, it is expected that when code + * execution begins here, the following registers contain valid, yet + * optional, information: + * + * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) + * r4 - Starting address of the init RAM disk + * r5 - Ending address of the init RAM disk + * r6 - Start of kernel command line string (e.g. "mem=128") + * r7 - End of kernel command line string + * + */ + .text +_GLOBAL(_stext) +_GLOBAL(_start) + /* + * Reserve a word at a fixed location to store the address + * of abatron_pteptrs + */ + nop +/* + * Save parameters we are passed + */ + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* CPU number */ + +/* We try to not make any assumptions about how the boot loader + * setup or used the TLBs. We invalidate all mappings from the + * boot loader and load a single entry in TLB1[0] to map the + * first 16M of kernel memory. Any boot info passed from the + * bootloader needs to live in this first 16M. + * + * Requirement on bootloader: + * - The page we're executing in needs to reside in TLB1 and + * have IPROT=1. If not an invalidate broadcast could + * evict the entry we're currently executing in. + * + * r3 = Index of TLB1 were executing in + * r4 = Current MSR[IS] + * r5 = Index of TLB1 temp mapping + * + * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0] + * if needed + */ + +/* 1. Find the index of the entry we're executing in */ + bl invstr /* Find our address */ +invstr: mflr r6 /* Make it accessible */ + mfmsr r7 + rlwinm r4,r7,27,31,31 /* extract MSR[IS] */ + mfspr r7, SPRN_PID0 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ +#ifndef CONFIG_E200 + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + mfspr r7,SPRN_PID1 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */ + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + mfspr r7, SPRN_PID2 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* Fall through, we had to match */ +#endif +match_TLB: + mfspr r7,SPRN_MAS0 + rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ + + mfspr r7,SPRN_MAS1 /* Insure IPROT set */ + oris r7,r7,MAS1_IPROT@h + mtspr SPRN_MAS1,r7 + tlbwe + +/* 2. Invalidate all entries except the entry we're executing in */ + mfspr r9,SPRN_TLB1CFG + andi. r9,r9,0xfff + li r6,0 /* Set Entry counter to 0 */ +1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */ + mtspr SPRN_MAS0,r7 + tlbre + mfspr r7,SPRN_MAS1 + rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */ + cmpw r3,r6 + beq skpinv /* Dont update the current execution TLB */ + mtspr SPRN_MAS1,r7 + tlbwe + isync +skpinv: addi r6,r6,1 /* Increment */ + cmpw r6,r9 /* Are we done? */ + bne 1b /* If not, repeat */ + + /* Invalidate TLB0 */ + li r6,0x04 + tlbivax 0,r6 +#ifdef CONFIG_SMP + tlbsync +#endif + /* Invalidate TLB1 */ + li r6,0x0c + tlbivax 0,r6 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + +/* 3. Setup a temp mapping and jump to it */ + andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */ + addi r5, r5, 0x1 + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + + /* Just modify the entry ID and EPN for the temp mapping */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + xori r6,r4,1 /* Setup TMP mapping in the other Address space */ + slwi r6,r6,12 + oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l + mtspr SPRN_MAS1,r6 + mfspr r6,SPRN_MAS2 + li r7,0 /* temp EPN = 0 */ + rlwimi r7,r6,0,20,31 + mtspr SPRN_MAS2,r7 + tlbwe + + xori r6,r4,1 + slwi r6,r6,5 /* setup new context with other address space */ + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r7,r9,0,20,31 + addi r7,r7,24 + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r6 + rfi + +/* 4. Clear out PIDs & Search info */ + li r6,0 + mtspr SPRN_PID0,r6 +#ifndef CONFIG_E200 + mtspr SPRN_PID1,r6 + mtspr SPRN_PID2,r6 +#endif + mtspr SPRN_MAS6,r6 + +/* 5. Invalidate mapping we started in */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + li r6,0 + mtspr SPRN_MAS1,r6 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + +/* 6. Setup KERNELBASE mapping in TLB1[0] */ + lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ + mtspr SPRN_MAS0,r6 + lis r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l + mtspr SPRN_MAS1,r6 + li r7,0 + lis r6,KERNELBASE@h + ori r6,r6,KERNELBASE@l + rlwimi r6,r7,0,20,31 + mtspr SPRN_MAS2,r6 + li r7,(MAS3_SX|MAS3_SW|MAS3_SR) + mtspr SPRN_MAS3,r7 + tlbwe + +/* 7. Jump to KERNELBASE mapping */ + lis r7,MSR_KERNEL@h + ori r7,r7,MSR_KERNEL@l + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r6,r9,0,20,31 + addi r6,r6,24 + mtspr SPRN_SRR0,r6 + mtspr SPRN_SRR1,r7 + rfi /* start execution out of TLB1[0] entry */ + +/* 8. Clear out the temp mapping */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + tlbre + mtspr SPRN_MAS1,r8 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + + /* Establish the interrupt vector offsets */ + SET_IVOR(0, CriticalInput); + SET_IVOR(1, MachineCheck); + SET_IVOR(2, DataStorage); + SET_IVOR(3, InstructionStorage); + SET_IVOR(4, ExternalInput); + SET_IVOR(5, Alignment); + SET_IVOR(6, Program); + SET_IVOR(7, FloatingPointUnavailable); + SET_IVOR(8, SystemCall); + SET_IVOR(9, AuxillaryProcessorUnavailable); + SET_IVOR(10, Decrementer); + SET_IVOR(11, FixedIntervalTimer); + SET_IVOR(12, WatchdogTimer); + SET_IVOR(13, DataTLBError); + SET_IVOR(14, InstructionTLBError); + SET_IVOR(15, Debug); + SET_IVOR(32, SPEUnavailable); + SET_IVOR(33, SPEFloatingPointData); + SET_IVOR(34, SPEFloatingPointRound); +#ifndef CONFIG_E200 + SET_IVOR(35, PerformanceMonitor); +#endif + + /* Establish the interrupt vector base */ + lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ + mtspr SPRN_IVPR,r4 + + /* Setup the defaults for TLB entries */ + li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l +#ifdef CONFIG_E200 + oris r2,r2,MAS4_TLBSELD(1)@h +#endif + mtspr SPRN_MAS4, r2 + +#if 0 + /* Enable DOZE */ + mfspr r2,SPRN_HID0 + oris r2,r2,HID0_DOZE@h + mtspr SPRN_HID0, r2 +#endif +#ifdef CONFIG_E200 + /* enable dedicated debug exception handling resources (Debug APU) */ + mfspr r2,SPRN_HID0 + ori r2,r2,HID0_DAPUEN@l + mtspr SPRN_HID0,r2 +#endif + +#if !defined(CONFIG_BDI_SWITCH) + /* + * The Abatron BDI JTAG debugger does not tolerate others + * mucking with the debug registers. + */ + lis r2,DBCR0_IDM@h + mtspr SPRN_DBCR0,r2 + /* clear any residual debug events */ + li r2,-1 + mtspr SPRN_DBSR,r2 +#endif + + /* + * This is where the main kernel code starts. + */ + + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + + /* ptr to current thread */ + addi r4,r2,THREAD /* init task's THREAD */ + mtspr SPRN_SPRG3,r4 + + /* stack */ + lis r1,init_thread_union@h + ori r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) + + bl early_init + + mfspr r3,SPRN_TLB1CFG + andi. r3,r3,0xfff + lis r4,num_tlbcam_entries@ha + stw r3,num_tlbcam_entries@l(r4) +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + + /* Setup PTE pointers for the Abatron bdiGDB */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + lis r4, KERNELBASE@h + ori r4, r4, KERNELBASE@l + stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ + stw r6, 0(r5) + + /* Let's move on */ + lis r4,start_kernel@h + ori r4,r4,start_kernel@l + lis r3,MSR_KERNEL@h + ori r3,r3,MSR_KERNEL@l + mtspr SPRN_SRR0,r4 + mtspr SPRN_SRR1,r3 + rfi /* change context and jump to start_kernel */ + +/* Macros to hide the PTE size differences + * + * FIND_PTE -- walks the page tables given EA & pgdir pointer + * r10 -- EA of fault + * r11 -- PGDIR pointer + * r12 -- free + * label 2: is the bailout case + * + * if we find the pte (fall through): + * r11 is low pte word + * r12 is pointer to the pte + */ +#ifdef CONFIG_PTE_64BIT +#define PTE_FLAGS_OFFSET 4 +#define FIND_PTE \ + rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \ + lwzx r11, r12, r11; /* Get pgd/pmd entry */ \ + rlwinm. r12, r11, 0, 0, 20; /* Extract pt base address */ \ + beq 2f; /* Bail if no table */ \ + rlwimi r12, r10, 23, 20, 28; /* Compute pte address */ \ + lwz r11, 4(r12); /* Get pte entry */ +#else +#define PTE_FLAGS_OFFSET 0 +#define FIND_PTE \ + rlwimi r11, r10, 12, 20, 29; /* Create L1 (pgdir/pmd) address */ \ + lwz r11, 0(r11); /* Get L1 entry */ \ + rlwinm. r12, r11, 0, 0, 19; /* Extract L2 (pte) base address */ \ + beq 2f; /* Bail if no table */ \ + rlwimi r12, r10, 22, 20, 29; /* Compute PTE address */ \ + lwz r11, 0(r12); /* Get Linux PTE */ +#endif + +/* + * Interrupt vector entry code + * + * The Book E MMUs are always on so we don't need to handle + * interrupts in real mode as with previous PPC processors. In + * this case we handle interrupts in the kernel virtual address + * space. + * + * Interrupt vectors are dynamically placed relative to the + * interrupt prefix as determined by the address of interrupt_base. + * The interrupt vectors offsets are programmed using the labels + * for each interrupt vector entry. + * + * Interrupt vectors must be aligned on a 16 byte boundary. + * We align on a 32 byte cache line boundary for good measure. + */ + +interrupt_base: + /* Critical Input Interrupt */ + CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + + /* Machine Check Interrupt */ +#ifdef CONFIG_E200 + /* no RFMCI, MCSRRs on E200 */ + CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#else + MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#endif + + /* Data Storage Interrupt */ + START_EXCEPTION(DataStorage) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + + /* + * Check if it was a store fault, if not then bail + * because a user tried to access a kernel or + * read-protected page. Otherwise, get the + * offending address and handle it. + */ + mfspr r10, SPRN_ESR + andis. r10, r10, ESR_ST@h + beq 2f + + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 0, r10, r11 + bge 2f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) +4: + FIND_PTE + + /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */ + andi. r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE + cmpwi 0, r13, _PAGE_RW|_PAGE_USER + bne 2f /* Bail if not */ + + /* Update 'changed'. */ + ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + stw r11, PTE_FLAGS_OFFSET(r12) /* Update Linux page table */ + + /* MAS2 not updated as the entry does exist in the tlb, this + fault taken to detect state transition (eg: COW -> DIRTY) + */ + andi. r11, r11, _PAGE_HWEXEC + rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ + ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ + + /* update search PID in MAS6, AS = 0 */ + mfspr r12, SPRN_PID0 + slwi r12, r12, 16 + mtspr SPRN_MAS6, r12 + + /* find the TLB index that caused the fault. It has to be here. */ + tlbsx 0, r10 + + /* only update the perm bits, assume the RPN is fine */ + mfspr r12, SPRN_MAS3 + rlwimi r12, r11, 0, 20, 31 + mtspr SPRN_MAS3,r12 + tlbwe + + /* Done...restore registers and get out of here. */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + rfi /* Force context change */ + +2: + /* + * The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b data_access + + /* Instruction Storage Interrupt */ + INSTRUCTION_STORAGE_EXCEPTION + + /* External Input Interrupt */ + EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) + + /* Alignment Interrupt */ + ALIGNMENT_EXCEPTION + + /* Program Interrupt */ + PROGRAM_EXCEPTION + + /* Floating Point Unavailable Interrupt */ +#ifdef CONFIG_PPC_FPU + FP_UNAVAILABLE_EXCEPTION +#else +#ifdef CONFIG_E200 + /* E200 treats 'normal' floating point instructions as FP Unavail exception */ + EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE) +#else + EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) +#endif +#endif + + /* System Call Interrupt */ + START_EXCEPTION(SystemCall) + NORMAL_EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0x0c00, DoSyscall) + + /* Auxillary Processor Unavailable Interrupt */ + EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + + /* Decrementer Interrupt */ + DECREMENTER_EXCEPTION + + /* Fixed Internal Timer Interrupt */ + /* TODO: Add FIT support */ + EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + + /* Watchdog Timer Interrupt */ +#ifdef CONFIG_BOOKE_WDT + CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException) +#else + CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) +#endif + + /* Data TLB Error Interrupt */ + START_EXCEPTION(DataTLBError) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 5, r10, r11 + blt 5, 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MAS1 /* Set TID to 0 */ + rlwinm r12,r12,0,16,1 + mtspr SPRN_MAS1,r12 + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + +4: + FIND_PTE + andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ + beq 2f /* Bail if not present */ + +#ifdef CONFIG_PTE_64BIT + lwz r13, 0(r12) +#endif + ori r11, r11, _PAGE_ACCESSED + stw r11, PTE_FLAGS_OFFSET(r12) + + /* Jump to common tlb load */ + b finish_tlb_load +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b data_access + + /* Instruction TLB Error Interrupt */ + /* + * Nearly the same as above, except we get our + * information from different registers and bailout + * to a different point. + */ + START_EXCEPTION(InstructionTLBError) + mtspr SPRN_SPRG0, r10 /* Save some working registers */ + mtspr SPRN_SPRG1, r11 + mtspr SPRN_SPRG4W, r12 + mtspr SPRN_SPRG5W, r13 + mfcr r11 + mtspr SPRN_SPRG7W, r11 + mfspr r10, SPRN_SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 5, r10, r11 + blt 5, 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MAS1 /* Set TID to 0 */ + rlwinm r12,r12,0,16,1 + mtspr SPRN_MAS1,r12 + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + +4: + FIND_PTE + andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ + beq 2f /* Bail if not present */ + +#ifdef CONFIG_PTE_64BIT + lwz r13, 0(r12) +#endif + ori r11, r11, _PAGE_ACCESSED + stw r11, PTE_FLAGS_OFFSET(r12) + + /* Jump to common TLB load point */ + b finish_tlb_load + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + b InstructionStorage + +#ifdef CONFIG_SPE + /* SPE Unavailable */ + START_EXCEPTION(SPEUnavailable) + NORMAL_EXCEPTION_PROLOG + bne load_up_spe + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x2010, KernelSPE) +#else + EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE) +#endif /* CONFIG_SPE */ + + /* SPE Floating Point Data */ +#ifdef CONFIG_SPE + EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE); +#else + EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE) +#endif /* CONFIG_SPE */ + + /* SPE Floating Point Round */ + EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE) + + /* Performance Monitor */ + EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD) + + + /* Debug Interrupt */ + DEBUG_EXCEPTION + +/* + * Local functions + */ + + /* + * Data TLB exceptions will bail out to this point + * if they can't resolve the lightweight TLB fault. + */ +data_access: + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r11) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + andis. r10,r5,(ESR_ILK|ESR_DLK)@h + bne 1f + EXC_XFER_EE_LITE(0x0300, handle_page_fault) +1: + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x0300, CacheLockingException) + +/* + + * Both the instruction and data TLB miss get to this + * point to load the TLB. + * r10 - EA of fault + * r11 - TLB (info from Linux PTE) + * r12, r13 - available to use + * CR5 - results of addr < TASK_SIZE + * MAS0, MAS1 - loaded with proper value when we get here + * MAS2, MAS3 - will need additional info from Linux PTE + * Upon exit, we reload everything and RFI. + */ +finish_tlb_load: + /* + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + + mfspr r12, SPRN_MAS2 +#ifdef CONFIG_PTE_64BIT + rlwimi r12, r11, 26, 24, 31 /* extract ...WIMGE from pte */ +#else + rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ +#endif + mtspr SPRN_MAS2, r12 + + bge 5, 1f + + /* is user addr */ + andi. r12, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC) + andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ + srwi r10, r12, 1 + or r12, r12, r10 /* Copy user perms into supervisor */ + iseleq r12, 0, r12 + b 2f + + /* is kernel addr */ +1: rlwinm r12, r11, 31, 29, 29 /* Extract _PAGE_HWWRITE into SW */ + ori r12, r12, (MAS3_SX | MAS3_SR) + +#ifdef CONFIG_PTE_64BIT +2: rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ + rlwimi r12, r11, 24, 8, 19 /* grab RPN[40:51] */ + mtspr SPRN_MAS3, r12 +BEGIN_FTR_SECTION + srwi r10, r13, 8 /* grab RPN[8:31] */ + mtspr SPRN_MAS7, r10 +END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS) +#else +2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ + mtspr SPRN_MAS3, r11 +#endif +#ifdef CONFIG_E200 + /* Round robin TLB1 entries assignment */ + mfspr r12, SPRN_MAS0 + + /* Extract TLB1CFG(NENTRY) */ + mfspr r11, SPRN_TLB1CFG + andi. r11, r11, 0xfff + + /* Extract MAS0(NV) */ + andi. r13, r12, 0xfff + addi r13, r13, 1 + cmpw 0, r13, r11 + addi r12, r12, 1 + + /* check if we need to wrap */ + blt 7f + + /* wrap back to first free tlbcam entry */ + lis r13, tlbcam_index@ha + lwz r13, tlbcam_index@l(r13) + rlwimi r12, r13, 0, 20, 31 +7: + mtspr SPRN_MAS0,r12 +#endif /* CONFIG_E200 */ + + tlbwe + + /* Done...restore registers and get out of here. */ + mfspr r11, SPRN_SPRG7R + mtcr r11 + mfspr r13, SPRN_SPRG5R + mfspr r12, SPRN_SPRG4R + mfspr r11, SPRN_SPRG1 + mfspr r10, SPRN_SPRG0 + rfi /* Force context change */ + +#ifdef CONFIG_SPE +/* Note that the SPE support is closely modeled after the AltiVec + * support. Changes to one are likely to be applicable to the + * other! */ +load_up_spe: +/* + * Disable SPE for the task which had SPE previously, + * and save its SPE registers in its thread_struct. + * Enables SPE for use in the kernel on return. + * On SMP we know the SPE units are free, since we give it up every + * switch. -- Kumar + */ + mfmsr r5 + oris r5,r5,MSR_SPE@h + mtmsr r5 /* enable use of SPE now */ + isync +/* + * For SMP, we don't do lazy SPE switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_spe in switch_to. + */ +#ifndef CONFIG_SMP + lis r3,last_task_used_spe@ha + lwz r4,last_task_used_spe@l(r3) + cmpi 0,r4,0 + beq 1f + addi r4,r4,THREAD /* want THREAD of last_task_used_spe */ + SAVE_32EVRS(0,r10,r4) + evxor evr10, evr10, evr10 /* clear out evr10 */ + evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */ + li r5,THREAD_ACC + evstddx evr10, r4, r5 /* save off accumulator */ + lwz r5,PT_REGS(r4) + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r10,MSR_SPE@h + andc r4,r4,r10 /* disable SPE for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of SPE after return */ + oris r9,r9,MSR_SPE@h + mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ + li r4,1 + li r10,THREAD_ACC + stw r4,THREAD_USED_SPE(r5) + evlddx evr4,r10,r5 + evmra evr4,evr4 + REST_32EVRS(0,r10,r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + stw r4,last_task_used_spe@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ +2: REST_4GPRS(3, r11) + lwz r10,_CCR(r11) + REST_GPR(1, r11) + mtcr r10 + lwz r10,_LINK(r11) + mtlr r10 + REST_GPR(10, r11) + mtspr SPRN_SRR1,r9 + mtspr SPRN_SRR0,r12 + REST_GPR(9, r11) + REST_GPR(12, r11) + lwz r11,GPR11(r11) + SYNC + rfi + +/* + * SPE unavailable trap from kernel - print a message, but let + * the task use SPE in the kernel until it returns to user mode. + */ +KernelSPE: + lwz r3,_MSR(r1) + oris r3,r3,MSR_SPE@h + stw r3,_MSR(r1) /* enable use of SPE after return */ + lis r3,87f@h + ori r3,r3,87f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +87: .string "SPE used in kernel (task=%p, pc=%x) \n" + .align 4,0 + +#endif /* CONFIG_SPE */ + +/* + * Global functions + */ + +/* + * extern void loadcam_entry(unsigned int index) + * + * Load TLBCAM[index] entry in to the L2 CAM MMU + */ +_GLOBAL(loadcam_entry) + lis r4,TLBCAM@ha + addi r4,r4,TLBCAM@l + mulli r5,r3,20 + add r3,r5,r4 + lwz r4,0(r3) + mtspr SPRN_MAS0,r4 + lwz r4,4(r3) + mtspr SPRN_MAS1,r4 + lwz r4,8(r3) + mtspr SPRN_MAS2,r4 + lwz r4,12(r3) + mtspr SPRN_MAS3,r4 + tlbwe + isync + blr + +/* + * extern void giveup_altivec(struct task_struct *prev) + * + * The e500 core does not have an AltiVec unit. + */ +_GLOBAL(giveup_altivec) + blr + +#ifdef CONFIG_SPE +/* + * extern void giveup_spe(struct task_struct *prev) + * + */ +_GLOBAL(giveup_spe) + mfmsr r5 + oris r5,r5,MSR_SPE@h + SYNC + mtmsr r5 /* enable use of SPE now */ + isync + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32EVRS(0, r4, r3) + evxor evr6, evr6, evr6 /* clear out evr6 */ + evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */ + li r4,THREAD_ACC + evstddx evr6, r4, r3 /* save off accumulator */ + mfspr r6,SPRN_SPEFSCR + stw r6,THREAD_SPEFSCR(r3) /* save spefscr register value */ + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_SPE@h + andc r4,r4,r3 /* disable SPE for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_spe@ha + stw r5,last_task_used_spe@l(r4) +#endif /* CONFIG_SMP */ + blr +#endif /* CONFIG_SPE */ + +/* + * extern void giveup_fpu(struct task_struct *prev) + * + * Not all FSL Book-E cores have an FPU + */ +#ifndef CONFIG_PPC_FPU +_GLOBAL(giveup_fpu) + blr +#endif + +/* + * extern void abort(void) + * + * At present, this routine just applies a system reset. + */ +_GLOBAL(abort) + li r13,0 + mtspr SPRN_DBCR0,r13 /* disable all debug events */ + mfmsr r13 + ori r13,r13,MSR_DE@l /* Enable Debug Events */ + mtmsr r13 + mfspr r13,SPRN_DBCR0 + lis r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h + mtspr SPRN_DBCR0,r13 + +_GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is the second parameter. + */ + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r4, 0x4(r5) +#endif + mtspr SPRN_PID,r3 + isync /* Force context change */ + blr + +/* + * We put a few things here that have to be page-aligned. This stuff + * goes at the beginning of the data segment, which is page-aligned. + */ + .data +_GLOBAL(sdata) +_GLOBAL(empty_zero_page) + .space 4096 +_GLOBAL(swapper_pg_dir) + .space 4096 + +/* Reserved 4k for the critical exception stack & 4k for the machine + * check stack per CPU for kernel mode exceptions */ + .section .bss + .align 12 +exception_stack_bottom: + .space BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS +_GLOBAL(exception_stack_top) + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* + * Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 + diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S new file mode 100644 index 000000000000..1a2194cf6828 --- /dev/null +++ b/arch/powerpc/kernel/idle_6xx.S @@ -0,0 +1,233 @@ +/* + * This file contains the power_save function for 6xx & 7xxx CPUs + * rewritten in assembler + * + * Warning ! This code assumes that if your machine has a 750fx + * it will have PLL 1 set to low speed mode (used during NAP/DOZE). + * if this is not the case some additional changes will have to + * be done to check a runtime var (a bit like powersave-nap) + * + * 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 + +#undef DEBUG + + .text + +/* + * Init idle, called at early CPU setup time from head.S for each CPU + * Make sure no rest of NAP mode remains in HID0, save default + * values for some CPU specific registers. Called with r24 + * containing CPU number and r3 reloc offset + */ +_GLOBAL(init_idle_6xx) +BEGIN_FTR_SECTION + mfspr r4,SPRN_HID0 + rlwinm r4,r4,0,10,8 /* Clear NAP */ + mtspr SPRN_HID0, r4 + b 1f +END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) + blr +1: + slwi r5,r24,2 + add r5,r5,r3 +BEGIN_FTR_SECTION + mfspr r4,SPRN_MSSCR0 + addis r6,r5, nap_save_msscr0@ha + stw r4,nap_save_msscr0@l(r6) +END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) +BEGIN_FTR_SECTION + mfspr r4,SPRN_HID1 + addis r6,r5,nap_save_hid1@ha + stw r4,nap_save_hid1@l(r6) +END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) + blr + +/* + * Here is the power_save_6xx function. This could eventually be + * split into several functions & changing the function pointer + * depending on the various features. + */ +_GLOBAL(ppc6xx_idle) + /* Check if we can nap or doze, put HID0 mask in r3 + */ + lis r3, 0 +BEGIN_FTR_SECTION + lis r3,HID0_DOZE@h +END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) +BEGIN_FTR_SECTION + /* We must dynamically check for the NAP feature as it + * can be cleared by CPU init after the fixups are done + */ + lis r4,cur_cpu_spec@ha + lwz r4,cur_cpu_spec@l(r4) + lwz r4,CPU_SPEC_FEATURES(r4) + andi. r0,r4,CPU_FTR_CAN_NAP + beq 1f + /* Now check if user or arch enabled NAP mode */ + lis r4,powersave_nap@ha + lwz r4,powersave_nap@l(r4) + cmpwi 0,r4,0 + beq 1f + lis r3,HID0_NAP@h +1: +END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) + cmpwi 0,r3,0 + beqlr + + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* Check current_thread_info()->flags */ + rlwinm r4,r1,0,0,18 + lwz r4,TI_FLAGS(r4) + andi. r0,r4,_TIF_NEED_RESCHED + beq 1f + mtmsr r7 /* out of line this ? */ + blr +1: + /* Some pre-nap cleanups needed on some CPUs */ + andis. r0,r3,HID0_NAP@h + beq 2f +BEGIN_FTR_SECTION + /* Disable L2 prefetch on some 745x and try to ensure + * L2 prefetch engines are idle. As explained by errata + * text, we can't be sure they are, we just hope very hard + * that well be enough (sic !). At least I noticed Apple + * doesn't even bother doing the dcbf's here... + */ + mfspr r4,SPRN_MSSCR0 + rlwinm r4,r4,0,0,29 + sync + mtspr SPRN_MSSCR0,r4 + sync + isync + lis r4,KERNELBASE@h + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 +END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) +#ifdef DEBUG + lis r6,nap_enter_count@ha + lwz r4,nap_enter_count@l(r6) + addi r4,r4,1 + stw r4,nap_enter_count@l(r6) +#endif +2: +BEGIN_FTR_SECTION + /* Go to low speed mode on some 750FX */ + lis r4,powersave_lowspeed@ha + lwz r4,powersave_lowspeed@l(r4) + cmpwi 0,r4,0 + beq 1f + mfspr r4,SPRN_HID1 + oris r4,r4,0x0001 + mtspr SPRN_HID1,r4 +1: +END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) + + /* Go to NAP or DOZE now */ + mfspr r4,SPRN_HID0 + lis r5,(HID0_NAP|HID0_SLEEP)@h +BEGIN_FTR_SECTION + oris r5,r5,HID0_DOZE@h +END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) + andc r4,r4,r5 + or r4,r4,r3 +BEGIN_FTR_SECTION + oris r4,r4,HID0_DPM@h /* that should be done once for all */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) + mtspr SPRN_HID0,r4 +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + ori r7,r7,MSR_EE /* Could be ommited (already set) */ + oris r7,r7,MSR_POW@h + sync + isync + mtmsr r7 + isync + sync + blr + +/* + * Return from NAP/DOZE mode, restore some CPU specific registers, + * we are called with DR/IR still off and r2 containing physical + * address of current. + */ +_GLOBAL(power_save_6xx_restore) + mfspr r11,SPRN_HID0 + rlwinm. r11,r11,0,10,8 /* Clear NAP & copy NAP bit !state to cr1 EQ */ + cror 4*cr1+eq,4*cr0+eq,4*cr0+eq +BEGIN_FTR_SECTION + rlwinm r11,r11,0,9,7 /* Clear DOZE */ +END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) + mtspr SPRN_HID0, r11 + +#ifdef DEBUG + beq cr1,1f + lis r11,(nap_return_count-KERNELBASE)@ha + lwz r9,nap_return_count@l(r11) + addi r9,r9,1 + stw r9,nap_return_count@l(r11) +1: +#endif + + rlwinm r9,r1,0,0,18 + tophys(r9,r9) + lwz r11,TI_CPU(r9) + slwi r11,r11,2 + /* Todo make sure all these are in the same page + * and load r22 (@ha part + CPU offset) only once + */ +BEGIN_FTR_SECTION + beq cr1,1f + addis r9,r11,(nap_save_msscr0-KERNELBASE)@ha + lwz r9,nap_save_msscr0@l(r9) + mtspr SPRN_MSSCR0, r9 + sync + isync +1: +END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) +BEGIN_FTR_SECTION + addis r9,r11,(nap_save_hid1-KERNELBASE)@ha + lwz r9,nap_save_hid1@l(r9) + mtspr SPRN_HID1, r9 +END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) + b transfer_to_handler_cont + + .data + +_GLOBAL(nap_save_msscr0) + .space 4*NR_CPUS + +_GLOBAL(nap_save_hid1) + .space 4*NR_CPUS + +_GLOBAL(powersave_nap) + .long 0 +_GLOBAL(powersave_lowspeed) + .long 0 + +#ifdef DEBUG +_GLOBAL(nap_enter_count) + .space 4 +_GLOBAL(nap_return_count) + .space 4 +#endif diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c new file mode 100644 index 000000000000..f5a9d2a84fa1 --- /dev/null +++ b/arch/powerpc/kernel/process.c @@ -0,0 +1,724 @@ +/* + * arch/ppc/kernel/process.c + * + * Derived from "arch/i386/kernel/process.c" + * Copyright (C) 1995 Linus Torvalds + * + * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and + * Paul Mackerras (paulus@cs.anu.edu.au) + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * 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 + +extern unsigned long _get_SP(void); + +#ifndef CONFIG_SMP +struct task_struct *last_task_used_math = NULL; +struct task_struct *last_task_used_altivec = NULL; +struct task_struct *last_task_used_spe = NULL; +#endif + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); +EXPORT_SYMBOL(init_mm); + +/* this is 8kB-aligned so we can get to the thread_info struct + at the base of it from the stack pointer with 1 integer instruction. */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = +{ INIT_THREAD_INFO(init_task) }; + +/* initial task structure */ +struct task_struct init_task = INIT_TASK(init_task); +EXPORT_SYMBOL(init_task); + +/* only used to get secondary processor up */ +struct task_struct *current_set[NR_CPUS] = {&init_task, }; + +/* + * Make sure the floating-point register state in the + * the thread_struct is up to date for task tsk. + */ +void flush_fp_to_thread(struct task_struct *tsk) +{ + if (tsk->thread.regs) { + /* + * We need to disable preemption here because if we didn't, + * another process could get scheduled after the regs->msr + * test but before we have finished saving the FP registers + * to the thread_struct. That process could take over the + * FPU, and then when we get scheduled again we would store + * bogus values for the remaining FP registers. + */ + preempt_disable(); + if (tsk->thread.regs->msr & MSR_FP) { +#ifdef CONFIG_SMP + /* + * This should only ever be called for current or + * for a stopped child process. Since we save away + * the FP register state on context switch on SMP, + * there is something wrong if a stopped child appears + * to still have its FP state in the CPU registers. + */ + BUG_ON(tsk != current); +#endif + giveup_fpu(current); + } + preempt_enable(); + } +} + +void enable_kernel_fp(void) +{ + WARN_ON(preemptible()); + +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) + giveup_fpu(current); + else + giveup_fpu(NULL); /* just enables FP for kernel */ +#else + giveup_fpu(last_task_used_math); +#endif /* CONFIG_SMP */ +} +EXPORT_SYMBOL(enable_kernel_fp); + +int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + if (!tsk->thread.regs) + return 0; + flush_fp_to_thread(current); + + memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); + + return 1; +} + +#ifdef CONFIG_ALTIVEC +void enable_kernel_altivec(void) +{ + WARN_ON(preemptible()); + +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) + giveup_altivec(current); + else + giveup_altivec(NULL); /* just enable AltiVec for kernel - force */ +#else + giveup_altivec(last_task_used_altivec); +#endif /* CONFIG_SMP */ +} +EXPORT_SYMBOL(enable_kernel_altivec); + +/* + * Make sure the VMX/Altivec register state in the + * the thread_struct is up to date for task tsk. + */ +void flush_altivec_to_thread(struct task_struct *tsk) +{ + if (tsk->thread.regs) { + preempt_disable(); + if (tsk->thread.regs->msr & MSR_VEC) { +#ifdef CONFIG_SMP + BUG_ON(tsk != current); +#endif + giveup_altivec(current); + } + preempt_enable(); + } +} + +int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) +{ + flush_altivec_to_thread(current); + memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); + return 1; +} +#endif /* CONFIG_ALTIVEC */ + +#ifdef CONFIG_SPE + +void enable_kernel_spe(void) +{ + WARN_ON(preemptible()); + +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_SPE)) + giveup_spe(current); + else + giveup_spe(NULL); /* just enable SPE for kernel - force */ +#else + giveup_spe(last_task_used_spe); +#endif /* __SMP __ */ +} +EXPORT_SYMBOL(enable_kernel_spe); + +void flush_spe_to_thread(struct task_struct *tsk) +{ + if (tsk->thread.regs) { + preempt_disable(); + if (tsk->thread.regs->msr & MSR_SPE) { +#ifdef CONFIG_SMP + BUG_ON(tsk != current); +#endif + giveup_spe(current); + } + preempt_enable(); + } +} + +int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) +{ + flush_spe_to_thread(current); + /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ + memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); + return 1; +} +#endif /* CONFIG_SPE */ + +static void set_dabr_spr(unsigned long val) +{ + mtspr(SPRN_DABR, val); +} + +int set_dabr(unsigned long dabr) +{ + int ret = 0; + +#ifdef CONFIG_PPC64 + if (firmware_has_feature(FW_FEATURE_XDABR)) { + /* We want to catch accesses from kernel and userspace */ + unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; + ret = plpar_set_xdabr(dabr, flags); + } else if (firmware_has_feature(FW_FEATURE_DABR)) { + ret = plpar_set_dabr(dabr); + } else +#endif + set_dabr_spr(dabr); + + return ret; +} + +static DEFINE_PER_CPU(unsigned long, current_dabr); + +struct task_struct *__switch_to(struct task_struct *prev, + struct task_struct *new) +{ + struct thread_struct *new_thread, *old_thread; + unsigned long flags; + struct task_struct *last; + +#ifdef CONFIG_SMP + /* avoid complexity of lazy save/restore of fpu + * by just saving it every time we switch out if + * this task used the fpu during the last quantum. + * + * If it tries to use the fpu again, it'll trap and + * reload its fp regs. So we don't have to do a restore + * every switch, just a save. + * -- Cort + */ + if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) + giveup_fpu(prev); +#ifdef CONFIG_ALTIVEC + /* + * If the previous thread used altivec in the last quantum + * (thus changing altivec regs) then save them. + * We used to check the VRSAVE register but not all apps + * set it, so we don't rely on it now (and in fact we need + * to save & restore VSCR even if VRSAVE == 0). -- paulus + * + * On SMP we always save/restore altivec regs just to avoid the + * complexity of changing processors. + * -- Cort + */ + if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) + giveup_altivec(prev); + /* Avoid the trap. On smp this this never happens since + * we don't set last_task_used_altivec -- Cort + */ + if (new->thread.regs && last_task_used_altivec == new) + new->thread.regs->msr |= MSR_VEC; +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + /* + * If the previous thread used spe in the last quantum + * (thus changing spe regs) then save them. + * + * On SMP we always save/restore spe regs just to avoid the + * complexity of changing processors. + */ + if ((prev->thread.regs && (prev->thread.regs->msr & MSR_SPE))) + giveup_spe(prev); + /* Avoid the trap. On smp this this never happens since + * we don't set last_task_used_spe + */ + if (new->thread.regs && last_task_used_spe == new) + new->thread.regs->msr |= MSR_SPE; +#endif /* CONFIG_SPE */ +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_PPC64 /* for now */ + if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { + set_dabr(new->thread.dabr); + __get_cpu_var(current_dabr) = new->thread.dabr; + } +#endif + + new_thread = &new->thread; + old_thread = ¤t->thread; + local_irq_save(flags); + last = _switch(old_thread, new_thread); + + local_irq_restore(flags); + + return last; +} + +void show_regs(struct pt_regs * regs) +{ + int i, trap; + + printk("NIP: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx %s\n", + regs->nip, regs->link, regs->gpr[1], regs, regs->trap, + print_tainted()); + printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + trap = TRAP(regs); + if (trap == 0x300 || trap == 0x600) + printk("DAR: %08lX, DSISR: %08lX\n", regs->dar, regs->dsisr); + printk("TASK = %p[%d] '%s' THREAD: %p\n", + current, current->pid, current->comm, current->thread_info); + printk("Last syscall: %ld ", current->thread.last_syscall); + +#ifdef CONFIG_SMP + printk(" CPU: %d", smp_processor_id()); +#endif /* CONFIG_SMP */ + + for (i = 0; i < 32; i++) { + long r; + if ((i % 8) == 0) + printk("\n" KERN_INFO "GPR%02d: ", i); + if (__get_user(r, ®s->gpr[i])) + break; + printk("%08lX ", r); + if (i == 12 && !FULL_REGS(regs)) + break; + } + printk("\n"); +#ifdef CONFIG_KALLSYMS + /* + * Lookup NIP late so we have the best change of getting the + * above info out without failing + */ + printk("NIP [%08lx] ", regs->nip); + print_symbol("%s\n", regs->nip); + printk("LR [%08lx] ", regs->link); + print_symbol("%s\n", regs->link); +#endif + show_stack(current, (unsigned long *) regs->gpr[1]); +} + +void exit_thread(void) +{ +#ifndef CONFIG_SMP + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef CONFIG_ALTIVEC + if (last_task_used_altivec == current) + last_task_used_altivec = NULL; +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + if (last_task_used_spe == current) + last_task_used_spe = NULL; +#endif +#endif /* CONFIG_SMP */ +} + +void flush_thread(void) +{ +#ifndef CONFIG_SMP + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef CONFIG_ALTIVEC + if (last_task_used_altivec == current) + last_task_used_altivec = NULL; +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + if (last_task_used_spe == current) + last_task_used_spe = NULL; +#endif +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_PPC64 /* for now */ + if (current->thread.dabr) { + current->thread.dabr = 0; + set_dabr(0); + } +#endif +} + +void +release_thread(struct task_struct *t) +{ +} + +/* + * This gets called before we allocate a new thread and copy + * the current task into it. + */ +void prepare_to_copy(struct task_struct *tsk) +{ + flush_fp_to_thread(current); + flush_altivec_to_thread(current); + flush_spe_to_thread(current); +} + +/* + * Copy a thread.. + */ +int +copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs, *kregs; + extern void ret_from_fork(void); + unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE; + unsigned long childframe; + + CHECK_FULL_REGS(regs); + /* Copy registers */ + sp -= sizeof(struct pt_regs); + childregs = (struct pt_regs *) sp; + *childregs = *regs; + if ((childregs->msr & MSR_PR) == 0) { + /* for kernel thread, set `current' and stackptr in new task */ + childregs->gpr[1] = sp + sizeof(struct pt_regs); + childregs->gpr[2] = (unsigned long) p; + p->thread.regs = NULL; /* no user register state */ + } else { + childregs->gpr[1] = usp; + p->thread.regs = childregs; + if (clone_flags & CLONE_SETTLS) + childregs->gpr[2] = childregs->gpr[6]; + } + childregs->gpr[3] = 0; /* Result from fork() */ + sp -= STACK_FRAME_OVERHEAD; + childframe = sp; + + /* + * The way this works is that at some point in the future + * some task will call _switch to switch to the new task. + * That will pop off the stack frame created below and start + * the new task running at ret_from_fork. The new task will + * do some house keeping and then return from the fork or clone + * system call, using the stack frame created above. + */ + sp -= sizeof(struct pt_regs); + kregs = (struct pt_regs *) sp; + sp -= STACK_FRAME_OVERHEAD; + p->thread.ksp = sp; + kregs->nip = (unsigned long)ret_from_fork; + + p->thread.last_syscall = -1; + + return 0; +} + +/* + * Set up a thread for executing a new program + */ +void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) +{ + set_fs(USER_DS); + memset(regs->gpr, 0, sizeof(regs->gpr)); + regs->ctr = 0; + regs->link = 0; + regs->xer = 0; + regs->ccr = 0; + regs->mq = 0; + regs->nip = nip; + regs->gpr[1] = sp; + regs->msr = MSR_USER; +#ifndef CONFIG_SMP + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef CONFIG_ALTIVEC + if (last_task_used_altivec == current) + last_task_used_altivec = NULL; +#endif +#ifdef CONFIG_SPE + if (last_task_used_spe == current) + last_task_used_spe = NULL; +#endif +#endif /* CONFIG_SMP */ + memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); + current->thread.fpscr = 0; +#ifdef CONFIG_ALTIVEC + memset(current->thread.vr, 0, sizeof(current->thread.vr)); + memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); + current->thread.vrsave = 0; + current->thread.used_vr = 0; +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + memset(current->thread.evr, 0, sizeof(current->thread.evr)); + current->thread.acc = 0; + current->thread.spefscr = 0; + current->thread.used_spe = 0; +#endif /* CONFIG_SPE */ +} + +#define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \ + | PR_FP_EXC_RES | PR_FP_EXC_INV) + +int set_fpexc_mode(struct task_struct *tsk, unsigned int val) +{ + struct pt_regs *regs = tsk->thread.regs; + + /* This is a bit hairy. If we are an SPE enabled processor + * (have embedded fp) we store the IEEE exception enable flags in + * fpexc_mode. fpexc_mode is also used for setting FP exception + * mode (asyn, precise, disabled) for 'Classic' FP. */ + if (val & PR_FP_EXC_SW_ENABLE) { +#ifdef CONFIG_SPE + tsk->thread.fpexc_mode = val & + (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); +#else + return -EINVAL; +#endif + } else { + /* on a CONFIG_SPE this does not hurt us. The bits that + * __pack_fe01 use do not overlap with bits used for + * PR_FP_EXC_SW_ENABLE. Additionally, the MSR[FE0,FE1] bits + * on CONFIG_SPE implementations are reserved so writing to + * them does not change anything */ + if (val > PR_FP_EXC_PRECISE) + return -EINVAL; + tsk->thread.fpexc_mode = __pack_fe01(val); + if (regs != NULL && (regs->msr & MSR_FP) != 0) + regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) + | tsk->thread.fpexc_mode; + } + return 0; +} + +int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) +{ + unsigned int val; + + if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) +#ifdef CONFIG_SPE + val = tsk->thread.fpexc_mode; +#else + return -EINVAL; +#endif + else + val = __unpack_fe01(tsk->thread.fpexc_mode); + return put_user(val, (unsigned int __user *) adr); +} + +int sys_clone(unsigned long clone_flags, unsigned long usp, + int __user *parent_tidp, void __user *child_threadptr, + int __user *child_tidp, int p6, + struct pt_regs *regs) +{ + CHECK_FULL_REGS(regs); + if (usp == 0) + usp = regs->gpr[1]; /* stack pointer for child */ + return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); +} + +int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, + struct pt_regs *regs) +{ + CHECK_FULL_REGS(regs); + return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); +} + +int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, + struct pt_regs *regs) +{ + CHECK_FULL_REGS(regs); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], + regs, 0, NULL, NULL); +} + +int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs *regs) +{ + int error; + char * filename; + + filename = getname((char __user *) a0); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + flush_fp_to_thread(current); + flush_altivec_to_thread(current); + flush_spe_to_thread(current); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } + putname(filename); +out: + return error; +} + +static int validate_sp(unsigned long sp, struct task_struct *p, + unsigned long nbytes) +{ + unsigned long stack_page = (unsigned long)p->thread_info; + + if (sp >= stack_page + sizeof(struct thread_struct) + && sp <= stack_page + THREAD_SIZE - nbytes) + return 1; + +#ifdef CONFIG_IRQSTACKS + stack_page = (unsigned long) hardirq_ctx[task_cpu(p)]; + if (sp >= stack_page + sizeof(struct thread_struct) + && sp <= stack_page + THREAD_SIZE - nbytes) + return 1; + + stack_page = (unsigned long) softirq_ctx[task_cpu(p)]; + if (sp >= stack_page + sizeof(struct thread_struct) + && sp <= stack_page + THREAD_SIZE - nbytes) + return 1; +#endif + + return 0; +} + +void dump_stack(void) +{ + show_stack(current, NULL); +} + +EXPORT_SYMBOL(dump_stack); + +void show_stack(struct task_struct *tsk, unsigned long *stack) +{ + unsigned long sp, stack_top, prev_sp, ret; + int count = 0; + unsigned long next_exc = 0; + struct pt_regs *regs; + extern char ret_from_except, ret_from_except_full, ret_from_syscall; + + sp = (unsigned long) stack; + if (tsk == NULL) + tsk = current; + if (sp == 0) { + if (tsk == current) + asm("mr %0,1" : "=r" (sp)); + else + sp = tsk->thread.ksp; + } + + prev_sp = (unsigned long) (tsk->thread_info + 1); + stack_top = (unsigned long) tsk->thread_info + THREAD_SIZE; + while (count < 16 && sp > prev_sp && sp < stack_top && (sp & 3) == 0) { + if (count == 0) { + printk("Call trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + } else { + if (next_exc) { + ret = next_exc; + next_exc = 0; + } else + ret = *(unsigned long *)(sp + 4); + printk(" [%08lx] ", ret); +#ifdef CONFIG_KALLSYMS + print_symbol("%s", ret); + printk("\n"); +#endif + if (ret == (unsigned long) &ret_from_except + || ret == (unsigned long) &ret_from_except_full + || ret == (unsigned long) &ret_from_syscall) { + /* sp + 16 points to an exception frame */ + regs = (struct pt_regs *) (sp + 16); + if (sp + 16 + sizeof(*regs) <= stack_top) + next_exc = regs->nip; + } + } + ++count; + sp = *(unsigned long *)sp; + } +#ifndef CONFIG_KALLSYMS + if (count > 0) + printk("\n"); +#endif +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ip, sp; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + sp = p->thread.ksp; + if (!validate_sp(sp, p, 16)) + return 0; + + do { + sp = *(unsigned long *)sp; + if (!validate_sp(sp, p, 16)) + return 0; + if (count > 0) { + ip = *(unsigned long *)(sp + 4); + if (!in_sched_functions(ip)) + return ip; + } + } while (count++ < 16); + return 0; +} +EXPORT_SYMBOL(get_wchan); diff --git a/arch/powerpc/kernel/semaphore.c b/arch/powerpc/kernel/semaphore.c new file mode 100644 index 000000000000..2f8c3c951394 --- /dev/null +++ b/arch/powerpc/kernel/semaphore.c @@ -0,0 +1,135 @@ +/* + * PowerPC-specific semaphore code. + * + * Copyright (C) 1999 Cort Dougan + * + * 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. + * + * April 2001 - Reworked by Paul Mackerras + * to eliminate the SMP races in the old version between the updates + * of `count' and `waking'. Now we use negative `count' values to + * indicate that some process(es) are waiting for the semaphore. + */ + +#include +#include +#include + +#include +#include +#include + +/* + * Atomically update sem->count. + * This does the equivalent of the following: + * + * old_count = sem->count; + * tmp = MAX(old_count, 0) + incr; + * sem->count = tmp; + * return old_count; + */ +static inline int __sem_update_count(struct semaphore *sem, int incr) +{ + int old_count, tmp; + + __asm__ __volatile__("\n" +"1: lwarx %0,0,%3\n" +" srawi %1,%0,31\n" +" andc %1,%0,%1\n" +" add %1,%1,%4\n" + PPC405_ERR77(0,%3) +" stwcx. %1,0,%3\n" +" bne 1b" + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (&sem->count), "r" (incr), "m" (sem->count) + : "cc"); + + return old_count; +} + +void __up(struct semaphore *sem) +{ + /* + * Note that we incremented count in up() before we came here, + * but that was ineffective since the result was <= 0, and + * any negative value of count is equivalent to 0. + * This ends up setting count to 1, unless count is now > 0 + * (i.e. because some other cpu has called up() in the meantime), + * in which case we just increment count. + */ + __sem_update_count(sem, 1); + wake_up(&sem->wait); +} +EXPORT_SYMBOL(__up); + +/* + * Note that when we come in to __down or __down_interruptible, + * we have already decremented count, but that decrement was + * ineffective since the result was < 0, and any negative value + * of count is equivalent to 0. + * Thus it is only when we decrement count from some value > 0 + * that we have actually got the semaphore. + */ +void __sched __down(struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __set_task_state(tsk, TASK_UNINTERRUPTIBLE); + add_wait_queue_exclusive(&sem->wait, &wait); + + /* + * Try to get the semaphore. If the count is > 0, then we've + * got the semaphore; we decrement count and exit the loop. + * If the count is 0 or negative, we set it to -1, indicating + * that we are asleep, and then sleep. + */ + while (__sem_update_count(sem, -1) <= 0) { + schedule(); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + } + remove_wait_queue(&sem->wait, &wait); + __set_task_state(tsk, TASK_RUNNING); + + /* + * If there are any more sleepers, wake one of them up so + * that it can either get the semaphore, or set count to -1 + * indicating that there are still processes sleeping. + */ + wake_up(&sem->wait); +} +EXPORT_SYMBOL(__down); + +int __sched __down_interruptible(struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __set_task_state(tsk, TASK_INTERRUPTIBLE); + add_wait_queue_exclusive(&sem->wait, &wait); + + while (__sem_update_count(sem, -1) <= 0) { + if (signal_pending(current)) { + /* + * A signal is pending - give up trying. + * Set sem->count to 0 if it is negative, + * since we are no longer sleeping. + */ + __sem_update_count(sem, 0); + retval = -EINTR; + break; + } + schedule(); + set_task_state(tsk, TASK_INTERRUPTIBLE); + } + remove_wait_queue(&sem->wait, &wait); + __set_task_state(tsk, TASK_RUNNING); + + wake_up(&sem->wait); + return retval; +} +EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c new file mode 100644 index 000000000000..c7afbbba0f36 --- /dev/null +++ b/arch/powerpc/kernel/traps.c @@ -0,0 +1,1047 @@ +/* + * arch/powerpc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * 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. + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@samba.org) + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#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 +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif +#include + +#ifdef CONFIG_DEBUGGER +int (*__debugger)(struct pt_regs *regs); +int (*__debugger_ipi)(struct pt_regs *regs); +int (*__debugger_bpt)(struct pt_regs *regs); +int (*__debugger_sstep)(struct pt_regs *regs); +int (*__debugger_iabr_match)(struct pt_regs *regs); +int (*__debugger_dabr_match)(struct pt_regs *regs); +int (*__debugger_fault_handler)(struct pt_regs *regs); + +EXPORT_SYMBOL(__debugger); +EXPORT_SYMBOL(__debugger_ipi); +EXPORT_SYMBOL(__debugger_bpt); +EXPORT_SYMBOL(__debugger_sstep); +EXPORT_SYMBOL(__debugger_iabr_match); +EXPORT_SYMBOL(__debugger_dabr_match); +EXPORT_SYMBOL(__debugger_fault_handler); +#endif + +struct notifier_block *powerpc_die_chain; +static DEFINE_SPINLOCK(die_notifier_lock); + +int register_die_notifier(struct notifier_block *nb) +{ + int err = 0; + unsigned long flags; + + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&powerpc_die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; +} + +/* + * Trap & Exception support + */ + +static DEFINE_SPINLOCK(die_lock); + +int die(const char *str, struct pt_regs *regs, long err) +{ + static int die_counter; + int nl = 0; + + if (debugger(regs)) + return 1; + + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); +#ifdef CONFIG_PMAC_BACKLIGHT + if (_machine == _MACH_Pmac) { + set_backlight_enable(1); + set_backlight_level(BACKLIGHT_MAX); + } +#endif + printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); + nl = 1; +#endif +#ifdef CONFIG_SMP + printk("SMP NR_CPUS=%d ", NR_CPUS); + nl = 1; +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC "); + nl = 1; +#endif +#ifdef CONFIG_NUMA + printk("NUMA "); + nl = 1; +#endif +#ifdef CONFIG_PPC64 + switch (systemcfg->platform) { + case PLATFORM_PSERIES: + printk("PSERIES "); + nl = 1; + break; + case PLATFORM_PSERIES_LPAR: + printk("PSERIES LPAR "); + nl = 1; + break; + case PLATFORM_ISERIES_LPAR: + printk("ISERIES LPAR "); + nl = 1; + break; + case PLATFORM_POWERMAC: + printk("POWERMAC "); + nl = 1; + break; + case PLATFORM_BPA: + printk("BPA "); + nl = 1; + break; + } +#endif + if (nl) + printk("\n"); + print_modules(); + show_regs(regs); + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + panic("Fatal exception"); + } + do_exit(err); + + return 0; +} + +void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) +{ + siginfo_t info; + + if (!user_mode(regs)) { + if (die("Exception in kernel mode", regs, signr)) + return; + } + + memset(&info, 0, sizeof(info)); + info.si_signo = signr; + info.si_code = code; + info.si_addr = (void __user *) addr; + force_sig_info(signr, &info, current); + + /* + * Init gets no signals that it doesn't have a handler for. + * That's all very well, but if it has caused a synchronous + * exception and we ignore the resulting signal, it will just + * generate the same exception over and over again and we get + * nowhere. Better to kill it and let the kernel panic. + */ + if (current->pid == 1) { + __sighandler_t handler; + + spin_lock_irq(¤t->sighand->siglock); + handler = current->sighand->action[signr-1].sa.sa_handler; + spin_unlock_irq(¤t->sighand->siglock); + if (handler == SIG_DFL) { + /* init has generated a synchronous exception + and it doesn't have a handler for the signal */ + printk(KERN_CRIT "init has generated signal %d " + "but has no handler for it\n", signr); + do_exit(signr); + } + } +} + +#ifdef CONFIG_PPC64 +void system_reset_exception(struct pt_regs *regs) +{ + /* See if any machine dependent calls */ + if (ppc_md.system_reset_exception) + ppc_md.system_reset_exception(regs); + + die("System Reset", regs, SIGABRT); + + /* Must die if the interrupt is not recoverable */ + if (!(regs->msr & MSR_RI)) + panic("Unrecoverable System Reset"); + + /* What should we do here? We could issue a shutdown or hard reset. */ +} +#endif + +/* + * I/O accesses can cause machine checks on powermacs. + * Check if the NIP corresponds to the address of a sync + * instruction for which there is an entry in the exception + * table. + * Note that the 601 only takes a machine check on TEA + * (transfer error ack) signal assertion, and does not + * set any of the top 16 bits of SRR1. + * -- paulus. + */ +static inline int check_io_access(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC_PMAC + unsigned long msr = regs->msr; + const struct exception_table_entry *entry; + unsigned int *nip = (unsigned int *)regs->nip; + + if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000))) + && (entry = search_exception_tables(regs->nip)) != NULL) { + /* + * Check that it's a sync instruction, or somewhere + * in the twi; isync; nop sequence that inb/inw/inl uses. + * As the address is in the exception table + * we should be able to read the instr there. + * For the debug message, we look at the preceding + * load or store. + */ + if (*nip == 0x60000000) /* nop */ + nip -= 2; + else if (*nip == 0x4c00012c) /* isync */ + --nip; + if (*nip == 0x7c0004ac || (*nip >> 26) == 3) { + /* sync or twi */ + unsigned int rb; + + --nip; + rb = (*nip >> 11) & 0x1f; + printk(KERN_DEBUG "%s bad port %lx at %p\n", + (*nip & 0x100)? "OUT to": "IN from", + regs->gpr[rb] - _IO_BASE, nip); + regs->msr |= MSR_RI; + regs->nip = entry->fixup; + return 1; + } + } +#endif /* CONFIG_PPC_PMAC */ + return 0; +} + +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) +/* On 4xx, the reason for the machine check or program exception + is in the ESR. */ +#define get_reason(regs) ((regs)->dsisr) +#ifndef CONFIG_FSL_BOOKE +#define get_mc_reason(regs) ((regs)->dsisr) +#else +#define get_mc_reason(regs) (mfspr(SPRN_MCSR)) +#endif +#define REASON_FP ESR_FP +#define REASON_ILLEGAL (ESR_PIL | ESR_PUO) +#define REASON_PRIVILEGED ESR_PPR +#define REASON_TRAP ESR_PTR + +/* single-step stuff */ +#define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC) +#define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC) + +#else +/* On non-4xx, the reason for the machine check or program + exception is in the MSR. */ +#define get_reason(regs) ((regs)->msr) +#define get_mc_reason(regs) ((regs)->msr) +#define REASON_FP 0x100000 +#define REASON_ILLEGAL 0x80000 +#define REASON_PRIVILEGED 0x40000 +#define REASON_TRAP 0x20000 + +#define single_stepping(regs) ((regs)->msr & MSR_SE) +#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) +#endif + +/* + * This is "fall-back" implementation for configurations + * which don't provide platform-specific machine check info + */ +void __attribute__ ((weak)) +platform_machine_check(struct pt_regs *regs) +{ +} + +void MachineCheckException(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC64 + int recover = 0; + + /* See if any machine dependent calls */ + if (ppc_md.machine_check_exception) + recover = ppc_md.machine_check_exception(regs); + + if (recover) + return; +#else + unsigned long reason = get_mc_reason(regs); + + if (user_mode(regs)) { + regs->msr |= MSR_RI; + _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); + return; + } + +#if defined(CONFIG_8xx) && defined(CONFIG_PCI) + /* the qspan pci read routines can cause machine checks -- Cort */ + bad_page_fault(regs, regs->dar, SIGBUS); + return; +#endif + + if (debugger_fault_handler(regs)) { + regs->msr |= MSR_RI; + return; + } + + if (check_io_access(regs)) + return; + +#if defined(CONFIG_4xx) && !defined(CONFIG_440A) + if (reason & ESR_IMCP) { + printk("Instruction"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + } else + printk("Data"); + printk(" machine check in kernel mode.\n"); +#elif defined(CONFIG_440A) + printk("Machine check in kernel mode.\n"); + if (reason & ESR_IMCP){ + printk("Instruction Synchronous Machine Check exception\n"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + } + else { + u32 mcsr = mfspr(SPRN_MCSR); + if (mcsr & MCSR_IB) + printk("Instruction Read PLB Error\n"); + if (mcsr & MCSR_DRB) + printk("Data Read PLB Error\n"); + if (mcsr & MCSR_DWB) + printk("Data Write PLB Error\n"); + if (mcsr & MCSR_TLBP) + printk("TLB Parity Error\n"); + if (mcsr & MCSR_ICP){ + flush_instruction_cache(); + printk("I-Cache Parity Error\n"); + } + if (mcsr & MCSR_DCSP) + printk("D-Cache Search Parity Error\n"); + if (mcsr & MCSR_DCFP) + printk("D-Cache Flush Parity Error\n"); + if (mcsr & MCSR_IMPE) + printk("Machine Check exception is imprecise\n"); + + /* Clear MCSR */ + mtspr(SPRN_MCSR, mcsr); + } +#elif defined (CONFIG_E500) + printk("Machine check in kernel mode.\n"); + printk("Caused by (from MCSR=%lx): ", reason); + + if (reason & MCSR_MCP) + printk("Machine Check Signal\n"); + if (reason & MCSR_ICPERR) + printk("Instruction Cache Parity Error\n"); + if (reason & MCSR_DCP_PERR) + printk("Data Cache Push Parity Error\n"); + if (reason & MCSR_DCPERR) + printk("Data Cache Parity Error\n"); + if (reason & MCSR_GL_CI) + printk("Guarded Load or Cache-Inhibited stwcx.\n"); + if (reason & MCSR_BUS_IAERR) + printk("Bus - Instruction Address Error\n"); + if (reason & MCSR_BUS_RAERR) + printk("Bus - Read Address Error\n"); + if (reason & MCSR_BUS_WAERR) + printk("Bus - Write Address Error\n"); + if (reason & MCSR_BUS_IBERR) + printk("Bus - Instruction Data Error\n"); + if (reason & MCSR_BUS_RBERR) + printk("Bus - Read Data Bus Error\n"); + if (reason & MCSR_BUS_WBERR) + printk("Bus - Read Data Bus Error\n"); + if (reason & MCSR_BUS_IPERR) + printk("Bus - Instruction Parity Error\n"); + if (reason & MCSR_BUS_RPERR) + printk("Bus - Read Parity Error\n"); +#elif defined (CONFIG_E200) + printk("Machine check in kernel mode.\n"); + printk("Caused by (from MCSR=%lx): ", reason); + + if (reason & MCSR_MCP) + printk("Machine Check Signal\n"); + if (reason & MCSR_CP_PERR) + printk("Cache Push Parity Error\n"); + if (reason & MCSR_CPERR) + printk("Cache Parity Error\n"); + if (reason & MCSR_EXCP_ERR) + printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n"); + if (reason & MCSR_BUS_IRERR) + printk("Bus - Read Bus Error on instruction fetch\n"); + if (reason & MCSR_BUS_DRERR) + printk("Bus - Read Bus Error on data load\n"); + if (reason & MCSR_BUS_WRERR) + printk("Bus - Write Bus Error on buffered store or cache line push\n"); +#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */ + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", reason); + switch (reason & 0x601F0000) { + case 0x80000: + printk("Machine check signal\n"); + break; + case 0: /* for 601 */ + case 0x40000: + case 0x140000: /* 7450 MSS error and TEA */ + printk("Transfer error ack signal\n"); + break; + case 0x20000: + printk("Data parity error signal\n"); + break; + case 0x10000: + printk("Address parity error signal\n"); + break; + case 0x20000000: + printk("L1 Data Cache error\n"); + break; + case 0x40000000: + printk("L1 Instruction Cache error\n"); + break; + case 0x00100000: + printk("L2 data cache parity error\n"); + break; + default: + printk("Unknown values in msr\n"); + } +#endif /* CONFIG_4xx */ + + /* + * Optional platform-provided routine to print out + * additional info, e.g. bus error registers. + */ + platform_machine_check(regs); +#endif /* CONFIG_PPC64 */ + + if (debugger_fault_handler(regs)) + return; + die("Machine check", regs, SIGBUS); + + /* Must die if the interrupt is not recoverable */ + if (!(regs->msr & MSR_RI)) + panic("Unrecoverable Machine check"); +} + +void SMIException(struct pt_regs *regs) +{ + die("System Management Interrupt", regs, SIGABRT); +} + +void UnknownException(struct pt_regs *regs) +{ + printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + + _exception(SIGTRAP, regs, 0, 0); +} + +void InstructionBreakpoint(struct pt_regs *regs) +{ + if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, + 5, SIGTRAP) == NOTIFY_STOP) + return; + if (debugger_iabr_match(regs)) + return; + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); +} + +void RunModeException(struct pt_regs *regs) +{ + _exception(SIGTRAP, regs, 0, 0); +} + +void SingleStepException(struct pt_regs *regs) +{ + regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ + + if (notify_die(DIE_SSTEP, "single_step", regs, 5, + 5, SIGTRAP) == NOTIFY_STOP) + return; + if (debugger_sstep(regs)) + return; + + _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); +} + +/* + * After we have successfully emulated an instruction, we have to + * check if the instruction was being single-stepped, and if so, + * pretend we got a single-step exception. This was pointed out + * by Kumar Gala. -- paulus + */ +static void emulate_single_step(struct pt_regs *regs) +{ + if (single_stepping(regs)) { + clear_single_step(regs); + _exception(SIGTRAP, regs, TRAP_TRACE, 0); + } +} + +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or -EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +#define INST_DCBA 0x7c0005ec +#define INST_DCBA_MASK 0x7c0007fe + +#define INST_MCRXR 0x7c000400 +#define INST_MCRXR_MASK 0x7c0007fe + +#define INST_STRING 0x7c00042a +#define INST_STRING_MASK 0x7c0007fe +#define INST_STRING_GEN_MASK 0x7c00067e +#define INST_LSWI 0x7c0004aa +#define INST_LSWX 0x7c00042a +#define INST_STSWI 0x7c0005aa +#define INST_STSWX 0x7c00052a + +static int emulate_string_inst(struct pt_regs *regs, u32 instword) +{ + u8 rT = (instword >> 21) & 0x1f; + u8 rA = (instword >> 16) & 0x1f; + u8 NB_RB = (instword >> 11) & 0x1f; + u32 num_bytes; + unsigned long EA; + int pos = 0; + + /* Early out if we are an invalid form of lswx */ + if ((instword & INST_STRING_MASK) == INST_LSWX) + if ((rT == rA) || (rT == NB_RB)) + return -EINVAL; + + EA = (rA == 0) ? 0 : regs->gpr[rA]; + + switch (instword & INST_STRING_MASK) { + case INST_LSWX: + case INST_STSWX: + EA += NB_RB; + num_bytes = regs->xer & 0x7f; + break; + case INST_LSWI: + case INST_STSWI: + num_bytes = (NB_RB == 0) ? 32 : NB_RB; + break; + default: + return -EINVAL; + } + + while (num_bytes != 0) + { + u8 val; + u32 shift = 8 * (3 - (pos & 0x3)); + + switch ((instword & INST_STRING_MASK)) { + case INST_LSWX: + case INST_LSWI: + if (get_user(val, (u8 __user *)EA)) + return -EFAULT; + /* first time updating this reg, + * zero it out */ + if (pos == 0) + regs->gpr[rT] = 0; + regs->gpr[rT] |= val << shift; + break; + case INST_STSWI: + case INST_STSWX: + val = regs->gpr[rT] >> shift; + if (put_user(val, (u8 __user *)EA)) + return -EFAULT; + break; + } + /* move EA to next address */ + EA += 1; + num_bytes--; + + /* manage our position within the register */ + if (++pos == 4) { + pos = 0; + if (++rT == 32) + rT = 0; + } + } + + return 0; +} + +static int emulate_instruction(struct pt_regs *regs) +{ + u32 instword; + u32 rd; + + if (!user_mode(regs)) + return -EINVAL; + CHECK_FULL_REGS(regs); + + if (get_user(instword, (u32 __user *)(regs->nip))) + return -EFAULT; + + /* Emulate the mfspr rD, PVR. */ + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = mfspr(SPRN_PVR); + return 0; + } + + /* Emulating the dcba insn is just a no-op. */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) + return 0; + + /* Emulate the mcrxr insn. */ + if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { + int shift = (instword >> 21) & 0x1c; + unsigned long msk = 0xf0000000UL >> shift; + + regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); + regs->xer &= ~0xf0000000UL; + return 0; + } + + /* Emulate load/store string insn. */ + if ((instword & INST_STRING_GEN_MASK) == INST_STRING) + return emulate_string_inst(regs, instword); + + return -EINVAL; +} + +/* + * Look through the list of trap instructions that are used for BUG(), + * BUG_ON() and WARN_ON() and see if we hit one. At this point we know + * that the exception was caused by a trap instruction of some kind. + * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 + * otherwise. + */ +extern struct bug_entry __start___bug_table[], __stop___bug_table[]; + +#ifndef CONFIG_MODULES +#define module_find_bug(x) NULL +#endif + +struct bug_entry *find_bug(unsigned long bugaddr) +{ + struct bug_entry *bug; + + for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) + if (bugaddr == bug->bug_addr) + return bug; + return module_find_bug(bugaddr); +} + +int check_bug_trap(struct pt_regs *regs) +{ + struct bug_entry *bug; + unsigned long addr; + + if (regs->msr & MSR_PR) + return 0; /* not in kernel */ + addr = regs->nip; /* address of trap instruction */ + if (addr < PAGE_OFFSET) + return 0; + bug = find_bug(regs->nip); + if (bug == NULL) + return 0; + if (bug->line & BUG_WARNING_TRAP) { + /* this is a WARN_ON rather than BUG/BUG_ON */ +#ifdef CONFIG_XMON + xmon_printf(KERN_ERR "Badness in %s at %s:%d\n", + bug->function, bug->file, + bug->line & ~BUG_WARNING_TRAP); +#endif /* CONFIG_XMON */ + printk(KERN_ERR "Badness in %s at %s:%d\n", + bug->function, bug->file, + bug->line & ~BUG_WARNING_TRAP); + dump_stack(); + return 1; + } +#ifdef CONFIG_XMON + xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n", + bug->function, bug->file, bug->line); + xmon(regs); +#endif /* CONFIG_XMON */ + printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", + bug->function, bug->file, bug->line); + + return 0; +} + +void ProgramCheckException(struct pt_regs *regs) +{ + unsigned int reason = get_reason(regs); + extern int do_mathemu(struct pt_regs *regs); + +#ifdef CONFIG_MATH_EMULATION + /* (reason & REASON_ILLEGAL) would be the obvious thing here, + * but there seems to be a hardware bug on the 405GP (RevD) + * that means ESR is sometimes set incorrectly - either to + * ESR_DST (!?) or 0. In the process of chasing this with the + * hardware people - not sure if it can happen on any illegal + * instruction or only on FP instructions, whether there is a + * pattern to occurences etc. -dgibson 31/Mar/2003 */ + if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) { + emulate_single_step(regs); + return; + } +#endif /* CONFIG_MATH_EMULATION */ + + if (reason & REASON_FP) { + /* IEEE FP exception */ + int code = 0; + u32 fpscr; + + /* We must make sure the FP state is consistent with + * our MSR_FP in regs + */ + preempt_disable(); + if (regs->msr & MSR_FP) + giveup_fpu(current); + preempt_enable(); + + fpscr = current->thread.fpscr; + fpscr &= fpscr << 22; /* mask summary bits with enables */ + if (fpscr & FPSCR_VX) + code = FPE_FLTINV; + else if (fpscr & FPSCR_OX) + code = FPE_FLTOVF; + else if (fpscr & FPSCR_UX) + code = FPE_FLTUND; + else if (fpscr & FPSCR_ZX) + code = FPE_FLTDIV; + else if (fpscr & FPSCR_XX) + code = FPE_FLTRES; + _exception(SIGFPE, regs, code, regs->nip); + return; + } + + if (reason & REASON_TRAP) { + /* trap exception */ + if (debugger_bpt(regs)) + return; + if (check_bug_trap(regs)) { + regs->nip += 4; + return; + } + _exception(SIGTRAP, regs, TRAP_BRKPT, 0); + return; + } + + /* Try to emulate it if we should. */ + if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { + switch (emulate_instruction(regs)) { + case 0: + regs->nip += 4; + emulate_single_step(regs); + return; + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; + } + } + + if (reason & REASON_PRIVILEGED) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); +} + +void AlignmentException(struct pt_regs *regs) +{ + int fixed; + + fixed = fix_alignment(regs); + + if (fixed == 1) { + regs->nip += 4; /* skip over emulated instruction */ + emulate_single_step(regs); + return; + } + + /* Operand address was bad */ + if (fixed == -EFAULT) { + if (user_mode(regs)) + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); + else + /* Search exception table */ + bad_page_fault(regs, regs->dar, SIGSEGV); + return; + } + _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); +} + +void StackOverflow(struct pt_regs *regs) +{ + printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", + current, regs->gpr[1]); + debugger(regs); + show_regs(regs); + panic("kernel stack overflow"); +} + +void nonrecoverable_exception(struct pt_regs *regs) +{ + printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n", + regs->nip, regs->msr); + debugger(regs); + die("nonrecoverable exception", regs, SIGKILL); +} + +void trace_syscall(struct pt_regs *regs) +{ + printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", + current, current->pid, regs->nip, regs->link, regs->gpr[0], + regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); +} + +#ifdef CONFIG_8xx +void SoftwareEmulation(struct pt_regs *regs) +{ + extern int do_mathemu(struct pt_regs *); + extern int Soft_emulate_8xx(struct pt_regs *); + int errcode; + + CHECK_FULL_REGS(regs); + + if (!user_mode(regs)) { + debugger(regs); + die("Kernel Mode Software FPU Emulation", regs, SIGFPE); + } + +#ifdef CONFIG_MATH_EMULATION + errcode = do_mathemu(regs); +#else + errcode = Soft_emulate_8xx(regs); +#endif + if (errcode) { + if (errcode > 0) + _exception(SIGFPE, regs, 0, 0); + else if (errcode == -EFAULT) + _exception(SIGSEGV, regs, 0, 0); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + } else + emulate_single_step(regs); +} +#endif /* CONFIG_8xx */ + +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + +void DebugException(struct pt_regs *regs, unsigned long debug_status) +{ + if (debug_status & DBSR_IC) { /* instruction completion */ + regs->msr &= ~MSR_DE; + if (user_mode(regs)) { + current->thread.dbcr0 &= ~DBCR0_IC; + } else { + /* Disable instruction completion */ + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC); + /* Clear the instruction completion event */ + mtspr(SPRN_DBSR, DBSR_IC); + if (debugger_sstep(regs)) + return; + } + _exception(SIGTRAP, regs, TRAP_TRACE, 0); + } +} +#endif /* CONFIG_4xx || CONFIG_BOOKE */ + +#if !defined(CONFIG_TAU_INT) +void TAUException(struct pt_regs *regs) +{ + printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx %s\n", + regs->nip, regs->msr, regs->trap, print_tainted()); +} +#endif /* CONFIG_INT_TAU */ + +void AltivecUnavailException(struct pt_regs *regs) +{ + static int kernel_altivec_count; + +#ifndef CONFIG_ALTIVEC + if (user_mode(regs)) { + /* A user program has executed an altivec instruction, + but this kernel doesn't support altivec. */ + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + return; + } +#endif + /* The kernel has executed an altivec instruction without + first enabling altivec. Whinge but let it do it. */ + if (++kernel_altivec_count < 10) + printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", + current, regs->nip); + regs->msr |= MSR_VEC; +} + +#ifdef CONFIG_ALTIVEC +void AltivecAssistException(struct pt_regs *regs) +{ + int err; + + preempt_disable(); + if (regs->msr & MSR_VEC) + giveup_altivec(current); + preempt_enable(); + if (!user_mode(regs)) { + printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" + " at %lx\n", regs->nip); + die("Kernel Altivec assist exception", regs, SIGILL); + } + + err = emulate_altivec(regs); + if (err == 0) { + regs->nip += 4; /* skip emulated instruction */ + emulate_single_step(regs); + return; + } + + if (err == -EFAULT) { + /* got an error reading the instruction */ + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); + } else { + /* didn't recognize the instruction */ + /* XXX quick hack for now: set the non-Java bit in the VSCR */ + if (printk_ratelimit()) + printk(KERN_ERR "Unrecognized altivec instruction " + "in %s at %lx\n", current->comm, regs->nip); + current->thread.vscr.u[3] |= 0x10000; + } +} +#endif /* CONFIG_ALTIVEC */ + +#ifdef CONFIG_E500 +void PerformanceMonitorException(struct pt_regs *regs) +{ + perf_irq(regs); +} +#endif + +#ifdef CONFIG_FSL_BOOKE +void CacheLockingException(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ + /* We treat cache locking instructions from the user + * as priv ops, in the future we could try to do + * something smarter + */ + if (error_code & (ESR_DLK|ESR_ILK)) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + return; +} +#endif /* CONFIG_FSL_BOOKE */ + +#ifdef CONFIG_SPE +void SPEFloatingPointException(struct pt_regs *regs) +{ + unsigned long spefscr; + int fpexc_mode; + int code = 0; + + spefscr = current->thread.spefscr; + fpexc_mode = current->thread.fpexc_mode; + + /* Hardware does not neccessarily set sticky + * underflow/overflow/invalid flags */ + if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) { + code = FPE_FLTOVF; + spefscr |= SPEFSCR_FOVFS; + } + else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) { + code = FPE_FLTUND; + spefscr |= SPEFSCR_FUNFS; + } + else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV)) + code = FPE_FLTDIV; + else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) { + code = FPE_FLTINV; + spefscr |= SPEFSCR_FINVS; + } + else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES)) + code = FPE_FLTRES; + + current->thread.spefscr = spefscr; + + _exception(SIGFPE, regs, code, regs->nip); + return; +} +#endif + +#ifdef CONFIG_BOOKE_WDT +/* + * Default handler for a Watchdog exception, + * spins until a reboot occurs + */ +void __attribute__ ((weak)) WatchdogHandler(struct pt_regs *regs) +{ + /* Generic WatchdogHandler, implement your own */ + mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE)); + return; +} + +void WatchdogException(struct pt_regs *regs) +{ + printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n"); + WatchdogHandler(regs); +} +#endif + +void __init trap_init(void) +{ +} diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S new file mode 100644 index 000000000000..12cb90bc209c --- /dev/null +++ b/arch/powerpc/kernel/vector.S @@ -0,0 +1,197 @@ +#include +#include +#include + +/* + * The routines below are in assembler so we can closely control the + * usage of floating-point registers. These routines must be called + * with preempt disabled. + */ +#ifdef CONFIG_PPC32 + .data +fpzero: + .long 0 +fpone: + .long 0x3f800000 /* 1.0 in single-precision FP */ +fphalf: + .long 0x3f000000 /* 0.5 in single-precision FP */ + +#define LDCONST(fr, name) \ + lis r11,name@ha; \ + lfs fr,name@l(r11) +#else + + .section ".toc","aw" +fpzero: + .tc FD_0_0[TC],0 +fpone: + .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */ +fphalf: + .tc FD_3fe00000_0[TC],0x3fe0000000000000 /* 0.5 */ + +#define LDCONST(fr, name) \ + lfd fr,name@toc(r2) +#endif + + .text +/* + * Internal routine to enable floating point and set FPSCR to 0. + * Don't call it from C; it doesn't use the normal calling convention. + */ +fpenable: +#ifdef CONFIG_PPC32 + stwu r1,-64(r1) +#else + stdu r1,-64(r1) +#endif + mfmsr r10 + ori r11,r10,MSR_FP + mtmsr r11 + isync + stfd fr0,24(r1) + stfd fr1,16(r1) + stfd fr31,8(r1) + LDCONST(fr1, fpzero) + mffs fr31 + mtfsf 0xff,fr1 + blr + +fpdisable: + mtlr r12 + mtfsf 0xff,fr31 + lfd fr31,8(r1) + lfd fr1,16(r1) + lfd fr0,24(r1) + mtmsr r10 + isync + addi r1,r1,64 + blr + +/* + * Vector add, floating point. + */ +_GLOBAL(vaddfp) + mflr r12 + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fadds fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector subtract, floating point. + */ +_GLOBAL(vsubfp) + mflr r12 + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fsubs fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector multiply and add, floating point. + */ +_GLOBAL(vmaddfp) + mflr r12 + bl fpenable + stfd fr2,32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fmadds fr0,fr0,fr2,fr1 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,32(r1) + b fpdisable + +/* + * Vector negative multiply and subtract, floating point. + */ +_GLOBAL(vnmsubfp) + mflr r12 + bl fpenable + stfd fr2,32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fnmsubs fr0,fr0,fr2,fr1 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,32(r1) + b fpdisable + +/* + * Vector reciprocal estimate. We just compute 1.0/x. + * r3 -> destination, r4 -> source. + */ +_GLOBAL(vrefp) + mflr r12 + bl fpenable + li r0,4 + LDCONST(fr1, fpone) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + fdivs fr0,fr1,fr0 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector reciprocal square-root estimate, floating point. + * We use the frsqrte instruction for the initial estimate followed + * by 2 iterations of Newton-Raphson to get sufficient accuracy. + * r3 -> destination, r4 -> source. + */ +_GLOBAL(vrsqrtefp) + mflr r12 + bl fpenable + stfd fr2,32(r1) + stfd fr3,40(r1) + stfd fr4,48(r1) + stfd fr5,56(r1) + li r0,4 + LDCONST(fr4, fpone) + LDCONST(fr5, fphalf) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + frsqrte fr1,fr0 /* r = frsqrte(s) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + stfsx fr1,r3,r6 + addi r6,r6,4 + bdnz 1b + lfd fr5,56(r1) + lfd fr4,48(r1) + lfd fr3,40(r1) + lfd fr2,32(r1) + b fpdisable diff --git a/arch/powerpc/kernel/vmlinux.lds b/arch/powerpc/kernel/vmlinux.lds new file mode 100644 index 000000000000..d62c288a81d0 --- /dev/null +++ b/arch/powerpc/kernel/vmlinux.lds @@ -0,0 +1,174 @@ +/* Align . to a 8 byte boundary equals to maximum function alignment. */ +/* sched.text is aling to function alignment to secure we have same + * address even at second ld pass when generating System.map */ +/* spinlock.text is aling to function alignment to secure we have same + * address even at second ld pass when generating System.map */ + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to + the beginning of the section so we begin them at 0. */ + /* Stabs debugging sections. */ +OUTPUT_ARCH(powerpc:common) +jiffies = jiffies_64 + 4; +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } +/* .init : { *(.init) } =0*/ + .plt : { *(.plt) } + .text : + { + *(.text) + . = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .; + . = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .; + *(.fixup) + *(.got1) + __got2_start = .; + *(.got2) + __got2_end = .; + } + _etext = .; + PROVIDE (etext = .); + .rodata : AT(ADDR(.rodata) - 0) { *(.rodata) *(.rodata.*) *(__vermagic) } .rodata1 : AT(ADDR(.rodata1) - 0) { *(.rodata1) } .pci_fixup : AT(ADDR(.pci_fixup) - 0) { __start_pci_fixups_early = .; *(.pci_fixup_early) __end_pci_fixups_early = .; __start_pci_fixups_header = .; *(.pci_fixup_header) __end_pci_fixups_header = .; __start_pci_fixups_final = .; *(.pci_fixup_final) __end_pci_fixups_final = .; __start_pci_fixups_enable = .; *(.pci_fixup_enable) __end_pci_fixups_enable = .; } __ksymtab : AT(ADDR(__ksymtab) - 0) { __start___ksymtab = .; *(__ksymtab) __stop___ksymtab = .; } __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - 0) { __start___ksymtab_gpl = .; *(__ksymtab_gpl) __stop___ksymtab_gpl = .; } __kcrctab : AT(ADDR(__kcrctab) - 0) { __start___kcrctab = .; *(__kcrctab) __stop___kcrctab = .; } __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - 0) { __start___kcrctab_gpl = .; *(__kcrctab_gpl) __stop___kcrctab_gpl = .; } __ksymtab_strings : AT(ADDR(__ksymtab_strings) - 0) { *(__ksymtab_strings) } __param : AT(ADDR(__param) - 0) { __start___param = .; *(__param) __stop___param = .; } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .fixup : { *(.fixup) } + __ex_table : { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + __bug_table : { + __start___bug_table = .; + *(__bug_table) + __stop___bug_table = .; + } + /* Read-write section, merged into data segment: */ + . = ALIGN(4096); + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + _edata = .; + PROVIDE (edata = .); + + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + /* .exit.text is discarded at runtime, not link time, + to deal with references from __bug_table */ + .exit.text : { *(.exit.text) } + .init.data : { + *(.init.data); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .init.setup : { *(.init.setup) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + } + __initcall_end = .; + + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + + .security_initcall.init : AT(ADDR(.security_initcall.init) - 0) { __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; } + + __start___ftr_fixup = .; + __ftr_fixup : { *(__ftr_fixup) } + __stop___ftr_fixup = .; + + . = ALIGN(32); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + _sextratext = .; + _eextratext = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + __bss_stop = .; + + _end = . ; + PROVIDE (end = .); + + /* Sections to be discarded. */ + /DISCARD/ : { + *(.exitcall.exit) + *(.exit.data) + } +} diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..09c6525cfa61 --- /dev/null +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -0,0 +1,172 @@ +#include + +OUTPUT_ARCH(powerpc:common) +jiffies = jiffies_64 + 4; +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } +/* .init : { *(.init) } =0*/ + .plt : { *(.plt) } + .text : + { + *(.text) + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.got1) + __got2_start = .; + *(.got2) + __got2_end = .; + } + _etext = .; + PROVIDE (etext = .); + + RODATA + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + .fixup : { *(.fixup) } + + __ex_table : { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + __bug_table : { + __start___bug_table = .; + *(__bug_table) + __stop___bug_table = .; + } + + /* Read-write section, merged into data segment: */ + . = ALIGN(4096); + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + _edata = .; + PROVIDE (edata = .); + + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + /* .exit.text is discarded at runtime, not link time, + to deal with references from __bug_table */ + .exit.text : { *(.exit.text) } + .init.data : { + *(.init.data); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .init.setup : { *(.init.setup) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + } + __initcall_end = .; + + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + + SECURITY_INIT + + __start___ftr_fixup = .; + __ftr_fixup : { *(__ftr_fixup) } + __stop___ftr_fixup = .; + + . = ALIGN(32); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + _sextratext = .; + _eextratext = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + __bss_stop = .; + + _end = . ; + PROVIDE (end = .); + + /* Sections to be discarded. */ + /DISCARD/ : { + *(.exitcall.exit) + *(.exit.data) + } +} diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile new file mode 100644 index 000000000000..347f9798e433 --- /dev/null +++ b/arch/powerpc/lib/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for ppc-specific library files.. +# + +obj-y := strcase.o string.o +obj-$(CONFIG_PPC32) += div64.o copy32.o checksum.o +obj-$(CONFIG_PPC64) += copypage.o copyuser.o memcpy.o usercopy.o \ + sstep.o checksum64.o +obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/powerpc/lib/checksum.S b/arch/powerpc/lib/checksum.S new file mode 100644 index 000000000000..7874e8a80455 --- /dev/null +++ b/arch/powerpc/lib/checksum.S @@ -0,0 +1,225 @@ +/* + * This file contains assembly-language implementations + * of IP-style 1's complement checksum routines. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * 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. + * + * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). + */ + +#include +#include +#include +#include + + .text + +/* + * ip_fast_csum(buf, len) -- Optimized for IP header + * len is in words and is always >= 5. + */ +_GLOBAL(ip_fast_csum) + lwz r0,0(r3) + lwzu r5,4(r3) + addic. r4,r4,-2 + addc r0,r0,r5 + mtctr r4 + blelr- +1: lwzu r4,4(r3) + adde r0,r0,r4 + bdnz 1b + addze r0,r0 /* add in final carry */ + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * Compute checksum of TCP or UDP pseudo-header: + * csum_tcpudp_magic(saddr, daddr, len, proto, sum) + */ +_GLOBAL(csum_tcpudp_magic) + rlwimi r5,r6,16,0,15 /* put proto in upper half of len */ + addc r0,r3,r4 /* add 4 32-bit words together */ + adde r0,r0,r5 + adde r0,r0,r7 + addze r0,r0 /* add in final carry */ + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * csum_partial(buff, len, sum) + */ +_GLOBAL(csum_partial) + addic r0,r5,0 + subi r3,r3,4 + srwi. r6,r4,2 + beq 3f /* if we're doing < 4 bytes */ + andi. r5,r3,2 /* Align buffer to longword boundary */ + beq+ 1f + lhz r5,4(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r4,r4,2 + addc r0,r0,r5 + srwi. r6,r4,2 /* # words to do */ + beq 3f +1: mtctr r6 +2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */ + adde r0,r0,r5 /* be unnecessary to unroll this loop */ + bdnz 2b + andi. r4,r4,3 +3: cmpwi 0,r4,2 + blt+ 4f + lhz r5,4(r3) + addi r3,r3,2 + subi r4,r4,2 + adde r0,r0,r5 +4: cmpwi 0,r4,1 + bne+ 5f + lbz r5,4(r3) + slwi r5,r5,8 /* Upper byte of word */ + adde r0,r0,r5 +5: addze r3,r0 /* add in final carry */ + blr + +/* + * Computes the checksum of a memory block at src, length len, + * and adds in "sum" (32-bit), while copying the block to dst. + * If an access exception occurs on src or dst, it stores -EFAULT + * to *src_err or *dst_err respectively, and (for an error on + * src) zeroes the rest of dst. + * + * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err) + */ +_GLOBAL(csum_partial_copy_generic) + addic r0,r6,0 + subi r3,r3,4 + subi r4,r4,4 + srwi. r6,r5,2 + beq 3f /* if we're doing < 4 bytes */ + andi. r9,r4,2 /* Align dst to longword boundary */ + beq+ 1f +81: lhz r6,4(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r5,r5,2 +91: sth r6,4(r4) + addi r4,r4,2 + addc r0,r0,r6 + srwi. r6,r5,2 /* # words to do */ + beq 3f +1: srwi. r6,r5,4 /* # groups of 4 words to do */ + beq 10f + mtctr r6 +71: lwz r6,4(r3) +72: lwz r9,8(r3) +73: lwz r10,12(r3) +74: lwzu r11,16(r3) + adde r0,r0,r6 +75: stw r6,4(r4) + adde r0,r0,r9 +76: stw r9,8(r4) + adde r0,r0,r10 +77: stw r10,12(r4) + adde r0,r0,r11 +78: stwu r11,16(r4) + bdnz 71b +10: rlwinm. r6,r5,30,30,31 /* # words left to do */ + beq 13f + mtctr r6 +82: lwzu r9,4(r3) +92: stwu r9,4(r4) + adde r0,r0,r9 + bdnz 82b +13: andi. r5,r5,3 +3: cmpwi 0,r5,2 + blt+ 4f +83: lhz r6,4(r3) + addi r3,r3,2 + subi r5,r5,2 +93: sth r6,4(r4) + addi r4,r4,2 + adde r0,r0,r6 +4: cmpwi 0,r5,1 + bne+ 5f +84: lbz r6,4(r3) +94: stb r6,4(r4) + slwi r6,r6,8 /* Upper byte of word */ + adde r0,r0,r6 +5: addze r3,r0 /* add in final carry */ + blr + +/* These shouldn't go in the fixup section, since that would + cause the ex_table addresses to get out of order. */ + +src_error_4: + mfctr r6 /* update # bytes remaining from ctr */ + rlwimi r5,r6,4,0,27 + b 79f +src_error_1: + li r6,0 + subi r5,r5,2 +95: sth r6,4(r4) + addi r4,r4,2 +79: srwi. r6,r5,2 + beq 3f + mtctr r6 +src_error_2: + li r6,0 +96: stwu r6,4(r4) + bdnz 96b +3: andi. r5,r5,3 + beq src_error +src_error_3: + li r6,0 + mtctr r5 + addi r4,r4,3 +97: stbu r6,1(r4) + bdnz 97b +src_error: + cmpwi 0,r7,0 + beq 1f + li r6,-EFAULT + stw r6,0(r7) +1: addze r3,r0 + blr + +dst_error: + cmpwi 0,r8,0 + beq 1f + li r6,-EFAULT + stw r6,0(r8) +1: addze r3,r0 + blr + +.section __ex_table,"a" + .long 81b,src_error_1 + .long 91b,dst_error + .long 71b,src_error_4 + .long 72b,src_error_4 + .long 73b,src_error_4 + .long 74b,src_error_4 + .long 75b,dst_error + .long 76b,dst_error + .long 77b,dst_error + .long 78b,dst_error + .long 82b,src_error_2 + .long 92b,dst_error + .long 83b,src_error_3 + .long 93b,dst_error + .long 84b,src_error_3 + .long 94b,dst_error + .long 95b,dst_error + .long 96b,dst_error + .long 97b,dst_error diff --git a/arch/powerpc/lib/checksum64.S b/arch/powerpc/lib/checksum64.S new file mode 100644 index 000000000000..ef96c6c58efc --- /dev/null +++ b/arch/powerpc/lib/checksum64.S @@ -0,0 +1,229 @@ +/* + * This file contains assembly-language implementations + * of IP-style 1's complement checksum routines. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * 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. + * + * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). + */ + +#include +#include +#include +#include + +/* + * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header + * len is in words and is always >= 5. + * + * In practice len == 5, but this is not guaranteed. So this code does not + * attempt to use doubleword instructions. + */ +_GLOBAL(ip_fast_csum) + lwz r0,0(r3) + lwzu r5,4(r3) + addic. r4,r4,-2 + addc r0,r0,r5 + mtctr r4 + blelr- +1: lwzu r4,4(r3) + adde r0,r0,r4 + bdnz 1b + addze r0,r0 /* add in final carry */ + rldicl r4,r0,32,0 /* fold two 32-bit halves together */ + add r0,r0,r4 + srdi r0,r0,32 + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * Compute checksum of TCP or UDP pseudo-header: + * csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum) + * No real gain trying to do this specially for 64 bit, but + * the 32 bit addition may spill into the upper bits of + * the doubleword so we still must fold it down from 64. + */ +_GLOBAL(csum_tcpudp_magic) + rlwimi r5,r6,16,0,15 /* put proto in upper half of len */ + addc r0,r3,r4 /* add 4 32-bit words together */ + adde r0,r0,r5 + adde r0,r0,r7 + rldicl r4,r0,32,0 /* fold 64 bit value */ + add r0,r4,r0 + srdi r0,r0,32 + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * Computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit). + * + * This code assumes at least halfword alignment, though the length + * can be any number of bytes. The sum is accumulated in r5. + * + * csum_partial(r3=buff, r4=len, r5=sum) + */ +_GLOBAL(csum_partial) + subi r3,r3,8 /* we'll offset by 8 for the loads */ + srdi. r6,r4,3 /* divide by 8 for doubleword count */ + addic r5,r5,0 /* clear carry */ + beq 3f /* if we're doing < 8 bytes */ + andi. r0,r3,2 /* aligned on a word boundary already? */ + beq+ 1f + lhz r6,8(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r4,r4,2 + addc r5,r5,r6 + srdi. r6,r4,3 /* recompute number of doublewords */ + beq 3f /* any left? */ +1: mtctr r6 +2: ldu r6,8(r3) /* main sum loop */ + adde r5,r5,r6 + bdnz 2b + andi. r4,r4,7 /* compute bytes left to sum after doublewords */ +3: cmpwi 0,r4,4 /* is at least a full word left? */ + blt 4f + lwz r6,8(r3) /* sum this word */ + addi r3,r3,4 + subi r4,r4,4 + adde r5,r5,r6 +4: cmpwi 0,r4,2 /* is at least a halfword left? */ + blt+ 5f + lhz r6,8(r3) /* sum this halfword */ + addi r3,r3,2 + subi r4,r4,2 + adde r5,r5,r6 +5: cmpwi 0,r4,1 /* is at least a byte left? */ + bne+ 6f + lbz r6,8(r3) /* sum this byte */ + slwi r6,r6,8 /* this byte is assumed to be the upper byte of a halfword */ + adde r5,r5,r6 +6: addze r5,r5 /* add in final carry */ + rldicl r4,r5,32,0 /* fold two 32-bit halves together */ + add r3,r4,r5 + srdi r3,r3,32 + blr + +/* + * Computes the checksum of a memory block at src, length len, + * and adds in "sum" (32-bit), while copying the block to dst. + * If an access exception occurs on src or dst, it stores -EFAULT + * to *src_err or *dst_err respectively, and (for an error on + * src) zeroes the rest of dst. + * + * This code needs to be reworked to take advantage of 64 bit sum+copy. + * However, due to tokenring halfword alignment problems this will be very + * tricky. For now we'll leave it until we instrument it somehow. + * + * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err) + */ +_GLOBAL(csum_partial_copy_generic) + addic r0,r6,0 + subi r3,r3,4 + subi r4,r4,4 + srwi. r6,r5,2 + beq 3f /* if we're doing < 4 bytes */ + andi. r9,r4,2 /* Align dst to longword boundary */ + beq+ 1f +81: lhz r6,4(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r5,r5,2 +91: sth r6,4(r4) + addi r4,r4,2 + addc r0,r0,r6 + srwi. r6,r5,2 /* # words to do */ + beq 3f +1: mtctr r6 +82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */ +92: stwu r6,4(r4) /* be unnecessary to unroll this loop */ + adde r0,r0,r6 + bdnz 82b + andi. r5,r5,3 +3: cmpwi 0,r5,2 + blt+ 4f +83: lhz r6,4(r3) + addi r3,r3,2 + subi r5,r5,2 +93: sth r6,4(r4) + addi r4,r4,2 + adde r0,r0,r6 +4: cmpwi 0,r5,1 + bne+ 5f +84: lbz r6,4(r3) +94: stb r6,4(r4) + slwi r6,r6,8 /* Upper byte of word */ + adde r0,r0,r6 +5: addze r3,r0 /* add in final carry (unlikely with 64-bit regs) */ + rldicl r4,r3,32,0 /* fold 64 bit value */ + add r3,r4,r3 + srdi r3,r3,32 + blr + +/* These shouldn't go in the fixup section, since that would + cause the ex_table addresses to get out of order. */ + + .globl src_error_1 +src_error_1: + li r6,0 + subi r5,r5,2 +95: sth r6,4(r4) + addi r4,r4,2 + srwi. r6,r5,2 + beq 3f + mtctr r6 + .globl src_error_2 +src_error_2: + li r6,0 +96: stwu r6,4(r4) + bdnz 96b +3: andi. r5,r5,3 + beq src_error + .globl src_error_3 +src_error_3: + li r6,0 + mtctr r5 + addi r4,r4,3 +97: stbu r6,1(r4) + bdnz 97b + .globl src_error +src_error: + cmpdi 0,r7,0 + beq 1f + li r6,-EFAULT + stw r6,0(r7) +1: addze r3,r0 + blr + + .globl dst_error +dst_error: + cmpdi 0,r8,0 + beq 1f + li r6,-EFAULT + stw r6,0(r8) +1: addze r3,r0 + blr + +.section __ex_table,"a" + .align 3 + .llong 81b,src_error_1 + .llong 91b,dst_error + .llong 82b,src_error_2 + .llong 92b,dst_error + .llong 83b,src_error_3 + .llong 93b,dst_error + .llong 84b,src_error_3 + .llong 94b,dst_error + .llong 95b,dst_error + .llong 96b,dst_error + .llong 97b,dst_error diff --git a/arch/powerpc/lib/copy32.S b/arch/powerpc/lib/copy32.S new file mode 100644 index 000000000000..420a912198a2 --- /dev/null +++ b/arch/powerpc/lib/copy32.S @@ -0,0 +1,543 @@ +/* + * Memory copy functions for 32-bit PowerPC. + * + * Copyright (C) 1996-2005 Paul Mackerras. + * + * 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 + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 2; \ + .long 8 ## n ## 0b,9 ## n ## 0b; \ + .long 8 ## n ## 1b,9 ## n ## 0b; \ + .long 8 ## n ## 2b,9 ## n ## 0b; \ + .long 8 ## n ## 3b,9 ## n ## 0b; \ + .long 8 ## n ## 4b,9 ## n ## 1b; \ + .long 8 ## n ## 5b,9 ## n ## 1b; \ + .long 8 ## n ## 6b,9 ## n ## 1b; \ + .long 8 ## n ## 7b,9 ## n ## 1b; \ + .text + + .text + .stabs "arch/powerpc/lib/",N_SO,0,0,0f + .stabs "copy32.S",N_SO,0,0,0f +0: + +CACHELINE_BYTES = L1_CACHE_LINE_SIZE +LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE +CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1) + +/* + * Use dcbz on the complete cache lines in the destination + * to set them to zero. This requires that the destination + * area is cacheable. -- paulus + */ +_GLOBAL(cacheable_memzero) + mr r5,r4 + li r4,0 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + clrlwi r7,r6,32-LG_CACHELINE_BYTES + add r8,r7,r5 + srwi r9,r8,LG_CACHELINE_BYTES + addic. r9,r9,-1 /* total number of complete cachelines */ + ble 2f + xori r0,r7,CACHELINE_MASK & ~3 + srwi. r0,r0,2 + beq 3f + mtctr r0 +4: stwu r4,4(r6) + bdnz 4b +3: mtctr r9 + li r7,4 +#if !defined(CONFIG_8xx) +10: dcbz r7,r6 +#else +10: stw r4, 4(r6) + stw r4, 8(r6) + stw r4, 12(r6) + stw r4, 16(r6) +#if CACHE_LINE_SIZE >= 32 + stw r4, 20(r6) + stw r4, 24(r6) + stw r4, 28(r6) + stw r4, 32(r6) +#endif /* CACHE_LINE_SIZE */ +#endif + addi r6,r6,CACHELINE_BYTES + bdnz 10b + clrlwi r5,r8,32-LG_CACHELINE_BYTES + addi r5,r5,4 +2: srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + +_GLOBAL(memset) + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + +/* + * This version uses dcbz on the complete cache lines in the + * destination area to reduce memory traffic. This requires that + * the destination area is cacheable. + * We only use this version if the source and dest don't overlap. + * -- paulus. + */ +_GLOBAL(cacheable_memcpy) + add r7,r3,r5 /* test if the src & dst overlap */ + add r8,r4,r5 + cmplw 0,r4,r7 + cmplw 1,r3,r8 + crand 0,0,4 /* cr0.lt &= cr1.lt */ + blt memcpy /* if regions overlap */ + + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + subf r5,r0,r5 + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ + stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ + stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: +#if !defined(CONFIG_8xx) + dcbz r11,r6 +#endif + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) + stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) + stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: blr + +_GLOBAL(memmove) + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + +_GLOBAL(memcpy) + srwi. r7,r5,3 + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + +_GLOBAL(backwards_memcpy) + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + +_GLOBAL(__copy_tofrom_user) + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ +71: stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: subf r5,r0,r5 + srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ +73: stwu r9,4(r6) + bdnz 72b + + .section __ex_table,"a" + .align 2 + .long 70b,100f + .long 71b,101f + .long 72b,102f + .long 73b,103f + .text + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + beq 63f + +#ifdef CONFIG_8xx + /* Don't use prefetch on 8xx */ + mtctr r0 + li r0,0 +53: COPY_16_BYTES_WITHEX(0) + bdnz 53b + +#else /* not CONFIG_8xx */ + /* Here we decide how far ahead to prefetch the source */ + li r3,4 + cmpwi r0,1 + li r7,0 + ble 114f + li r7,1 +#if MAX_COPY_PREFETCH > 1 + /* Heuristically, for large transfers we prefetch + MAX_COPY_PREFETCH cachelines ahead. For small transfers + we prefetch 1 cacheline ahead. */ + cmpwi r0,MAX_COPY_PREFETCH + ble 112f + li r7,MAX_COPY_PREFETCH +112: mtctr r7 +111: dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES + bdnz 111b +#else + dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES +#endif /* MAX_COPY_PREFETCH > 1 */ + +114: subf r8,r7,r0 + mr r0,r7 + mtctr r8 + +53: dcbt r3,r4 +54: dcbz r11,r6 + .section __ex_table,"a" + .align 2 + .long 54b,105f + .text +/* the main body of the cacheline loop */ + COPY_16_BYTES_WITHEX(0) +#if L1_CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_WITHEX(1) +#if L1_CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_WITHEX(2) + COPY_16_BYTES_WITHEX(3) +#if L1_CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_WITHEX(4) + COPY_16_BYTES_WITHEX(5) + COPY_16_BYTES_WITHEX(6) + COPY_16_BYTES_WITHEX(7) +#endif +#endif +#endif + bdnz 53b + cmpwi r0,0 + li r3,4 + li r7,0 + bne 114b +#endif /* CONFIG_8xx */ + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) +31: stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) +41: stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: li r3,0 + blr + +/* read fault, initial single-byte copy */ +100: li r9,0 + b 90f +/* write fault, initial single-byte copy */ +101: li r9,1 +90: subf r5,r8,r5 + li r3,0 + b 99f +/* read fault, initial word copy */ +102: li r9,0 + b 91f +/* write fault, initial word copy */ +103: li r9,1 +91: li r3,2 + b 99f + +/* + * this stuff handles faults in the cacheline loop and branches to either + * 104f (if in read part) or 105f (if in write part), after updating r5 + */ + COPY_16_BYTES_EXCODE(0) +#if L1_CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_EXCODE(1) +#if L1_CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_EXCODE(2) + COPY_16_BYTES_EXCODE(3) +#if L1_CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_EXCODE(4) + COPY_16_BYTES_EXCODE(5) + COPY_16_BYTES_EXCODE(6) + COPY_16_BYTES_EXCODE(7) +#endif +#endif +#endif + +/* read fault in cacheline loop */ +104: li r9,0 + b 92f +/* fault on dcbz (effectively a write fault) */ +/* or write fault in cacheline loop */ +105: li r9,1 +92: li r3,LG_CACHELINE_BYTES + mfctr r8 + add r0,r0,r8 + b 106f +/* read fault in final word loop */ +108: li r9,0 + b 93f +/* write fault in final word loop */ +109: li r9,1 +93: andi. r5,r5,3 + li r3,2 + b 99f +/* read fault in final byte loop */ +110: li r9,0 + b 94f +/* write fault in final byte loop */ +111: li r9,1 +94: li r5,0 + li r3,0 +/* + * At this stage the number of bytes not copied is + * r5 + (ctr << r3), and r9 is 0 for read or 1 for write. + */ +99: mfctr r0 +106: slw r3,r0,r3 + add. r3,r3,r5 + beq 120f /* shouldn't happen */ + cmpwi 0,r9,0 + bne 120f +/* for a read fault, first try to continue the copy one byte at a time */ + mtctr r3 +130: lbz r0,4(r4) +131: stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 130b +/* then clear out the destination: r3 bytes starting at 4(r6) */ +132: mfctr r3 + srwi. r0,r3,2 + li r9,0 + mtctr r0 + beq 113f +112: stwu r9,4(r6) + bdnz 112b +113: andi. r0,r3,3 + mtctr r0 + beq 120f +114: stb r9,4(r6) + addi r6,r6,1 + bdnz 114b +120: blr + + .section __ex_table,"a" + .align 2 + .long 30b,108b + .long 31b,109b + .long 40b,110b + .long 41b,111b + .long 130b,132b + .long 131b,120b + .long 112b,120b + .long 114b,120b + .text diff --git a/arch/powerpc/lib/copypage.S b/arch/powerpc/lib/copypage.S new file mode 100644 index 000000000000..733d61618bbf --- /dev/null +++ b/arch/powerpc/lib/copypage.S @@ -0,0 +1,121 @@ +/* + * arch/ppc64/lib/copypage.S + * + * Copyright (C) 2002 Paul Mackerras, 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 + +_GLOBAL(copy_page) + std r31,-8(1) + std r30,-16(1) + std r29,-24(1) + std r28,-32(1) + std r27,-40(1) + std r26,-48(1) + std r25,-56(1) + std r24,-64(1) + std r23,-72(1) + std r22,-80(1) + std r21,-88(1) + std r20,-96(1) + li r5,4096/32 - 1 + addi r3,r3,-8 + li r12,5 +0: addi r5,r5,-24 + mtctr r12 + ld r22,640(4) + ld r21,512(4) + ld r20,384(4) + ld r11,256(4) + ld r9,128(4) + ld r7,0(4) + ld r25,648(4) + ld r24,520(4) + ld r23,392(4) + ld r10,264(4) + ld r8,136(4) + ldu r6,8(4) + cmpwi r5,24 +1: std r22,648(3) + std r21,520(3) + std r20,392(3) + std r11,264(3) + std r9,136(3) + std r7,8(3) + ld r28,648(4) + ld r27,520(4) + ld r26,392(4) + ld r31,264(4) + ld r30,136(4) + ld r29,8(4) + std r25,656(3) + std r24,528(3) + std r23,400(3) + std r10,272(3) + std r8,144(3) + std r6,16(3) + ld r22,656(4) + ld r21,528(4) + ld r20,400(4) + ld r11,272(4) + ld r9,144(4) + ld r7,16(4) + std r28,664(3) + std r27,536(3) + std r26,408(3) + std r31,280(3) + std r30,152(3) + stdu r29,24(3) + ld r25,664(4) + ld r24,536(4) + ld r23,408(4) + ld r10,280(4) + ld r8,152(4) + ldu r6,24(4) + bdnz 1b + std r22,648(3) + std r21,520(3) + std r20,392(3) + std r11,264(3) + std r9,136(3) + std r7,8(3) + addi r4,r4,640 + addi r3,r3,648 + bge 0b + mtctr r5 + ld r7,0(4) + ld r8,8(4) + ldu r9,16(4) +3: ld r10,8(4) + std r7,8(3) + ld r7,16(4) + std r8,16(3) + ld r8,24(4) + std r9,24(3) + ldu r9,32(4) + stdu r10,32(3) + bdnz 3b +4: ld r10,8(4) + std r7,8(3) + std r8,16(3) + std r9,24(3) + std r10,32(3) +9: ld r20,-96(1) + ld r21,-88(1) + ld r22,-80(1) + ld r23,-72(1) + ld r24,-64(1) + ld r25,-56(1) + ld r26,-48(1) + ld r27,-40(1) + ld r28,-32(1) + ld r29,-24(1) + ld r30,-16(1) + ld r31,-8(1) + blr diff --git a/arch/powerpc/lib/copyuser.S b/arch/powerpc/lib/copyuser.S new file mode 100644 index 000000000000..a0b3fbbd6fb1 --- /dev/null +++ b/arch/powerpc/lib/copyuser.S @@ -0,0 +1,576 @@ +/* + * arch/ppc64/lib/copyuser.S + * + * Copyright (C) 2002 Paul Mackerras, 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 + + .align 7 +_GLOBAL(__copy_tofrom_user) + /* first check for a whole page copy on a page boundary */ + cmpldi cr1,r5,16 + cmpdi cr6,r5,4096 + or r0,r3,r4 + neg r6,r3 /* LS 3 bits = # bytes to 8-byte dest bdry */ + andi. r0,r0,4095 + std r3,-24(r1) + crand cr0*4+2,cr0*4+2,cr6*4+2 + std r4,-16(r1) + std r5,-8(r1) + dcbt 0,r4 + beq .Lcopy_page + andi. r6,r6,7 + mtcrf 0x01,r5 + blt cr1,.Lshort_copy + bne .Ldst_unaligned +.Ldst_aligned: + andi. r0,r4,7 + addi r3,r3,-16 + bne .Lsrc_unaligned + srdi r7,r5,4 +20: ld r9,0(r4) + addi r4,r4,-8 + mtctr r7 + andi. r5,r5,7 + bf cr7*4+0,22f + addi r3,r3,8 + addi r4,r4,8 + mr r8,r9 + blt cr1,72f +21: ld r9,8(r4) +70: std r8,8(r3) +22: ldu r8,16(r4) +71: stdu r9,16(r3) + bdnz 21b +72: std r8,8(r3) + beq+ 3f + addi r3,r3,16 +23: ld r9,8(r4) +.Ldo_tail: + bf cr7*4+1,1f + rotldi r9,r9,32 +73: stw r9,0(r3) + addi r3,r3,4 +1: bf cr7*4+2,2f + rotldi r9,r9,16 +74: sth r9,0(r3) + addi r3,r3,2 +2: bf cr7*4+3,3f + rotldi r9,r9,8 +75: stb r9,0(r3) +3: li r3,0 + blr + +.Lsrc_unaligned: + srdi r6,r5,3 + addi r5,r5,-16 + subf r4,r0,r4 + srdi r7,r5,4 + sldi r10,r0,3 + cmpldi cr6,r6,3 + andi. r5,r5,7 + mtctr r7 + subfic r11,r10,64 + add r5,r5,r0 + bt cr7*4+0,28f + +24: ld r9,0(r4) /* 3+2n loads, 2+2n stores */ +25: ld r0,8(r4) + sld r6,r9,r10 +26: ldu r9,16(r4) + srd r7,r0,r11 + sld r8,r0,r10 + or r7,r7,r6 + blt cr6,79f +27: ld r0,8(r4) + b 2f + +28: ld r0,0(r4) /* 4+2n loads, 3+2n stores */ +29: ldu r9,8(r4) + sld r8,r0,r10 + addi r3,r3,-8 + blt cr6,5f +30: ld r0,8(r4) + srd r12,r9,r11 + sld r6,r9,r10 +31: ldu r9,16(r4) + or r12,r8,r12 + srd r7,r0,r11 + sld r8,r0,r10 + addi r3,r3,16 + beq cr6,78f + +1: or r7,r7,r6 +32: ld r0,8(r4) +76: std r12,8(r3) +2: srd r12,r9,r11 + sld r6,r9,r10 +33: ldu r9,16(r4) + or r12,r8,r12 +77: stdu r7,16(r3) + srd r7,r0,r11 + sld r8,r0,r10 + bdnz 1b + +78: std r12,8(r3) + or r7,r7,r6 +79: std r7,16(r3) +5: srd r12,r9,r11 + or r12,r8,r12 +80: std r12,24(r3) + bne 6f + li r3,0 + blr +6: cmpwi cr1,r5,8 + addi r3,r3,32 + sld r9,r9,r10 + ble cr1,.Ldo_tail +34: ld r0,8(r4) + srd r7,r0,r11 + or r9,r7,r9 + b .Ldo_tail + +.Ldst_unaligned: + mtcrf 0x01,r6 /* put #bytes to 8B bdry into cr7 */ + subf r5,r6,r5 + li r7,0 + cmpldi r1,r5,16 + bf cr7*4+3,1f +35: lbz r0,0(r4) +81: stb r0,0(r3) + addi r7,r7,1 +1: bf cr7*4+2,2f +36: lhzx r0,r7,r4 +82: sthx r0,r7,r3 + addi r7,r7,2 +2: bf cr7*4+1,3f +37: lwzx r0,r7,r4 +83: stwx r0,r7,r3 +3: mtcrf 0x01,r5 + add r4,r6,r4 + add r3,r6,r3 + b .Ldst_aligned + +.Lshort_copy: + bf cr7*4+0,1f +38: lwz r0,0(r4) +39: lwz r9,4(r4) + addi r4,r4,8 +84: stw r0,0(r3) +85: stw r9,4(r3) + addi r3,r3,8 +1: bf cr7*4+1,2f +40: lwz r0,0(r4) + addi r4,r4,4 +86: stw r0,0(r3) + addi r3,r3,4 +2: bf cr7*4+2,3f +41: lhz r0,0(r4) + addi r4,r4,2 +87: sth r0,0(r3) + addi r3,r3,2 +3: bf cr7*4+3,4f +42: lbz r0,0(r4) +88: stb r0,0(r3) +4: li r3,0 + blr + +/* + * exception handlers follow + * we have to return the number of bytes not copied + * for an exception on a load, we set the rest of the destination to 0 + */ + +136: +137: + add r3,r3,r7 + b 1f +130: +131: + addi r3,r3,8 +120: +122: +124: +125: +126: +127: +128: +129: +133: + addi r3,r3,8 +121: +132: + addi r3,r3,8 +123: +134: +135: +138: +139: +140: +141: +142: + +/* + * here we have had a fault on a load and r3 points to the first + * unmodified byte of the destination + */ +1: ld r6,-24(r1) + ld r4,-16(r1) + ld r5,-8(r1) + subf r6,r6,r3 + add r4,r4,r6 + subf r5,r6,r5 /* #bytes left to go */ + +/* + * first see if we can copy any more bytes before hitting another exception + */ + mtctr r5 +43: lbz r0,0(r4) + addi r4,r4,1 +89: stb r0,0(r3) + addi r3,r3,1 + bdnz 43b + li r3,0 /* huh? all copied successfully this time? */ + blr + +/* + * here we have trapped again, need to clear ctr bytes starting at r3 + */ +143: mfctr r5 + li r0,0 + mr r4,r3 + mr r3,r5 /* return the number of bytes not copied */ +1: andi. r9,r4,7 + beq 3f +90: stb r0,0(r4) + addic. r5,r5,-1 + addi r4,r4,1 + bne 1b + blr +3: cmpldi cr1,r5,8 + srdi r9,r5,3 + andi. r5,r5,7 + blt cr1,93f + mtctr r9 +91: std r0,0(r4) + addi r4,r4,8 + bdnz 91b +93: beqlr + mtctr r5 +92: stb r0,0(r4) + addi r4,r4,1 + bdnz 92b + blr + +/* + * exception handlers for stores: we just need to work + * out how many bytes weren't copied + */ +182: +183: + add r3,r3,r7 + b 1f +180: + addi r3,r3,8 +171: +177: + addi r3,r3,8 +170: +172: +176: +178: + addi r3,r3,4 +185: + addi r3,r3,4 +173: +174: +175: +179: +181: +184: +186: +187: +188: +189: +1: + ld r6,-24(r1) + ld r5,-8(r1) + add r6,r6,r5 + subf r3,r3,r6 /* #bytes not copied */ +190: +191: +192: + blr /* #bytes not copied in r3 */ + + .section __ex_table,"a" + .align 3 + .llong 20b,120b + .llong 21b,121b + .llong 70b,170b + .llong 22b,122b + .llong 71b,171b + .llong 72b,172b + .llong 23b,123b + .llong 73b,173b + .llong 74b,174b + .llong 75b,175b + .llong 24b,124b + .llong 25b,125b + .llong 26b,126b + .llong 27b,127b + .llong 28b,128b + .llong 29b,129b + .llong 30b,130b + .llong 31b,131b + .llong 32b,132b + .llong 76b,176b + .llong 33b,133b + .llong 77b,177b + .llong 78b,178b + .llong 79b,179b + .llong 80b,180b + .llong 34b,134b + .llong 35b,135b + .llong 81b,181b + .llong 36b,136b + .llong 82b,182b + .llong 37b,137b + .llong 83b,183b + .llong 38b,138b + .llong 39b,139b + .llong 84b,184b + .llong 85b,185b + .llong 40b,140b + .llong 86b,186b + .llong 41b,141b + .llong 87b,187b + .llong 42b,142b + .llong 88b,188b + .llong 43b,143b + .llong 89b,189b + .llong 90b,190b + .llong 91b,191b + .llong 92b,192b + + .text + +/* + * Routine to copy a whole page of data, optimized for POWER4. + * On POWER4 it is more than 50% faster than the simple loop + * above (following the .Ldst_aligned label) but it runs slightly + * slower on POWER3. + */ +.Lcopy_page: + std r31,-32(1) + std r30,-40(1) + std r29,-48(1) + std r28,-56(1) + std r27,-64(1) + std r26,-72(1) + std r25,-80(1) + std r24,-88(1) + std r23,-96(1) + std r22,-104(1) + std r21,-112(1) + std r20,-120(1) + li r5,4096/32 - 1 + addi r3,r3,-8 + li r0,5 +0: addi r5,r5,-24 + mtctr r0 +20: ld r22,640(4) +21: ld r21,512(4) +22: ld r20,384(4) +23: ld r11,256(4) +24: ld r9,128(4) +25: ld r7,0(4) +26: ld r25,648(4) +27: ld r24,520(4) +28: ld r23,392(4) +29: ld r10,264(4) +30: ld r8,136(4) +31: ldu r6,8(4) + cmpwi r5,24 +1: +32: std r22,648(3) +33: std r21,520(3) +34: std r20,392(3) +35: std r11,264(3) +36: std r9,136(3) +37: std r7,8(3) +38: ld r28,648(4) +39: ld r27,520(4) +40: ld r26,392(4) +41: ld r31,264(4) +42: ld r30,136(4) +43: ld r29,8(4) +44: std r25,656(3) +45: std r24,528(3) +46: std r23,400(3) +47: std r10,272(3) +48: std r8,144(3) +49: std r6,16(3) +50: ld r22,656(4) +51: ld r21,528(4) +52: ld r20,400(4) +53: ld r11,272(4) +54: ld r9,144(4) +55: ld r7,16(4) +56: std r28,664(3) +57: std r27,536(3) +58: std r26,408(3) +59: std r31,280(3) +60: std r30,152(3) +61: stdu r29,24(3) +62: ld r25,664(4) +63: ld r24,536(4) +64: ld r23,408(4) +65: ld r10,280(4) +66: ld r8,152(4) +67: ldu r6,24(4) + bdnz 1b +68: std r22,648(3) +69: std r21,520(3) +70: std r20,392(3) +71: std r11,264(3) +72: std r9,136(3) +73: std r7,8(3) +74: addi r4,r4,640 +75: addi r3,r3,648 + bge 0b + mtctr r5 +76: ld r7,0(4) +77: ld r8,8(4) +78: ldu r9,16(4) +3: +79: ld r10,8(4) +80: std r7,8(3) +81: ld r7,16(4) +82: std r8,16(3) +83: ld r8,24(4) +84: std r9,24(3) +85: ldu r9,32(4) +86: stdu r10,32(3) + bdnz 3b +4: +87: ld r10,8(4) +88: std r7,8(3) +89: std r8,16(3) +90: std r9,24(3) +91: std r10,32(3) +9: ld r20,-120(1) + ld r21,-112(1) + ld r22,-104(1) + ld r23,-96(1) + ld r24,-88(1) + ld r25,-80(1) + ld r26,-72(1) + ld r27,-64(1) + ld r28,-56(1) + ld r29,-48(1) + ld r30,-40(1) + ld r31,-32(1) + li r3,0 + blr + +/* + * on an exception, reset to the beginning and jump back into the + * standard __copy_tofrom_user + */ +100: ld r20,-120(1) + ld r21,-112(1) + ld r22,-104(1) + ld r23,-96(1) + ld r24,-88(1) + ld r25,-80(1) + ld r26,-72(1) + ld r27,-64(1) + ld r28,-56(1) + ld r29,-48(1) + ld r30,-40(1) + ld r31,-32(1) + ld r3,-24(r1) + ld r4,-16(r1) + li r5,4096 + b .Ldst_aligned + + .section __ex_table,"a" + .align 3 + .llong 20b,100b + .llong 21b,100b + .llong 22b,100b + .llong 23b,100b + .llong 24b,100b + .llong 25b,100b + .llong 26b,100b + .llong 27b,100b + .llong 28b,100b + .llong 29b,100b + .llong 30b,100b + .llong 31b,100b + .llong 32b,100b + .llong 33b,100b + .llong 34b,100b + .llong 35b,100b + .llong 36b,100b + .llong 37b,100b + .llong 38b,100b + .llong 39b,100b + .llong 40b,100b + .llong 41b,100b + .llong 42b,100b + .llong 43b,100b + .llong 44b,100b + .llong 45b,100b + .llong 46b,100b + .llong 47b,100b + .llong 48b,100b + .llong 49b,100b + .llong 50b,100b + .llong 51b,100b + .llong 52b,100b + .llong 53b,100b + .llong 54b,100b + .llong 55b,100b + .llong 56b,100b + .llong 57b,100b + .llong 58b,100b + .llong 59b,100b + .llong 60b,100b + .llong 61b,100b + .llong 62b,100b + .llong 63b,100b + .llong 64b,100b + .llong 65b,100b + .llong 66b,100b + .llong 67b,100b + .llong 68b,100b + .llong 69b,100b + .llong 70b,100b + .llong 71b,100b + .llong 72b,100b + .llong 73b,100b + .llong 74b,100b + .llong 75b,100b + .llong 76b,100b + .llong 77b,100b + .llong 78b,100b + .llong 79b,100b + .llong 80b,100b + .llong 81b,100b + .llong 82b,100b + .llong 83b,100b + .llong 84b,100b + .llong 85b,100b + .llong 86b,100b + .llong 87b,100b + .llong 88b,100b + .llong 89b,100b + .llong 90b,100b + .llong 91b,100b diff --git a/arch/powerpc/lib/div64.S b/arch/powerpc/lib/div64.S new file mode 100644 index 000000000000..3527569e9926 --- /dev/null +++ b/arch/powerpc/lib/div64.S @@ -0,0 +1,58 @@ +/* + * Divide a 64-bit unsigned number by a 32-bit unsigned number. + * This routine assumes that the top 32 bits of the dividend are + * non-zero to start with. + * On entry, r3 points to the dividend, which get overwritten with + * the 64-bit quotient, and r4 contains the divisor. + * On exit, r3 contains the remainder. + * + * Copyright (C) 2002 Paul Mackerras, 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 + +_GLOBAL(__div64_32) + lwz r5,0(r3) # get the dividend into r5/r6 + lwz r6,4(r3) + cmplw r5,r4 + li r7,0 + li r8,0 + blt 1f + divwu r7,r5,r4 # if dividend.hi >= divisor, + mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor + subf. r5,r0,r5 # dividend.hi %= divisor + beq 3f +1: mr r11,r5 # here dividend.hi != 0 + andis. r0,r5,0xc000 + bne 2f + cntlzw r0,r5 # we are shifting the dividend right + li r10,-1 # to make it < 2^32, and shifting + srw r10,r10,r0 # the divisor right the same amount, + add r9,r4,r10 # rounding up (so the estimate cannot + andc r11,r6,r10 # ever be too large, only too small) + andc r9,r9,r10 + or r11,r5,r11 + rotlw r9,r9,r0 + rotlw r11,r11,r0 + divwu r11,r11,r9 # then we divide the shifted quantities +2: mullw r10,r11,r4 # to get an estimate of the quotient, + mulhwu r9,r11,r4 # multiply the estimate by the divisor, + subfc r6,r10,r6 # take the product from the divisor, + add r8,r8,r11 # and add the estimate to the accumulated + subfe. r5,r9,r5 # quotient + bne 1b +3: cmplw r6,r4 + blt 4f + divwu r0,r6,r4 # perform the remaining 32-bit division + mullw r10,r0,r4 # and get the remainder + add r8,r8,r0 + subf r6,r10,r6 +4: stw r7,0(r3) # return the quotient in *r3 + stw r8,4(r3) + mr r3,r6 # return the remainder in r3 + blr diff --git a/arch/powerpc/lib/e2a.c b/arch/powerpc/lib/e2a.c new file mode 100644 index 000000000000..d2b834887920 --- /dev/null +++ b/arch/powerpc/lib/e2a.c @@ -0,0 +1,108 @@ +/* + * arch/ppc64/lib/e2a.c + * + * EBCDIC to ASCII conversion + * + * This function moved here from arch/ppc64/kernel/viopath.c + * + * (C) Copyright 2000-2004 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) anyu 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 + +unsigned char e2a(unsigned char x) +{ + switch (x) { + case 0xF0: + return '0'; + case 0xF1: + return '1'; + case 0xF2: + return '2'; + case 0xF3: + return '3'; + case 0xF4: + return '4'; + case 0xF5: + return '5'; + case 0xF6: + return '6'; + case 0xF7: + return '7'; + case 0xF8: + return '8'; + case 0xF9: + return '9'; + case 0xC1: + return 'A'; + case 0xC2: + return 'B'; + case 0xC3: + return 'C'; + case 0xC4: + return 'D'; + case 0xC5: + return 'E'; + case 0xC6: + return 'F'; + case 0xC7: + return 'G'; + case 0xC8: + return 'H'; + case 0xC9: + return 'I'; + case 0xD1: + return 'J'; + case 0xD2: + return 'K'; + case 0xD3: + return 'L'; + case 0xD4: + return 'M'; + case 0xD5: + return 'N'; + case 0xD6: + return 'O'; + case 0xD7: + return 'P'; + case 0xD8: + return 'Q'; + case 0xD9: + return 'R'; + case 0xE2: + return 'S'; + case 0xE3: + return 'T'; + case 0xE4: + return 'U'; + case 0xE5: + return 'V'; + case 0xE6: + return 'W'; + case 0xE7: + return 'X'; + case 0xE8: + return 'Y'; + case 0xE9: + return 'Z'; + } + return ' '; +} +EXPORT_SYMBOL(e2a); + + diff --git a/arch/powerpc/lib/memcpy.S b/arch/powerpc/lib/memcpy.S new file mode 100644 index 000000000000..9ccacdf5bcb9 --- /dev/null +++ b/arch/powerpc/lib/memcpy.S @@ -0,0 +1,172 @@ +/* + * arch/ppc64/lib/memcpy.S + * + * Copyright (C) 2002 Paul Mackerras, 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 + + .align 7 +_GLOBAL(memcpy) + mtcrf 0x01,r5 + cmpldi cr1,r5,16 + neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry + andi. r6,r6,7 + dcbt 0,r4 + blt cr1,.Lshort_copy + bne .Ldst_unaligned +.Ldst_aligned: + andi. r0,r4,7 + addi r3,r3,-16 + bne .Lsrc_unaligned + srdi r7,r5,4 + ld r9,0(r4) + addi r4,r4,-8 + mtctr r7 + andi. r5,r5,7 + bf cr7*4+0,2f + addi r3,r3,8 + addi r4,r4,8 + mr r8,r9 + blt cr1,3f +1: ld r9,8(r4) + std r8,8(r3) +2: ldu r8,16(r4) + stdu r9,16(r3) + bdnz 1b +3: std r8,8(r3) + beqlr + addi r3,r3,16 + ld r9,8(r4) +.Ldo_tail: + bf cr7*4+1,1f + rotldi r9,r9,32 + stw r9,0(r3) + addi r3,r3,4 +1: bf cr7*4+2,2f + rotldi r9,r9,16 + sth r9,0(r3) + addi r3,r3,2 +2: bf cr7*4+3,3f + rotldi r9,r9,8 + stb r9,0(r3) +3: blr + +.Lsrc_unaligned: + srdi r6,r5,3 + addi r5,r5,-16 + subf r4,r0,r4 + srdi r7,r5,4 + sldi r10,r0,3 + cmpdi cr6,r6,3 + andi. r5,r5,7 + mtctr r7 + subfic r11,r10,64 + add r5,r5,r0 + + bt cr7*4+0,0f + + ld r9,0(r4) # 3+2n loads, 2+2n stores + ld r0,8(r4) + sld r6,r9,r10 + ldu r9,16(r4) + srd r7,r0,r11 + sld r8,r0,r10 + or r7,r7,r6 + blt cr6,4f + ld r0,8(r4) + # s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12 + b 2f + +0: ld r0,0(r4) # 4+2n loads, 3+2n stores + ldu r9,8(r4) + sld r8,r0,r10 + addi r3,r3,-8 + blt cr6,5f + ld r0,8(r4) + srd r12,r9,r11 + sld r6,r9,r10 + ldu r9,16(r4) + or r12,r8,r12 + srd r7,r0,r11 + sld r8,r0,r10 + addi r3,r3,16 + beq cr6,3f + + # d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9 +1: or r7,r7,r6 + ld r0,8(r4) + std r12,8(r3) +2: srd r12,r9,r11 + sld r6,r9,r10 + ldu r9,16(r4) + or r12,r8,r12 + stdu r7,16(r3) + srd r7,r0,r11 + sld r8,r0,r10 + bdnz 1b + +3: std r12,8(r3) + or r7,r7,r6 +4: std r7,16(r3) +5: srd r12,r9,r11 + or r12,r8,r12 + std r12,24(r3) + beqlr + cmpwi cr1,r5,8 + addi r3,r3,32 + sld r9,r9,r10 + ble cr1,.Ldo_tail + ld r0,8(r4) + srd r7,r0,r11 + or r9,r7,r9 + b .Ldo_tail + +.Ldst_unaligned: + mtcrf 0x01,r6 # put #bytes to 8B bdry into cr7 + subf r5,r6,r5 + li r7,0 + cmpldi r1,r5,16 + bf cr7*4+3,1f + lbz r0,0(r4) + stb r0,0(r3) + addi r7,r7,1 +1: bf cr7*4+2,2f + lhzx r0,r7,r4 + sthx r0,r7,r3 + addi r7,r7,2 +2: bf cr7*4+1,3f + lwzx r0,r7,r4 + stwx r0,r7,r3 +3: mtcrf 0x01,r5 + add r4,r6,r4 + add r3,r6,r3 + b .Ldst_aligned + +.Lshort_copy: + bf cr7*4+0,1f + lwz r0,0(r4) + lwz r9,4(r4) + addi r4,r4,8 + stw r0,0(r3) + stw r9,4(r3) + addi r3,r3,8 +1: bf cr7*4+1,2f + lwz r0,0(r4) + addi r4,r4,4 + stw r0,0(r3) + addi r3,r3,4 +2: bf cr7*4+2,3f + lhz r0,0(r4) + addi r4,r4,2 + sth r0,0(r3) + addi r3,r3,2 +3: bf cr7*4+3,4f + lbz r0,0(r4) + stb r0,0(r3) +4: blr diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c new file mode 100644 index 000000000000..42c5de2c898f --- /dev/null +++ b/arch/powerpc/lib/rheap.c @@ -0,0 +1,693 @@ +/* + * arch/ppc/syslib/rheap.c + * + * A Remote Heap. Remote means that we don't touch the memory that the + * heap points to. Normal heap implementations use the memory they manage + * to place their list. We cannot do that because the memory we manage may + * have special properties, for example it is uncachable or of different + * endianess. + * + * Author: Pantelis Antoniou + * + * 2004 (c) INTRACOM S.A. Greece. 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 + +/* + * Fixup a list_head, needed when copying lists. If the pointers fall + * between s and e, apply the delta. This assumes that + * sizeof(struct list_head *) == sizeof(unsigned long *). + */ +static inline void fixup(unsigned long s, unsigned long e, int d, + struct list_head *l) +{ + unsigned long *pp; + + pp = (unsigned long *)&l->next; + if (*pp >= s && *pp < e) + *pp += d; + + pp = (unsigned long *)&l->prev; + if (*pp >= s && *pp < e) + *pp += d; +} + +/* Grow the allocated blocks */ +static int grow(rh_info_t * info, int max_blocks) +{ + rh_block_t *block, *blk; + int i, new_blocks; + int delta; + unsigned long blks, blke; + + if (max_blocks <= info->max_blocks) + return -EINVAL; + + new_blocks = max_blocks - info->max_blocks; + + block = kmalloc(sizeof(rh_block_t) * max_blocks, GFP_KERNEL); + if (block == NULL) + return -ENOMEM; + + if (info->max_blocks > 0) { + + /* copy old block area */ + memcpy(block, info->block, + sizeof(rh_block_t) * info->max_blocks); + + delta = (char *)block - (char *)info->block; + + /* and fixup list pointers */ + blks = (unsigned long)info->block; + blke = (unsigned long)(info->block + info->max_blocks); + + for (i = 0, blk = block; i < info->max_blocks; i++, blk++) + fixup(blks, blke, delta, &blk->list); + + fixup(blks, blke, delta, &info->empty_list); + fixup(blks, blke, delta, &info->free_list); + fixup(blks, blke, delta, &info->taken_list); + + /* free the old allocated memory */ + if ((info->flags & RHIF_STATIC_BLOCK) == 0) + kfree(info->block); + } + + info->block = block; + info->empty_slots += new_blocks; + info->max_blocks = max_blocks; + info->flags &= ~RHIF_STATIC_BLOCK; + + /* add all new blocks to the free list */ + for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++) + list_add(&blk->list, &info->empty_list); + + return 0; +} + +/* + * Assure at least the required amount of empty slots. If this function + * causes a grow in the block area then all pointers kept to the block + * area are invalid! + */ +static int assure_empty(rh_info_t * info, int slots) +{ + int max_blocks; + + /* This function is not meant to be used to grow uncontrollably */ + if (slots >= 4) + return -EINVAL; + + /* Enough space */ + if (info->empty_slots >= slots) + return 0; + + /* Next 16 sized block */ + max_blocks = ((info->max_blocks + slots) + 15) & ~15; + + return grow(info, max_blocks); +} + +static rh_block_t *get_slot(rh_info_t * info) +{ + rh_block_t *blk; + + /* If no more free slots, and failure to extend. */ + /* XXX: You should have called assure_empty before */ + if (info->empty_slots == 0) { + printk(KERN_ERR "rh: out of slots; crash is imminent.\n"); + return NULL; + } + + /* Get empty slot to use */ + blk = list_entry(info->empty_list.next, rh_block_t, list); + list_del_init(&blk->list); + info->empty_slots--; + + /* Initialize */ + blk->start = NULL; + blk->size = 0; + blk->owner = NULL; + + return blk; +} + +static inline void release_slot(rh_info_t * info, rh_block_t * blk) +{ + list_add(&blk->list, &info->empty_list); + info->empty_slots++; +} + +static void attach_free_block(rh_info_t * info, rh_block_t * blkn) +{ + rh_block_t *blk; + rh_block_t *before; + rh_block_t *after; + rh_block_t *next; + int size; + unsigned long s, e, bs, be; + struct list_head *l; + + /* We assume that they are aligned properly */ + size = blkn->size; + s = (unsigned long)blkn->start; + e = s + size; + + /* Find the blocks immediately before and after the given one + * (if any) */ + before = NULL; + after = NULL; + next = NULL; + + list_for_each(l, &info->free_list) { + blk = list_entry(l, rh_block_t, list); + + bs = (unsigned long)blk->start; + be = bs + blk->size; + + if (next == NULL && s >= bs) + next = blk; + + if (be == s) + before = blk; + + if (e == bs) + after = blk; + + /* If both are not null, break now */ + if (before != NULL && after != NULL) + break; + } + + /* Now check if they are really adjacent */ + if (before != NULL && s != (unsigned long)before->start + before->size) + before = NULL; + + if (after != NULL && e != (unsigned long)after->start) + after = NULL; + + /* No coalescing; list insert and return */ + if (before == NULL && after == NULL) { + + if (next != NULL) + list_add(&blkn->list, &next->list); + else + list_add(&blkn->list, &info->free_list); + + return; + } + + /* We don't need it anymore */ + release_slot(info, blkn); + + /* Grow the before block */ + if (before != NULL && after == NULL) { + before->size += size; + return; + } + + /* Grow the after block backwards */ + if (before == NULL && after != NULL) { + after->start = (int8_t *)after->start - size; + after->size += size; + return; + } + + /* Grow the before block, and release the after block */ + before->size += size + after->size; + list_del(&after->list); + release_slot(info, after); +} + +static void attach_taken_block(rh_info_t * info, rh_block_t * blkn) +{ + rh_block_t *blk; + struct list_head *l; + + /* Find the block immediately before the given one (if any) */ + list_for_each(l, &info->taken_list) { + blk = list_entry(l, rh_block_t, list); + if (blk->start > blkn->start) { + list_add_tail(&blkn->list, &blk->list); + return; + } + } + + list_add_tail(&blkn->list, &info->taken_list); +} + +/* + * Create a remote heap dynamically. Note that no memory for the blocks + * are allocated. It will upon the first allocation + */ +rh_info_t *rh_create(unsigned int alignment) +{ + rh_info_t *info; + + /* Alignment must be a power of two */ + if ((alignment & (alignment - 1)) != 0) + return ERR_PTR(-EINVAL); + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + return ERR_PTR(-ENOMEM); + + info->alignment = alignment; + + /* Initially everything as empty */ + info->block = NULL; + info->max_blocks = 0; + info->empty_slots = 0; + info->flags = 0; + + INIT_LIST_HEAD(&info->empty_list); + INIT_LIST_HEAD(&info->free_list); + INIT_LIST_HEAD(&info->taken_list); + + return info; +} + +/* + * Destroy a dynamically created remote heap. Deallocate only if the areas + * are not static + */ +void rh_destroy(rh_info_t * info) +{ + if ((info->flags & RHIF_STATIC_BLOCK) == 0 && info->block != NULL) + kfree(info->block); + + if ((info->flags & RHIF_STATIC_INFO) == 0) + kfree(info); +} + +/* + * Initialize in place a remote heap info block. This is needed to support + * operation very early in the startup of the kernel, when it is not yet safe + * to call kmalloc. + */ +void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks, + rh_block_t * block) +{ + int i; + rh_block_t *blk; + + /* Alignment must be a power of two */ + if ((alignment & (alignment - 1)) != 0) + return; + + info->alignment = alignment; + + /* Initially everything as empty */ + info->block = block; + info->max_blocks = max_blocks; + info->empty_slots = max_blocks; + info->flags = RHIF_STATIC_INFO | RHIF_STATIC_BLOCK; + + INIT_LIST_HEAD(&info->empty_list); + INIT_LIST_HEAD(&info->free_list); + INIT_LIST_HEAD(&info->taken_list); + + /* Add all new blocks to the free list */ + for (i = 0, blk = block; i < max_blocks; i++, blk++) + list_add(&blk->list, &info->empty_list); +} + +/* Attach a free memory region, coalesces regions if adjuscent */ +int rh_attach_region(rh_info_t * info, void *start, int size) +{ + rh_block_t *blk; + unsigned long s, e, m; + int r; + + /* The region must be aligned */ + s = (unsigned long)start; + e = s + size; + m = info->alignment - 1; + + /* Round start up */ + s = (s + m) & ~m; + + /* Round end down */ + e = e & ~m; + + /* Take final values */ + start = (void *)s; + size = (int)(e - s); + + /* Grow the blocks, if needed */ + r = assure_empty(info, 1); + if (r < 0) + return r; + + blk = get_slot(info); + blk->start = start; + blk->size = size; + blk->owner = NULL; + + attach_free_block(info, blk); + + return 0; +} + +/* Detatch given address range, splits free block if needed. */ +void *rh_detach_region(rh_info_t * info, void *start, int size) +{ + struct list_head *l; + rh_block_t *blk, *newblk; + unsigned long s, e, m, bs, be; + + /* Validate size */ + if (size <= 0) + return ERR_PTR(-EINVAL); + + /* The region must be aligned */ + s = (unsigned long)start; + e = s + size; + m = info->alignment - 1; + + /* Round start up */ + s = (s + m) & ~m; + + /* Round end down */ + e = e & ~m; + + if (assure_empty(info, 1) < 0) + return ERR_PTR(-ENOMEM); + + blk = NULL; + list_for_each(l, &info->free_list) { + blk = list_entry(l, rh_block_t, list); + /* The range must lie entirely inside one free block */ + bs = (unsigned long)blk->start; + be = (unsigned long)blk->start + blk->size; + if (s >= bs && e <= be) + break; + blk = NULL; + } + + if (blk == NULL) + return ERR_PTR(-ENOMEM); + + /* Perfect fit */ + if (bs == s && be == e) { + /* Delete from free list, release slot */ + list_del(&blk->list); + release_slot(info, blk); + return (void *)s; + } + + /* blk still in free list, with updated start and/or size */ + if (bs == s || be == e) { + if (bs == s) + blk->start = (int8_t *)blk->start + size; + blk->size -= size; + + } else { + /* The front free fragment */ + blk->size = s - bs; + + /* the back free fragment */ + newblk = get_slot(info); + newblk->start = (void *)e; + newblk->size = be - e; + + list_add(&newblk->list, &blk->list); + } + + return (void *)s; +} + +void *rh_alloc(rh_info_t * info, int size, const char *owner) +{ + struct list_head *l; + rh_block_t *blk; + rh_block_t *newblk; + void *start; + + /* Validate size */ + if (size <= 0) + return ERR_PTR(-EINVAL); + + /* Align to configured alignment */ + size = (size + (info->alignment - 1)) & ~(info->alignment - 1); + + if (assure_empty(info, 1) < 0) + return ERR_PTR(-ENOMEM); + + blk = NULL; + list_for_each(l, &info->free_list) { + blk = list_entry(l, rh_block_t, list); + if (size <= blk->size) + break; + blk = NULL; + } + + if (blk == NULL) + return ERR_PTR(-ENOMEM); + + /* Just fits */ + if (blk->size == size) { + /* Move from free list to taken list */ + list_del(&blk->list); + blk->owner = owner; + start = blk->start; + + attach_taken_block(info, blk); + + return start; + } + + newblk = get_slot(info); + newblk->start = blk->start; + newblk->size = size; + newblk->owner = owner; + + /* blk still in free list, with updated start, size */ + blk->start = (int8_t *)blk->start + size; + blk->size -= size; + + start = newblk->start; + + attach_taken_block(info, newblk); + + return start; +} + +/* allocate at precisely the given address */ +void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner) +{ + struct list_head *l; + rh_block_t *blk, *newblk1, *newblk2; + unsigned long s, e, m, bs, be; + + /* Validate size */ + if (size <= 0) + return ERR_PTR(-EINVAL); + + /* The region must be aligned */ + s = (unsigned long)start; + e = s + size; + m = info->alignment - 1; + + /* Round start up */ + s = (s + m) & ~m; + + /* Round end down */ + e = e & ~m; + + if (assure_empty(info, 2) < 0) + return ERR_PTR(-ENOMEM); + + blk = NULL; + list_for_each(l, &info->free_list) { + blk = list_entry(l, rh_block_t, list); + /* The range must lie entirely inside one free block */ + bs = (unsigned long)blk->start; + be = (unsigned long)blk->start + blk->size; + if (s >= bs && e <= be) + break; + } + + if (blk == NULL) + return ERR_PTR(-ENOMEM); + + /* Perfect fit */ + if (bs == s && be == e) { + /* Move from free list to taken list */ + list_del(&blk->list); + blk->owner = owner; + + start = blk->start; + attach_taken_block(info, blk); + + return start; + + } + + /* blk still in free list, with updated start and/or size */ + if (bs == s || be == e) { + if (bs == s) + blk->start = (int8_t *)blk->start + size; + blk->size -= size; + + } else { + /* The front free fragment */ + blk->size = s - bs; + + /* The back free fragment */ + newblk2 = get_slot(info); + newblk2->start = (void *)e; + newblk2->size = be - e; + + list_add(&newblk2->list, &blk->list); + } + + newblk1 = get_slot(info); + newblk1->start = (void *)s; + newblk1->size = e - s; + newblk1->owner = owner; + + start = newblk1->start; + attach_taken_block(info, newblk1); + + return start; +} + +int rh_free(rh_info_t * info, void *start) +{ + rh_block_t *blk, *blk2; + struct list_head *l; + int size; + + /* Linear search for block */ + blk = NULL; + list_for_each(l, &info->taken_list) { + blk2 = list_entry(l, rh_block_t, list); + if (start < blk2->start) + break; + blk = blk2; + } + + if (blk == NULL || start > (blk->start + blk->size)) + return -EINVAL; + + /* Remove from taken list */ + list_del(&blk->list); + + /* Get size of freed block */ + size = blk->size; + attach_free_block(info, blk); + + return size; +} + +int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats) +{ + rh_block_t *blk; + struct list_head *l; + struct list_head *h; + int nr; + + switch (what) { + + case RHGS_FREE: + h = &info->free_list; + break; + + case RHGS_TAKEN: + h = &info->taken_list; + break; + + default: + return -EINVAL; + } + + /* Linear search for block */ + nr = 0; + list_for_each(l, h) { + blk = list_entry(l, rh_block_t, list); + if (stats != NULL && nr < max_stats) { + stats->start = blk->start; + stats->size = blk->size; + stats->owner = blk->owner; + stats++; + } + nr++; + } + + return nr; +} + +int rh_set_owner(rh_info_t * info, void *start, const char *owner) +{ + rh_block_t *blk, *blk2; + struct list_head *l; + int size; + + /* Linear search for block */ + blk = NULL; + list_for_each(l, &info->taken_list) { + blk2 = list_entry(l, rh_block_t, list); + if (start < blk2->start) + break; + blk = blk2; + } + + if (blk == NULL || start > (blk->start + blk->size)) + return -EINVAL; + + blk->owner = owner; + size = blk->size; + + return size; +} + +void rh_dump(rh_info_t * info) +{ + static rh_stats_t st[32]; /* XXX maximum 32 blocks */ + int maxnr; + int i, nr; + + maxnr = sizeof(st) / sizeof(st[0]); + + printk(KERN_INFO + "info @0x%p (%d slots empty / %d max)\n", + info, info->empty_slots, info->max_blocks); + + printk(KERN_INFO " Free:\n"); + nr = rh_get_stats(info, RHGS_FREE, maxnr, st); + if (nr > maxnr) + nr = maxnr; + for (i = 0; i < nr; i++) + printk(KERN_INFO + " 0x%p-0x%p (%u)\n", + st[i].start, (int8_t *) st[i].start + st[i].size, + st[i].size); + printk(KERN_INFO "\n"); + + printk(KERN_INFO " Taken:\n"); + nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st); + if (nr > maxnr) + nr = maxnr; + for (i = 0; i < nr; i++) + printk(KERN_INFO + " 0x%p-0x%p (%u) %s\n", + st[i].start, (int8_t *) st[i].start + st[i].size, + st[i].size, st[i].owner != NULL ? st[i].owner : ""); + printk(KERN_INFO "\n"); +} + +void rh_dump_blk(rh_info_t * info, rh_block_t * blk) +{ + printk(KERN_INFO + "blk @0x%p: 0x%p-0x%p (%u)\n", + blk, blk->start, (int8_t *) blk->start + blk->size, blk->size); +} diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c new file mode 100644 index 000000000000..e79123d1485c --- /dev/null +++ b/arch/powerpc/lib/sstep.c @@ -0,0 +1,141 @@ +/* + * Single-step support. + * + * Copyright (C) 2004 Paul Mackerras , IBM + * + * 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 + +extern char system_call_common[]; + +/* Bits in SRR1 that are copied from MSR */ +#define MSR_MASK 0xffffffff87c0ffff + +/* + * Determine whether a conditional branch instruction would branch. + */ +static int branch_taken(unsigned int instr, struct pt_regs *regs) +{ + unsigned int bo = (instr >> 21) & 0x1f; + unsigned int bi; + + if ((bo & 4) == 0) { + /* decrement counter */ + --regs->ctr; + if (((bo >> 1) & 1) ^ (regs->ctr == 0)) + return 0; + } + if ((bo & 0x10) == 0) { + /* check bit from CR */ + bi = (instr >> 16) & 0x1f; + if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1)) + return 0; + } + return 1; +} + +/* + * Emulate instructions that cause a transfer of control. + * Returns 1 if the step was emulated, 0 if not, + * or -1 if the instruction is one that should not be stepped, + * such as an rfid, or a mtmsrd that would clear MSR_RI. + */ +int emulate_step(struct pt_regs *regs, unsigned int instr) +{ + unsigned int opcode, rd; + unsigned long int imm; + + opcode = instr >> 26; + switch (opcode) { + case 16: /* bc */ + imm = (signed short)(instr & 0xfffc); + if ((instr & 2) == 0) + imm += regs->nip; + regs->nip += 4; + if ((regs->msr & MSR_SF) == 0) + regs->nip &= 0xffffffffUL; + if (instr & 1) + regs->link = regs->nip; + if (branch_taken(instr, regs)) + regs->nip = imm; + return 1; + case 17: /* sc */ + /* + * N.B. this uses knowledge about how the syscall + * entry code works. If that is changed, this will + * need to be changed also. + */ + regs->gpr[9] = regs->gpr[13]; + regs->gpr[11] = regs->nip + 4; + regs->gpr[12] = regs->msr & MSR_MASK; + regs->gpr[13] = (unsigned long) get_paca(); + regs->nip = (unsigned long) &system_call_common; + regs->msr = MSR_KERNEL; + return 1; + case 18: /* b */ + imm = instr & 0x03fffffc; + if (imm & 0x02000000) + imm -= 0x04000000; + if ((instr & 2) == 0) + imm += regs->nip; + if (instr & 1) { + regs->link = regs->nip + 4; + if ((regs->msr & MSR_SF) == 0) + regs->link &= 0xffffffffUL; + } + if ((regs->msr & MSR_SF) == 0) + imm &= 0xffffffffUL; + regs->nip = imm; + return 1; + case 19: + switch (instr & 0x7fe) { + case 0x20: /* bclr */ + case 0x420: /* bcctr */ + imm = (instr & 0x400)? regs->ctr: regs->link; + regs->nip += 4; + if ((regs->msr & MSR_SF) == 0) { + regs->nip &= 0xffffffffUL; + imm &= 0xffffffffUL; + } + if (instr & 1) + regs->link = regs->nip; + if (branch_taken(instr, regs)) + regs->nip = imm; + return 1; + case 0x24: /* rfid, scary */ + return -1; + } + case 31: + rd = (instr >> 21) & 0x1f; + switch (instr & 0x7fe) { + case 0xa6: /* mfmsr */ + regs->gpr[rd] = regs->msr & MSR_MASK; + regs->nip += 4; + if ((regs->msr & MSR_SF) == 0) + regs->nip &= 0xffffffffUL; + return 1; + case 0x164: /* mtmsrd */ + /* only MSR_EE and MSR_RI get changed if bit 15 set */ + /* mtmsrd doesn't change MSR_HV and MSR_ME */ + imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL; + imm = (regs->msr & MSR_MASK & ~imm) + | (regs->gpr[rd] & imm); + if ((imm & MSR_RI) == 0) + /* can't step mtmsrd that would clear MSR_RI */ + return -1; + regs->msr = imm; + regs->nip += 4; + if ((imm & MSR_SF) == 0) + regs->nip &= 0xffffffffUL; + return 1; + } + } + return 0; +} diff --git a/arch/powerpc/lib/strcase.c b/arch/powerpc/lib/strcase.c new file mode 100644 index 000000000000..36b521091bbc --- /dev/null +++ b/arch/powerpc/lib/strcase.c @@ -0,0 +1,23 @@ +#include + +int strcasecmp(const char *s1, const char *s2) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 == c2 && c1 != 0); + return c1 - c2; +} + +int strncasecmp(const char *s1, const char *s2, int n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S new file mode 100644 index 000000000000..15d40e9ef8b1 --- /dev/null +++ b/arch/powerpc/lib/string.S @@ -0,0 +1,203 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * 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 + + .text + .stabs "arch/powerpc/lib/",N_SO,0,0,0f + .stabs "string.S",N_SO,0,0,0f +0: + + .section __ex_table,"a" +#ifdef CONFIG_PPC64 + .align 3 +#define EXTBL .llong +#else + .align 2 +#define EXTBL .long +#endif + .text + +_GLOBAL(strcpy) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + +/* This clears out any unused part of the destination buffer, + just as the libc version does. -- paulus */ +_GLOBAL(strncpy) + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + bnelr /* if we didn't hit a null char, we're done */ + mfctr r5 + cmpwi 0,r5,0 /* any space left in destination buffer? */ + beqlr /* we know r0 == 0 here */ +2: stbu r0,1(r6) /* clear it out if so */ + bdnz 2b + blr + +_GLOBAL(strcat) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + +_GLOBAL(strcmp) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + +_GLOBAL(strlen) + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + +_GLOBAL(memcmp) + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr +2: li r3,0 + blr + +_GLOBAL(memchr) + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r3,r3,-1 +1: lbzu r0,1(r3) + cmpw 0,r0,r4 + bdnzf 2,1b + beqlr +2: li r3,0 + blr + +_GLOBAL(__clear_user) + addi r6,r3,-4 + li r3,0 + li r5,0 + cmplwi 0,r4,4 + blt 7f + /* clear a single word */ +11: stwu r5,4(r6) + beqlr + /* clear word sized chunks */ + andi. r0,r6,3 + add r4,r0,r4 + subf r6,r0,r6 + srwi r0,r4,2 + andi. r4,r4,3 + mtctr r0 + bdz 7f +1: stwu r5,4(r6) + bdnz 1b + /* clear byte sized chunks */ +7: cmpwi 0,r4,0 + beqlr + mtctr r4 + addi r6,r6,3 +8: stbu r5,1(r6) + bdnz 8b + blr +90: mr r3,r4 + blr +91: mfctr r3 + slwi r3,r3,2 + add r3,r3,r4 + blr +92: mfctr r3 + blr + + .section __ex_table,"a" + EXTBL 11b,90b + EXTBL 1b,91b + EXTBL 8b,92b + .text + +_GLOBAL(__strncpy_from_user) + addi r6,r3,-1 + addi r4,r4,-1 + cmpwi 0,r5,0 + beq 2f + mtctr r5 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + beq 3f +2: addi r6,r6,1 +3: subf r3,r3,r6 + blr +99: li r3,-EFAULT + blr + + .section __ex_table,"a" + EXTBL 1b,99b + .text + +/* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ +_GLOBAL(__strnlen_user) + addi r7,r3,-1 + subf r6,r7,r5 /* top+1 - str */ + cmplw 0,r4,r6 + bge 0f + mr r6,r4 +0: mtctr r6 /* ctr = min(len, top - str) */ +1: lbzu r0,1(r7) /* get next byte */ + cmpwi 0,r0,0 + bdnzf 2,1b /* loop if --ctr != 0 && byte != 0 */ + addi r7,r7,1 + subf r3,r3,r7 /* number of bytes we have looked at */ + beqlr /* return if we found a 0 byte */ + cmpw 0,r3,r4 /* did we look at all len bytes? */ + blt 99f /* if not, must have hit top */ + addi r3,r4,1 /* return len + 1 to indicate no null found */ + blr +99: li r3,0 /* bad address, return 0 */ + blr + + .section __ex_table,"a" + EXTBL 1b,99b diff --git a/arch/powerpc/lib/usercopy.c b/arch/powerpc/lib/usercopy.c new file mode 100644 index 000000000000..5eea6f3c1e03 --- /dev/null +++ b/arch/powerpc/lib/usercopy.c @@ -0,0 +1,41 @@ +/* + * Functions which are too large to be inlined. + * + * 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 + +unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) +{ + if (likely(access_ok(VERIFY_READ, from, n))) + n = __copy_from_user(to, from, n); + else + memset(to, 0, n); + return n; +} + +unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) +{ + if (likely(access_ok(VERIFY_WRITE, to, n))) + n = __copy_to_user(to, from, n); + return n; +} + +unsigned long copy_in_user(void __user *to, const void __user *from, + unsigned long n) +{ + might_sleep(); + if (likely(access_ok(VERIFY_READ, from, n) && + access_ok(VERIFY_WRITE, to, n))) + n =__copy_tofrom_user(to, from, n); + return n; +} + +EXPORT_SYMBOL(copy_from_user); +EXPORT_SYMBOL(copy_to_user); +EXPORT_SYMBOL(copy_in_user); + diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c new file mode 100644 index 000000000000..3d79ce281b67 --- /dev/null +++ b/arch/powerpc/mm/44x_mmu.c @@ -0,0 +1,120 @@ +/* + * Modifications by Matt Porter (mporter@mvista.com) to support + * PPC44x Book E processors. + * + * This file contains the routines for initializing the MMU + * on the 4xx series of chips. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mmu_decl.h" + +extern char etext[], _stext[]; + +/* Used by the 44x TLB replacement exception handler. + * Just needed it declared someplace. + */ +unsigned int tlb_44x_index = 0; +unsigned int tlb_44x_hwater = 62; + +/* + * "Pins" a 256MB TLB entry in AS0 for kernel lowmem + */ +static void __init +ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys) +{ + unsigned long attrib = 0; + + __asm__ __volatile__("\ + clrrwi %2,%2,10\n\ + ori %2,%2,%4\n\ + clrrwi %1,%1,10\n\ + li %0,0\n\ + ori %0,%0,%5\n\ + tlbwe %2,%3,%6\n\ + tlbwe %1,%3,%7\n\ + tlbwe %0,%3,%8" + : + : "r" (attrib), "r" (phys), "r" (virt), "r" (slot), + "i" (PPC44x_TLB_VALID | PPC44x_TLB_256M), + "i" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), + "i" (PPC44x_TLB_PAGEID), + "i" (PPC44x_TLB_XLAT), + "i" (PPC44x_TLB_ATTRIB)); +} + +/* + * MMU_init_hw does the chip-specific initialization of the MMU hardware. + */ +void __init MMU_init_hw(void) +{ + flush_instruction_cache(); +} + +unsigned long __init mmu_mapin_ram(void) +{ + unsigned int pinned_tlbs = 1; + int i; + + /* Determine number of entries necessary to cover lowmem */ + pinned_tlbs = (unsigned int) + (_ALIGN(total_lowmem, PPC44x_PIN_SIZE) >> PPC44x_PIN_SHIFT); + + /* Write upper watermark to save location */ + tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs; + + /* If necessary, set additional pinned TLBs */ + if (pinned_tlbs > 1) + for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) { + unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC44x_PIN_SIZE; + ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr); + } + + return total_lowmem; +} diff --git a/arch/powerpc/mm/4xx_mmu.c b/arch/powerpc/mm/4xx_mmu.c new file mode 100644 index 000000000000..b7bcbc232f39 --- /dev/null +++ b/arch/powerpc/mm/4xx_mmu.c @@ -0,0 +1,141 @@ +/* + * This file contains the routines for initializing the MMU + * on the 4xx series of chips. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mmu_decl.h" + +extern int __map_without_ltlbs; +/* + * MMU_init_hw does the chip-specific initialization of the MMU hardware. + */ +void __init MMU_init_hw(void) +{ + /* + * The Zone Protection Register (ZPR) defines how protection will + * be applied to every page which is a member of a given zone. At + * present, we utilize only two of the 4xx's zones. + * The zone index bits (of ZSEL) in the PTE are used for software + * indicators, except the LSB. For user access, zone 1 is used, + * for kernel access, zone 0 is used. We set all but zone 1 + * to zero, allowing only kernel access as indicated in the PTE. + * For zone 1, we set a 01 binary (a value of 10 will not work) + * to allow user access as indicated in the PTE. This also allows + * kernel access as indicated in the PTE. + */ + + mtspr(SPRN_ZPR, 0x10000000); + + flush_instruction_cache(); + + /* + * Set up the real-mode cache parameters for the exception vector + * handlers (which are run in real-mode). + */ + + mtspr(SPRN_DCWR, 0x00000000); /* All caching is write-back */ + + /* + * Cache instruction and data space where the exception + * vectors and the kernel live in real-mode. + */ + + mtspr(SPRN_DCCR, 0xF0000000); /* 512 MB of data space at 0x0. */ + mtspr(SPRN_ICCR, 0xF0000000); /* 512 MB of instr. space at 0x0. */ +} + +#define LARGE_PAGE_SIZE_16M (1<<24) +#define LARGE_PAGE_SIZE_4M (1<<22) + +unsigned long __init mmu_mapin_ram(void) +{ + unsigned long v, s; + phys_addr_t p; + + v = KERNELBASE; + p = PPC_MEMSTART; + s = 0; + + if (__map_without_ltlbs) { + return s; + } + + while (s <= (total_lowmem - LARGE_PAGE_SIZE_16M)) { + pmd_t *pmdp; + unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE; + + spin_lock(&init_mm.page_table_lock); + pmdp = pmd_offset(pgd_offset_k(v), v); + pmd_val(*pmdp++) = val; + pmd_val(*pmdp++) = val; + pmd_val(*pmdp++) = val; + pmd_val(*pmdp++) = val; + spin_unlock(&init_mm.page_table_lock); + + v += LARGE_PAGE_SIZE_16M; + p += LARGE_PAGE_SIZE_16M; + s += LARGE_PAGE_SIZE_16M; + } + + while (s <= (total_lowmem - LARGE_PAGE_SIZE_4M)) { + pmd_t *pmdp; + unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE; + + spin_lock(&init_mm.page_table_lock); + pmdp = pmd_offset(pgd_offset_k(v), v); + pmd_val(*pmdp) = val; + spin_unlock(&init_mm.page_table_lock); + + v += LARGE_PAGE_SIZE_4M; + p += LARGE_PAGE_SIZE_4M; + s += LARGE_PAGE_SIZE_4M; + } + + return s; +} diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile new file mode 100644 index 000000000000..9f52c26acd86 --- /dev/null +++ b/arch/powerpc/mm/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the linux ppc-specific parts of the memory manager. +# + +obj-y := fault.o mem.o +obj-$(CONFIG_PPC32) += init.o pgtable.o mmu_context.o \ + mem_pieces.o tlb.o +obj-$(CONFIG_PPC64) += init64.o pgtable64.o mmu_context64.o +obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu.o hash_32.o +obj-$(CONFIG_40x) += 4xx_mmu.o +obj-$(CONFIG_44x) += 44x_mmu.o +obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c new file mode 100644 index 000000000000..3df641fa789d --- /dev/null +++ b/arch/powerpc/mm/fault.c @@ -0,0 +1,391 @@ +/* + * arch/ppc/mm/fault.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/i386/mm/fault.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Modified by Cort Dougan and Paul Mackerras. + * + * Modified for PPC64 by Dave Engebretsen (engebret@ibm.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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Check whether the instruction at regs->nip is a store using + * an update addressing form which will update r1. + */ +static int store_updates_sp(struct pt_regs *regs) +{ + unsigned int inst; + + if (get_user(inst, (unsigned int __user *)regs->nip)) + return 0; + /* check for 1 in the rA field */ + if (((inst >> 16) & 0x1f) != 1) + return 0; + /* check major opcode */ + switch (inst >> 26) { + case 37: /* stwu */ + case 39: /* stbu */ + case 45: /* sthu */ + case 53: /* stfsu */ + case 55: /* stfdu */ + return 1; + case 62: /* std or stdu */ + return (inst & 3) == 1; + case 31: + /* check minor opcode */ + switch ((inst >> 1) & 0x3ff) { + case 181: /* stdux */ + case 183: /* stwux */ + case 247: /* stbux */ + case 439: /* sthux */ + case 695: /* stfsux */ + case 759: /* stfdux */ + return 1; + } + } + return 0; +} + +static void do_dabr(struct pt_regs *regs, unsigned long error_code) +{ + siginfo_t info; + + if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, + 11, SIGSEGV) == NOTIFY_STOP) + return; + + if (debugger_dabr_match(regs)) + return; + + /* Clear the DABR */ + set_dabr(0); + + /* Deliver the signal to userspace */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + info.si_addr = (void __user *)regs->nip; + force_sig_info(SIGTRAP, &info, current); +} + +/* + * For 600- and 800-family processors, the error_code parameter is DSISR + * for a data fault, SRR1 for an instruction fault. For 400-family processors + * the error_code parameter is ESR for a data fault, 0 for an instruction + * fault. + * For 64-bit processors, the error_code parameter is + * - DSISR for a non-SLB data access fault, + * - SRR1 & 0x08000000 for a non-SLB instruction access fault + * - 0 any SLB fault. + * + * The return value is 0 if the fault was handled, or the signal + * number if this is a kernel fault that can't be handled here. + */ +int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ + struct vm_area_struct * vma; + struct mm_struct *mm = current->mm; + siginfo_t info; + int code = SEGV_MAPERR; + int is_write = 0; + int trap = TRAP(regs); + int is_exec = trap == 0x400; + +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) + /* + * Fortunately the bit assignments in SRR1 for an instruction + * fault and DSISR for a data fault are mostly the same for the + * bits we are interested in. But there are some bits which + * indicate errors in DSISR but can validly be set in SRR1. + */ + if (trap == 0x400) + error_code &= 0x48200000; + else + is_write = error_code & DSISR_ISSTORE; +#else + is_write = error_code & ESR_DST; +#endif /* CONFIG_4xx || CONFIG_BOOKE */ + + if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, error_code, + 11, SIGSEGV) == NOTIFY_STOP) + return 0; + + if (trap == 0x300) { + if (debugger_fault_handler(regs)) + return 0; + } + + /* On a kernel SLB miss we can only check for a valid exception entry */ + if (!user_mode(regs) && (address >= TASK_SIZE)) + return SIGSEGV; + +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) + if (error_code & DSISR_DABRMATCH) { + /* DABR match */ + do_dabr(regs, error_code); + return 0; + } +#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ + + if (in_atomic() || mm == NULL) { + if (!user_mode(regs)) + return SIGSEGV; + /* in_atomic() in user mode is really bad, + as is current->mm == NULL. */ + printk(KERN_EMERG "Page fault in user mode with" + "in_atomic() = %d mm = %p\n", in_atomic(), mm); + printk(KERN_EMERG "NIP = %lx MSR = %lx\n", + regs->nip, regs->msr); + die("Weird page fault", regs, SIGSEGV); + } + + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunatly, in the case of an + * erroneous fault occuring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user + * space from well defined areas of code, which are listed in the + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform + * the source reference check when there is a possibilty of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if (!user_mode(regs) && !search_exception_tables(regs->nip)) + goto bad_area_nosemaphore; + + down_read(&mm->mmap_sem); + } + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + + /* + * N.B. The POWER/Open ABI allows programs to access up to + * 288 bytes below the stack pointer. + * The kernel signal delivery code writes up to about 1.5kB + * below the stack pointer (r1) before decrementing it. + * The exec code can write slightly over 640kB to the stack + * before setting the user r1. Thus we allow the stack to + * expand to 1MB without further checks. + */ + if (address + 0x100000 < vma->vm_end) { + /* get user regs even if this fault is in kernel mode */ + struct pt_regs *uregs = current->thread.regs; + if (uregs == NULL) + goto bad_area; + + /* + * A user-mode access to an address a long way below + * the stack pointer is only valid if the instruction + * is one which would update the stack pointer to the + * address accessed if the instruction completed, + * i.e. either stwu rs,n(r1) or stwux rs,r1,rb + * (or the byte, halfword, float or double forms). + * + * If we don't check this then any write to the area + * between the last mapped region and the stack will + * expand the stack rather than segfaulting. + */ + if (address + 2048 < uregs->gpr[1] + && (!user_mode(regs) || !store_updates_sp(regs))) + goto bad_area; + } + if (expand_stack(vma, address)) + goto bad_area; + +good_area: + code = SEGV_ACCERR; +#if defined(CONFIG_6xx) + if (error_code & 0x95700000) + /* an error such as lwarx to I/O controller space, + address matching DABR, eciwx, etc. */ + goto bad_area; +#endif /* CONFIG_6xx */ +#if defined(CONFIG_8xx) + /* The MPC8xx seems to always set 0x80000000, which is + * "undefined". Of those that can be set, this is the only + * one which seems bad. + */ + if (error_code & 0x10000000) + /* Guarded storage error. */ + goto bad_area; +#endif /* CONFIG_8xx */ + + if (is_exec) { +#ifdef CONFIG_PPC64 + /* protection fault */ + if (error_code & DSISR_PROTFAULT) + goto bad_area; + if (!(vma->vm_flags & VM_EXEC)) + goto bad_area; +#endif +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + pte_t *ptep; + + /* Since 4xx/Book-E supports per-page execute permission, + * we lazily flush dcache to icache. */ + ptep = NULL; + if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) { + struct page *page = pte_page(*ptep); + + if (! test_bit(PG_arch_1, &page->flags)) { + flush_dcache_icache_page(page); + set_bit(PG_arch_1, &page->flags); + } + pte_update(ptep, 0, _PAGE_HWEXEC); + _tlbie(address); + pte_unmap(ptep); + up_read(&mm->mmap_sem); + return 0; + } + if (ptep != NULL) + pte_unmap(ptep); +#endif + /* a write */ + } else if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + /* a read */ + } else { + /* protection fault */ + if (error_code & 0x08000000) + goto bad_area; + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + survive: + switch (handle_mm_fault(mm, vma, address, is_write)) { + + case VM_FAULT_MINOR: + current->min_flt++; + break; + case VM_FAULT_MAJOR: + current->maj_flt++; + break; + case VM_FAULT_SIGBUS: + goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } + + up_read(&mm->mmap_sem); + return 0; + +bad_area: + up_read(&mm->mmap_sem); + +bad_area_nosemaphore: + /* User mode accesses cause a SIGSEGV */ + if (user_mode(regs)) { + _exception(SIGSEGV, regs, code, address); + return 0; + } + + if (is_exec && (error_code & DSISR_PROTFAULT) + && printk_ratelimit()) + printk(KERN_CRIT "kernel tried to execute NX-protected" + " page (%lx) - exploit attempt? (uid: %d)\n", + address, current->uid); + + return SIGSEGV; + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + if (current->pid == 1) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + return SIGKILL; + +do_sigbus: + up_read(&mm->mmap_sem); + if (user_mode(regs)) { + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, current); + return 0; + } + return SIGBUS; +} + +/* + * bad_page_fault is called when we have a bad access from the kernel. + * It is called from the DSI and ISI handlers in head.S and from some + * of the procedures in traps.c. + */ +void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) +{ + const struct exception_table_entry *entry; + + /* Are we prepared to handle this fault? */ + if ((entry = search_exception_tables(regs->nip)) != NULL) { + regs->nip = entry->fixup; + return; + } + + /* kernel has accessed a bad area */ + die("Kernel access of bad area", regs, sig); +} diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c new file mode 100644 index 000000000000..af9ca0eb6d55 --- /dev/null +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -0,0 +1,237 @@ +/* + * Modifications by Kumar Gala (kumar.gala@freescale.com) to support + * E500 Book E processors. + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This file contains the routines for initializing the MMU + * on the 4xx series of chips. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 + +extern void loadcam_entry(unsigned int index); +unsigned int tlbcam_index; +unsigned int num_tlbcam_entries; +static unsigned long __cam0, __cam1, __cam2; +extern unsigned long total_lowmem; +extern unsigned long __max_low_memory; +#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE + +#define NUM_TLBCAMS (16) + +struct tlbcam { + u32 MAS0; + u32 MAS1; + u32 MAS2; + u32 MAS3; + u32 MAS7; +} TLBCAM[NUM_TLBCAMS]; + +struct tlbcamrange { + unsigned long start; + unsigned long limit; + phys_addr_t phys; +} tlbcam_addrs[NUM_TLBCAMS]; + +extern unsigned int tlbcam_index; + +/* + * Return PA for this VA if it is mapped by a CAM, or 0 + */ +unsigned long v_mapped_by_tlbcam(unsigned long va) +{ + int b; + for (b = 0; b < tlbcam_index; ++b) + if (va >= tlbcam_addrs[b].start && va < tlbcam_addrs[b].limit) + return tlbcam_addrs[b].phys + (va - tlbcam_addrs[b].start); + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +unsigned long p_mapped_by_tlbcam(unsigned long pa) +{ + int b; + for (b = 0; b < tlbcam_index; ++b) + if (pa >= tlbcam_addrs[b].phys + && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) + +tlbcam_addrs[b].phys) + return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); + return 0; +} + +/* + * Set up one of the I/D BAT (block address translation) register pairs. + * The parameters are not checked; in particular size must be a power + * of 4 between 4k and 256M. + */ +void settlbcam(int index, unsigned long virt, phys_addr_t phys, + unsigned int size, int flags, unsigned int pid) +{ + unsigned int tsize, lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size)); + tsize = (21 - lz) / 2; + +#ifdef CONFIG_SMP + if ((flags & _PAGE_NO_CACHE) == 0) + flags |= _PAGE_COHERENT; +#endif + + TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1); + TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid); + TLBCAM[index].MAS2 = virt & PAGE_MASK; + + TLBCAM[index].MAS2 |= (flags & _PAGE_WRITETHRU) ? MAS2_W : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_NO_CACHE) ? MAS2_I : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_COHERENT) ? MAS2_M : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; + + TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); + +#ifndef CONFIG_KGDB /* want user access for breakpoints */ + if (flags & _PAGE_USER) { + TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); + } +#else + TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); +#endif + + tlbcam_addrs[index].start = virt; + tlbcam_addrs[index].limit = virt + size - 1; + tlbcam_addrs[index].phys = phys; + + loadcam_entry(index); +} + +void invalidate_tlbcam_entry(int index) +{ + TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index); + TLBCAM[index].MAS1 = ~MAS1_VALID; + + loadcam_entry(index); +} + +void __init cam_mapin_ram(unsigned long cam0, unsigned long cam1, + unsigned long cam2) +{ + settlbcam(0, KERNELBASE, PPC_MEMSTART, cam0, _PAGE_KERNEL, 0); + tlbcam_index++; + if (cam1) { + tlbcam_index++; + settlbcam(1, KERNELBASE+cam0, PPC_MEMSTART+cam0, cam1, _PAGE_KERNEL, 0); + } + if (cam2) { + tlbcam_index++; + settlbcam(2, KERNELBASE+cam0+cam1, PPC_MEMSTART+cam0+cam1, cam2, _PAGE_KERNEL, 0); + } +} + +/* + * MMU_init_hw does the chip-specific initialization of the MMU hardware. + */ +void __init MMU_init_hw(void) +{ + flush_instruction_cache(); +} + +unsigned long __init mmu_mapin_ram(void) +{ + cam_mapin_ram(__cam0, __cam1, __cam2); + + return __cam0 + __cam1 + __cam2; +} + + +void __init +adjust_total_lowmem(void) +{ + unsigned long max_low_mem = MAX_LOW_MEM; + unsigned long cam_max = 0x10000000; + unsigned long ram; + + /* adjust CAM size to max_low_mem */ + if (max_low_mem < cam_max) + cam_max = max_low_mem; + + /* adjust lowmem size to max_low_mem */ + if (max_low_mem < total_lowmem) + ram = max_low_mem; + else + ram = total_lowmem; + + /* Calculate CAM values */ + __cam0 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam0 > cam_max) + __cam0 = cam_max; + ram -= __cam0; + if (ram) { + __cam1 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam1 > cam_max) + __cam1 = cam_max; + ram -= __cam1; + } + if (ram) { + __cam2 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam2 > cam_max) + __cam2 = cam_max; + ram -= __cam2; + } + + printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb," + " CAM2=%ldMb residual: %ldMb\n", + __cam0 >> 20, __cam1 >> 20, __cam2 >> 20, + (total_lowmem - __cam0 - __cam1 - __cam2) >> 20); + __max_low_memory = max_low_mem = __cam0 + __cam1 + __cam2; +} diff --git a/arch/powerpc/mm/hash_32.S b/arch/powerpc/mm/hash_32.S new file mode 100644 index 000000000000..57278a8dd132 --- /dev/null +++ b/arch/powerpc/mm/hash_32.S @@ -0,0 +1,618 @@ +/* + * arch/ppc/kernel/hashtable.S + * + * $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * This file contains low-level assembler routines for managing + * the PowerPC MMU hash table. (PPC 8xx processors don't use a + * hash table, so this file is not used on them.) + * + * 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 + +#ifdef CONFIG_SMP + .comm mmu_hash_lock,4 +#endif /* CONFIG_SMP */ + +/* + * Sync CPUs with hash_page taking & releasing the hash + * table lock + */ +#ifdef CONFIG_SMP + .text +_GLOBAL(hash_page_sync) + lis r8,mmu_hash_lock@h + ori r8,r8,mmu_hash_lock@l + lis r0,0x0fff + b 10f +11: lwz r6,0(r8) + cmpwi 0,r6,0 + bne 11b +10: lwarx r6,0,r8 + cmpwi 0,r6,0 + bne- 11b + stwcx. r0,0,r8 + bne- 10b + isync + eieio + li r0,0 + stw r0,0(r8) + blr +#endif + +/* + * Load a PTE into the hash table, if possible. + * The address is in r4, and r3 contains an access flag: + * _PAGE_RW (0x400) if a write. + * r9 contains the SRR1 value, from which we use the MSR_PR bit. + * SPRG3 contains the physical address of the current task's thread. + * + * Returns to the caller if the access is illegal or there is no + * mapping for the address. Otherwise it places an appropriate PTE + * in the hash table and returns from the exception. + * Uses r0, r3 - r8, ctr, lr. + */ + .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 + ori r8,r8,mmu_hash_lock@l + lis r0,0x0fff + b 10f +11: lwz r6,0(r8) + cmpwi 0,r6,0 + bne 11b +10: lwarx r6,0,r8 + cmpwi 0,r6,0 + bne- 11b + stwcx. r0,0,r8 + bne- 10b + isync +#endif + /* Get PTE (linux-style) and check access */ + lis r0,KERNELBASE@h /* check if kernel address */ + cmplw 0,r4,r0 + mfspr r8,SPRN_SPRG3 /* current task's THREAD (phys) */ + ori r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */ + lwz r5,PGDIR(r8) /* virt page-table root */ + blt+ 112f /* assume user more likely */ + lis r5,swapper_pg_dir@ha /* if kernel address, use */ + addi r5,r5,swapper_pg_dir@l /* kernel page table */ + rlwimi r3,r9,32-12,29,29 /* MSR_PR -> _PAGE_USER */ +112: add r5,r5,r7 /* convert to phys addr */ + rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */ + lwz r8,0(r5) /* get pmd entry */ + rlwinm. r8,r8,0,0,19 /* extract address of pte page */ +#ifdef CONFIG_SMP + beq- hash_page_out /* return if no mapping */ +#else + /* XXX it seems like the 601 will give a machine fault on the + rfi if its alignment is wrong (bottom 4 bits of address are + 8 or 0xc) and we have had a not-taken conditional branch + to the address following the rfi. */ + beqlr- +#endif + rlwimi r8,r4,22,20,29 /* insert next 10 bits of address */ + rlwinm r0,r3,32-3,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ + ori r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE + + /* + * Update the linux PTE atomically. We do the lwarx up-front + * because almost always, there won't be a permission violation + * and there won't already be an HPTE, and thus we will have + * to update the PTE to set _PAGE_HASHPTE. -- paulus. + */ +retry: + lwarx r6,0,r8 /* get linux-style pte */ + andc. r5,r3,r6 /* check access & ~permission */ +#ifdef CONFIG_SMP + bne- hash_page_out /* return if access not permitted */ +#else + bnelr- +#endif + or r5,r0,r6 /* set accessed/dirty bits */ + stwcx. r5,0,r8 /* attempt to update PTE */ + bne- retry /* retry if someone got there first */ + + mfsrin r3,r4 /* get segment reg for segment */ + mfctr r0 + stw r0,_CTR(r11) + bl create_hpte /* add the hash table entry */ + +#ifdef CONFIG_SMP + eieio + addis r8,r7,mmu_hash_lock@ha + li r0,0 + stw r0,mmu_hash_lock@l(r8) +#endif + + /* Return from the exception */ + lwz r5,_CTR(r11) + mtctr r5 + lwz r0,GPR0(r11) + lwz r7,GPR7(r11) + lwz r8,GPR8(r11) + b fast_exception_return + +#ifdef CONFIG_SMP +hash_page_out: + eieio + addis r8,r7,mmu_hash_lock@ha + li r0,0 + stw r0,mmu_hash_lock@l(r8) + blr +#endif /* CONFIG_SMP */ + +/* + * Add an entry for a particular page to the hash table. + * + * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval) + * + * We assume any necessary modifications to the pte (e.g. setting + * the accessed bit) have already been done and that there is actually + * a hash table in use (i.e. we're not on a 603). + */ +_GLOBAL(add_hash_page) + mflr r0 + stw r0,4(r1) + + /* Convert context and va to VSID */ + mulli r3,r3,897*16 /* multiply context by context skew */ + rlwinm r0,r4,4,28,31 /* get ESID (top 4 bits of va) */ + mulli r0,r0,0x111 /* multiply by ESID skew */ + add r3,r3,r0 /* note create_hpte trims to 24 bits */ + +#ifdef CONFIG_SMP + rlwinm r8,r1,0,0,18 /* use cpu number to make tag */ + lwz r8,TI_CPU(r8) /* to go in mmu_hash_lock */ + oris r8,r8,12 +#endif /* CONFIG_SMP */ + + /* + * We disable interrupts here, even on UP, because we don't + * want to race with hash_page, and because we want the + * _PAGE_HASHPTE bit to be a reliable indication of whether + * the HPTE exists (or at least whether one did once). + * We also turn off the MMU for data accesses so that we + * we can't take a hash table miss (assuming the code is + * covered by a BAT). -- paulus + */ + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear MSR_DR */ + mtmsr r0 + SYNC_601 + isync + + tophys(r7,0) + +#ifdef CONFIG_SMP + addis r9,r7,mmu_hash_lock@ha + addi r9,r9,mmu_hash_lock@l +10: lwarx r0,0,r9 /* take the mmu_hash_lock */ + cmpi 0,r0,0 + bne- 11f + stwcx. r8,0,r9 + beq+ 12f +11: lwz r0,0(r9) + cmpi 0,r0,0 + beq 10b + b 11b +12: isync +#endif + + /* + * Fetch the linux pte and test and set _PAGE_HASHPTE atomically. + * If _PAGE_HASHPTE was already set, we don't replace the existing + * HPTE, so we just unlock and return. + */ + mr r8,r5 + rlwimi r8,r4,22,20,29 +1: lwarx r6,0,r8 + andi. r0,r6,_PAGE_HASHPTE + bne 9f /* if HASHPTE already set, done */ + ori r5,r6,_PAGE_HASHPTE + stwcx. r5,0,r8 + bne- 1b + + bl create_hpte + +9: +#ifdef CONFIG_SMP + eieio + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ +#endif + + /* reenable interrupts and DR */ + mtmsr r10 + SYNC_601 + isync + + lwz r0,4(r1) + mtlr r0 + blr + +/* + * This routine adds a hardware PTE to the hash table. + * It is designed to be called with the MMU either on or off. + * r3 contains the VSID, r4 contains the virtual address, + * r5 contains the linux PTE, r6 contains the old value of the + * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the + * offset to be added to addresses (0 if the MMU is on, + * -KERNELBASE if it is off). + * On SMP, the caller should have the mmu_hash_lock held. + * We assume that the caller has (or will) set the _PAGE_HASHPTE + * bit in the linux PTE in memory. The value passed in r6 should + * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set + * this routine will skip the search for an existing HPTE. + * This procedure modifies r0, r3 - r6, r8, cr0. + * -- paulus. + * + * For speed, 4 of the instructions get patched once the size and + * physical address of the hash table are known. These definitions + * of Hash_base and Hash_bits below are just an example. + */ +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 +#define LG_PTEG_SIZE 6 +#define LDPTEu lwzu +#define STPTE stw +#define CMPPTE cmpw +#define PTE_H 0x40 +#define PTE_V 0x80000000 +#define TST_V(r) rlwinm. r,r,0,0,0 +#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 + +_GLOBAL(create_hpte) + /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */ + rlwinm r8,r5,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r0,r5,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r8,r8,r0 /* writable if _RW & _DIRTY */ + rlwimi r5,r5,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */ + ori r8,r8,0xe14 /* clear out reserved bits and M */ + andc r8,r5,r8 /* PP = user? (rw&dirty? 2: 3): 0 */ +BEGIN_FTR_SECTION + ori r8,r8,_PAGE_COHERENT /* set M (coherence required) */ +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) */ +_GLOBAL(hash_page_patch_A) + addis r0,r7,Hash_base@h /* base address of hash table */ + rlwimi r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* VSID -> hash */ + rlwinm r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */ + xor r3,r3,r0 /* make primary hash */ + li r0,8 /* PTEs/group */ + + /* + * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search + * if it is clear, meaning that the HPTE isn't there already... + */ + andi. r6,r6,_PAGE_HASHPTE + beq+ 10f /* no PTE: go look for an empty slot */ + tlbie r4 + + addis r4,r7,htab_hash_searches@ha + lwz r6,htab_hash_searches@l(r4) + addi r6,r6,1 /* count how many searches we do */ + stw r6,htab_hash_searches@l(r4) + + /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */ + mtctr r0 + addi r4,r3,-PTE_SIZE +1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */ + CMPPTE 0,r6,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_slot + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,PTE_H /* set H (secondary hash) bit */ +_GLOBAL(hash_page_patch_B) + xoris r4,r3,Hash_msk>>16 /* compute secondary hash */ + xori r4,r4,(-PTEG_SIZE & 0xffff) + addi r4,r4,-PTE_SIZE + mtctr r0 +2: LDPTEu r6,PTE_SIZE(r4) + CMPPTE 0,r6,r5 + bdnzf 2,2b + beq+ found_slot + xori r5,r5,PTE_H /* clear H bit again */ + + /* Search the primary PTEG for an empty slot */ +10: mtctr r0 + addi r4,r3,-PTE_SIZE /* search primary PTEG */ +1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */ + TST_V(r6) /* test valid bit */ + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_empty + + /* update counter of times that the primary PTEG is full */ + addis r4,r7,primary_pteg_full@ha + lwz r6,primary_pteg_full@l(r4) + addi r6,r6,1 + stw r6,primary_pteg_full@l(r4) + + /* Search the secondary PTEG for an empty slot */ + ori r5,r5,PTE_H /* set H (secondary hash) bit */ +_GLOBAL(hash_page_patch_C) + xoris r4,r3,Hash_msk>>16 /* compute secondary hash */ + xori r4,r4,(-PTEG_SIZE & 0xffff) + addi r4,r4,-PTE_SIZE + mtctr r0 +2: LDPTEu r6,PTE_SIZE(r4) + TST_V(r6) + bdnzf 2,2b + beq+ found_empty + xori r5,r5,PTE_H /* clear H bit again */ + + /* + * Choose an arbitrary slot in the primary PTEG to overwrite. + * Since both the primary and secondary PTEGs are full, and we + * have no information that the PTEs in the primary PTEG are + * more important or useful than those in the secondary PTEG, + * and we know there is a definite (although small) speed + * advantage to putting the PTE in the primary PTEG, we always + * put the PTE in the primary PTEG. + */ + addis r4,r7,next_slot@ha + lwz r6,next_slot@l(r4) + addi r6,r6,PTE_SIZE + andi. r6,r6,7*PTE_SIZE + stw r6,next_slot@l(r4) + add r4,r3,r6 + +#ifndef CONFIG_SMP + /* Store PTE in PTEG */ +found_empty: + STPTE r5,0(r4) +found_slot: + STPTE r8,PTE_SIZE/2(r4) + +#else /* CONFIG_SMP */ +/* + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. + */ +found_empty: +found_slot: + CLR_V(r5,r0) /* clear V (valid) bit in PTE */ + STPTE r5,0(r4) + sync + TLBSYNC + STPTE r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */ + sync + SET_V(r5) + STPTE r5,0(r4) /* finally set V bit in PTE */ +#endif /* CONFIG_SMP */ + + sync /* make sure pte updates get to memory */ + blr + + .comm next_slot,4 + .comm primary_pteg_full,4 + .comm htab_hash_searches,4 + +/* + * Flush the entry for a particular page from the hash table. + * + * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval, + * int count) + * + * We assume that there is a hash table in use (Hash != 0). + */ +_GLOBAL(flush_hash_pages) + tophys(r7,0) + + /* + * We disable interrupts here, even on UP, because we want + * the _PAGE_HASHPTE bit to be a reliable indication of + * whether the HPTE exists (or at least whether one did once). + * We also turn off the MMU for data accesses so that we + * we can't take a hash table miss (assuming the code is + * covered by a BAT). -- paulus + */ + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear MSR_DR */ + mtmsr r0 + SYNC_601 + isync + + /* First find a PTE in the range that has _PAGE_HASHPTE set */ + rlwimi r5,r4,22,20,29 +1: lwz r0,0(r5) + cmpwi cr1,r6,1 + andi. r0,r0,_PAGE_HASHPTE + bne 2f + ble cr1,19f + addi r4,r4,0x1000 + addi r5,r5,4 + addi r6,r6,-1 + b 1b + + /* Convert context and va to VSID */ +2: mulli r3,r3,897*16 /* multiply context by context skew */ + rlwinm r0,r4,4,28,31 /* get ESID (top 4 bits of va) */ + mulli r0,r0,0x111 /* multiply by ESID skew */ + 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 + addis r9,r7,mmu_hash_lock@ha + addi r9,r9,mmu_hash_lock@l + rlwinm r8,r1,0,0,18 + add r8,r8,r7 + lwz r8,TI_CPU(r8) + oris r8,r8,9 +10: lwarx r0,0,r9 + cmpi 0,r0,0 + bne- 11f + stwcx. r8,0,r9 + beq+ 12f +11: lwz r0,0(r9) + cmpi 0,r0,0 + beq 10b + b 11b +12: isync +#endif + + /* + * Check the _PAGE_HASHPTE bit in the linux PTE. If it is + * already clear, we're done (for this pte). If not, + * clear it (atomically) and proceed. -- paulus. + */ +33: lwarx r8,0,r5 /* fetch the pte */ + andi. r0,r8,_PAGE_HASHPTE + beq 8f /* done if HASHPTE is already clear */ + rlwinm r8,r8,0,31,29 /* clear HASHPTE bit */ + stwcx. r8,0,r5 /* update the pte */ + bne- 33b + + /* Get the address of the primary PTE group in the hash table (r3) */ +_GLOBAL(flush_hash_patch_A) + addis r8,r7,Hash_base@h /* base address of hash table */ + rlwimi r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* VSID -> hash */ + rlwinm r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */ + xor r8,r0,r8 /* make primary hash */ + + /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */ + li r0,8 /* PTEs/group */ + mtctr r0 + addi r12,r8,-PTE_SIZE +1: LDPTEu r0,PTE_SIZE(r12) /* get next PTE */ + CMPPTE 0,r0,r11 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ 3f + + /* Search the secondary PTEG for a matching PTE */ + ori r11,r11,PTE_H /* set H (secondary hash) bit */ + li r0,8 /* PTEs/group */ +_GLOBAL(flush_hash_patch_B) + xoris r12,r8,Hash_msk>>16 /* compute secondary hash */ + xori r12,r12,(-PTEG_SIZE & 0xffff) + addi r12,r12,-PTE_SIZE + mtctr r0 +2: LDPTEu r0,PTE_SIZE(r12) + CMPPTE 0,r0,r11 + bdnzf 2,2b + xori r11,r11,PTE_H /* clear H again */ + bne- 4f /* should rarely fail to find it */ + +3: li r0,0 + STPTE r0,0(r12) /* invalidate entry */ +4: sync + tlbie r4 /* in hw tlb too */ + sync + +8: ble cr1,9f /* if all ptes checked */ +81: addi r6,r6,-1 + addi r5,r5,4 /* advance to next pte */ + addi r4,r4,0x1000 + lwz r0,0(r5) /* check next pte */ + cmpwi cr1,r6,1 + andi. r0,r0,_PAGE_HASHPTE + bne 33b + bgt cr1,81b + +9: +#ifdef CONFIG_SMP + TLBSYNC + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ +#endif + +19: mtmsr r10 + SYNC_601 + isync + blr diff --git a/arch/powerpc/mm/init.c b/arch/powerpc/mm/init.c new file mode 100644 index 000000000000..f4d983a6e521 --- /dev/null +++ b/arch/powerpc/mm/init.c @@ -0,0 +1,581 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * PPC44x/36-bit changes by Matt Porter (mporter@mvista.com) + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mem_pieces.h" +#include "mmu_decl.h" + +#if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL) +/* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */ +#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE)) +#error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL" +#endif +#endif +#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +unsigned long total_memory; +unsigned long total_lowmem; + +unsigned long ppc_memstart; +unsigned long ppc_memoffset = PAGE_OFFSET; + +int mem_init_done; +int init_bootmem_done; +int boot_mapsize; +#ifdef CONFIG_PPC_PMAC +unsigned long agp_special_page; +#endif + +extern char _end[]; +extern char etext[], _stext[]; +extern char __init_begin, __init_end; + +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif + +void MMU_init(void); +void set_phys_avail(unsigned long total_ram); + +/* XXX should be in current.h -- paulus */ +extern struct task_struct *current_set[NR_CPUS]; + +char *klimit = _end; +struct mem_pieces phys_avail; +struct device_node *memory_node; + +/* + * this tells the system to map all of ram with the segregs + * (i.e. page tables) instead of the bats. + * -- Cort + */ +int __map_without_bats; +int __map_without_ltlbs; + +/* max amount of RAM to use */ +unsigned long __max_memory; +/* max amount of low RAM to map in */ +unsigned long __max_low_memory = MAX_LOW_MEM; + +/* + * Read in a property describing some pieces of memory. + */ +static int __init get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int i, s; + unsigned int *ip; + int nac = prom_n_addr_cells(memory_node); + int nsc = prom_n_size_cells(memory_node); + + ip = (unsigned int *) get_property(memory_node, name, &s); + if (ip == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + return 0; + } + s /= (nsc + nac) * 4; + rp = mp->regions; + for (i = 0; i < s; ++i, ip += nac+nsc) { + if (nac >= 2 && ip[nac-2] != 0) + continue; + rp->address = ip[nac-1]; + if (nsc >= 2 && ip[nac+nsc-2] != 0) + rp->size = ~0U; + else + rp->size = ip[nac+nsc-1]; + ++rp; + } + mp->n_regions = rp - mp->regions; + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); + return 1; +} + +/* + * Collect information about physical RAM and which pieces are + * already in use from the device tree. + */ +unsigned long __init find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + memory_node = find_devices("memory"); + if (memory_node == NULL || !get_mem_prop("reg", &phys_mem) + || phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + +/* + * Check for command-line options that affect what MMU_init will do. + */ +void MMU_setup(void) +{ + /* Check for nobats option (used in mapin_ram). */ + if (strstr(cmd_line, "nobats")) { + __map_without_bats = 1; + } + + if (strstr(cmd_line, "noltlbs")) { + __map_without_ltlbs = 1; + } + + /* Look for mem= option on command line */ + if (strstr(cmd_line, "mem=")) { + char *p, *q; + unsigned long maxmem = 0; + + for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { + q = p + 4; + if (p > cmd_line && p[-1] != ' ') + continue; + maxmem = simple_strtoul(q, &q, 0); + if (*q == 'k' || *q == 'K') { + maxmem <<= 10; + ++q; + } else if (*q == 'm' || *q == 'M') { + maxmem <<= 20; + ++q; + } + } + __max_memory = maxmem; + } +} + +/* + * MMU_init sets up the basic memory mappings for the kernel, + * including both RAM and possibly some I/O regions, + * and sets up the page tables and the MMU hardware ready to go. + */ +void __init MMU_init(void) +{ + if (ppc_md.progress) + ppc_md.progress("MMU:enter", 0x111); + + /* parse args from command line */ + MMU_setup(); + + /* + * Figure out how much memory we have, how much + * is lowmem, and how much is highmem. If we were + * passed the total memory size from the bootloader, + * just use it. + */ + if (boot_mem_size) + total_memory = boot_mem_size; + else + total_memory = ppc_md.find_end_of_memory(); + + if (__max_memory && total_memory > __max_memory) + total_memory = __max_memory; + total_lowmem = total_memory; +#ifdef CONFIG_FSL_BOOKE + /* Freescale Book-E parts expect lowmem to be mapped by fixed TLB + * entries, so we need to adjust lowmem to match the amount we can map + * in the fixed entries */ + adjust_total_lowmem(); +#endif /* CONFIG_FSL_BOOKE */ + if (total_lowmem > __max_low_memory) { + total_lowmem = __max_low_memory; +#ifndef CONFIG_HIGHMEM + total_memory = total_lowmem; +#endif /* CONFIG_HIGHMEM */ + } + set_phys_avail(total_lowmem); + + /* Initialize the MMU hardware */ + if (ppc_md.progress) + ppc_md.progress("MMU:hw init", 0x300); + MMU_init_hw(); + + /* Map in all of RAM starting at KERNELBASE */ + if (ppc_md.progress) + ppc_md.progress("MMU:mapin", 0x301); + mapin_ram(); + +#ifdef CONFIG_HIGHMEM + ioremap_base = PKMAP_BASE; +#else + ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */ +#endif /* CONFIG_HIGHMEM */ + ioremap_bot = ioremap_base; + + /* Map in I/O resources */ + if (ppc_md.progress) + ppc_md.progress("MMU:setio", 0x302); + if (ppc_md.setup_io_mappings) + ppc_md.setup_io_mappings(); + + /* Initialize the context management stuff */ + mmu_context_init(); + + if (ppc_md.progress) + ppc_md.progress("MMU:exit", 0x211); + +#ifdef CONFIG_BOOTX_TEXT + /* By default, we are no longer mapped */ + boot_text_mapped = 0; + /* Must be done last, or ppc_md.progress will die. */ + map_boot_text(); +#endif +} + +/* This is only called until mem_init is done. */ +void __init *early_get_page(void) +{ + void *p; + + if (init_bootmem_done) { + p = alloc_bootmem_pages(PAGE_SIZE); + } else { + p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE); + } + return p; +} + +/* Free up now-unused memory */ +static void free_sec(unsigned long start, unsigned long end, const char *name) +{ + unsigned long cnt = 0; + + while (start < end) { + ClearPageReserved(virt_to_page(start)); + set_page_count(virt_to_page(start), 1); + free_page(start); + cnt++; + start += PAGE_SIZE; + } + if (cnt) { + printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name); + totalram_pages += cnt; + } +} + +void free_initmem(void) +{ +#define FREESEC(TYPE) \ + free_sec((unsigned long)(&__ ## TYPE ## _begin), \ + (unsigned long)(&__ ## TYPE ## _end), \ + #TYPE); + + printk ("Freeing unused kernel memory:"); + FREESEC(init); + printk("\n"); + ppc_md.progress = NULL; +#undef FREESEC +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (start < end) + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + set_page_count(virt_to_page(start), 1); + free_page(start); + totalram_pages++; + } +} +#endif + +/* + * Initialize the bootmem system and give it all the memory we + * have available. + */ +void __init do_init_bootmem(void) +{ + unsigned long start, size; + int i; + + /* + * Find an area to use for the bootmem bitmap. + * We look for the first area which is at least + * 128kB in length (128kB is enough for a bitmap + * for 4GB of memory, using 4kB pages), plus 1 page + * (in case the address isn't page-aligned). + */ + start = 0; + size = 0; + for (i = 0; i < phys_avail.n_regions; ++i) { + unsigned long a = phys_avail.regions[i].address; + unsigned long s = phys_avail.regions[i].size; + if (s <= size) + continue; + start = a; + size = s; + if (s >= 33 * PAGE_SIZE) + break; + } + start = PAGE_ALIGN(start); + + min_low_pfn = start >> PAGE_SHIFT; + max_low_pfn = (PPC_MEMSTART + total_lowmem) >> PAGE_SHIFT; + max_pfn = (PPC_MEMSTART + total_memory) >> PAGE_SHIFT; + boot_mapsize = init_bootmem_node(&contig_page_data, min_low_pfn, + PPC_MEMSTART >> PAGE_SHIFT, + max_low_pfn); + + /* remove the bootmem bitmap from the available memory */ + mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); + + /* add everything in phys_avail into the bootmem map */ + for (i = 0; i < phys_avail.n_regions; ++i) + free_bootmem(phys_avail.regions[i].address, + phys_avail.regions[i].size); + + init_bootmem_done = 1; +} + +/* + * paging_init() sets up the page tables - in fact we've already done this. + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES], i; + +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k + (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset_kernel(pmd_offset(pgd_offset_k + (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + + /* + * All pages are DMA-able so we put them all in the DMA zone. + */ + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + + free_area_init(zones_size); +} + +void __init mem_init(void) +{ + unsigned long addr; + int codepages = 0; + int datapages = 0; + int initpages = 0; +#ifdef CONFIG_HIGHMEM + unsigned long highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + max_mapnr = total_memory >> PAGE_SHIFT; + + high_memory = (void *) __va(PPC_MEMSTART + total_lowmem); + num_physpages = max_mapnr; /* RAM is assumed contiguous */ + + totalram_pages += free_all_bootmem(); + +#ifdef CONFIG_BLK_DEV_INITRD + /* if we are booted from BootX with an initial ramdisk, + make sure the ramdisk pages aren't reserved. */ + if (initrd_start) { + for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE) + ClearPageReserved(virt_to_page(addr)); + } +#endif /* CONFIG_BLK_DEV_INITRD */ + +#ifdef CONFIG_PPC_OF + /* mark the RTAS pages as reserved */ + if ( rtas_data ) + for (addr = (ulong)__va(rtas_data); + addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; + addr += PAGE_SIZE) + SetPageReserved(virt_to_page(addr)); +#endif +#ifdef CONFIG_PPC_PMAC + if (agp_special_page) + SetPageReserved(virt_to_page(agp_special_page)); +#endif + for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory; + addr += PAGE_SIZE) { + if (!PageReserved(virt_to_page(addr))) + continue; + if (addr < (ulong) etext) + codepages++; + else if (addr >= (unsigned long)&__init_begin + && addr < (unsigned long)&__init_end) + initpages++; + else if (addr < (ulong) klimit) + datapages++; + } + +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn; + + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = mem_map + pfn; + + ClearPageReserved(page); + set_page_count(page, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + } +#endif /* CONFIG_HIGHMEM */ + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", + (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), + codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), + initpages<< (PAGE_SHIFT-10), + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); + +#ifdef CONFIG_PPC_PMAC + if (agp_special_page) + printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); +#endif + + mem_init_done = 1; +} + +/* + * Set phys_avail to the amount of physical memory, + * less the kernel text/data/bss. + */ +void __init +set_phys_avail(unsigned long total_memory) +{ + unsigned long kstart, ksize; + + /* + * Initially, available physical memory is equivalent to all + * physical memory. + */ + + phys_avail.regions[0].address = PPC_MEMSTART; + phys_avail.regions[0].size = total_memory; + phys_avail.n_regions = 1; + + /* + * Map out the kernel text/data/bss from the available physical + * memory. + */ + + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(klimit - _stext); + + mem_pieces_remove(&phys_avail, kstart, ksize, 0); + mem_pieces_remove(&phys_avail, 0, 0x4000, 0); + +#if defined(CONFIG_BLK_DEV_INITRD) + /* Remove the init RAM disk from the available memory. */ + if (initrd_start) { + mem_pieces_remove(&phys_avail, __pa(initrd_start), + initrd_end - initrd_start, 1); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +#ifdef CONFIG_PPC_OF + /* remove the RTAS pages from the available memory */ + if (rtas_data) + mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); +#endif +#ifdef CONFIG_PPC_PMAC + /* Because of some uninorth weirdness, we need a page of + * memory as high as possible (it must be outside of the + * bus address seen as the AGP aperture). It will be used + * by the r128 DRM driver + * + * FIXME: We need to make sure that page doesn't overlap any of the\ + * above. This could be done by improving mem_pieces_find to be able + * to do a backward search from the end of the list. + */ + if (_machine == _MACH_Pmac && find_devices("uni-north-agp")) { + agp_special_page = (total_memory - PAGE_SIZE); + mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0); + agp_special_page = (unsigned long)__va(agp_special_page); + } +#endif /* CONFIG_PPC_PMAC */ +} + +/* Mark some memory as reserved by removing it from phys_avail. */ +void __init reserve_phys_mem(unsigned long start, unsigned long size) +{ + mem_pieces_remove(&phys_avail, start, size, 1); +} diff --git a/arch/powerpc/mm/init64.c b/arch/powerpc/mm/init64.c new file mode 100644 index 000000000000..81f6745b31ef --- /dev/null +++ b/arch/powerpc/mm/init64.c @@ -0,0 +1,385 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Dave Engebretsen + * Rework for PPC64 port. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if PGTABLE_RANGE > USER_VSID_RANGE +#warning Limited user VSID range means pagetable space is wasted +#endif + +#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE) +#warning TASK_SIZE is smaller than it needs to be. +#endif + +int mem_init_done; +unsigned long ioremap_bot = IMALLOC_BASE; +static unsigned long phbs_io_bot = PHBS_IO_BASE; + +extern pgd_t swapper_pg_dir[]; +extern struct task_struct *current_set[NR_CPUS]; + +unsigned long klimit = (unsigned long)_end; + +unsigned long _SDR1=0; +unsigned long _ASR=0; + +/* max amount of RAM to use */ +unsigned long __max_memory; + +/* info on what we think the IO hole is */ +unsigned long io_hole_start; +unsigned long io_hole_size; + +/* + * Do very early mm setup. + */ +void __init mm_init_ppc64(void) +{ +#ifndef CONFIG_PPC_ISERIES + unsigned long i; +#endif + + ppc64_boot_msg(0x100, "MM Init"); + + /* This is the story of the IO hole... please, keep seated, + * unfortunately, we are out of oxygen masks at the moment. + * So we need some rough way to tell where your big IO hole + * is. On pmac, it's between 2G and 4G, on POWER3, it's around + * that area as well, on POWER4 we don't have one, etc... + * We need that as a "hint" when sizing the TCE table on POWER3 + * So far, the simplest way that seem work well enough for us it + * to just assume that the first discontinuity in our physical + * RAM layout is the IO hole. That may not be correct in the future + * (and isn't on iSeries but then we don't care ;) + */ + +#ifndef CONFIG_PPC_ISERIES + for (i = 1; i < lmb.memory.cnt; i++) { + unsigned long base, prevbase, prevsize; + + prevbase = lmb.memory.region[i-1].base; + prevsize = lmb.memory.region[i-1].size; + base = lmb.memory.region[i].base; + if (base > (prevbase + prevsize)) { + io_hole_start = prevbase + prevsize; + io_hole_size = base - (prevbase + prevsize); + break; + } + } +#endif /* CONFIG_PPC_ISERIES */ + if (io_hole_start) + printk("IO Hole assumed to be %lx -> %lx\n", + io_hole_start, io_hole_start + io_hole_size - 1); + + ppc64_boot_msg(0x100, "MM Init Done"); +} + +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)__init_begin; + for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { + memset((void *)addr, 0xcc, PAGE_SIZE); + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing unused kernel memory: %luk freed\n", + ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (start < end) + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + set_page_count(virt_to_page(start), 1); + free_page(start); + totalram_pages++; + } +} +#endif + +/* + * Initialize the bootmem system and give it all the memory we + * have available. + */ +#ifndef CONFIG_NEED_MULTIPLE_NODES +void __init do_init_bootmem(void) +{ + unsigned long i; + unsigned long start, bootmap_pages; + unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; + int boot_mapsize; + + /* + * Find an area to use for the bootmem bitmap. Calculate the size of + * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE. + * Add 1 additional page in case the address isn't page-aligned. + */ + bootmap_pages = bootmem_bootmap_pages(total_pages); + + start = lmb_alloc(bootmap_pages<> PAGE_SHIFT, total_pages); + + max_pfn = max_low_pfn; + + /* Add all physical memory to the bootmem map, mark each area + * present. + */ + for (i=0; i < lmb.memory.cnt; i++) + free_bootmem(lmb.memory.region[i].base, + lmb_size_bytes(&lmb.memory, i)); + + /* reserve the sections we're already using */ + for (i=0; i < lmb.reserved.cnt; i++) + reserve_bootmem(lmb.reserved.region[i].base, + lmb_size_bytes(&lmb.reserved, i)); + + for (i=0; i < lmb.memory.cnt; i++) + memory_present(0, lmb_start_pfn(&lmb.memory, i), + lmb_end_pfn(&lmb.memory, i)); +} + +/* + * paging_init() sets up the page tables - in fact we've already done this. + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long total_ram = lmb_phys_mem_size(); + unsigned long top_of_ram = lmb_end_of_DRAM(); + + printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", + top_of_ram, total_ram); + printk(KERN_INFO "Memory hole size: %ldMB\n", + (top_of_ram - total_ram) >> 20); + /* + * All pages are DMA-able so we put them all in the DMA zone. + */ + memset(zones_size, 0, sizeof(zones_size)); + memset(zholes_size, 0, sizeof(zholes_size)); + + zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; + zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; + + free_area_init_node(0, NODE_DATA(0), zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); +} +#endif /* ! CONFIG_NEED_MULTIPLE_NODES */ + +static struct kcore_list kcore_vmem; + +static int __init setup_kcore(void) +{ + int i; + + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long base, size; + struct kcore_list *kcore_mem; + + base = lmb.memory.region[i].base; + size = lmb.memory.region[i].size; + + /* GFP_ATOMIC to avoid might_sleep warnings during boot */ + kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC); + if (!kcore_mem) + panic("mem_init: kmalloc failed\n"); + + kclist_add(kcore_mem, __va(base), size); + } + + kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); + + return 0; +} +module_init(setup_kcore); + +void __init mem_init(void) +{ +#ifdef CONFIG_NEED_MULTIPLE_NODES + int nid; +#endif + pg_data_t *pgdat; + unsigned long i; + struct page *page; + unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; + + num_physpages = max_low_pfn; /* RAM is assumed contiguous */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); + +#ifdef CONFIG_NEED_MULTIPLE_NODES + for_each_online_node(nid) { + if (NODE_DATA(nid)->node_spanned_pages != 0) { + printk("freeing bootmem node %x\n", nid); + totalram_pages += + free_all_bootmem_node(NODE_DATA(nid)); + } + } +#else + max_mapnr = num_physpages; + totalram_pages += free_all_bootmem(); +#endif + + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat_page_nr(pgdat, i); + if (PageReserved(page)) + reservedpages++; + } + } + + codesize = (unsigned long)&_etext - (unsigned long)&_stext; + initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; + datasize = (unsigned long)&_edata - (unsigned long)&__init_end; + bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; + + printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " + "%luk reserved, %luk data, %luk bss, %luk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + bsssize >> 10, + initsize >> 10); + + mem_init_done = 1; + + /* Initialize the vDSO */ + vdso_init(); +} + +void __iomem * reserve_phb_iospace(unsigned long size) +{ + void __iomem *virt_addr; + + if (phbs_io_bot >= IMALLOC_BASE) + panic("reserve_phb_iospace(): phb io space overflow\n"); + + virt_addr = (void __iomem *) phbs_io_bot; + phbs_io_bot += size; + + return virt_addr; +} + +static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) +{ + memset(addr, 0, kmem_cache_size(cache)); +} + +static const int pgtable_cache_size[2] = { + PTE_TABLE_SIZE, PMD_TABLE_SIZE +}; +static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { + "pgd_pte_cache", "pud_pmd_cache", +}; + +kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; + +void pgtable_cache_init(void) +{ + int i; + + BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]); + BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]); + BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]); + BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]); + + for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) { + int size = pgtable_cache_size[i]; + const char *name = pgtable_cache_name[i]; + + pgtable_cache[i] = kmem_cache_create(name, + size, size, + SLAB_HWCACHE_ALIGN + | SLAB_MUST_HWCACHE_ALIGN, + zero_ctor, + NULL); + if (! pgtable_cache[i]) + panic("pgtable_cache_init(): could not create %s!\n", + name); + } +} + +pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, + unsigned long size, pgprot_t vma_prot) +{ + if (ppc_md.phys_mem_access_prot) + return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); + + if (!page_is_ram(addr >> PAGE_SHIFT)) + vma_prot = __pgprot(pgprot_val(vma_prot) + | _PAGE_GUARDED | _PAGE_NO_CACHE); + return vma_prot; +} +EXPORT_SYMBOL(phys_mem_access_prot); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c new file mode 100644 index 000000000000..345db08e5d20 --- /dev/null +++ b/arch/powerpc/mm/mem.c @@ -0,0 +1,299 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * PPC44x/36-bit changes by Matt Porter (mporter@mvista.com) + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mem_pieces.h" +#include "mmu_decl.h" + +#ifndef CPU_FTR_COHERENT_ICACHE +#define CPU_FTR_COHERENT_ICACHE 0 /* XXX for now */ +#define CPU_FTR_NOEXECUTE 0 +#endif + +/* + * This is called by /dev/mem to know if a given address has to + * be mapped non-cacheable or not + */ +int page_is_ram(unsigned long pfn) +{ + unsigned long paddr = (pfn << PAGE_SHIFT); + +#ifndef CONFIG_PPC64 /* XXX for now */ + return paddr < __pa(high_memory); +#else + int i; + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long base; + + base = lmb.memory.region[i].base; + + if ((paddr >= base) && + (paddr < (base + lmb.memory.region[i].size))) { + return 1; + } + } + + return 0; +#endif +} +EXPORT_SYMBOL(page_is_ram); + +pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, + unsigned long size, pgprot_t vma_prot) +{ + if (ppc_md.phys_mem_access_prot) + return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); + + if (!page_is_ram(addr >> PAGE_SHIFT)) + vma_prot = __pgprot(pgprot_val(vma_prot) + | _PAGE_GUARDED | _PAGE_NO_CACHE); + return vma_prot; +} +EXPORT_SYMBOL(phys_mem_access_prot); + +void show_mem(void) +{ + unsigned long total = 0, reserved = 0; + unsigned long shared = 0, cached = 0; + unsigned long highmem = 0; + struct page *page; + pg_data_t *pgdat; + unsigned long i; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat_page_nr(pgdat, i); + total++; + if (PageHighMem(page)) + highmem++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } + } + printk("%ld pages of RAM\n", total); +#ifdef CONFIG_HIGHMEM + printk("%ld pages of HIGHMEM\n", highmem); +#endif + printk("%ld reserved pages\n", reserved); + printk("%ld pages shared\n", shared); + printk("%ld pages swap cached\n", cached); +} + +/* + * This is called when a page has been modified by the kernel. + * It just marks the page as not i-cache clean. We do the i-cache + * flush later when the page is given to a user process, if necessary. + */ +void flush_dcache_page(struct page *page) +{ + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &page->flags)) + clear_bit(PG_arch_1, &page->flags); +} +EXPORT_SYMBOL(flush_dcache_page); + +void flush_dcache_icache_page(struct page *page) +{ +#ifdef CONFIG_BOOKE + void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); + __flush_dcache_icache(start); + kunmap_atomic(start, KM_PPC_SYNC_ICACHE); +#elif defined(CONFIG_8xx) + /* On 8xx there is no need to kmap since highmem is not supported */ + __flush_dcache_icache(page_address(page)); +#else + __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT); +#endif + +} +void clear_user_page(void *page, unsigned long vaddr, struct page *pg) +{ + clear_page(page); + + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + /* + * We shouldnt have to do this, but some versions of glibc + * require it (ld.so assumes zero filled pages are icache clean) + * - Anton + */ + + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &pg->flags)) + clear_bit(PG_arch_1, &pg->flags); +} +EXPORT_SYMBOL(clear_user_page); + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + copy_page(vto, vfrom); + + /* + * We should be able to use the following optimisation, however + * there are two problems. + * Firstly a bug in some versions of binutils meant PLT sections + * were not marked executable. + * Secondly the first word in the GOT section is blrl, used + * to establish the GOT address. Until recently the GOT was + * not marked executable. + * - Anton + */ +#if 0 + if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0)) + return; +#endif + + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &pg->flags)) + clear_bit(PG_arch_1, &pg->flags); +} + +void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + unsigned long maddr; + + maddr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + flush_icache_range(maddr, maddr + len); + kunmap(page); +} +EXPORT_SYMBOL(flush_icache_user_range); + +/* + * This is called at the end of handling a user page fault, when the + * fault has been handled by updating a PTE in the linux page tables. + * We use it to preload an HPTE into the hash table corresponding to + * the updated linux PTE. + * + * This must always be called with the mm->page_table_lock held + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, + pte_t pte) +{ + /* handle i-cache coherency */ + unsigned long pfn = pte_pfn(pte); +#ifdef CONFIG_PPC32 + pmd_t *pmd; +#else + unsigned long vsid; + void *pgdir; + pte_t *ptep; + int local = 0; + cpumask_t tmp; + unsigned long flags; +#endif + + /* handle i-cache coherency */ + if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && + !cpu_has_feature(CPU_FTR_NOEXECUTE) && + pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + if (!PageReserved(page) + && !test_bit(PG_arch_1, &page->flags)) { + if (vma->vm_mm == current->active_mm) { +#ifdef CONFIG_8xx + /* On 8xx, cache control instructions (particularly + * "dcbst" from flush_dcache_icache) fault as write + * operation if there is an unpopulated TLB entry + * for the address in question. To workaround that, + * we invalidate the TLB here, thus avoiding dcbst + * misbehaviour. + */ + _tlbie(address); +#endif + __flush_dcache_icache((void *) address); + } else + flush_dcache_icache_page(page); + set_bit(PG_arch_1, &page->flags); + } + } + +#ifdef CONFIG_PPC_STD_MMU + /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ + if (!pte_young(pte) || address >= TASK_SIZE) + return; +#ifdef CONFIG_PPC32 + if (Hash == 0) + return; + pmd = pmd_offset(pgd_offset(vma->vm_mm, address), address); + if (!pmd_none(*pmd)) + add_hash_page(vma->vm_mm->context, address, pmd_val(*pmd)); +#else + pgdir = vma->vm_mm->pgd; + if (pgdir == NULL) + return; + + ptep = find_linux_pte(pgdir, ea); + if (!ptep) + return; + + vsid = get_vsid(vma->vm_mm->context.id, ea); + + local_irq_save(flags); + tmp = cpumask_of_cpu(smp_processor_id()); + if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) + local = 1; + + __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, + 0x300, local); + local_irq_restore(flags); +#endif +#endif +} diff --git a/arch/powerpc/mm/mem64.c b/arch/powerpc/mm/mem64.c new file mode 100644 index 000000000000..ef765a84433f --- /dev/null +++ b/arch/powerpc/mm/mem64.c @@ -0,0 +1,259 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Dave Engebretsen + * Rework for PPC64 port. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This is called by /dev/mem to know if a given address has to + * be mapped non-cacheable or not + */ +int page_is_ram(unsigned long pfn) +{ + int i; + unsigned long paddr = (pfn << PAGE_SHIFT); + + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long base; + + base = lmb.memory.region[i].base; + + if ((paddr >= base) && + (paddr < (base + lmb.memory.region[i].size))) { + return 1; + } + } + + return 0; +} +EXPORT_SYMBOL(page_is_ram); + +pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, + unsigned long size, pgprot_t vma_prot) +{ + if (ppc_md.phys_mem_access_prot) + return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); + + if (!page_is_ram(addr >> PAGE_SHIFT)) + vma_prot = __pgprot(pgprot_val(vma_prot) + | _PAGE_GUARDED | _PAGE_NO_CACHE); + return vma_prot; +} +EXPORT_SYMBOL(phys_mem_access_prot); + +void show_mem(void) +{ + unsigned long total = 0, reserved = 0; + unsigned long shared = 0, cached = 0; + struct page *page; + pg_data_t *pgdat; + unsigned long i; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat_page_nr(pgdat, i); + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } + } + printk("%ld pages of RAM\n", total); + printk("%ld reserved pages\n", reserved); + printk("%ld pages shared\n", shared); + printk("%ld pages swap cached\n", cached); +} + +/* + * This is called when a page has been modified by the kernel. + * It just marks the page as not i-cache clean. We do the i-cache + * flush later when the page is given to a user process, if necessary. + */ +void flush_dcache_page(struct page *page) +{ + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &page->flags)) + clear_bit(PG_arch_1, &page->flags); +} +EXPORT_SYMBOL(flush_dcache_page); + +void clear_user_page(void *page, unsigned long vaddr, struct page *pg) +{ + clear_page(page); + + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + /* + * We shouldnt have to do this, but some versions of glibc + * require it (ld.so assumes zero filled pages are icache clean) + * - Anton + */ + + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &pg->flags)) + clear_bit(PG_arch_1, &pg->flags); +} +EXPORT_SYMBOL(clear_user_page); + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + copy_page(vto, vfrom); + + /* + * We should be able to use the following optimisation, however + * there are two problems. + * Firstly a bug in some versions of binutils meant PLT sections + * were not marked executable. + * Secondly the first word in the GOT section is blrl, used + * to establish the GOT address. Until recently the GOT was + * not marked executable. + * - Anton + */ +#if 0 + if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0)) + return; +#endif + + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) + return; + + /* avoid an atomic op if possible */ + if (test_bit(PG_arch_1, &pg->flags)) + clear_bit(PG_arch_1, &pg->flags); +} + +void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + unsigned long maddr; + + maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK); + flush_icache_range(maddr, maddr + len); +} +EXPORT_SYMBOL(flush_icache_user_range); + +/* + * This is called at the end of handling a user page fault, when the + * fault has been handled by updating a PTE in the linux page tables. + * We use it to preload an HPTE into the hash table corresponding to + * the updated linux PTE. + * + * This must always be called with the mm->page_table_lock held + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea, + pte_t pte) +{ + unsigned long vsid; + void *pgdir; + pte_t *ptep; + int local = 0; + cpumask_t tmp; + unsigned long flags; + + /* handle i-cache coherency */ + if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && + !cpu_has_feature(CPU_FTR_NOEXECUTE)) { + unsigned long pfn = pte_pfn(pte); + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + if (!PageReserved(page) + && !test_bit(PG_arch_1, &page->flags)) { + __flush_dcache_icache(page_address(page)); + set_bit(PG_arch_1, &page->flags); + } + } + } + + /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ + if (!pte_young(pte)) + return; + + pgdir = vma->vm_mm->pgd; + if (pgdir == NULL) + return; + + ptep = find_linux_pte(pgdir, ea); + if (!ptep) + return; + + vsid = get_vsid(vma->vm_mm->context.id, ea); + + local_irq_save(flags); + tmp = cpumask_of_cpu(smp_processor_id()); + if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) + local = 1; + + __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, + 0x300, local); + local_irq_restore(flags); +} diff --git a/arch/powerpc/mm/mem_pieces.c b/arch/powerpc/mm/mem_pieces.c new file mode 100644 index 000000000000..3d639052017e --- /dev/null +++ b/arch/powerpc/mm/mem_pieces.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1996 Paul Mackerras + * Changes to accommodate Power Macintoshes. + * Cort Dougan + * Rewrites. + * Grant Erickson + * General rework and split from mm/init.c. + * + * Module name: mem_pieces.c + * + * Description: + * Routines and data structures for manipulating and representing + * phyiscal memory extents (i.e. address/length pairs). + * + */ + +#include +#include +#include +#include +#include + +#include "mem_pieces.h" + +extern struct mem_pieces phys_avail; + +static void mem_pieces_print(struct mem_pieces *); + +/* + * Scan a region for a piece of a given size with the required alignment. + */ +void __init * +mem_pieces_find(unsigned int size, unsigned int align) +{ + int i; + unsigned a, e; + struct mem_pieces *mp = &phys_avail; + + for (i = 0; i < mp->n_regions; ++i) { + a = mp->regions[i].address; + e = a + mp->regions[i].size; + a = (a + align - 1) & -align; + if (a + size <= e) { + mem_pieces_remove(mp, a, size, 1); + return (void *) __va(a); + } + } + panic("Couldn't find %u bytes at %u alignment\n", size, align); + + return NULL; +} + +/* + * Remove some memory from an array of pieces + */ +void __init +mem_pieces_remove(struct mem_pieces *mp, unsigned int start, unsigned int size, + int must_exist) +{ + int i, j; + unsigned int end, rs, re; + struct reg_property *rp; + + end = start + size; + for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) { + if (end > rp->address && start < rp->address + rp->size) + break; + } + if (i >= mp->n_regions) { + if (must_exist) + printk("mem_pieces_remove: [%x,%x) not in any region\n", + start, end); + return; + } + for (; i < mp->n_regions && end > rp->address; ++i, ++rp) { + rs = rp->address; + re = rs + rp->size; + if (must_exist && (start < rs || end > re)) { + printk("mem_pieces_remove: bad overlap [%x,%x) with", + start, end); + mem_pieces_print(mp); + must_exist = 0; + } + if (start > rs) { + rp->size = start - rs; + if (end < re) { + /* need to split this entry */ + if (mp->n_regions >= MEM_PIECES_MAX) + panic("eek... mem_pieces overflow"); + for (j = mp->n_regions; j > i + 1; --j) + mp->regions[j] = mp->regions[j-1]; + ++mp->n_regions; + rp[1].address = end; + rp[1].size = re - end; + } + } else { + if (end < re) { + rp->address = end; + rp->size = re - end; + } else { + /* need to delete this entry */ + for (j = i; j < mp->n_regions - 1; ++j) + mp->regions[j] = mp->regions[j+1]; + --mp->n_regions; + --i; + --rp; + } + } + } +} + +static void __init +mem_pieces_print(struct mem_pieces *mp) +{ + int i; + + for (i = 0; i < mp->n_regions; ++i) + printk(" [%x, %x)", mp->regions[i].address, + mp->regions[i].address + mp->regions[i].size); + printk("\n"); +} + +void __init +mem_pieces_sort(struct mem_pieces *mp) +{ + unsigned long a, s; + int i, j; + + for (i = 1; i < mp->n_regions; ++i) { + a = mp->regions[i].address; + s = mp->regions[i].size; + for (j = i - 1; j >= 0; --j) { + if (a >= mp->regions[j].address) + break; + mp->regions[j+1] = mp->regions[j]; + } + mp->regions[j+1].address = a; + mp->regions[j+1].size = s; + } +} + +void __init +mem_pieces_coalesce(struct mem_pieces *mp) +{ + unsigned long a, s, ns; + int i, j, d; + + d = 0; + for (i = 0; i < mp->n_regions; i = j) { + a = mp->regions[i].address; + s = mp->regions[i].size; + for (j = i + 1; j < mp->n_regions + && mp->regions[j].address - a <= s; ++j) { + ns = mp->regions[j].address + mp->regions[j].size - a; + if (ns > s) + s = ns; + } + mp->regions[d].address = a; + mp->regions[d].size = s; + ++d; + } + mp->n_regions = d; +} diff --git a/arch/powerpc/mm/mem_pieces.h b/arch/powerpc/mm/mem_pieces.h new file mode 100644 index 000000000000..e2b700dc7f18 --- /dev/null +++ b/arch/powerpc/mm/mem_pieces.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1996 Paul Mackerras + * Changes to accommodate Power Macintoshes. + * Cort Dougan + * Rewrites. + * Grant Erickson + * General rework and split from mm/init.c. + * + * Module name: mem_pieces.h + * + * Description: + * Routines and data structures for manipulating and representing + * phyiscal memory extents (i.e. address/length pairs). + * + */ + +#ifndef __MEM_PIECES_H__ +#define __MEM_PIECES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Type Definitions */ + +#define MEM_PIECES_MAX 32 + +struct mem_pieces { + int n_regions; + struct reg_property regions[MEM_PIECES_MAX]; +}; + +/* Function Prototypes */ + +extern void *mem_pieces_find(unsigned int size, unsigned int align); +extern void mem_pieces_remove(struct mem_pieces *mp, unsigned int start, + unsigned int size, int must_exist); +extern void mem_pieces_coalesce(struct mem_pieces *mp); +extern void mem_pieces_sort(struct mem_pieces *mp); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEM_PIECES_H__ */ diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c new file mode 100644 index 000000000000..a8816e0f6a86 --- /dev/null +++ b/arch/powerpc/mm/mmu_context.c @@ -0,0 +1,86 @@ +/* + * This file contains the routines for handling the MMU on those + * PowerPC implementations where the MMU substantially follows the + * architecture specification. This includes the 6xx, 7xx, 7xxx, + * 8260, and POWER3 implementations but excludes the 8xx and 4xx. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 + +mm_context_t next_mmu_context; +unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; +#ifdef FEW_CONTEXTS +atomic_t nr_free_contexts; +struct mm_struct *context_mm[LAST_CONTEXT+1]; +void steal_context(void); +#endif /* FEW_CONTEXTS */ + +/* + * Initialize the context management stuff. + */ +void __init +mmu_context_init(void) +{ + /* + * Some processors have too few contexts to reserve one for + * init_mm, and require using context 0 for a normal task. + * Other processors reserve the use of context zero for the kernel. + * This code assumes FIRST_CONTEXT < 32. + */ + context_map[0] = (1 << FIRST_CONTEXT) - 1; + next_mmu_context = FIRST_CONTEXT; +#ifdef FEW_CONTEXTS + atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); +#endif /* FEW_CONTEXTS */ +} + +#ifdef FEW_CONTEXTS +/* + * Steal a context from a task that has one at the moment. + * This is only used on 8xx and 4xx and we presently assume that + * they don't do SMP. If they do then this will have to check + * whether the MM we steal is in use. + * We also assume that this is only used on systems that don't + * use an MMU hash table - this is true for 8xx and 4xx. + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + */ +void +steal_context(void) +{ + struct mm_struct *mm; + + /* free up context `next_mmu_context' */ + /* if we shouldn't free context 0, don't... */ + if (next_mmu_context < FIRST_CONTEXT) + next_mmu_context = FIRST_CONTEXT; + mm = context_mm[next_mmu_context]; + flush_tlb_mm(mm); + destroy_context(mm); +} +#endif /* FEW_CONTEXTS */ diff --git a/arch/powerpc/mm/mmu_context64.c b/arch/powerpc/mm/mmu_context64.c new file mode 100644 index 000000000000..714a84dd8d5d --- /dev/null +++ b/arch/powerpc/mm/mmu_context64.c @@ -0,0 +1,63 @@ +/* + * MMU context allocation for 64-bit kernels. + * + * Copyright (C) 2004 Anton Blanchard, 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 + +static DEFINE_SPINLOCK(mmu_context_lock); +static DEFINE_IDR(mmu_context_idr); + +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + int index; + int err; + +again: + if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mmu_context_lock); + err = idr_get_new_above(&mmu_context_idr, NULL, 1, &index); + spin_unlock(&mmu_context_lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > MAX_CONTEXT) { + idr_remove(&mmu_context_idr, index); + return -ENOMEM; + } + + mm->context.id = index; + + return 0; +} + +void destroy_context(struct mm_struct *mm) +{ + spin_lock(&mmu_context_lock); + idr_remove(&mmu_context_idr, mm->context.id); + spin_unlock(&mmu_context_lock); + + mm->context.id = NO_CONTEXT; +} diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h new file mode 100644 index 000000000000..540f3292b229 --- /dev/null +++ b/arch/powerpc/mm/mmu_decl.h @@ -0,0 +1,85 @@ +/* + * Declarations of procedures and variables shared between files + * in arch/ppc/mm/. + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 + +extern void mapin_ram(void); +extern int map_page(unsigned long va, phys_addr_t pa, int flags); +extern void setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags); +extern void reserve_phys_mem(unsigned long start, unsigned long size); +extern void settlbcam(int index, unsigned long virt, phys_addr_t phys, + unsigned int size, int flags, unsigned int pid); +extern void invalidate_tlbcam_entry(int index); + +extern int __map_without_bats; +extern unsigned long ioremap_base; +extern unsigned long ioremap_bot; +extern unsigned int rtas_data, rtas_size; + +extern unsigned long total_memory; +extern unsigned long total_lowmem; +extern int mem_init_done; + +extern PTE *Hash, *Hash_end; +extern unsigned long Hash_size, Hash_mask; + +extern unsigned int num_tlbcam_entries; + +/* ...and now those things that may be slightly different between processor + * architectures. -- Dan + */ +#if defined(CONFIG_8xx) +#define flush_HPTE(X, va, pg) _tlbie(va) +#define MMU_init_hw() do { } while(0) +#define mmu_mapin_ram() (0UL) + +#elif defined(CONFIG_4xx) +#define flush_HPTE(X, va, pg) _tlbie(va) +extern void MMU_init_hw(void); +extern unsigned long mmu_mapin_ram(void); + +#elif defined(CONFIG_FSL_BOOKE) +#define flush_HPTE(X, va, pg) _tlbie(va) +extern void MMU_init_hw(void); +extern unsigned long mmu_mapin_ram(void); +extern void adjust_total_lowmem(void); + +#else +/* anything except 4xx or 8xx */ +extern void MMU_init_hw(void); +extern unsigned long mmu_mapin_ram(void); + +/* Be careful....this needs to be updated if we ever encounter 603 SMPs, + * which includes all new 82xx processors. We need tlbie/tlbsync here + * in that case (I think). -- Dan. + */ +static inline void flush_HPTE(unsigned context, unsigned long va, + unsigned long pdval) +{ + if ((Hash != 0) && + cpu_has_feature(CPU_FTR_HPTE_TABLE)) + flush_hash_pages(0, va, pdval, 1); + else + _tlbie(va); +} +#endif diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c new file mode 100644 index 000000000000..81a3d7446d37 --- /dev/null +++ b/arch/powerpc/mm/pgtable.c @@ -0,0 +1,470 @@ +/* + * This file contains the routines setting up the linux page tables. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mmu_decl.h" + +unsigned long ioremap_base; +unsigned long ioremap_bot; +int io_bat_index; + +#if defined(CONFIG_6xx) || defined(CONFIG_POWER3) +#define HAVE_BATS 1 +#endif + +#if defined(CONFIG_FSL_BOOKE) +#define HAVE_TLBCAM 1 +#endif + +extern char etext[], _stext[]; + +#ifdef CONFIG_SMP +extern void hash_page_sync(void); +#endif + +#ifdef HAVE_BATS +extern unsigned long v_mapped_by_bats(unsigned long va); +extern unsigned long p_mapped_by_bats(unsigned long pa); +void setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags); + +#else /* !HAVE_BATS */ +#define v_mapped_by_bats(x) (0UL) +#define p_mapped_by_bats(x) (0UL) +#endif /* HAVE_BATS */ + +#ifdef HAVE_TLBCAM +extern unsigned int tlbcam_index; +extern unsigned long v_mapped_by_tlbcam(unsigned long va); +extern unsigned long p_mapped_by_tlbcam(unsigned long pa); +#else /* !HAVE_TLBCAM */ +#define v_mapped_by_tlbcam(x) (0UL) +#define p_mapped_by_tlbcam(x) (0UL) +#endif /* HAVE_TLBCAM */ + +#ifdef CONFIG_PTE_64BIT +/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */ +#define PGDIR_ORDER 1 +#else +#define PGDIR_ORDER 0 +#endif + +pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *ret; + + ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER); + return ret; +} + +void pgd_free(pgd_t *pgd) +{ + free_pages((unsigned long)pgd, PGDIR_ORDER); +} + +pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + extern int mem_init_done; + extern void *early_get_page(void); + + if (mem_init_done) { + pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); + } else { + pte = (pte_t *)early_get_page(); + if (pte) + clear_page(pte); + } + return pte; +} + +struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + struct page *ptepage; + +#ifdef CONFIG_HIGHPTE + int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT; +#else + int flags = GFP_KERNEL | __GFP_REPEAT; +#endif + + ptepage = alloc_pages(flags, 0); + if (ptepage) + clear_highpage(ptepage); + return ptepage; +} + +void pte_free_kernel(pte_t *pte) +{ +#ifdef CONFIG_SMP + hash_page_sync(); +#endif + free_page((unsigned long)pte); +} + +void pte_free(struct page *ptepage) +{ +#ifdef CONFIG_SMP + hash_page_sync(); +#endif + __free_page(ptepage); +} + +#ifndef CONFIG_PHYS_64BIT +void __iomem * +ioremap(phys_addr_t addr, unsigned long size) +{ + return __ioremap(addr, size, _PAGE_NO_CACHE); +} +#else /* CONFIG_PHYS_64BIT */ +void __iomem * +ioremap64(unsigned long long addr, unsigned long size) +{ + return __ioremap(addr, size, _PAGE_NO_CACHE); +} + +void __iomem * +ioremap(phys_addr_t addr, unsigned long size) +{ + phys_addr_t addr64 = fixup_bigphys_addr(addr, size); + + return ioremap64(addr64, size); +} +#endif /* CONFIG_PHYS_64BIT */ + +void __iomem * +__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) +{ + unsigned long v, i; + phys_addr_t p; + int err; + + /* + * Choose an address to map it to. + * Once the vmalloc system is running, we use it. + * Before then, we use space going down from ioremap_base + * (ioremap_bot records where we're up to). + */ + p = addr & PAGE_MASK; + size = PAGE_ALIGN(addr + size) - p; + + /* + * If the address lies within the first 16 MB, assume it's in ISA + * memory space + */ + if (p < 16*1024*1024) + p += _ISA_MEM_BASE; + + /* + * Don't allow anybody to remap normal RAM that we're using. + * mem_init() sets high_memory so only do the check after that. + */ + if ( mem_init_done && (p < virt_to_phys(high_memory)) ) + { + printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p, + __builtin_return_address(0)); + return NULL; + } + + if (size == 0) + return NULL; + + /* + * Is it already mapped? Perhaps overlapped by a previous + * BAT mapping. If the whole area is mapped then we're done, + * otherwise remap it since we want to keep the virt addrs for + * each request contiguous. + * + * We make the assumption here that if the bottom and top + * of the range we want are mapped then it's mapped to the + * same virt address (and this is contiguous). + * -- Cort + */ + if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) + goto out; + + if ((v = p_mapped_by_tlbcam(p))) + goto out; + + if (mem_init_done) { + struct vm_struct *area; + area = get_vm_area(size, VM_IOREMAP); + if (area == 0) + return NULL; + v = (unsigned long) area->addr; + } else { + v = (ioremap_bot -= size); + } + + if ((flags & _PAGE_PRESENT) == 0) + flags |= _PAGE_KERNEL; + if (flags & _PAGE_NO_CACHE) + flags |= _PAGE_GUARDED; + + /* + * Should check if it is a candidate for a BAT mapping + */ + + err = 0; + for (i = 0; i < size && err == 0; i += PAGE_SIZE) + err = map_page(v+i, p+i, flags); + if (err) { + if (mem_init_done) + vunmap((void *)v); + return NULL; + } + +out: + return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK)); +} + +void iounmap(volatile void __iomem *addr) +{ + /* + * If mapped by BATs then there is nothing to do. + * Calling vfree() generates a benign warning. + */ + if (v_mapped_by_bats((unsigned long)addr)) return; + + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vunmap((void *) (PAGE_MASK & (unsigned long)addr)); +} + +void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + return (void __iomem *) (port + _IO_BASE); +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +int +map_page(unsigned long va, phys_addr_t pa, int flags) +{ + pmd_t *pd; + pte_t *pg; + int err = -ENOMEM; + + spin_lock(&init_mm.page_table_lock); + /* Use upper 10 bits of VA to index the first level map */ + pd = pmd_offset(pgd_offset_k(va), va); + /* Use middle 10 bits of VA to index the second-level map */ + pg = pte_alloc_kernel(&init_mm, pd, va); + if (pg != 0) { + err = 0; + set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); + if (mem_init_done) + flush_HPTE(0, va, pmd_val(*pd)); + } + spin_unlock(&init_mm.page_table_lock); + return err; +} + +/* + * Map in all of physical memory starting at KERNELBASE. + */ +void __init mapin_ram(void) +{ + unsigned long v, p, s, f; + + s = mmu_mapin_ram(); + v = KERNELBASE + s; + p = PPC_MEMSTART + s; + for (; s < total_lowmem; s += PAGE_SIZE) { + if ((char *) v >= _stext && (char *) v < etext) + f = _PAGE_RAM_TEXT; + else + f = _PAGE_RAM; + map_page(v, p, f); + v += PAGE_SIZE; + p += PAGE_SIZE; + } +} + +/* is x a power of 2? */ +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) + +/* is x a power of 4? */ +#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1)) + +/* + * Set up a mapping for a block of I/O. + * virt, phys, size must all be page-aligned. + * This should only be called before ioremap is called. + */ +void __init io_block_mapping(unsigned long virt, phys_addr_t phys, + unsigned int size, int flags) +{ + int i; + + if (virt > KERNELBASE && virt < ioremap_bot) + ioremap_bot = ioremap_base = virt; + +#ifdef HAVE_BATS + /* + * Use a BAT for this if possible... + */ + if (io_bat_index < 2 && is_power_of_2(size) + && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) { + setbat(io_bat_index, virt, phys, size, flags); + ++io_bat_index; + return; + } +#endif /* HAVE_BATS */ + +#ifdef HAVE_TLBCAM + /* + * Use a CAM for this if possible... + */ + if (tlbcam_index < num_tlbcam_entries && is_power_of_4(size) + && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) { + settlbcam(tlbcam_index, virt, phys, size, flags, 0); + ++tlbcam_index; + return; + } +#endif /* HAVE_TLBCAM */ + + /* No BATs available, put it in the page tables. */ + for (i = 0; i < size; i += PAGE_SIZE) + map_page(virt + i, phys + i, flags); +} + +/* Scan the real Linux page tables and return a PTE pointer for + * a virtual address in a context. + * Returns true (1) if PTE was found, zero otherwise. The pointer to + * the PTE pointer is unmodified if PTE is not found. + */ +int +get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int retval = 0; + + pgd = pgd_offset(mm, addr & PAGE_MASK); + if (pgd) { + pmd = pmd_offset(pgd, addr & PAGE_MASK); + if (pmd_present(*pmd)) { + pte = pte_offset_map(pmd, addr & PAGE_MASK); + if (pte) { + retval = 1; + *ptep = pte; + /* XXX caller needs to do pte_unmap, yuck */ + } + } + } + return(retval); +} + +/* Find physical address for this virtual address. Normally used by + * I/O functions, but anyone can call it. + */ +unsigned long iopa(unsigned long addr) +{ + unsigned long pa; + + /* I don't know why this won't work on PMacs or CHRP. It + * appears there is some bug, or there is some implicit + * mapping done not properly represented by BATs or in page + * tables.......I am actively working on resolving this, but + * can't hold up other stuff. -- Dan + */ + pte_t *pte; + struct mm_struct *mm; + + /* Check the BATs */ + pa = v_mapped_by_bats(addr); + if (pa) + return pa; + + /* Allow mapping of user addresses (within the thread) + * for DMA if necessary. + */ + if (addr < TASK_SIZE) + mm = current->mm; + else + mm = &init_mm; + + pa = 0; + if (get_pteptr(mm, addr, &pte)) { + pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK); + pte_unmap(pte); + } + + return(pa); +} + +/* This is will find the virtual address for a physical one.... + * Swiped from APUS, could be dangerous :-). + * This is only a placeholder until I really find a way to make this + * work. -- Dan + */ +unsigned long +mm_ptov (unsigned long paddr) +{ + unsigned long ret; +#if 0 + if (paddr < 16*1024*1024) + ret = ZTWO_VADDR(paddr); + else { + int i; + + for (i = 0; i < kmap_chunk_count;){ + unsigned long phys = kmap_chunks[i++]; + unsigned long size = kmap_chunks[i++]; + unsigned long virt = kmap_chunks[i++]; + if (paddr >= phys + && paddr < (phys + size)){ + ret = virt + paddr - phys; + goto exit; + } + } + + ret = (unsigned long) __va(paddr); + } +exit: +#ifdef DEBUGPV + printk ("PTOV(%lx)=%lx\n", paddr, ret); +#endif +#else + ret = (unsigned long)paddr + KERNELBASE; +#endif + return ret; +} + diff --git a/arch/powerpc/mm/pgtable64.c b/arch/powerpc/mm/pgtable64.c new file mode 100644 index 000000000000..724f97e5dee5 --- /dev/null +++ b/arch/powerpc/mm/pgtable64.c @@ -0,0 +1,357 @@ +/* + * This file contains ioremap and related functions for 64-bit machines. + * + * Derived from arch/ppc64/mm/init.c + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@samba.org) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Dave Engebretsen + * Rework for PPC64 port. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if PGTABLE_RANGE > USER_VSID_RANGE +#warning Limited user VSID range means pagetable space is wasted +#endif + +#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE) +#warning TASK_SIZE is smaller than it needs to be. +#endif + +int mem_init_done; +unsigned long ioremap_bot = IMALLOC_BASE; +static unsigned long phbs_io_bot = PHBS_IO_BASE; + +extern pgd_t swapper_pg_dir[]; +extern struct task_struct *current_set[NR_CPUS]; + +unsigned long klimit = (unsigned long)_end; + +/* max amount of RAM to use */ +unsigned long __max_memory; + +/* info on what we think the IO hole is */ +unsigned long io_hole_start; +unsigned long io_hole_size; + +#ifdef CONFIG_PPC_ISERIES + +void __iomem *ioremap(unsigned long addr, unsigned long size) +{ + return (void __iomem *)addr; +} + +extern void __iomem *__ioremap(unsigned long addr, unsigned long size, + unsigned long flags) +{ + return (void __iomem *)addr; +} + +void iounmap(volatile void __iomem *addr) +{ + return; +} + +#else + +/* + * map_io_page currently only called by __ioremap + * map_io_page adds an entry to the ioremap page table + * and adds an entry to the HPT, possibly bolting it + */ +static int map_io_page(unsigned long ea, unsigned long pa, int flags) +{ + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long vsid; + + if (mem_init_done) { + spin_lock(&init_mm.page_table_lock); + pgdp = pgd_offset_k(ea); + pudp = pud_alloc(&init_mm, pgdp, ea); + if (!pudp) + return -ENOMEM; + pmdp = pmd_alloc(&init_mm, pudp, ea); + if (!pmdp) + return -ENOMEM; + ptep = pte_alloc_kernel(&init_mm, pmdp, ea); + if (!ptep) + return -ENOMEM; + set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, + __pgprot(flags))); + spin_unlock(&init_mm.page_table_lock); + } else { + unsigned long va, vpn, hash, hpteg; + + /* + * If the mm subsystem is not fully up, we cannot create a + * linux page table entry for this mapping. Simply bolt an + * entry in the hardware page table. + */ + vsid = get_kernel_vsid(ea); + va = (vsid << 28) | (ea & 0xFFFFFFF); + vpn = va >> PAGE_SHIFT; + + hash = hpt_hash(vpn, 0); + + hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); + + /* Panic if a pte grpup is full */ + if (ppc_md.hpte_insert(hpteg, va, pa >> PAGE_SHIFT, + HPTE_V_BOLTED, + _PAGE_NO_CACHE|_PAGE_GUARDED|PP_RWXX) + == -1) { + panic("map_io_page: could not insert mapping"); + } + } + return 0; +} + + +static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, + unsigned long ea, unsigned long size, + unsigned long flags) +{ + unsigned long i; + + if ((flags & _PAGE_PRESENT) == 0) + flags |= pgprot_val(PAGE_KERNEL); + + for (i = 0; i < size; i += PAGE_SIZE) + if (map_io_page(ea+i, pa+i, flags)) + return NULL; + + return (void __iomem *) (ea + (addr & ~PAGE_MASK)); +} + + +void __iomem * +ioremap(unsigned long addr, unsigned long size) +{ + return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED); +} + +void __iomem * __ioremap(unsigned long addr, unsigned long size, + unsigned long flags) +{ + unsigned long pa, ea; + void __iomem *ret; + + /* + * Choose an address to map it to. + * Once the imalloc system is running, we use it. + * Before that, we map using addresses going + * up from ioremap_bot. imalloc will use + * the addresses from ioremap_bot through + * IMALLOC_END + * + */ + pa = addr & PAGE_MASK; + size = PAGE_ALIGN(addr + size) - pa; + + if (size == 0) + return NULL; + + if (mem_init_done) { + struct vm_struct *area; + area = im_get_free_area(size); + if (area == NULL) + return NULL; + ea = (unsigned long)(area->addr); + ret = __ioremap_com(addr, pa, ea, size, flags); + if (!ret) + im_free(area->addr); + } else { + ea = ioremap_bot; + ret = __ioremap_com(addr, pa, ea, size, flags); + if (ret) + ioremap_bot += size; + } + return ret; +} + +#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK)) + +int __ioremap_explicit(unsigned long pa, unsigned long ea, + unsigned long size, unsigned long flags) +{ + struct vm_struct *area; + void __iomem *ret; + + /* For now, require page-aligned values for pa, ea, and size */ + if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) || + !IS_PAGE_ALIGNED(size)) { + printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__); + return 1; + } + + if (!mem_init_done) { + /* Two things to consider in this case: + * 1) No records will be kept (imalloc, etc) that the region + * has been remapped + * 2) It won't be easy to iounmap() the region later (because + * of 1) + */ + ; + } else { + area = im_get_area(ea, size, + IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS); + if (area == NULL) { + /* Expected when PHB-dlpar is in play */ + return 1; + } + if (ea != (unsigned long) area->addr) { + printk(KERN_ERR "unexpected addr return from " + "im_get_area\n"); + return 1; + } + } + + ret = __ioremap_com(pa, pa, ea, size, flags); + if (ret == NULL) { + printk(KERN_ERR "ioremap_explicit() allocation failure !\n"); + return 1; + } + if (ret != (void *) ea) { + printk(KERN_ERR "__ioremap_com() returned unexpected addr\n"); + return 1; + } + + return 0; +} + +/* + * Unmap an IO region and remove it from imalloc'd list. + * Access to IO memory should be serialized by driver. + * This code is modeled after vmalloc code - unmap_vm_area() + * + * XXX what about calls before mem_init_done (ie python_countermeasures()) + */ +void iounmap(volatile void __iomem *token) +{ + void *addr; + + if (!mem_init_done) + return; + + addr = (void *) ((unsigned long __force) token & PAGE_MASK); + + im_free(addr); +} + +static int iounmap_subset_regions(unsigned long addr, unsigned long size) +{ + struct vm_struct *area; + + /* Check whether subsets of this region exist */ + area = im_get_area(addr, size, IM_REGION_SUPERSET); + if (area == NULL) + return 1; + + while (area) { + iounmap((void __iomem *) area->addr); + area = im_get_area(addr, size, + IM_REGION_SUPERSET); + } + + return 0; +} + +int iounmap_explicit(volatile void __iomem *start, unsigned long size) +{ + struct vm_struct *area; + unsigned long addr; + int rc; + + addr = (unsigned long __force) start & PAGE_MASK; + + /* Verify that the region either exists or is a subset of an existing + * region. In the latter case, split the parent region to create + * the exact region + */ + area = im_get_area(addr, size, + IM_REGION_EXISTS | IM_REGION_SUBSET); + if (area == NULL) { + /* Determine whether subset regions exist. If so, unmap */ + rc = iounmap_subset_regions(addr, size); + if (rc) { + printk(KERN_ERR + "%s() cannot unmap nonexistent range 0x%lx\n", + __FUNCTION__, addr); + return 1; + } + } else { + iounmap((void __iomem *) area->addr); + } + /* + * FIXME! This can't be right: + iounmap(area->addr); + * Maybe it should be "iounmap(area);" + */ + return 0; +} + +#endif + +EXPORT_SYMBOL(ioremap); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); diff --git a/arch/powerpc/mm/ppc_mmu.c b/arch/powerpc/mm/ppc_mmu.c new file mode 100644 index 000000000000..9a381ed5eb21 --- /dev/null +++ b/arch/powerpc/mm/ppc_mmu.c @@ -0,0 +1,296 @@ +/* + * This file contains the routines for handling the MMU on those + * PowerPC implementations where the MMU substantially follows the + * architecture specification. This includes the 6xx, 7xx, 7xxx, + * 8260, and POWER3 implementations but excludes the 8xx and 4xx. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mmu_decl.h" +#include "mem_pieces.h" + +PTE *Hash, *Hash_end; +unsigned long Hash_size, Hash_mask; +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 */ + unsigned long start; + unsigned long limit; + unsigned long phys; +} bat_addrs[4]; + +/* + * Return PA for this VA if it is mapped by a BAT, or 0 + */ +unsigned long v_mapped_by_bats(unsigned long va) +{ + int b; + for (b = 0; b < 4; ++b) + if (va >= bat_addrs[b].start && va < bat_addrs[b].limit) + return bat_addrs[b].phys + (va - bat_addrs[b].start); + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +unsigned long p_mapped_by_bats(unsigned long pa) +{ + int b; + for (b = 0; b < 4; ++b) + if (pa >= bat_addrs[b].phys + && pa < (bat_addrs[b].limit-bat_addrs[b].start) + +bat_addrs[b].phys) + return bat_addrs[b].start+(pa-bat_addrs[b].phys); + return 0; +} + +unsigned long __init mmu_mapin_ram(void) +{ +#ifdef CONFIG_POWER4 + return 0; +#else + unsigned long tot, bl, done; + unsigned long max_size = (256<<20); + unsigned long align; + + if (__map_without_bats) + return 0; + + /* Set up BAT2 and if necessary BAT3 to cover RAM. */ + + /* Make sure we don't map a block larger than the + smallest alignment of the physical address. */ + /* alignment of PPC_MEMSTART */ + align = ~(PPC_MEMSTART-1) & PPC_MEMSTART; + /* set BAT block size to MIN(max_size, align) */ + if (align && align < max_size) + max_size = align; + + tot = total_lowmem; + for (bl = 128<<10; bl < max_size; bl <<= 1) { + if (bl * 2 > tot) + break; + } + + setbat(2, KERNELBASE, PPC_MEMSTART, bl, _PAGE_RAM); + done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; + if ((done < tot) && !bat_addrs[3].limit) { + /* use BAT3 to cover a bit more */ + tot -= done; + for (bl = 128<<10; bl < max_size; bl <<= 1) + if (bl * 2 > tot) + break; + setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bl, _PAGE_RAM); + done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1; + } + + return done; +#endif +} + +/* + * Set up one of the I/D BAT (block address translation) register pairs. + * The parameters are not checked; in particular size must be a power + * of 2 between 128k and 256M. + */ +void __init setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags) +{ + unsigned int bl; + int wimgxpp; + union ubat *bat = BATS[index]; + + if (((flags & _PAGE_NO_CACHE) == 0) && + cpu_has_feature(CPU_FTR_NEED_COHERENT)) + flags |= _PAGE_COHERENT; + + bl = (size >> 17) - 1; + if (PVR_VER(mfspr(SPRN_PVR)) != 1) { + /* 603, 604, etc. */ + /* Do DBAT first */ + wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE + | _PAGE_COHERENT | _PAGE_GUARDED); + wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX; + bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */ + bat[1].word[1] = phys | wimgxpp; +#ifndef CONFIG_KGDB /* want user access for breakpoints */ + if (flags & _PAGE_USER) +#endif + bat[1].bat.batu.vp = 1; + if (flags & _PAGE_GUARDED) { + /* G bit must be zero in IBATs */ + bat[0].word[0] = bat[0].word[1] = 0; + } else { + /* make IBAT same as DBAT */ + bat[0] = bat[1]; + } + } else { + /* 601 cpu */ + if (bl > BL_8M) + bl = BL_8M; + wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE + | _PAGE_COHERENT); + wimgxpp |= (flags & _PAGE_RW)? + ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX; + bat->word[0] = virt | wimgxpp | 4; /* Ks=0, Ku=1 */ + bat->word[1] = phys | bl | 0x40; /* V=1 */ + } + + bat_addrs[index].start = virt; + bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1; + bat_addrs[index].phys = phys; +} + +/* + * Initialize the hash table and patch the instructions in hashtable.S. + */ +void __init MMU_init_hw(void) +{ + unsigned int hmask, mb, mb2; + unsigned int n_hpteg, lg_n_hpteg; + + extern unsigned int hash_page_patch_A[]; + extern unsigned int hash_page_patch_B[], hash_page_patch_C[]; + extern unsigned int hash_page[]; + extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[]; + + if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) { + /* + * Put a blr (procedure return) instruction at the + * start of hash_page, since we can still get DSI + * exceptions on a 603. + */ + hash_page[0] = 0x4e800020; + flush_icache_range((unsigned long) &hash_page[0], + (unsigned long) &hash_page[1]); + return; + } + + 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 + +#ifdef CONFIG_POWER4 + /* The hash table has already been allocated and initialized + in prom.c */ + n_hpteg = Hash_size >> LG_HPTEG_SIZE; + lg_n_hpteg = __ilog2(n_hpteg); + + /* Remove the hash table from the available memory */ + if (Hash) + reserve_phys_mem(__pa(Hash), Hash_size); + +#else /* CONFIG_POWER4 */ + /* + * Allow 1 HPTE (1/8 HPTEG) for each page of memory. + * This is less than the recommended amount, but then + * Linux ain't AIX. + */ + n_hpteg = total_memory / (PAGE_SIZE * 8); + if (n_hpteg < MIN_N_HPTEG) + n_hpteg = MIN_N_HPTEG; + lg_n_hpteg = __ilog2(n_hpteg); + if (n_hpteg & (n_hpteg - 1)) { + ++lg_n_hpteg; /* round up if not power of 2 */ + n_hpteg = 1 << lg_n_hpteg; + } + Hash_size = n_hpteg << LG_HPTEG_SIZE; + + /* + * Find some memory for the hash table. + */ + if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); + Hash = mem_pieces_find(Hash_size, Hash_size); + cacheable_memzero(Hash, Hash_size); + _SDR1 = __pa(Hash) | SDR1_LOW_BITS; +#endif /* CONFIG_POWER4 */ + + Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); + + printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n", + total_memory >> 20, Hash_size >> 10, Hash); + + + /* + * Patch up the instructions in hashtable.S:create_hpte + */ + if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345); + Hash_mask = n_hpteg - 1; + hmask = Hash_mask >> (16 - LG_HPTEG_SIZE); + mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg; + if (lg_n_hpteg > 16) + mb2 = 16 - LG_HPTEG_SIZE; + + hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) + | ((unsigned int)(Hash) >> 16); + hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6); + hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | (mb2 << 6); + hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | hmask; + hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask; + + /* + * Ensure that the locations we've patched have been written + * out from the data cache and invalidated in the instruction + * cache, on those machines with split caches. + */ + flush_icache_range((unsigned long) &hash_page_patch_A[0], + (unsigned long) &hash_page_patch_C[1]); + + /* + * Patch up the instructions in hashtable.S:flush_hash_page + */ + flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff) + | ((unsigned int)(Hash) >> 16); + flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) | (mb << 6); + flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) | (mb2 << 6); + flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) | hmask; + flush_icache_range((unsigned long) &flush_hash_patch_A[0], + (unsigned long) &flush_hash_patch_B[1]); + + if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); +} diff --git a/arch/powerpc/mm/tlb.c b/arch/powerpc/mm/tlb.c new file mode 100644 index 000000000000..6c3dc3c44c86 --- /dev/null +++ b/arch/powerpc/mm/tlb.c @@ -0,0 +1,183 @@ +/* + * This file contains the routines for TLB flushing. + * On machines where the MMU uses a hash table to store virtual to + * physical translations, these routines flush entries from the + * hash table also. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * 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 "mmu_decl.h" + +/* + * Called when unmapping pages to flush entries from the TLB/hash table. + */ +void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr) +{ + unsigned long ptephys; + + if (Hash != 0) { + ptephys = __pa(ptep) & PAGE_MASK; + flush_hash_pages(mm->context, addr, ptephys, 1); + } +} + +/* + * Called by ptep_set_access_flags, must flush on CPUs for which the + * DSI handler can't just "fixup" the TLB on a write fault + */ +void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr) +{ + if (Hash != 0) + return; + _tlbie(addr); +} + +/* + * Called at the end of a mmu_gather operation to make sure the + * TLB flush is completely done. + */ +void tlb_flush(struct mmu_gather *tlb) +{ + if (Hash == 0) { + /* + * 603 needs to flush the whole TLB here since + * it doesn't use a hash table. + */ + _tlbia(); + } +} + +/* + * TLB flushing: + * + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes kernel pages + * + * since the hardware hash table functions as an extension of the + * tlb as far as the linux tables are concerned, flush it too. + * -- Cort + */ + +/* + * 750 SMP is a Bad Idea because the 750 doesn't broadcast all + * the cache operations on the bus. Hence we need to use an IPI + * to get the other CPU(s) to invalidate their TLBs. + */ +#ifdef CONFIG_SMP_750 +#define FINISH_FLUSH smp_send_tlb_invalidate(0) +#else +#define FINISH_FLUSH do { } while (0) +#endif + +static void flush_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + pmd_t *pmd; + unsigned long pmd_end; + int count; + unsigned int ctx = mm->context; + + if (Hash == 0) { + _tlbia(); + return; + } + start &= PAGE_MASK; + if (start >= end) + return; + end = (end - 1) | ~PAGE_MASK; + pmd = pmd_offset(pgd_offset(mm, start), start); + for (;;) { + pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1; + if (pmd_end > end) + pmd_end = end; + if (!pmd_none(*pmd)) { + count = ((pmd_end - start) >> PAGE_SHIFT) + 1; + flush_hash_pages(ctx, start, pmd_val(*pmd), count); + } + if (pmd_end == end) + break; + start = pmd_end + 1; + ++pmd; + } +} + +/* + * Flush kernel TLB entries in the given range + */ +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + flush_range(&init_mm, start, end); + FINISH_FLUSH; +} + +/* + * Flush all the (user) entries for the address space described by mm. + */ +void flush_tlb_mm(struct mm_struct *mm) +{ + struct vm_area_struct *mp; + + if (Hash == 0) { + _tlbia(); + return; + } + + for (mp = mm->mmap; mp != NULL; mp = mp->vm_next) + flush_range(mp->vm_mm, mp->vm_start, mp->vm_end); + FINISH_FLUSH; +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + struct mm_struct *mm; + pmd_t *pmd; + + if (Hash == 0) { + _tlbie(vmaddr); + return; + } + 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); + FINISH_FLUSH; +} + +/* + * For each address in the range, find the pte for the address + * and check _PAGE_HASHPTE bit; if it is set, find and destroy + * the corresponding HPTE. + */ +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + flush_range(vma->vm_mm, start, end); + FINISH_FLUSH; +} diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/4xx/Kconfig new file mode 100644 index 000000000000..ed39d6a3d22a --- /dev/null +++ b/arch/powerpc/platforms/4xx/Kconfig @@ -0,0 +1,280 @@ +config 4xx + bool + depends on 40x || 44x + default y + +config WANT_EARLY_SERIAL + bool + select SERIAL_8250 + default n + +menu "AMCC 4xx options" + depends on 4xx + +choice + prompt "Machine Type" + depends on 40x + default WALNUT + +config BUBINGA + bool "Bubinga" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM 405EP evaluation board. + +config CPCI405 + bool "CPCI405" + help + This option enables support for the CPCI405 board. + +config EP405 + bool "EP405/EP405PC" + help + This option enables support for the EP405/EP405PC boards. + +config REDWOOD_5 + bool "Redwood-5" + help + This option enables support for the IBM STB04 evaluation board. + +config REDWOOD_6 + bool "Redwood-6" + help + This option enables support for the IBM STBx25xx evaluation board. + +config SYCAMORE + bool "Sycamore" + help + This option enables support for the IBM PPC405GPr evaluation board. + +config WALNUT + bool "Walnut" + help + This option enables support for the IBM PPC405GP evaluation board. + +config XILINX_ML300 + bool "Xilinx-ML300" + help + This option enables support for the Xilinx ML300 evaluation board. + +endchoice + +choice + prompt "Machine Type" + depends on 44x + default EBONY + +config BAMBOO + bool "Bamboo" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440EP evaluation board. + +config EBONY + bool "Ebony" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440GP evaluation board. + +config LUAN + bool "Luan" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440SP evaluation board. + +config OCOTEA + bool "Ocotea" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440GX evaluation board. + +endchoice + +config EP405PC + bool "EP405PC Support" + depends on EP405 + + +# It's often necessary to know the specific 4xx processor type. +# Fortunately, it is impled (so far) from the board type, so we +# don't need to ask more redundant questions. +config NP405H + bool + depends on ASH + default y + +config 440EP + bool + depends on BAMBOO + select PPC_FPU + default y + +config 440GP + bool + depends on EBONY + default y + +config 440GX + bool + depends on OCOTEA + default y + +config 440SP + bool + depends on LUAN + default y + +config 440 + bool + depends on 440GP || 440SP || 440EP + default y + +config 440A + bool + depends on 440GX + default y + +config IBM440EP_ERR42 + bool + depends on 440EP + default y + +# All 405-based cores up until the 405GPR and 405EP have this errata. +config IBM405_ERR77 + bool + depends on 40x && !403GCX && !405GPR && !405EP + default y + +# All 40x-based cores, up until the 405GPR and 405EP have this errata. +config IBM405_ERR51 + bool + depends on 40x && !405GPR && !405EP + default y + +config BOOKE + bool + depends on 44x + default y + +config IBM_OCP + bool + depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y + +config XILINX_OCP + bool + depends on XILINX_ML300 + default y + +config IBM_EMAC4 + bool + depends on 440GX || 440SP + default y + +config BIOS_FIXUP + bool + depends on BUBINGA || EP405 || SYCAMORE || WALNUT + default y + +# OAK doesn't exist but wanted to keep this around for any future 403GCX boards +config 403GCX + bool + depends OAK + default y + +config 405EP + bool + depends on BUBINGA + default y + +config 405GP + bool + depends on CPCI405 || EP405 || WALNUT + default y + +config 405GPR + bool + depends on SYCAMORE + default y + +config VIRTEX_II_PRO + bool + depends on XILINX_ML300 + default y + +config STB03xxx + bool + depends on REDWOOD_5 || REDWOOD_6 + default y + +config EMBEDDEDBOOT + bool + depends on EP405 || XILINX_ML300 + default y + +config IBM_OPENBIOS + bool + depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y + +config PPC4xx_DMA + bool "PPC4xx DMA controller support" + depends on 4xx + +config PPC4xx_EDMA + bool + depends on !STB03xxx && PPC4xx_DMA + default y + +config PPC_GEN550 + bool + depends on 4xx + default y + +choice + prompt "TTYS0 device and default console" + depends on 40x + default UART0_TTYS0 + +config UART0_TTYS0 + bool "UART0" + +config UART0_TTYS1 + bool "UART1" + +endchoice + +config SERIAL_SICC + bool "SICC Serial port support" + depends on STB03xxx + +config UART1_DFLT_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +config SERIAL_SICC_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y +endmenu + + +menu "IBM 40x options" + depends on 40x + +config SERIAL_SICC + bool "SICC Serial port" + depends on STB03xxx + +config UART1_DFLT_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +config SERIAL_SICC_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +endmenu diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig new file mode 100644 index 000000000000..c5bc2821d991 --- /dev/null +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -0,0 +1,86 @@ +config 85xx + bool + depends on E500 + default y + +config PPC_INDIRECT_PCI_BE + bool + depends on 85xx + default y + +menu "Freescale 85xx options" + depends on E500 + +choice + prompt "Machine Type" + depends on 85xx + default MPC8540_ADS + +config MPC8540_ADS + bool "Freescale MPC8540 ADS" + help + This option enables support for the MPC 8540 ADS evaluation board. + +config MPC8548_CDS + bool "Freescale MPC8548 CDS" + help + This option enablese support for the MPC8548 CDS evaluation board. + +config MPC8555_CDS + bool "Freescale MPC8555 CDS" + help + This option enablese support for the MPC8555 CDS evaluation board. + +config MPC8560_ADS + bool "Freescale MPC8560 ADS" + help + This option enables support for the MPC 8560 ADS evaluation board. + +config SBC8560 + bool "WindRiver PowerQUICC III SBC8560" + help + This option enables support for the WindRiver PowerQUICC III + SBC8560 board. + +config STX_GP3 + bool "Silicon Turnkey Express GP3" + help + This option enables support for the Silicon Turnkey Express GP3 + board. + +endchoice + +# It's often necessary to know the specific 85xx processor type. +# Fortunately, it is implied (so far) from the board type, so we +# don't need to ask more redundant questions. +config MPC8540 + bool + depends on MPC8540_ADS + default y + +config MPC8548 + bool + depends on MPC8548_CDS + default y + +config MPC8555 + bool + depends on MPC8555_CDS + default y + +config MPC8560 + bool + depends on SBC8560 || MPC8560_ADS || STX_GP3 + default y + +config 85xx_PCI2 + bool "Supprt for 2nd PCI host controller" + depends on MPC8555_CDS + default y + +config PPC_GEN550 + bool + depends on MPC8540 || SBC8560 || MPC8555 + default y + +endmenu diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig new file mode 100644 index 000000000000..c8c0ba3cf8e8 --- /dev/null +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -0,0 +1,352 @@ +config FADS + bool + +choice + prompt "8xx Machine Type" + depends on 8xx + default RPXLITE + +config RPXLITE + bool "RPX-Lite" + ---help--- + Single-board computers based around the PowerPC MPC8xx chips and + intended for embedded applications. The following types are + supported: + + RPX-Lite: + Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823. + + RPX-Classic: + Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on + the MPC 860 + + BSE-IP: + Bright Star Engineering ip-Engine. + + TQM823L: + TQM850L: + TQM855L: + TQM860L: + MPC8xx based family of mini modules, half credit card size, + up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports, + 2 x CAN bus interface, ... + Manufacturer: TQ Components, www.tq-group.de + Date of Release: October (?) 1999 + End of Life: not yet :-) + URL: + - module: + - starter kit: + - images: + + FPS850L: + FingerPrint Sensor System (based on TQM850L) + Manufacturer: IKENDI AG, + Date of Release: November 1999 + End of life: end 2000 ? + URL: see TQM850L + + IVMS8: + MPC860 based board used in the "Integrated Voice Mail System", + Small Version (8 voice channels) + Manufacturer: Speech Design, + Date of Release: December 2000 (?) + End of life: - + URL: + + IVML24: + MPC860 based board used in the "Integrated Voice Mail System", + Large Version (24 voice channels) + Manufacturer: Speech Design, + Date of Release: March 2001 (?) + End of life: - + URL: + + HERMES: + Hermes-Pro ISDN/LAN router with integrated 8 x hub + Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik + + Date of Release: 2000 (?) + End of life: - + URL: + + IP860: + VMEBus IP (Industry Pack) carrier board with MPC860 + Manufacturer: MicroSys GmbH, + Date of Release: ? + End of life: - + URL: + + PCU_E: + PCU = Peripheral Controller Unit, Extended + Manufacturer: Siemens AG, ICN (Information and Communication Networks) + + Date of Release: April 2001 + End of life: August 2001 + URL: n. a. + +config RPXCLASSIC + bool "RPX-Classic" + help + The RPX-Classic is a single-board computer based on the Motorola + MPC860. It features 16MB of DRAM and a variable amount of flash, + I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two + LEDs. Variants with Ethernet ports exist. Say Y here to support it + directly. + +config BSEIP + bool "BSE-IP" + help + Say Y here to support the Bright Star Engineering ipEngine SBC. + This is a credit-card-sized device featuring a MPC823 processor, + 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video + controller, and two RS232 ports. + +config MPC8XXFADS + bool "FADS" + select FADS + +config MPC86XADS + bool "MPC86XADS" + help + MPC86x Application Development System by Freescale Semiconductor. + The MPC86xADS is meant to serve as a platform for s/w and h/w + development around the MPC86X processor families. + select FADS + +config MPC885ADS + bool "MPC885ADS" + help + Freescale Semiconductor MPC885 Application Development System (ADS). + Also known as DUET. + The MPC885ADS is meant to serve as a platform for s/w and h/w + development around the MPC885 processor family. + +config TQM823L + bool "TQM823L" + help + Say Y here to support the TQM823L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +config TQM850L + bool "TQM850L" + help + Say Y here to support the TQM850L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +config TQM855L + bool "TQM855L" + help + Say Y here to support the TQM855L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +config TQM860L + bool "TQM860L" + help + Say Y here to support the TQM860L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +config FPS850L + bool "FPS850L" + +config IVMS8 + bool "IVMS8" + help + Say Y here to support the Integrated Voice-Mail Small 8-channel SBC + from Speech Design, released March 2001. The manufacturer's website + is at . + +config IVML24 + bool "IVML24" + help + Say Y here to support the Integrated Voice-Mail Large 24-channel SBC + from Speech Design, released March 2001. The manufacturer's website + is at . + +config HERMES_PRO + bool "HERMES" + +config IP860 + bool "IP860" + +config LWMON + bool "LWMON" + +config PCU_E + bool "PCU_E" + +config CCM + bool "CCM" + +config LANTEC + bool "LANTEC" + +config MBX + bool "MBX" + help + MBX is a line of Motorola single-board computer based around the + MPC821 and MPC860 processors, and intended for embedded-controller + applications. Say Y here to support these boards directly. + +config WINCEPT + bool "WinCept" + help + The Wincept 100/110 is a Motorola single-board computer based on the + MPC821 PowerPC, introduced in 1998 and designed to be used in + thin-client machines. Say Y to support it directly. + +endchoice + +# +# MPC8xx Communication options +# + +menu "MPC8xx CPM Options" + depends on 8xx + +config SCC_ENET + bool "CPM SCC Ethernet" + depends on NET_ETHERNET + help + Enable Ethernet support via the Motorola MPC8xx serial + communications controller. + +choice + prompt "SCC used for Ethernet" + depends on SCC_ENET + default SCC1_ENET + +config SCC1_ENET + bool "SCC1" + help + Use MPC8xx serial communications controller 1 to drive Ethernet + (default). + +config SCC2_ENET + bool "SCC2" + help + Use MPC8xx serial communications controller 2 to drive Ethernet. + +config SCC3_ENET + bool "SCC3" + help + Use MPC8xx serial communications controller 3 to drive Ethernet. + +endchoice + +config FEC_ENET + bool "860T FEC Ethernet" + depends on NET_ETHERNET + help + Enable Ethernet support via the Fast Ethernet Controller (FCC) on + the Motorola MPC8260. + +config USE_MDIO + bool "Use MDIO for PHY configuration" + depends on FEC_ENET + help + On some boards the hardware configuration of the ethernet PHY can be + used without any software interaction over the MDIO interface, so + all MII code can be omitted. Say N here if unsure or if you don't + need link status reports. + +config FEC_AM79C874 + bool "Support AMD79C874 PHY" + depends on USE_MDIO + +config FEC_LXT970 + bool "Support LXT970 PHY" + depends on USE_MDIO + +config FEC_LXT971 + bool "Support LXT971 PHY" + depends on USE_MDIO + +config FEC_QS6612 + bool "Support QS6612 PHY" + depends on USE_MDIO + +config ENET_BIG_BUFFERS + bool "Use Big CPM Ethernet Buffers" + depends on SCC_ENET || FEC_ENET + help + Allocate large buffers for MPC8xx Ethernet. Increases throughput + and decreases the likelihood of dropped packets, but costs memory. + +config HTDMSOUND + bool "Embedded Planet HIOX Audio" + depends on SOUND=y + +# This doesn't really belong here, but it is convenient to ask +# 8xx specific questions. +comment "Generic MPC8xx Options" + +config 8xx_COPYBACK + bool "Copy-Back Data Cache (else Writethrough)" + help + Saying Y here will cause the cache on an MPC8xx processor to be used + in Copy-Back mode. If you say N here, it is used in Writethrough + mode. + + If in doubt, say Y here. + +config 8xx_CPU6 + bool "CPU6 Silicon Errata (860 Pre Rev. C)" + help + MPC860 CPUs, prior to Rev C have some bugs in the silicon, which + require workarounds for Linux (and most other OSes to work). If you + get a BUG() very early in boot, this might fix the problem. For + more details read the document entitled "MPC860 Family Device Errata + Reference" on Motorola's website. This option also incurs a + performance hit. + + If in doubt, say N here. + +choice + prompt "Microcode patch selection" + default NO_UCODE_PATCH + help + Help not implemented yet, coming soon. + +config NO_UCODE_PATCH + bool "None" + +config USB_SOF_UCODE_PATCH + bool "USB SOF patch" + help + Help not implemented yet, coming soon. + +config I2C_SPI_UCODE_PATCH + bool "I2C/SPI relocation patch" + help + Help not implemented yet, coming soon. + +config I2C_SPI_SMC1_UCODE_PATCH + bool "I2C/SPI/SMC1 relocation patch" + help + Help not implemented yet, coming soon. + +endchoice + +config UCODE_PATCH + bool + default y + depends on !NO_UCODE_PATCH + +endmenu + diff --git a/arch/powerpc/platforms/apus/Kconfig b/arch/powerpc/platforms/apus/Kconfig new file mode 100644 index 000000000000..6bde3bffed86 --- /dev/null +++ b/arch/powerpc/platforms/apus/Kconfig @@ -0,0 +1,130 @@ + +config AMIGA + bool + depends on APUS + default y + help + This option enables support for the Amiga series of computers. + +config ZORRO + bool + depends on APUS + default y + help + This enables support for the Zorro bus in the Amiga. If you have + expansion cards in your Amiga that conform to the Amiga + AutoConfig(tm) specification, say Y, otherwise N. Note that even + expansion cards that do not fit in the Zorro slots but fit in e.g. + the CPU slot may fall in this category, so you have to say Y to let + Linux use these. + +config ABSTRACT_CONSOLE + bool + depends on APUS + default y + +config APUS_FAST_EXCEPT + bool + depends on APUS + default y + +config AMIGA_PCMCIA + bool "Amiga 1200/600 PCMCIA support" + depends on APUS && EXPERIMENTAL + help + Include support in the kernel for pcmcia on Amiga 1200 and Amiga + 600. If you intend to use pcmcia cards say Y; otherwise say N. + +config AMIGA_BUILTIN_SERIAL + tristate "Amiga builtin serial support" + depends on APUS + help + If you want to use your Amiga's built-in serial port in Linux, + answer Y. + + To compile this driver as a module, choose M here. + +config GVPIOEXT + tristate "GVP IO-Extender support" + depends on APUS + help + If you want to use a GVP IO-Extender serial card in Linux, say Y. + Otherwise, say N. + +config GVPIOEXT_LP + tristate "GVP IO-Extender parallel printer support" + depends on GVPIOEXT + help + Say Y to enable driving a printer from the parallel port on your + GVP IO-Extender card, N otherwise. + +config GVPIOEXT_PLIP + tristate "GVP IO-Extender PLIP support" + depends on GVPIOEXT + help + Say Y to enable doing IP over the parallel port on your GVP + IO-Extender card, N otherwise. + +config MULTIFACE_III_TTY + tristate "Multiface Card III serial support" + depends on APUS + help + If you want to use a Multiface III card's serial port in Linux, + answer Y. + + To compile this driver as a module, choose M here. + +config A2232 + tristate "Commodore A2232 serial support (EXPERIMENTAL)" + depends on EXPERIMENTAL && APUS + ---help--- + This option supports the 2232 7-port serial card shipped with the + Amiga 2000 and other Zorro-bus machines, dating from 1989. At + a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip + each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The + ports were connected with 8 pin DIN connectors on the card bracket, + for which 8 pin to DB25 adapters were supplied. The card also had + jumpers internally to toggle various pinning configurations. + + This driver can be built as a module; but then "generic_serial" + will also be built as a module. This has to be loaded before + "ser_a2232". If you want to do this, answer M here. + +config WHIPPET_SERIAL + tristate "Hisoft Whippet PCMCIA serial support" + depends on AMIGA_PCMCIA + help + HiSoft has a web page at , but there + is no listing for the Whippet in their Amiga section. + +config APNE + tristate "PCMCIA NE2000 support" + depends on AMIGA_PCMCIA + help + If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, + say N. + + To compile this driver as a module, choose M here: the + module will be called apne. + +config SERIAL_CONSOLE + bool "Support for serial port console" + depends on APUS && (AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y) + +config HEARTBEAT + bool "Use power LED as a heartbeat" + depends on APUS + help + Use the power-on LED on your machine as a load meter. The exact + behavior is platform-dependent, but normally the flash frequency is + a hyperbolic function of the 5-minute load average. + +config PROC_HARDWARE + bool "/proc/hardware support" + depends on APUS + +source "drivers/zorro/Kconfig" + +config PCI_PERMEDIA + bool "PCI for Permedia2" + depends on !4xx && !8xx && APUS diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig new file mode 100644 index 000000000000..4f3551430596 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -0,0 +1,313 @@ +choice + prompt "Machine Type" + depends on EMBEDDED6xx + +config APUS + bool "Amiga-APUS" + depends on BROKEN + help + Select APUS if configuring for a PowerUP Amiga. + More information is available at: + . + +config KATANA + bool "Artesyn-Katana" + help + Select KATANA if configuring an Artesyn KATANA 750i or 3750 + cPCI board. + +config WILLOW + bool "Cogent-Willow" + +config CPCI690 + bool "Force-CPCI690" + help + Select CPCI690 if configuring a Force CPCI690 cPCI board. + +config POWERPMC250 + bool "Force-PowerPMC250" + +config CHESTNUT + bool "IBM 750FX Eval board or 750GX Eval board" + help + Select CHESTNUT if configuring an IBM 750FX Eval Board or a + IBM 750GX Eval board. + +config SPRUCE + bool "IBM-Spruce" + +config HDPU + bool "Sky-HDPU" + help + Select HDPU if configuring a Sky Computers Compute Blade. + +config HDPU_FEATURES + depends HDPU + tristate "HDPU-Features" + help + Select to enable HDPU enhanced features. + +config EV64260 + bool "Marvell-EV64260BP" + help + Select EV64260 if configuring a Marvell (formerly Galileo) + EV64260BP Evaluation platform. + +config LOPEC + bool "Motorola-LoPEC" + +config MVME5100 + bool "Motorola-MVME5100" + +config PPLUS + bool "Motorola-PowerPlus" + +config PRPMC750 + bool "Motorola-PrPMC750" + +config PRPMC800 + bool "Motorola-PrPMC800" + +config SANDPOINT + bool "Motorola-Sandpoint" + help + Select SANDPOINT if configuring for a Motorola Sandpoint X3 + (any flavor). + +config RADSTONE_PPC7D + bool "Radstone Technology PPC7D board" + +config PAL4 + bool "SBS-Palomar4" + +config GEMINI + bool "Synergy-Gemini" + depends on BROKEN + help + Select Gemini if configuring for a Synergy Microsystems' Gemini + series Single Board Computer. More information is available at: + . + +config EST8260 + bool "EST8260" + ---help--- + The EST8260 is a single-board computer manufactured by Wind River + Systems, Inc. (formerly Embedded Support Tools Corp.) and based on + the MPC8260. Wind River Systems has a website at + , but the EST8260 cannot be found on it + and has probably been discontinued or rebadged. + +config SBC82xx + bool "SBC82xx" + ---help--- + SBC PowerQUICC II, single-board computer with MPC82xx CPU + Manufacturer: Wind River Systems, Inc. + Date of Release: May 2003 + End of Life: - + URL: + +config SBS8260 + bool "SBS8260" + +config RPX8260 + bool "RPXSUPER" + +config TQM8260 + bool "TQM8260" + ---help--- + MPC8260 based module, little larger than credit card, + up to 128 MB global + 64 MB local RAM, 32 MB Flash, + 32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet, + 2 x serial ports, ... + Manufacturer: TQ Components, www.tq-group.de + Date of Release: June 2001 + End of Life: not yet :-) + URL: + +config ADS8272 + bool "ADS8272" + +config PQ2FADS + bool "Freescale-PQ2FADS" + help + Select PQ2FADS if you wish to configure for a Freescale + PQ2FADS board (-VR or -ZU). + +config LITE5200 + bool "Freescale LITE5200 / (IceCube)" + select PPC_MPC52xx + help + Support for the LITE5200 dev board for the MPC5200 from Freescale. + This is for the LITE5200 version 2.0 board. Don't know if it changes + much but it's only been tested on this board version. I think this + board is also known as IceCube. + +config MPC834x_SYS + bool "Freescale MPC834x SYS" + help + This option enables support for the MPC 834x SYS evaluation board. + + Be aware that PCI buses can only function when SYS board is plugged + into the PIB (Platform IO Board) board from Freescale which provide + 3 PCI slots. The PIBs PCI initialization is the bootloader's + responsiblilty. + +config EV64360 + bool "Marvell-EV64360BP" + help + Select EV64360 if configuring a Marvell EV64360BP Evaluation + platform. +endchoice + +config PQ2ADS + bool + depends on ADS8272 + default y + +config TQM8xxL + bool + depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L) + default y + +config PPC_MPC52xx + bool + +config 8260 + bool "CPM2 Support" if WILLOW + depends on 6xx + default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS + help + The MPC8260 is a typical embedded CPU made by Motorola. Selecting + this option means that you wish to build a kernel for a machine with + an 8260 class CPU. + +config 8272 + bool + depends on 6xx + default y if ADS8272 + select 8260 + help + The MPC8272 CPM has a different internal dpram setup than other CPM2 + devices + +config 83xx + bool + default y if MPC834x_SYS + +config MPC834x + bool + default y if MPC834x_SYS + +config CPM2 + bool + depends on 8260 || MPC8560 || MPC8555 + default y + help + The CPM2 (Communications Processor Module) is a coprocessor on + embedded CPUs made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with a CPM2 coprocessor + on it (826x, 827x, 8560). + +config PPC_GEN550 + bool + depends on SANDPOINT || SPRUCE || PPLUS || \ + PRPMC750 || PRPMC800 || LOPEC || \ + (EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \ + 83xx + default y + +config FORCE + bool + depends on 6xx && POWERPMC250 + default y + +config GT64260 + bool + depends on EV64260 || CPCI690 + default y + +config MV64360 # Really MV64360 & MV64460 + bool + depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360 + default y + +config MV64X60 + bool + depends on (GT64260 || MV64360) + default y + +menu "Set bridge options" + depends on MV64X60 + +config NOT_COHERENT_CACHE + bool "Turn off Cache Coherency" + default n + help + Some 64x60 bridges lock up when trying to enforce cache coherency. + When this option is selected, cache coherency will be turned off. + Note that this can cause other problems (e.g., stale data being + speculatively loaded via a cached mapping). Use at your own risk. + +config MV64X60_BASE + hex "Set bridge base used by firmware" + default "0xf1000000" + help + A firmware can leave the base address of the bridge's registers at + a non-standard location. If so, set this value to reflect the + address of that non-standard location. + +config MV64X60_NEW_BASE + hex "Set bridge base used by kernel" + default "0xf1000000" + help + If the current base address of the bridge's registers is not where + you want it, set this value to the address that you want it moved to. + +endmenu + +config NONMONARCH_SUPPORT + bool "Enable Non-Monarch Support" + depends on PRPMC800 + +config HARRIER + bool + depends on PRPMC800 + default y + +config EPIC_SERIAL_MODE + bool + depends on 6xx && (LOPEC || SANDPOINT) + default y + +config MPC10X_BRIDGE + bool + depends on POWERPMC250 || LOPEC || SANDPOINT + default y + +config MPC10X_OPENPIC + bool + depends on POWERPMC250 || LOPEC || SANDPOINT + default y + +config MPC10X_STORE_GATHERING + bool "Enable MPC10x store gathering" + depends on MPC10X_BRIDGE + +config SANDPOINT_ENABLE_UART1 + bool "Enable DUART mode on Sandpoint" + depends on SANDPOINT + help + If this option is enabled then the MPC824x processor will run + in DUART mode instead of UART mode. + +config HARRIER_STORE_GATHERING + bool "Enable Harrier store gathering" + depends on HARRIER + +config MVME5100_IPMC761_PRESENT + bool "MVME5100 configured with an IPMC761" + depends on MVME5100 + +config SPRUCE_BAUD_33M + bool "Spruce baud clock support" + depends on SPRUCE diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig new file mode 100644 index 000000000000..3d957a30c8c2 --- /dev/null +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -0,0 +1,31 @@ + +menu "iSeries device drivers" + depends on PPC_ISERIES + +config VIOCONS + tristate "iSeries Virtual Console Support" + +config VIODASD + tristate "iSeries Virtual I/O disk support" + help + If you are running on an iSeries system and you want to use + virtual disks created and managed by OS/400, say Y. + +config VIOCD + tristate "iSeries Virtual I/O CD support" + help + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. + +config VIOTAPE + tristate "iSeries Virtual Tape Support" + help + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + +endmenu + +config VIOPATH + bool + depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || VETH + default y diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile new file mode 100644 index 000000000000..37b7341396e4 --- /dev/null +++ b/arch/powerpc/platforms/powermac/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ + pmac_feature.o pmac_pci.o pmac_sleep.o \ + pmac_low_i2c.o pmac_cache.o +obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o +ifeq ($(CONFIG_PPC_PMAC),y) +obj-$(CONFIG_NVRAM) += pmac_nvram.o +obj-$(CONFIG_SMP) += pmac_smp.o +endif diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h new file mode 100644 index 000000000000..40e1c5030f74 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -0,0 +1,31 @@ +#ifndef __PMAC_H__ +#define __PMAC_H__ + +#include +#include + +/* + * Declaration for the various functions exported by the + * pmac_* files. Mostly for use by pmac_setup + */ + +extern void pmac_get_boot_time(struct rtc_time *tm); +extern void pmac_get_rtc_time(struct rtc_time *tm); +extern int pmac_set_rtc_time(struct rtc_time *tm); +extern void pmac_read_rtc_time(void); +extern void pmac_calibrate_decr(void); + +extern void pmac_pcibios_fixup(void); +extern void pmac_pci_init(void); +extern void pmac_setup_pci_dma(void); +extern void pmac_check_ht_link(void); + +extern void pmac_setup_smp(void); + +extern unsigned long pmac_ide_get_base(int index); +extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, + unsigned long data_port, unsigned long ctrl_port, int *irq); + +extern void pmac_nvram_init(void); + +#endif /* __PMAC_H__ */ diff --git a/arch/powerpc/platforms/powermac/pmac_backlight.c b/arch/powerpc/platforms/powermac/pmac_backlight.c new file mode 100644 index 000000000000..8be2f7d071f0 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_backlight.c @@ -0,0 +1,202 @@ +/* + * Miscellaneous procedures for dealing with the PowerMac hardware. + * Contains support for the backlight. + * + * Copyright (C) 2000 Benjamin Herrenschmidt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct backlight_controller *backlighter; +static void* backlighter_data; +static int backlight_autosave; +static int backlight_level = BACKLIGHT_MAX; +static int backlight_enabled = 1; +static int backlight_req_level = -1; +static int backlight_req_enable = -1; + +static void backlight_callback(void *); +static DECLARE_WORK(backlight_work, backlight_callback, NULL); + +void register_backlight_controller(struct backlight_controller *ctrler, + void *data, char *type) +{ + struct device_node* bk_node; + char *prop; + int valid = 0; + + /* There's already a matching controller, bail out */ + if (backlighter != NULL) + return; + + bk_node = find_devices("backlight"); + +#ifdef CONFIG_ADB_PMU + /* Special case for the old PowerBook since I can't test on it */ + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) + valid = 1; +#endif + if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); + if (prop && !strncmp(prop, type, strlen(type))) + valid = 1; + } + if (!valid) + return; + backlighter = ctrler; + backlighter_data = data; + + if (bk_node && !backlight_autosave) + prop = get_property(bk_node, "bklt", NULL); + else + prop = NULL; + if (prop) { + backlight_level = ((*prop)+1) >> 1; + if (backlight_level > BACKLIGHT_MAX) + backlight_level = BACKLIGHT_MAX; + } + +#ifdef CONFIG_ADB_PMU + if (backlight_autosave) { + struct adb_request req; + pmu_request(&req, NULL, 2, 0xd9, 0); + while (!req.complete) + pmu_poll(); + backlight_level = req.reply[0] >> 4; + } +#endif + acquire_console_sem(); + if (!backlighter->set_enable(1, backlight_level, data)) + backlight_enabled = 1; + release_console_sem(); + + printk(KERN_INFO "Registered \"%s\" backlight controller," + "level: %d/15\n", type, backlight_level); +} +EXPORT_SYMBOL(register_backlight_controller); + +void unregister_backlight_controller(struct backlight_controller + *ctrler, void *data) +{ + /* We keep the current backlight level (for now) */ + if (ctrler == backlighter && data == backlighter_data) + backlighter = NULL; +} +EXPORT_SYMBOL(unregister_backlight_controller); + +static int __set_backlight_enable(int enable) +{ + int rc; + + if (!backlighter) + return -ENODEV; + acquire_console_sem(); + rc = backlighter->set_enable(enable, backlight_level, + backlighter_data); + if (!rc) + backlight_enabled = enable; + release_console_sem(); + return rc; +} +int set_backlight_enable(int enable) +{ + if (!backlighter) + return -ENODEV; + backlight_req_enable = enable; + schedule_work(&backlight_work); + return 0; +} + +EXPORT_SYMBOL(set_backlight_enable); + +int get_backlight_enable(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_enabled; +} +EXPORT_SYMBOL(get_backlight_enable); + +static int __set_backlight_level(int level) +{ + int rc = 0; + + if (!backlighter) + return -ENODEV; + if (level < BACKLIGHT_MIN) + level = BACKLIGHT_OFF; + if (level > BACKLIGHT_MAX) + level = BACKLIGHT_MAX; + acquire_console_sem(); + if (backlight_enabled) + rc = backlighter->set_level(level, backlighter_data); + if (!rc) + backlight_level = level; + release_console_sem(); + if (!rc && !backlight_autosave) { + level <<=1; + if (level & 0x10) + level |= 0x01; + // -- todo: save to property "bklt" + } + return rc; +} +int set_backlight_level(int level) +{ + if (!backlighter) + return -ENODEV; + backlight_req_level = level; + schedule_work(&backlight_work); + return 0; +} + +EXPORT_SYMBOL(set_backlight_level); + +int get_backlight_level(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_level; +} +EXPORT_SYMBOL(get_backlight_level); + +static void backlight_callback(void *dummy) +{ + int level, enable; + + do { + level = backlight_req_level; + enable = backlight_req_enable; + mb(); + + if (level >= 0) + __set_backlight_level(level); + if (enable >= 0) + __set_backlight_enable(enable); + } while(cmpxchg(&backlight_req_level, level, -1) != level || + cmpxchg(&backlight_req_enable, enable, -1) != enable); +} diff --git a/arch/powerpc/platforms/powermac/pmac_cache.S b/arch/powerpc/platforms/powermac/pmac_cache.S new file mode 100644 index 000000000000..fb977de6b704 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_cache.S @@ -0,0 +1,359 @@ +/* + * This file contains low-level cache management functions + * used for sleep and CPU speed changes on Apple machines. + * (In fact the only thing that is Apple-specific is that we assume + * that we can read from ROM at physical address 0xfff00000.) + * + * Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and + * Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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 + +/* + * Flush and disable all data caches (dL1, L2, L3). This is used + * when going to sleep, when doing a PMU based cpufreq transition, + * or when "offlining" a CPU on SMP machines. This code is over + * paranoid, but I've had enough issues with various CPU revs and + * bugs that I decided it was worth beeing over cautious + */ + +_GLOBAL(flush_disable_caches) +#ifndef CONFIG_6xx + blr +#else +BEGIN_FTR_SECTION + b flush_disable_745x +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) +BEGIN_FTR_SECTION + b flush_disable_75x +END_FTR_SECTION_IFSET(CPU_FTR_L2CR) + b __flush_disable_L1 + +/* This is the code for G3 and 74[01]0 */ +flush_disable_75x: + mflr r10 + + /* Turn off EE and DR in MSR */ + mfmsr r11 + rlwinm r0,r11,0,~MSR_EE + rlwinm r0,r0,0,~MSR_DR + sync + mtmsr r0 + isync + + /* Stop DST streams */ +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + + /* Stop DPM */ + mfspr r8,SPRN_HID0 /* Save SPRN_HID0 in r8 */ + rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ + sync + mtspr SPRN_HID0,r4 /* Disable DPM */ + sync + + /* Disp-flush L1. We have a weird problem here that I never + * totally figured out. On 750FX, using the ROM for the flush + * results in a non-working flush. We use that workaround for + * now until I finally understand what's going on. --BenH + */ + + /* ROM base by default */ + lis r4,0xfff0 + mfpvr r3 + srwi r3,r3,16 + cmplwi cr0,r3,0x7000 + bne+ 1f + /* RAM base on 750FX */ + li r4,0 +1: li r4,0x4000 + mtctr r4 +1: lwz r0,0(r4) + addi r4,r4,32 + bdnz 1b + sync + isync + + /* Disable / invalidate / enable L1 data */ + mfspr r3,SPRN_HID0 + rlwinm r3,r3,0,~(HID0_DCE | HID0_ICE) + mtspr SPRN_HID0,r3 + sync + isync + ori r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI) + sync + isync + mtspr SPRN_HID0,r3 + xori r3,r3,(HID0_DCI|HID0_ICFI) + mtspr SPRN_HID0,r3 + sync + + /* Get the current enable bit of the L2CR into r4 */ + mfspr r5,SPRN_L2CR + /* Set to data-only (pre-745x bit) */ + oris r3,r5,L2CR_L2DO@h + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r3 +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: /* disp-flush L2. The interesting thing here is that the L2 can be + * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory + * but that is probbaly fine. We disp-flush over 4Mb to be safe + */ + lis r4,2 + mtctr r4 + lis r4,0xfff0 +1: lwz r0,0(r4) + addi r4,r4,32 + bdnz 1b + sync + isync + lis r4,2 + mtctr r4 + lis r4,0xfff0 +1: dcbf 0,r4 + addi r4,r4,32 + bdnz 1b + sync + isync + + /* now disable L2 */ + rlwinm r5,r5,0,~L2CR_L2E + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r5 +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */ + oris r4,r5,L2CR_L2I@h + mtspr SPRN_L2CR,r4 + sync + isync + + /* Wait for the invalidation to complete */ +1: mfspr r3,SPRN_L2CR + rlwinm. r0,r3,0,31,31 + bne 1b + + /* Clear L2I */ + xoris r4,r4,L2CR_L2I@h + sync + mtspr SPRN_L2CR,r4 + sync + + /* now disable the L1 data cache */ + mfspr r0,SPRN_HID0 + rlwinm r0,r0,0,~(HID0_DCE|HID0_ICE) + mtspr SPRN_HID0,r0 + sync + isync + + /* Restore HID0[DPM] to whatever it was before */ + sync + mfspr r0,SPRN_HID0 + rlwimi r0,r8,0,11,11 /* Turn back HID0[DPM] */ + mtspr SPRN_HID0,r0 + sync + + /* restore DR and EE */ + sync + mtmsr r11 + isync + + mtlr r10 + blr + +/* This code is for 745x processors */ +flush_disable_745x: + /* Turn off EE and DR in MSR */ + mfmsr r11 + rlwinm r0,r11,0,~MSR_EE + rlwinm r0,r0,0,~MSR_DR + sync + mtmsr r0 + isync + + /* Stop prefetch streams */ + DSSALL + sync + + /* Disable L2 prefetching */ + mfspr r0,SPRN_MSSCR0 + rlwinm r0,r0,0,0,29 + mtspr SPRN_MSSCR0,r0 + sync + isync + lis r4,0 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + + /* Due to a bug with the HW flush on some CPU revs, we occasionally + * experience data corruption. I'm adding a displacement flush along + * with a dcbf loop over a few Mb to "help". The problem isn't totally + * fixed by this in theory, but at least, in practice, I couldn't reproduce + * it even with a big hammer... + */ + + lis r4,0x0002 + mtctr r4 + li r4,0 +1: + lwz r0,0(r4) + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + isync + + /* Now, flush the first 4MB of memory */ + lis r4,0x0002 + mtctr r4 + li r4,0 + sync +1: + dcbf 0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + + /* Flush and disable the L1 data cache */ + mfspr r6,SPRN_LDSTCR + lis r3,0xfff0 /* read from ROM for displacement flush */ + li r4,0xfe /* start with only way 0 unlocked */ + li r5,128 /* 128 lines in each way */ +1: mtctr r5 + rlwimi r6,r4,0,24,31 + mtspr SPRN_LDSTCR,r6 + sync + isync +2: lwz r0,0(r3) /* touch each cache line */ + addi r3,r3,32 + bdnz 2b + rlwinm r4,r4,1,24,30 /* move on to the next way */ + ori r4,r4,1 + cmpwi r4,0xff /* all done? */ + bne 1b + /* now unlock the L1 data cache */ + li r4,0 + rlwimi r6,r4,0,24,31 + sync + mtspr SPRN_LDSTCR,r6 + sync + isync + + /* Flush the L2 cache using the hardware assist */ + mfspr r3,SPRN_L2CR + cmpwi r3,0 /* check if it is enabled first */ + bge 4f + oris r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h + b 2f + /* When disabling/locking L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r0 /* lock the L2 cache */ +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + ori r0,r3,L2CR_L2HWF_745x + sync + mtspr SPRN_L2CR,r0 /* set the hardware flush bit */ +3: mfspr r0,SPRN_L2CR /* wait for it to go to 0 */ + andi. r0,r0,L2CR_L2HWF_745x + bne 3b + sync + rlwinm r3,r3,0,~L2CR_L2E + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r3 /* disable the L2 cache */ +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + oris r4,r3,L2CR_L2I@h + mtspr SPRN_L2CR,r4 + sync + isync +1: mfspr r4,SPRN_L2CR + andis. r0,r4,L2CR_L2I@h + bne 1b + sync + +BEGIN_FTR_SECTION + /* Flush the L3 cache using the hardware assist */ +4: mfspr r3,SPRN_L3CR + cmpwi r3,0 /* check if it is enabled */ + bge 6f + oris r0,r3,L3CR_L3IO@h + ori r0,r0,L3CR_L3DO + sync + mtspr SPRN_L3CR,r0 /* lock the L3 cache */ + sync + isync + ori r0,r0,L3CR_L3HWF + sync + mtspr SPRN_L3CR,r0 /* set the hardware flush bit */ +5: mfspr r0,SPRN_L3CR /* wait for it to go to zero */ + andi. r0,r0,L3CR_L3HWF + bne 5b + rlwinm r3,r3,0,~L3CR_L3E + sync + mtspr SPRN_L3CR,r3 /* disable the L3 cache */ + sync + ori r4,r3,L3CR_L3I + mtspr SPRN_L3CR,r4 +1: mfspr r4,SPRN_L3CR + andi. r0,r4,L3CR_L3I + bne 1b + sync +END_FTR_SECTION_IFSET(CPU_FTR_L3CR) + +6: mfspr r0,SPRN_HID0 /* now disable the L1 data cache */ + rlwinm r0,r0,0,~HID0_DCE + mtspr SPRN_HID0,r0 + sync + isync + mtmsr r11 /* restore DR and EE */ + isync + blr +#endif /* CONFIG_6xx */ diff --git a/arch/powerpc/platforms/powermac/pmac_cpufreq.c b/arch/powerpc/platforms/powermac/pmac_cpufreq.c new file mode 100644 index 000000000000..6d32d99402be --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_cpufreq.c @@ -0,0 +1,728 @@ +/* + * arch/ppc/platforms/pmac_cpufreq.c + * + * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt + * Copyright (C) 2004 John Steele Scott + * + * 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. + * + * TODO: Need a big cleanup here. Basically, we need to have different + * cpufreq_driver structures for the different type of HW instead of the + * current mess. We also need to better deal with the detection of the + * type of machine. + * + */ + +#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 + +/* WARNING !!! This will cause calibrate_delay() to be called, + * but this is an __init function ! So you MUST go edit + * init/main.c to make it non-init before enabling DEBUG_FREQ + */ +#undef DEBUG_FREQ + +/* + * There is a problem with the core cpufreq code on SMP kernels, + * it won't recalculate the Bogomips properly + */ +#ifdef CONFIG_SMP +#warning "WARNING, CPUFREQ not recommended on SMP kernels" +#endif + +extern void low_choose_7447a_dfs(int dfs); +extern void low_choose_750fx_pll(int pll); +extern void low_sleep_handler(void); + +/* + * Currently, PowerMac cpufreq supports only high & low frequencies + * that are set by the firmware + */ +static unsigned int low_freq; +static unsigned int hi_freq; +static unsigned int cur_freq; +static unsigned int sleep_freq; + +/* + * Different models uses different mecanisms to switch the frequency + */ +static int (*set_speed_proc)(int low_speed); +static unsigned int (*get_speed_proc)(void); + +/* + * Some definitions used by the various speedprocs + */ +static u32 voltage_gpio; +static u32 frequency_gpio; +static u32 slew_done_gpio; +static int no_schedule; +static int has_cpu_l2lve; +static int is_pmu_based; + +/* There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +#define CPUFREQ_HIGH 0 +#define CPUFREQ_LOW 1 + +static struct cpufreq_frequency_table pmac_cpu_freqs[] = { + {CPUFREQ_HIGH, 0}, + {CPUFREQ_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static struct freq_attr* pmac_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static inline void local_delay(unsigned long ms) +{ + if (no_schedule) + mdelay(ms); + else + msleep(ms); +} + +static inline void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + +#ifdef DEBUG_FREQ +static inline void debug_calc_bogomips(void) +{ + /* This will cause a recalc of bogomips and display the + * result. We backup/restore the value to avoid affecting the + * core cpufreq framework's own calculation. + */ + extern void calibrate_delay(void); + + unsigned long save_lpj = loops_per_jiffy; + calibrate_delay(); + loops_per_jiffy = save_lpj; +} +#endif /* DEBUG_FREQ */ + +/* Switch CPU speed under 750FX CPU control + */ +static int cpu_750fx_cpu_speed(int low_speed) +{ + u32 hid2; + + if (low_speed == 0) { + /* ramping up, set voltage first */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Make sure we sleep for at least 1ms */ + local_delay(10); + + /* tweak L2 for high voltage */ + if (has_cpu_l2lve) { + hid2 = mfspr(SPRN_HID2); + hid2 &= ~0x2000; + mtspr(SPRN_HID2, hid2); + } + } +#ifdef CONFIG_6xx + low_choose_750fx_pll(low_speed); +#endif + if (low_speed == 1) { + /* tweak L2 for low voltage */ + if (has_cpu_l2lve) { + hid2 = mfspr(SPRN_HID2); + hid2 |= 0x2000; + mtspr(SPRN_HID2, hid2); + } + + /* ramping down, set voltage last */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + local_delay(10); + } + + return 0; +} + +static unsigned int cpu_750fx_get_cpu_speed(void) +{ + if (mfspr(SPRN_HID1) & HID1_PS) + return low_freq; + else + return hi_freq; +} + +/* Switch CPU speed using DFS */ +static int dfs_set_cpu_speed(int low_speed) +{ + if (low_speed == 0) { + /* ramping up, set voltage first */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Make sure we sleep for at least 1ms */ + local_delay(1); + } + + /* set frequency */ +#ifdef CONFIG_6xx + low_choose_7447a_dfs(low_speed); +#endif + udelay(100); + + if (low_speed == 1) { + /* ramping down, set voltage last */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + local_delay(1); + } + + return 0; +} + +static unsigned int dfs_get_cpu_speed(void) +{ + if (mfspr(SPRN_HID1) & HID1_DFS) + return low_freq; + else + return hi_freq; +} + + +/* Switch CPU speed using slewing GPIOs + */ +static int gpios_set_cpu_speed(int low_speed) +{ + int gpio, timeout = 0; + + /* If ramping up, set voltage first */ + if (low_speed == 0) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Delay is way too big but it's ok, we schedule */ + local_delay(10); + } + + /* Set frequency */ + gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + if (low_speed == ((gpio & 0x01) == 0)) + goto skip; + + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, + low_speed ? 0x04 : 0x05); + udelay(200); + do { + if (++timeout > 100) + break; + local_delay(1); + gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0); + } while((gpio & 0x02) == 0); + skip: + /* If ramping down, set voltage last */ + if (low_speed == 1) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + /* Delay is way too big but it's ok, we schedule */ + local_delay(10); + } + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + return 0; +} + +/* Switch CPU speed under PMU control + */ +static int pmu_set_cpu_speed(int low_speed) +{ + struct adb_request req; + unsigned long save_l2cr; + unsigned long save_l3cr; + unsigned int pic_prio; + unsigned long flags; + + preempt_disable(); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + pmu_suspend(); + + /* Disable all interrupt sources on openpic */ + pic_prio = mpic_cpu_get_priority(); + mpic_cpu_set_priority(0xf); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* We can now disable MSR_EE */ + local_irq_save(flags); + + /* Giveup the FPU & vec */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + /* Save & disable L2 and L3 caches */ + save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ + save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ + + /* Send the new speed command. My assumption is that this command + * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep + */ + pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); + while (!req.complete) + pmu_poll(); + + /* Prepare the northbridge for the speed transition */ + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); + + /* Call low level code to backup CPU state and recover from + * hardware reset + */ + low_sleep_handler(); + + /* Restore the northbridge */ + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); + + /* Restore L2 cache */ + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr); + /* Restore L3 cache */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); +#endif + + /* Restore low level PMU operations */ + pmu_unlock(); + + /* Restore decrementer */ + wakeup_decrementer(); + + /* Restore interrupts */ + mpic_cpu_set_priority(pic_prio); + + /* Let interrupts flow again ... */ + local_irq_restore(flags); + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + pmu_resume(); + + preempt_enable(); + + return 0; +} + +static int do_set_cpu_speed(int speed_mode, int notify) +{ + struct cpufreq_freqs freqs; + unsigned long l3cr; + static unsigned long prev_l3cr; + + freqs.old = cur_freq; + freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; + freqs.cpu = smp_processor_id(); + + if (freqs.old == freqs.new) + return 0; + + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (speed_mode == CPUFREQ_LOW && + cpu_has_feature(CPU_FTR_L3CR)) { + l3cr = _get_L3CR(); + if (l3cr & L3CR_L3E) { + prev_l3cr = l3cr; + _set_L3CR(0); + } + } + set_speed_proc(speed_mode == CPUFREQ_LOW); + if (speed_mode == CPUFREQ_HIGH && + cpu_has_feature(CPU_FTR_L3CR)) { + l3cr = _get_L3CR(); + if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) + _set_L3CR(prev_l3cr); + } + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; + + return 0; +} + +static unsigned int pmac_cpufreq_get_speed(unsigned int cpu) +{ + return cur_freq; +} + +static int pmac_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); +} + +static int pmac_cpufreq_target( struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, + target_freq, relation, &newstate)) + return -EINVAL; + + return do_set_cpu_speed(newstate, 1); +} + +unsigned int pmac_get_one_cpufreq(int i) +{ + /* Supports only one CPU for now */ + return (i == 0) ? cur_freq : 0; +} + +static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -ENODEV; + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = cur_freq; + + cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); + return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs); +} + +static u32 read_gpio(struct device_node *np) +{ + u32 *reg = (u32 *)get_property(np, "reg", NULL); + u32 offset; + + if (reg == NULL) + return 0; + /* That works for all keylargos but shall be fixed properly + * some day... The problem is that it seems we can't rely + * on the "reg" property of the GPIO nodes, they are either + * relative to the base of KeyLargo or to the base of the + * GPIO space, and the device-tree doesn't help. + */ + offset = *reg; + if (offset < KEYLARGO_GPIO_LEVELS0) + offset += KEYLARGO_GPIO_LEVELS0; + return offset; +} + +static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg) +{ + /* Ok, this could be made a bit smarter, but let's be robust for now. We + * always force a speed change to high speed before sleep, to make sure + * we have appropriate voltage and/or bus speed for the wakeup process, + * and to make sure our loops_per_jiffies are "good enough", that is will + * not cause too short delays if we sleep in low speed and wake in high + * speed.. + */ + no_schedule = 1; + sleep_freq = cur_freq; + if (cur_freq == low_freq && !is_pmu_based) + do_set_cpu_speed(CPUFREQ_HIGH, 0); + return 0; +} + +static int pmac_cpufreq_resume(struct cpufreq_policy *policy) +{ + /* If we resume, first check if we have a get() function */ + if (get_speed_proc) + cur_freq = get_speed_proc(); + else + cur_freq = 0; + + /* We don't, hrm... we don't really know our speed here, best + * is that we force a switch to whatever it was, which is + * probably high speed due to our suspend() routine + */ + do_set_cpu_speed(sleep_freq == low_freq ? + CPUFREQ_LOW : CPUFREQ_HIGH, 0); + + no_schedule = 0; + return 0; +} + +static struct cpufreq_driver pmac_cpufreq_driver = { + .verify = pmac_cpufreq_verify, + .target = pmac_cpufreq_target, + .get = pmac_cpufreq_get_speed, + .init = pmac_cpufreq_cpu_init, + .suspend = pmac_cpufreq_suspend, + .resume = pmac_cpufreq_resume, + .flags = CPUFREQ_PM_NO_WARN, + .attr = pmac_cpu_freqs_attr, + .name = "powermac", + .owner = THIS_MODULE, +}; + + +static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np = of_find_node_by_name(NULL, + "voltage-gpio"); + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, + "frequency-gpio"); + struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, + "slewing-done"); + u32 *value; + + /* + * Check to see if it's GPIO driven or PMU only + * + * The way we extract the GPIO address is slightly hackish, but it + * works well enough for now. We need to abstract the whole GPIO + * stuff sooner or later anyway + */ + + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (freq_gpio_np) + frequency_gpio = read_gpio(freq_gpio_np); + if (slew_done_gpio_np) + slew_done_gpio = read_gpio(slew_done_gpio_np); + + /* If we use the frequency GPIOs, calculate the min/max speeds based + * on the bus frequencies + */ + if (frequency_gpio && slew_done_gpio) { + int lenp, rc; + u32 *freqs, *ratio; + + freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); + lenp /= sizeof(u32); + if (freqs == NULL || lenp != 2) { + printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); + return 1; + } + ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); + if (ratio == NULL) { + printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); + return 1; + } + + /* Get the min/max bus frequencies */ + low_freq = min(freqs[0], freqs[1]); + hi_freq = max(freqs[0], freqs[1]); + + /* Grrrr.. It _seems_ that the device-tree is lying on the low bus + * frequency, it claims it to be around 84Mhz on some models while + * it appears to be approx. 101Mhz on all. Let's hack around here... + * fortunately, we don't need to be too precise + */ + if (low_freq < 98000000) + low_freq = 101000000; + + /* Convert those to CPU core clocks */ + low_freq = (low_freq * (*ratio)) / 2000; + hi_freq = (hi_freq * (*ratio)) / 2000; + + /* Now we get the frequencies, we read the GPIO to see what is out current + * speed + */ + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + cur_freq = (rc & 0x01) ? hi_freq : low_freq; + + set_speed_proc = gpios_set_cpu_speed; + return 1; + } + + /* If we use the PMU, look for the min & max frequencies in the + * device-tree + */ + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + return 1; + low_freq = (*value) / 1000; + /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree + * here */ + if (low_freq < 100000) + low_freq *= 10; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + return 1; + hi_freq = (*value) / 1000; + set_speed_proc = pmu_set_cpu_speed; + is_pmu_based = 1; + + return 0; +} + +static int pmac_cpufreq_init_7447A(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np; + + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) + return 1; + + volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (!voltage_gpio){ + printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); + return 1; + } + + /* OF only reports the high frequency */ + hi_freq = cur_freq; + low_freq = cur_freq/2; + + /* Read actual frequency from CPU */ + cur_freq = dfs_get_cpu_speed(); + set_speed_proc = dfs_set_cpu_speed; + get_speed_proc = dfs_get_cpu_speed; + + return 0; +} + +static int pmac_cpufreq_init_750FX(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np; + u32 pvr, *value; + + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) + return 1; + + hi_freq = cur_freq; + value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); + if (!value) + return 1; + low_freq = (*value) / 1000; + + volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + + pvr = mfspr(SPRN_PVR); + has_cpu_l2lve = !((pvr & 0xf00) == 0x100); + + set_speed_proc = cpu_750fx_cpu_speed; + get_speed_proc = cpu_750fx_get_cpu_speed; + cur_freq = cpu_750fx_get_cpu_speed(); + + return 0; +} + +/* Currently, we support the following machines: + * + * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) + * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) + * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) + * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) + * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz) + * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) + * - Recent MacRISC3 laptops + * - All new machines with 7447A CPUs + */ +static int __init pmac_cpufreq_setup(void) +{ + struct device_node *cpunode; + u32 *value; + + if (strstr(cmd_line, "nocpufreq")) + return 0; + + /* Assume only one CPU */ + cpunode = find_type_devices("cpu"); + if (!cpunode) + goto out; + + /* Get current cpu clock freq */ + value = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!value) + goto out; + cur_freq = (*value) / 1000; + + /* Check for 7447A based MacRISC3 */ + if (machine_is_compatible("MacRISC3") && + get_property(cpunode, "dynamic-power-step", NULL) && + PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { + pmac_cpufreq_init_7447A(cpunode); + /* Check for other MacRISC3 machines */ + } else if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5") || + machine_is_compatible("MacRISC3")) { + pmac_cpufreq_init_MacRISC3(cpunode); + /* Else check for iBook2 500/600 */ + } else if (machine_is_compatible("PowerBook4,1")) { + hi_freq = cur_freq; + low_freq = 400000; + set_speed_proc = pmu_set_cpu_speed; + is_pmu_based = 1; + } + /* Else check for TiPb 400 & 500 */ + else if (machine_is_compatible("PowerBook3,2")) { + /* We only know about the 400 MHz and the 500Mhz model + * they both have 300 MHz as low frequency + */ + if (cur_freq < 350000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 300000; + set_speed_proc = pmu_set_cpu_speed; + is_pmu_based = 1; + } + /* Else check for 750FX */ + else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000) + pmac_cpufreq_init_750FX(cpunode); +out: + if (set_speed_proc == NULL) + return -ENODEV; + + pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; + pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; + + printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", + low_freq/1000, hi_freq/1000, cur_freq/1000); + + return cpufreq_register_driver(&pmac_cpufreq_driver); +} + +module_init(pmac_cpufreq_setup); + diff --git a/arch/powerpc/platforms/powermac/pmac_feature.c b/arch/powerpc/platforms/powermac/pmac_feature.c new file mode 100644 index 000000000000..2cba670c71b7 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_feature.c @@ -0,0 +1,3062 @@ +/* + * arch/ppc/platforms/pmac_feature.c + * + * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) + * Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * 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. + * + * TODO: + * + * - Replace mdelay with some schedule loop if possible + * - Shorten some obfuscated delays on some routines (like modem + * power) + * - Refcount some clocks (see darwin) + * - Split split split... + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_FEATURE + +#ifdef DEBUG_FEATURE +#define DBG(fmt...) printk(KERN_DEBUG fmt) +#else +#define DBG(fmt...) +#endif + +#ifdef CONFIG_6xx +extern int powersave_lowspeed; +#endif + +extern int powersave_nap; +extern struct device_node *k2_skiplist[2]; + + +/* + * We use a single global lock to protect accesses. Each driver has + * to take care of its own locking + */ +static DEFINE_SPINLOCK(feature_lock); + +#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); +#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); + + +/* + * Instance of some macio stuffs + */ +struct macio_chip macio_chips[MAX_MACIO_CHIPS]; + +struct macio_chip *macio_find(struct device_node *child, int type) +{ + while(child) { + int i; + + for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) + if (child == macio_chips[i].of_node && + (!type || macio_chips[i].type == type)) + return &macio_chips[i]; + child = child->parent; + } + return NULL; +} +EXPORT_SYMBOL_GPL(macio_find); + +static const char *macio_names[] = +{ + "Unknown", + "Grand Central", + "OHare", + "OHareII", + "Heathrow", + "Gatwick", + "Paddington", + "Keylargo", + "Pangea", + "Intrepid", + "K2" +}; + + + +/* + * Uninorth reg. access. Note that Uni-N regs are big endian + */ + +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + +static struct device_node *uninorth_node; +static u32 __iomem *uninorth_base; +static u32 uninorth_rev; +static int uninorth_u3; +static void __iomem *u3_ht; + +/* + * For each motherboard family, we have a table of functions pointers + * that handle the various features. + */ + +typedef long (*feature_call)(struct device_node *node, long param, long value); + +struct feature_table_entry { + unsigned int selector; + feature_call function; +}; + +struct pmac_mb_def +{ + const char* model_string; + const char* model_name; + int model_id; + struct feature_table_entry* features; + unsigned long board_flags; +}; +static struct pmac_mb_def pmac_mb; + +/* + * Here are the chip specific feature functions + */ + +static inline int simple_feature_tweak(struct device_node *node, int type, + int reg, u32 mask, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, type); + if (!macio) + return -ENODEV; + LOCK(flags); + if (value) + MACIO_BIS(reg, mask); + else + MACIO_BIC(reg, mask); + (void)MACIO_IN32(reg); + UNLOCK(flags); + + return 0; +} + +#ifndef CONFIG_POWER4 + +static long ohare_htw_scc_enable(struct device_node *node, long param, + long value) +{ + struct macio_chip* macio; + unsigned long chan_mask; + unsigned long fcr; + unsigned long flags; + int htw, trans; + unsigned long rmask; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + htw = (macio->type == macio_heathrow || macio->type == macio_paddington + || macio->type == macio_gatwick); + /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */ + trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES); + if (value) { +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(1); +#endif /* CONFIG_ADB_PMU */ + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + /* Check if scc cell need enabling */ + if (!(fcr & OH_SCC_ENABLE)) { + fcr |= OH_SCC_ENABLE; + if (htw) { + /* Side effect: this will also power up the + * modem, but it's too messy to figure out on which + * ports this controls the tranceiver and on which + * it controls the modem + */ + if (trans) + fcr &= ~HRW_SCC_TRANS_EN_N; + MACIO_OUT32(OHARE_FCR, fcr); + fcr |= (rmask = HRW_RESET_SCC); + MACIO_OUT32(OHARE_FCR, fcr); + } else { + fcr |= (rmask = OH_SCC_RESET); + MACIO_OUT32(OHARE_FCR, fcr); + } + UNLOCK(flags); + (void)MACIO_IN32(OHARE_FCR); + mdelay(15); + LOCK(flags); + fcr &= ~rmask; + MACIO_OUT32(OHARE_FCR, fcr); + } + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr |= OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr |= OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + macio->flags |= chan_mask; + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr &= ~OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) { + fcr &= ~OH_SCC_ENABLE; + if (htw && trans) + fcr |= HRW_SCC_TRANS_EN_N; + MACIO_OUT32(OHARE_FCR, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(0); +#endif /* CONFIG_ADB_PMU */ + } + return 0; +} + +static long ohare_floppy_enable(struct device_node *node, long param, + long value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_FLOPPY_ENABLE, value); +} + +static long ohare_mesh_enable(struct device_node *node, long param, long value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_MESH_ENABLE, value); +} + +static long ohare_ide_enable(struct device_node *node, long param, long value) +{ + switch(param) { + case 0: + /* For some reason, setting the bit in set_initial_features() + * doesn't stick. I'm still investigating... --BenH. + */ + if (value) + simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IOBUS_ENABLE, 1); + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static long ohare_ide_reset(struct device_node *node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long ohare_sleep_state(struct device_node *node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) { + MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE); + } else if (value == 0) { + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + + return 0; +} + +static long heathrow_modem_enable(struct device_node *node, long param, + long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1; + if (!value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + mdelay(250); + } + if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES) { + LOCK(flags); + if (value) + MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + else + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(250); + } + if (value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long heathrow_floppy_enable(struct device_node *node, long param, + long value) +{ + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, + HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE, + value); +} + +static long heathrow_mesh_enable(struct device_node *node, long param, + long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + LOCK(flags); + /* Set clear mesh cell enable */ + if (value) + MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE); + else + MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE); + (void)MACIO_IN32(HEATHROW_FCR); + udelay(10); + /* Set/Clear termination power */ + if (value) + MACIO_BIC(HEATHROW_MBCR, 0x04000000); + else + MACIO_BIS(HEATHROW_MBCR, 0x04000000); + (void)MACIO_IN32(HEATHROW_MBCR); + udelay(10); + UNLOCK(flags); + + return 0; +} + +static long heathrow_ide_enable(struct device_node *node, long param, + long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static long heathrow_ide_reset(struct device_node *node, long param, + long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long heathrow_bmac_enable(struct device_node *node, long param, + long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + } else { + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static long heathrow_sound_enable(struct device_node *node, long param, + long value) +{ + struct macio_chip* macio; + unsigned long flags; + + /* B&W G3 and Yikes don't support that properly (the + * sound appear to never come back after beeing shut down). + */ + if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE || + pmac_mb.model_id == PMAC_TYPE_YIKES) + return 0; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + } else { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static u32 save_fcr[6]; +static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; +static u32 save_unin_clock_ctl; +static struct dbdma_regs save_dbdma[13]; +static struct dbdma_regs save_alt_dbdma[13]; + +static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i = 0; i < 13; i++) { + volatile struct dbdma_regs __iomem * chan = (void __iomem *) + (macio->base + ((0x8000+i*0x100)>>2)); + save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); + save[i].cmdptr = in_le32(&chan->cmdptr); + save[i].intr_sel = in_le32(&chan->intr_sel); + save[i].br_sel = in_le32(&chan->br_sel); + save[i].wait_sel = in_le32(&chan->wait_sel); + } +} + +static void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i = 0; i < 13; i++) { + volatile struct dbdma_regs __iomem * chan = (void __iomem *) + (macio->base + ((0x8000+i*0x100)>>2)); + out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); + while (in_le32(&chan->status) & ACTIVE) + mb(); + out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi); + out_le32(&chan->cmdptr, save[i].cmdptr); + out_le32(&chan->intr_sel, save[i].intr_sel); + out_le32(&chan->br_sel, save[i].br_sel); + out_le32(&chan->wait_sel, save[i].wait_sel); + } +} + +static void heathrow_sleep(struct macio_chip *macio, int secondary) +{ + if (secondary) { + dbdma_save(macio, save_alt_dbdma); + save_fcr[2] = MACIO_IN32(0x38); + save_fcr[3] = MACIO_IN32(0x3c); + } else { + dbdma_save(macio, save_dbdma); + save_fcr[0] = MACIO_IN32(0x38); + save_fcr[1] = MACIO_IN32(0x3c); + save_mbcr = MACIO_IN32(0x34); + /* Make sure sound is shut down */ + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + /* This seems to be necessary as well or the fan + * keeps coming up and battery drains fast */ + MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N); + /* Make sure eth is down even if module or sleep + * won't work properly */ + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET); + } + /* Make sure modem is shut down */ + MACIO_OUT8(HRW_GPIO_MODEM_RESET, + MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1); + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE); + + /* Let things settle */ + (void)MACIO_IN32(HEATHROW_FCR); +} + +static void heathrow_wakeup(struct macio_chip *macio, int secondary) +{ + if (secondary) { + MACIO_OUT32(0x38, save_fcr[2]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[3]); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_alt_dbdma); + } else { + MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[1]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x34, save_mbcr); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_dbdma); + } +} + +static long heathrow_sleep_state(struct device_node *node, long param, + long value) +{ + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) { + if (macio_chips[1].type == macio_gatwick) + heathrow_sleep(&macio_chips[0], 1); + heathrow_sleep(&macio_chips[0], 0); + } else if (value == 0) { + heathrow_wakeup(&macio_chips[0], 0); + if (macio_chips[1].type == macio_gatwick) + heathrow_wakeup(&macio_chips[0], 1); + } + return 0; +} + +static long core99_scc_enable(struct device_node *node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + unsigned long chan_mask; + u32 fcr; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + if (value) { + int need_reset_scc = 0; + int need_reset_irda = 0; + + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + /* Check if scc cell need enabling */ + if (!(fcr & KL0_SCC_CELL_ENABLE)) { + fcr |= KL0_SCC_CELL_ENABLE; + need_reset_scc = 1; + } + if (chan_mask & MACIO_FLAG_SCCA_ON) { + fcr |= KL0_SCCA_ENABLE; + /* Don't enable line drivers for I2S modem */ + if ((param & 0xfff) == PMAC_SCC_I2S1) + fcr &= ~KL0_SCC_A_INTF_ENABLE; + else + fcr |= KL0_SCC_A_INTF_ENABLE; + } + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr |= KL0_SCCB_ENABLE; + /* Perform irda specific inits */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_SCC_B_INTF_ENABLE; + fcr |= KL0_IRDA_ENABLE; + fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE; + fcr |= KL0_IRDA_SOURCE1_SEL; + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + need_reset_irda = 1; + } else + fcr |= KL0_SCC_B_INTF_ENABLE; + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + macio->flags |= chan_mask; + if (need_reset_scc) { + MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET); + } + if (need_reset_irda) { + MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET); + } + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~KL0_SCCA_ENABLE; + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr &= ~KL0_SCCB_ENABLE; + /* Perform irda specific clears */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_IRDA_ENABLE; + fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE); + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + } + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) { + fcr &= ~KL0_SCC_CELL_ENABLE; + MACIO_OUT32(KEYLARGO_FCR0, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); + } + return 0; +} + +static long +core99_modem_enable(struct device_node *node, long param, long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_keylargo) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long +pangea_modem_enable(struct device_node *node, long param, long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_pangea && + macio_chips[0].type != macio_intrepid) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long +core99_ata100_enable(struct device_node *node, long value) +{ + unsigned long flags; + struct pci_dev *pdev = NULL; + u8 pbus, pid; + + if (uninorth_rev < 0x24) + return -ENODEV; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + if (value) { + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + return 0; + pci_enable_device(pdev); + pci_set_master(pdev); + } + return 0; +} + +static long +core99_ide_enable(struct device_node *node, long param, long value) +{ + /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 + * based ata-100 + */ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_ENABLE, value); + case 3: + return core99_ata100_enable(node, value); + default: + return -ENODEV; + } +} + +static long +core99_ide_reset(struct device_node *node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long +core99_gmac_enable(struct device_node *node, long param, long value) +{ + unsigned long flags; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + return 0; +} + +static long +core99_gmac_phy_reset(struct device_node *node, long param, long value) +{ + unsigned long flags; + struct macio_chip *macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */ + KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + mdelay(10); + + return 0; +} + +static long +core99_sound_chip_enable(struct device_node *node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Do a better probe code, screamer G4 desktops & + * iMacs can do that too, add a recalibrate in + * the driver as well + */ + if (pmac_mb.model_id == PMAC_TYPE_PISMO || + pmac_mb.model_id == PMAC_TYPE_TITANIUM) { + LOCK(flags); + if (value) + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | + KEYLARGO_GPIO_OUTOUT_DATA); + else + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_SOUND_POWER); + UNLOCK(flags); + } + return 0; +} + +static long +core99_airport_enable(struct device_node *node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + int state; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Hint: we allow passing of macio itself for the sake of the + * sleep code + */ + if (node != macio->of_node && + (!node->parent || node->parent != macio->of_node)) + return -ENODEV; + state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0; + if (value == state) + return 0; + if (value) { + /* This code is a reproduction of OF enable-cardslot + * and init-wireless methods, slightly hacked until + * I got it working. + */ + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + + mdelay(10); + + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe); + UNLOCK(flags); + udelay(10); + MACIO_OUT32(0x1c000, 0); + mdelay(1); + MACIO_OUT8(0x1a3e0, 0x41); + (void)MACIO_IN8(0x1a3e0); + udelay(10); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + UNLOCK(flags); + mdelay(100); + + macio->flags |= MACIO_FLAG_AIRPORT_ON; + } else { + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + MACIO_OUT8(KL_GPIO_AIRPORT_0, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_1, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_2, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_3, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_4, 0); + (void)MACIO_IN8(KL_GPIO_AIRPORT_4); + UNLOCK(flags); + + macio->flags &= ~MACIO_FLAG_AIRPORT_ON; + } + return 0; +} + +#ifdef CONFIG_SMP +static long +core99_reset_cpu(struct device_node *node, long param, long value) +{ + unsigned int reset_io = 0; + unsigned long flags; + struct macio_chip *macio; + struct device_node *np; + const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo) + return -ENODEV; + + np = find_path_device("/cpus"); + if (np == NULL) + return -ENODEV; + for (np = np->child; np != NULL; np = np->sibling) { + u32 *num = (u32 *)get_property(np, "reg", NULL); + u32 *rst = (u32 *)get_property(np, "soft-reset", NULL); + if (num == NULL || rst == NULL) + continue; + if (param == *num) { + reset_io = *rst; + break; + } + } + if (np == NULL || reset_io == 0) + reset_io = dflt_reset_lines[param]; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, 0); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +static long +core99_usb_enable(struct device_node *node, long param, long value) +{ + struct macio_chip *macio; + unsigned long flags; + char *prop; + int number; + u32 reg; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + prop = (char *)get_property(node, "AAPL,clock-id", NULL); + if (!prop) + return -ENODEV; + if (strncmp(prop, "usb0u048", 8) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", 8) == 0) + number = 2; + else if (strncmp(prop, "usb2u248", 8) == 0) + number = 4; + else + return -ENODEV; + + /* Sorry for the brute-force locking, but this is only used during + * sleep and the timing seem to be critical + */ + LOCK(flags); + if (value) { + /* Turn ON */ + if (number == 0) { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else if (number == 2) { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } else if (number == 4) { + MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR1); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE); + } + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number)); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1)); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(10); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0)); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1)); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(10); + } + if (macio->type == macio_intrepid) { + /* wait for clock stopped bits to clear */ + u32 test0 = 0, test1 = 0; + u32 status0, status1; + int timeout = 1000; + + UNLOCK(flags); + switch (number) { + case 0: + test0 = UNI_N_CLOCK_STOPPED_USB0; + test1 = UNI_N_CLOCK_STOPPED_USB0PCI; + break; + case 2: + test0 = UNI_N_CLOCK_STOPPED_USB1; + test1 = UNI_N_CLOCK_STOPPED_USB1PCI; + break; + case 4: + test0 = UNI_N_CLOCK_STOPPED_USB2; + test1 = UNI_N_CLOCK_STOPPED_USB2PCI; + break; + } + do { + if (--timeout <= 0) { + printk(KERN_ERR "core99_usb_enable: " + "Timeout waiting for clocks\n"); + break; + } + mdelay(1); + status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0); + status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1); + } while ((status0 & test0) | (status1 & test1)); + LOCK(flags); + } + } else { + /* Turn OFF */ + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number); + reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(1); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(1); + } + if (number == 0) { + if (macio->type != macio_intrepid) + MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } else if (number == 2) { + if (macio->type != macio_intrepid) + MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } else if (number == 4) { + udelay(1); + MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR1); + } + udelay(1); + } + UNLOCK(flags); + + return 0; +} + +static long +core99_firewire_enable(struct device_node *node, long param, long value) +{ + unsigned long flags; + struct macio_chip *macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } else { + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long +core99_firewire_cable_power(struct device_node *node, long param, long value) +{ + unsigned long flags; + struct macio_chip *macio; + + /* Trick: we allow NULL node */ + if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0) + return -ENODEV; + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); + udelay(10); + } else { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long +intrepid_aack_delay_enable(struct device_node *node, long param, long value) +{ + unsigned long flags; + + if (uninorth_rev < 0xd2) + return -ENODEV; + + LOCK(flags); + if (param) + UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + else + UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + UNLOCK(flags); + + return 0; +} + + +#endif /* CONFIG_POWER4 */ + +static long +core99_read_gpio(struct device_node *node, long param, long value) +{ + struct macio_chip *macio = &macio_chips[0]; + + return MACIO_IN8(param); +} + + +static long +core99_write_gpio(struct device_node *node, long param, long value) +{ + struct macio_chip *macio = &macio_chips[0]; + + MACIO_OUT8(param, (u8)(value & 0xff)); + return 0; +} + +#ifdef CONFIG_POWER4 +static long g5_gmac_enable(struct device_node *node, long param, long value) +{ + struct macio_chip *macio = &macio_chips[0]; + unsigned long flags; + + if (node == NULL) + return -ENODEV; + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + mb(); + k2_skiplist[0] = NULL; + } else { + k2_skiplist[0] = node; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long g5_fw_enable(struct device_node *node, long param, long value) +{ + struct macio_chip *macio = &macio_chips[0]; + unsigned long flags; + + if (node == NULL) + return -ENODEV; + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + mb(); + k2_skiplist[1] = NULL; + } else { + k2_skiplist[1] = node; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long g5_mpic_enable(struct device_node *node, long param, long value) +{ + unsigned long flags; + + if (node->parent == NULL || strcmp(node->parent->name, "u3")) + return 0; + + LOCK(flags); + UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); + UNLOCK(flags); + + return 0; +} + +static long g5_eth_phy_reset(struct device_node *node, long param, long value) +{ + struct macio_chip *macio = &macio_chips[0]; + struct device_node *phy; + int need_reset; + + /* + * We must not reset the combo PHYs, only the BCM5221 found in + * the iMac G5. + */ + phy = of_get_next_child(node, NULL); + if (!phy) + return -ENODEV; + need_reset = device_is_compatible(phy, "B5221"); + of_node_put(phy); + if (!need_reset) + return 0; + + /* PHY reset is GPIO 29, not in device-tree unfortunately */ + MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + /* Thankfully, this is now always called at a time when we can + * schedule by sungem. + */ + msleep(10); + MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0); + + return 0; +} + +static long g5_i2s_enable(struct device_node *node, long param, long value) +{ + /* Very crude implementation for now */ + struct macio_chip *macio = &macio_chips[0]; + unsigned long flags; + + if (value == 0) + return 0; /* don't disable yet */ + + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | + KL3_I2S0_CLK18_ENABLE); + udelay(10); + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | + K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); + udelay(10); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); + UNLOCK(flags); + udelay(10); + + return 0; +} + + +#ifdef CONFIG_SMP +static long g5_reset_cpu(struct device_node *node, long param, long value) +{ + unsigned int reset_io = 0; + unsigned long flags; + struct macio_chip *macio; + struct device_node *np; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo2) + return -ENODEV; + + np = find_path_device("/cpus"); + if (np == NULL) + return -ENODEV; + for (np = np->child; np != NULL; np = np->sibling) { + u32 *num = (u32 *)get_property(np, "reg", NULL); + u32 *rst = (u32 *)get_property(np, "soft-reset", NULL); + if (num == NULL || rst == NULL) + continue; + if (param == *num) { + reset_io = *rst; + break; + } + } + if (np == NULL || reset_io == 0) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, 0); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * This can be called from pmac_smp so isn't static + * + * This takes the second CPU off the bus on dual CPU machines + * running UP + */ +void g5_phy_disable_cpu1(void) +{ + UN_OUT(U3_API_PHY_CONFIG_1, 0); +} +#endif /* CONFIG_POWER4 */ + +#ifndef CONFIG_POWER4 + +static void +keylargo_shutdown(struct macio_chip *macio, int sleep_mode) +{ + u32 temp; + + if (sleep_mode) { + mdelay(1); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + } + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | + KL0_IRDA_CLK19_ENABLE); + + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | + KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | + KL1_UIDE_ENABLE); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); + + temp = MACIO_IN32(KEYLARGO_FCR3); + if (macio->rev >= 2) { + temp |= KL3_SHUTDOWN_PLL2X; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLL_TOTAL; + } + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void +pangea_shutdown(struct macio_chip *macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_UIDE_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void +intrepid_shutdown(struct macio_chip *macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + /*KL1_USB2_CELL_ENABLE |*/ + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | + KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(10); +} + + +void pmac_tweak_clock_spreading(int enable) +{ + struct macio_chip *macio = &macio_chips[0]; + + /* Hack for doing clock spreading on some machines PowerBooks and + * iBooks. This implements the "platform-do-clockspreading" OF + * property as decoded manually on various models. For safety, we also + * check the product ID in the device-tree in cases we'll whack the i2c + * chip to make reasonably sure we won't set wrong values in there + * + * Of course, ultimately, we have to implement a real parser for + * the platform-do-* stuff... + */ + + if (macio->type == macio_intrepid) { + if (enable) + UN_OUT(UNI_N_CLOCK_SPREADING, 2); + else + UN_OUT(UNI_N_CLOCK_SPREADING, 0); + mdelay(40); + } + + while (machine_is_compatible("PowerBook5,2") || + machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook6,2") || + machine_is_compatible("PowerBook6,3")) { + struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); + struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); + u8 buffer[9]; + u32 *productID; + int i, rc, changed = 0; + + if (dt == NULL) + break; + productID = (u32 *)get_property(dt, "pid#", NULL); + if (productID == NULL) + break; + while(ui2c) { + struct device_node *p = of_get_parent(ui2c); + if (p && !strcmp(p->name, "uni-n")) + break; + ui2c = of_find_node_by_type(ui2c, "i2c"); + } + if (ui2c == NULL) + break; + DBG("Trying to bump clock speed for PID: %08x...\n", *productID); + rc = pmac_low_i2c_open(ui2c, 1); + if (rc != 0) + break; + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + DBG("\n"); + + switch(*productID) { + case 0x1182: /* AlBook 12" rev 2 */ + case 0x1183: /* iBook G4 12" */ + buffer[0] = (buffer[0] & 0x8f) | 0x70; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba); + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + case 0x3142: /* AlBook 15" (ATI M10) */ + case 0x3143: /* AlBook 17" (ATI M10) */ + buffer[0] = (buffer[0] & 0xaf) | 0x50; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0); + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + default: + DBG("i2c-hwclock: Machine model not handled\n"); + break; + } + if (!changed) { + pmac_low_i2c_close(ui2c); + break; + } + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); + DBG("write result: %d,", rc); + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + pmac_low_i2c_close(ui2c); + break; + } +} + + +static int +core99_sleep(void) +{ + struct macio_chip *macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + /* We power off the wireless slot in case it was not done + * by the driver. We don't power it on automatically however + */ + if (macio->flags & MACIO_FLAG_AIRPORT_ON) + core99_airport_enable(macio->of_node, 0, 0); + + /* We power off the FW cable. Should be done by the driver... */ + if (macio->flags & MACIO_FLAG_FW_SUPPORTED) { + core99_firewire_enable(NULL, 0, 0); + core99_firewire_cable_power(NULL, 0, 0); + } + + /* We make sure int. modem is off (in case driver lost it) */ + if (macio->type == macio_keylargo) + core99_modem_enable(macio->of_node, 0, 0); + else + pangea_modem_enable(macio->of_node, 0, 0); + + /* We make sure the sound is off as well */ + core99_sound_chip_enable(macio->of_node, 0, 0); + + /* + * Save various bits of KeyLargo + */ + + /* Save the state of the various GPIOs */ + save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1); + for (i=0; itype == macio_keylargo) + save_mbcr = MACIO_IN32(KEYLARGO_MBCR); + save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0); + save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1); + save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2); + save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3); + save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4); + if (macio->type == macio_pangea || macio->type == macio_intrepid) + save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5); + + /* Save state & config of DBDMA channels */ + dbdma_save(macio, save_dbdma); + + /* + * Turn off as much as we can + */ + if (macio->type == macio_pangea) + pangea_shutdown(macio, 1); + else if (macio->type == macio_intrepid) + intrepid_shutdown(macio, 1); + else if (macio->type == macio_keylargo) + keylargo_shutdown(macio, 1); + + /* + * Put the host bridge to sleep + */ + + save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); + /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it + * enabled ! + */ + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & + ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); + udelay(100); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + mdelay(10); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) { + MACIO_BIS(0x506e0, 0x00400000); + MACIO_BIS(0x506e0, 0x80000000); + } + return 0; +} + +static int +core99_wake_up(void) +{ + struct macio_chip *macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); + + /* + * Restore KeyLargo + */ + + if (macio->type == macio_keylargo) { + MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + } + MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]); + (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]); + (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]); + (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10); + MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]); + (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]); + (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10); + if (macio->type == macio_pangea || macio->type == macio_intrepid) { + MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]); + (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10); + } + + dbdma_restore(macio, save_dbdma); + + MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + for (i=0; itype) { +#ifndef CONFIG_POWER4 + case macio_grand_central: + pmac_mb.model_id = PMAC_TYPE_PSURGE; + pmac_mb.model_name = "Unknown PowerSurge"; + break; + case macio_ohare: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE; + pmac_mb.model_name = "Unknown OHare-based"; + break; + case macio_heathrow: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW; + pmac_mb.model_name = "Unknown Heathrow-based"; + pmac_mb.features = heathrow_desktop_features; + break; + case macio_paddington: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON; + pmac_mb.model_name = "Unknown Paddington-based"; + pmac_mb.features = paddington_features; + break; + case macio_keylargo: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99; + pmac_mb.model_name = "Unknown Keylargo-based"; + pmac_mb.features = core99_features; + break; + case macio_pangea: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA; + pmac_mb.model_name = "Unknown Pangea-based"; + pmac_mb.features = pangea_features; + break; + case macio_intrepid: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID; + pmac_mb.model_name = "Unknown Intrepid-based"; + pmac_mb.features = intrepid_features; + break; +#else /* CONFIG_POWER4 */ + case macio_keylargo2: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; + pmac_mb.model_name = "Unknown K2-based"; + pmac_mb.features = g5_features; + break; +#endif /* CONFIG_POWER4 */ + default: + return -ENODEV; + } +found: +#ifndef CONFIG_POWER4 + /* Fixup Hooper vs. Comet */ + if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { + u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4); + if (!mach_id_ptr) + return -ENODEV; + /* Here, I used to disable the media-bay on comet. It + * appears this is wrong, the floppy connector is actually + * a kind of media-bay and works with the current driver. + */ + if (__raw_readl(mach_id_ptr) & 0x20000000UL) + pmac_mb.model_id = PMAC_TYPE_COMET; + iounmap(mach_id_ptr); + } +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_6xx + /* Set default value of powersave_nap on machines that support it. + * It appears that uninorth rev 3 has a problem with it, we don't + * enable it on those. In theory, the flush-on-lock property is + * supposed to be set when not supported, but I'm not very confident + * that all Apple OF revs did it properly, I do it the paranoid way. + */ + while (uninorth_base && uninorth_rev > 3) { + struct device_node *np = find_path_device("/cpus"); + if (!np || !np->child) { + printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); + break; + } + np = np->child; + /* Nap mode not supported on SMP */ + if (np->sibling) + break; + /* Nap mode not supported if flush-on-lock property is present */ + if (get_property(np, "flush-on-lock", NULL)) + break; + powersave_nap = 1; + printk(KERN_INFO "Processor NAP mode on idle enabled.\n"); + break; + } + + /* On CPUs that support it (750FX), lowspeed by default during + * NAP mode + */ + powersave_lowspeed = 1; +#endif /* CONFIG_6xx */ +#ifdef CONFIG_POWER4 + powersave_nap = 1; +#endif + /* Check for "mobile" machine */ + if (model && (strncmp(model, "PowerBook", 9) == 0 + || strncmp(model, "iBook", 5) == 0)) + pmac_mb.board_flags |= PMAC_MB_MOBILE; + + + printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); + return 0; +} + +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void __init probe_uninorth(void) +{ + unsigned long actrl; + + /* Locate core99 Uni-N */ + uninorth_node = of_find_node_by_name(NULL, "uni-n"); + /* Locate G5 u3 */ + if (uninorth_node == NULL) { + uninorth_node = of_find_node_by_name(NULL, "u3"); + uninorth_u3 = 1; + } + if (uninorth_node && uninorth_node->n_addrs > 0) { + unsigned long address = uninorth_node->addrs[0].address; + uninorth_base = ioremap(address, 0x40000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + if (uninorth_u3) + u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + } else + uninorth_node = NULL; + + if (!uninorth_node) + return; + + printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n", + uninorth_u3 ? "U3" : "UniNorth", uninorth_rev); + printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); + + /* Set the arbitrer QAck delay according to what Apple does + */ + if (uninorth_rev < 0x11) { + actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : + UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + } + + /* Some more magic as done by them in recent MacOS X on UniNorth + * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI + * memory timeout + */ + if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0) + UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); +} + +static void __init probe_one_macio(const char *name, const char *compat, int type) +{ + struct device_node* node; + int i; + volatile u32 __iomem * base; + u32* revp; + + node = find_devices(name); + if (!node || !node->n_addrs) + return; + if (compat) + do { + if (device_is_compatible(node, compat)) + break; + node = node->next; + } while (node); + if (!node) + return; + for(i=0; i= MAX_MACIO_CHIPS) { + printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); + printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); + return; + } + base = ioremap(node->addrs[0].address, node->addrs[0].size); + if (!base) { + printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); + return; + } + if (type == macio_keylargo) { + u32 *did = (u32 *)get_property(node, "device-id", NULL); + if (*did == 0x00000025) + type = macio_pangea; + if (*did == 0x0000003e) + type = macio_intrepid; + } + macio_chips[i].of_node = node; + macio_chips[i].type = type; + macio_chips[i].base = base; + macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; + macio_chips[i].name = macio_names[type]; + revp = (u32 *)get_property(node, "revision-id", NULL); + if (revp) + macio_chips[i].rev = *revp; + printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", + macio_names[type], macio_chips[i].rev, macio_chips[i].base); +} + +static int __init +probe_macios(void) +{ + /* Warning, ordering is important */ + probe_one_macio("gc", NULL, macio_grand_central); + probe_one_macio("ohare", NULL, macio_ohare); + probe_one_macio("pci106b,7", NULL, macio_ohareII); + probe_one_macio("mac-io", "keylargo", macio_keylargo); + probe_one_macio("mac-io", "paddington", macio_paddington); + probe_one_macio("mac-io", "gatwick", macio_gatwick); + probe_one_macio("mac-io", "heathrow", macio_heathrow); + probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); + + /* Make sure the "main" macio chip appear first */ + if (macio_chips[0].type == macio_gatwick + && macio_chips[1].type == macio_heathrow) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + if (macio_chips[0].type == macio_ohareII + && macio_chips[1].type == macio_ohare) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + macio_chips[0].lbus.index = 0; + macio_chips[1].lbus.index = 1; + + return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; +} + +static void __init +initial_serial_shutdown(struct device_node *np) +{ + int len; + struct slot_names_prop { + int count; + char name[1]; + } *slots; + char *conn; + int port_type = PMAC_SCC_ASYNC; + int modem = 0; + + slots = (struct slot_names_prop *)get_property(np, "slot-names", &len); + conn = get_property(np, "AAPL,connector", &len); + if (conn && (strcmp(conn, "infrared") == 0)) + port_type = PMAC_SCC_IRDA; + else if (device_is_compatible(np, "cobalt")) + modem = 1; + else if (slots && slots->count > 0) { + if (strcmp(slots->name, "IrDA") == 0) + port_type = PMAC_SCC_IRDA; + else if (strcmp(slots->name, "Modem") == 0) + modem = 1; + } + if (modem) + pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0); + pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0); +} + +static void __init +set_initial_features(void) +{ + struct device_node *np; + + /* That hack appears to be necessary for some StarMax motherboards + * but I'm not too sure it was audited for side-effects on other + * ohare based machines... + * Since I still have difficulties figuring the right way to + * differenciate them all and since that hack was there for a long + * time, I'll keep it around + */ + if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) { + struct macio_chip *macio = &macio_chips[0]; + MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); + } else if (macio_chips[0].type == macio_ohare) { + struct macio_chip *macio = &macio_chips[0]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } else if (macio_chips[1].type == macio_ohare) { + struct macio_chip *macio = &macio_chips[1]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + +#ifdef CONFIG_POWER4 + if (macio_chips[0].type == macio_keylargo2) { +#ifndef CONFIG_SMP + /* On SMP machines running UP, we have the second CPU eating + * bus cycles. We need to take it off the bus. This is done + * from pmac_smp for SMP kernels running on one CPU + */ + np = of_find_node_by_type(NULL, "cpu"); + if (np != NULL) + np = of_find_node_by_type(np, "cpu"); + if (np != NULL) { + g5_phy_disable_cpu1(); + of_node_put(np); + } +#endif /* CONFIG_SMP */ + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = of_find_node_by_name(NULL, "ethernet"); + while(np) { + if (device_is_compatible(np, "K2-GMAC")) + g5_gmac_enable(np, 0, 1); + np = of_find_node_by_name(np, "ethernet"); + } + + /* Enable FW before PCI probe. Will be disabled later on + * Note: We should have a batter way to check that we are + * dealing with uninorth internal cell and not a PCI cell + * on the external PCI. The code below works though. + */ + np = of_find_node_by_name(NULL, "firewire"); + while(np) { + if (device_is_compatible(np, "pci106b,5811")) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + g5_fw_enable(np, 0, 1); + } + np = of_find_node_by_name(np, "firewire"); + } + } +#else /* CONFIG_POWER4 */ + + if (macio_chips[0].type == macio_keylargo || + macio_chips[0].type == macio_pangea || + macio_chips[0].type == macio_intrepid) { + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = of_find_node_by_name(NULL, "ethernet"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && device_is_compatible(np, "gmac")) + core99_gmac_enable(np, 0, 1); + np = of_find_node_by_name(np, "ethernet"); + } + + /* Enable FW before PCI probe. Will be disabled later on + * Note: We should have a batter way to check that we are + * dealing with uninorth internal cell and not a PCI cell + * on the external PCI. The code below works though. + */ + np = of_find_node_by_name(NULL, "firewire"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && (device_is_compatible(np, "pci106b,18") || + device_is_compatible(np, "pci106b,30") || + device_is_compatible(np, "pci11c1,5811"))) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + core99_firewire_enable(np, 0, 1); + } + np = of_find_node_by_name(np, "firewire"); + } + + /* Enable ATA-100 before PCI probe. */ + np = of_find_node_by_name(NULL, "ata-6"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && device_is_compatible(np, "kauai-ata")) { + core99_ata100_enable(np, 1); + } + np = of_find_node_by_name(np, "ata-6"); + } + + /* Switch airport off */ + np = find_devices("radio"); + while(np) { + if (np && np->parent == macio_chips[0].of_node) { + macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; + core99_airport_enable(np, 0, 0); + } + np = np->next; + } + } + + /* On all machines that support sound PM, switch sound off */ + if (macio_chips[0].of_node) + pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, + macio_chips[0].of_node, 0, 0); + + /* While on some desktop G3s, we turn it back on */ + if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow + && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER || + pmac_mb.model_id == PMAC_TYPE_SILK)) { + struct macio_chip *macio = &macio_chips[0]; + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + } + + /* Some machine models need the clock chip to be properly setup for + * clock spreading now. This should be a platform function but we + * don't do these at the moment + */ + pmac_tweak_clock_spreading(1); + +#endif /* CONFIG_POWER4 */ + + /* On all machines, switch modem & serial ports off */ + np = find_devices("ch-a"); + while(np) { + initial_serial_shutdown(np); + np = np->next; + } + np = find_devices("ch-b"); + while(np) { + initial_serial_shutdown(np); + np = np->next; + } +} + +void __init +pmac_feature_init(void) +{ + /* Detect the UniNorth memory controller */ + probe_uninorth(); + + /* Probe mac-io controllers */ + if (probe_macios()) { + printk(KERN_WARNING "No mac-io chip found\n"); + return; + } + + /* Setup low-level i2c stuffs */ + pmac_init_low_i2c(); + + /* Probe machine type */ + if (probe_motherboard()) + printk(KERN_WARNING "Unknown PowerMac !\n"); + + /* Set some initial features (turn off some chips that will + * be later turned on) + */ + set_initial_features(); +} + +int __init pmac_feature_late_init(void) +{ +#if 0 + struct device_node *np; + + /* Request some resources late */ + if (uninorth_node) + request_OF_resource(uninorth_node, 0, NULL); + np = find_devices("hammerhead"); + if (np) + request_OF_resource(np, 0, NULL); + np = find_devices("interrupt-controller"); + if (np) + request_OF_resource(np, 0, NULL); +#endif + return 0; +} + +device_initcall(pmac_feature_late_init); + +#if 0 +static void dump_HT_speeds(char *name, u32 cfg, u32 frq) +{ + int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; + int bits[8] = { 8,16,0,32,2,4,0,0 }; + int freq = (frq >> 8) & 0xf; + + if (freqs[freq] == 0) + printk("%s: Unknown HT link frequency %x\n", name, freq); + else + printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", + name, freqs[freq], + bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); +} + +void __init pmac_check_ht_link(void) +{ +#if 0 /* Disabled for now */ + u32 ufreq, freq, ucfg, cfg; + struct device_node *pcix_node; + u8 px_bus, px_devfn; + struct pci_controller *px_hose; + + (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); + ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); + ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); + dump_HT_speeds("U3 HyperTransport", cfg, freq); + + pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); + if (pcix_node == NULL) { + printk("No PCI-X bridge found\n"); + return; + } + if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) { + printk("PCI-X bridge found but not matched to pci\n"); + return; + } + px_hose = pci_find_hose_for_OF_device(pcix_node); + if (px_hose == NULL) { + printk("PCI-X bridge found but not matched to host\n"); + return; + } + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); + dump_HT_speeds("PCI-X HT Uplink", cfg, freq); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); + dump_HT_speeds("PCI-X HT Downlink", cfg, freq); +#endif +} + +#endif /* CONFIG_POWER4 */ + +/* + * Early video resume hook + */ + +static void (*pmac_early_vresume_proc)(void *data); +static void *pmac_early_vresume_data; + +void pmac_set_early_video_resume(void (*proc)(void *data), void *data) +{ + if (_machine != _MACH_Pmac) + return; + preempt_disable(); + pmac_early_vresume_proc = proc; + pmac_early_vresume_data = data; + preempt_enable(); +} +EXPORT_SYMBOL(pmac_set_early_video_resume); + +void pmac_call_early_video_resume(void) +{ + if (pmac_early_vresume_proc) + pmac_early_vresume_proc(pmac_early_vresume_data); +} + +/* + * AGP related suspend/resume code + */ + +static struct pci_dev *pmac_agp_bridge; +static int (*pmac_agp_suspend)(struct pci_dev *bridge); +static int (*pmac_agp_resume)(struct pci_dev *bridge); + +void pmac_register_agp_pm(struct pci_dev *bridge, + int (*suspend)(struct pci_dev *bridge), + int (*resume)(struct pci_dev *bridge)) +{ + if (suspend || resume) { + pmac_agp_bridge = bridge; + pmac_agp_suspend = suspend; + pmac_agp_resume = resume; + return; + } + if (bridge != pmac_agp_bridge) + return; + pmac_agp_suspend = pmac_agp_resume = NULL; + return; +} +EXPORT_SYMBOL(pmac_register_agp_pm); + +void pmac_suspend_agp_for_card(struct pci_dev *dev) +{ + if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) + return; + if (pmac_agp_bridge->bus != dev->bus) + return; + pmac_agp_suspend(pmac_agp_bridge); +} +EXPORT_SYMBOL(pmac_suspend_agp_for_card); + +void pmac_resume_agp_for_card(struct pci_dev *dev) +{ + if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) + return; + if (pmac_agp_bridge->bus != dev->bus) + return; + pmac_agp_resume(pmac_agp_bridge); +} +EXPORT_SYMBOL(pmac_resume_agp_for_card); diff --git a/arch/powerpc/platforms/powermac/pmac_low_i2c.c b/arch/powerpc/platforms/powermac/pmac_low_i2c.c new file mode 100644 index 000000000000..f3f39e8e337a --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_low_i2c.c @@ -0,0 +1,523 @@ +/* + * arch/ppc/platforms/pmac_low_i2c.c + * + * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * 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 file contains some low-level i2c access routines that + * need to be used by various bits of the PowerMac platform code + * at times where the real asynchronous & interrupt driven driver + * cannot be used. The API borrows some semantics from the darwin + * driver in order to ease the implementation of the platform + * properties parser + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_LOW_I2C_HOST 4 + +#ifdef DEBUG +#define DBG(x...) do {\ + printk(KERN_DEBUG "KW:" x); \ + } while(0) +#else +#define DBG(x...) +#endif + +struct low_i2c_host; + +typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); + +struct low_i2c_host +{ + struct device_node *np; /* OF device node */ + struct semaphore mutex; /* Access mutex for use by i2c-keywest */ + low_i2c_func_t func; /* Access function */ + unsigned int is_open : 1; /* Poor man's access control */ + int mode; /* Current mode */ + int channel; /* Current channel */ + int num_channels; /* Number of channels */ + void __iomem *base; /* For keywest-i2c, base address */ + int bsteps; /* And register stepping */ + int speed; /* And speed */ +}; + +static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; + +/* No locking is necessary on allocation, we are running way before + * anything can race with us + */ +static struct low_i2c_host *find_low_i2c_host(struct device_node *np) +{ + int i; + + for (i = 0; i < MAX_LOW_I2C_HOST; i++) + if (low_i2c_hosts[i].np == np) + return &low_i2c_hosts[i]; + return NULL; +} + +/* + * + * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) + * + */ + +/* + * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, + * should be moved somewhere in include/asm-ppc/ + */ +/* Register indices */ +typedef enum { + reg_mode = 0, + reg_control, + reg_status, + reg_isr, + reg_ier, + reg_addr, + reg_subaddr, + reg_data +} reg_t; + + +/* Mode register */ +#define KW_I2C_MODE_100KHZ 0x00 +#define KW_I2C_MODE_50KHZ 0x01 +#define KW_I2C_MODE_25KHZ 0x02 +#define KW_I2C_MODE_DUMB 0x00 +#define KW_I2C_MODE_STANDARD 0x04 +#define KW_I2C_MODE_STANDARDSUB 0x08 +#define KW_I2C_MODE_COMBINED 0x0C +#define KW_I2C_MODE_MODE_MASK 0x0C +#define KW_I2C_MODE_CHAN_MASK 0xF0 + +/* Control register */ +#define KW_I2C_CTL_AAK 0x01 +#define KW_I2C_CTL_XADDR 0x02 +#define KW_I2C_CTL_STOP 0x04 +#define KW_I2C_CTL_START 0x08 + +/* Status register */ +#define KW_I2C_STAT_BUSY 0x01 +#define KW_I2C_STAT_LAST_AAK 0x02 +#define KW_I2C_STAT_LAST_RW 0x04 +#define KW_I2C_STAT_SDA 0x08 +#define KW_I2C_STAT_SCL 0x10 + +/* IER & ISR registers */ +#define KW_I2C_IRQ_DATA 0x01 +#define KW_I2C_IRQ_ADDR 0x02 +#define KW_I2C_IRQ_STOP 0x04 +#define KW_I2C_IRQ_START 0x08 +#define KW_I2C_IRQ_MASK 0x0F + +/* State machine states */ +enum { + state_idle, + state_addr, + state_read, + state_write, + state_stop, + state_dead +}; + +#define WRONG_STATE(name) do {\ + printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ + name, __kw_state_names[state], isr); \ + } while(0) + +static const char *__kw_state_names[] = { + "state_idle", + "state_addr", + "state_read", + "state_write", + "state_stop", + "state_dead" +}; + +static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) +{ + return readb(host->base + (((unsigned int)reg) << host->bsteps)); +} + +static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) +{ + writeb(val, host->base + (((unsigned)reg) << host->bsteps)); + (void)__kw_read_reg(host, reg_subaddr); +} + +#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) +#define kw_read_reg(reg) __kw_read_reg(host, reg) + + +/* Don't schedule, the g5 fan controller is too + * timing sensitive + */ +static u8 kw_wait_interrupt(struct low_i2c_host* host) +{ + int i, j; + u8 isr; + + for (i = 0; i < 100000; i++) { + isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; + if (isr != 0) + return isr; + + /* This code is used with the timebase frozen, we cannot rely + * on udelay ! For now, just use a bogus loop + */ + for (j = 1; j < 10000; j++) + mb(); + } + return isr; +} + +static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) +{ + u8 ack; + + DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); + + if (isr == 0) { + if (state != state_stop) { + DBG("KW: Timeout !\n"); + *rc = -EIO; + goto stop; + } + if (state == state_stop) { + ack = kw_read_reg(reg_status); + if (!(ack & KW_I2C_STAT_BUSY)) { + state = state_idle; + kw_write_reg(reg_ier, 0x00); + } + } + return state; + } + + if (isr & KW_I2C_IRQ_ADDR) { + ack = kw_read_reg(reg_status); + if (state != state_addr) { + kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); + WRONG_STATE("KW_I2C_IRQ_ADDR"); + *rc = -EIO; + goto stop; + } + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + *rc = -ENODEV; + DBG("KW: NAK on address\n"); + return state_stop; + } else { + if (rw) { + state = state_read; + if (*len > 1) + kw_write_reg(reg_control, KW_I2C_CTL_AAK); + } else { + state = state_write; + kw_write_reg(reg_data, **data); + (*data)++; (*len)--; + } + } + kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); + } + + if (isr & KW_I2C_IRQ_DATA) { + if (state == state_read) { + **data = kw_read_reg(reg_data); + (*data)++; (*len)--; + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + if ((*len) == 0) + state = state_stop; + else if ((*len) == 1) + kw_write_reg(reg_control, 0); + } else if (state == state_write) { + ack = kw_read_reg(reg_status); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + DBG("KW: nack on data write\n"); + *rc = -EIO; + goto stop; + } else if (*len) { + kw_write_reg(reg_data, **data); + (*data)++; (*len)--; + } else { + kw_write_reg(reg_control, KW_I2C_CTL_STOP); + state = state_stop; + *rc = 0; + } + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + } else { + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + WRONG_STATE("KW_I2C_IRQ_DATA"); + if (state != state_stop) { + *rc = -EIO; + goto stop; + } + } + } + + if (isr & KW_I2C_IRQ_STOP) { + kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); + if (state != state_stop) { + WRONG_STATE("KW_I2C_IRQ_STOP"); + *rc = -EIO; + } + return state_idle; + } + + if (isr & KW_I2C_IRQ_START) + kw_write_reg(reg_isr, KW_I2C_IRQ_START); + + return state; + + stop: + kw_write_reg(reg_control, KW_I2C_CTL_STOP); + return state_stop; +} + +static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) +{ + u8 mode_reg = host->speed; + int state = state_addr; + int rc = 0; + + /* Setup mode & subaddress if any */ + switch(host->mode) { + case pmac_low_i2c_mode_dumb: + printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); + return -EINVAL; + case pmac_low_i2c_mode_std: + mode_reg |= KW_I2C_MODE_STANDARD; + break; + case pmac_low_i2c_mode_stdsub: + mode_reg |= KW_I2C_MODE_STANDARDSUB; + break; + case pmac_low_i2c_mode_combined: + mode_reg |= KW_I2C_MODE_COMBINED; + break; + } + + /* Setup channel & clear pending irqs */ + kw_write_reg(reg_isr, kw_read_reg(reg_isr)); + kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); + kw_write_reg(reg_status, 0); + + /* Set up address and r/w bit */ + kw_write_reg(reg_addr, addr); + + /* Set up the sub address */ + if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB + || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) + kw_write_reg(reg_subaddr, subaddr); + + /* Start sending address & disable interrupt*/ + kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); + kw_write_reg(reg_control, KW_I2C_CTL_XADDR); + + /* State machine, to turn into an interrupt handler */ + while(state != state_idle) { + u8 isr = kw_wait_interrupt(host); + state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); + } + + return rc; +} + +static void keywest_low_i2c_add(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(NULL); + u32 *psteps, *prate, steps, aoffset = 0; + struct device_node *parent; + + if (host == NULL) { + printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", + np->full_name); + return; + } + memset(host, 0, sizeof(*host)); + + init_MUTEX(&host->mutex); + host->np = of_node_get(np); + psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); + steps = psteps ? (*psteps) : 0x10; + for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) + steps >>= 1; + parent = of_get_parent(np); + host->num_channels = 1; + if (parent && parent->name[0] == 'u') { + host->num_channels = 2; + aoffset = 3; + } + /* Select interface rate */ + host->speed = KW_I2C_MODE_100KHZ; + prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); + if (prate) switch(*prate) { + case 100: + host->speed = KW_I2C_MODE_100KHZ; + break; + case 50: + host->speed = KW_I2C_MODE_50KHZ; + break; + case 25: + host->speed = KW_I2C_MODE_25KHZ; + break; + } + + host->mode = pmac_low_i2c_mode_std; + host->base = ioremap(np->addrs[0].address + aoffset, + np->addrs[0].size); + host->func = keywest_low_i2c_func; +} + +/* + * + * PMU implementation + * + */ + + +#ifdef CONFIG_ADB_PMU + +static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) +{ + // TODO + return -ENODEV; +} + +static void pmu_low_i2c_add(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(NULL); + + if (host == NULL) { + printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", + np->full_name); + return; + } + memset(host, 0, sizeof(*host)); + + init_MUTEX(&host->mutex); + host->np = of_node_get(np); + host->num_channels = 3; + host->mode = pmac_low_i2c_mode_std; + host->func = pmu_low_i2c_func; +} + +#endif /* CONFIG_ADB_PMU */ + +void __init pmac_init_low_i2c(void) +{ + struct device_node *np; + + /* Probe keywest-i2c busses */ + np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); + while(np) { + keywest_low_i2c_add(np); + np = of_find_compatible_node(np, "i2c", "keywest-i2c"); + } + +#ifdef CONFIG_ADB_PMU + /* Probe PMU busses */ + np = of_find_node_by_name(NULL, "via-pmu"); + if (np) + pmu_low_i2c_add(np); +#endif /* CONFIG_ADB_PMU */ + + /* TODO: Add CUDA support as well */ +} + +int pmac_low_i2c_lock(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + down(&host->mutex); + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_lock); + +int pmac_low_i2c_unlock(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + up(&host->mutex); + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_unlock); + + +int pmac_low_i2c_open(struct device_node *np, int channel) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + + if (channel >= host->num_channels) + return -EINVAL; + + down(&host->mutex); + host->is_open = 1; + host->channel = channel; + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_open); + +int pmac_low_i2c_close(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + + host->is_open = 0; + up(&host->mutex); + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_close); + +int pmac_low_i2c_setmode(struct device_node *np, int mode) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + WARN_ON(!host->is_open); + host->mode = mode; + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_setmode); + +int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + WARN_ON(!host->is_open); + + return host->func(host, addrdir, subaddr, data, len); +} +EXPORT_SYMBOL(pmac_low_i2c_xfer); + diff --git a/arch/powerpc/platforms/powermac/pmac_nvram.c b/arch/powerpc/platforms/powermac/pmac_nvram.c new file mode 100644 index 000000000000..8c9b008c7226 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_nvram.c @@ -0,0 +1,584 @@ +/* + * arch/ppc/platforms/pmac_nvram.c + * + * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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. + * + * Todo: - add support for the OF persistent properties + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ + +#define CORE99_SIGNATURE 0x5a +#define CORE99_ADLER_START 0x14 + +/* On Core99, nvram is either a sharp, a micron or an AMD flash */ +#define SM_FLASH_STATUS_DONE 0x80 +#define SM_FLASH_STATUS_ERR 0x38 +#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 +#define SM_FLASH_CMD_ERASE_SETUP 0x20 +#define SM_FLASH_CMD_RESET 0xff +#define SM_FLASH_CMD_WRITE_SETUP 0x40 +#define SM_FLASH_CMD_CLEAR_STATUS 0x50 +#define SM_FLASH_CMD_READ_STATUS 0x70 + +/* CHRP NVRAM header */ +struct chrp_header { + u8 signature; + u8 cksum; + u16 len; + char name[12]; + u8 data[0]; +}; + +struct core99_header { + struct chrp_header hdr; + u32 adler; + u32 generation; + u32 reserved[2]; +}; + +/* + * Read and write the non-volatile RAM on PowerMacs and CHRP machines. + */ +static int nvram_naddrs; +static volatile unsigned char *nvram_addr; +static volatile unsigned char *nvram_data; +static int nvram_mult, is_core_99; +static int core99_bank = 0; +static int nvram_partitions[3]; +static DEFINE_SPINLOCK(nv_lock); + +extern int pmac_newworld; +extern int system_running; + +static int (*core99_write_bank)(int bank, u8* datas); +static int (*core99_erase_bank)(int bank); + +static char *nvram_image; + + +static unsigned char core99_nvram_read_byte(int addr) +{ + if (nvram_image == NULL) + return 0xff; + return nvram_image[addr]; +} + +static void core99_nvram_write_byte(int addr, unsigned char val) +{ + if (nvram_image == NULL) + return; + nvram_image[addr] = val; +} + + +static unsigned char direct_nvram_read_byte(int addr) +{ + return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]); +} + +static void direct_nvram_write_byte(int addr, unsigned char val) +{ + out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val); +} + + +static unsigned char indirect_nvram_read_byte(int addr) +{ + unsigned char val; + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + val = in_8(&nvram_data[(addr & 0x1f) << 4]); + spin_unlock_irqrestore(&nv_lock, flags); + + return val; +} + +static void indirect_nvram_write_byte(int addr, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + out_8(&nvram_data[(addr & 0x1f) << 4], val); + spin_unlock_irqrestore(&nv_lock, flags); +} + + +#ifdef CONFIG_ADB_PMU + +static void pmu_nvram_complete(struct adb_request *req) +{ + if (req->arg) + complete((struct completion *)req->arg); +} + +static unsigned char pmu_nvram_read_byte(int addr) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM, + (addr >> 8) & 0xff, addr & 0xff)) + return 0xff; + if (system_state == SYSTEM_RUNNING) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); + return req.reply[0]; +} + +static void pmu_nvram_write_byte(int addr, unsigned char val) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM, + (addr >> 8) & 0xff, addr & 0xff, val)) + return; + if (system_state == SYSTEM_RUNNING) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); +} + +#endif /* CONFIG_ADB_PMU */ + + +static u8 chrp_checksum(struct chrp_header* hdr) +{ + u8 *ptr; + u16 sum = hdr->signature; + for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) + sum += *ptr; + while (sum > 0xFF) + sum = (sum & 0xFF) + (sum>>8); + return sum; +} + +static u32 core99_calc_adler(u8 *buffer) +{ + int cnt; + u32 low, high; + + buffer += CORE99_ADLER_START; + low = 1; + high = 0; + for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { + if ((cnt % 5000) == 0) { + high %= 65521UL; + high %= 65521UL; + } + low += buffer[cnt]; + high += low; + } + low %= 65521UL; + high %= 65521UL; + + return (high << 16) | low; +} + +static u32 core99_check(u8* datas) +{ + struct core99_header* hdr99 = (struct core99_header*)datas; + + if (hdr99->hdr.signature != CORE99_SIGNATURE) { + DBG("Invalid signature\n"); + return 0; + } + if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { + DBG("Invalid checksum\n"); + return 0; + } + if (hdr99->adler != core99_calc_adler(datas)) { + DBG("Invalid adler\n"); + return 0; + } + return hdr99->generation; +} + +static int sm_erase_bank(int bank) +{ + int stat, i; + unsigned long timeout; + + u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + + DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); + + out_8(base, SM_FLASH_CMD_ERASE_SETUP); + out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + if (!(stat & SM_FLASH_STATUS_DONE)) + break; + } + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: AMD flash write timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + if (stat != 0) + break; + } + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + + for (i=0; iname, "common")) + nvram_partitions[pmac_nvram_OF] = offset + 0x10; + if (!strcmp(hdr->name, "APL,MacOS75")) { + nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10; + nvram_partitions[pmac_nvram_NR] = offset + 0x110; + } + offset += (hdr->len * 0x10); + } while(offset < NVRAM_SIZE); + } else { + nvram_partitions[pmac_nvram_OF] = 0x1800; + nvram_partitions[pmac_nvram_XPRAM] = 0x1300; + nvram_partitions[pmac_nvram_NR] = 0x1400; + } + DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]); + DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]); + DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]); +} + +static void core99_nvram_sync(void) +{ + struct core99_header* hdr99; + unsigned long flags; + + if (!is_core_99 || !nvram_data || !nvram_image) + return; + + spin_lock_irqsave(&nv_lock, flags); + if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, + NVRAM_SIZE)) + goto bail; + + DBG("Updating nvram...\n"); + + hdr99 = (struct core99_header*)nvram_image; + hdr99->generation++; + hdr99->hdr.signature = CORE99_SIGNATURE; + hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); + hdr99->adler = core99_calc_adler(nvram_image); + core99_bank = core99_bank ? 0 : 1; + if (core99_erase_bank) + if (core99_erase_bank(core99_bank)) { + printk("nvram: Error erasing bank %d\n", core99_bank); + goto bail; + } + if (core99_write_bank) + if (core99_write_bank(core99_bank, nvram_image)) + printk("nvram: Error writing bank %d\n", core99_bank); + bail: + spin_unlock_irqrestore(&nv_lock, flags); + +#ifdef DEBUG + mdelay(2000); +#endif +} + +void __init pmac_nvram_init(void) +{ + struct device_node *dp; + + nvram_naddrs = 0; + + dp = find_devices("nvram"); + if (dp == NULL) { + printk(KERN_ERR "Can't find NVRAM device\n"); + return; + } + nvram_naddrs = dp->n_addrs; + is_core_99 = device_is_compatible(dp, "nvram,flash"); + if (is_core_99) { + int i; + u32 gen_bank0, gen_bank1; + + if (nvram_naddrs < 1) { + printk(KERN_ERR "nvram: no address\n"); + return; + } + nvram_image = alloc_bootmem(NVRAM_SIZE); + if (nvram_image == NULL) { + printk(KERN_ERR "nvram: can't allocate ram image\n"); + return; + } + nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); + nvram_naddrs = 1; /* Make sure we get the correct case */ + + DBG("nvram: Checking bank 0...\n"); + + gen_bank0 = core99_check((u8 *)nvram_data); + gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); + core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; + + DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); + DBG("nvram: Active bank is: %d\n", core99_bank); + + for (i=0; iaddrs[0].address + isa_mem_base, + dp->addrs[0].size); + nvram_mult = 1; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; + } else if (nvram_naddrs == 1) { + nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; + } else if (nvram_naddrs == 2) { + nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); + ppc_md.nvram_read_val = indirect_nvram_read_byte; + ppc_md.nvram_write_val = indirect_nvram_write_byte; + } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { +#ifdef CONFIG_ADB_PMU + nvram_naddrs = -1; + ppc_md.nvram_read_val = pmu_nvram_read_byte; + ppc_md.nvram_write_val = pmu_nvram_write_byte; +#endif /* CONFIG_ADB_PMU */ + } else { + printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", + nvram_naddrs); + } + lookup_partitions(); +} + +int pmac_get_partition(int partition) +{ + return nvram_partitions[partition]; +} + +u8 pmac_xpram_read(int xpaddr) +{ + int offset = nvram_partitions[pmac_nvram_XPRAM]; + + if (offset < 0) + return 0xff; + + return ppc_md.nvram_read_val(xpaddr + offset); +} + +void pmac_xpram_write(int xpaddr, u8 data) +{ + int offset = nvram_partitions[pmac_nvram_XPRAM]; + + if (offset < 0) + return; + + ppc_md.nvram_write_val(xpaddr + offset, data); +} + +EXPORT_SYMBOL(pmac_get_partition); +EXPORT_SYMBOL(pmac_xpram_read); +EXPORT_SYMBOL(pmac_xpram_write); diff --git a/arch/powerpc/platforms/powermac/pmac_pci.c b/arch/powerpc/platforms/powermac/pmac_pci.c new file mode 100644 index 000000000000..40bcd3e55afb --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_pci.c @@ -0,0 +1,1341 @@ +/* + * Support for PCI bridges found on Power Macintoshes. + * At present the "bandit" and "chaos" bridges are supported. + * Fortunately you access configuration space in the same + * way with either bridge. + * + * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) + * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) + * + * 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 + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static int add_bridge(struct device_node *dev); +extern void pmac_check_ht_link(void); + +/* XXX Could be per-controller, but I don't think we risk anything by + * assuming we won't have both UniNorth and Bandit */ +static int has_uninorth; +#ifdef CONFIG_POWER4 +static struct pci_controller *u3_agp; +#endif /* CONFIG_POWER4 */ + +extern u8 pci_cache_line_size; +extern int pcibios_assign_bus_offset; + +struct device_node *k2_skiplist[2]; + +/* + * Magic constants for enabling cache coherency in the bandit/PSX bridge. + */ +#define BANDIT_DEVID_2 8 +#define BANDIT_REVID 3 + +#define BANDIT_DEVNUM 11 +#define BANDIT_MAGIC 0x50 +#define BANDIT_COHERENT 0x40 + +static int __init fixup_one_level_bus_range(struct device_node *node, int higher) +{ + for (; node != 0;node = node->sibling) { + int * bus_range; + unsigned int *class_code; + int len; + + /* For PCI<->PCI bridges or CardBus bridges, we go down */ + class_code = (unsigned int *) get_property(node, "class-code", NULL); + if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && + (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) + continue; + bus_range = (int *) get_property(node, "bus-range", &len); + if (bus_range != NULL && len > 2 * sizeof(int)) { + if (bus_range[1] > higher) + higher = bus_range[1]; + } + higher = fixup_one_level_bus_range(node->child, higher); + } + return higher; +} + +/* This routine fixes the "bus-range" property of all bridges in the + * system since they tend to have their "last" member wrong on macs + * + * Note that the bus numbers manipulated here are OF bus numbers, they + * are not Linux bus numbers. + */ +static void __init fixup_bus_range(struct device_node *bridge) +{ + int * bus_range; + int len; + + /* Lookup the "bus-range" property for the hose */ + bus_range = (int *) get_property(bridge, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + bridge->full_name); + return; + } + bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); +} + +/* + * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers. + * + * The "Bandit" version is present in all early PCI PowerMacs, + * and up to the first ones using Grackle. Some machines may + * have 2 bandit controllers (2 PCI busses). + * + * "Chaos" is used in some "Bandit"-type machines as a bridge + * for the separate display bus. It is accessed the same + * way as bandit, but cannot be probed for devices. It therefore + * has its own config access functions. + * + * The "UniNorth" version is present in all Core99 machines + * (iBook, G4, new IMacs, and all the recent Apple machines). + * It contains 3 controllers in one ASIC. + * + * The U3 is the bridge used on G5 machines. It contains an + * AGP bus which is dealt with the old UniNorth access routines + * and a HyperTransport bus which uses its own set of access + * functions. + */ + +#define MACRISC_CFA0(devfn, off) \ + ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ + | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ + | (((unsigned long)(off)) & 0xFCUL)) + +#define MACRISC_CFA1(bus, devfn, off) \ + ((((unsigned long)(bus)) << 16) \ + |(((unsigned long)(devfn)) << 8) \ + |(((unsigned long)(off)) & 0xFCUL) \ + |1UL) + +static unsigned long macrisc_cfg_access(struct pci_controller* hose, + u8 bus, u8 dev_fn, u8 offset) +{ + unsigned int caddr; + + if (bus == hose->first_busno) { + if (dev_fn < (11 << 3)) + return 0; + caddr = MACRISC_CFA0(dev_fn, offset); + } else + caddr = MACRISC_CFA1(bus, dev_fn, offset); + + /* Uninorth will return garbage if we don't read back the value ! */ + do { + out_le32(hose->cfg_addr, caddr); + } while (in_le32(hose->cfg_addr) != caddr); + + offset &= has_uninorth ? 0x07 : 0x03; + return ((unsigned long)hose->cfg_data) + offset; +} + +static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr; + + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8((u8 *)addr); + break; + case 2: + *val = in_le16((u16 *)addr); + break; + default: + *val = in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr; + + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8((u8 *)addr, val); + (void) in_8((u8 *)addr); + break; + case 2: + out_le16((u16 *)addr, val); + (void) in_le16((u16 *)addr); + break; + default: + out_le32((u32 *)addr, val); + (void) in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops macrisc_pci_ops = +{ + macrisc_read_config, + macrisc_write_config +}; + +/* + * Verifiy that a specific (bus, dev_fn) exists on chaos + */ +static int +chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) +{ + struct device_node *np; + u32 *vendor, *device; + + np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + vendor = (u32 *)get_property(np, "vendor-id", NULL); + device = (u32 *)get_property(np, "device-id", NULL); + if (vendor == NULL || device == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10) + && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +static int +chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + int result = chaos_validate_dev(bus, devfn, offset); + if (result == PCIBIOS_BAD_REGISTER_NUMBER) + *val = ~0U; + if (result != PCIBIOS_SUCCESSFUL) + return result; + return macrisc_read_config(bus, devfn, offset, len, val); +} + +static int +chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + int result = chaos_validate_dev(bus, devfn, offset); + if (result != PCIBIOS_SUCCESSFUL) + return result; + return macrisc_write_config(bus, devfn, offset, len, val); +} + +static struct pci_ops chaos_pci_ops = +{ + chaos_read_config, + chaos_write_config +}; + +#ifdef CONFIG_POWER4 + +/* + * These versions of U3 HyperTransport config space access ops do not + * implement self-view of the HT host yet + */ + +/* + * This function deals with some "special cases" devices. + * + * 0 -> No special case + * 1 -> Skip the device but act as if the access was successfull + * (return 0xff's on reads, eventually, cache config space + * accesses in a later version) + * -1 -> Hide the device (unsuccessful acess) + */ +static int u3_ht_skip_device(struct pci_controller *hose, + struct pci_bus *bus, unsigned int devfn) +{ + struct device_node *busdn, *dn; + int i; + + /* We only allow config cycles to devices that are in OF device-tree + * as we are apparently having some weird things going on with some + * revs of K2 on recent G5s + */ + if (bus->self) + busdn = pci_device_to_OF_node(bus->self); + else + busdn = hose->arch_data; + for (dn = busdn->child; dn; dn = dn->sibling) + if (dn->data && PCI_DN(dn)->devfn == devfn) + break; + if (dn == NULL) + return -1; + + /* + * When a device in K2 is powered down, we die on config + * cycle accesses. Fix that here. + */ + for (i=0; i<2; i++) + if (k2_skiplist[i] == dn) + return 1; + + return 0; +} + +#define U3_HT_CFA0(devfn, off) \ + ((((unsigned long)devfn) << 8) | offset) +#define U3_HT_CFA1(bus, devfn, off) \ + (U3_HT_CFA0(devfn, off) \ + + (((unsigned long)bus) << 16) \ + + 0x01000000UL) + +static unsigned long u3_ht_cfg_access(struct pci_controller* hose, + u8 bus, u8 devfn, u8 offset) +{ + if (bus == hose->first_busno) { + /* For now, we don't self probe U3 HT bridge */ + if (PCI_SLOT(devfn) == 0) + return 0; + return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); + } else + return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); +} + +static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr; + + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (u3_ht_skip_device(hose, bus, devfn)) { + case 0: + break; + case 1: + switch (len) { + case 1: + *val = 0xff; break; + case 2: + *val = 0xffff; break; + default: + *val = 0xfffffffful; break; + } + return PCIBIOS_SUCCESSFUL; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8((u8 *)addr); + break; + case 2: + *val = in_le16((u16 *)addr); + break; + default: + *val = in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr; + + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (u3_ht_skip_device(hose, bus, devfn)) { + case 0: + break; + case 1: + return PCIBIOS_SUCCESSFUL; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8((u8 *)addr, val); + (void) in_8((u8 *)addr); + break; + case 2: + out_le16((u16 *)addr, val); + (void) in_le16((u16 *)addr); + break; + default: + out_le32((u32 *)addr, val); + (void) in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops u3_ht_pci_ops = +{ + u3_ht_read_config, + u3_ht_write_config +}; + +#endif /* CONFIG_POWER4 */ + +/* + * For a bandit bridge, turn on cache coherency if necessary. + * N.B. we could clean this up using the hose ops directly. + */ +static void __init +init_bandit(struct pci_controller *bp) +{ + unsigned int vendev, magic; + int rev; + + /* read the word at offset 0 in config space for device 11 */ + out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); + udelay(2); + vendev = in_le32(bp->cfg_data); + if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + + PCI_VENDOR_ID_APPLE) { + /* read the revision id */ + out_le32(bp->cfg_addr, + (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); + udelay(2); + rev = in_8(bp->cfg_data); + if (rev != BANDIT_REVID) + printk(KERN_WARNING + "Unknown revision %d for bandit\n", rev); + } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { + printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); + return; + } + + /* read the word at offset 0x50 */ + out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC); + udelay(2); + magic = in_le32(bp->cfg_data); + if ((magic & BANDIT_COHERENT) != 0) + return; + magic |= BANDIT_COHERENT; + udelay(2); + out_le32(bp->cfg_data, magic); + printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); +} + + +/* + * Tweak the PCI-PCI bridge chip on the blue & white G3s. + */ +static void __init +init_p2pbridge(void) +{ + struct device_node *p2pbridge; + struct pci_controller* hose; + u8 bus, devfn; + u16 val; + + /* XXX it would be better here to identify the specific + PCI-PCI bridge chip we have. */ + if ((p2pbridge = find_devices("pci-bridge")) == 0 + || p2pbridge->parent == NULL + || strcmp(p2pbridge->parent->name, "pci") != 0) + return; + if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { + DBG("Can't find PCI infos for PCI<->PCI bridge\n"); + return; + } + /* Warning: At this point, we have not yet renumbered all busses. + * So we must use OF walking to find out hose + */ + hose = pci_find_hose_for_OF_device(p2pbridge); + if (!hose) { + DBG("Can't find hose for PCI<->PCI bridge\n"); + return; + } + if (early_read_config_word(hose, bus, devfn, + PCI_BRIDGE_CONTROL, &val) < 0) { + printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); + return; + } + val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; + early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); +} + +/* + * Some Apple desktop machines have a NEC PD720100A USB2 controller + * on the motherboard. Open Firmware, on these, will disable the + * EHCI part of it so it behaves like a pair of OHCI's. This fixup + * code re-enables it ;) + */ +static void __init +fixup_nec_usb2(void) +{ + struct device_node *nec; + + for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) { + struct pci_controller *hose; + u32 data, *prop; + u8 bus, devfn; + + prop = (u32 *)get_property(nec, "vendor-id", NULL); + if (prop == NULL) + continue; + if (0x1033 != *prop) + continue; + prop = (u32 *)get_property(nec, "device-id", NULL); + if (prop == NULL) + continue; + if (0x0035 != *prop) + continue; + prop = (u32 *)get_property(nec, "reg", NULL); + if (prop == NULL) + continue; + devfn = (prop[0] >> 8) & 0xff; + bus = (prop[0] >> 16) & 0xff; + if (PCI_FUNC(devfn) != 0) + continue; + hose = pci_find_hose_for_OF_device(nec); + if (!hose) + continue; + early_read_config_dword(hose, bus, devfn, 0xe4, &data); + if (data & 1UL) { + printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n"); + data &= ~1UL; + early_write_config_dword(hose, bus, devfn, 0xe4, data); + early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE, + nec->intrs[0].line); + } + } +} + +void __init +pmac_find_bridges(void) +{ + struct device_node *np, *root; + struct device_node *ht = NULL; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + return; + } + for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { + if (np->name == NULL) + continue; + if (strcmp(np->name, "bandit") == 0 + || strcmp(np->name, "chaos") == 0 + || strcmp(np->name, "pci") == 0) { + if (add_bridge(np) == 0) + of_node_get(np); + } + if (strcmp(np->name, "ht") == 0) { + of_node_get(np); + ht = np; + } + } + of_node_put(root); + + /* Probe HT last as it relies on the agp resources to be already + * setup + */ + if (ht && add_bridge(ht) != 0) + of_node_put(ht); + + init_p2pbridge(); + fixup_nec_usb2(); + + /* We are still having some issues with the Xserve G4, enabling + * some offset between bus number and domains for now when we + * assign all busses should help for now + */ + if (pci_assign_all_busses) + pcibios_assign_bus_offset = 0x10; + +#ifdef CONFIG_POWER4 + /* There is something wrong with DMA on U3/HT. I haven't figured out + * the details yet, but if I set the cache line size to 128 bytes like + * it should, I'm getting memory corruption caused by devices like + * sungem (even without the MWI bit set, but maybe sungem doesn't + * care). Right now, it appears that setting up a 64 bytes line size + * works properly, 64 bytes beeing the max transfer size of HT, I + * suppose this is related the way HT/PCI are hooked together. I still + * need to dive into more specs though to be really sure of what's + * going on. --BenH. + * + * Ok, apparently, it's just that HT can't do more than 64 bytes + * transactions. MWI seem to be meaningless there as well, it may + * be worth nop'ing out pci_set_mwi too though I haven't done that + * yet. + * + * Note that it's a bit different for whatever is in the AGP slot. + * For now, I don't care, but this can become a real issue, we + * should probably hook pci_set_mwi anyway to make sure it sets + * the real cache line size in there. + */ + if (machine_is_compatible("MacRISC4")) + pci_cache_line_size = 16; /* 64 bytes */ + + pmac_check_ht_link(); +#endif /* CONFIG_POWER4 */ +} + +#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ + | (((o) & ~3) << 24)) + +#define GRACKLE_PICR1_STG 0x00000040 +#define GRACKLE_PICR1_LOOPSNOOP 0x00000010 + +/* N.B. this is called before bridges is initialized, so we can't + use grackle_pcibios_{read,write}_config_dword. */ +static inline void grackle_set_stg(struct pci_controller* bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_STG) : + (val & ~GRACKLE_PICR1_STG); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : + (val & ~GRACKLE_PICR1_LOOPSNOOP); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +static int __init +setup_uninorth(struct pci_controller* hose, struct reg_property* addr) +{ + pci_assign_all_busses = 1; + has_uninorth = 1; + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + /* We "know" that the bridge at f2000000 has the PCI slots. */ + return addr->address == 0xf2000000; +} + +static void __init +setup_bandit(struct pci_controller* hose, struct reg_property* addr) +{ + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + init_bandit(hose); +} + +static void __init +setup_chaos(struct pci_controller* hose, struct reg_property* addr) +{ + /* assume a `chaos' bridge */ + hose->ops = &chaos_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); +} + +#ifdef CONFIG_POWER4 + +static void __init setup_u3_agp(struct pci_controller* hose) +{ + /* On G5, we move AGP up to high bus number so we don't need + * to reassign bus numbers for HT. If we ever have P2P bridges + * on AGP, we'll have to move pci_assign_all_busses to the + * pci_controller structure so we enable it for AGP and not for + * HT childs. + * We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->first_busno = 0xf0; + hose->last_busno = 0xff; + has_uninorth = 1; + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); + hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); + + u3_agp = hose; +} + +static void __init setup_u3_ht(struct pci_controller* hose) +{ + struct device_node *np = (struct device_node *)hose->arch_data; + int i, cur; + + hose->ops = &u3_ht_pci_ops; + + /* We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); + + /* + * /ht node doesn't expose a "ranges" property, so we "remove" regions that + * have been allocated to AGP. So far, this version of the code doesn't assign + * any of the 0xfxxxxxxx "fine" memory regions to /ht. + * We need to fix that sooner or later by either parsing all child "ranges" + * properties or figuring out the U3 address space decoding logic and + * then read its configuration register (if any). + */ + hose->io_base_phys = 0xf4000000; + hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); + isa_io_base = (unsigned long) hose->io_base_virt; + hose->io_resource.name = np->full_name; + hose->io_resource.start = 0; + hose->io_resource.end = 0x003fffff; + hose->io_resource.flags = IORESOURCE_IO; + hose->pci_mem_offset = 0; + hose->first_busno = 0; + hose->last_busno = 0xef; + hose->mem_resources[0].name = np->full_name; + hose->mem_resources[0].start = 0x80000000; + hose->mem_resources[0].end = 0xefffffff; + hose->mem_resources[0].flags = IORESOURCE_MEM; + + if (u3_agp == NULL) { + DBG("U3 has no AGP, using full resource range\n"); + return; + } + + /* We "remove" the AGP resources from the resources allocated to HT, that + * is we create "holes". However, that code does assumptions that so far + * happen to be true (cross fingers...), typically that resources in the + * AGP node are properly ordered + */ + cur = 0; + for (i=0; i<3; i++) { + struct resource *res = &u3_agp->mem_resources[i]; + if (res->flags != IORESOURCE_MEM) + continue; + /* We don't care about "fine" resources */ + if (res->start >= 0xf0000000) + continue; + /* Check if it's just a matter of "shrinking" us in one direction */ + if (hose->mem_resources[cur].start == res->start) { + DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].start, res->end + 1); + hose->mem_resources[cur].start = res->end + 1; + continue; + } + if (hose->mem_resources[cur].end == res->end) { + DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].end, res->start - 1); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + /* No, it's not the case, we need a hole */ + if (cur == 2) { + /* not enough resources to make a hole, we drop part of the range */ + printk(KERN_WARNING "Running out of resources for /ht host !\n"); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + cur++; + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + cur-1, res->start - 1, cur, res->end + 1); + hose->mem_resources[cur].name = np->full_name; + hose->mem_resources[cur].flags = IORESOURCE_MEM; + hose->mem_resources[cur].start = res->end + 1; + hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; + hose->mem_resources[cur-1].end = res->start - 1; + } +} + +#endif /* CONFIG_POWER4 */ + +void __init +setup_grackle(struct pci_controller *hose) +{ + setup_indirect_pci(hose, 0xfec00000, 0xfee00000); + if (machine_is_compatible("AAPL,PowerBook1998")) + grackle_set_loop_snoop(hose, 1); +#if 0 /* Disabled for now, HW problems ??? */ + grackle_set_stg(hose, 1); +#endif +} + +static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + static unsigned int static_lc_ranges[2024]; + unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; + unsigned int size; + int rlen = 0, orig_rlen; + int memno = 0; + struct resource *res; + int np, na = prom_n_addr_cells(dev); + + np = na + 5; + + /* First we try to merge ranges to fix a problem with some pmacs + * that can have more than 3 ranges, fortunately using contiguous + * addresses -- BenH + */ + dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + if (!dt_ranges) + return; + /* lc_ranges = alloc_bootmem(rlen);*/ + lc_ranges = static_lc_ranges; + if (!lc_ranges) + return; /* what can we do here ? */ + memcpy(lc_ranges, dt_ranges, rlen); + orig_rlen = rlen; + + /* Let's work on a copy of the "ranges" property instead of damaging + * the device-tree image in memory + */ + ranges = lc_ranges; + prev = NULL; + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + if (prev) { + if (prev[0] == ranges[0] && prev[1] == ranges[1] && + (prev[2] + prev[na+4]) == ranges[2] && + (prev[na+2] + prev[na+4]) == ranges[na+2]) { + prev[na+4] += ranges[na+4]; + ranges[0] = 0; + ranges += np; + continue; + } + } + prev = ranges; + ranges += np; + } + + /* + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 2: a PCI address + * cells 3 or 3+4: a CPU physical address + * (size depending on dev->n_addr_cells) + * cells 4+5 or 5+6: the size of the range + */ + ranges = lc_ranges; + rlen = orig_rlen; + while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { + res = NULL; + size = ranges[na+4]; + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + if (ranges[2] != 0) + break; + hose->io_base_phys = ranges[na+2]; + /* limit I/O space to 16MB */ + if (size > 0x01000000) + size = 0x01000000; + hose->io_base_virt = ioremap(ranges[na+2], size); + if (primary) + isa_io_base = (unsigned long) hose->io_base_virt; + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = ranges[2]; + break; + case 2: /* memory space */ + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[na+4] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ +#if 0 + if (primary) + isa_mem_base = ranges[na+2]; +#endif + memno = 1; + } + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) + hose->pci_mem_offset = ranges[na+2] - ranges[2]; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[na+2]; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + size - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += np; + } +} + +/* + * We assume that if we have a G3 powermac, we have one bridge called + * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, + * if we have one or more bandit or chaos bridges, we don't have a MPC106. + */ +static int __init add_bridge(struct device_node *dev) +{ + int len; + struct pci_controller *hose; + struct reg_property *addr; + char* disp_name; + int *bus_range; + int primary = 1; + + DBG("Adding PCI host bridge %s\n", dev->full_name); + + addr = (struct reg_property *) get_property(dev, "reg", &len); + if (addr == NULL || len < sizeof(*addr)) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + return -ENODEV; + } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } + + hose = pcibios_alloc_controller(); + if (!hose) + return -ENOMEM; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + disp_name = NULL; +#ifdef CONFIG_POWER4 + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose, addr); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose, addr); + disp_name = "U3-HT"; + primary = 1; + } else +#endif /* CONFIG_POWER4 */ + if (device_is_compatible(dev, "uni-north")) { + primary = setup_uninorth(hose, addr); + disp_name = "UniNorth"; + } else if (strcmp(dev->name, "pci") == 0) { + /* XXX assume this is a mpc106 (grackle) */ + setup_grackle(hose); + disp_name = "Grackle (MPC106)"; + } else if (strcmp(dev->name, "bandit") == 0) { + setup_bandit(hose, addr); + disp_name = "Bandit"; + } else if (strcmp(dev->name, "chaos") == 0) { + setup_chaos(hose, addr); + disp_name = "Chaos"; + primary = 0; + } + printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", + disp_name, addr->address, hose->first_busno, hose->last_busno); + DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", + hose, hose->cfg_addr, hose->cfg_data); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev, primary); + + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); + + return 0; +} + +static void __init +pcibios_fixup_OF_interrupts(void) +{ + struct pci_dev* dev = NULL; + + /* + * Open Firmware often doesn't initialize the + * PCI_INTERRUPT_LINE config register properly, so we + * should find the device node and apply the interrupt + * obtained from the OF device-tree + */ + for_each_pci_dev(dev) { + struct device_node *node; + node = pci_device_to_OF_node(dev); + /* this is the node, see if it has interrupts */ + if (node && node->n_intrs > 0) + dev->irq = node->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +void __init +pmac_pcibios_fixup(void) +{ + /* Fixup interrupts according to OF tree */ + pcibios_fixup_OF_interrupts(); +} + +int +pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) +{ + struct device_node* node; + int updatecfg = 0; + int uninorth_child; + + node = pci_device_to_OF_node(dev); + + /* We don't want to enable USB controllers absent from the OF tree + * (iBook second controller) + */ + if (dev->vendor == PCI_VENDOR_ID_APPLE + && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) + && !node) { + printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n", + pci_name(dev)); + return -EINVAL; + } + + if (!node) + return 0; + + uninorth_child = node->parent && + device_is_compatible(node->parent, "uni-north"); + + /* Firewire & GMAC were disabled after PCI probe, the driver is + * claiming them, we must re-enable them now. + */ + if (uninorth_child && !strcmp(node->name, "firewire") && + (device_is_compatible(node, "pci106b,18") || + device_is_compatible(node, "pci106b,30") || + device_is_compatible(node, "pci11c1,5811"))) { + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1); + pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1); + updatecfg = 1; + } + if (uninorth_child && !strcmp(node->name, "ethernet") && + device_is_compatible(node, "gmac")) { + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1); + updatecfg = 1; + } + + if (updatecfg) { + u16 cmd; + + /* + * Make sure PCI is correctly configured + * + * We use old pci_bios versions of the function since, by + * default, gmac is not powered up, and so will be absent + * from the kernel initial PCI lookup. + * + * Should be replaced by 2.4 new PCI mechanisms and really + * register the device. + */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); + } + + return 0; +} + +/* We power down some devices after they have been probed. They'll + * be powered back on later on + */ +void __init +pmac_pcibios_after_init(void) +{ + struct device_node* nd; + +#ifdef CONFIG_BLK_DEV_IDE + struct pci_dev *dev = NULL; + + /* OF fails to initialize IDE controllers on macs + * (and maybe other machines) + * + * Ideally, this should be moved to the IDE layer, but we need + * to check specifically with Andre Hedrick how to do it cleanly + * since the common IDE code seem to care about the fact that the + * BIOS may have disabled a controller. + * + * -- BenH + */ + for_each_pci_dev(dev) { + if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) + pci_enable_device(dev); + } +#endif /* CONFIG_BLK_DEV_IDE */ + + nd = find_devices("firewire"); + while (nd) { + if (nd->parent && (device_is_compatible(nd, "pci106b,18") || + device_is_compatible(nd, "pci106b,30") || + device_is_compatible(nd, "pci11c1,5811")) + && device_is_compatible(nd->parent, "uni-north")) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); + } + nd = nd->next; + } + nd = find_devices("ethernet"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "gmac") + && device_is_compatible(nd->parent, "uni-north")) + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); + nd = nd->next; + } +} + +#ifdef CONFIG_PPC64 +static void __init pmac_fixup_phb_resources(void) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; + hose->io_resource.start += offset; + hose->io_resource.end += offset; + printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", + hose->global_number, + hose->io_resource.start, hose->io_resource.end); + } +} + +void __init pmac_pci_init(void) +{ + struct device_node *np, *root; + struct device_node *ht = NULL; + + /* Probe root PCI hosts, that is on U3 the AGP host and the + * HyperTransport host. That one is actually "kept" around + * and actually added last as it's resource management relies + * on the AGP resources to have been setup first + */ + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + return; + } + for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { + if (np->name == NULL) + continue; + if (strcmp(np->name, "pci") == 0) { + if (add_bridge(np) == 0) + of_node_get(np); + } + if (strcmp(np->name, "ht") == 0) { + of_node_get(np); + ht = np; + } + } + of_node_put(root); + + /* Now setup the HyperTransport host if we found any + */ + if (ht && add_bridge(ht) != 0) + of_node_put(ht); + + /* Fixup the IO resources on our host bridges as the common code + * does it only for childs of the host bridges + */ + pmac_fixup_phb_resources(); + + /* Setup the linkage between OF nodes and PHBs */ + pci_devs_phb_init(); + + /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We + * assume there is no P2P bridge on the AGP bus, which should be a + * safe assumptions hopefully. + */ + if (u3_agp) { + struct device_node *np = u3_agp->arch_data; + PCI_DN(np)->busno = 0xf0; + for (np = np->child; np; np = np->sibling) + PCI_DN(np)->busno = 0xf0; + } + + pmac_check_ht_link(); + + /* Tell pci.c to not use the common resource allocation mecanism */ + pci_probe_only = 1; + + /* Allow all IO */ + io_page_mask = -1; +} +#endif + +#ifdef CONFIG_PPC32 +void pmac_pci_fixup_cardbus(struct pci_dev* dev) +{ + if (_machine != _MACH_Pmac) + return; + /* + * Fix the interrupt routing on the various cardbus bridges + * used on powerbooks + */ + if (dev->vendor != PCI_VENDOR_ID_TI) + return; + if (dev->device == PCI_DEVICE_ID_TI_1130 || + dev->device == PCI_DEVICE_ID_TI_1131) { + u8 val; + /* Enable PCI interrupt */ + if (pci_read_config_byte(dev, 0x91, &val) == 0) + pci_write_config_byte(dev, 0x91, val | 0x30); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } + if (dev->device == PCI_DEVICE_ID_TI_1210 || + dev->device == PCI_DEVICE_ID_TI_1211 || + dev->device == PCI_DEVICE_ID_TI_1410 || + dev->device == PCI_DEVICE_ID_TI_1510) { + u8 val; + /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA + signal out the MFUNC0 pin */ + if (pci_read_config_byte(dev, 0x8c, &val) == 0) + pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus); + +void pmac_pci_fixup_pciata(struct pci_dev* dev) +{ + u8 progif = 0; + + /* + * On PowerMacs, we try to switch any PCI ATA controller to + * fully native mode + */ + if (_machine != _MACH_Pmac) + return; + /* Some controllers don't have the class IDE */ + if (dev->vendor == PCI_VENDOR_ID_PROMISE) + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20246: + case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20277: + goto good; + } + /* Others, check PCI class */ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + good: + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); + if ((progif & 5) != 5) { + printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev)); + (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || + (progif & 5) != 5) + printk(KERN_ERR "Rewrite of PROGIF failed !\n"); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); +#endif + +/* + * Disable second function on K2-SATA, it's broken + * and disable IO BARs on first one + */ +static void fixup_k2_sata(struct pci_dev* dev) +{ + int i; + u16 cmd; + + if (PCI_FUNC(dev->devfn) > 0) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 6; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } else { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 5; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); + diff --git a/arch/powerpc/platforms/powermac/pmac_pic.c b/arch/powerpc/platforms/powermac/pmac_pic.c new file mode 100644 index 000000000000..bf3e1899a4cc --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_pic.c @@ -0,0 +1,655 @@ +/* + * Support for the interrupt controllers found on Power Macintosh, + * currently Apple's "Grand Central" interrupt controller in all + * it's incarnations. OpenPIC support used on newer machines is + * in a separate file + * + * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) + * + * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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 "pmac_pic.h" + +/* + * XXX this should be in xmon.h, but putting it there means xmon.h + * has to include (to get irqreturn_t), which + * causes all sorts of problems. -- paulus + */ +extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); + +struct pmac_irq_hw { + unsigned int event; + unsigned int enable; + unsigned int ack; + unsigned int level; +}; + +/* Default addresses */ +static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { + (struct pmac_irq_hw *) 0xf3000020, + (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, +}; + +#define GC_LEVEL_MASK 0x3ff00000 +#define OHARE_LEVEL_MASK 0x1ff00000 +#define HEATHROW_LEVEL_MASK 0x1ff00000 + +static int max_irqs; +static int max_real_irqs; +static u32 level_mask[4]; + +static DEFINE_SPINLOCK(pmac_pic_lock); + + +#define GATWICK_IRQ_POOL_SIZE 10 +static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; + +/* + * Mark an irq as "lost". This is only used on the pmac + * since it can lose interrupts (see pmac_set_irq_mask). + * -- Cort + */ +void +__set_lost(unsigned long irq_nr, int nokick) +{ + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { + atomic_inc(&ppc_n_lost_interrupts); + if (!nokick) + set_dec(1); + } +} + +static void +pmac_mask_and_ack_irq(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + unsigned long flags; + + if ((unsigned)irq_nr >= max_irqs) + return; + + clear_bit(irq_nr, ppc_cached_irq_mask); + if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) + atomic_dec(&ppc_n_lost_interrupts); + spin_lock_irqsave(&pmac_pic_lock, flags); + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + out_le32(&pmac_irq_hw[i]->ack, bit); + do { + /* make sure ack gets to controller before we enable + interrupts */ + mb(); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); + spin_unlock_irqrestore(&pmac_pic_lock, flags); +} + +static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + unsigned long flags; + + if ((unsigned)irq_nr >= max_irqs) + return; + + spin_lock_irqsave(&pmac_pic_lock, flags); + /* enable unmasked interrupts */ + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + + do { + /* make sure mask gets to controller before we + return to user */ + mb(); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); + + /* + * Unfortunately, setting the bit in the enable register + * when the device interrupt is already on *doesn't* set + * the bit in the flag register or request another interrupt. + */ + if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) + __set_lost((ulong)irq_nr, nokicklost); + spin_unlock_irqrestore(&pmac_pic_lock, flags); +} + +/* When an irq gets requested for the first client, if it's an + * edge interrupt, we clear any previous one on the controller + */ +static unsigned int pmac_startup_irq(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + + if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) + out_le32(&pmac_irq_hw[i]->ack, bit); + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); + + return 0; +} + +static void pmac_mask_irq(unsigned int irq_nr) +{ + clear_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); + mb(); +} + +static void pmac_unmask_irq(unsigned int irq_nr) +{ + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); +} + +static void pmac_end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) + && irq_desc[irq_nr].action) { + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 1); + } +} + + +struct hw_interrupt_type pmac_pic = { + .typename = " PMAC-PIC ", + .startup = pmac_startup_irq, + .enable = pmac_unmask_irq, + .disable = pmac_mask_irq, + .ack = pmac_mask_and_ack_irq, + .end = pmac_end_irq, +}; + +struct hw_interrupt_type gatwick_pic = { + .typename = " GATWICK ", + .startup = pmac_startup_irq, + .enable = pmac_unmask_irq, + .disable = pmac_mask_irq, + .ack = pmac_mask_and_ack_irq, + .end = pmac_end_irq, +}; + +static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int irq, bits; + + for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { + int i = irq >> 5; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; + if (bits == 0) + continue; + irq += __ilog2(bits); + __do_IRQ(irq, regs); + return IRQ_HANDLED; + } + printk("gatwick irq not from gatwick pic\n"); + return IRQ_NONE; +} + +int +pmac_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits = 0; + +#ifdef CONFIG_SMP + void psurge_smp_message_recv(struct pt_regs *); + + /* IPI's are a hack on the powersurge -- Cort */ + if ( smp_processor_id() != 0 ) { + psurge_smp_message_recv(regs); + return -2; /* ignore, already handled */ + } +#endif /* CONFIG_SMP */ + for (irq = max_real_irqs; (irq -= 32) >= 0; ) { + int i = irq >> 5; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; + if (bits == 0) + continue; + irq += __ilog2(bits); + break; + } + + return irq; +} + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +static void __init +pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + int count; + + memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); + node = gw->child; + count = 0; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child) { + if (node->child->n_intrs < 3) { + node->child->intrs = &gatwick_int_pool[count]; + count += 3; + } + node->child->n_intrs = 3; + node->child->intrs[0].line = 15+irq_base; + node->child->intrs[1].line = 4+irq_base; + node->child->intrs[2].line = 5+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", + node->child->intrs[0].line, + node->child->intrs[1].line, + node->child->intrs[2].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) { + struct device_node* ya_node; + + if (node->n_intrs == 0) + node->intrs = &gatwick_int_pool[count++]; + node->n_intrs = 1; + node->intrs[0].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + node->intrs[0].line); + + ya_node = node->child; + while(ya_node) + { + if (strcasecmp(ya_node->name, "floppy") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 19+irq_base; + ya_node->intrs[1].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + if (strcasecmp(ya_node->name, "ata4") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 14+irq_base; + ya_node->intrs[1].line = 3+irq_base; + printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + if (count > 10) { + printk("WARNING !! Gatwick interrupt pool overflow\n"); + printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); + printk(" requested = %d\n", count); + } +} + +/* + * The PowerBook 3400/2400/3500 can have a combo ethernet/modem + * card which includes an ohare chip that acts as a second interrupt + * controller. If we find this second ohare, set it up and fix the + * interrupt value in the device tree for the ethernet chip. + */ +static int __init enable_second_ohare(void) +{ + unsigned char bus, devfn; + unsigned short cmd; + unsigned long addr; + struct device_node *irqctrler = find_devices("pci106b,7"); + struct device_node *ether; + + if (irqctrler == NULL || irqctrler->n_addrs <= 0) + return -1; + addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); + pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); + max_irqs = 64; + if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) { + struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler); + if (!hose) + printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); + else { + early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + cmd &= ~PCI_COMMAND_IO; + early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); + } + } + + /* Fix interrupt for the modem/ethernet combo controller. The number + in the device tree (27) is bogus (correct for the ethernet-only + board but not the combo ethernet/modem board). + The real interrupt is 28 on the second controller -> 28+32 = 60. + */ + ether = find_devices("pci1011,14"); + if (ether && ether->n_intrs > 0) { + ether->intrs[0].line = 60; + printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", + ether->intrs[0].line); + } + + /* Return the interrupt number of the cascade */ + return irqctrler->intrs[0].line; +} + +static int pmac_u3_cascade(struct pt_regs *regs, void *data) +{ + return mpic_get_one_irq((struct mpic *)data, regs); +} + +#ifdef CONFIG_XMON +static struct irqaction xmon_action = { + .handler = xmon_irq, + .flags = 0, + .mask = CPU_MASK_NONE, + .name = "NMI - XMON" +}; +#endif + +static struct irqaction gatwick_cascade_action = { + .handler = gatwick_action, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + +void __init pmac_pic_init(void) +{ + int i; + struct device_node *irqctrler = NULL; + struct device_node *irqctrler2 = NULL; + struct device_node *np; + unsigned long addr; + int irq_cascade = -1; + struct mpic *mpic1, *mpic2; + + /* We first try to detect Apple's new Core99 chipset, since mac-io + * is quite different on those machines and contains an IBM MPIC2. + */ + np = find_type_devices("open-pic"); + while (np) { + if (np->parent && !strcmp(np->parent->name, "u3")) + irqctrler2 = np; + else + irqctrler = np; + np = np->next; + } + if (irqctrler != NULL && irqctrler->n_addrs > 0) { + unsigned char senses[128]; + + printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", + (unsigned int)irqctrler->addrs[0].address); + + prom_get_irq_senses(senses, 0, 128); + mpic1 = mpic_alloc(irqctrler->addrs[0].address, + MPIC_PRIMARY | MPIC_WANTS_RESET, + 0, 0, 128, 256, senses, 128, " K2-MPIC "); + BUG_ON(mpic1 == NULL); + mpic_init(mpic1); + + if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && + irqctrler2->n_addrs > 0) { + printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", + (u32)irqctrler2->addrs[0].address, + irqctrler2->intrs[0].line); + + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); + prom_get_irq_senses(senses, 128, 128 + 128); + + /* We don't need to set MPIC_BROKEN_U3 here since we don't have + * hypertransport interrupts routed to it + */ + mpic2 = mpic_alloc(irqctrler2->addrs[0].address, + MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, + 0, 128, 128, 0, senses, 128, " U3-MPIC "); + BUG_ON(mpic2 == NULL); + mpic_init(mpic2); + mpic_setup_cascade(irqctrler2->intrs[0].line, + pmac_u3_cascade, mpic2); + } + } + + /* Get the level/edge settings, assume if it's not + * a Grand Central nor an OHare, then it's an Heathrow + * (or Paddington). + */ + if (find_devices("gc")) + level_mask[0] = GC_LEVEL_MASK; + else if (find_devices("ohare")) { + level_mask[0] = OHARE_LEVEL_MASK; + /* We might have a second cascaded ohare */ + level_mask[1] = OHARE_LEVEL_MASK; + } else { + level_mask[0] = HEATHROW_LEVEL_MASK; + level_mask[1] = 0; + /* We might have a second cascaded heathrow */ + level_mask[2] = HEATHROW_LEVEL_MASK; + level_mask[3] = 0; + } + + /* + * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, + * 1998 G3 Series PowerBooks have 128, + * other powermacs have 32. + * The combo ethernet/modem card for the Powerstar powerbooks + * (2400/3400/3500, ohare based) has a second ohare chip + * effectively making a total of 64. + */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + for ( i = 0; i < max_real_irqs ; i++ ) + irq_desc[i].handler = &pmac_pic; + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = irqctrler->next; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + irq_cascade = irqctrler->intrs[0].line; + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + } + } else { + /* older powermacs have a GC (grand central) or ohare at + f3000000, with interrupt control registers at f3000020. */ + addr = (unsigned long) ioremap(0xf3000000, 0x40); + pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); + } + + /* PowerBooks 3400 and 3500 can have a second controller in a second + ohare chip, on the combo ethernet/modem card */ + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) + irq_cascade = enable_second_ohare(); + + /* disable all interrupts in all controllers */ + for (i = 0; i * 32 < max_irqs; ++i) + out_le32(&pmac_irq_hw[i]->enable, 0); + /* mark level interrupts */ + for (i = 0; i < max_irqs; i++) + if (level_mask[i >> 5] & (1UL << (i & 0x1f))) + irq_desc[i].status = IRQ_LEVEL; + + /* get interrupt line of secondary interrupt controller */ + if (irq_cascade >= 0) { + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)irq_cascade); + for ( i = max_real_irqs ; i < max_irqs ; i++ ) + irq_desc[i].handler = &gatwick_pic; + setup_irq(irq_cascade, &gatwick_cascade_action); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + +#ifdef CONFIG_XMON + setup_irq(20, &xmon_action); +#endif /* CONFIG_XMON */ +} + +#ifdef CONFIG_PM +/* + * These procedures are used in implementing sleep on the powerbooks. + * sleep_save_intrs() saves the states of all interrupt enables + * and disables all interrupts except for the nominated one. + * sleep_restore_intrs() restores the states of all interrupt enables. + */ +unsigned long sleep_save_mask[2]; + +/* This used to be passed by the PMU driver but that link got + * broken with the new driver model. We use this tweak for now... + */ +static int pmacpic_find_viaint(void) +{ + int viaint = -1; + +#ifdef CONFIG_ADB_PMU + struct device_node *np; + + if (pmu_get_model() != PMU_OHARE_BASED) + goto not_found; + np = of_find_node_by_name(NULL, "via-pmu"); + if (np == NULL) + goto not_found; + viaint = np->intrs[0].line; +#endif /* CONFIG_ADB_PMU */ + +not_found: + return viaint; +} + +static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state) +{ + int viaint = pmacpic_find_viaint(); + + sleep_save_mask[0] = ppc_cached_irq_mask[0]; + sleep_save_mask[1] = ppc_cached_irq_mask[1]; + ppc_cached_irq_mask[0] = 0; + ppc_cached_irq_mask[1] = 0; + if (viaint > 0) + set_bit(viaint, ppc_cached_irq_mask); + out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); + (void)in_le32(&pmac_irq_hw[0]->event); + /* make sure mask gets to controller before we return to caller */ + mb(); + (void)in_le32(&pmac_irq_hw[0]->enable); + + return 0; +} + +static int pmacpic_resume(struct sys_device *sysdev) +{ + int i; + + out_le32(&pmac_irq_hw[0]->enable, 0); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, 0); + mb(); + for (i = 0; i < max_real_irqs; ++i) + if (test_bit(i, sleep_save_mask)) + pmac_unmask_irq(i); + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct sysdev_class pmacpic_sysclass = { + set_kset_name("pmac_pic"), +}; + +static struct sys_device device_pmacpic = { + .id = 0, + .cls = &pmacpic_sysclass, +}; + +static struct sysdev_driver driver_pmacpic = { +#ifdef CONFIG_PM + .suspend = &pmacpic_suspend, + .resume = &pmacpic_resume, +#endif /* CONFIG_PM */ +}; + +static int __init init_pmacpic_sysfs(void) +{ + if (max_irqs == 0) + return -ENODEV; + + printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); + sysdev_class_register(&pmacpic_sysclass); + sysdev_register(&device_pmacpic); + sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); + return 0; +} + +subsys_initcall(init_pmacpic_sysfs); + diff --git a/arch/powerpc/platforms/powermac/pmac_pic.h b/arch/powerpc/platforms/powermac/pmac_pic.h new file mode 100644 index 000000000000..664103dfeef9 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_pic.h @@ -0,0 +1,11 @@ +#ifndef __PPC_PLATFORMS_PMAC_PIC_H +#define __PPC_PLATFORMS_PMAC_PIC_H + +#include + +extern struct hw_interrupt_type pmac_pic; + +void pmac_pic_init(void); +int pmac_get_irq(struct pt_regs *regs); + +#endif /* __PPC_PLATFORMS_PMAC_PIC_H */ diff --git a/arch/powerpc/platforms/powermac/pmac_setup.c b/arch/powerpc/platforms/powermac/pmac_setup.c new file mode 100644 index 000000000000..dbc921a084cd --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_setup.c @@ -0,0 +1,662 @@ +/* + * arch/ppc/platforms/setup.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * Derived from "arch/alpha/kernel/setup.c" + * Copyright (C) 1995 Linus Torvalds + * + * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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. + * + */ + +/* + * bootup setup stuff.. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmac_pic.h" + +#undef SHOW_GATWICK_IRQS + +extern long pmac_time_init(void); +extern unsigned long pmac_get_rtc_time(void); +extern int pmac_set_rtc_time(unsigned long nowtime); +extern void pmac_read_rtc_time(void); +extern void pmac_calibrate_decr(void); +extern void pmac_pcibios_fixup(void); +extern void pmac_find_bridges(void); +extern unsigned long pmac_ide_get_base(int index); +extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, + unsigned long data_port, unsigned long ctrl_port, int *irq); + +extern void pmac_nvram_update(void); +extern unsigned char pmac_nvram_read_byte(int addr); +extern void pmac_nvram_write_byte(int addr, unsigned char val); +extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +extern void pmac_pcibios_after_init(void); +extern int of_show_percpuinfo(struct seq_file *m, int i); + +unsigned char drive_info; + +int ppc_override_l2cr = 0; +int ppc_override_l2cr_value; +int has_l2cache = 0; + +static int current_root_goodness = -1; + +extern int pmac_newworld; + +#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ + +extern void zs_kgdb_hook(int tty_num); +static void ohare_init(void); +#ifdef CONFIG_BOOTX_TEXT +static void pmac_progress(char *s, unsigned short hex); +#endif + +sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; + +#ifdef CONFIG_SMP +extern struct smp_ops_t psurge_smp_ops; +extern struct smp_ops_t core99_smp_ops; +#endif /* CONFIG_SMP */ + +static int +pmac_show_cpuinfo(struct seq_file *m) +{ + struct device_node *np; + char *pp; + int plen; + int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); + unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_FLAGS, 0); + char* mbname; + + if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0) + mbname = "Unknown"; + + /* find motherboard type */ + seq_printf(m, "machine\t\t: "); + np = find_devices("device-tree"); + if (np != NULL) { + pp = (char *) get_property(np, "model", NULL); + if (pp != NULL) + seq_printf(m, "%s\n", pp); + else + seq_printf(m, "PowerMac\n"); + pp = (char *) get_property(np, "compatible", &plen); + if (pp != NULL) { + seq_printf(m, "motherboard\t:"); + while (plen > 0) { + int l = strlen(pp) + 1; + seq_printf(m, " %s", pp); + plen -= l; + pp += l; + } + seq_printf(m, "\n"); + } + } else + seq_printf(m, "PowerMac\n"); + + /* print parsed model */ + seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); + seq_printf(m, "pmac flags\t: %08x\n", mbflags); + + /* find l2 cache info */ + np = find_devices("l2-cache"); + if (np == 0) + np = find_type_devices("cache"); + if (np != 0) { + unsigned int *ic = (unsigned int *) + get_property(np, "i-cache-size", NULL); + unsigned int *dc = (unsigned int *) + get_property(np, "d-cache-size", NULL); + seq_printf(m, "L2 cache\t:"); + has_l2cache = 1; + if (get_property(np, "cache-unified", NULL) != 0 && dc) { + seq_printf(m, " %dK unified", *dc / 1024); + } else { + if (ic) + seq_printf(m, " %dK instruction", *ic / 1024); + if (dc) + seq_printf(m, "%s %dK data", + (ic? " +": ""), *dc / 1024); + } + pp = get_property(np, "ram-type", NULL); + if (pp) + seq_printf(m, " %s", pp); + seq_printf(m, "\n"); + } + + /* find ram info */ + np = find_devices("memory"); + if (np != 0) { + int n; + struct reg_property *reg = (struct reg_property *) + get_property(np, "reg", &n); + + if (reg != 0) { + unsigned long total = 0; + + for (n /= sizeof(struct reg_property); n > 0; --n) + total += (reg++)->size; + seq_printf(m, "memory\t\t: %luMB\n", total >> 20); + } + } + + /* Checks "l2cr-value" property in the registry */ + np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr); + } + } + + /* Indicate newworld/oldworld */ + seq_printf(m, "pmac-generation\t: %s\n", + pmac_newworld ? "NewWorld" : "OldWorld"); + + + return 0; +} + +static int +pmac_show_percpuinfo(struct seq_file *m, int i) +{ +#ifdef CONFIG_CPU_FREQ_PMAC + extern unsigned int pmac_get_one_cpufreq(int i); + unsigned int freq = pmac_get_one_cpufreq(i); + if (freq != 0) { + seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); + return 0; + } +#endif /* CONFIG_CPU_FREQ_PMAC */ + return of_show_percpuinfo(m, i); +} + +static volatile u32 *sysctrl_regs; + +void __init +pmac_setup_arch(void) +{ + struct device_node *cpu; + int *fp; + unsigned long pvr; + + pvr = PVR_VER(mfspr(SPRN_PVR)); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (int *) get_property(cpu, "clock-frequency", NULL); + if (fp != 0) { + if (pvr == 4 || pvr >= 8) + /* 604, G3, G4 etc. */ + loops_per_jiffy = *fp / HZ; + else + /* 601, 603, etc. */ + loops_per_jiffy = *fp / (2*HZ); + } else + loops_per_jiffy = 50000000 / HZ; + } + + /* this area has the CPU identification register + and some registers used by smp boards */ + sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); + ohare_init(); + + /* Lookup PCI hosts */ + pmac_find_bridges(); + + /* Checks "l2cr-value" property in the registry */ + if (cpu_has_feature(CPU_FTR_L2CR)) { + struct device_node *np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + ppc_override_l2cr = 1; + ppc_override_l2cr_value = *l2cr; + _set_L2CR(0); + _set_L2CR(ppc_override_l2cr_value); + } + } + } + + if (ppc_override_l2cr) + printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", + ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) + ? "enabled" : "disabled"); + +#ifdef CONFIG_KGDB + zs_kgdb_hook(0); +#endif + +#ifdef CONFIG_ADB_CUDA + find_via_cuda(); +#else + if (find_devices("via-cuda")) { + printk("WARNING ! Your machine is Cuda based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); + } +#endif +#ifdef CONFIG_ADB_PMU + find_via_pmu(); +#else + if (find_devices("via-pmu")) { + printk("WARNING ! Your machine is PMU based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); + } +#endif +#ifdef CONFIG_NVRAM + pmac_nvram_init(); +#endif +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = DEFAULT_ROOT_DEVICE; + +#ifdef CONFIG_SMP + /* Check for Core99 */ + if (find_devices("uni-n") || find_devices("u3")) + ppc_md.smp_ops = &core99_smp_ops; + else + ppc_md.smp_ops = &psurge_smp_ops; +#endif /* CONFIG_SMP */ + + pci_create_OF_bus_map(); +} + +static void __init ohare_init(void) +{ + /* + * Turn on the L2 cache. + * We assume that we have a PSX memory controller iff + * we have an ohare I/O controller. + */ + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + if(has_l2cache) + printk(KERN_INFO "Level 2 cache enabled\n"); + } + } +} + +extern char *bootpath; +extern char *bootdevice; +void *boot_host; +int boot_target; +int boot_part; +extern dev_t boot_dev; + +#ifdef CONFIG_SCSI +void __init +note_scsi_host(struct device_node *node, void *host) +{ + int l; + char *p; + + l = strlen(node->full_name); + if (bootpath != NULL && bootdevice != NULL + && strncmp(node->full_name, bootdevice, l) == 0 + && (bootdevice[l] == '/' || bootdevice[l] == 0)) { + boot_host = host; + /* + * There's a bug in OF 1.0.5. (Why am I not surprised.) + * If you pass a path like scsi/sd@1:0 to canon, it returns + * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 + * That is, the scsi target number doesn't get preserved. + * So we pick the target number out of bootpath and use that. + */ + p = strstr(bootpath, "/sd@"); + if (p != NULL) { + p += 4; + boot_target = simple_strtoul(p, NULL, 10); + p = strchr(p, ':'); + if (p != NULL) + boot_part = simple_strtoul(p + 1, NULL, 10); + } + } +} +#endif + +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) +static dev_t __init +find_ide_boot(void) +{ + char *p; + int n; + dev_t __init pmac_find_ide_boot(char *bootdevice, int n); + + if (bootdevice == NULL) + return 0; + p = strrchr(bootdevice, '/'); + if (p == NULL) + return 0; + n = p - bootdevice; + + return pmac_find_ide_boot(bootdevice, n); +} +#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ + +static void __init +find_boot_device(void) +{ +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) + boot_dev = find_ide_boot(); +#endif +} + +static int initializing = 1; +/* TODO: Merge the suspend-to-ram with the common code !!! + * currently, this is a stub implementation for suspend-to-disk + * only + */ + +#ifdef CONFIG_SOFTWARE_SUSPEND + +static int pmac_pm_prepare(suspend_state_t state) +{ + printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); + + return 0; +} + +static int pmac_pm_enter(suspend_state_t state) +{ + printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); + + /* Giveup the lazy FPU & vec so we don't have to back them + * up from the low level code + */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + return 0; +} + +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); + + return 0; +} + +static struct pm_ops pmac_pm_ops = { + .pm_disk_mode = PM_DISK_SHUTDOWN, + .prepare = pmac_pm_prepare, + .enter = pmac_pm_enter, + .finish = pmac_pm_finish, +}; + +#endif /* CONFIG_SOFTWARE_SUSPEND */ + +static int pmac_late_init(void) +{ + initializing = 0; +#ifdef CONFIG_SOFTWARE_SUSPEND + pm_set_ops(&pmac_pm_ops); +#endif /* CONFIG_SOFTWARE_SUSPEND */ + return 0; +} + +late_initcall(pmac_late_init); + +/* can't be __init - can be called whenever a disk is first accessed */ +void +note_bootable_part(dev_t dev, int part, int goodness) +{ + static int found_boot = 0; + char *p; + + if (!initializing) + return; + if ((goodness <= current_root_goodness) && + ROOT_DEV != DEFAULT_ROOT_DEVICE) + return; + p = strstr(saved_command_line, "root="); + if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + return; + + if (!found_boot) { + find_boot_device(); + found_boot = 1; + } + if (!boot_dev || dev == boot_dev) { + ROOT_DEV = dev + part; + boot_dev = 0; + current_root_goodness = goodness; + } +} + +static void +pmac_restart(char *cmd) +{ +#ifdef CONFIG_ADB_CUDA + struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_RESET_SYSTEM); + for (;;) + cuda_poll(); + break; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + pmu_restart(); + break; +#endif /* CONFIG_ADB_PMU */ + default: ; + } +} + +static void +pmac_power_off(void) +{ +#ifdef CONFIG_ADB_CUDA + struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_POWERDOWN); + for (;;) + cuda_poll(); + break; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + pmu_shutdown(); + break; +#endif /* CONFIG_ADB_PMU */ + default: ; + } +} + +static void +pmac_halt(void) +{ + pmac_power_off(); +} + +void __init +pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* isa_io_base gets set in pmac_find_bridges */ + isa_mem_base = PMAC_ISA_MEM_BASE; + pci_dram_offset = PMAC_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 1; + DMA_MODE_WRITE = 2; + + ppc_md.setup_arch = pmac_setup_arch; + ppc_md.show_cpuinfo = pmac_show_cpuinfo; + ppc_md.show_percpuinfo = pmac_show_percpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = pmac_pic_init; + ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ + + ppc_md.pcibios_fixup = pmac_pcibios_fixup; + ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; + ppc_md.pcibios_after_init = pmac_pcibios_after_init; + ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; + + ppc_md.restart = pmac_restart; + ppc_md.power_off = pmac_power_off; + ppc_md.halt = pmac_halt; + + ppc_md.time_init = pmac_time_init; + ppc_md.set_rtc_time = pmac_set_rtc_time; + ppc_md.get_rtc_time = pmac_get_rtc_time; + ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.feature_call = pmac_do_feature_call; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#ifdef CONFIG_BLK_DEV_IDE_PMAC + ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; + ppc_ide_md.default_io_base = pmac_ide_get_base; +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ + +#ifdef CONFIG_BOOTX_TEXT + ppc_md.progress = pmac_progress; +#endif /* CONFIG_BOOTX_TEXT */ + + if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); + +} + +#ifdef CONFIG_BOOTX_TEXT +static void __init +pmac_progress(char *s, unsigned short hex) +{ + if (boot_text_mapped) { + btext_drawstring(s); + btext_drawchar('\n'); + } +} +#endif /* CONFIG_BOOTX_TEXT */ + +static int __init +pmac_declare_of_platform_devices(void) +{ + struct device_node *np; + + np = find_devices("uni-n"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "uni-n-i2c", + NULL); + break; + } + } + np = find_devices("u3"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "u3-i2c", + NULL); + break; + } + } + + np = find_devices("valkyrie"); + if (np) + of_platform_device_create(np, "valkyrie", NULL); + np = find_devices("platinum"); + if (np) + of_platform_device_create(np, "platinum", NULL); + + return 0; +} + +device_initcall(pmac_declare_of_platform_devices); diff --git a/arch/powerpc/platforms/powermac/pmac_sleep.S b/arch/powerpc/platforms/powermac/pmac_sleep.S new file mode 100644 index 000000000000..88419c77ac43 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_sleep.S @@ -0,0 +1,396 @@ +/* + * This file contains sleep low-level functions for PowerBook G3. + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * and Paul Mackerras (paulus@samba.org). + * + * 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 + +#define MAGIC 0x4c617273 /* 'Lars' */ + +/* + * Structure for storing CPU registers on the stack. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_SDR1 0xc +#define SL_SPRG0 0x10 /* 4 sprg's */ +#define SL_DBAT0 0x20 +#define SL_IBAT0 0x28 +#define SL_DBAT1 0x30 +#define SL_IBAT1 0x38 +#define SL_DBAT2 0x40 +#define SL_IBAT2 0x48 +#define SL_DBAT3 0x50 +#define SL_IBAT3 0x58 +#define SL_TB 0x60 +#define SL_R2 0x68 +#define SL_CR 0x6c +#define SL_R12 0x70 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + + .section .text + .align 5 + +#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) + +/* This gets called by via-pmu.c late during the sleep process. + * The PMU was already send the sleep command and will shut us down + * soon. We need to save all that is needed and setup the wakeup + * vector that will be called by the ROM on wakeup + */ +_GLOBAL(low_sleep_handler) +#ifndef CONFIG_6xx + blr +#else + mflr r0 + stw r0,4(r1) + stwu r1,-SL_SIZE(r1) + mfcr r0 + stw r0,SL_CR(r1) + stw r2,SL_R2(r1) + stmw r12,SL_R12(r1) + + /* Save MSR & SDR1 */ + mfmsr r4 + stw r4,SL_MSR(r1) + mfsdr1 r4 + stw r4,SL_SDR1(r1) + + /* Get a stable timebase and save it */ +1: mftbu r4 + stw r4,SL_TB(r1) + mftb r5 + stw r5,SL_TB+4(r1) + mftbu r3 + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r1) + mfsprg r4,1 + stw r4,SL_SPRG0+4(r1) + mfsprg r4,2 + stw r4,SL_SPRG0+8(r1) + mfsprg r4,3 + stw r4,SL_SPRG0+12(r1) + + /* Save BATs */ + mfdbatu r4,0 + stw r4,SL_DBAT0(r1) + mfdbatl r4,0 + stw r4,SL_DBAT0+4(r1) + mfdbatu r4,1 + stw r4,SL_DBAT1(r1) + mfdbatl r4,1 + stw r4,SL_DBAT1+4(r1) + mfdbatu r4,2 + stw r4,SL_DBAT2(r1) + mfdbatl r4,2 + stw r4,SL_DBAT2+4(r1) + mfdbatu r4,3 + stw r4,SL_DBAT3(r1) + mfdbatl r4,3 + stw r4,SL_DBAT3+4(r1) + mfibatu r4,0 + stw r4,SL_IBAT0(r1) + mfibatl r4,0 + stw r4,SL_IBAT0+4(r1) + mfibatu r4,1 + stw r4,SL_IBAT1(r1) + mfibatl r4,1 + stw r4,SL_IBAT1+4(r1) + mfibatu r4,2 + stw r4,SL_IBAT2(r1) + mfibatl r4,2 + stw r4,SL_IBAT2+4(r1) + mfibatu r4,3 + stw r4,SL_IBAT3(r1) + mfibatl r4,3 + stw r4,SL_IBAT3+4(r1) + + /* Backup various CPU config stuffs */ + bl __save_cpu_setup + + /* The ROM can wake us up via 2 different vectors: + * - On wallstreet & lombard, we must write a magic + * value 'Lars' at address 4 and a pointer to a + * memory location containing the PC to resume from + * at address 0. + * - On Core99, we must store the wakeup vector at + * address 0x80 and eventually it's parameters + * at address 0x84. I've have some trouble with those + * parameters however and I no longer use them. + */ + lis r5,grackle_wake_up@ha + addi r5,r5,grackle_wake_up@l + tophys(r5,r5) + stw r5,SL_PC(r1) + lis r4,KERNELBASE@h + tophys(r5,r1) + addi r5,r5,SL_PC + lis r6,MAGIC@ha + addi r6,r6,MAGIC@l + stw r5,0(r4) + stw r6,4(r4) + /* Setup stuffs at 0x80-0x84 for Core99 */ + lis r3,core99_wake_up@ha + addi r3,r3,core99_wake_up@l + tophys(r3,r3) + stw r3,0x80(r4) + stw r5,0x84(r4) + /* Store a pointer to our backup storage into + * a kernel global + */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + stw r5,0(r3) + + .globl low_cpu_die +low_cpu_die: + /* Flush & disable all caches */ + bl flush_disable_caches + + /* Turn off data relocation. */ + mfmsr r3 /* Save MSR in r7 */ + rlwinm r3,r3,0,28,26 /* Turn off DR bit */ + sync + mtmsr r3 + isync + +BEGIN_FTR_SECTION + /* Flush any pending L2 data prefetches to work around HW bug */ + sync + lis r3,0xfff0 + lwz r0,0(r3) /* perform cache-inhibited load to ROM */ + sync /* (caches are disabled at this point) */ +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) + +/* + * Set the HID0 and MSR for sleep. + */ + mfspr r2,SPRN_HID0 + rlwinm r2,r2,0,10,7 /* clear doze, nap */ + oris r2,r2,HID0_SLEEP@h + sync + isync + mtspr SPRN_HID0,r2 + sync + +/* This loop puts us back to sleep in case we have a spurrious + * wakeup so that the host bridge properly stays asleep. The + * CPU will be turned off, either after a known time (about 1 + * second) on wallstreet & lombard, or as soon as the CPU enters + * SLEEP mode on core99 + */ + mfmsr r2 + oris r2,r2,MSR_POW@h +1: sync + mtmsr r2 + isync + b 1b + +/* + * Here is the resume code. + */ + + +/* + * Core99 machines resume here + * r4 has the physical address of SL_PC(sp) (unused) + */ +_GLOBAL(core99_wake_up) + /* Make sure HID0 no longer contains any sleep bit and that data cache + * is disabled + */ + mfspr r3,SPRN_HID0 + rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ + rlwinm 3,r3,0,18,15 /* clear DCE, ICE */ + mtspr SPRN_HID0,r3 + sync + isync + + /* sanitize MSR */ + mfmsr r3 + ori r3,r3,MSR_EE|MSR_IP + xori r3,r3,MSR_EE|MSR_IP + sync + isync + mtmsr r3 + sync + isync + + /* Recover sleep storage */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + tophys(r3,r3) + lwz r1,0(r3) + + /* Pass thru to older resume code ... */ +/* + * Here is the resume code for older machines. + * r1 has the physical address of SL_PC(sp). + */ + +grackle_wake_up: + + /* Restore the kernel's segment registers before + * we do any r1 memory access as we are not sure they + * are in a sane state above the first 256Mb region + */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + sync + isync + + subi r1,r1,SL_PC + + /* Restore various CPU config stuffs */ + bl __restore_cpu_setup + + /* Make sure all FPRs have been initialized */ + bl reloc_offset + bl __init_fpu_registers + + /* Invalidate & enable L1 cache, we don't care about + * whatever the ROM may have tried to write to memory + */ + bl __inval_enable_L1 + + /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ + lwz r4,SL_SDR1(r1) + mtsdr1 r4 + lwz r4,SL_SPRG0(r1) + mtsprg 0,r4 + lwz r4,SL_SPRG0+4(r1) + mtsprg 1,r4 + lwz r4,SL_SPRG0+8(r1) + mtsprg 2,r4 + lwz r4,SL_SPRG0+12(r1) + mtsprg 3,r4 + + lwz r4,SL_DBAT0(r1) + mtdbatu 0,r4 + lwz r4,SL_DBAT0+4(r1) + mtdbatl 0,r4 + lwz r4,SL_DBAT1(r1) + mtdbatu 1,r4 + lwz r4,SL_DBAT1+4(r1) + mtdbatl 1,r4 + lwz r4,SL_DBAT2(r1) + mtdbatu 2,r4 + lwz r4,SL_DBAT2+4(r1) + mtdbatl 2,r4 + lwz r4,SL_DBAT3(r1) + mtdbatu 3,r4 + lwz r4,SL_DBAT3+4(r1) + mtdbatl 3,r4 + lwz r4,SL_IBAT0(r1) + mtibatu 0,r4 + lwz r4,SL_IBAT0+4(r1) + mtibatl 0,r4 + lwz r4,SL_IBAT1(r1) + mtibatu 1,r4 + lwz r4,SL_IBAT1+4(r1) + mtibatl 1,r4 + lwz r4,SL_IBAT2(r1) + mtibatu 2,r4 + lwz r4,SL_IBAT2+4(r1) + mtibatl 2,r4 + lwz r4,SL_IBAT3(r1) + mtibatu 3,r4 + lwz r4,SL_IBAT3+4(r1) + mtibatl 3,r4 + +BEGIN_FTR_SECTION + li r4,0 + mtspr SPRN_DBAT4U,r4 + mtspr SPRN_DBAT4L,r4 + mtspr SPRN_DBAT5U,r4 + mtspr SPRN_DBAT5L,r4 + mtspr SPRN_DBAT6U,r4 + mtspr SPRN_DBAT6L,r4 + mtspr SPRN_DBAT7U,r4 + mtspr SPRN_DBAT7L,r4 + mtspr SPRN_IBAT4U,r4 + mtspr SPRN_IBAT4L,r4 + mtspr SPRN_IBAT5U,r4 + mtspr SPRN_IBAT5L,r4 + mtspr SPRN_IBAT6U,r4 + mtspr SPRN_IBAT6L,r4 + mtspr SPRN_IBAT7U,r4 + mtspr SPRN_IBAT7L,r4 +END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) + + /* Flush all TLBs */ + lis r4,0x1000 +1: addic. r4,r4,-0x1000 + tlbie r4 + blt 1b + sync + + /* restore the MSR and turn on the MMU */ + lwz r3,SL_MSR(r1) + bl turn_on_mmu + + /* get back the stack pointer */ + tovirt(r1,r1) + + /* Restore TB */ + li r3,0 + mttbl r3 + lwz r3,SL_TB(r1) + lwz r4,SL_TB+4(r1) + mttbu r3 + mttbl r4 + + /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r1) + mtcr r0 + lwz r2,SL_R2(r1) + lmw r12,SL_R12(r1) + addi r1,r1,SL_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +turn_on_mmu: + mflr r4 + tovirt(r4,r4) + mtsrr0 r4 + mtsrr1 r3 + sync + isync + rfi + +#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */ + + .section .data + .balign L1_CACHE_LINE_SIZE +sleep_storage: + .long 0 + .balign L1_CACHE_LINE_SIZE, 0 + +#endif /* CONFIG_6xx */ + .section .text diff --git a/arch/powerpc/platforms/powermac/pmac_smp.c b/arch/powerpc/platforms/powermac/pmac_smp.c new file mode 100644 index 000000000000..995e9095d865 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_smp.c @@ -0,0 +1,716 @@ +/* + * SMP support for power macintosh. + * + * We support both the old "powersurge" SMP architecture + * and the current Core99 (G4 PowerMac) machines. + * + * Note that we don't support the very first rev. of + * Apple/DayStar 2 CPUs board, the one with the funky + * watchdog. Hopefully, none of these should be there except + * maybe internally to Apple. I should probably still add some + * code to detect this card though and disable SMP. --BenH. + * + * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) + * and Ben Herrenschmidt . + * + * Support for DayStar quad CPU cards + * Copyright (C) XLR8, Inc. 1994-2000 + * + * 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 + +/* + * Powersurge (old powermac SMP) support. + */ + +extern void __secondary_start_pmac_0(void); + +/* Addresses for powersurge registers */ +#define HAMMERHEAD_BASE 0xf8000000 +#define HHEAD_CONFIG 0x90 +#define HHEAD_SEC_INTR 0xc0 + +/* register for interrupting the primary processor on the powersurge */ +/* N.B. this is actually the ethernet ROM! */ +#define PSURGE_PRI_INTR 0xf3019000 + +/* register for storing the start address for the secondary processor */ +/* N.B. this is the PCI config space address register for the 1st bridge */ +#define PSURGE_START 0xf2800000 + +/* Daystar/XLR8 4-CPU card */ +#define PSURGE_QUAD_REG_ADDR 0xf8800000 + +#define PSURGE_QUAD_IRQ_SET 0 +#define PSURGE_QUAD_IRQ_CLR 1 +#define PSURGE_QUAD_IRQ_PRIMARY 2 +#define PSURGE_QUAD_CKSTOP_CTL 3 +#define PSURGE_QUAD_PRIMARY_ARB 4 +#define PSURGE_QUAD_BOARD_ID 6 +#define PSURGE_QUAD_WHICH_CPU 7 +#define PSURGE_QUAD_CKSTOP_RDBK 8 +#define PSURGE_QUAD_RESET_CTL 11 + +#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v))) +#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f) +#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v))) +#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v))) + +/* virtual addresses for the above */ +static volatile u8 __iomem *hhead_base; +static volatile u8 __iomem *quad_base; +static volatile u32 __iomem *psurge_pri_intr; +static volatile u8 __iomem *psurge_sec_intr; +static volatile u32 __iomem *psurge_start; + +/* values for psurge_type */ +#define PSURGE_NONE -1 +#define PSURGE_DUAL 0 +#define PSURGE_QUAD_OKEE 1 +#define PSURGE_QUAD_COTTON 2 +#define PSURGE_QUAD_ICEGRASS 3 + +/* what sort of powersurge board we have */ +static int psurge_type = PSURGE_NONE; + +/* L2 and L3 cache settings to pass from CPU0 to CPU1 */ +volatile static long int core99_l2_cache; +volatile static long int core99_l3_cache; + +/* Timebase freeze GPIO */ +static unsigned int core99_tb_gpio; + +/* Sync flag for HW tb sync */ +static volatile int sec_tb_reset = 0; +static unsigned int pri_tb_hi, pri_tb_lo; +static unsigned int pri_tb_stamp; + +static void __devinit core99_init_caches(int cpu) +{ + if (!cpu_has_feature(CPU_FTR_L2CR)) + return; + + if (cpu == 0) { + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); + } else { + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(0); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } + + if (!cpu_has_feature(CPU_FTR_L3CR)) + return; + + if (cpu == 0){ + core99_l3_cache = _get_L3CR(); + printk("CPU0: L3CR is %lx\n", core99_l3_cache); + } else { + printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); + _set_L3CR(0); + _set_L3CR(core99_l3_cache); + printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); + } +} + +/* + * Set and clear IPIs for powersurge. + */ +static inline void psurge_set_ipi(int cpu) +{ + if (psurge_type == PSURGE_NONE) + return; + if (cpu == 0) + in_be32(psurge_pri_intr); + else if (psurge_type == PSURGE_DUAL) + out_8(psurge_sec_intr, 0); + else + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu); +} + +static inline void psurge_clr_ipi(int cpu) +{ + if (cpu > 0) { + switch(psurge_type) { + case PSURGE_DUAL: + out_8(psurge_sec_intr, ~0); + case PSURGE_NONE: + break; + default: + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu); + } + } +} + +/* + * On powersurge (old SMP powermac architecture) we don't have + * separate IPIs for separate messages like openpic does. Instead + * we have a bitmap for each processor, where a 1 bit means that + * the corresponding message is pending for that processor. + * Ideally each cpu's entry would be in a different cache line. + * -- paulus. + */ +static unsigned long psurge_smp_message[NR_CPUS]; + +void psurge_smp_message_recv(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int msg; + + /* clear interrupt */ + psurge_clr_ipi(cpu); + + if (num_online_cpus() < 2) + return; + + /* make sure there is a message there */ + for (msg = 0; msg < 4; msg++) + if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) + smp_message_recv(msg, regs); +} + +irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs) +{ + psurge_smp_message_recv(regs); + return IRQ_HANDLED; +} + +static void smp_psurge_message_pass(int target, int msg, unsigned long data, + int wait) +{ + int i; + + if (num_online_cpus() < 2) + return; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (target == MSG_ALL + || (target == MSG_ALL_BUT_SELF && i != smp_processor_id()) + || target == i) { + set_bit(msg, &psurge_smp_message[i]); + psurge_set_ipi(i); + } + } +} + +/* + * Determine a quad card presence. We read the board ID register, we + * force the data bus to change to something else, and we read it again. + * It it's stable, then the register probably exist (ugh !) + */ +static int __init psurge_quad_probe(void) +{ + int type; + unsigned int i; + + type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID); + if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS + || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) + return PSURGE_DUAL; + + /* looks OK, try a slightly more rigorous test */ + /* bogus is not necessarily cacheline-aligned, + though I don't suppose that really matters. -- paulus */ + for (i = 0; i < 100; i++) { + volatile u32 bogus[8]; + bogus[(0+i)%8] = 0x00000000; + bogus[(1+i)%8] = 0x55555555; + bogus[(2+i)%8] = 0xFFFFFFFF; + bogus[(3+i)%8] = 0xAAAAAAAA; + bogus[(4+i)%8] = 0x33333333; + bogus[(5+i)%8] = 0xCCCCCCCC; + bogus[(6+i)%8] = 0xCCCCCCCC; + bogus[(7+i)%8] = 0x33333333; + wmb(); + asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory"); + mb(); + if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) + return PSURGE_DUAL; + } + return type; +} + +static void __init psurge_quad_init(void) +{ + int procbits; + + if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351); + procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU); + if (psurge_type == PSURGE_QUAD_ICEGRASS) + PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); + else + PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits); + mdelay(33); + out_8(psurge_sec_intr, ~0); + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits); + PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); + if (psurge_type != PSURGE_QUAD_ICEGRASS) + PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits); + PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits); + mdelay(33); + PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits); + mdelay(33); + PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits); + mdelay(33); +} + +static int __init smp_psurge_probe(void) +{ + int i, ncpus; + + /* We don't do SMP on the PPC601 -- paulus */ + if (PVR_VER(mfspr(SPRN_PVR)) == 1) + return 1; + + /* + * The powersurge cpu board can be used in the generation + * of powermacs that have a socket for an upgradeable cpu card, + * including the 7500, 8500, 9500, 9600. + * The device tree doesn't tell you if you have 2 cpus because + * OF doesn't know anything about the 2nd processor. + * Instead we look for magic bits in magic registers, + * in the hammerhead memory controller in the case of the + * dual-cpu powersurge board. -- paulus. + */ + if (find_devices("hammerhead") == NULL) + return 1; + + hhead_base = ioremap(HAMMERHEAD_BASE, 0x800); + quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024); + psurge_sec_intr = hhead_base + HHEAD_SEC_INTR; + + psurge_type = psurge_quad_probe(); + if (psurge_type != PSURGE_DUAL) { + psurge_quad_init(); + /* All released cards using this HW design have 4 CPUs */ + ncpus = 4; + } else { + iounmap(quad_base); + if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { + /* not a dual-cpu card */ + iounmap(hhead_base); + psurge_type = PSURGE_NONE; + return 1; + } + ncpus = 2; + } + + psurge_start = ioremap(PSURGE_START, 4); + psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); + + /* this is not actually strictly necessary -- paulus. */ + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; + + if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); + + return ncpus; +} + +static void __init smp_psurge_kick_cpu(int nr) +{ + unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; + unsigned long a; + + /* may need to flush here if secondary bats aren't setup */ + for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) + asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); + asm volatile("sync"); + + if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); + + out_be32(psurge_start, start); + mb(); + + psurge_set_ipi(nr); + udelay(10); + psurge_clr_ipi(nr); + + if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); +} + +/* + * With the dual-cpu powersurge board, the decrementers and timebases + * of both cpus are frozen after the secondary cpu is started up, + * until we give the secondary cpu another interrupt. This routine + * uses this to get the timebases synchronized. + * -- paulus. + */ +static void __init psurge_dual_sync_tb(int cpu_nr) +{ + int t; + + set_dec(tb_ticks_per_jiffy); + set_tb(0, 0); + last_jiffy_stamp(cpu_nr) = 0; + + if (cpu_nr > 0) { + mb(); + sec_tb_reset = 1; + return; + } + + /* wait for the secondary to have reset its TB before proceeding */ + for (t = 10000000; t > 0 && !sec_tb_reset; --t) + ; + + /* now interrupt the secondary, starting both TBs */ + psurge_set_ipi(1); + + smp_tb_synchronized = 1; +} + +static struct irqaction psurge_irqaction = { + .handler = psurge_primary_intr, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "primary IPI", +}; + +static void __init smp_psurge_setup_cpu(int cpu_nr) +{ + + if (cpu_nr == 0) { + /* If we failed to start the second CPU, we should still + * send it an IPI to start the timebase & DEC or we might + * have them stuck. + */ + if (num_online_cpus() < 2) { + if (psurge_type == PSURGE_DUAL) + psurge_set_ipi(1); + return; + } + /* reset the entry point so if we get another intr we won't + * try to startup again */ + out_be32(psurge_start, 0x100); + if (setup_irq(30, &psurge_irqaction)) + printk(KERN_ERR "Couldn't get primary IPI interrupt"); + } + + if (psurge_type == PSURGE_DUAL) + psurge_dual_sync_tb(cpu_nr); +} + +void __init smp_psurge_take_timebase(void) +{ + /* Dummy implementation */ +} + +void __init smp_psurge_give_timebase(void) +{ + /* Dummy implementation */ +} + +static int __init smp_core99_probe(void) +{ +#ifdef CONFIG_6xx + extern int powersave_nap; +#endif + struct device_node *cpus, *firstcpu; + int i, ncpus = 0, boot_cpu = -1; + u32 *tbprop = NULL; + + if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); + cpus = firstcpu = find_type_devices("cpu"); + while(cpus != NULL) { + u32 *regprop = (u32 *)get_property(cpus, "reg", NULL); + char *stateprop = (char *)get_property(cpus, "state", NULL); + if (regprop != NULL && stateprop != NULL && + !strncmp(stateprop, "running", 7)) + boot_cpu = *regprop; + ++ncpus; + cpus = cpus->next; + } + if (boot_cpu == -1) + printk(KERN_WARNING "Couldn't detect boot CPU !\n"); + if (boot_cpu != 0) + printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu); + + if (machine_is_compatible("MacRISC4")) { + extern struct smp_ops_t core99_smp_ops; + + core99_smp_ops.take_timebase = smp_generic_take_timebase; + core99_smp_ops.give_timebase = smp_generic_give_timebase; + } else { + if (firstcpu != NULL) + tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL); + if (tbprop) + core99_tb_gpio = *tbprop; + else + core99_tb_gpio = KL_GPIO_TB_ENABLE; + } + + if (ncpus > 1) { + mpic_request_ipis(); + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; +#ifdef CONFIG_6xx + powersave_nap = 0; +#endif + core99_init_caches(0); + } + + return ncpus; +} + +static void __devinit smp_core99_kick_cpu(int nr) +{ + unsigned long save_vector, new_vector; + unsigned long flags; + + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x100)); + if (nr < 0 || nr > 3) + return; + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); + + local_irq_save(flags); + local_irq_disable(); + + /* Save reset vector */ + save_vector = *vector; + + /* Setup fake reset vector that does + * b __secondary_start_pmac_0 + nr*8 - KERNELBASE + */ + new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; + *vector = 0x48000002 + new_vector - KERNELBASE; + + /* flush data cache and inval instruction cache */ + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + /* Put some life in our friend */ + pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); + + /* FIXME: We wait a bit for the CPU to take the exception, I should + * instead wait for the entry code to set something for me. Well, + * ideally, all that crap will be done in prom.c and the CPU left + * in a RAM-based wait loop like CHRP. + */ + mdelay(1); + + /* Restore our exception vector */ + *vector = save_vector; + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + local_irq_restore(flags); + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); +} + +static void __devinit smp_core99_setup_cpu(int cpu_nr) +{ + /* Setup L2/L3 */ + if (cpu_nr != 0) + core99_init_caches(cpu_nr); + + /* Setup openpic */ + mpic_setup_this_cpu(); + + if (cpu_nr == 0) { +#ifdef CONFIG_POWER4 + extern void g5_phy_disable_cpu1(void); + + /* If we didn't start the second CPU, we must take + * it off the bus + */ + if (machine_is_compatible("MacRISC4") && + num_online_cpus() < 2) + g5_phy_disable_cpu1(); +#endif /* CONFIG_POWER4 */ + if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); + } +} + +/* not __init, called in sleep/wakeup code */ +void smp_core99_take_timebase(void) +{ + unsigned long flags; + + /* tell the primary we're here */ + sec_tb_reset = 1; + mb(); + + /* wait for the primary to set pri_tb_hi/lo */ + while (sec_tb_reset < 2) + mb(); + + /* set our stuff the same as the primary */ + local_irq_save(flags); + set_dec(1); + set_tb(pri_tb_hi, pri_tb_lo); + last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; + mb(); + + /* tell the primary we're done */ + sec_tb_reset = 0; + mb(); + local_irq_restore(flags); +} + +/* not __init, called in sleep/wakeup code */ +void smp_core99_give_timebase(void) +{ + unsigned long flags; + unsigned int t; + + /* wait for the secondary to be in take_timebase */ + for (t = 100000; t > 0 && !sec_tb_reset; --t) + udelay(10); + if (!sec_tb_reset) { + printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); + return; + } + + /* freeze the timebase and read it */ + /* disable interrupts so the timebase is disabled for the + shortest possible time */ + local_irq_save(flags); + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + mb(); + pri_tb_hi = get_tbu(); + pri_tb_lo = get_tbl(); + pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); + mb(); + + /* tell the secondary we're ready */ + sec_tb_reset = 2; + mb(); + + /* wait for the secondary to have taken it */ + for (t = 100000; t > 0 && sec_tb_reset; --t) + udelay(10); + if (sec_tb_reset) + printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); + else + smp_tb_synchronized = 1; + + /* Now, restart the timebase by leaving the GPIO to an open collector */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + local_irq_restore(flags); +} + +void smp_core99_message_pass(int target, int msg, unsigned long data, int wait) +{ + cpumask_t mask = CPU_MASK_ALL; + /* make sure we're sending something that translates to an IPI */ + if (msg > 0x3) { + printk("SMP %d: smp_message_pass: unknown msg %d\n", + smp_processor_id(), msg); + return; + } + switch (target) { + case MSG_ALL: + mpic_send_ipi(msg, mask); + break; + case MSG_ALL_BUT_SELF: + cpu_clear(smp_processor_id(), mask); + mpic_send_ipi(msg, mask); + break; + default: + mpic_send_ipi(msg, cpumask_of_cpu(target)); + break; + } +} + + +/* PowerSurge-style Macs */ +struct smp_ops_t psurge_smp_ops = { + .message_pass = smp_psurge_message_pass, + .probe = smp_psurge_probe, + .kick_cpu = smp_psurge_kick_cpu, + .setup_cpu = smp_psurge_setup_cpu, + .give_timebase = smp_psurge_give_timebase, + .take_timebase = smp_psurge_take_timebase, +}; + +/* Core99 Macs (dual G4s) */ +struct smp_ops_t core99_smp_ops = { + .message_pass = smp_core99_message_pass, + .probe = smp_core99_probe, + .kick_cpu = smp_core99_kick_cpu, + .setup_cpu = smp_core99_setup_cpu, + .give_timebase = smp_core99_give_timebase, + .take_timebase = smp_core99_take_timebase, +}; + +#ifdef CONFIG_HOTPLUG_CPU + +int __cpu_disable(void) +{ + cpu_clear(smp_processor_id(), cpu_online_map); + + /* XXX reset cpu affinity here */ + openpic_set_priority(0xf); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + mb(); + udelay(20); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + return 0; +} + +extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */ +static int cpu_dead[NR_CPUS]; + +void cpu_die(void) +{ + local_irq_disable(); + cpu_dead[smp_processor_id()] = 1; + mb(); + low_cpu_die(); +} + +void __cpu_die(unsigned int cpu) +{ + int timeout; + + timeout = 1000; + while (!cpu_dead[cpu]) { + if (--timeout == 0) { + printk("CPU %u refused to die!\n", cpu); + break; + } + msleep(1); + } + cpu_callin_map[cpu] = 0; + cpu_dead[cpu] = 0; +} + +#endif diff --git a/arch/powerpc/platforms/powermac/pmac_time.c b/arch/powerpc/platforms/powermac/pmac_time.c new file mode 100644 index 000000000000..ff6adff36cb8 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_time.c @@ -0,0 +1,291 @@ +/* + * Support for periodic interrupts (100 per second) and for getting + * the current time from the RTC on Power Macintoshes. + * + * We use the decrementer register for our periodic interrupts. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Apparently the RTC stores seconds since 1 Jan 1904 */ +#define RTC_OFFSET 2082844800 + +/* + * Calibrate the decrementer frequency with the VIA timer 1. + */ +#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ + +/* VIA registers */ +#define RS 0x200 /* skip between registers */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define ACR (11*RS) /* Auxiliary control register */ +#define IFR (13*RS) /* Interrupt flag register */ + +/* Bits in ACR */ +#define T1MODE 0xc0 /* Timer 1 mode */ +#define T1MODE_CONT 0x40 /* continuous interrupts */ + +/* Bits in IFR and IER */ +#define T1_INT 0x40 /* Timer 1 interrupt */ + +extern struct timezone sys_tz; + +long __init +pmac_time_init(void) +{ +#ifdef CONFIG_NVRAM + s32 delta = 0; + int dst; + + delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; + delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; + delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); + if (delta & 0x00800000UL) + delta |= 0xFF000000UL; + dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); + printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, + dst ? "on" : "off"); + return delta; +#else + return 0; +#endif +} + +unsigned long +pmac_get_rtc_time(void) +{ +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) + struct adb_request req; + unsigned long now; +#endif + + /* Get the time from the RTC */ + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if (req.reply_len != 7) + printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", + req.reply_len); + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return now - RTC_OFFSET; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) + return 0; + while (!req.complete) + pmu_poll(); + if (req.reply_len != 4) + printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", + req.reply_len); + now = (req.reply[0] << 24) + (req.reply[1] << 16) + + (req.reply[2] << 8) + req.reply[3]; + return now - RTC_OFFSET; +#endif /* CONFIG_ADB_PMU */ + default: ; + } + return 0; +} + +int +pmac_set_rtc_time(unsigned long nowtime) +{ +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) + struct adb_request req; +#endif + + nowtime += RTC_OFFSET; + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, + nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if ((req.reply_len != 3) && (req.reply_len != 7)) + printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", + req.reply_len); + return 1; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + if (pmu_request(&req, NULL, 5, PMU_SET_RTC, + nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) + return 0; + while (!req.complete) + pmu_poll(); + if (req.reply_len != 0) + printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", + req.reply_len); + return 1; +#endif /* CONFIG_ADB_PMU */ + default: + return 0; + } +} + +/* + * Calibrate the decrementer register using VIA timer 1. + * This is used both on powermacs and CHRP machines. + */ +int __init +via_calibrate_decr(void) +{ + struct device_node *vias; + volatile unsigned char __iomem *via; + int count = VIA_TIMER_FREQ_6 / 100; + unsigned int dstart, dend; + + vias = find_devices("via-cuda"); + if (vias == 0) + vias = find_devices("via-pmu"); + if (vias == 0) + vias = find_devices("via"); + if (vias == 0 || vias->n_addrs == 0) + return 0; + via = ioremap(vias->addrs[0].address, vias->addrs[0].size); + + /* set timer 1 for continuous interrupts */ + out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); + /* set the counter to a small value */ + out_8(&via[T1CH], 2); + /* set the latch to `count' */ + out_8(&via[T1LL], count); + out_8(&via[T1LH], count >> 8); + /* wait until it hits 0 */ + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dstart = get_dec(); + /* clear the interrupt & wait until it hits 0 again */ + in_8(&via[T1CL]); + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dend = get_dec(); + + tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100)); + tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); + + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + tb_ticks_per_jiffy, dstart - dend); + + iounmap(via); + + return 1; +} + +#ifdef CONFIG_PM +/* + * Reset the time after a sleep. + */ +static int +time_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + static unsigned long time_diff; + unsigned long flags; + unsigned long seq; + + switch (when) { + case PBOOK_SLEEP_NOW: + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + time_diff = xtime.tv_sec - pmac_get_rtc_time(); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + break; + case PBOOK_WAKE: + write_seqlock_irqsave(&xtime_lock, flags); + xtime.tv_sec = pmac_get_rtc_time() + time_diff; + xtime.tv_nsec = 0; + last_rtc_update = xtime.tv_sec; + write_sequnlock_irqrestore(&xtime_lock, flags); + break; + } + return PBOOK_SLEEP_OK; +} + +static struct pmu_sleep_notifier time_sleep_notifier = { + time_sleep_notify, SLEEP_LEVEL_MISC, +}; +#endif /* CONFIG_PM */ + +/* + * Query the OF and get the decr frequency. + * This was taken from the pmac time_init() when merging the prep/pmac + * time functions. + */ +void __init +pmac_calibrate_decr(void) +{ + struct device_node *cpu; + unsigned int freq, *fp; + +#ifdef CONFIG_PM + pmu_register_sleep_notifier(&time_sleep_notifier); +#endif /* CONFIG_PM */ + + /* We assume MacRISC2 machines have correct device-tree + * calibration. That's better since the VIA itself seems + * to be slightly off. --BenH + */ + if (!machine_is_compatible("MacRISC2") && + !machine_is_compatible("MacRISC3") && + !machine_is_compatible("MacRISC4")) + if (via_calibrate_decr()) + return; + + /* Special case: QuickSilver G4s seem to have a badly calibrated + * timebase-frequency in OF, VIA is much better on these. We should + * probably implement calibration based on the KL timer on these + * machines anyway... -BenH + */ + if (machine_is_compatible("PowerMac3,5")) + if (via_calibrate_decr()) + return; + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + cpu = find_type_devices("cpu"); + if (cpu == 0) + panic("can't find cpu node in time_init"); + fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); + if (fp == 0) + panic("can't get cpu timebase frequency"); + freq = *fp; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} diff --git a/arch/powerpc/platforms/prep/Kconfig b/arch/powerpc/platforms/prep/Kconfig new file mode 100644 index 000000000000..673ac47a1626 --- /dev/null +++ b/arch/powerpc/platforms/prep/Kconfig @@ -0,0 +1,22 @@ + +config PREP_RESIDUAL + bool "Support for PReP Residual Data" + depends on PPC_PREP + help + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is + not present or incorrect, in which case it could lead to the machine + behaving incorrectly. If this happens, either disable PREP_RESIDUAL + or pass the 'noresidual' option to the kernel. + + If you are running a PReP system, say Y here, otherwise say N. + +config PROC_PREPRESIDUAL + bool "Support for reading of PReP Residual Data in /proc" + depends on PREP_RESIDUAL && PROC_FS + help + Enabling this option will create a /proc/residual file which allows + you to get at the residual data on PReP systems. You will need a tool + (lsresidual) to parse it. If you aren't on a PReP system, you don't + want this. diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig new file mode 100644 index 000000000000..7a3b6fc4d976 --- /dev/null +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -0,0 +1,47 @@ + +config PPC_SPLPAR + depends on PPC_PSERIES + bool "Support for shared-processor logical partitions" + default n + help + Enabling this option will make the kernel run more efficiently + on logically-partitioned pSeries systems which use shared + processors, that is, which share physical processors between + two or more partitions. + +config HMT + bool "Hardware multithreading" + depends on SMP && PPC_PSERIES && BROKEN + help + This option enables hardware multithreading on RS64 cpus. + pSeries systems p620 and p660 have such a cpu type. + +config EEH + bool "PCI Extended Error Handling (EEH)" if EMBEDDED + depends on PPC_PSERIES + default y if !EMBEDDED + +config PPC_RTAS + bool + depends on PPC_PSERIES || PPC_BPA + default y + +config RTAS_PROC + bool "Proc interface to RTAS" + depends on PPC_RTAS + default y + +config RTAS_FLASH + tristate "Firmware flash interface" + depends on PPC64 && RTAS_PROC + +config SCANLOG + tristate "Scanlog dump interface" + depends on RTAS_PROC && PPC_PSERIES + +config LPARCFG + tristate "LPAR Configuration Data" + depends on PPC_PSERIES || PPC_ISERIES + help + Provide system capacity information via human readable + = pairs through a /proc/ppc64/lparcfg interface. diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile new file mode 100644 index 000000000000..26bdcd9a2a43 --- /dev/null +++ b/arch/powerpc/sysdev/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MPIC) += mpic.o diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c new file mode 100644 index 000000000000..c660e7d7c643 --- /dev/null +++ b/arch/powerpc/sysdev/mpic.c @@ -0,0 +1,904 @@ +/* + * arch/powerpc/kernel/mpic.c + * + * Driver for interrupt controllers following the OpenPIC standard, the + * common implementation beeing IBM's MPIC. This driver also can deal + * with various broken implementations of this HW. + * + * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. + * + * 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. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif + +static struct mpic *mpics; +static struct mpic *mpic_primary; +static DEFINE_SPINLOCK(mpic_lock); + + +/* + * Register accessor functions + */ + + +static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, + unsigned int reg) +{ + if (be) + return in_be32(base + (reg >> 2)); + else + return in_le32(base + (reg >> 2)); +} + +static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, + unsigned int reg, u32 value) +{ + if (be) + out_be32(base + (reg >> 2), value); + else + out_le32(base + (reg >> 2), value); +} + +static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) +{ + unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; + unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); + + if (mpic->flags & MPIC_BROKEN_IPI) + be = !be; + return _mpic_read(be, mpic->gregs, offset); +} + +static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) +{ + unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); + + _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); +} + +static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) +{ + unsigned int cpu = 0; + + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + + return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); +} + +static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) +{ + unsigned int cpu = 0; + + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + + _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); +} + +static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) +{ + unsigned int isu = src_no >> mpic->isu_shift; + unsigned int idx = src_no & mpic->isu_mask; + + return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], + reg + (idx * MPIC_IRQ_STRIDE)); +} + +static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, + unsigned int reg, u32 value) +{ + unsigned int isu = src_no >> mpic->isu_shift; + unsigned int idx = src_no & mpic->isu_mask; + + _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], + reg + (idx * MPIC_IRQ_STRIDE), value); +} + +#define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) +#define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) +#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) +#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) +#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) +#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) +#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) +#define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) + + +/* + * Low level utility functions + */ + + + +/* Check if we have one of those nice broken MPICs with a flipped endian on + * reads from IPI registers + */ +static void __init mpic_test_broken_ipi(struct mpic *mpic) +{ + u32 r; + + mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK); + r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0); + + if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { + printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); + mpic->flags |= MPIC_BROKEN_IPI; + } +} + +#ifdef CONFIG_MPIC_BROKEN_U3 + +/* Test if an interrupt is sourced from HyperTransport (used on broken U3s) + * to force the edge setting on the MPIC and do the ack workaround. + */ +static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) +{ + if (source_no >= 128 || !mpic->fixups) + return 0; + return mpic->fixups[source_no].base != NULL; +} + +static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) +{ + struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; + u32 tmp; + + spin_lock(&mpic->fixup_lock); + writeb(0x11 + 2 * fixup->irq, fixup->base); + tmp = readl(fixup->base + 2); + writel(tmp | 0x80000000ul, fixup->base + 2); + /* config writes shouldn't be posted but let's be safe ... */ + (void)readl(fixup->base + 2); + spin_unlock(&mpic->fixup_lock); +} + + +static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) +{ + int i, irq; + u32 tmp; + + printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); + + for (i=0; i < 24; i++) { + writeb(0x10 + 2*i, devbase + 0xf2); + tmp = readl(devbase + 0xf4); + if ((tmp & 0x1) || !(tmp & 0x20)) + continue; + irq = (tmp >> 16) & 0xff; + mpic->fixups[irq].irq = i; + mpic->fixups[irq].base = devbase + 0xf2; + } +} + +static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase) +{ + int i, irq; + u32 tmp; + + printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); + + for (i=0; i < 4; i++) { + writeb(0x10 + 2*i, devbase + 0xba); + tmp = readl(devbase + 0xbc); + if ((tmp & 0x1) || !(tmp & 0x20)) + continue; + irq = (tmp >> 16) & 0xff; + mpic->fixups[irq].irq = i; + mpic->fixups[irq].base = devbase + 0xba; + } +} + +static void __init mpic_scan_ioapics(struct mpic *mpic) +{ + unsigned int devfn; + u8 __iomem *cfgspace; + + printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); + + /* Allocate fixups array */ + mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); + BUG_ON(mpic->fixups == NULL); + memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); + + /* Init spinlock */ + spin_lock_init(&mpic->fixup_lock); + + /* Map u3 config space. We assume all IO-APICs are on the primary bus + * and slot will never be above "0xf" so we only need to map 32k + */ + cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); + BUG_ON(cfgspace == NULL); + + /* Now we scan all slots. We do a very quick scan, we read the header type, + * vendor ID and device ID only, that's plenty enough + */ + for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { + u8 __iomem *devbase = cfgspace + (devfn << 8); + u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); + u32 l = readl(devbase + PCI_VENDOR_ID); + u16 vendor_id, device_id; + int multifunc = 0; + + DBG("devfn %x, l: %x\n", devfn, l); + + /* If no device, skip */ + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) + goto next; + + /* Check if it's a multifunction device (only really used + * to function 0 though + */ + multifunc = !!(hdr_type & 0x80); + vendor_id = l & 0xffff; + device_id = (l >> 16) & 0xffff; + + /* If a known device, go to fixup setup code */ + if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460) + mpic_amd8111_read_irq(mpic, devbase); + if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450) + mpic_amd8131_read_irq(mpic, devbase); + next: + /* next device, if function 0 */ + if ((PCI_FUNC(devfn) == 0) && !multifunc) + devfn += 7; + } +} + +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + +/* Find an mpic associated with a given linux interrupt */ +static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) +{ + struct mpic *mpic = mpics; + + while(mpic) { + /* search IPIs first since they may override the main interrupts */ + if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) { + if (is_ipi) + *is_ipi = 1; + return mpic; + } + if (irq >= mpic->irq_offset && + irq < (mpic->irq_offset + mpic->irq_count)) { + if (is_ipi) + *is_ipi = 0; + return mpic; + } + mpic = mpic -> next; + } + return NULL; +} + +/* Convert a cpu mask from logical to physical cpu numbers. */ +static inline u32 mpic_physmask(u32 cpumask) +{ + int i; + u32 mask = 0; + + for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) + mask |= (cpumask & 1) << get_hard_smp_processor_id(i); + return mask; +} + +#ifdef CONFIG_SMP +/* Get the mpic structure from the IPI number */ +static inline struct mpic * mpic_from_ipi(unsigned int ipi) +{ + return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi); +} +#endif + +/* Get the mpic structure from the irq number */ +static inline struct mpic * mpic_from_irq(unsigned int irq) +{ + return container_of(irq_desc[irq].handler, struct mpic, hc_irq); +} + +/* Send an EOI */ +static inline void mpic_eoi(struct mpic *mpic) +{ + mpic_cpu_write(MPIC_CPU_EOI, 0); + (void)mpic_cpu_read(MPIC_CPU_WHOAMI); +} + +#ifdef CONFIG_SMP +static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mpic *mpic = dev_id; + + smp_message_recv(irq - mpic->ipi_offset, regs); + return IRQ_HANDLED; +} +#endif /* CONFIG_SMP */ + +/* + * Linux descriptor level callbacks + */ + + +static void mpic_enable_irq(unsigned int irq) +{ + unsigned int loops = 100000; + struct mpic *mpic = mpic_from_irq(irq); + unsigned int src = irq - mpic->irq_offset; + + DBG("%s: enable_irq: %d (src %d)\n", mpic->name, irq, src); + + mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, + mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & ~MPIC_VECPRI_MASK); + + /* make sure mask gets to controller before we return to user */ + do { + if (!loops--) { + printk(KERN_ERR "mpic_enable_irq timeout\n"); + break; + } + } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); +} + +static void mpic_disable_irq(unsigned int irq) +{ + unsigned int loops = 100000; + struct mpic *mpic = mpic_from_irq(irq); + unsigned int src = irq - mpic->irq_offset; + + DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); + + mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, + mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | MPIC_VECPRI_MASK); + + /* make sure mask gets to controller before we return to user */ + do { + if (!loops--) { + printk(KERN_ERR "mpic_enable_irq timeout\n"); + break; + } + } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); +} + +static void mpic_end_irq(unsigned int irq) +{ + struct mpic *mpic = mpic_from_irq(irq); + + DBG("%s: end_irq: %d\n", mpic->name, irq); + + /* We always EOI on end_irq() even for edge interrupts since that + * should only lower the priority, the MPIC should have properly + * latched another edge interrupt coming in anyway + */ + +#ifdef CONFIG_MPIC_BROKEN_U3 + if (mpic->flags & MPIC_BROKEN_U3) { + unsigned int src = irq - mpic->irq_offset; + if (mpic_is_ht_interrupt(mpic, src)) + mpic_apic_end_irq(mpic, src); + } +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + mpic_eoi(mpic); +} + +#ifdef CONFIG_SMP + +static void mpic_enable_ipi(unsigned int irq) +{ + struct mpic *mpic = mpic_from_ipi(irq); + unsigned int src = irq - mpic->ipi_offset; + + DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); + mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); +} + +static void mpic_disable_ipi(unsigned int irq) +{ + /* NEVER disable an IPI... that's just plain wrong! */ +} + +static void mpic_end_ipi(unsigned int irq) +{ + struct mpic *mpic = mpic_from_ipi(irq); + + /* + * IPIs are marked IRQ_PER_CPU. This has the side effect of + * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from + * applying to them. We EOI them late to avoid re-entering. + * We mark IPI's with SA_INTERRUPT as they must run with + * irqs disabled. + */ + mpic_eoi(mpic); +} + +#endif /* CONFIG_SMP */ + +static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + struct mpic *mpic = mpic_from_irq(irq); + + cpumask_t tmp; + + cpus_and(tmp, cpumask, cpu_online_map); + + mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION, + mpic_physmask(cpus_addr(tmp)[0])); +} + + +/* + * Exported functions + */ + + +struct mpic * __init mpic_alloc(unsigned long phys_addr, + unsigned int flags, + unsigned int isu_size, + unsigned int irq_offset, + unsigned int irq_count, + unsigned int ipi_offset, + unsigned char *senses, + unsigned int senses_count, + const char *name) +{ + struct mpic *mpic; + u32 reg; + const char *vers; + int i; + + mpic = alloc_bootmem(sizeof(struct mpic)); + if (mpic == NULL) + return NULL; + + + memset(mpic, 0, sizeof(struct mpic)); + mpic->name = name; + + mpic->hc_irq.typename = name; + mpic->hc_irq.enable = mpic_enable_irq; + mpic->hc_irq.disable = mpic_disable_irq; + mpic->hc_irq.end = mpic_end_irq; + if (flags & MPIC_PRIMARY) + mpic->hc_irq.set_affinity = mpic_set_affinity; +#ifdef CONFIG_SMP + mpic->hc_ipi.typename = name; + mpic->hc_ipi.enable = mpic_enable_ipi; + mpic->hc_ipi.disable = mpic_disable_ipi; + mpic->hc_ipi.end = mpic_end_ipi; +#endif /* CONFIG_SMP */ + + mpic->flags = flags; + mpic->isu_size = isu_size; + mpic->irq_offset = irq_offset; + mpic->irq_count = irq_count; + mpic->ipi_offset = ipi_offset; + mpic->num_sources = 0; /* so far */ + mpic->senses = senses; + mpic->senses_count = senses_count; + + /* Map the global registers */ + mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); + mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2); + BUG_ON(mpic->gregs == NULL); + + /* Reset */ + if (flags & MPIC_WANTS_RESET) { + mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, + mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) + | MPIC_GREG_GCONF_RESET); + while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) + & MPIC_GREG_GCONF_RESET) + mb(); + } + + /* Read feature register, calculate num CPUs and, for non-ISU + * MPICs, num sources as well. On ISU MPICs, sources are counted + * as ISUs are added + */ + reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0); + mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) + >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; + if (isu_size == 0) + mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) + >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; + + /* Map the per-CPU registers */ + for (i = 0; i < mpic->num_cpus; i++) { + mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE + + i * MPIC_CPU_STRIDE, 0x1000); + BUG_ON(mpic->cpuregs[i] == NULL); + } + + /* Initialize main ISU if none provided */ + if (mpic->isu_size == 0) { + mpic->isu_size = mpic->num_sources; + mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE, + MPIC_IRQ_STRIDE * mpic->isu_size); + BUG_ON(mpic->isus[0] == NULL); + } + mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); + mpic->isu_mask = (1 << mpic->isu_shift) - 1; + + /* Display version */ + switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { + case 1: + vers = "1.0"; + break; + case 2: + vers = "1.2"; + break; + case 3: + vers = "1.3"; + break; + default: + vers = ""; + break; + } + printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", + name, vers, phys_addr, mpic->num_cpus); + printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, + mpic->isu_shift, mpic->isu_mask); + + mpic->next = mpics; + mpics = mpic; + + if (flags & MPIC_PRIMARY) + mpic_primary = mpic; + + return mpic; +} + +void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, + unsigned long phys_addr) +{ + unsigned int isu_first = isu_num * mpic->isu_size; + + BUG_ON(isu_num >= MPIC_MAX_ISU); + + mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size); + if ((isu_first + mpic->isu_size) > mpic->num_sources) + mpic->num_sources = isu_first + mpic->isu_size; +} + +void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, + void *data) +{ + struct mpic *mpic = mpic_find(irq, NULL); + unsigned long flags; + + /* Synchronization here is a bit dodgy, so don't try to replace cascade + * interrupts on the fly too often ... but normally it's set up at boot. + */ + spin_lock_irqsave(&mpic_lock, flags); + if (mpic->cascade) + mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); + mpic->cascade = NULL; + wmb(); + mpic->cascade_vec = irq - mpic->irq_offset; + mpic->cascade_data = data; + wmb(); + mpic->cascade = handler; + mpic_enable_irq(irq); + spin_unlock_irqrestore(&mpic_lock, flags); +} + +void __init mpic_init(struct mpic *mpic) +{ + int i; + + BUG_ON(mpic->num_sources == 0); + + printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); + + /* Set current processor priority to max */ + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); + + /* Initialize timers: just disable them all */ + for (i = 0; i < 4; i++) { + mpic_write(mpic->tmregs, + i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0); + mpic_write(mpic->tmregs, + i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI, + MPIC_VECPRI_MASK | + (MPIC_VEC_TIMER_0 + i)); + } + + /* Initialize IPIs to our reserved vectors and mark them disabled for now */ + mpic_test_broken_ipi(mpic); + for (i = 0; i < 4; i++) { + mpic_ipi_write(i, + MPIC_VECPRI_MASK | + (10 << MPIC_VECPRI_PRIORITY_SHIFT) | + (MPIC_VEC_IPI_0 + i)); +#ifdef CONFIG_SMP + if (!(mpic->flags & MPIC_PRIMARY)) + continue; + irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; + irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi; + +#endif /* CONFIG_SMP */ + } + + /* Initialize interrupt sources */ + if (mpic->irq_count == 0) + mpic->irq_count = mpic->num_sources; + +#ifdef CONFIG_MPIC_BROKEN_U3 + /* Do the ioapic fixups on U3 broken mpic */ + DBG("MPIC flags: %x\n", mpic->flags); + if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) + mpic_scan_ioapics(mpic); +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + for (i = 0; i < mpic->num_sources; i++) { + /* start with vector = source number, and masked */ + u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); + int level = 0; + + /* if it's an IPI, we skip it */ + if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) && + (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4)) + continue; + + /* do senses munging */ + if (mpic->senses && i < mpic->senses_count) { + if (mpic->senses[i] & IRQ_SENSE_LEVEL) + vecpri |= MPIC_VECPRI_SENSE_LEVEL; + if (mpic->senses[i] & IRQ_POLARITY_POSITIVE) + vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; + } else + vecpri |= MPIC_VECPRI_SENSE_LEVEL; + + /* remember if it was a level interrupts */ + level = (vecpri & MPIC_VECPRI_SENSE_LEVEL); + + /* deal with broken U3 */ + if (mpic->flags & MPIC_BROKEN_U3) { +#ifdef CONFIG_MPIC_BROKEN_U3 + if (mpic_is_ht_interrupt(mpic, i)) { + vecpri &= ~(MPIC_VECPRI_SENSE_MASK | + MPIC_VECPRI_POLARITY_MASK); + vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; + } +#else + printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n"); +#endif + } + + DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri, + (level != 0)); + + /* init hw */ + mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); + mpic_irq_write(i, MPIC_IRQ_DESTINATION, + 1 << hard_smp_processor_id()); + + /* init linux descriptors */ + if (i < mpic->irq_count) { + irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; + irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq; + } + } + + /* Init spurrious vector */ + mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS); + + /* Disable 8259 passthrough */ + mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, + mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) + | MPIC_GREG_GCONF_8259_PTHROU_DIS); + + /* Set current processor priority to 0 */ + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); +} + + + +void mpic_irq_set_priority(unsigned int irq, unsigned int pri) +{ + int is_ipi; + struct mpic *mpic = mpic_find(irq, &is_ipi); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&mpic_lock, flags); + if (is_ipi) { + reg = mpic_ipi_read(irq - mpic->ipi_offset) & MPIC_VECPRI_PRIORITY_MASK; + mpic_ipi_write(irq - mpic->ipi_offset, + reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); + } else { + reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI) + & MPIC_VECPRI_PRIORITY_MASK; + mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI, + reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); + } + spin_unlock_irqrestore(&mpic_lock, flags); +} + +unsigned int mpic_irq_get_priority(unsigned int irq) +{ + int is_ipi; + struct mpic *mpic = mpic_find(irq, &is_ipi); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&mpic_lock, flags); + if (is_ipi) + reg = mpic_ipi_read(irq - mpic->ipi_offset); + else + reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI); + spin_unlock_irqrestore(&mpic_lock, flags); + return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; +} + +void mpic_setup_this_cpu(void) +{ +#ifdef CONFIG_SMP + struct mpic *mpic = mpic_primary; + unsigned long flags; + u32 msk = 1 << hard_smp_processor_id(); + unsigned int i; + + BUG_ON(mpic == NULL); + + DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); + + spin_lock_irqsave(&mpic_lock, flags); + + /* let the mpic know we want intrs. default affinity is 0xffffffff + * until changed via /proc. That's how it's done on x86. If we want + * it differently, then we should make sure we also change the default + * values of irq_affinity in irq.c. + */ + if (distribute_irqs) { + for (i = 0; i < mpic->num_sources ; i++) + mpic_irq_write(i, MPIC_IRQ_DESTINATION, + mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk); + } + + /* Set current processor priority to 0 */ + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); + + spin_unlock_irqrestore(&mpic_lock, flags); +#endif /* CONFIG_SMP */ +} + +int mpic_cpu_get_priority(void) +{ + struct mpic *mpic = mpic_primary; + + return mpic_cpu_read(MPIC_CPU_CURRENT_TASK_PRI); +} + +void mpic_cpu_set_priority(int prio) +{ + struct mpic *mpic = mpic_primary; + + prio &= MPIC_CPU_TASKPRI_MASK; + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, prio); +} + +/* + * XXX: someone who knows mpic should check this. + * do we need to eoi the ipi including for kexec cpu here (see xics comments)? + * or can we reset the mpic in the new kernel? + */ +void mpic_teardown_this_cpu(int secondary) +{ + struct mpic *mpic = mpic_primary; + unsigned long flags; + u32 msk = 1 << hard_smp_processor_id(); + unsigned int i; + + BUG_ON(mpic == NULL); + + DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); + spin_lock_irqsave(&mpic_lock, flags); + + /* let the mpic know we don't want intrs. */ + for (i = 0; i < mpic->num_sources ; i++) + mpic_irq_write(i, MPIC_IRQ_DESTINATION, + mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk); + + /* Set current processor priority to max */ + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); + + spin_unlock_irqrestore(&mpic_lock, flags); +} + + +void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) +{ + struct mpic *mpic = mpic_primary; + + BUG_ON(mpic == NULL); + + DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); + + mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, + mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); +} + +int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) +{ + u32 irq; + + irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; + DBG("%s: get_one_irq(): %d\n", mpic->name, irq); + + if (mpic->cascade && irq == mpic->cascade_vec) { + DBG("%s: cascading ...\n", mpic->name); + irq = mpic->cascade(regs, mpic->cascade_data); + mpic_eoi(mpic); + return irq; + } + if (unlikely(irq == MPIC_VEC_SPURRIOUS)) + return -1; + if (irq < MPIC_VEC_IPI_0) + return irq + mpic->irq_offset; + DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); + return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; +} + +int mpic_get_irq(struct pt_regs *regs) +{ + struct mpic *mpic = mpic_primary; + + BUG_ON(mpic == NULL); + + return mpic_get_one_irq(mpic, regs); +} + + +#ifdef CONFIG_SMP +void mpic_request_ipis(void) +{ + struct mpic *mpic = mpic_primary; + + BUG_ON(mpic == NULL); + + printk("requesting IPIs ... \n"); + + /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ + request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT, + "IPI0 (call function)", mpic); + request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT, + "IPI1 (reschedule)", mpic); + request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT, + "IPI2 (unused)", mpic); + request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT, + "IPI3 (debugger break)", mpic); + + printk("IPIs requested... \n"); +} +#endif /* CONFIG_SMP */ diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index ce166e3de53b..0649540bc7d9 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -1,6 +1,7 @@ # # Makefile for the linux kernel. # +ifneq ($(CONFIG_PPC_MERGE),y) extra-$(CONFIG_PPC_STD_MMU) := head.o extra-$(CONFIG_40x) := head_4xx.o @@ -37,3 +38,23 @@ endif # These are here while we do the architecture merge vecemu-y += ../../powerpc/kernel/vecemu.o + +else +obj-y := entry.o irq.o idle.o time.o misc.o \ + signal.o ptrace.o align.o \ + syscalls.o setup.o \ + cputable.o perfmon.o +obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o +obj-$(CONFIG_POWER4) += cpu_setup_power4.o +obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o +obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_KGDB) += ppc-stub.o +obj-$(CONFIG_SMP) += smp.o smp-tbsync.o +obj-$(CONFIG_TAU) += temp.o +ifndef CONFIG_E200 +obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o +endif +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +endif diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 77fecfbabe88..1b891b806f3d 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -83,6 +83,8 @@ extern void pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); extern void chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); + +dev_t boot_dev; #endif /* CONFIG_PPC_MULTIPLATFORM */ #ifdef CONFIG_MAGIC_SYSRQ @@ -405,11 +407,13 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, _machine = _MACH_prep; } +#ifdef CONFIG_PPC_PREP /* not much more to do here, if prep */ if (_machine == _MACH_prep) { prep_init(r3, r4, r5, r6, r7); return; } +#endif /* prom_init has already been called from __start */ if (boot_infos) @@ -480,12 +484,16 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif /* CONFIG_ADB */ switch (_machine) { +#ifdef CONFIG_PPC_PMAC case _MACH_Pmac: pmac_init(r3, r4, r5, r6, r7); break; +#endif +#ifdef CONFIG_PPC_CHRP case _MACH_chrp: chrp_init(r3, r4, r5, r6, r7); break; +#endif } } diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index fccafbcd4b58..8bc734fe6682 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -89,9 +89,6 @@ extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi #define cached_21 (((char *)(ppc_cached_irq_mask))[3]) #define cached_A1 (((char *)(ppc_cached_irq_mask))[2]) -/* for the mac fs */ -dev_t boot_dev; - #ifdef CONFIG_SOUND_CS4232 long ppc_cs4232_dma, ppc_cs4232_dma2; #endif diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index b8d08f33f7ee..1b0a84931afc 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -5,6 +5,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC +ifneq ($(CONFIG_PPC_MERGE),y) wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o @@ -109,3 +110,16 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o \ ifeq ($(CONFIG_PPC_MPC52xx),y) obj-$(CONFIG_PCI) += mpc52xx_pci.o endif + +else +# Stuff still needed by the merged powerpc sources + +obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o +obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o +obj-$(CONFIG_PPC_PMAC) += indirect_pci.o +obj-$(CONFIG_PPC_CHRP) += indirect_pci.o i8259.o +obj-$(CONFIG_PPC_PREP) += indirect_pci.o i8259.o todc_time.o +obj-$(CONFIG_BOOTX_TEXT) += btext.o +obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o ppc_sys.o + +endif diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 76719451e384..503461884528 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -405,7 +405,7 @@ static int __init via_pmu_start(void) bright_req_2.complete = 1; batt_req.complete = 1; -#ifdef CONFIG_PPC32 +#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE) if (pmu_kind == PMU_KEYLARGO_BASED) openpic_set_irq_priority(vias->intrs[0].line, OPENPIC_PRIORITY_DEFAULT + 1); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index a3453555a94e..5b6b0b6038a7 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -629,12 +629,4 @@ void __init proc_misc_init(void) if (entry) entry->proc_fops = &proc_sysrq_trigger_operations; #endif -#ifdef CONFIG_PPC32 - { - extern struct file_operations ppc_htab_operations; - entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_htab_operations; - } -#endif } diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h new file mode 100644 index 000000000000..7c55abf597f6 --- /dev/null +++ b/include/asm-powerpc/kdebug.h @@ -0,0 +1,42 @@ +#ifndef _POWERPC_KDEBUG_H +#define _POWERPC_KDEBUG_H 1 + +/* nearly identical to x86_64/i386 code */ + +#include + +struct pt_regs; + +struct die_args { + struct pt_regs *regs; + const char *str; + long err; + int trapnr; + int signr; +}; + +/* + Note - you should never unregister because that can race with NMIs. + If you really want to do it first unregister - then synchronize_sched - + then free. + */ +int register_die_notifier(struct notifier_block *nb); +extern struct notifier_block *powerpc_die_chain; + +/* Grossly misnamed. */ +enum die_val { + DIE_OOPS = 1, + DIE_IABR_MATCH, + DIE_DABR_MATCH, + DIE_BPT, + DIE_SSTEP, + DIE_PAGE_FAULT, +}; + +static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) +{ + struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; + return notifier_call_chain(&powerpc_die_chain, val, &args); +} + +#endif diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h new file mode 100644 index 000000000000..d9129d2b038e --- /dev/null +++ b/include/asm-powerpc/kprobes.h @@ -0,0 +1,67 @@ +#ifndef _ASM_KPROBES_H +#define _ASM_KPROBES_H +/* + * Kernel Probes (KProbes) + * include/asm-ppc64/kprobes.h + * + * 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. + * + * Copyright (C) IBM Corporation, 2002, 2004 + * + * 2002-Oct Created by Vamsi Krishna S Kernel + * Probes initial implementation ( includes suggestions from + * Rusty Russell). + * 2004-Nov Modified for PPC64 by Ananth N Mavinakayanahalli + * + */ +#include +#include + +struct pt_regs; + +typedef unsigned int kprobe_opcode_t; +#define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */ +#define MAX_INSN_SIZE 1 + +#define IS_TW(instr) (((instr) & 0xfc0007fe) == 0x7c000008) +#define IS_TD(instr) (((instr) & 0xfc0007fe) == 0x7c000088) +#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) +#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) + +#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) + +#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ + IS_TWI(instr) || IS_TDI(instr)) + +#define ARCH_SUPPORTS_KRETPROBES +void kretprobe_trampoline(void); + +/* Architecture specific copy of original instruction */ +struct arch_specific_insn { + /* copy of original instruction */ + kprobe_opcode_t *insn; +}; + +#ifdef CONFIG_KPROBES +extern int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); +#else /* !CONFIG_KPROBES */ +static inline int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return 0; +} +#endif +#endif /* _ASM_KPROBES_H */ diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h new file mode 100644 index 000000000000..f1e24f4b2d1c --- /dev/null +++ b/include/asm-powerpc/mpic.h @@ -0,0 +1,279 @@ +#include + +/* + * Global registers + */ + +#define MPIC_GREG_BASE 0x01000 + +#define MPIC_GREG_FEATURE_0 0x00000 +#define MPIC_GREG_FEATURE_LAST_SRC_MASK 0x07ff0000 +#define MPIC_GREG_FEATURE_LAST_SRC_SHIFT 16 +#define MPIC_GREG_FEATURE_LAST_CPU_MASK 0x00001f00 +#define MPIC_GREG_FEATURE_LAST_CPU_SHIFT 8 +#define MPIC_GREG_FEATURE_VERSION_MASK 0xff +#define MPIC_GREG_FEATURE_1 0x00010 +#define MPIC_GREG_GLOBAL_CONF_0 0x00020 +#define MPIC_GREG_GCONF_RESET 0x80000000 +#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_VENDOR_0 0x00040 +#define MPIC_GREG_VENDOR_1 0x00050 +#define MPIC_GREG_VENDOR_2 0x00060 +#define MPIC_GREG_VENDOR_3 0x00070 +#define MPIC_GREG_VENDOR_ID 0x00080 +#define MPIC_GREG_VENDOR_ID_STEPPING_MASK 0x00ff0000 +#define MPIC_GREG_VENDOR_ID_STEPPING_SHIFT 16 +#define MPIC_GREG_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00 +#define MPIC_GREG_VENDOR_ID_DEVICE_ID_SHIFT 8 +#define MPIC_GREG_VENDOR_ID_VENDOR_ID_MASK 0x000000ff +#define MPIC_GREG_PROCESSOR_INIT 0x00090 +#define MPIC_GREG_IPI_VECTOR_PRI_0 0x000a0 +#define MPIC_GREG_IPI_VECTOR_PRI_1 0x000b0 +#define MPIC_GREG_IPI_VECTOR_PRI_2 0x000c0 +#define MPIC_GREG_IPI_VECTOR_PRI_3 0x000d0 +#define MPIC_GREG_SPURIOUS 0x000e0 +#define MPIC_GREG_TIMER_FREQ 0x000f0 + +/* + * + * Timer registers + */ +#define MPIC_TIMER_BASE 0x01100 +#define MPIC_TIMER_STRIDE 0x40 + +#define MPIC_TIMER_CURRENT_CNT 0x00000 +#define MPIC_TIMER_BASE_CNT 0x00010 +#define MPIC_TIMER_VECTOR_PRI 0x00020 +#define MPIC_TIMER_DESTINATION 0x00030 + +/* + * Per-Processor registers + */ + +#define MPIC_CPU_THISBASE 0x00000 +#define MPIC_CPU_BASE 0x20000 +#define MPIC_CPU_STRIDE 0x01000 + +#define MPIC_CPU_IPI_DISPATCH_0 0x00040 +#define MPIC_CPU_IPI_DISPATCH_1 0x00050 +#define MPIC_CPU_IPI_DISPATCH_2 0x00060 +#define MPIC_CPU_IPI_DISPATCH_3 0x00070 +#define MPIC_CPU_CURRENT_TASK_PRI 0x00080 +#define MPIC_CPU_TASKPRI_MASK 0x0000000f +#define MPIC_CPU_WHOAMI 0x00090 +#define MPIC_CPU_WHOAMI_MASK 0x0000001f +#define MPIC_CPU_INTACK 0x000a0 +#define MPIC_CPU_EOI 0x000b0 + +/* + * Per-source registers + */ + +#define MPIC_IRQ_BASE 0x10000 +#define MPIC_IRQ_STRIDE 0x00020 +#define MPIC_IRQ_VECTOR_PRI 0x00000 +#define MPIC_VECPRI_MASK 0x80000000 +#define MPIC_VECPRI_ACTIVITY 0x40000000 /* Read Only */ +#define MPIC_VECPRI_PRIORITY_MASK 0x000f0000 +#define MPIC_VECPRI_PRIORITY_SHIFT 16 +#define MPIC_VECPRI_VECTOR_MASK 0x000007ff +#define MPIC_VECPRI_POLARITY_POSITIVE 0x00800000 +#define MPIC_VECPRI_POLARITY_NEGATIVE 0x00000000 +#define MPIC_VECPRI_POLARITY_MASK 0x00800000 +#define MPIC_VECPRI_SENSE_LEVEL 0x00400000 +#define MPIC_VECPRI_SENSE_EDGE 0x00000000 +#define MPIC_VECPRI_SENSE_MASK 0x00400000 +#define MPIC_IRQ_DESTINATION 0x00010 + +#define MPIC_MAX_IRQ_SOURCES 2048 +#define MPIC_MAX_CPUS 32 +#define MPIC_MAX_ISU 32 + +/* + * Special vector numbers (internal use only) + */ +#define MPIC_VEC_SPURRIOUS 255 +#define MPIC_VEC_IPI_3 254 +#define MPIC_VEC_IPI_2 253 +#define MPIC_VEC_IPI_1 252 +#define MPIC_VEC_IPI_0 251 + +/* unused */ +#define MPIC_VEC_TIMER_3 250 +#define MPIC_VEC_TIMER_2 249 +#define MPIC_VEC_TIMER_1 248 +#define MPIC_VEC_TIMER_0 247 + +/* Type definition of the cascade handler */ +typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); + +#ifdef CONFIG_MPIC_BROKEN_U3 +/* Fixup table entry */ +struct mpic_irq_fixup +{ + u8 __iomem *base; + unsigned int irq; +}; +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + +/* The instance data of a given MPIC */ +struct mpic +{ + /* The "linux" controller struct */ + hw_irq_controller hc_irq; +#ifdef CONFIG_SMP + hw_irq_controller hc_ipi; +#endif + const char *name; + /* Flags */ + unsigned int flags; + /* How many irq sources in a given ISU */ + unsigned int isu_size; + unsigned int isu_shift; + unsigned int isu_mask; + /* Offset of irq vector numbers */ + unsigned int irq_offset; + unsigned int irq_count; + /* Offset of ipi vector numbers */ + unsigned int ipi_offset; + /* Number of sources */ + unsigned int num_sources; + /* Number of CPUs */ + unsigned int num_cpus; + /* cascade handler */ + mpic_cascade_t cascade; + void *cascade_data; + unsigned int cascade_vec; + /* senses array */ + unsigned char *senses; + unsigned int senses_count; + +#ifdef CONFIG_MPIC_BROKEN_U3 + /* The fixup table */ + struct mpic_irq_fixup *fixups; + spinlock_t fixup_lock; +#endif + + /* The various ioremap'ed bases */ + volatile u32 __iomem *gregs; + volatile u32 __iomem *tmregs; + volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS]; + volatile u32 __iomem *isus[MPIC_MAX_ISU]; + + /* link */ + struct mpic *next; +}; + +/* This is the primary controller, only that one has IPIs and + * has afinity control. A non-primary MPIC always uses CPU0 + * registers only + */ +#define MPIC_PRIMARY 0x00000001 +/* Set this for a big-endian MPIC */ +#define MPIC_BIG_ENDIAN 0x00000002 +/* Broken U3 MPIC */ +#define MPIC_BROKEN_U3 0x00000004 +/* Broken IPI registers (autodetected) */ +#define MPIC_BROKEN_IPI 0x00000008 +/* MPIC wants a reset */ +#define MPIC_WANTS_RESET 0x00000010 + +/* Allocate the controller structure and setup the linux irq descs + * for the range if interrupts passed in. No HW initialization is + * actually performed. + * + * @phys_addr: physial base address of the MPIC + * @flags: flags, see constants above + * @isu_size: number of interrupts in an ISU. Use 0 to use a + * standard ISU-less setup (aka powermac) + * @irq_offset: first irq number to assign to this mpic + * @irq_count: number of irqs to use with this mpic IRQ sources. Pass 0 + * to match the number of sources + * @ipi_offset: first irq number to assign to this mpic IPI sources, + * used only on primary mpic + * @senses: array of sense values + * @senses_num: number of entries in the array + * + * Note about the sense array. If none is passed, all interrupts are + * setup to be level negative unless MPIC_BROKEN_U3 is set in which + * case they are edge positive (and the array is ignored anyway). + * The values in the array start at the first source of the MPIC, + * that is senses[0] correspond to linux irq "irq_offset". + */ +extern struct mpic *mpic_alloc(unsigned long phys_addr, + unsigned int flags, + unsigned int isu_size, + unsigned int irq_offset, + unsigned int irq_count, + unsigned int ipi_offset, + unsigned char *senses, + unsigned int senses_num, + const char *name); + +/* Assign ISUs, to call before mpic_init() + * + * @mpic: controller structure as returned by mpic_alloc() + * @isu_num: ISU number + * @phys_addr: physical address of the ISU + */ +extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, + unsigned long phys_addr); + +/* Initialize the controller. After this has been called, none of the above + * should be called again for this mpic + */ +extern void mpic_init(struct mpic *mpic); + +/* Setup a cascade. Currently, only one cascade is supported this + * way, though you can always do a normal request_irq() and add + * other cascades this way. You should call this _after_ having + * added all the ISUs + * + * @irq_no: "linux" irq number of the cascade (that is offset'ed vector) + * @handler: cascade handler function + */ +extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder, + void *data); + +/* + * All of the following functions must only be used after the + * ISUs have been assigned and the controller fully initialized + * with mpic_init() + */ + + +/* Change/Read the priority of an interrupt. Default is 8 for irqs and + * 10 for IPIs. You can call this on both IPIs and IRQ numbers, but the + * IPI number is then the offset'ed (linux irq number mapped to the IPI) + */ +extern void mpic_irq_set_priority(unsigned int irq, unsigned int pri); +extern unsigned int mpic_irq_get_priority(unsigned int irq); + +/* Setup a non-boot CPU */ +extern void mpic_setup_this_cpu(void); + +/* Clean up for kexec (or cpu offline or ...) */ +extern void mpic_teardown_this_cpu(int secondary); + +/* Get the current cpu priority for this cpu (0..15) */ +extern int mpic_cpu_get_priority(void); + +/* Set the current cpu priority for this cpu */ +extern void mpic_cpu_set_priority(int prio); + +/* Request IPIs on primary mpic */ +extern void mpic_request_ipis(void); + +/* Send an IPI (non offseted number 0..3) */ +extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); + +/* Fetch interrupt from a given mpic */ +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); + +/* global mpic for pSeries */ +extern struct mpic *pSeries_mpic; diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h new file mode 100644 index 000000000000..f97a5f1761b4 --- /dev/null +++ b/include/asm-powerpc/reg.h @@ -0,0 +1,446 @@ +/* + * Contains the definition of registers common to all PowerPC variants. + * If a register definition has been changed in a different PowerPC + * variant, we will case it in #ifndef XXX ... #endif, and have the + * number used in the Programming Environments Manual For 32-Bit + * Implementations of the PowerPC Architecture (a.k.a. Green Book) here. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_PPC_REGS_H__ +#define __ASM_PPC_REGS_H__ + +#include + +/* Pickup Book E specific registers. */ +#if defined(CONFIG_BOOKE) || defined(CONFIG_40x) +#include +#endif + +/* Machine State Register (MSR) Fields */ +#define MSR_SF (1<<63) +#define MSR_ISF (1<<61) +#define MSR_VEC (1<<25) /* Enable AltiVec */ +#define MSR_POW (1<<18) /* Enable Power Management */ +#define MSR_WE (1<<18) /* Wait State Enable */ +#define MSR_TGPR (1<<17) /* TLB Update registers in use */ +#define MSR_CE (1<<17) /* Critical Interrupt Enable */ +#define MSR_ILE (1<<16) /* Interrupt Little Endian */ +#define MSR_EE (1<<15) /* External Interrupt Enable */ +#define MSR_PR (1<<14) /* Problem State / Privilege Level */ +#define MSR_FP (1<<13) /* Floating Point enable */ +#define MSR_ME (1<<12) /* Machine Check Enable */ +#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ +#define MSR_SE (1<<10) /* Single Step */ +#define MSR_BE (1<<9) /* Branch Trace */ +#define MSR_DE (1<<9) /* Debug Exception Enable */ +#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ +#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ +#define MSR_IR (1<<5) /* Instruction Relocate */ +#define MSR_DR (1<<4) /* Data Relocate */ +#define MSR_PE (1<<3) /* Protection Enable */ +#define MSR_PX (1<<2) /* Protection Exclusive Mode */ +#define MSR_RI (1<<1) /* Recoverable Exception */ +#define MSR_LE (1<<0) /* Little Endian */ + +/* Default MSR for kernel mode. */ +#ifdef CONFIG_APUS_FAST_EXCEPT +#define MSR_KERNEL (MSR_ME|MSR_IP|MSR_RI|MSR_IR|MSR_DR) +#endif + +#ifndef MSR_KERNEL +#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) +#endif + +#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) + +/* Floating Point Status and Control Register (FPSCR) Fields */ +#define FPSCR_FX 0x80000000 /* FPU exception summary */ +#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ +#define FPSCR_VX 0x20000000 /* Invalid operation summary */ +#define FPSCR_OX 0x10000000 /* Overflow exception summary */ +#define FPSCR_UX 0x08000000 /* Underflow exception summary */ +#define FPSCR_ZX 0x04000000 /* Zero-divide exception summary */ +#define FPSCR_XX 0x02000000 /* Inexact exception summary */ +#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ +#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ +#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ +#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ +#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ +#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ +#define FPSCR_FR 0x00040000 /* Fraction rounded */ +#define FPSCR_FI 0x00020000 /* Fraction inexact */ +#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ +#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ +#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ +#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ +#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ +#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ +#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ +#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ +#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ +#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ +#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ +#define FPSCR_RN 0x00000003 /* FPU rounding control */ + +/* Special Purpose Registers (SPRNs)*/ +#define SPRN_CTR 0x009 /* Count Register */ +#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 DSISR_NOHPTE 0x40000000 /* no translation found */ +#define DSISR_PROTFAULT 0x08000000 /* protection fault */ +#define DSISR_ISSTORE 0x02000000 /* access was a store */ +#define DSISR_DABRMATCH 0x00400000 /* hit data breakpoint */ +#define DSISR_NOSEGMENT 0x00200000 /* STAB/SLB miss */ +#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */ +#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */ +#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ +#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ +#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ +#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */ +#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */ +#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */ +#define SPRN_DBAT1U 0x21A /* Data BAT 1 Upper Register */ +#define SPRN_DBAT2L 0x21D /* Data BAT 2 Lower Register */ +#define SPRN_DBAT2U 0x21C /* Data BAT 2 Upper Register */ +#define SPRN_DBAT3L 0x21F /* Data BAT 3 Lower Register */ +#define SPRN_DBAT3U 0x21E /* Data BAT 3 Upper Register */ +#define SPRN_DBAT4L 0x239 /* Data BAT 4 Lower Register */ +#define SPRN_DBAT4U 0x238 /* Data BAT 4 Upper Register */ +#define SPRN_DBAT5L 0x23B /* Data BAT 5 Lower Register */ +#define SPRN_DBAT5U 0x23A /* Data BAT 5 Upper Register */ +#define SPRN_DBAT6L 0x23D /* Data BAT 6 Lower Register */ +#define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */ +#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */ +#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */ + +#define SPRN_DEC 0x016 /* Decrement Register */ +#define SPRN_DER 0x095 /* Debug Enable Regsiter */ +#define DER_RSTE 0x40000000 /* Reset Interrupt */ +#define DER_CHSTPE 0x20000000 /* Check Stop */ +#define DER_MCIE 0x10000000 /* Machine Check Interrupt */ +#define DER_EXTIE 0x02000000 /* External Interrupt */ +#define DER_ALIE 0x01000000 /* Alignment Interrupt */ +#define DER_PRIE 0x00800000 /* Program Interrupt */ +#define DER_FPUVIE 0x00400000 /* FP Unavailable Interrupt */ +#define DER_DECIE 0x00200000 /* Decrementer Interrupt */ +#define DER_SYSIE 0x00040000 /* System Call Interrupt */ +#define DER_TRE 0x00020000 /* Trace Interrupt */ +#define DER_SEIE 0x00004000 /* FP SW Emulation Interrupt */ +#define DER_ITLBMSE 0x00002000 /* Imp. Spec. Instruction TLB Miss */ +#define DER_ITLBERE 0x00001000 /* Imp. Spec. Instruction TLB Error */ +#define DER_DTLBMSE 0x00000800 /* Imp. Spec. Data TLB Miss */ +#define DER_DTLBERE 0x00000400 /* Imp. Spec. Data TLB Error */ +#define DER_LBRKE 0x00000008 /* Load/Store Breakpoint Interrupt */ +#define DER_IBRKE 0x00000004 /* Instruction Breakpoint Interrupt */ +#define DER_EBRKE 0x00000002 /* External Breakpoint Interrupt */ +#define DER_DPIE 0x00000001 /* Dev. Port Nonmaskable Request */ +#define SPRN_DMISS 0x3D0 /* Data TLB Miss Register */ +#define SPRN_EAR 0x11A /* External Address Register */ +#define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */ +#define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */ +#define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */ +#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ +#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ +#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ +#define HID0_SBCLK (1<<27) +#define HID0_EICE (1<<26) +#define HID0_TBEN (1<<26) /* Timebase enable - 745x */ +#define HID0_ECLK (1<<25) +#define HID0_PAR (1<<24) +#define HID0_STEN (1<<24) /* Software table search enable - 745x */ +#define HID0_HIGH_BAT (1<<23) /* Enable high BATs - 7455 */ +#define HID0_DOZE (1<<23) +#define HID0_NAP (1<<22) +#define HID0_SLEEP (1<<21) +#define HID0_DPM (1<<20) +#define HID0_BHTCLR (1<<18) /* Clear branch history table - 7450 */ +#define HID0_XAEN (1<<17) /* Extended addressing enable - 7450 */ +#define HID0_NHR (1<<16) /* Not hard reset (software bit-7450)*/ +#define HID0_ICE (1<<15) /* Instruction Cache Enable */ +#define HID0_DCE (1<<14) /* Data Cache Enable */ +#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ +#define HID0_DLOCK (1<<12) /* Data Cache Lock */ +#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ +#define HID0_DCI (1<<10) /* Data Cache Invalidate */ +#define HID0_SPD (1<<9) /* Speculative disable */ +#define HID0_DAPUEN (1<<8) /* Debug APU enable */ +#define HID0_SGE (1<<7) /* Store Gathering Enable */ +#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ +#define HID0_DFCA (1<<6) /* Data Cache Flush Assist */ +#define HID0_LRSTK (1<<4) /* Link register stack - 745x */ +#define HID0_BTIC (1<<5) /* Branch Target Instr Cache Enable */ +#define HID0_ABE (1<<3) /* Address Broadcast Enable */ +#define HID0_FOLD (1<<3) /* Branch Folding enable - 745x */ +#define HID0_BHTE (1<<2) /* Branch History Table Enable */ +#define HID0_BTCD (1<<1) /* Branch target cache disable */ +#define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */ +#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */ + +#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ +#define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */ +#define HID1_DFS (1<<22) /* 7447A Dynamic Frequency Scaling */ +#define HID1_PC0 (1<<16) /* 7450 PLL_CFG[0] */ +#define HID1_PC1 (1<<15) /* 7450 PLL_CFG[1] */ +#define HID1_PC2 (1<<14) /* 7450 PLL_CFG[2] */ +#define HID1_PC3 (1<<13) /* 7450 PLL_CFG[3] */ +#define HID1_SYNCBE (1<<11) /* 7450 ABE for sync, eieio */ +#define HID1_ABE (1<<10) /* 7450 Address Broadcast Enable */ +#define HID1_PS (1<<16) /* 750FX PLL selection */ +#define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ +#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ +#define SPRN_HID4 0x3F4 /* 970 HID4 */ +#define SPRN_HID5 0x3F6 /* 970 HID5 */ +#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2) +#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */ +#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */ +#endif +#define SPRN_IBAT0L 0x211 /* Instruction BAT 0 Lower Register */ +#define SPRN_IBAT0U 0x210 /* Instruction BAT 0 Upper Register */ +#define SPRN_IBAT1L 0x213 /* Instruction BAT 1 Lower Register */ +#define SPRN_IBAT1U 0x212 /* Instruction BAT 1 Upper Register */ +#define SPRN_IBAT2L 0x215 /* Instruction BAT 2 Lower Register */ +#define SPRN_IBAT2U 0x214 /* Instruction BAT 2 Upper Register */ +#define SPRN_IBAT3L 0x217 /* Instruction BAT 3 Lower Register */ +#define SPRN_IBAT3U 0x216 /* Instruction BAT 3 Upper Register */ +#define SPRN_IBAT4L 0x231 /* Instruction BAT 4 Lower Register */ +#define SPRN_IBAT4U 0x230 /* Instruction BAT 4 Upper Register */ +#define SPRN_IBAT5L 0x233 /* Instruction BAT 5 Lower Register */ +#define SPRN_IBAT5U 0x232 /* Instruction BAT 5 Upper Register */ +#define SPRN_IBAT6L 0x235 /* Instruction BAT 6 Lower Register */ +#define SPRN_IBAT6U 0x234 /* Instruction BAT 6 Upper Register */ +#define SPRN_IBAT7L 0x237 /* Instruction BAT 7 Lower Register */ +#define SPRN_IBAT7U 0x236 /* Instruction BAT 7 Upper Register */ +#define SPRN_ICMP 0x3D5 /* Instruction TLB Compare Register */ +#define SPRN_ICTC 0x3FB /* Instruction Cache Throttling Control Reg */ +#define SPRN_ICTRL 0x3F3 /* 1011 7450 icache and interrupt ctrl */ +#define ICTRL_EICE 0x08000000 /* enable icache parity errs */ +#define ICTRL_EDC 0x04000000 /* enable dcache parity errs */ +#define ICTRL_EICP 0x00000100 /* enable icache par. check */ +#define SPRN_IMISS 0x3D4 /* Instruction TLB Miss Register */ +#define SPRN_IMMR 0x27E /* Internal Memory Map Register */ +#define SPRN_L2CR 0x3F9 /* Level 2 Cache Control Regsiter */ +#define SPRN_L2CR2 0x3f8 +#define L2CR_L2E 0x80000000 /* L2 enable */ +#define L2CR_L2PE 0x40000000 /* L2 parity enable */ +#define L2CR_L2SIZ_MASK 0x30000000 /* L2 size mask */ +#define L2CR_L2SIZ_256KB 0x10000000 /* L2 size 256KB */ +#define L2CR_L2SIZ_512KB 0x20000000 /* L2 size 512KB */ +#define L2CR_L2SIZ_1MB 0x30000000 /* L2 size 1MB */ +#define L2CR_L2CLK_MASK 0x0e000000 /* L2 clock mask */ +#define L2CR_L2CLK_DISABLED 0x00000000 /* L2 clock disabled */ +#define L2CR_L2CLK_DIV1 0x02000000 /* L2 clock / 1 */ +#define L2CR_L2CLK_DIV1_5 0x04000000 /* L2 clock / 1.5 */ +#define L2CR_L2CLK_DIV2 0x08000000 /* L2 clock / 2 */ +#define L2CR_L2CLK_DIV2_5 0x0a000000 /* L2 clock / 2.5 */ +#define L2CR_L2CLK_DIV3 0x0c000000 /* L2 clock / 3 */ +#define L2CR_L2RAM_MASK 0x01800000 /* L2 RAM type mask */ +#define L2CR_L2RAM_FLOW 0x00000000 /* L2 RAM flow through */ +#define L2CR_L2RAM_PIPE 0x01000000 /* L2 RAM pipelined */ +#define L2CR_L2RAM_PIPE_LW 0x01800000 /* L2 RAM pipelined latewr */ +#define L2CR_L2DO 0x00400000 /* L2 data only */ +#define L2CR_L2I 0x00200000 /* L2 global invalidate */ +#define L2CR_L2CTL 0x00100000 /* L2 RAM control */ +#define L2CR_L2WT 0x00080000 /* L2 write-through */ +#define L2CR_L2TS 0x00040000 /* L2 test support */ +#define L2CR_L2OH_MASK 0x00030000 /* L2 output hold mask */ +#define L2CR_L2OH_0_5 0x00000000 /* L2 output hold 0.5 ns */ +#define L2CR_L2OH_1_0 0x00010000 /* L2 output hold 1.0 ns */ +#define L2CR_L2SL 0x00008000 /* L2 DLL slow */ +#define L2CR_L2DF 0x00004000 /* L2 differential clock */ +#define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */ +#define L2CR_L2IP 0x00000001 /* L2 GI in progress */ +#define L2CR_L2IO_745x 0x00100000 /* L2 instr. only (745x) */ +#define L2CR_L2DO_745x 0x00010000 /* L2 data only (745x) */ +#define L2CR_L2REP_745x 0x00001000 /* L2 repl. algorithm (745x) */ +#define L2CR_L2HWF_745x 0x00000800 /* L2 hardware flush (745x) */ +#define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter */ +#define L3CR_L3E 0x80000000 /* L3 enable */ +#define L3CR_L3PE 0x40000000 /* L3 data parity enable */ +#define L3CR_L3APE 0x20000000 /* L3 addr parity enable */ +#define L3CR_L3SIZ 0x10000000 /* L3 size */ +#define L3CR_L3CLKEN 0x08000000 /* L3 clock enable */ +#define L3CR_L3RES 0x04000000 /* L3 special reserved bit */ +#define L3CR_L3CLKDIV 0x03800000 /* L3 clock divisor */ +#define L3CR_L3IO 0x00400000 /* L3 instruction only */ +#define L3CR_L3SPO 0x00040000 /* L3 sample point override */ +#define L3CR_L3CKSP 0x00030000 /* L3 clock sample point */ +#define L3CR_L3PSP 0x0000e000 /* L3 P-clock sample point */ +#define L3CR_L3REP 0x00001000 /* L3 replacement algorithm */ +#define L3CR_L3HWF 0x00000800 /* L3 hardware flush */ +#define L3CR_L3I 0x00000400 /* L3 global invalidate */ +#define L3CR_L3RT 0x00000300 /* L3 SRAM type */ +#define L3CR_L3NIRCA 0x00000080 /* L3 non-integer ratio clock adj. */ +#define L3CR_L3DO 0x00000040 /* L3 data only mode */ +#define L3CR_PMEN 0x00000004 /* L3 private memory enable */ +#define L3CR_PMSIZ 0x00000001 /* L3 private memory size */ +#define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */ +#define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */ +#define SPRN_LDSTCR 0x3f8 /* Load/Store control register */ +#define SPRN_LDSTDB 0x3f4 /* */ +#define SPRN_LR 0x008 /* Link Register */ +#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ +#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ +#ifndef SPRN_PIR +#define SPRN_PIR 0x3FF /* Processor Identification Register */ +#endif +#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ +#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ +#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ +#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ +#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_PVR 0x11F /* Processor Version Register */ +#define SPRN_RPA 0x3D6 /* Required Physical Address Register */ +#define SPRN_SDA 0x3BF /* Sampled Data Address Register */ +#define SPRN_SDR1 0x019 /* MMU Hash Base Register */ +#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ +#define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ +#define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ +#define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ +#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ +#define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */ +#define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */ +#define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */ +#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */ +#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ +#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ +#ifndef SPRN_SVR +#define SPRN_SVR 0x11E /* System Version Register */ +#endif +#define SPRN_THRM1 0x3FC /* Thermal Management Register 1 */ +/* these bits were defined in inverted endian sense originally, ugh, confusing */ +#define THRM1_TIN (1 << 31) +#define THRM1_TIV (1 << 30) +#define THRM1_THRES(x) ((x&0x7f)<<23) +#define THRM3_SITV(x) ((x&0x3fff)<<1) +#define THRM1_TID (1<<2) +#define THRM1_TIE (1<<1) +#define THRM1_V (1<<0) +#define SPRN_THRM2 0x3FD /* Thermal Management Register 2 */ +#define SPRN_THRM3 0x3FE /* Thermal Management Register 3 */ +#define THRM3_E (1<<0) +#define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */ +#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */ +#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */ +#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */ +#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */ +#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ +#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ +#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ +#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ +#define SPRN_XER 0x001 /* Fixed Point Exception Register */ + +/* Bit definitions for MMCR0 and PMC1 / PMC2. */ +#define MMCR0_PMC1_CYCLES (1 << 7) +#define MMCR0_PMC1_ICACHEMISS (5 << 7) +#define MMCR0_PMC1_DTLB (6 << 7) +#define MMCR0_PMC2_DCACHEMISS 0x6 +#define MMCR0_PMC2_CYCLES 0x1 +#define MMCR0_PMC2_ITLB 0x7 +#define MMCR0_PMC2_LOADMISSTIME 0x5 +#define MMCR0_PMXE (1 << 26) + +/* Processor Version Register */ + +/* Processor Version Register (PVR) field extraction */ + +#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ +#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ + +/* + * IBM has further subdivided the standard PowerPC 16-bit version and + * revision subfields of the PVR for the PowerPC 403s into the following: + */ + +#define PVR_FAM(pvr) (((pvr) >> 20) & 0xFFF) /* Family field */ +#define PVR_MEM(pvr) (((pvr) >> 16) & 0xF) /* Member field */ +#define PVR_CORE(pvr) (((pvr) >> 12) & 0xF) /* Core field */ +#define PVR_CFG(pvr) (((pvr) >> 8) & 0xF) /* Configuration field */ +#define PVR_MAJ(pvr) (((pvr) >> 4) & 0xF) /* Major revision field */ +#define PVR_MIN(pvr) (((pvr) >> 0) & 0xF) /* Minor revision field */ + +/* Processor Version Numbers */ + +#define PVR_403GA 0x00200000 +#define PVR_403GB 0x00200100 +#define PVR_403GC 0x00200200 +#define PVR_403GCX 0x00201400 +#define PVR_405GP 0x40110000 +#define PVR_STB03XXX 0x40310000 +#define PVR_NP405H 0x41410000 +#define PVR_NP405L 0x41610000 +#define PVR_601 0x00010000 +#define PVR_602 0x00050000 +#define PVR_603 0x00030000 +#define PVR_603e 0x00060000 +#define PVR_603ev 0x00070000 +#define PVR_603r 0x00071000 +#define PVR_604 0x00040000 +#define PVR_604e 0x00090000 +#define PVR_604r 0x000A0000 +#define PVR_620 0x00140000 +#define PVR_740 0x00080000 +#define PVR_750 PVR_740 +#define PVR_740P 0x10080000 +#define PVR_750P PVR_740P +#define PVR_7400 0x000C0000 +#define PVR_7410 0x800C0000 +#define PVR_7450 0x80000000 +#define PVR_8540 0x80200000 +#define PVR_8560 0x80200000 +/* + * For the 8xx processors, all of them report the same PVR family for + * the PowerPC core. The various versions of these processors must be + * differentiated by the version number in the Communication Processor + * Module (CPM). + */ +#define PVR_821 0x00500000 +#define PVR_823 PVR_821 +#define PVR_850 PVR_821 +#define PVR_860 PVR_821 +#define PVR_8240 0x00810100 +#define PVR_8245 0x80811014 +#define PVR_8260 PVR_8240 + +#if 0 +/* Segment Registers */ +#define SR0 0 +#define SR1 1 +#define SR2 2 +#define SR3 3 +#define SR4 4 +#define SR5 5 +#define SR6 6 +#define SR7 7 +#define SR8 8 +#define SR9 9 +#define SR10 10 +#define SR11 11 +#define SR12 12 +#define SR13 13 +#define SR14 14 +#define SR15 15 +#endif + +/* Macros for setting and retrieving special purpose registers */ +#ifndef __ASSEMBLY__ +#define mfmsr() ({unsigned int rval; \ + asm volatile("mfmsr %0" : "=r" (rval)); rval;}) +#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) + +#define mfspr(rn) ({unsigned int rval; \ + asm volatile("mfspr %0," __stringify(rn) \ + : "=r" (rval)); rval;}) +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) + +#define mfsrin(v) ({unsigned int rval; \ + asm volatile("mfsrin %0,%1" : "=r" (rval) : "r" (v)); \ + rval;}) + +#define proc_trap() asm volatile("trap") +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_PPC_REGS_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h new file mode 100644 index 000000000000..be542efb32d3 --- /dev/null +++ b/include/asm-powerpc/system.h @@ -0,0 +1,350 @@ +/* + * Copyright (C) 1999 Cort Dougan + */ +#ifndef __PPC_SYSTEM_H +#define __PPC_SYSTEM_H + +#include +#include + +#include +#include + +/* + * Memory barrier. + * The sync instruction guarantees that all memory accesses initiated + * by this processor have been performed (with respect to all other + * mechanisms that access memory). The eieio instruction is a barrier + * providing an ordering (separately) for (a) cacheable stores and (b) + * loads and stores to non-cacheable memory (e.g. I/O devices). + * + * mb() prevents loads and stores being reordered across this point. + * rmb() prevents loads being reordered across this point. + * wmb() prevents stores being reordered across this point. + * read_barrier_depends() prevents data-dependent loads being reordered + * across this point (nop on PPC). + * + * We have to use the sync instructions for mb(), since lwsync doesn't + * order loads with respect to previous stores. Lwsync is fine for + * rmb(), though. Note that lwsync is interpreted as sync by + * 32-bit and older 64-bit CPUs. + * + * For wmb(), we use sync since wmb is used in drivers to order + * stores to system memory with respect to writes to the device. + * However, smp_wmb() can be a lighter-weight eieio barrier on + * SMP since it is only used to order updates to system memory. + */ +#define mb() __asm__ __volatile__ ("sync" : : : "memory") +#define rmb() __asm__ __volatile__ ("lwsync" : : : "memory") +#define wmb() __asm__ __volatile__ ("sync" : : : "memory") +#define read_barrier_depends() do { } while(0) + +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() __asm__ __volatile__ ("eieio" : : : "memory") +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) +#endif /* CONFIG_SMP */ + +#ifdef __KERNEL__ +struct task_struct; +struct pt_regs; + +#ifdef CONFIG_DEBUGGER + +extern int (*__debugger)(struct pt_regs *regs); +extern int (*__debugger_ipi)(struct pt_regs *regs); +extern int (*__debugger_bpt)(struct pt_regs *regs); +extern int (*__debugger_sstep)(struct pt_regs *regs); +extern int (*__debugger_iabr_match)(struct pt_regs *regs); +extern int (*__debugger_dabr_match)(struct pt_regs *regs); +extern int (*__debugger_fault_handler)(struct pt_regs *regs); + +#define DEBUGGER_BOILERPLATE(__NAME) \ +static inline int __NAME(struct pt_regs *regs) \ +{ \ + if (unlikely(__ ## __NAME)) \ + return __ ## __NAME(regs); \ + return 0; \ +} + +DEBUGGER_BOILERPLATE(debugger) +DEBUGGER_BOILERPLATE(debugger_ipi) +DEBUGGER_BOILERPLATE(debugger_bpt) +DEBUGGER_BOILERPLATE(debugger_sstep) +DEBUGGER_BOILERPLATE(debugger_iabr_match) +DEBUGGER_BOILERPLATE(debugger_dabr_match) +DEBUGGER_BOILERPLATE(debugger_fault_handler) + +#ifdef CONFIG_XMON +extern void xmon_init(int enable); +#endif + +#else +static inline int debugger(struct pt_regs *regs) { return 0; } +static inline int debugger_ipi(struct pt_regs *regs) { return 0; } +static inline int debugger_bpt(struct pt_regs *regs) { return 0; } +static inline int debugger_sstep(struct pt_regs *regs) { return 0; } +static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; } +static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } +static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } +#endif + +extern int set_dabr(unsigned long dabr); +extern void print_backtrace(unsigned long *); +extern void show_regs(struct pt_regs * regs); +extern void flush_instruction_cache(void); +extern void hard_reset_now(void); +extern void poweroff_now(void); + +#ifdef CONFIG_6xx +extern long _get_L2CR(void); +extern long _get_L3CR(void); +extern void _set_L2CR(unsigned long); +extern void _set_L3CR(unsigned long); +#else +#define _get_L2CR() 0L +#define _get_L3CR() 0L +#define _set_L2CR(val) do { } while(0) +#define _set_L3CR(val) do { } while(0) +#endif + +extern void via_cuda_init(void); +extern void pmac_nvram_init(void); +extern void read_rtc_time(void); +extern void pmac_find_display(void); +extern void giveup_fpu(struct task_struct *); +extern void enable_kernel_fp(void); +extern void flush_fp_to_thread(struct task_struct *); +extern void enable_kernel_altivec(void); +extern void giveup_altivec(struct task_struct *); +extern void load_up_altivec(struct task_struct *); +extern void giveup_spe(struct task_struct *); +extern void load_up_spe(struct task_struct *); +extern int fix_alignment(struct pt_regs *); +extern void cvt_fd(float *from, double *to, unsigned long *fpscr); +extern void cvt_df(double *from, float *to, unsigned long *fpscr); + +#ifdef CONFIG_ALTIVEC +extern void flush_altivec_to_thread(struct task_struct *); +#else +static inline void flush_altivec_to_thread(struct task_struct *t) +{ +} +#endif + +#ifdef CONFIG_SPE +extern void flush_spe_to_thread(struct task_struct *); +#else +static inline void flush_spe_to_thread(struct task_struct *t) +{ +} +#endif + +extern int call_rtas(const char *, int, int, unsigned long *, ...); +extern void cacheable_memzero(void *p, unsigned int nb); +extern void *cacheable_memcpy(void *, const void *, unsigned int); +extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); +extern void bad_page_fault(struct pt_regs *, unsigned long, int); +extern int die(const char *, struct pt_regs *, long); +extern void _exception(int, struct pt_regs *, int, unsigned long); +#ifdef CONFIG_BOOKE_WDT +extern u32 booke_wdt_enabled; +extern u32 booke_wdt_period; +#endif /* CONFIG_BOOKE_WDT */ + +/* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */ +extern unsigned char e2a(unsigned char); + +struct device_node; +extern void note_scsi_host(struct device_node *, void *); + +extern struct task_struct *__switch_to(struct task_struct *, + struct task_struct *); +#define switch_to(prev, next, last) ((last) = __switch_to((prev), (next))) + +struct thread_struct; +extern struct task_struct *_switch(struct thread_struct *prev, + struct thread_struct *next); + +extern unsigned int rtas_data; + +/* + * Atomic exchange + * + * Changes the memory location '*ptr' to be val and returns + * the previous value stored there. + */ +static __inline__ unsigned long +__xchg_u32(volatile void *p, unsigned long val) +{ + unsigned long prev; + + __asm__ __volatile__( + EIEIO_ON_SMP +"1: lwarx %0,0,%2 \n" + PPC405_ERR77(0,%2) +" stwcx. %3,0,%2 \n\ + bne- 1b" + ISYNC_ON_SMP + : "=&r" (prev), "=m" (*(volatile unsigned int *)p) + : "r" (p), "r" (val), "m" (*(volatile unsigned int *)p) + : "cc", "memory"); + + return prev; +} + +#ifdef CONFIG_PPC64 +static __inline__ unsigned long +__xchg_u64(volatile void *p, unsigned long val) +{ + unsigned long prev; + + __asm__ __volatile__( + EIEIO_ON_SMP +"1: ldarx %0,0,%2 \n" + PPC405_ERR77(0,%2) +" stdcx. %3,0,%2 \n\ + bne- 1b" + ISYNC_ON_SMP + : "=&r" (prev), "=m" (*(volatile unsigned long *)p) + : "r" (p), "r" (val), "m" (*(volatile unsigned long *)p) + : "cc", "memory"); + + return prev; +} +#endif + +/* + * This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid xchg(). + */ +extern void __xchg_called_with_bad_pointer(void); + +static __inline__ unsigned long +__xchg(volatile void *ptr, unsigned long x, unsigned int size) +{ + switch (size) { + case 4: + return __xchg_u32(ptr, x); +#ifdef CONFIG_PPC64 + case 8: + return __xchg_u64(ptr, x); +#endif + } + __xchg_called_with_bad_pointer(); + return x; +} + +#define xchg(ptr,x) \ + ({ \ + __typeof__(*(ptr)) _x_ = (x); \ + (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ + }) + +#define tas(ptr) (xchg((ptr),1)) + +/* + * Compare and exchange - if *p == old, set it to new, + * and return the old value of *p. + */ +#define __HAVE_ARCH_CMPXCHG 1 + +static __inline__ unsigned long +__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) +{ + unsigned int prev; + + __asm__ __volatile__ ( + EIEIO_ON_SMP +"1: lwarx %0,0,%2 # __cmpxchg_u32\n\ + cmpw 0,%0,%3\n\ + bne- 2f\n" + PPC405_ERR77(0,%2) +" stwcx. %4,0,%2\n\ + bne- 1b" + ISYNC_ON_SMP + "\n\ +2:" + : "=&r" (prev), "=m" (*p) + : "r" (p), "r" (old), "r" (new), "m" (*p) + : "cc", "memory"); + + return prev; +} + +#ifdef CONFIG_PPC64 +static __inline__ unsigned long +__cmpxchg_u64(volatile long *p, unsigned long old, unsigned long new) +{ + unsigned long prev; + + __asm__ __volatile__ ( + EIEIO_ON_SMP +"1: ldarx %0,0,%2 # __cmpxchg_u64\n\ + cmpd 0,%0,%3\n\ + bne- 2f\n\ + stdcx. %4,0,%2\n\ + bne- 1b" + ISYNC_ON_SMP + "\n\ +2:" + : "=&r" (prev), "=m" (*p) + : "r" (p), "r" (old), "r" (new), "m" (*p) + : "cc", "memory"); + + return prev; +} +#endif + +/* This function doesn't exist, so you'll get a linker error + if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +static __inline__ unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, + unsigned int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); +#ifdef CONFIG_PPC64 + case 8: + return __cmpxchg_u64(ptr, old, new); +#endif + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + +#ifdef CONFIG_PPC64 +/* + * We handle most unaligned accesses in hardware. On the other hand + * unaligned DMA can be very expensive on some ppc64 IO chips (it does + * powers of 2 writes until it reaches sufficient alignment). + * + * Based on this we disable the IP header alignment in network drivers. + */ +#define NET_IP_ALIGN 0 +#endif + +#define arch_align_stack(x) (x) + +#endif /* __KERNEL__ */ +#endif /* __PPC_SYSTEM_H */ diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index 829481c0a9dc..79c1be3dfe61 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -45,30 +45,21 @@ extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); extern void cpu_die(void) __attribute__((noreturn)); -#define NO_PROC_ID 0xFF /* No processor magic marker */ -#define PROC_CHANGE_PENALTY 20 - #define raw_smp_processor_id() (current_thread_info()->cpu) extern int __cpu_up(unsigned int cpu); extern int smp_hw_index[]; -#define hard_smp_processor_id() (smp_hw_index[smp_processor_id()]) - -struct klock_info_struct { - unsigned long kernel_flag; - unsigned char akp; -}; - -extern struct klock_info_struct klock_info; -#define KLOCK_HELD 0xffffffff -#define KLOCK_CLEAR 0x0 +#define hard_smp_processor_id() (smp_hw_index[smp_processor_id()]) +#define get_hard_smp_processor_id(cpu) (smp_hw_index[(cpu)]) #endif /* __ASSEMBLY__ */ #else /* !(CONFIG_SMP) */ static inline void cpu_die(void) { } +#define get_hard_smp_processor_id(cpu) 0 +#define hard_smp_processor_id() 0 #endif /* !(CONFIG_SMP) */ From bbeb3f4c55f666df7bcd2655b303dfb8c4d1a119 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 27 Sep 2005 13:51:59 +1000 Subject: [PATCH 0202/1939] powerpc: clean up after powermac build merge Complete moving arch/ppc64/kernel/mpic.h, include/asm-ppc/reg.h, include/asm-ppc64/kdebug.h and include/asm-ppc64/kprobes.h Add arch/powerpc/platforms/Makefile and use it from arch/powerpc/Makefile Introduce OLDARCH temporarily so we can point back to the originating architecture Signed-off-by: Stephen Rothwell --- arch/powerpc/Makefile | 31 +- arch/powerpc/platforms/Makefile | 4 + arch/powerpc/platforms/embedded6xx/Kconfig | 8 - arch/ppc64/kernel/kprobes.c | 1 - arch/ppc64/kernel/maple_setup.c | 3 +- arch/ppc64/kernel/mpic.c | 3 +- arch/ppc64/kernel/mpic.h | 273 ------------- arch/ppc64/kernel/pSeries_setup.c | 2 +- arch/ppc64/kernel/pSeries_smp.c | 2 +- arch/ppc64/kernel/pmac_setup.c | 2 +- arch/ppc64/kernel/pmac_smp.c | 3 +- arch/ppc64/kernel/rtas_pci.c | 2 +- arch/ppc64/kernel/smp.c | 3 +- arch/ppc64/kernel/traps.c | 4 +- include/asm-powerpc/kdebug.h | 6 +- include/asm-powerpc/kprobes.h | 7 +- include/asm-powerpc/mpic.h | 5 + include/asm-powerpc/reg.h | 6 +- include/asm-powerpc/system.h | 6 +- include/asm-ppc/reg.h | 440 --------------------- include/asm-ppc64/kdebug.h | 43 -- include/asm-ppc64/kprobes.h | 67 ---- 22 files changed, 41 insertions(+), 880 deletions(-) create mode 100644 arch/powerpc/platforms/Makefile delete mode 100644 arch/ppc64/kernel/mpic.h delete mode 100644 include/asm-ppc/reg.h delete mode 100644 include/asm-ppc64/kdebug.h delete mode 100644 include/asm-ppc64/kprobes.h diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 8a65e112211b..d94878193cd9 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -18,6 +18,7 @@ KERNELLOAD := $(CONFIG_KERNEL_START) HAS_BIARCH := $(call cc-option-yn, -m32) ifeq ($(CONFIG_PPC64),y) +OLDARCH := ppc64 SZ := 64 # Set default 32 bits cross compilers for vdso and boot wrapper @@ -46,6 +47,7 @@ NM := $(NM) --synthetic endif else +OLDARCH := ppc SZ := 32 endif @@ -61,11 +63,9 @@ LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic -e $(KERNELLOAD) CPPFLAGS += -Iarch/$(ARCH) -Iarch/$(ARCH)/include AFLAGS += -Iarch/$(ARCH) CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe -ifeq ($(CONFIG_PPC64),y) -CFLAGS += -mminimal-toc -mtraceback=none -mcall-aixdesc -else -CFLAGS += -ffixed-r2 -mmultiple -endif +CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc +CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple +CFLAGS += $(CFLAGS-y) CPP = $(CC) -E $(CFLAGS) # Temporary hack until we have migrated to asm-powerpc LINUXINCLUDE += -Iarch/$(ARCH)/include @@ -126,16 +126,12 @@ head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o endif core-y += arch/powerpc/kernel/ \ + arch/$(OLDARCH)/kernel/ \ arch/powerpc/mm/ \ arch/powerpc/lib/ \ - arch/powerpc/sysdev/ -core-$(CONFIG_PPC32) += arch/ppc/kernel/ \ - arch/ppc/syslib/ -core-$(CONFIG_PPC64) += arch/ppc64/kernel/ -core-$(CONFIG_PPC_PMAC) += arch/powerpc/platforms/powermac/ -core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ -core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ -core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ + arch/powerpc/sysdev/ \ + arch/powerpc/platforms/ +core-$(CONFIG_PPC32) += arch/ppc/syslib/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_APUS) += arch/ppc/amiga/ @@ -182,17 +178,10 @@ archclean: archprepare: checkbin # Temporary hack until we have migrated to asm-powerpc -ifeq ($(CONFIG_PPC64),y) include/asm: arch/$(ARCH)/include/asm arch/$(ARCH)/include/asm: $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi - $(Q)ln -fsn $(srctree)/include/asm-ppc64 arch/$(ARCH)/include/asm -else -include/asm: arch/$(ARCH)/include/asm -arch/$(ARCH)/include/asm: - $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi - $(Q)ln -fsn $(srctree)/include/asm-ppc arch/$(ARCH)/include/asm -endif + $(Q)ln -fsn $(srctree)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm # Use the file '.tmp_gas_check' for binutils tests, as gas won't output # to stdout and these checks are run even on install targets. diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile new file mode 100644 index 000000000000..dbc093759a89 --- /dev/null +++ b/arch/powerpc/platforms/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_PPC_PMAC) += powermac/ +obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_83xx) += 83xx/ +obj-$(CONFIG_85xx) += 85xx/ diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 4f3551430596..2d755b79d51f 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -2,14 +2,6 @@ choice prompt "Machine Type" depends on EMBEDDED6xx -config APUS - bool "Amiga-APUS" - depends on BROKEN - help - Select APUS if configuring for a PowerUP Amiga. - More information is available at: - . - config KATANA bool "Artesyn-Katana" help diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index 7e80d49c589a..abb90e67534a 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c @@ -395,7 +395,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, if (post_kprobe_handler(args->regs)) ret = NOTIFY_STOP; break; - case DIE_GPF: case DIE_PAGE_FAULT: if (kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index fc0567498a3a..2a7fae01eee1 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c @@ -59,8 +59,7 @@ #include #include #include - -#include "mpic.h" +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c index cc262a05ddb4..ec22321342ad 100644 --- a/arch/ppc64/kernel/mpic.c +++ b/arch/ppc64/kernel/mpic.c @@ -31,8 +31,7 @@ #include #include #include - -#include "mpic.h" +#include #ifdef DEBUG #define DBG(fmt...) printk(fmt) diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h deleted file mode 100644 index ca78a7f10528..000000000000 --- a/arch/ppc64/kernel/mpic.h +++ /dev/null @@ -1,273 +0,0 @@ -#include - -/* - * Global registers - */ - -#define MPIC_GREG_BASE 0x01000 - -#define MPIC_GREG_FEATURE_0 0x00000 -#define MPIC_GREG_FEATURE_LAST_SRC_MASK 0x07ff0000 -#define MPIC_GREG_FEATURE_LAST_SRC_SHIFT 16 -#define MPIC_GREG_FEATURE_LAST_CPU_MASK 0x00001f00 -#define MPIC_GREG_FEATURE_LAST_CPU_SHIFT 8 -#define MPIC_GREG_FEATURE_VERSION_MASK 0xff -#define MPIC_GREG_FEATURE_1 0x00010 -#define MPIC_GREG_GLOBAL_CONF_0 0x00020 -#define MPIC_GREG_GCONF_RESET 0x80000000 -#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_VENDOR_0 0x00040 -#define MPIC_GREG_VENDOR_1 0x00050 -#define MPIC_GREG_VENDOR_2 0x00060 -#define MPIC_GREG_VENDOR_3 0x00070 -#define MPIC_GREG_VENDOR_ID 0x00080 -#define MPIC_GREG_VENDOR_ID_STEPPING_MASK 0x00ff0000 -#define MPIC_GREG_VENDOR_ID_STEPPING_SHIFT 16 -#define MPIC_GREG_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00 -#define MPIC_GREG_VENDOR_ID_DEVICE_ID_SHIFT 8 -#define MPIC_GREG_VENDOR_ID_VENDOR_ID_MASK 0x000000ff -#define MPIC_GREG_PROCESSOR_INIT 0x00090 -#define MPIC_GREG_IPI_VECTOR_PRI_0 0x000a0 -#define MPIC_GREG_IPI_VECTOR_PRI_1 0x000b0 -#define MPIC_GREG_IPI_VECTOR_PRI_2 0x000c0 -#define MPIC_GREG_IPI_VECTOR_PRI_3 0x000d0 -#define MPIC_GREG_SPURIOUS 0x000e0 -#define MPIC_GREG_TIMER_FREQ 0x000f0 - -/* - * - * Timer registers - */ -#define MPIC_TIMER_BASE 0x01100 -#define MPIC_TIMER_STRIDE 0x40 - -#define MPIC_TIMER_CURRENT_CNT 0x00000 -#define MPIC_TIMER_BASE_CNT 0x00010 -#define MPIC_TIMER_VECTOR_PRI 0x00020 -#define MPIC_TIMER_DESTINATION 0x00030 - -/* - * Per-Processor registers - */ - -#define MPIC_CPU_THISBASE 0x00000 -#define MPIC_CPU_BASE 0x20000 -#define MPIC_CPU_STRIDE 0x01000 - -#define MPIC_CPU_IPI_DISPATCH_0 0x00040 -#define MPIC_CPU_IPI_DISPATCH_1 0x00050 -#define MPIC_CPU_IPI_DISPATCH_2 0x00060 -#define MPIC_CPU_IPI_DISPATCH_3 0x00070 -#define MPIC_CPU_CURRENT_TASK_PRI 0x00080 -#define MPIC_CPU_TASKPRI_MASK 0x0000000f -#define MPIC_CPU_WHOAMI 0x00090 -#define MPIC_CPU_WHOAMI_MASK 0x0000001f -#define MPIC_CPU_INTACK 0x000a0 -#define MPIC_CPU_EOI 0x000b0 - -/* - * Per-source registers - */ - -#define MPIC_IRQ_BASE 0x10000 -#define MPIC_IRQ_STRIDE 0x00020 -#define MPIC_IRQ_VECTOR_PRI 0x00000 -#define MPIC_VECPRI_MASK 0x80000000 -#define MPIC_VECPRI_ACTIVITY 0x40000000 /* Read Only */ -#define MPIC_VECPRI_PRIORITY_MASK 0x000f0000 -#define MPIC_VECPRI_PRIORITY_SHIFT 16 -#define MPIC_VECPRI_VECTOR_MASK 0x000007ff -#define MPIC_VECPRI_POLARITY_POSITIVE 0x00800000 -#define MPIC_VECPRI_POLARITY_NEGATIVE 0x00000000 -#define MPIC_VECPRI_POLARITY_MASK 0x00800000 -#define MPIC_VECPRI_SENSE_LEVEL 0x00400000 -#define MPIC_VECPRI_SENSE_EDGE 0x00000000 -#define MPIC_VECPRI_SENSE_MASK 0x00400000 -#define MPIC_IRQ_DESTINATION 0x00010 - -#define MPIC_MAX_IRQ_SOURCES 2048 -#define MPIC_MAX_CPUS 32 -#define MPIC_MAX_ISU 32 - -/* - * Special vector numbers (internal use only) - */ -#define MPIC_VEC_SPURRIOUS 255 -#define MPIC_VEC_IPI_3 254 -#define MPIC_VEC_IPI_2 253 -#define MPIC_VEC_IPI_1 252 -#define MPIC_VEC_IPI_0 251 - -/* unused */ -#define MPIC_VEC_TIMER_3 250 -#define MPIC_VEC_TIMER_2 249 -#define MPIC_VEC_TIMER_1 248 -#define MPIC_VEC_TIMER_0 247 - -/* Type definition of the cascade handler */ -typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); - -#ifdef CONFIG_MPIC_BROKEN_U3 -/* Fixup table entry */ -struct mpic_irq_fixup -{ - u8 __iomem *base; - unsigned int irq; -}; -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - -/* The instance data of a given MPIC */ -struct mpic -{ - /* The "linux" controller struct */ - hw_irq_controller hc_irq; -#ifdef CONFIG_SMP - hw_irq_controller hc_ipi; -#endif - const char *name; - /* Flags */ - unsigned int flags; - /* How many irq sources in a given ISU */ - unsigned int isu_size; - unsigned int isu_shift; - unsigned int isu_mask; - /* Offset of irq vector numbers */ - unsigned int irq_offset; - unsigned int irq_count; - /* Offset of ipi vector numbers */ - unsigned int ipi_offset; - /* Number of sources */ - unsigned int num_sources; - /* Number of CPUs */ - unsigned int num_cpus; - /* cascade handler */ - mpic_cascade_t cascade; - void *cascade_data; - unsigned int cascade_vec; - /* senses array */ - unsigned char *senses; - unsigned int senses_count; - -#ifdef CONFIG_MPIC_BROKEN_U3 - /* The fixup table */ - struct mpic_irq_fixup *fixups; - spinlock_t fixup_lock; -#endif - - /* The various ioremap'ed bases */ - volatile u32 __iomem *gregs; - volatile u32 __iomem *tmregs; - volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS]; - volatile u32 __iomem *isus[MPIC_MAX_ISU]; - - /* link */ - struct mpic *next; -}; - -/* This is the primary controller, only that one has IPIs and - * has afinity control. A non-primary MPIC always uses CPU0 - * registers only - */ -#define MPIC_PRIMARY 0x00000001 -/* Set this for a big-endian MPIC */ -#define MPIC_BIG_ENDIAN 0x00000002 -/* Broken U3 MPIC */ -#define MPIC_BROKEN_U3 0x00000004 -/* Broken IPI registers (autodetected) */ -#define MPIC_BROKEN_IPI 0x00000008 -/* MPIC wants a reset */ -#define MPIC_WANTS_RESET 0x00000010 - -/* Allocate the controller structure and setup the linux irq descs - * for the range if interrupts passed in. No HW initialization is - * actually performed. - * - * @phys_addr: physial base address of the MPIC - * @flags: flags, see constants above - * @isu_size: number of interrupts in an ISU. Use 0 to use a - * standard ISU-less setup (aka powermac) - * @irq_offset: first irq number to assign to this mpic - * @irq_count: number of irqs to use with this mpic IRQ sources. Pass 0 - * to match the number of sources - * @ipi_offset: first irq number to assign to this mpic IPI sources, - * used only on primary mpic - * @senses: array of sense values - * @senses_num: number of entries in the array - * - * Note about the sense array. If none is passed, all interrupts are - * setup to be level negative unless MPIC_BROKEN_U3 is set in which - * case they are edge positive (and the array is ignored anyway). - * The values in the array start at the first source of the MPIC, - * that is senses[0] correspond to linux irq "irq_offset". - */ -extern struct mpic *mpic_alloc(unsigned long phys_addr, - unsigned int flags, - unsigned int isu_size, - unsigned int irq_offset, - unsigned int irq_count, - unsigned int ipi_offset, - unsigned char *senses, - unsigned int senses_num, - const char *name); - -/* Assign ISUs, to call before mpic_init() - * - * @mpic: controller structure as returned by mpic_alloc() - * @isu_num: ISU number - * @phys_addr: physical address of the ISU - */ -extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, - unsigned long phys_addr); - -/* Initialize the controller. After this has been called, none of the above - * should be called again for this mpic - */ -extern void mpic_init(struct mpic *mpic); - -/* Setup a cascade. Currently, only one cascade is supported this - * way, though you can always do a normal request_irq() and add - * other cascades this way. You should call this _after_ having - * added all the ISUs - * - * @irq_no: "linux" irq number of the cascade (that is offset'ed vector) - * @handler: cascade handler function - */ -extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder, - void *data); - -/* - * All of the following functions must only be used after the - * ISUs have been assigned and the controller fully initialized - * with mpic_init() - */ - - -/* Change/Read the priority of an interrupt. Default is 8 for irqs and - * 10 for IPIs. You can call this on both IPIs and IRQ numbers, but the - * IPI number is then the offset'ed (linux irq number mapped to the IPI) - */ -extern void mpic_irq_set_priority(unsigned int irq, unsigned int pri); -extern unsigned int mpic_irq_get_priority(unsigned int irq); - -/* Setup a non-boot CPU */ -extern void mpic_setup_this_cpu(void); - -/* Clean up for kexec (or cpu offline or ...) */ -extern void mpic_teardown_this_cpu(int secondary); - -/* Request IPIs on primary mpic */ -extern void mpic_request_ipis(void); - -/* Send an IPI (non offseted number 0..3) */ -extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); - -/* Fetch interrupt from a given mpic */ -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); - -/* global mpic for pSeries */ -extern struct mpic *pSeries_mpic; diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 3009701eb90d..b9bcff21b463 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -62,9 +62,9 @@ #include #include #include +#include #include "i8259.h" -#include "mpic.h" #include "pci.h" #ifdef DEBUG diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index d2c7e2c4733b..5d1ed850f47b 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -46,8 +46,8 @@ #include #include #include +#include -#include "mpic.h" #include "bpa_iic.h" #ifdef DEBUG diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index bb0c3bfbb7e2..497c3cd95bc3 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -72,9 +72,9 @@ #include #include #include +#include #include "pmac.h" -#include "mpic.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index 9fd23ea55bc9..3a1683f5b07f 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -51,8 +51,7 @@ #include #include #include - -#include "mpic.h" +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 4a9719b48abe..4d920dd41dc6 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -38,8 +38,8 @@ #include #include #include +#include -#include "mpic.h" #include "pci.h" /* RTAS tokens */ diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 793b562da653..6f4f3da12a63 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -45,8 +45,7 @@ #include #include #include - -#include "mpic.h" +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index 5c4647b2c5f3..a728c9f0b53f 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -62,7 +62,7 @@ EXPORT_SYMBOL(__debugger_dabr_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif -struct notifier_block *ppc64_die_chain; +struct notifier_block *powerpc_die_chain; static DEFINE_SPINLOCK(die_notifier_lock); int register_die_notifier(struct notifier_block *nb) @@ -71,7 +71,7 @@ int register_die_notifier(struct notifier_block *nb) unsigned long flags; spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&ppc64_die_chain, nb); + err = notifier_chain_register(&powerpc_die_chain, nb); spin_unlock_irqrestore(&die_notifier_lock, flags); return err; } diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 7c55abf597f6..9dcbac674811 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h @@ -1,5 +1,5 @@ -#ifndef _POWERPC_KDEBUG_H -#define _POWERPC_KDEBUG_H 1 +#ifndef _ASM_POWERPC_KDEBUG_H +#define _ASM_POWERPC_KDEBUG_H /* nearly identical to x86_64/i386 code */ @@ -39,4 +39,4 @@ static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,lon return notifier_call_chain(&powerpc_die_chain, val, &args); } -#endif +#endif /* _ASM_POWERPC_KDEBUG_H */ diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index d9129d2b038e..b2f09f17fbe0 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -1,8 +1,7 @@ -#ifndef _ASM_KPROBES_H -#define _ASM_KPROBES_H +#ifndef _ASM_POWERPC_KPROBES_H +#define _ASM_POWERPC_KPROBES_H /* * Kernel Probes (KProbes) - * include/asm-ppc64/kprobes.h * * 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 @@ -64,4 +63,4 @@ static inline int kprobe_exceptions_notify(struct notifier_block *self, return 0; } #endif -#endif /* _ASM_KPROBES_H */ +#endif /* _ASM_POWERPC_KPROBES_H */ diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index f1e24f4b2d1c..6b558aeb9cb9 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -1,3 +1,6 @@ +#ifndef _ASM_POWERPC_MPIC_H +#define _ASM_POWERPC_MPIC_H + #include /* @@ -277,3 +280,5 @@ extern int mpic_get_irq(struct pt_regs *regs); /* global mpic for pSeries */ extern struct mpic *pSeries_mpic; + +#endif /* _ASM_POWERPC_MPIC_H */ diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index f97a5f1761b4..1402a2dedffb 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -6,9 +6,9 @@ * Implementations of the PowerPC Architecture (a.k.a. Green Book) here. */ +#ifndef _ASM_POWERPC_REGS_H +#define _ASM_POWERPC_REGS_H #ifdef __KERNEL__ -#ifndef __ASM_PPC_REGS_H__ -#define __ASM_PPC_REGS_H__ #include @@ -442,5 +442,5 @@ #define proc_trap() asm volatile("trap") #endif /* __ASSEMBLY__ */ -#endif /* __ASM_PPC_REGS_H__ */ #endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_REGS_H */ diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index be542efb32d3..1b64879a02c3 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -1,8 +1,8 @@ /* * Copyright (C) 1999 Cort Dougan */ -#ifndef __PPC_SYSTEM_H -#define __PPC_SYSTEM_H +#ifndef _ASM_POWERPC_SYSTEM_H +#define _ASM_POWERPC_SYSTEM_H #include #include @@ -347,4 +347,4 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, #define arch_align_stack(x) (x) #endif /* __KERNEL__ */ -#endif /* __PPC_SYSTEM_H */ +#endif /* _ASM_POWERPC_SYSTEM_H */ diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h deleted file mode 100644 index 73c33e3ef9c6..000000000000 --- a/include/asm-ppc/reg.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Contains the definition of registers common to all PowerPC variants. - * If a register definition has been changed in a different PowerPC - * variant, we will case it in #ifndef XXX ... #endif, and have the - * number used in the Programming Environments Manual For 32-Bit - * Implementations of the PowerPC Architecture (a.k.a. Green Book) here. - */ - -#ifdef __KERNEL__ -#ifndef __ASM_PPC_REGS_H__ -#define __ASM_PPC_REGS_H__ - -#include - -/* Pickup Book E specific registers. */ -#if defined(CONFIG_BOOKE) || defined(CONFIG_40x) -#include -#endif - -/* Machine State Register (MSR) Fields */ -#define MSR_SF (1<<63) -#define MSR_ISF (1<<61) -#define MSR_VEC (1<<25) /* Enable AltiVec */ -#define MSR_POW (1<<18) /* Enable Power Management */ -#define MSR_WE (1<<18) /* Wait State Enable */ -#define MSR_TGPR (1<<17) /* TLB Update registers in use */ -#define MSR_CE (1<<17) /* Critical Interrupt Enable */ -#define MSR_ILE (1<<16) /* Interrupt Little Endian */ -#define MSR_EE (1<<15) /* External Interrupt Enable */ -#define MSR_PR (1<<14) /* Problem State / Privilege Level */ -#define MSR_FP (1<<13) /* Floating Point enable */ -#define MSR_ME (1<<12) /* Machine Check Enable */ -#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ -#define MSR_SE (1<<10) /* Single Step */ -#define MSR_BE (1<<9) /* Branch Trace */ -#define MSR_DE (1<<9) /* Debug Exception Enable */ -#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ -#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ -#define MSR_IR (1<<5) /* Instruction Relocate */ -#define MSR_DR (1<<4) /* Data Relocate */ -#define MSR_PE (1<<3) /* Protection Enable */ -#define MSR_PX (1<<2) /* Protection Exclusive Mode */ -#define MSR_RI (1<<1) /* Recoverable Exception */ -#define MSR_LE (1<<0) /* Little Endian */ - -/* Default MSR for kernel mode. */ -#ifdef CONFIG_APUS_FAST_EXCEPT -#define MSR_KERNEL (MSR_ME|MSR_IP|MSR_RI|MSR_IR|MSR_DR) -#endif - -#ifndef MSR_KERNEL -#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) -#endif - -#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) - -/* Floating Point Status and Control Register (FPSCR) Fields */ -#define FPSCR_FX 0x80000000 /* FPU exception summary */ -#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ -#define FPSCR_VX 0x20000000 /* Invalid operation summary */ -#define FPSCR_OX 0x10000000 /* Overflow exception summary */ -#define FPSCR_UX 0x08000000 /* Underflow exception summary */ -#define FPSCR_ZX 0x04000000 /* Zero-devide exception summary */ -#define FPSCR_XX 0x02000000 /* Inexact exception summary */ -#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ -#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ -#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ -#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ -#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ -#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ -#define FPSCR_FR 0x00040000 /* Fraction rounded */ -#define FPSCR_FI 0x00020000 /* Fraction inexact */ -#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ -#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ -#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ -#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ -#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ -#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ -#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ -#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ -#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ -#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ -#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ -#define FPSCR_RN 0x00000003 /* FPU rounding control */ - -/* Special Purpose Registers (SPRNs)*/ -#define SPRN_CTR 0x009 /* Count Register */ -#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ -#define SPRN_DAR 0x013 /* Data Address Register */ -#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */ -#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */ -#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ -#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ -#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ -#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */ -#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */ -#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */ -#define SPRN_DBAT1U 0x21A /* Data BAT 1 Upper Register */ -#define SPRN_DBAT2L 0x21D /* Data BAT 2 Lower Register */ -#define SPRN_DBAT2U 0x21C /* Data BAT 2 Upper Register */ -#define SPRN_DBAT3L 0x21F /* Data BAT 3 Lower Register */ -#define SPRN_DBAT3U 0x21E /* Data BAT 3 Upper Register */ -#define SPRN_DBAT4L 0x239 /* Data BAT 4 Lower Register */ -#define SPRN_DBAT4U 0x238 /* Data BAT 4 Upper Register */ -#define SPRN_DBAT5L 0x23B /* Data BAT 5 Lower Register */ -#define SPRN_DBAT5U 0x23A /* Data BAT 5 Upper Register */ -#define SPRN_DBAT6L 0x23D /* Data BAT 6 Lower Register */ -#define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */ -#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */ -#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */ - -#define SPRN_DEC 0x016 /* Decrement Register */ -#define SPRN_DER 0x095 /* Debug Enable Regsiter */ -#define DER_RSTE 0x40000000 /* Reset Interrupt */ -#define DER_CHSTPE 0x20000000 /* Check Stop */ -#define DER_MCIE 0x10000000 /* Machine Check Interrupt */ -#define DER_EXTIE 0x02000000 /* External Interrupt */ -#define DER_ALIE 0x01000000 /* Alignment Interrupt */ -#define DER_PRIE 0x00800000 /* Program Interrupt */ -#define DER_FPUVIE 0x00400000 /* FP Unavailable Interrupt */ -#define DER_DECIE 0x00200000 /* Decrementer Interrupt */ -#define DER_SYSIE 0x00040000 /* System Call Interrupt */ -#define DER_TRE 0x00020000 /* Trace Interrupt */ -#define DER_SEIE 0x00004000 /* FP SW Emulation Interrupt */ -#define DER_ITLBMSE 0x00002000 /* Imp. Spec. Instruction TLB Miss */ -#define DER_ITLBERE 0x00001000 /* Imp. Spec. Instruction TLB Error */ -#define DER_DTLBMSE 0x00000800 /* Imp. Spec. Data TLB Miss */ -#define DER_DTLBERE 0x00000400 /* Imp. Spec. Data TLB Error */ -#define DER_LBRKE 0x00000008 /* Load/Store Breakpoint Interrupt */ -#define DER_IBRKE 0x00000004 /* Instruction Breakpoint Interrupt */ -#define DER_EBRKE 0x00000002 /* External Breakpoint Interrupt */ -#define DER_DPIE 0x00000001 /* Dev. Port Nonmaskable Request */ -#define SPRN_DMISS 0x3D0 /* Data TLB Miss Register */ -#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ -#define SPRN_EAR 0x11A /* External Address Register */ -#define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */ -#define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */ -#define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */ -#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ -#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ -#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ -#define HID0_SBCLK (1<<27) -#define HID0_EICE (1<<26) -#define HID0_TBEN (1<<26) /* Timebase enable - 745x */ -#define HID0_ECLK (1<<25) -#define HID0_PAR (1<<24) -#define HID0_STEN (1<<24) /* Software table search enable - 745x */ -#define HID0_HIGH_BAT (1<<23) /* Enable high BATs - 7455 */ -#define HID0_DOZE (1<<23) -#define HID0_NAP (1<<22) -#define HID0_SLEEP (1<<21) -#define HID0_DPM (1<<20) -#define HID0_BHTCLR (1<<18) /* Clear branch history table - 7450 */ -#define HID0_XAEN (1<<17) /* Extended addressing enable - 7450 */ -#define HID0_NHR (1<<16) /* Not hard reset (software bit-7450)*/ -#define HID0_ICE (1<<15) /* Instruction Cache Enable */ -#define HID0_DCE (1<<14) /* Data Cache Enable */ -#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ -#define HID0_DLOCK (1<<12) /* Data Cache Lock */ -#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ -#define HID0_DCI (1<<10) /* Data Cache Invalidate */ -#define HID0_SPD (1<<9) /* Speculative disable */ -#define HID0_DAPUEN (1<<8) /* Debug APU enable */ -#define HID0_SGE (1<<7) /* Store Gathering Enable */ -#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ -#define HID0_DFCA (1<<6) /* Data Cache Flush Assist */ -#define HID0_LRSTK (1<<4) /* Link register stack - 745x */ -#define HID0_BTIC (1<<5) /* Branch Target Instr Cache Enable */ -#define HID0_ABE (1<<3) /* Address Broadcast Enable */ -#define HID0_FOLD (1<<3) /* Branch Folding enable - 745x */ -#define HID0_BHTE (1<<2) /* Branch History Table Enable */ -#define HID0_BTCD (1<<1) /* Branch target cache disable */ -#define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */ -#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */ - -#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ -#define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */ -#define HID1_DFS (1<<22) /* 7447A Dynamic Frequency Scaling */ -#define HID1_PC0 (1<<16) /* 7450 PLL_CFG[0] */ -#define HID1_PC1 (1<<15) /* 7450 PLL_CFG[1] */ -#define HID1_PC2 (1<<14) /* 7450 PLL_CFG[2] */ -#define HID1_PC3 (1<<13) /* 7450 PLL_CFG[3] */ -#define HID1_SYNCBE (1<<11) /* 7450 ABE for sync, eieio */ -#define HID1_ABE (1<<10) /* 7450 Address Broadcast Enable */ -#define HID1_PS (1<<16) /* 750FX PLL selection */ -#define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ -#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ -#define SPRN_HID4 0x3F4 /* 970 HID4 */ -#define SPRN_HID5 0x3F6 /* 970 HID5 */ -#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2) -#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */ -#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */ -#endif -#define SPRN_IBAT0L 0x211 /* Instruction BAT 0 Lower Register */ -#define SPRN_IBAT0U 0x210 /* Instruction BAT 0 Upper Register */ -#define SPRN_IBAT1L 0x213 /* Instruction BAT 1 Lower Register */ -#define SPRN_IBAT1U 0x212 /* Instruction BAT 1 Upper Register */ -#define SPRN_IBAT2L 0x215 /* Instruction BAT 2 Lower Register */ -#define SPRN_IBAT2U 0x214 /* Instruction BAT 2 Upper Register */ -#define SPRN_IBAT3L 0x217 /* Instruction BAT 3 Lower Register */ -#define SPRN_IBAT3U 0x216 /* Instruction BAT 3 Upper Register */ -#define SPRN_IBAT4L 0x231 /* Instruction BAT 4 Lower Register */ -#define SPRN_IBAT4U 0x230 /* Instruction BAT 4 Upper Register */ -#define SPRN_IBAT5L 0x233 /* Instruction BAT 5 Lower Register */ -#define SPRN_IBAT5U 0x232 /* Instruction BAT 5 Upper Register */ -#define SPRN_IBAT6L 0x235 /* Instruction BAT 6 Lower Register */ -#define SPRN_IBAT6U 0x234 /* Instruction BAT 6 Upper Register */ -#define SPRN_IBAT7L 0x237 /* Instruction BAT 7 Lower Register */ -#define SPRN_IBAT7U 0x236 /* Instruction BAT 7 Upper Register */ -#define SPRN_ICMP 0x3D5 /* Instruction TLB Compare Register */ -#define SPRN_ICTC 0x3FB /* Instruction Cache Throttling Control Reg */ -#define SPRN_ICTRL 0x3F3 /* 1011 7450 icache and interrupt ctrl */ -#define ICTRL_EICE 0x08000000 /* enable icache parity errs */ -#define ICTRL_EDC 0x04000000 /* enable dcache parity errs */ -#define ICTRL_EICP 0x00000100 /* enable icache par. check */ -#define SPRN_IMISS 0x3D4 /* Instruction TLB Miss Register */ -#define SPRN_IMMR 0x27E /* Internal Memory Map Register */ -#define SPRN_L2CR 0x3F9 /* Level 2 Cache Control Regsiter */ -#define SPRN_L2CR2 0x3f8 -#define L2CR_L2E 0x80000000 /* L2 enable */ -#define L2CR_L2PE 0x40000000 /* L2 parity enable */ -#define L2CR_L2SIZ_MASK 0x30000000 /* L2 size mask */ -#define L2CR_L2SIZ_256KB 0x10000000 /* L2 size 256KB */ -#define L2CR_L2SIZ_512KB 0x20000000 /* L2 size 512KB */ -#define L2CR_L2SIZ_1MB 0x30000000 /* L2 size 1MB */ -#define L2CR_L2CLK_MASK 0x0e000000 /* L2 clock mask */ -#define L2CR_L2CLK_DISABLED 0x00000000 /* L2 clock disabled */ -#define L2CR_L2CLK_DIV1 0x02000000 /* L2 clock / 1 */ -#define L2CR_L2CLK_DIV1_5 0x04000000 /* L2 clock / 1.5 */ -#define L2CR_L2CLK_DIV2 0x08000000 /* L2 clock / 2 */ -#define L2CR_L2CLK_DIV2_5 0x0a000000 /* L2 clock / 2.5 */ -#define L2CR_L2CLK_DIV3 0x0c000000 /* L2 clock / 3 */ -#define L2CR_L2RAM_MASK 0x01800000 /* L2 RAM type mask */ -#define L2CR_L2RAM_FLOW 0x00000000 /* L2 RAM flow through */ -#define L2CR_L2RAM_PIPE 0x01000000 /* L2 RAM pipelined */ -#define L2CR_L2RAM_PIPE_LW 0x01800000 /* L2 RAM pipelined latewr */ -#define L2CR_L2DO 0x00400000 /* L2 data only */ -#define L2CR_L2I 0x00200000 /* L2 global invalidate */ -#define L2CR_L2CTL 0x00100000 /* L2 RAM control */ -#define L2CR_L2WT 0x00080000 /* L2 write-through */ -#define L2CR_L2TS 0x00040000 /* L2 test support */ -#define L2CR_L2OH_MASK 0x00030000 /* L2 output hold mask */ -#define L2CR_L2OH_0_5 0x00000000 /* L2 output hold 0.5 ns */ -#define L2CR_L2OH_1_0 0x00010000 /* L2 output hold 1.0 ns */ -#define L2CR_L2SL 0x00008000 /* L2 DLL slow */ -#define L2CR_L2DF 0x00004000 /* L2 differential clock */ -#define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */ -#define L2CR_L2IP 0x00000001 /* L2 GI in progress */ -#define L2CR_L2IO_745x 0x00100000 /* L2 instr. only (745x) */ -#define L2CR_L2DO_745x 0x00010000 /* L2 data only (745x) */ -#define L2CR_L2REP_745x 0x00001000 /* L2 repl. algorithm (745x) */ -#define L2CR_L2HWF_745x 0x00000800 /* L2 hardware flush (745x) */ -#define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter */ -#define L3CR_L3E 0x80000000 /* L3 enable */ -#define L3CR_L3PE 0x40000000 /* L3 data parity enable */ -#define L3CR_L3APE 0x20000000 /* L3 addr parity enable */ -#define L3CR_L3SIZ 0x10000000 /* L3 size */ -#define L3CR_L3CLKEN 0x08000000 /* L3 clock enable */ -#define L3CR_L3RES 0x04000000 /* L3 special reserved bit */ -#define L3CR_L3CLKDIV 0x03800000 /* L3 clock divisor */ -#define L3CR_L3IO 0x00400000 /* L3 instruction only */ -#define L3CR_L3SPO 0x00040000 /* L3 sample point override */ -#define L3CR_L3CKSP 0x00030000 /* L3 clock sample point */ -#define L3CR_L3PSP 0x0000e000 /* L3 P-clock sample point */ -#define L3CR_L3REP 0x00001000 /* L3 replacement algorithm */ -#define L3CR_L3HWF 0x00000800 /* L3 hardware flush */ -#define L3CR_L3I 0x00000400 /* L3 global invalidate */ -#define L3CR_L3RT 0x00000300 /* L3 SRAM type */ -#define L3CR_L3NIRCA 0x00000080 /* L3 non-integer ratio clock adj. */ -#define L3CR_L3DO 0x00000040 /* L3 data only mode */ -#define L3CR_PMEN 0x00000004 /* L3 private memory enable */ -#define L3CR_PMSIZ 0x00000001 /* L3 private memory size */ -#define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */ -#define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */ -#define SPRN_LDSTCR 0x3f8 /* Load/Store control register */ -#define SPRN_LDSTDB 0x3f4 /* */ -#define SPRN_LR 0x008 /* Link Register */ -#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ -#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ -#ifndef SPRN_PIR -#define SPRN_PIR 0x3FF /* Processor Identification Register */ -#endif -#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ -#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ -#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ -#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ -#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_PVR 0x11F /* Processor Version Register */ -#define SPRN_RPA 0x3D6 /* Required Physical Address Register */ -#define SPRN_SDA 0x3BF /* Sampled Data Address Register */ -#define SPRN_SDR1 0x019 /* MMU Hash Base Register */ -#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ -#define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ -#define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ -#define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ -#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ -#define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */ -#define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */ -#define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */ -#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */ -#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ -#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ -#ifndef SPRN_SVR -#define SPRN_SVR 0x11E /* System Version Register */ -#endif -#define SPRN_THRM1 0x3FC /* Thermal Management Register 1 */ -/* these bits were defined in inverted endian sense originally, ugh, confusing */ -#define THRM1_TIN (1 << 31) -#define THRM1_TIV (1 << 30) -#define THRM1_THRES(x) ((x&0x7f)<<23) -#define THRM3_SITV(x) ((x&0x3fff)<<1) -#define THRM1_TID (1<<2) -#define THRM1_TIE (1<<1) -#define THRM1_V (1<<0) -#define SPRN_THRM2 0x3FD /* Thermal Management Register 2 */ -#define SPRN_THRM3 0x3FE /* Thermal Management Register 3 */ -#define THRM3_E (1<<0) -#define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */ -#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */ -#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */ -#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */ -#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */ -#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ -#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ -#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ -#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ -#define SPRN_XER 0x001 /* Fixed Point Exception Register */ - -/* Bit definitions for MMCR0 and PMC1 / PMC2. */ -#define MMCR0_PMC1_CYCLES (1 << 7) -#define MMCR0_PMC1_ICACHEMISS (5 << 7) -#define MMCR0_PMC1_DTLB (6 << 7) -#define MMCR0_PMC2_DCACHEMISS 0x6 -#define MMCR0_PMC2_CYCLES 0x1 -#define MMCR0_PMC2_ITLB 0x7 -#define MMCR0_PMC2_LOADMISSTIME 0x5 -#define MMCR0_PMXE (1 << 26) - -/* Processor Version Register */ - -/* Processor Version Register (PVR) field extraction */ - -#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ -#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ - -/* - * IBM has further subdivided the standard PowerPC 16-bit version and - * revision subfields of the PVR for the PowerPC 403s into the following: - */ - -#define PVR_FAM(pvr) (((pvr) >> 20) & 0xFFF) /* Family field */ -#define PVR_MEM(pvr) (((pvr) >> 16) & 0xF) /* Member field */ -#define PVR_CORE(pvr) (((pvr) >> 12) & 0xF) /* Core field */ -#define PVR_CFG(pvr) (((pvr) >> 8) & 0xF) /* Configuration field */ -#define PVR_MAJ(pvr) (((pvr) >> 4) & 0xF) /* Major revision field */ -#define PVR_MIN(pvr) (((pvr) >> 0) & 0xF) /* Minor revision field */ - -/* Processor Version Numbers */ - -#define PVR_403GA 0x00200000 -#define PVR_403GB 0x00200100 -#define PVR_403GC 0x00200200 -#define PVR_403GCX 0x00201400 -#define PVR_405GP 0x40110000 -#define PVR_STB03XXX 0x40310000 -#define PVR_NP405H 0x41410000 -#define PVR_NP405L 0x41610000 -#define PVR_601 0x00010000 -#define PVR_602 0x00050000 -#define PVR_603 0x00030000 -#define PVR_603e 0x00060000 -#define PVR_603ev 0x00070000 -#define PVR_603r 0x00071000 -#define PVR_604 0x00040000 -#define PVR_604e 0x00090000 -#define PVR_604r 0x000A0000 -#define PVR_620 0x00140000 -#define PVR_740 0x00080000 -#define PVR_750 PVR_740 -#define PVR_740P 0x10080000 -#define PVR_750P PVR_740P -#define PVR_7400 0x000C0000 -#define PVR_7410 0x800C0000 -#define PVR_7450 0x80000000 -#define PVR_8540 0x80200000 -#define PVR_8560 0x80200000 -/* - * For the 8xx processors, all of them report the same PVR family for - * the PowerPC core. The various versions of these processors must be - * differentiated by the version number in the Communication Processor - * Module (CPM). - */ -#define PVR_821 0x00500000 -#define PVR_823 PVR_821 -#define PVR_850 PVR_821 -#define PVR_860 PVR_821 -#define PVR_8240 0x00810100 -#define PVR_8245 0x80811014 -#define PVR_8260 PVR_8240 - -#if 0 -/* Segment Registers */ -#define SR0 0 -#define SR1 1 -#define SR2 2 -#define SR3 3 -#define SR4 4 -#define SR5 5 -#define SR6 6 -#define SR7 7 -#define SR8 8 -#define SR9 9 -#define SR10 10 -#define SR11 11 -#define SR12 12 -#define SR13 13 -#define SR14 14 -#define SR15 15 -#endif - -/* Macros for setting and retrieving special purpose registers */ -#ifndef __ASSEMBLY__ -#define mfmsr() ({unsigned int rval; \ - asm volatile("mfmsr %0" : "=r" (rval)); rval;}) -#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) - -#define mfspr(rn) ({unsigned int rval; \ - asm volatile("mfspr %0," __stringify(rn) \ - : "=r" (rval)); rval;}) -#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) - -#define mfsrin(v) ({unsigned int rval; \ - asm volatile("mfsrin %0,%1" : "=r" (rval) : "r" (v)); \ - rval;}) - -#define proc_trap() asm volatile("trap") -#endif /* __ASSEMBLY__ */ -#endif /* __ASM_PPC_REGS_H__ */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc64/kdebug.h b/include/asm-ppc64/kdebug.h deleted file mode 100644 index d383d161cf8d..000000000000 --- a/include/asm-ppc64/kdebug.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _PPC64_KDEBUG_H -#define _PPC64_KDEBUG_H 1 - -/* nearly identical to x86_64/i386 code */ - -#include - -struct pt_regs; - -struct die_args { - struct pt_regs *regs; - const char *str; - long err; - int trapnr; - int signr; -}; - -/* - Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *ppc64_die_chain; - -/* Grossly misnamed. */ -enum die_val { - DIE_OOPS = 1, - DIE_IABR_MATCH, - DIE_DABR_MATCH, - DIE_BPT, - DIE_SSTEP, - DIE_GPF, - DIE_PAGE_FAULT, -}; - -static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) -{ - struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; - return notifier_call_chain(&ppc64_die_chain, val, &args); -} - -#endif diff --git a/include/asm-ppc64/kprobes.h b/include/asm-ppc64/kprobes.h deleted file mode 100644 index d9129d2b038e..000000000000 --- a/include/asm-ppc64/kprobes.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _ASM_KPROBES_H -#define _ASM_KPROBES_H -/* - * Kernel Probes (KProbes) - * include/asm-ppc64/kprobes.h - * - * 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. - * - * Copyright (C) IBM Corporation, 2002, 2004 - * - * 2002-Oct Created by Vamsi Krishna S Kernel - * Probes initial implementation ( includes suggestions from - * Rusty Russell). - * 2004-Nov Modified for PPC64 by Ananth N Mavinakayanahalli - * - */ -#include -#include - -struct pt_regs; - -typedef unsigned int kprobe_opcode_t; -#define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */ -#define MAX_INSN_SIZE 1 - -#define IS_TW(instr) (((instr) & 0xfc0007fe) == 0x7c000008) -#define IS_TD(instr) (((instr) & 0xfc0007fe) == 0x7c000088) -#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) -#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) - -#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) - -#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ - IS_TWI(instr) || IS_TDI(instr)) - -#define ARCH_SUPPORTS_KRETPROBES -void kretprobe_trampoline(void); - -/* Architecture specific copy of original instruction */ -struct arch_specific_insn { - /* copy of original instruction */ - kprobe_opcode_t *insn; -}; - -#ifdef CONFIG_KPROBES -extern int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data); -#else /* !CONFIG_KPROBES */ -static inline int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - return 0; -} -#endif -#endif /* _ASM_KPROBES_H */ From e607d98369dbd8e7b33b19664d1729a8a81fe7cd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 27 Sep 2005 14:24:18 +1000 Subject: [PATCH 0203/1939] ppc64: Fix typo in iommu cleanups that broke pmac build. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- include/asm-ppc64/dart.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-ppc64/dart.h b/include/asm-ppc64/dart.h index a9000de8a2e3..cdf8a2dec05f 100644 --- a/include/asm-ppc64/dart.h +++ b/include/asm-ppc64/dart.h @@ -51,9 +51,9 @@ #define DARTMAP_RPNMASK 0x00ffffff -#define DART_SHIFT 12 -#define DART_PAGE_SIZE (1 << DART_SHIFT) -#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_SHIFT) +#define DART_PAGE_SHIFT 12 +#define DART_PAGE_SIZE (1 << DART_PAGE_SHIFT) +#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_PAGE_SHIFT) #endif From 6b67f62cf655c80147435544a2f8f6f57e07ec87 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 27 Sep 2005 14:09:39 +1000 Subject: [PATCH 0204/1939] [PATCH] ppc64 g5: merge tree build fix We removed __pmacdata in the merge. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/macintosh/smu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index a85ac18dd21d..5f283529620b 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -1092,7 +1092,7 @@ static int smu_release(struct inode *inode, struct file *file) } -static struct file_operations smu_device_fops __pmacdata = { +static struct file_operations smu_device_fops = { .llseek = no_llseek, .read = smu_read, .write = smu_write, @@ -1101,7 +1101,7 @@ static struct file_operations smu_device_fops __pmacdata = { .release = smu_release, }; -static struct miscdevice pmu_device __pmacdata = { +static struct miscdevice pmu_device = { MISC_DYNAMIC_MINOR, "smu", &smu_device_fops }; From ba0dd617a3e23321a14cb38ff7ad6f796ba32c34 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 23 Sep 2005 13:15:51 +1000 Subject: [PATCH 0205/1939] powerpc: Create arch/powerpc/platforms/iseries I also move arch/ppc64/kernel/HvCall.c to arch/powerpc/platforms/iseries/hvcall.c. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/Makefile | 9 +++++---- arch/powerpc/platforms/iseries/Makefile | 1 + .../HvCall.c => powerpc/platforms/iseries/hvcall.c} | 1 - arch/ppc64/Makefile | 1 + arch/ppc64/kernel/Makefile | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/Makefile rename arch/{ppc64/kernel/HvCall.c => powerpc/platforms/iseries/hvcall.c} (98%) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index dbc093759a89..697addea192f 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,4 +1,5 @@ -obj-$(CONFIG_PPC_PMAC) += powermac/ -obj-$(CONFIG_4xx) += 4xx/ -obj-$(CONFIG_83xx) += 83xx/ -obj-$(CONFIG_85xx) += 85xx/ +obj-$(CONFIG_PPC_PMAC) += powermac/ +obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_83xx) += 83xx/ +obj-$(CONFIG_85xx) += 85xx/ +obj-$(CONFIG_PPC_ISERIES) += iseries/ diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile new file mode 100644 index 000000000000..af0c7d97121d --- /dev/null +++ b/arch/powerpc/platforms/iseries/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PPC_ISERIES) += hvcall.o diff --git a/arch/ppc64/kernel/HvCall.c b/arch/powerpc/platforms/iseries/hvcall.c similarity index 98% rename from arch/ppc64/kernel/HvCall.c rename to arch/powerpc/platforms/iseries/hvcall.c index b772e65b57a2..f61e2e9ac9ec 100644 --- a/arch/ppc64/kernel/HvCall.c +++ b/arch/powerpc/platforms/iseries/hvcall.c @@ -1,5 +1,4 @@ /* - * HvCall.c * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 40675b3f924d..d4eb55f82f03 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -84,6 +84,7 @@ head-y := arch/ppc64/kernel/head.o libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ core-y += arch/ppc64/mm/ +core-y += arch/powerpc/platforms/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index afadb6e4a6dc..aba3895b74d4 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \ +obj-$(CONFIG_PPC_ISERIES) += HvLpConfig.o LparData.o \ iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o From acdbec1b8974f61b0cb69ebe57916f8721b2f3d7 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 23 Sep 2005 13:23:58 +1000 Subject: [PATCH 0206/1939] powerpc: Move HvLpConfig.c to powerpc arch Also rename it to hvlpconfig.c Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../HvLpConfig.c => powerpc/platforms/iseries/hvlpconfig.c} | 1 - arch/ppc64/kernel/Makefile | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) rename arch/{ppc64/kernel/HvLpConfig.c => powerpc/platforms/iseries/hvlpconfig.c} (98%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index af0c7d97121d..3b7a31d4acda 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-$(CONFIG_PPC_ISERIES) += hvcall.o +obj-$(CONFIG_PPC_ISERIES) += hvcall.o hvlpconfig.o diff --git a/arch/ppc64/kernel/HvLpConfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c similarity index 98% rename from arch/ppc64/kernel/HvLpConfig.c rename to arch/powerpc/platforms/iseries/hvlpconfig.c index cb1d6473203c..dc28621aea0d 100644 --- a/arch/ppc64/kernel/HvLpConfig.c +++ b/arch/powerpc/platforms/iseries/hvlpconfig.c @@ -1,5 +1,4 @@ /* - * HvLpConfig.c * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index aba3895b74d4..c80b6174231e 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += HvLpConfig.o LparData.o \ +obj-$(CONFIG_PPC_ISERIES) += LparData.o \ iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o From 2960eb661a82131b9492cdd1b6500a5f74ccc394 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 23 Sep 2005 13:42:26 +1000 Subject: [PATCH 0207/1939] powerpc: Move LparData.c to powerpc platforms Also rename it to lpardata.c Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../platforms/iseries/lpardata.c} | 18 +++++++++--------- arch/ppc64/kernel/Makefile | 3 +-- arch/ppc64/kernel/head.S | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) rename arch/{ppc64/kernel/LparData.c => powerpc/platforms/iseries/lpardata.c} (98%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 3b7a31d4acda..095471d50d9f 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-$(CONFIG_PPC_ISERIES) += hvcall.o hvlpconfig.o +obj-$(CONFIG_PPC_ISERIES) += hvcall.o hvlpconfig.o lpardata.o diff --git a/arch/ppc64/kernel/LparData.c b/arch/powerpc/platforms/iseries/lpardata.c similarity index 98% rename from arch/ppc64/kernel/LparData.c rename to arch/powerpc/platforms/iseries/lpardata.c index 0a9c23ca2f0c..87b7ad8ca465 100644 --- a/arch/ppc64/kernel/LparData.c +++ b/arch/powerpc/platforms/iseries/lpardata.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2001 Mike Corrigan, IBM Corp * * This program is free software; you can redistribute it and/or @@ -29,8 +29,8 @@ #include -/* The HvReleaseData is the root of the information shared between - * the hypervisor and Linux. +/* The HvReleaseData is the root of the information shared between + * the hypervisor and Linux. */ struct HvReleaseData hvReleaseData = { .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ @@ -79,7 +79,7 @@ extern void trap_0e_iSeries(void); extern void performance_monitor_iSeries(void); extern void data_access_slb_iSeries(void); extern void instruction_access_slb_iSeries(void); - + struct ItLpNaca itLpNaca = { .xDesc = 0xd397d581, /* "LpNa" ebcdic */ .xSize = 0x0400, /* size of ItLpNaca */ @@ -106,7 +106,7 @@ struct ItLpNaca itLpNaca = { .xLoadAreaChunks = 0, /* chunks for load area */ .xPaseSysCallCRMask = 0, /* PASE mask */ .xSlicSegmentTablePtr = 0, /* seg table */ - .xOldLpQueue = { 0 }, /* Old LP Queue */ + .xOldLpQueue = { 0 }, /* Old LP Queue */ .xInterruptHdlr = { (u64)system_reset_iSeries, /* 0x100 System Reset */ (u64)machine_check_iSeries, /* 0x200 Machine Check */ @@ -134,7 +134,7 @@ struct ItLpNaca itLpNaca = { EXPORT_SYMBOL(itLpNaca); /* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); +struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); /* May be filled in by the hypervisor so cannot end up in the BSS */ struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); @@ -151,7 +151,7 @@ struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { .xPVR = 0x3600 } }; - + /* Space for Main Store Vpd 27,200 bytes */ /* May be filled in by the hypervisor so cannot end up in the BSS */ u64 xMsVpd[3400] __attribute__((__section__(".data"))); @@ -197,7 +197,7 @@ struct ItVpdAreas itVpdAreas = { 26992, /* 7 length of MS VPD */ 0, /* 8 */ sizeof(struct ItLpNaca),/* 9 length of LP Naca */ - 0, /* 10 */ + 0, /* 10 */ 256, /* 11 length of Recovery Log Buf */ sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ 0,0,0, /* 13 - 15 */ @@ -207,7 +207,7 @@ struct ItVpdAreas itVpdAreas = { 0,0 /* 24 - 25 */ }, .xSlicVpdAdrs = { /* VPD addresses */ - 0,0,0, /* 0 - 2 */ + 0,0,0, /* 0 - 2 */ &xItExtVpdPanel, /* 3 Extended VPD */ &paca[0], /* 4 first Paca */ 0, /* 5 */ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index c80b6174231e..4d95f0d0137a 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,8 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += LparData.o \ - iSeries_setup.o ItLpQueue.o hvCall.o \ +obj-$(CONFIG_PPC_ISERIES) += iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index eb526c480b6c..db0cd3587627 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1253,7 +1253,7 @@ unrecov_slb: * * On iSeries, the hypervisor must fill in at least one entry before * we get control (with relocate on). The address is give to the hv - * as a page number (see xLparMap in LparData.c), so this must be at a + * as a page number (see xLparMap in lpardata.c), so this must be at a * fixed address (the linker can't compute (u64)&initial_stab >> * PAGE_SHIFT). */ From c8b84976f86adcd10c221d398e1d0be2b778f3c8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 27 Sep 2005 18:44:42 +1000 Subject: [PATCH 0208/1939] powerpc: move iSeries_setup.[ch] and mf.c into platforms/iseries iSeries_setup.c becomes setup.c iSeries_setup.h becomes setup.h mf.c retains its name Also moved iSeries_[gs]et_rtc_time and iSeries_get_boot_time into mf.c since they are just small wrappers around mf_ functions. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../kernel => powerpc/platforms/iseries}/mf.c | 85 +++++++++++++------ .../platforms/iseries/setup.c} | 5 +- .../platforms/iseries/setup.h} | 2 - arch/ppc64/kernel/Makefile | 4 +- arch/ppc64/kernel/rtc.c | 37 -------- 6 files changed, 65 insertions(+), 70 deletions(-) rename arch/{ppc64/kernel => powerpc/platforms/iseries}/mf.c (94%) rename arch/{ppc64/kernel/iSeries_setup.c => powerpc/platforms/iseries/setup.c} (99%) rename arch/{ppc64/kernel/iSeries_setup.h => powerpc/platforms/iseries/setup.h} (96%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 095471d50d9f..f5e11907cab1 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-$(CONFIG_PPC_ISERIES) += hvcall.o hvlpconfig.o lpardata.o +obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o diff --git a/arch/ppc64/kernel/mf.c b/arch/powerpc/platforms/iseries/mf.c similarity index 94% rename from arch/ppc64/kernel/mf.c rename to arch/powerpc/platforms/iseries/mf.c index ef4a338ebd01..82f5abab9afa 100644 --- a/arch/ppc64/kernel/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -1,29 +1,28 @@ /* - * mf.c - * Copyright (C) 2001 Troy D. Armstrong IBM Corporation - * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation - * - * This modules exists as an interface between a Linux secondary partition - * running on an iSeries and the primary partition's Virtual Service - * Processor (VSP) object. The VSP has final authority over powering on/off - * all partitions in the iSeries. It also provides miscellaneous low-level - * machine facility type operations. - * - * - * 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 - */ + * Copyright (C) 2001 Troy D. Armstrong IBM Corporation + * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation + * + * This modules exists as an interface between a Linux secondary partition + * running on an iSeries and the primary partition's Virtual Service + * Processor (VSP) object. The VSP has final authority over powering on/off + * all partitions in the iSeries. It also provides miscellaneous low-level + * machine facility type operations. + * + * + * 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 @@ -42,6 +41,10 @@ #include #include +#include "setup.h" + +extern int piranha_simulator; + /* * This is the structure layout for the Machine Facilites LPAR event * flows. @@ -1279,3 +1282,35 @@ static int __init mf_proc_init(void) __initcall(mf_proc_init); #endif /* CONFIG_PROC_FS */ + +/* + * Get the RTC from the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +void iSeries_get_rtc_time(struct rtc_time *rtc_tm) +{ + if (piranha_simulator) + return; + + mf_get_rtc(rtc_tm); + rtc_tm->tm_mon--; +} + +/* + * Set the RTC in the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +int iSeries_set_rtc_time(struct rtc_time *tm) +{ + mf_set_rtc(tm); + return 0; +} + +void iSeries_get_boot_time(struct rtc_time *tm) +{ + if (piranha_simulator) + return; + + mf_get_boot_rtc(tm); + tm->tm_mon -= 1; +} diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/powerpc/platforms/iseries/setup.c similarity index 99% rename from arch/ppc64/kernel/iSeries_setup.c rename to arch/powerpc/platforms/iseries/setup.c index 9daf734adbd5..ad78c8581a5a 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -2,8 +2,6 @@ * Copyright (c) 2000 Mike Corrigan * Copyright (c) 1999-2000 Grant Erickson * - * Module name: iSeries_setup.c - * * Description: * Architecture- / platform-specific boot-time initialization code for * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and @@ -42,7 +40,6 @@ #include #include -#include "iSeries_setup.h" #include #include #include @@ -62,6 +59,8 @@ #include #include +#include "setup.h" + extern void hvlog(char *fmt, ...); #ifdef DEBUG diff --git a/arch/ppc64/kernel/iSeries_setup.h b/arch/powerpc/platforms/iseries/setup.h similarity index 96% rename from arch/ppc64/kernel/iSeries_setup.h rename to arch/powerpc/platforms/iseries/setup.h index c6eb29a245ac..6da89ae991ce 100644 --- a/arch/ppc64/kernel/iSeries_setup.h +++ b/arch/powerpc/platforms/iseries/setup.h @@ -2,8 +2,6 @@ * Copyright (c) 2000 Mike Corrigan * Copyright (c) 1999-2000 Grant Erickson * - * Module name: as400_setup.h - * * Description: * Architecture- / platform-specific boot-time initialization code for * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 4d95f0d0137a..b558cc0f4d9e 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,8 +22,8 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_setup.o ItLpQueue.o hvCall.o \ - mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ +obj-$(CONFIG_PPC_ISERIES) += ItLpQueue.o hvCall.o \ + HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 6ff52bc61325..88ae13f81c46 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -43,11 +43,8 @@ #include #include -#include #include -extern int piranha_simulator; - /* * We sponge a minor off of the misc major. No need slurping * up another valuable major dev number for this. If you add @@ -265,40 +262,6 @@ static int rtc_read_proc(char *page, char **start, off_t off, return len; } -#ifdef CONFIG_PPC_ISERIES -/* - * Get the RTC from the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -void iSeries_get_rtc_time(struct rtc_time *rtc_tm) -{ - if (piranha_simulator) - return; - - mf_get_rtc(rtc_tm); - rtc_tm->tm_mon--; -} - -/* - * Set the RTC in the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -int iSeries_set_rtc_time(struct rtc_time *tm) -{ - mf_set_rtc(tm); - return 0; -} - -void iSeries_get_boot_time(struct rtc_time *tm) -{ - if ( piranha_simulator ) - return; - - mf_get_boot_rtc(tm); - tm->tm_mon -= 1; -} -#endif - #ifdef CONFIG_PPC_RTAS #define MAX_RTC_WAIT 5000 /* 5 sec */ #define RTAS_CLOCK_BUSY (-2) From 2952bc7c896ec76a20e18321e2be40a694a73a78 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 00:03:46 +1000 Subject: [PATCH 0209/1939] powerpc: move ItLpQueue.c to powerpc/platforms/iseries Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../kernel/ItLpQueue.c => powerpc/platforms/iseries/lpevents.c} | 1 - arch/ppc64/kernel/Makefile | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) rename arch/{ppc64/kernel/ItLpQueue.c => powerpc/platforms/iseries/lpevents.c} (99%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index f5e11907cab1..a5e91c9db5c7 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o +obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/powerpc/platforms/iseries/lpevents.c similarity index 99% rename from arch/ppc64/kernel/ItLpQueue.c rename to arch/powerpc/platforms/iseries/lpevents.c index 4231861288a3..819298a8a4db 100644 --- a/arch/ppc64/kernel/ItLpQueue.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -1,5 +1,4 @@ /* - * ItLpQueue.c * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index b558cc0f4d9e..e3bce4dda502 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += ItLpQueue.o hvCall.o \ +obj-$(CONFIG_PPC_ISERIES) += hvCall.o \ HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o From 99a2379cdddcc4e8579e70deb80479450ed65d49 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 00:17:40 +1000 Subject: [PATCH 0210/1939] powerpc: move hvCall.s to powerpc/platforms/iseries Rename it to hvcall.S and (so I can do that) rename hvcall.c to hvlog.c - a more appropriate name. Do some white space cleanups. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../platforms/iseries/hvcall.S} | 21 +++++++------------ .../platforms/iseries/{hvcall.c => hvlog.c} | 0 arch/ppc64/kernel/Makefile | 3 +-- 4 files changed, 10 insertions(+), 16 deletions(-) rename arch/{ppc64/kernel/hvCall.S => powerpc/platforms/iseries/hvcall.S} (96%) rename arch/powerpc/platforms/iseries/{hvcall.c => hvlog.c} (100%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index a5e91c9db5c7..3a9981a35e2a 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o +obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o hvcall.o diff --git a/arch/ppc64/kernel/hvCall.S b/arch/powerpc/platforms/iseries/hvcall.S similarity index 96% rename from arch/ppc64/kernel/hvCall.S rename to arch/powerpc/platforms/iseries/hvcall.S index 4c699eab1b95..9901c0ec1415 100644 --- a/arch/ppc64/kernel/hvCall.S +++ b/arch/powerpc/platforms/iseries/hvcall.S @@ -1,7 +1,4 @@ /* - * arch/ppc64/kernel/hvCall.S - * - * * This file contains the code to perform calls to the * iSeries LPAR hypervisor * @@ -16,12 +13,12 @@ .text -/* +/* * Hypervisor call - * + * * Invoke the iSeries hypervisor via the System Call instruction * Parameters are passed to this routine in registers r3 - r10 - * + * * r3 contains the HV function to be called * r4-r10 contain the operands to the hypervisor function * @@ -41,11 +38,11 @@ _GLOBAL(HvCall7) mfcr r0 std r0,-8(r1) stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) - + /* r0 = 0xffffffffffffffff indicates a hypervisor call */ - + li r0,-1 - + /* Invoke the hypervisor */ sc @@ -55,7 +52,7 @@ _GLOBAL(HvCall7) mtcrf 0xff,r0 /* return to caller, return value in r3 */ - + blr _GLOBAL(HvCall0Ret16) @@ -92,7 +89,5 @@ _GLOBAL(HvCall7Ret16) ld r0,-8(r1) mtcrf 0xff,r0 ld r31,-16(r1) - + blr - - diff --git a/arch/powerpc/platforms/iseries/hvcall.c b/arch/powerpc/platforms/iseries/hvlog.c similarity index 100% rename from arch/powerpc/platforms/iseries/hvcall.c rename to arch/powerpc/platforms/iseries/hvlog.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index e3bce4dda502..f84ae358db0a 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,8 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += hvCall.o \ - HvLpEvent.o iSeries_proc.o iSeries_htab.o \ +obj-$(CONFIG_PPC_ISERIES) += HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o From 544cbbaed4de962fb0e831e8799ab01c448ff37d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:18:47 +1000 Subject: [PATCH 0211/1939] powerpc: Merge HvLpEvent.c into lpevents.c These two files were intimately connected, so just merge them. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/lpevents.c | 68 +++++++++++++++++- arch/ppc64/kernel/HvLpEvent.c | 88 ----------------------- arch/ppc64/kernel/Makefile | 2 +- 3 files changed, 68 insertions(+), 90 deletions(-) delete mode 100644 arch/ppc64/kernel/HvLpEvent.c diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index 819298a8a4db..883603027ccf 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * The LpQueue is used to pass event data from the hypervisor to @@ -42,7 +43,8 @@ static char *event_types[HvLpEvent_Type_NumTypes] = { }; /* Array of LpEvent handler functions */ -extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; static struct HvLpEvent * get_next_hvlpevent(void) { @@ -198,6 +200,70 @@ void setup_hvlpevent_queue(void) hvlpevent_queue.xIndex = 0; } +/* Register a handler for an LpEvent type */ +int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler) +{ + if (eventType < HvLpEvent_Type_NumTypes) { + lpEventHandler[eventType] = handler; + return 0; + } + return 1; +} +EXPORT_SYMBOL(HvLpEvent_registerHandler); + +int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) +{ + might_sleep(); + + if (eventType < HvLpEvent_Type_NumTypes) { + if (!lpEventHandlerPaths[eventType]) { + lpEventHandler[eventType] = NULL; + /* + * We now sleep until all other CPUs have scheduled. + * This ensures that the deletion is seen by all + * other CPUs, and that the deleted handler isn't + * still running on another CPU when we return. + */ + synchronize_rcu(); + return 0; + } + } + return 1; +} +EXPORT_SYMBOL(HvLpEvent_unregisterHandler); + +/* + * lpIndex is the partition index of the target partition. + * needed only for VirtualIo, VirtualLan and SessionMgr. Zero + * indicates to use our partition index - for the other types. + */ +int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex) +{ + if ((eventType < HvLpEvent_Type_NumTypes) && + lpEventHandler[eventType]) { + if (lpIndex == 0) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_openLpEventPath(lpIndex, eventType); + ++lpEventHandlerPaths[eventType]; + return 0; + } + return 1; +} + +int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex) +{ + if ((eventType < HvLpEvent_Type_NumTypes) && + lpEventHandler[eventType] && + lpEventHandlerPaths[eventType]) { + if (lpIndex == 0) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_closeLpEventPath(lpIndex, eventType); + --lpEventHandlerPaths[eventType]; + return 0; + } + return 1; +} + static int proc_lpevents_show(struct seq_file *m, void *v) { int cpu, i; diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c deleted file mode 100644 index 90032b138902..000000000000 --- a/arch/ppc64/kernel/HvLpEvent.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2001 Mike Corrigan 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 - -/* Array of LpEvent handler functions */ -LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; -unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; - -/* Register a handler for an LpEvent type */ - -int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes ) { - lpEventHandler[eventType] = handler; - rc = 0; - } - return rc; - -} - -int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ) -{ - int rc = 1; - - might_sleep(); - - if ( eventType < HvLpEvent_Type_NumTypes ) { - if ( !lpEventHandlerPaths[eventType] ) { - lpEventHandler[eventType] = NULL; - rc = 0; - - /* We now sleep until all other CPUs have scheduled. This ensures that - * the deletion is seen by all other CPUs, and that the deleted handler - * isn't still running on another CPU when we return. */ - synchronize_rcu(); - } - } - return rc; -} -EXPORT_SYMBOL(HvLpEvent_registerHandler); -EXPORT_SYMBOL(HvLpEvent_unregisterHandler); - -/* (lpIndex is the partition index of the target partition. - * needed only for VirtualIo, VirtualLan and SessionMgr. Zero - * indicates to use our partition index - for the other types) - */ -int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes && - lpEventHandler[eventType] ) { - if ( lpIndex == 0 ) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_openLpEventPath( lpIndex, eventType ); - ++lpEventHandlerPaths[eventType]; - rc = 0; - } - return rc; -} - -int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes && - lpEventHandler[eventType] && - lpEventHandlerPaths[eventType] ) { - if ( lpIndex == 0 ) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_closeLpEventPath( lpIndex, eventType ); - --lpEventHandlerPaths[eventType]; - rc = 0; - } - return rc; -} - diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index f84ae358db0a..a4e5c5b86c74 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += HvLpEvent.o iSeries_proc.o iSeries_htab.o \ +obj-$(CONFIG_PPC_ISERIES) += iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o From cb5c7980ab16c461a883ec7899675be57798d285 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:24:05 +1000 Subject: [PATCH 0212/1939] powerpc: move iSeries_proc.c to powerpc/platforms/iseries And renamed it to proc.c Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 3 ++- .../platforms/iseries/proc.c} | 10 ++++++---- arch/ppc64/kernel/Makefile | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) rename arch/{ppc64/kernel/iSeries_proc.c => powerpc/platforms/iseries/proc.c} (93%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 3a9981a35e2a..0bd671573c87 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1,2 @@ -obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o hvcall.o +obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ + hvcall.o proc.o diff --git a/arch/ppc64/kernel/iSeries_proc.c b/arch/powerpc/platforms/iseries/proc.c similarity index 93% rename from arch/ppc64/kernel/iSeries_proc.c rename to arch/powerpc/platforms/iseries/proc.c index 0fe3116eba29..d46b473ce4dd 100644 --- a/arch/ppc64/kernel/iSeries_proc.c +++ b/arch/powerpc/platforms/iseries/proc.c @@ -1,5 +1,4 @@ /* - * iSeries_proc.c * Copyright (C) 2001 Kyle A. Lucke IBM Corporation * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation * @@ -68,12 +67,15 @@ static int proc_titantod_show(struct seq_file *m, void *v) unsigned long tb_ticks = (tb0 - startTb); unsigned long titan_jiffies = titan_usec / (1000000/HZ); unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); - unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec; + unsigned long titan_jiff_rem_usec = + titan_usec - titan_jiff_usec; unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; - unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec; - unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec; + unsigned long tb_jiff_rem_usec = + tb_jiff_rem_ticks / tb_ticks_per_usec; + unsigned long new_tb_ticks_per_jiffy = + (tb_ticks * (1000000/HZ))/titan_usec; seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index a4e5c5b86c74..271b71d20d15 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_proc.o iSeries_htab.o \ +obj-$(CONFIG_PPC_ISERIES) += iSeries_htab.o \ iSeries_iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o From e508f438e0c152dcd1fbec5104e9c0ee28f352d4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:28:45 +1000 Subject: [PATCH 0213/1939] powerpc: Move iSeries_htab.c to powerpc/platforms/iseries And rename it to htab.c Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../platforms/iseries/htab.c} | 25 ++++++++++--------- arch/ppc64/kernel/Makefile | 3 +-- 3 files changed, 15 insertions(+), 15 deletions(-) rename arch/{ppc64/kernel/iSeries_htab.c => powerpc/platforms/iseries/htab.c} (94%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 0bd671573c87..4ef588c1b606 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,2 +1,2 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ - hvcall.o proc.o + hvcall.o proc.o htab.o diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/powerpc/platforms/iseries/htab.c similarity index 94% rename from arch/ppc64/kernel/iSeries_htab.c rename to arch/powerpc/platforms/iseries/htab.c index 9a2be3abf349..431b22767d06 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/powerpc/platforms/iseries/htab.c @@ -1,10 +1,10 @@ /* * iSeries hashtable management. - * Derived from pSeries_htab.c + * Derived from pSeries_htab.c * * SMP scalability work: * Copyright (C) 2001 Anton Blanchard , IBM - * + * * 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 @@ -18,7 +18,8 @@ #include #include -static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = { [0 ... 63] = SPIN_LOCK_UNLOCKED}; +static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = + { [0 ... 63] = SPIN_LOCK_UNLOCKED}; /* * Very primitive algorithm for picking up a lock @@ -126,7 +127,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); if (! (hpte_v & HPTE_V_BOLTED)) { - HvCallHpt_invalidateSetSwBitsGet(hpte_group + + HvCallHpt_invalidateSetSwBitsGet(hpte_group + slot_offset, 0, 0); iSeries_hunlock(hpte_group); return i; @@ -143,9 +144,9 @@ static long iSeries_hpte_remove(unsigned long hpte_group) /* * The HyperVisor expects the "flags" argument in this form: - * bits 0..59 : reserved - * bit 60 : N - * bits 61..63 : PP2,PP1,PP0 + * bits 0..59 : reserved + * bit 60 : N + * bits 61..63 : PP2,PP1,PP0 */ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, int large, int local) @@ -171,7 +172,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, } /* - * Functions used to find the PTE for a particular virtual address. + * Functions used to find the PTE for a particular virtual address. * Only used during boot when bolting pages. * * Input : vpn : virtual page number @@ -189,7 +190,7 @@ static long iSeries_hpte_find(unsigned long vpn) * 0x00000000xxxxxxxx : Entry found in primary group, slot x * 0x80000000xxxxxxxx : Entry found in secondary group, slot x */ - slot = HvCallHpt_findValid(&hpte, vpn); + slot = HvCallHpt_findValid(&hpte, vpn); if (hpte.v & HPTE_V_VALID) { if (slot < 0) { slot &= 0x7fffffffffffffff; @@ -216,7 +217,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> PAGE_SHIFT; - slot = iSeries_hpte_find(vpn); + slot = iSeries_hpte_find(vpn); if (slot == -1) panic("updateboltedpp: Could not find page to bolt\n"); HvCallHpt_setPp(slot, newpp); @@ -234,7 +235,7 @@ static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, iSeries_hlock(slot); hpte_v = iSeries_hpte_getword0(slot); - + if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); @@ -249,7 +250,7 @@ void hpte_init_iSeries(void) ppc_md.hpte_updatepp = iSeries_hpte_updatepp; ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; ppc_md.hpte_insert = iSeries_hpte_insert; - ppc_md.hpte_remove = iSeries_hpte_remove; + ppc_md.hpte_remove = iSeries_hpte_remove; htab_finish_init(); } diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 271b71d20d15..9225a6704e8a 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,8 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_htab.o \ - iSeries_iommu.o +obj-$(CONFIG_PPC_ISERIES) += iSeries_iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o From cc14d430837e8854bd160275ad71d887a8a98488 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:32:16 +1000 Subject: [PATCH 0214/1939] powerpc: Move iSeries_iommu.c to powerpc/platforms/iseries And rename it to iommu.c Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../iSeries_iommu.c => powerpc/platforms/iseries/iommu.c} | 2 -- arch/ppc64/kernel/Makefile | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) rename arch/{ppc64/kernel/iSeries_iommu.c => powerpc/platforms/iseries/iommu.c} (99%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 4ef588c1b606..bf3992bf7ff8 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,2 +1,2 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ - hvcall.o proc.o htab.o + hvcall.o proc.o htab.o iommu.o diff --git a/arch/ppc64/kernel/iSeries_iommu.c b/arch/powerpc/platforms/iseries/iommu.c similarity index 99% rename from arch/ppc64/kernel/iSeries_iommu.c rename to arch/powerpc/platforms/iseries/iommu.c index 287db32d9867..65c76dd1d3de 100644 --- a/arch/ppc64/kernel/iSeries_iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -1,6 +1,4 @@ /* - * arch/ppc64/kernel/iSeries_iommu.c - * * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation * * Rewrite, cleanup: diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 9225a6704e8a..5988d555d36d 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,8 +22,6 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_iommu.o - obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ From d387899f3f7092edbafe16d69ea9737846473e99 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:50:25 +1000 Subject: [PATCH 0215/1939] powerpc: Move iSeries_pci.c to powerpc/platform/iseries and rename it to pci.c. This also required moving arch/ppc64/kernel/pci.h into include/asm-powerpc (called ppc-pci.h. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 1 + .../platforms/iseries/pci.c} | 66 +++++++++---------- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/bpa_iommu.c | 2 +- arch/ppc64/kernel/bpa_setup.c | 2 +- arch/ppc64/kernel/eeh.c | 2 +- arch/ppc64/kernel/maple_pci.c | 3 +- arch/ppc64/kernel/pSeries_iommu.c | 2 +- arch/ppc64/kernel/pSeries_pci.c | 3 +- arch/ppc64/kernel/pSeries_setup.c | 2 +- arch/ppc64/kernel/pci.c | 3 +- arch/ppc64/kernel/pci_direct_iommu.c | 3 +- arch/ppc64/kernel/pci_dn.c | 3 +- arch/ppc64/kernel/pci_iommu.c | 2 +- arch/ppc64/kernel/pmac_pci.c | 2 +- arch/ppc64/kernel/rtas_pci.c | 3 +- arch/ppc64/kernel/sys_ppc32.c | 3 +- arch/ppc64/kernel/u3_iommu.c | 3 +- .../pci.h => include/asm-powerpc/ppc-pci.h | 6 +- 19 files changed, 52 insertions(+), 61 deletions(-) rename arch/{ppc64/kernel/iSeries_pci.c => powerpc/platforms/iseries/pci.c} (95%) rename arch/ppc64/kernel/pci.h => include/asm-powerpc/ppc-pci.h (94%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index bf3992bf7ff8..7ee4592f83d3 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,2 +1,3 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/powerpc/platforms/iseries/pci.c similarity index 95% rename from arch/ppc64/kernel/iSeries_pci.c rename to arch/powerpc/platforms/iseries/pci.c index fbc273c32bcc..61a857218bc8 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -1,28 +1,26 @@ /* - * iSeries_pci.c - * * Copyright (C) 2001 Allan Trautman, IBM Corporation * * iSeries specific routines for PCI. - * + * * Based on code from pci.c and iSeries_pci.c 32bit * * 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 @@ -43,12 +41,12 @@ #include #include -#include "pci.h" +#include extern unsigned long io_page_mask; /* - * Forward declares of prototypes. + * Forward declares of prototypes. */ static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn); static void scan_PHB_slots(struct pci_controller *Phb); @@ -68,7 +66,7 @@ static long Pci_Cfg_Write_Count; #endif static long Pci_Error_Count; -static int Pci_Retry_Max = 3; /* Only retry 3 times */ +static int Pci_Retry_Max = 3; /* Only retry 3 times */ static int Pci_Error_Flag = 1; /* Set Retry Error on. */ static struct pci_ops iSeries_pci_ops; @@ -179,7 +177,7 @@ static void allocate_device_bars(struct pci_dev *dev) for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) { bar_res = &dev->resource[bar_num]; iomm_table_allocate_entry(dev, bar_num); - } + } } /* @@ -278,28 +276,28 @@ unsigned long __init find_and_init_phbs(void) /* * iSeries_pcibios_init - * + * * Chance to initialize and structures or variable before PCI Bus walk. */ void iSeries_pcibios_init(void) { - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); iomm_table_initialize(); find_and_init_phbs(); io_page_mask = -1; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); } /* - * iSeries_pci_final_fixup(void) + * iSeries_pci_final_fixup(void) */ void __init iSeries_pci_final_fixup(void) { struct pci_dev *pdev = NULL; struct iSeries_Device_Node *node; - int DeviceCount = 0; + int DeviceCount = 0; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); /* Fix up at the device node and pci_dev relationship */ mf_display_src(0xC9000100); @@ -332,24 +330,24 @@ void __init iSeries_pci_final_fixup(void) void pcibios_fixup_bus(struct pci_bus *PciBus) { PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n", - PciBus->number); + PciBus->number); } void pcibios_fixup_resources(struct pci_dev *pdev) { PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); -} +} /* - * Loop through each node function to find usable EADs bridges. + * Loop through each node function to find usable EADs bridges. */ static void scan_PHB_slots(struct pci_controller *Phb) { struct HvCallPci_DeviceInfo *DevInfo; - HvBusNumber bus = Phb->local_number; /* System Bus */ + HvBusNumber bus = Phb->local_number; /* System Bus */ const HvSubBusNumber SubBus = 0; /* EADs is always 0. */ int HvRc = 0; - int IdSel; + int IdSel; const int MaxAgents = 8; DevInfo = (struct HvCallPci_DeviceInfo*) @@ -358,10 +356,10 @@ static void scan_PHB_slots(struct pci_controller *Phb) return; /* - * Probe for EADs Bridges + * Probe for EADs Bridges */ for (IdSel = 1; IdSel < MaxAgents; ++IdSel) { - HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, + HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, ISERIES_HV_ADDR(DevInfo), sizeof(struct HvCallPci_DeviceInfo)); if (HvRc == 0) { @@ -393,19 +391,19 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, /* Note: hvSubBus and irq is always be 0 at this level! */ for (Function = 0; Function < 8; ++Function) { - AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + AgentId = ISERIES_PCI_AGENTID(IdSel, Function); HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0); - if (HvRc == 0) { + if (HvRc == 0) { printk("found device at bus %d idsel %d func %d (AgentId %x)\n", bus, IdSel, Function, AgentId); - /* Connect EADs: 0x18.00.12 = 0x00 */ + /* Connect EADs: 0x18.00.12 = 0x00 */ PPCDBG(PPCDBG_BUSWALK, "PCI:Connect EADs: 0x%02X.%02X.%02X\n", bus, SubBus, AgentId); - HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, + HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, ISERIES_HV_ADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo)); - if (HvRc == 0) { + if (HvRc == 0) { printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n", BridgeInfo->busUnitInfo.deviceType, BridgeInfo->subBusNumber, @@ -428,7 +426,7 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, printk("PCI: Invalid Bridge Configuration(0x%02X)", BridgeInfo->busUnitInfo.deviceType); } - } else if (HvRc != 0x000B) + } else if (HvRc != 0x000B) pci_Log_Error("EADs Connect", bus, SubBus, AgentId, HvRc); } @@ -451,16 +449,16 @@ static int scan_bridge_slot(HvBusNumber Bus, HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ - Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); + Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); PPCDBG(PPCDBG_BUSWALK, "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n", Bus, 0, EADsIdSel, Irq); /* - * Connect all functions of any device found. + * Connect all functions of any device found. */ - for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { - for (Function = 0; Function < 8; ++Function) { + for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { + for (Function = 0; Function < 8; ++Function) { HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq); @@ -484,7 +482,7 @@ static int scan_bridge_slot(HvBusNumber Bus, "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n", Bus, SubBus, AgentId, VendorId, Irq); HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, - PCI_INTERRUPT_LINE, Irq); + PCI_INTERRUPT_LINE, Irq); if (HvRc != 0) pci_Log_Error("PciCfgStore Irq Failed!", Bus, SubBus, AgentId, HvRc); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 5988d555d36d..8473a8784567 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,7 +16,7 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_irq.o \ +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o diff --git a/arch/ppc64/kernel/bpa_iommu.c b/arch/ppc64/kernel/bpa_iommu.c index f33a7bccb0d7..0cc463f24539 100644 --- a/arch/ppc64/kernel/bpa_iommu.c +++ b/arch/ppc64/kernel/bpa_iommu.c @@ -39,8 +39,8 @@ #include #include #include +#include -#include "pci.h" #include "bpa_iommu.h" static inline unsigned long diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c index 57b3db66f458..9f915f4222b1 100644 --- a/arch/ppc64/kernel/bpa_setup.c +++ b/arch/ppc64/kernel/bpa_setup.c @@ -43,8 +43,8 @@ #include #include #include +#include -#include "pci.h" #include "bpa_iic.h" #include "bpa_iommu.h" diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c index ba93fd731222..035d1b14a207 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/ppc64/kernel/eeh.c @@ -33,7 +33,7 @@ #include #include #include -#include "pci.h" +#include #undef DEBUG diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 1d297e0edfc0..0937649f4961 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -23,8 +23,7 @@ #include #include #include - -#include "pci.h" +#include #ifdef DEBUG #define DBG(x...) printk(x) diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 5914f61a152e..9e90d41131d8 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -47,7 +47,7 @@ #include #include #include -#include "pci.h" +#include #define DBG(fmt...) diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 1f5f141fb7a1..2dd477eb1c53 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c @@ -29,8 +29,7 @@ #include #include - -#include "pci.h" +#include static int __initdata s7a_workaround = -1; diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index b9bcff21b463..5a9fe96f9f67 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -63,9 +63,9 @@ #include #include #include +#include #include "i8259.h" -#include "pci.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index ff4be1da69d5..feec06bbafc3 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -31,8 +31,7 @@ #include #include #include - -#include "pci.h" +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pci_direct_iommu.c b/arch/ppc64/kernel/pci_direct_iommu.c index b8f7f58824f4..57980a5674d7 100644 --- a/arch/ppc64/kernel/pci_direct_iommu.c +++ b/arch/ppc64/kernel/pci_direct_iommu.c @@ -27,8 +27,7 @@ #include #include #include - -#include "pci.h" +#include static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, unsigned int __nocast flag) diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index a86389d07d57..493bbe43f5b4 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c @@ -30,8 +30,7 @@ #include #include #include - -#include "pci.h" +#include /* * Traverse_func that inits the PCI fields of the device node. diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index 14647e09c9cd..19362ea11572 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -37,7 +37,7 @@ #include #include #include -#include "pci.h" +#include #ifdef CONFIG_PPC_ISERIES #include diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index 1f61aa4746ec..f139fc034199 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -27,8 +27,8 @@ #include #include #include +#include -#include "pci.h" #include "pmac.h" #define DEBUG diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 4d920dd41dc6..20361bcd8cfb 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -39,8 +39,7 @@ #include #include #include - -#include "pci.h" +#include /* RTAS tokens */ static int read_pci_config; diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index e93c13458910..1cacf61f9c91 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -53,8 +53,7 @@ #include #include #include - -#include "pci.h" +#include /* readdir & getdents */ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c index df9c775f4955..fba871a1bda5 100644 --- a/arch/ppc64/kernel/u3_iommu.c +++ b/arch/ppc64/kernel/u3_iommu.c @@ -45,8 +45,7 @@ #include #include #include - -#include "pci.h" +#include extern int iommu_force_on; diff --git a/arch/ppc64/kernel/pci.h b/include/asm-powerpc/ppc-pci.h similarity index 94% rename from arch/ppc64/kernel/pci.h rename to include/asm-powerpc/ppc-pci.h index 5eb2cc320566..a88728fba8f6 100644 --- a/arch/ppc64/kernel/pci.h +++ b/include/asm-powerpc/ppc-pci.h @@ -6,8 +6,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#ifndef __PPC_KERNEL_PCI_H__ -#define __PPC_KERNEL_PCI_H__ +#ifndef _ASM_POWERPC_PPC_PCI_H +#define _ASM_POWERPC_PPC_PCI_H #include #include @@ -51,4 +51,4 @@ extern unsigned long pci_probe_only; extern unsigned long pci_assign_all_buses; extern int pci_read_irq_line(struct pci_dev *pci_dev); -#endif /* __PPC_KERNEL_PCI_H__ */ +#endif /* _ASM_POWERPC_PPC_PCI_H */ From cb4cf8056ead24ef0595859952319e2a608d5e07 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:54:39 +1000 Subject: [PATCH 0216/1939] powerpc: Move iSeries_irq.c to powerpc/platorms/iseries And rename it to irq.c. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../kernel/iSeries_irq.c => powerpc/platforms/iseries/irq.c} | 1 - arch/ppc64/kernel/Makefile | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) rename arch/{ppc64/kernel/iSeries_irq.c => powerpc/platforms/iseries/irq.c} (99%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 7ee4592f83d3..e5d6ab9e30bb 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,3 +1,3 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o -obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_PCI) += pci.o irq.o diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/powerpc/platforms/iseries/irq.c similarity index 99% rename from arch/ppc64/kernel/iSeries_irq.c rename to arch/powerpc/platforms/iseries/irq.c index 0170682a8ca5..5a8a0056b31f 100644 --- a/arch/ppc64/kernel/iSeries_irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -363,4 +363,3 @@ void virt_irq_init(void) { return; } - diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 8473a8784567..2ff5d490e725 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,8 +16,7 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ - iSeries_VpdInfo.o +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) From da3420fcd62a8967c14a586355e322253a1504a8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 02:59:19 +1000 Subject: [PATCH 0217/1939] powerpc: Move iSeries_VpdInfo.c to powerpc/platforms/iseries And rename it to vpdinfo.c. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 2 +- .../iSeries_VpdInfo.c => powerpc/platforms/iseries/vpdinfo.c} | 2 -- arch/ppc64/kernel/Makefile | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) rename arch/{ppc64/kernel/iSeries_VpdInfo.c => powerpc/platforms/iseries/vpdinfo.c} (98%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index e5d6ab9e30bb..d10305d7ad2f 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,3 +1,3 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o -obj-$(CONFIG_PCI) += pci.o irq.o +obj-$(CONFIG_PCI) += pci.o irq.o vpdinfo.o diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c similarity index 98% rename from arch/ppc64/kernel/iSeries_VpdInfo.c rename to arch/powerpc/platforms/iseries/vpdinfo.c index 5d921792571f..8b62f3bf1d26 100644 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -1,6 +1,4 @@ /* - * File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. - * * This code gets the card location of the hardware * Copyright (C) 2001 * Copyright (C) 2005 Stephen Rothwel, IBM Corp diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 2ff5d490e725..8b2743697c38 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,7 +16,6 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) From ed7f2c05de956da72baf066701ac642f7215dbf5 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 03:03:00 +1000 Subject: [PATCH 0218/1939] powerpc: Move iSeries_vio.c to powerpc/platforms/iseries And rename it to vio.c. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 1 + .../kernel/iSeries_vio.c => powerpc/platforms/iseries/vio.c} | 0 arch/ppc64/kernel/Makefile | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename arch/{ppc64/kernel/iSeries_vio.c => powerpc/platforms/iseries/vio.c} (100%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index d10305d7ad2f..3a1ed16963a4 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,3 +1,4 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o obj-$(CONFIG_PCI) += pci.o irq.o vpdinfo.o +obj-$(CONFIG_IBMVIO) += vio.o diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/powerpc/platforms/iseries/vio.c similarity index 100% rename from arch/ppc64/kernel/iSeries_vio.c rename to arch/powerpc/platforms/iseries/vio.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 8b2743697c38..7354c1dbe9f0 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_HVCS) += hvcserver.o vio-obj-$(CONFIG_PPC_PSERIES) += pSeries_vio.o -vio-obj-$(CONFIG_PPC_ISERIES) += iSeries_vio.o obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y) obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_MPIC) += mpic.o From b6b8681843f9eaee12f8c30ffac399f7b2601ab3 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 03:07:14 +1000 Subject: [PATCH 0219/1939] powerpc: Move iSeries_smp.c to powerpc/platforms/iseries And rename it to smp.c. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 1 + .../platforms/iseries/smp.c} | 16 ++++++++-------- arch/ppc64/kernel/Makefile | 1 - 3 files changed, 9 insertions(+), 9 deletions(-) rename arch/{ppc64/kernel/iSeries_smp.c => powerpc/platforms/iseries/smp.c} (88%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 3a1ed16963a4..202f17419df5 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -2,3 +2,4 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o obj-$(CONFIG_PCI) += pci.o irq.o vpdinfo.o obj-$(CONFIG_IBMVIO) += vio.o +obj-$(CONFIG_SMP) += smp.o diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/powerpc/platforms/iseries/smp.c similarity index 88% rename from arch/ppc64/kernel/iSeries_smp.c rename to arch/powerpc/platforms/iseries/smp.c index f982e5b805f4..f720916682f6 100644 --- a/arch/ppc64/kernel/iSeries_smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -47,17 +47,17 @@ static unsigned long iSeries_smp_message[NR_CPUS]; -void iSeries_smp_message_recv( struct pt_regs * regs ) +void iSeries_smp_message_recv(struct pt_regs *regs) { int cpu = smp_processor_id(); int msg; - if ( num_online_cpus() < 2 ) + if (num_online_cpus() < 2) return; - for ( msg = 0; msg < 4; ++msg ) - if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) ) - smp_message_recv( msg, regs ); + for (msg = 0; msg < 4; msg++) + if (test_and_clear_bit(msg, &iSeries_smp_message[cpu])) + smp_message_recv(msg, regs); } static inline void smp_iSeries_do_message(int cpu, int msg) @@ -74,8 +74,8 @@ static void smp_iSeries_message_pass(int target, int msg) smp_iSeries_do_message(target, msg); else { for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) + if ((target == MSG_ALL_BUT_SELF) && + (i == smp_processor_id())) continue; smp_iSeries_do_message(i, msg); } @@ -89,7 +89,7 @@ static int smp_iSeries_probe(void) static void smp_iSeries_kick_cpu(int nr) { - BUG_ON(nr < 0 || nr >= NR_CPUS); + BUG_ON((nr < 0) || (nr >= NR_CPUS)); /* Verify that our partition has a processor nr */ if (paca[nr].lppaca.dyn_proc_status >= 2) diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 7354c1dbe9f0..ee88fca0c886 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o -obj-$(CONFIG_PPC_ISERIES) += iSeries_smp.o obj-$(CONFIG_PPC_PSERIES) += pSeries_smp.o obj-$(CONFIG_PPC_BPA) += pSeries_smp.o obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o From d223e721b743787fad71f6aef5e860176214c8f9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 03:12:35 +1000 Subject: [PATCH 0220/1939] powerpc: Move viopath.c to powerpc/platforms/iseries Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 1 + arch/{ppc64/kernel => powerpc/platforms/iseries}/viopath.c | 3 +-- arch/ppc64/kernel/Makefile | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename arch/{ppc64/kernel => powerpc/platforms/iseries}/viopath.c (99%) diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 202f17419df5..5a27b888103c 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -3,3 +3,4 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ obj-$(CONFIG_PCI) += pci.o irq.o vpdinfo.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_VIOPATH) += viopath.o diff --git a/arch/ppc64/kernel/viopath.c b/arch/powerpc/platforms/iseries/viopath.c similarity index 99% rename from arch/ppc64/kernel/viopath.c rename to arch/powerpc/platforms/iseries/viopath.c index 2a6c4f01c45e..c0c767bd37f1 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -1,5 +1,4 @@ /* -*- linux-c -*- - * arch/ppc64/kernel/viopath.c * * iSeries Virtual I/O Message Path code * @@ -7,7 +6,7 @@ * Ryan Arnold * Colin Devilbiss * - * (C) Copyright 2000-2003 IBM Corporation + * (C) Copyright 2000-2005 IBM Corporation * * This code is used by the iSeries virtual disk, cd, * tape, and console to communicate with OS/400 in another diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index ee88fca0c886..bb5946b88b8b 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_VIOPATH) += viopath.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_BOOTX_TEXT) += btext.o From 7b875f4dc345dc5f6a2c3bd0e1f90bfee46b2258 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 09:40:24 +1000 Subject: [PATCH 0221/1939] powerpc: Make powerpc pmac 32 bit build again Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 697addea192f..7637ff3642c3 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,4 +1,6 @@ +ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_PPC_PMAC) += powermac/ +endif obj-$(CONFIG_4xx) += 4xx/ obj-$(CONFIG_83xx) += 83xx/ obj-$(CONFIG_85xx) += 85xx/ From c111d0bda8437d146ccf5101970801fe4ff23ed8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 13:28:01 +1000 Subject: [PATCH 0222/1939] powerpc: move more iSeries code Move the iSeries specific parts of misc.S and ppc_ksyms.c into powerpc/platforms/iseries. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/Makefile | 3 +- arch/powerpc/platforms/iseries/ksyms.c | 27 ++++++++++++ arch/powerpc/platforms/iseries/misc.S | 55 +++++++++++++++++++++++++ arch/ppc64/kernel/misc.S | 38 ----------------- arch/ppc64/kernel/ppc_ksyms.c | 20 --------- 5 files changed, 84 insertions(+), 59 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/ksyms.c create mode 100644 arch/powerpc/platforms/iseries/misc.S diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 5a27b888103c..18bf40077561 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,6 +1,7 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ - hvcall.o proc.o htab.o iommu.o + hvcall.o proc.o htab.o iommu.o misc.o obj-$(CONFIG_PCI) += pci.o irq.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/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c new file mode 100644 index 000000000000..f271b3539721 --- /dev/null +++ b/arch/powerpc/platforms/iseries/ksyms.c @@ -0,0 +1,27 @@ +/* + * (C) 2001-2005 PPC 64 Team, 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 + +EXPORT_SYMBOL(HvCall0); +EXPORT_SYMBOL(HvCall1); +EXPORT_SYMBOL(HvCall2); +EXPORT_SYMBOL(HvCall3); +EXPORT_SYMBOL(HvCall4); +EXPORT_SYMBOL(HvCall5); +EXPORT_SYMBOL(HvCall6); +EXPORT_SYMBOL(HvCall7); + +#ifdef CONFIG_SMP +EXPORT_SYMBOL(local_get_flags); +EXPORT_SYMBOL(local_irq_disable); +EXPORT_SYMBOL(local_irq_restore); +#endif diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S new file mode 100644 index 000000000000..09f14522e176 --- /dev/null +++ b/arch/powerpc/platforms/iseries/misc.S @@ -0,0 +1,55 @@ +/* + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-2005 IBM Corp + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * PPC64 updates by Dave Engebretsen (engebret@us.ibm.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. + */ + +#include +#include + + .text + +/* unsigned long local_save_flags(void) */ +_GLOBAL(local_get_flags) + lbz r3,PACAPROCENABLED(r13) + blr + +/* unsigned long local_irq_disable(void) */ +_GLOBAL(local_irq_disable) + lbz r3,PACAPROCENABLED(r13) + li r4,0 + stb r4,PACAPROCENABLED(r13) + blr /* Done */ + +/* void local_irq_restore(unsigned long flags) */ +_GLOBAL(local_irq_restore) + lbz r5,PACAPROCENABLED(r13) + /* Check if things are setup the way we want _already_. */ + cmpw 0,r3,r5 + beqlr + /* are we enabling interrupts? */ + cmpdi 0,r3,0 + stb r3,PACAPROCENABLED(r13) + beqlr + /* Check pending interrupts */ + /* A decrementer, IPI or PMC interrupt may have occurred + * while we were in the hypervisor (which enables) */ + ld r4,PACALPPACA+LPPACAANYINT(r13) + cmpdi r4,0 + beqlr + + /* + * Handle pending interrupts in interrupt context + */ + li r0,0x5555 + sc + blr diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index a25b59759ddb..d069bbd7f81f 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -64,44 +64,6 @@ _GLOBAL(get_srr1) _GLOBAL(get_sp) mr r3,r1 blr - -#ifdef CONFIG_PPC_ISERIES -/* unsigned long local_save_flags(void) */ -_GLOBAL(local_get_flags) - lbz r3,PACAPROCENABLED(r13) - blr - -/* unsigned long local_irq_disable(void) */ -_GLOBAL(local_irq_disable) - lbz r3,PACAPROCENABLED(r13) - li r4,0 - stb r4,PACAPROCENABLED(r13) - blr /* Done */ - -/* void local_irq_restore(unsigned long flags) */ -_GLOBAL(local_irq_restore) - lbz r5,PACAPROCENABLED(r13) - /* Check if things are setup the way we want _already_. */ - cmpw 0,r3,r5 - beqlr - /* are we enabling interrupts? */ - cmpdi 0,r3,0 - stb r3,PACAPROCENABLED(r13) - beqlr - /* Check pending interrupts */ - /* A decrementer, IPI or PMC interrupt may have occurred - * while we were in the hypervisor (which enables) */ - ld r4,PACALPPACA+LPPACAANYINT(r13) - cmpdi r4,0 - beqlr - - /* - * Handle pending interrupts in interrupt context - */ - li r0,0x5555 - sc - blr -#endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_IRQSTACKS _GLOBAL(call_do_softirq) diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c index 705742f4eec6..84006e26342c 100644 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ b/arch/ppc64/kernel/ppc_ksyms.c @@ -19,7 +19,6 @@ #include #include #include -#include EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); @@ -46,17 +45,6 @@ EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(reloc_offset); -#ifdef CONFIG_PPC_ISERIES -EXPORT_SYMBOL(HvCall0); -EXPORT_SYMBOL(HvCall1); -EXPORT_SYMBOL(HvCall2); -EXPORT_SYMBOL(HvCall3); -EXPORT_SYMBOL(HvCall4); -EXPORT_SYMBOL(HvCall5); -EXPORT_SYMBOL(HvCall6); -EXPORT_SYMBOL(HvCall7); -#endif - EXPORT_SYMBOL(_insb); EXPORT_SYMBOL(_outsb); EXPORT_SYMBOL(_insw); @@ -77,14 +65,6 @@ EXPORT_SYMBOL(giveup_altivec); EXPORT_SYMBOL(__flush_icache_range); EXPORT_SYMBOL(flush_dcache_range); -#ifdef CONFIG_SMP -#ifdef CONFIG_PPC_ISERIES -EXPORT_SYMBOL(local_get_flags); -EXPORT_SYMBOL(local_irq_disable); -EXPORT_SYMBOL(local_irq_restore); -#endif -#endif - EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); From 252e75a51d40757928d692b3d339e66838294b4b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 14:40:40 +1000 Subject: [PATCH 0223/1939] ppc64 iSeries: use device_node instead of iSeries_Device_node There needs to be more cleanup after this. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/iommu.c | 29 ++++---- arch/powerpc/platforms/iseries/pci.c | 91 +++++++++++++----------- arch/powerpc/platforms/iseries/vpdinfo.c | 2 +- arch/ppc64/kernel/pci_iommu.c | 6 -- include/asm-ppc64/iSeries/iSeries_pci.h | 30 ++------ include/asm-ppc64/iommu.h | 4 +- include/asm-ppc64/pci-bridge.h | 10 +++ include/asm-ppc64/prom.h | 3 + 8 files changed, 88 insertions(+), 87 deletions(-) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 65c76dd1d3de..9ac735d5b817 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -89,15 +89,17 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) */ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) { - struct iSeries_Device_Node *dp; + struct device_node *dp; list_for_each_entry(dp, &iSeries_Global_Device_List, Device_List) { - if ((dp->iommu_table != NULL) && - (dp->iommu_table->it_type == TCE_PCI) && - (dp->iommu_table->it_offset == tbl->it_offset) && - (dp->iommu_table->it_index == tbl->it_index) && - (dp->iommu_table->it_size == tbl->it_size)) - return dp->iommu_table; + struct iommu_table *it = PCI_DN(dp)->iommu_table; + + if ((it != NULL) && + (it->it_type == TCE_PCI) && + (it->it_offset == tbl->it_offset) && + (it->it_index == tbl->it_index) && + (it->it_size == tbl->it_size)) + return it; } return NULL; } @@ -111,7 +113,7 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) * 2. TCE table per Bus. * 3. TCE Table per IOA. */ -static void iommu_table_getparms(struct iSeries_Device_Node* dn, +static void iommu_table_getparms(struct device_node *dn, struct iommu_table* tbl) { struct iommu_table_cb *parms; @@ -123,7 +125,7 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn, memset(parms, 0, sizeof(*parms)); parms->itc_busno = ISERIES_BUS(dn); - parms->itc_slotno = dn->LogicalSlot; + parms->itc_slotno = PCI_DN(dn)->LogicalSlot; parms->itc_virtbus = 0; HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms)); @@ -143,18 +145,19 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn, } -void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn) +void iommu_devnode_init_iSeries(struct device_node *dn) { struct iommu_table *tbl; + struct pci_dn *pdn = PCI_DN(dn); tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); iommu_table_getparms(dn, tbl); /* Look for existing tce table */ - dn->iommu_table = iommu_table_find(tbl); - if (dn->iommu_table == NULL) - dn->iommu_table = iommu_init_table(tbl); + pdn->iommu_table = iommu_table_find(tbl); + if (pdn->iommu_table == NULL) + pdn->iommu_table = iommu_init_table(tbl); else kfree(tbl); } diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 61a857218bc8..501b1dcbfac5 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -48,7 +48,7 @@ extern unsigned long io_page_mask; /* * Forward declares of prototypes. */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn); +static struct device_node *find_Device_Node(int bus, int devfn); static void scan_PHB_slots(struct pci_controller *Phb); static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel); static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info); @@ -85,7 +85,7 @@ static long current_iomm_table_entry; /* * Lookup Tables. */ -static struct iSeries_Device_Node **iomm_table; +static struct device_node **iomm_table; static u8 *iobar_table; /* @@ -199,29 +199,35 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus, /* * build_device_node(u16 Bus, int SubBus, u8 DevFn) */ -static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, +static struct device_node *build_device_node(HvBusNumber Bus, HvSubBusNumber SubBus, int AgentId, int Function) { - struct iSeries_Device_Node *node; + struct device_node *node; + struct pci_dn *pdn; PPCDBG(PPCDBG_BUSWALK, "-build_device_node 0x%02X.%02X.%02X Function: %02X\n", Bus, SubBus, AgentId, Function); - node = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); + node = kmalloc(sizeof(struct device_node), GFP_KERNEL); if (node == NULL) return NULL; - - memset(node, 0, sizeof(struct iSeries_Device_Node)); + memset(node, 0, sizeof(struct device_node)); + pdn = kzalloc(sizeof(*pdn), GFP_KERNEL); + if (pdn == NULL) { + kfree(node); + return NULL; + } + node->data = pdn; list_add_tail(&node->Device_List, &iSeries_Global_Device_List); #if 0 - node->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); + pdn->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); #endif - node->DsaAddr.DsaAddr = 0; - node->DsaAddr.Dsa.busNumber = Bus; - node->DsaAddr.Dsa.subBusNumber = SubBus; - node->DsaAddr.Dsa.deviceId = 0x10; - node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); + pdn->DsaAddr.DsaAddr = 0; + pdn->DsaAddr.Dsa.busNumber = Bus; + pdn->DsaAddr.Dsa.subBusNumber = SubBus; + pdn->DsaAddr.Dsa.deviceId = 0x10; + pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); return node; } @@ -294,7 +300,7 @@ void iSeries_pcibios_init(void) void __init iSeries_pci_final_fixup(void) { struct pci_dev *pdev = NULL; - struct iSeries_Device_Node *node; + struct device_node *node; int DeviceCount = 0; PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); @@ -311,7 +317,7 @@ void __init iSeries_pci_final_fixup(void) if (node != NULL) { ++DeviceCount; pdev->sysdata = (void *)node; - node->PciDev = pdev; + PCI_DN(node)->pcidev = pdev; PPCDBG(PPCDBG_BUSWALK, "pdev 0x%p <==> DevNode 0x%p\n", pdev, node); @@ -321,7 +327,7 @@ void __init iSeries_pci_final_fixup(void) } else printk("PCI: Device Tree not found for 0x%016lX\n", (unsigned long)pdev); - pdev->irq = node->Irq; + pdev->irq = PCI_DN(node)->Irq; } iSeries_activate_IRQs(); mf_display_src(0xC9000200); @@ -439,7 +445,7 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *BridgeInfo) { - struct iSeries_Device_Node *node; + struct device_node *node; HvSubBusNumber SubBus = BridgeInfo->subBusNumber; u16 VendorId = 0; int HvRc = 0; @@ -489,8 +495,8 @@ static int scan_bridge_slot(HvBusNumber Bus, ++DeviceCount; node = build_device_node(Bus, SubBus, EADsIdSel, Function); - node->Irq = Irq; - node->LogicalSlot = BridgeInfo->logicalSlotNumber; + PCI_DN(node)->Irq = Irq; + PCI_DN(node)->LogicalSlot = BridgeInfo->logicalSlotNumber; } /* for (Function = 0; Function < 8; ++Function) */ } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ @@ -540,15 +546,16 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio); /* * Look down the chain to find the matching Device Device */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn) +static struct device_node *find_Device_Node(int bus, int devfn) { struct list_head *pos; list_for_each(pos, &iSeries_Global_Device_List) { - struct iSeries_Device_Node *node = - list_entry(pos, struct iSeries_Device_Node, Device_List); + struct device_node *node = + list_entry(pos, struct device_node, Device_List); - if ((bus == ISERIES_BUS(node)) && (devfn == node->DevFn)) + if ((bus == ISERIES_BUS(node)) && + (devfn == PCI_DN(node)->devfn)) return node; } return NULL; @@ -560,12 +567,12 @@ static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn) * Sanity Check Node PciDev to passed pci_dev * If none is found, returns a NULL which the client must handle. */ -static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *pdev) +static struct device_node *get_Device_Node(struct pci_dev *pdev) { - struct iSeries_Device_Node *node; + struct device_node *node; node = pdev->sysdata; - if (node == NULL || node->PciDev != pdev) + if (node == NULL || PCI_DN(node)->pcidev != pdev) node = find_Device_Node(pdev->bus->number, pdev->devfn); return node; } @@ -593,7 +600,7 @@ static u64 hv_cfg_write_func[4] = { static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int size, u32 *val) { - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); + struct device_node *node = find_Device_Node(bus->number, devfn); u64 fn; struct HvCallPci_LoadReturn ret; @@ -605,7 +612,7 @@ static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, } fn = hv_cfg_read_func[(size - 1) & 3]; - HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0); + HvCall3Ret16(fn, &ret, PCI_DN(node)->DsaAddr.DsaAddr, offset, 0); if (ret.rc != 0) { *val = ~0; @@ -623,7 +630,7 @@ static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int size, u32 val) { - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); + struct device_node *node = find_Device_Node(bus->number, devfn); u64 fn; u64 ret; @@ -633,7 +640,7 @@ static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_BAD_REGISTER_NUMBER; fn = hv_cfg_write_func[(size - 1) & 3]; - ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0); + ret = HvCall4(fn, PCI_DN(node)->DsaAddr.DsaAddr, offset, val, 0); if (ret != 0) return PCIBIOS_DEVICE_NOT_FOUND; @@ -655,14 +662,16 @@ static struct pci_ops iSeries_pci_ops = { * PCI: Device 23.90 ReadL Retry( 1) * PCI: Device 23.90 ReadL Retry Successful(1) */ -static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, +static int CheckReturnCode(char *TextHdr, struct device_node *DevNode, int *retry, u64 ret) { if (ret != 0) { + struct pci_dn *pdn = PCI_DN(DevNode); + ++Pci_Error_Count; (*retry)++; printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", - TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn, + TextHdr, pdn->DsaAddr.Dsa.busNumber, pdn->devfn, *retry, (int)ret); /* * Bump the retry and check for retry count exceeded. @@ -685,14 +694,14 @@ static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, * Note: Make sure the passed variable end up on the stack to avoid * the exposure of being device global. */ -static inline struct iSeries_Device_Node *xlate_iomm_address( +static inline struct device_node *xlate_iomm_address( const volatile void __iomem *IoAddress, u64 *dsaptr, u64 *BarOffsetPtr) { unsigned long OrigIoAddr; unsigned long BaseIoAddr; unsigned long TableIndex; - struct iSeries_Device_Node *DevNode; + struct device_node *DevNode; OrigIoAddr = (unsigned long __force)IoAddress; if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory)) @@ -703,7 +712,7 @@ static inline struct iSeries_Device_Node *xlate_iomm_address( if (DevNode != NULL) { int barnum = iobar_table[TableIndex]; - *dsaptr = DevNode->DsaAddr.DsaAddr | (barnum << 24); + *dsaptr = PCI_DN(DevNode)->DsaAddr.DsaAddr | (barnum << 24); *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; } else panic("PCI: Invalid PCI IoAddress detected!\n"); @@ -725,7 +734,7 @@ u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) u64 dsa; int retry = 0; struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { @@ -755,7 +764,7 @@ u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) u64 dsa; int retry = 0; struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { @@ -786,7 +795,7 @@ u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) u64 dsa; int retry = 0; struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { @@ -824,7 +833,7 @@ void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) u64 dsa; int retry = 0; u64 rc; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { @@ -852,7 +861,7 @@ void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) u64 dsa; int retry = 0; u64 rc; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { @@ -880,7 +889,7 @@ void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) u64 dsa; int retry = 0; u64 rc; - struct iSeries_Device_Node *DevNode = + struct device_node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); if (DevNode == NULL) { diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c index 8b62f3bf1d26..d8a6796924e2 100644 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -240,7 +240,7 @@ static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, */ void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) { - struct iSeries_Device_Node *DevNode = PciDev->sysdata; + struct device_node *DevNode = PciDev->sysdata; u16 bus; u8 frame; char card[4]; diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index 19362ea11572..6c9dc67f59d8 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -61,13 +61,7 @@ static inline struct iommu_table *devnode_table(struct device *dev) } else pdev = to_pci_dev(dev); -#ifdef CONFIG_PPC_ISERIES - return ISERIES_DEVNODE(pdev)->iommu_table; -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_MULTIPLATFORM return PCI_DN(PCI_GET_DN(pdev))->iommu_table; -#endif /* CONFIG_PPC_MULTIPLATFORM */ } diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index 575f611f8b33..a4d88b49fd9f 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -30,21 +30,19 @@ * End Change Activity */ -#include #include +#include +#include struct pci_dev; /* For Forward Reference */ -struct iSeries_Device_Node; /* - * Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure + * Gets iSeries Bus, SubBus, DevFn using device_node structure */ -#define ISERIES_BUS(DevPtr) DevPtr->DsaAddr.Dsa.busNumber -#define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.Dsa.subBusNumber -#define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.Dsa.deviceId -#define ISERIES_DSA(DevPtr) DevPtr->DsaAddr.DsaAddr -#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node *)PciDev->sysdata) +#define ISERIES_BUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.busNumber +#define ISERIES_SUBBUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.subBusNumber +#define ISERIES_DEVNODE(PciDev) ((struct device_node *)PciDev->sysdata) #define EADsMaxAgents 7 @@ -67,22 +65,6 @@ struct iSeries_Device_Node; #define ISERIES_HV_ADDR(virtaddr) \ (0x8000000000000000 | virt_to_abs(virtaddr)) -/* - * iSeries Device Information - */ -struct iSeries_Device_Node { - struct list_head Device_List; - struct pci_dev *PciDev; - union HvDsaMap DsaAddr; /* Direct Select Address */ - /* busNumber, subBusNumber, */ - /* deviceId, barNumber */ - int DevFn; /* Linux devfn */ - int Irq; /* Assigned IRQ */ - int Flags; /* Possible flags(disable/bist)*/ - u8 LogicalSlot; /* Hv Slot Index for Tces */ - struct iommu_table *iommu_table;/* Device TCE Table */ -}; - extern void iSeries_Device_Information(struct pci_dev*, int); #endif /* _ISERIES_64_PCI_H */ diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h index a6a173d49506..d096faf4191e 100644 --- a/include/asm-ppc64/iommu.h +++ b/include/asm-ppc64/iommu.h @@ -49,6 +49,7 @@ struct iommu_table { }; struct scatterlist; +struct device_node; #ifdef CONFIG_PPC_MULTIPLATFORM @@ -70,9 +71,8 @@ extern void iommu_devnode_init_pSeries(struct device_node *dn); #ifdef CONFIG_PPC_ISERIES -struct iSeries_Device_Node; /* Creates table for an individual device node */ -extern void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn); +extern void iommu_devnode_init_iSeries(struct device_node *dn); #endif /* CONFIG_PPC_ISERIES */ diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index d8991389ab39..8ca5fce626bb 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -4,6 +4,8 @@ #include +#include + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -71,6 +73,14 @@ 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 + union HvDsaMap DsaAddr; /* Direct Select Address */ + /* busNumber, subBusNumber, */ + /* deviceId, barNumber */ + int Irq; /* Assigned IRQ */ + int Flags; /* Possible flags(disable/bist)*/ + u8 LogicalSlot; /* Hv Slot Index for Tces */ +#endif u32 config_space[16]; /* saved PCI config space */ }; diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h index c02ec1d6b909..cf0284e081ea 100644 --- a/include/asm-ppc64/prom.h +++ b/include/asm-ppc64/prom.h @@ -137,6 +137,9 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; +#ifdef CONFIG_PPC_ISERIES + struct list_head Device_List; +#endif }; extern struct device_node *of_chosen; From a559c91d77c3220be521453bd23815e1e1980a82 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Tue, 27 Sep 2005 14:28:56 -0500 Subject: [PATCH 0224/1939] [PATCH] powerpc: merge byteorder.h powerpc: Merge byteorder.h Essentially adopts the 64-bit version of this file. The 32-bit version had been using unsigned ints for arguments/return values that were actually only 16 bits - the new file uses __u16 for these items as in the 64-bit version of the header. The order of some of the asm constraints in the 64-bit version was slightly different than the 32-bit version, but they produce identical code. Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- .../{asm-ppc64 => asm-powerpc}/byteorder.h | 11 ++- include/asm-ppc/byteorder.h | 76 ------------------- 2 files changed, 7 insertions(+), 80 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/byteorder.h (90%) delete mode 100644 include/asm-ppc/byteorder.h diff --git a/include/asm-ppc64/byteorder.h b/include/asm-powerpc/byteorder.h similarity index 90% rename from include/asm-ppc64/byteorder.h rename to include/asm-powerpc/byteorder.h index 8b57da62b674..b37752214a16 100644 --- a/include/asm-ppc64/byteorder.h +++ b/include/asm-powerpc/byteorder.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_BYTEORDER_H -#define _PPC64_BYTEORDER_H +#ifndef _ASM_POWERPC_BYTEORDER_H +#define _ASM_POWERPC_BYTEORDER_H /* * This program is free software; you can redistribute it and/or @@ -77,10 +77,13 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) #ifndef __STRICT_ANSI__ #define __BYTEORDER_HAS_U64__ -#endif +#ifndef __powerpc64__ +#define __SWAB_64_THRU_32__ +#endif /* __powerpc64__ */ +#endif /* __STRICT_ANSI__ */ #endif /* __GNUC__ */ #include -#endif /* _PPC64_BYTEORDER_H */ +#endif /* _ASM_POWERPC_BYTEORDER_H */ diff --git a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h deleted file mode 100644 index c63c81ec7968..000000000000 --- a/include/asm-ppc/byteorder.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _PPC_BYTEORDER_H -#define _PPC_BYTEORDER_H - -#include -#include - -#ifdef __GNUC__ -#ifdef __KERNEL__ - -extern __inline__ unsigned ld_le16(const volatile unsigned short *addr) -{ - unsigned val; - - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); - return val; -} - -extern __inline__ void st_le16(volatile unsigned short *addr, const unsigned val) -{ - __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); -} - -extern __inline__ unsigned ld_le32(const volatile unsigned *addr) -{ - unsigned val; - - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); - return val; -} - -extern __inline__ void st_le32(volatile unsigned *addr, const unsigned val) -{ - __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); -} - -static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) -{ - __u16 result; - - __asm__("rlwimi %0,%2,8,16,23" : "=&r" (result) : "0" (value >> 8), "r" (value)); - return result; -} - -static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) -{ - __u32 result; - - __asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (value>>24), "r" (value)); - __asm__("rlwimi %0,%2,8,8,15" : "=&r" (result) : "0" (result), "r" (value)); - __asm__("rlwimi %0,%2,24,0,7" : "=&r" (result) : "0" (result), "r" (value)); - - return result; -} -#define __arch__swab32(x) ___arch__swab32(x) -#define __arch__swab16(x) ___arch__swab16(x) - -/* The same, but returns converted value from the location pointer by addr. */ -#define __arch__swab16p(addr) ld_le16(addr) -#define __arch__swab32p(addr) ld_le32(addr) - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -#define __arch__swab16s(addr) st_le16(addr,*addr) -#define __arch__swab32s(addr) st_le32(addr,*addr) - -#endif /* __KERNEL__ */ - -#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) -# define __BYTEORDER_HAS_U64__ -# define __SWAB_64_THRU_32__ -#endif - -#endif /* __GNUC__ */ - -#include - -#endif /* _PPC_BYTEORDER_H */ From 10b35d9978ac35556aec0d2642055742d8941488 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 23 Sep 2005 14:08:58 -0500 Subject: [PATCH 0225/1939] [PATCH] powerpc: merged asm/cputable.h Merged cputable.h between ppc32 and ppc64. In doing this removed support for the BEGIN_FTR_SECTION/END_FTR_SECTION macros in C code since they dont compile correctly. C code should use cpu_has_feature(). This is based on Arnd Bergmann's initial patch. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/cputable.c | 399 +++++++---------------------- arch/ppc64/kernel/cputable.c | 82 ++---- include/asm-powerpc/cputable.h | 442 +++++++++++++++++++++++++++++++++ include/asm-ppc/cputable.h | 128 ---------- include/asm-ppc/mmu_context.h | 6 +- include/asm-ppc64/cputable.h | 167 ------------- 6 files changed, 547 insertions(+), 677 deletions(-) create mode 100644 include/asm-powerpc/cputable.h delete mode 100644 include/asm-ppc/cputable.h delete mode 100644 include/asm-ppc64/cputable.h diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index 546e1ea4cafa..97663d5d96ca 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -42,17 +42,6 @@ extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spe #define COMMON_PPC (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ PPC_FEATURE_HAS_MMU) -/* We only set the altivec features if the kernel was compiled with altivec - * support - */ -#ifdef CONFIG_ALTIVEC -#define CPU_FTR_ALTIVEC_COMP CPU_FTR_ALTIVEC -#define PPC_FEATURE_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC -#else -#define CPU_FTR_ALTIVEC_COMP 0 -#define PPC_FEATURE_ALTIVEC_COMP 0 -#endif - /* We only set the spe features if the kernel was compiled with * spe support */ @@ -62,34 +51,13 @@ extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spe #define PPC_FEATURE_SPE_COMP 0 #endif -/* We need to mark all pages as being coherent if we're SMP or we - * have a 74[45]x and an MPC107 host bridge. - */ -#if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE) -#define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT -#else -#define CPU_FTR_COMMON 0 -#endif - -/* The powersave features NAP & DOZE seems to confuse BDI when - debugging. So if a BDI is used, disable theses - */ -#ifndef CONFIG_BDI_SWITCH -#define CPU_FTR_MAYBE_CAN_DOZE CPU_FTR_CAN_DOZE -#define CPU_FTR_MAYBE_CAN_NAP CPU_FTR_CAN_NAP -#else -#define CPU_FTR_MAYBE_CAN_DOZE 0 -#define CPU_FTR_MAYBE_CAN_NAP 0 -#endif - struct cpu_spec cpu_specs[] = { #if CLASSIC_PPC { /* 601 */ .pvr_mask = 0xffff0000, .pvr_value = 0x00010000, .cpu_name = "601", - .cpu_features = CPU_FTR_COMMON | CPU_FTR_601 | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_PPC601, .cpu_user_features = COMMON_PPC | PPC_FEATURE_601_INSTR | PPC_FEATURE_UNIFIED_CACHE, .icache_bsize = 32, @@ -100,9 +68,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00030000, .cpu_name = "603", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP, + .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -112,9 +78,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00060000, .cpu_name = "603e", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP, + .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -124,9 +88,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00070000, .cpu_name = "603ev", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP, + .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -136,9 +98,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00040000, .cpu_name = "604", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -149,9 +109,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xfffff000, .pvr_value = 0x00090000, .cpu_name = "604e", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -162,9 +120,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00090000, .cpu_name = "604r", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -175,9 +131,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x000a0000, .cpu_name = "604ev", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -188,10 +142,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x00084202, .cpu_name = "740/750", - .cpu_features = 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_features = CPU_FTRS_740_NOTAU, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -202,10 +153,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xfffffff0, .pvr_value = 0x00080100, .cpu_name = "750CX", - .cpu_features = 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_features = CPU_FTRS_750, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -216,10 +164,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xfffffff0, .pvr_value = 0x00082200, .cpu_name = "750CX", - .cpu_features = 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_features = CPU_FTRS_750, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -230,10 +175,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xfffffff0, .pvr_value = 0x00082210, .cpu_name = "750CXe", - .cpu_features = 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_features = CPU_FTRS_750, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -244,10 +186,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x00083214, .cpu_name = "750CXe", - .cpu_features = 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_features = CPU_FTRS_750, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -258,10 +197,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xfffff000, .pvr_value = 0x00083000, .cpu_name = "745/755", - .cpu_features = 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_features = CPU_FTRS_750, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -272,11 +208,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffff00, .pvr_value = 0x70000100, .cpu_name = "750FX", - .cpu_features = 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_features = CPU_FTRS_750FX1, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -287,11 +219,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x70000200, .cpu_name = "750FX", - .cpu_features = 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_features = CPU_FTRS_750FX2, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -302,11 +230,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x70000000, .cpu_name = "750FX", - .cpu_features = 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_features = CPU_FTRS_750FX, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -317,11 +241,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x70020000, .cpu_name = "750GX", - .cpu_features = 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_features = CPU_FTRS_750GX, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -332,10 +252,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00080000, .cpu_name = "740/750", - .cpu_features = 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_features = CPU_FTRS_740, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -346,11 +263,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x000c1101, .cpu_name = "7400 (1.1)", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7400_NOTAU, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -360,12 +274,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x000c0000, .cpu_name = "7400", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7400, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -375,12 +285,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x800c0000, .cpu_name = "7410", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7400, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -390,12 +296,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x80000200, .cpu_name = "7450", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7450_20, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -405,14 +307,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x80000201, .cpu_name = "7450", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7450_21, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -422,13 +318,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80000000, .cpu_name = "7450", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7450_23, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -438,12 +329,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffff00, .pvr_value = 0x80010100, .cpu_name = "7455", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7455_1, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -453,14 +340,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x80010200, .cpu_name = "7455", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7455_20, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -470,14 +351,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80010000, .cpu_name = "7455", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7455, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -487,14 +362,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x80020100, .cpu_name = "7447/7457", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7447_10, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -504,14 +373,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffffff, .pvr_value = 0x80020101, .cpu_name = "7447/7457", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7447_10, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -521,14 +384,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80020000, .cpu_name = "7447/7457", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7447, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -538,13 +395,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80030000, .cpu_name = "7447A", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7447A, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -554,13 +406,8 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80040000, .cpu_name = "7448", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_7447A, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -570,9 +417,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x7fff0000, .pvr_value = 0x00810000, .cpu_name = "82xx", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_82XX, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -582,9 +427,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x7fff0000, .pvr_value = 0x00820000, .cpu_name = "G2_LE", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + .cpu_features = CPU_FTRS_G2_LE, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -594,9 +437,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x7fff0000, .pvr_value = 0x00830000, .cpu_name = "e300", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + .cpu_features = CPU_FTRS_E300, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -606,9 +447,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x00000000, .pvr_value = 0x00000000, .cpu_name = "(generic PPC)", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_CLASSIC32, .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, @@ -620,9 +459,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00400000, .cpu_name = "Power3 (630)", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_POWER3_32, .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, .icache_bsize = 128, .dcache_bsize = 128, @@ -633,9 +470,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00410000, .cpu_name = "Power3 (630+)", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_POWER3_32, .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, .icache_bsize = 128, .dcache_bsize = 128, @@ -646,9 +481,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00360000, .cpu_name = "I-star", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_POWER3_32, .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, .icache_bsize = 128, .dcache_bsize = 128, @@ -659,9 +492,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00370000, .cpu_name = "S-star", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, + .cpu_features = CPU_FTRS_POWER3_32, .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, .icache_bsize = 128, .dcache_bsize = 128, @@ -670,44 +501,12 @@ struct cpu_spec cpu_specs[] = { }, #endif /* CONFIG_PPC64BRIDGE */ #ifdef CONFIG_POWER4 - { /* Power4 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00350000, - .cpu_name = "Power4", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_HPTE_TABLE, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power4 - }, - { /* PPC970 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00390000, - .cpu_name = "PPC970", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_64 | - PPC_FEATURE_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970 - }, { /* PPC970FX */ .pvr_mask = 0xffff0000, .pvr_value = 0x003c0000, .cpu_name = "PPC970FX", - .cpu_features = 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_user_features = COMMON_PPC | PPC_FEATURE_64 | - PPC_FEATURE_ALTIVEC_COMP, + .cpu_features = CPU_FTRS_970_32, + .cpu_user_features = COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -721,8 +520,7 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "8xx", /* CPU_FTR_MAYBE_CAN_DOZE is possible, * if the 8xx code is there.... */ - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_8XX, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 16, .dcache_bsize = 16, @@ -733,8 +531,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffff00, .pvr_value = 0x00200200, .cpu_name = "403GC", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 16, .dcache_bsize = 16, @@ -743,8 +540,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffffff00, .pvr_value = 0x00201400, .cpu_name = "403GCX", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 16, .dcache_bsize = 16, @@ -753,8 +549,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00200000, .cpu_name = "403G ??", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 16, .dcache_bsize = 16, @@ -763,8 +558,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x40110000, .cpu_name = "405GP", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -774,8 +568,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x40130000, .cpu_name = "STB03xxx", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -785,8 +578,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x41810000, .cpu_name = "STB04xxx", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -796,8 +588,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x41610000, .cpu_name = "NP405L", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -807,8 +598,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x40B10000, .cpu_name = "NP4GS3", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -818,8 +608,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x41410000, .cpu_name = "NP405H", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -829,8 +618,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x50910000, .cpu_name = "405GPr", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -840,8 +628,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x51510000, .cpu_name = "STBx25xx", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -851,8 +638,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x41F10000, .cpu_name = "405LP", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -861,8 +647,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x20010000, .cpu_name = "Virtex-II Pro", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -872,8 +657,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x51210000, .cpu_name = "405EP", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, .icache_bsize = 32, @@ -886,8 +670,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x40000850, .cpu_name = "440EP Rev. A", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */ .icache_bsize = 32, .dcache_bsize = 32, @@ -896,8 +679,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x400008d3, .cpu_name = "440EP Rev. B", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */ .icache_bsize = 32, .dcache_bsize = 32, @@ -906,8 +688,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x40000440, .cpu_name = "440GP Rev. B", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -916,8 +697,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x40000481, .cpu_name = "440GP Rev. C", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -926,8 +706,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x50000850, .cpu_name = "440GX Rev. A", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -936,8 +715,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x50000851, .cpu_name = "440GX Rev. B", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -946,8 +724,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x50000892, .cpu_name = "440GX Rev. C", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -956,8 +733,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xf0000fff, .pvr_value = 0x50000894, .cpu_name = "440GX Rev. F", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -966,8 +742,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xff000fff, .pvr_value = 0x53000891, .cpu_name = "440SP Rev. A", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_44X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, .icache_bsize = 32, .dcache_bsize = 32, @@ -979,7 +754,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x81000000, .cpu_name = "e200z5", /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ - .cpu_features = CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_E200, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_UNIFIED_CACHE, @@ -990,7 +765,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x81100000, .cpu_name = "e200z6", /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ - .cpu_features = CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_E200, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE | @@ -1002,8 +777,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80200000, .cpu_name = "e500", /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB, + .cpu_features = CPU_FTRS_E500, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE, @@ -1016,8 +790,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80210000, .cpu_name = "e500v2", /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_BIG_PHYS, + .cpu_features = CPU_FTRS_E500_2, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE, @@ -1031,7 +804,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x00000000, .pvr_value = 0x00000000, .cpu_name = "(generic PPC)", - .cpu_features = CPU_FTR_COMMON, + .cpu_features = CPU_FTRS_GENERIC_32, .cpu_user_features = PPC_FEATURE_32, .icache_bsize = 32, .dcache_bsize = 32, diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 8831a28c3c4e..5134c53d536d 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c @@ -37,26 +37,13 @@ extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); - -/* We only set the altivec features if the kernel was compiled with altivec - * support - */ -#ifdef CONFIG_ALTIVEC -#define CPU_FTR_ALTIVEC_COMP CPU_FTR_ALTIVEC -#define PPC_FEATURE_HAS_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC -#else -#define CPU_FTR_ALTIVEC_COMP 0 -#define PPC_FEATURE_HAS_ALTIVEC_COMP 0 -#endif - struct cpu_spec cpu_specs[] = { { /* Power3 */ .pvr_mask = 0xffff0000, .pvr_value = 0x00400000, .cpu_name = "POWER3 (630)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, - .cpu_user_features = COMMON_USER_PPC64, + .cpu_features = CPU_FTRS_POWER3, + .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -70,8 +57,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00410000, .cpu_name = "POWER3 (630+)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, + .cpu_features = CPU_FTRS_POWER3, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -86,9 +72,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00330000, .cpu_name = "RS64-II (northstar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -103,9 +87,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00340000, .cpu_name = "RS64-III (pulsar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -120,9 +102,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00360000, .cpu_name = "RS64-III (icestar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -137,9 +117,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00370000, .cpu_name = "RS64-IV (sstar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -154,9 +132,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00350000, .cpu_name = "POWER4 (gp)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, + .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -171,9 +147,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00380000, .cpu_name = "POWER4+ (gq)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, + .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -188,10 +162,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00390000, .cpu_name = "PPC970", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, + .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, @@ -207,10 +178,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x003c0000, .cpu_name = "PPC970FX", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, + .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, @@ -226,10 +194,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x00440000, .cpu_name = "PPC970MP", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, + .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, @@ -244,11 +209,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x003a0000, .cpu_name = "POWER5 (gr)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | 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_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -263,11 +224,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x003b0000, .cpu_name = "POWER5 (gs)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | 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_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, @@ -281,11 +238,8 @@ struct cpu_spec cpu_specs[] = { { /* BE DD1.x */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, - .cpu_name = "Broadband Engine", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_SMT, + .cpu_name = "Cell Broadband Engine", + .cpu_features = CPU_FTRS_CELL, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, @@ -296,9 +250,7 @@ struct cpu_spec cpu_specs[] = { .pvr_mask = 0x00000000, .pvr_value = 0x00000000, .cpu_name = "POWER4 (compatible)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2, + .cpu_features = CPU_FTRS_COMPATIBLE, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h new file mode 100644 index 000000000000..5f81d44963f1 --- /dev/null +++ b/include/asm-powerpc/cputable.h @@ -0,0 +1,442 @@ +#ifndef __ASM_POWERPC_CPUTABLE_H +#define __ASM_POWERPC_CPUTABLE_H + +#include +#include /* for ASM_CONST */ + +#define PPC_FEATURE_32 0x80000000 +#define PPC_FEATURE_64 0x40000000 +#define PPC_FEATURE_601_INSTR 0x20000000 +#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 +#define PPC_FEATURE_HAS_FPU 0x08000000 +#define PPC_FEATURE_HAS_MMU 0x04000000 +#define PPC_FEATURE_HAS_4xxMAC 0x02000000 +#define PPC_FEATURE_UNIFIED_CACHE 0x01000000 +#define PPC_FEATURE_HAS_SPE 0x00800000 +#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 +#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +/* This structure can grow, it's real size is used by head.S code + * via the mkdefs mechanism. + */ +struct cpu_spec; +struct op_powerpc_model; + +#ifdef __powerpc64__ +typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec); +#else /* __powerpc64__ */ +typedef void (*cpu_setup_t)(unsigned long offset, int cpu_nr, struct cpu_spec* spec); +#endif /* __powerpc64__ */ + +struct cpu_spec { + /* CPU is matched via (PVR & pvr_mask) == pvr_value */ + unsigned int pvr_mask; + unsigned int pvr_value; + + char *cpu_name; + unsigned long cpu_features; /* Kernel features */ + unsigned int cpu_user_features; /* Userland features */ + + /* cache line sizes */ + unsigned int icache_bsize; + unsigned int dcache_bsize; + + /* number of performance monitor counters */ + unsigned int num_pmcs; + + /* this is called to initialize various CPU bits like L1 cache, + * BHT, SPD, etc... from head.S before branching to identify_machine + */ + cpu_setup_t cpu_setup; +#ifdef __powerpc64__ + + /* Used by oprofile userspace to select the right counters */ + char *oprofile_cpu_type; + + /* Processor specific oprofile operations */ + struct op_powerpc_model *oprofile_model; +#endif /* __powerpc64__ */ +}; + +extern struct cpu_spec cpu_specs[]; + +#ifdef __powerpc64__ +extern struct cpu_spec *cur_cpu_spec; +#else /* __powerpc64__ */ +extern struct cpu_spec *cur_cpu_spec[]; +#endif /* __powerpc64__ */ + +#endif /* __ASSEMBLY__ */ + +/* CPU kernel features */ + +/* Retain the 32b definitions all use bottom half of word */ +#define CPU_FTR_SPLIT_ID_CACHE ASM_CONST(0x0000000000000001) +#define CPU_FTR_L2CR ASM_CONST(0x0000000000000002) +#define CPU_FTR_SPEC7450 ASM_CONST(0x0000000000000004) +#define CPU_FTR_ALTIVEC ASM_CONST(0x0000000000000008) +#define CPU_FTR_TAU ASM_CONST(0x0000000000000010) +#define CPU_FTR_CAN_DOZE ASM_CONST(0x0000000000000020) +#define CPU_FTR_USE_TB ASM_CONST(0x0000000000000040) +#define CPU_FTR_604_PERF_MON ASM_CONST(0x0000000000000080) +#define CPU_FTR_601 ASM_CONST(0x0000000000000100) +#define CPU_FTR_HPTE_TABLE ASM_CONST(0x0000000000000200) +#define CPU_FTR_CAN_NAP ASM_CONST(0x0000000000000400) +#define CPU_FTR_L3CR ASM_CONST(0x0000000000000800) +#define CPU_FTR_L3_DISABLE_NAP ASM_CONST(0x0000000000001000) +#define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x0000000000002000) +#define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x0000000000004000) +#define CPU_FTR_NO_DPM ASM_CONST(0x0000000000008000) +#define CPU_FTR_HAS_HIGH_BATS ASM_CONST(0x0000000000010000) +#define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) +#define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) +#define CPU_FTR_BIG_PHYS ASM_CONST(0x0000000000080000) + +#ifdef __powerpc64__ +/* Add the 64b processor unique features in the top half of the word */ +#define CPU_FTR_SLB ASM_CONST(0x0000000100000000) +#define CPU_FTR_16M_PAGE ASM_CONST(0x0000000200000000) +#define CPU_FTR_TLBIEL ASM_CONST(0x0000000400000000) +#define CPU_FTR_NOEXECUTE ASM_CONST(0x0000000800000000) +#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000001000000000) +#define CPU_FTR_IABR ASM_CONST(0x0000002000000000) +#define CPU_FTR_MMCRA ASM_CONST(0x0000004000000000) +#define CPU_FTR_CTRL ASM_CONST(0x0000008000000000) +#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) +#else +/* ensure on 32b processors the flags are available for compiling but + * don't do anything */ +#define CPU_FTR_SLB ASM_CONST(0x0) +#define CPU_FTR_16M_PAGE ASM_CONST(0x0) +#define CPU_FTR_TLBIEL ASM_CONST(0x0) +#define CPU_FTR_NOEXECUTE ASM_CONST(0x0) +#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0) +#define CPU_FTR_IABR ASM_CONST(0x0) +#define CPU_FTR_MMCRA ASM_CONST(0x0) +#define CPU_FTR_CTRL ASM_CONST(0x0) +#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) +#endif + +#ifndef __ASSEMBLY__ + +#define COMMON_USER_PPC64 (PPC_FEATURE_32 | PPC_FEATURE_64 | \ + PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_MMU) + +#define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \ + CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \ + CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL) + +/* iSeries doesn't support large pages */ +#ifdef CONFIG_PPC_ISERIES +#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_PPCAS_ARCH_V2_BASE) +#else +#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_PPCAS_ARCH_V2_BASE | CPU_FTR_16M_PAGE) +#endif /* CONFIG_PPC_ISERIES */ + +/* We only set the altivec features if the kernel was compiled with altivec + * support + */ +#ifdef CONFIG_ALTIVEC +#define CPU_FTR_ALTIVEC_COMP CPU_FTR_ALTIVEC +#define PPC_FEATURE_HAS_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC +#else +#define CPU_FTR_ALTIVEC_COMP 0 +#define PPC_FEATURE_HAS_ALTIVEC_COMP 0 +#endif + +/* We need to mark all pages as being coherent if we're SMP or we + * have a 74[45]x and an MPC107 host bridge. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE) +#define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT +#else +#define CPU_FTR_COMMON 0 +#endif + +/* The powersave features NAP & DOZE seems to confuse BDI when + debugging. So if a BDI is used, disable theses + */ +#ifndef CONFIG_BDI_SWITCH +#define CPU_FTR_MAYBE_CAN_DOZE CPU_FTR_CAN_DOZE +#define CPU_FTR_MAYBE_CAN_NAP CPU_FTR_CAN_NAP +#else +#define CPU_FTR_MAYBE_CAN_DOZE 0 +#define CPU_FTR_MAYBE_CAN_NAP 0 +#endif + +#define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \ + !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \ + !defined(CONFIG_BOOKE)) + +enum { + CPU_FTRS_PPC601 = CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE, + 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_FTRS_604 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE, + 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_FTRS_82XX = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTRS_G2_LE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | + CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + CPU_FTRS_E300 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | + CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, + CPU_FTRS_CLASSIC32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, + CPU_FTRS_POWER3_32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, + CPU_FTRS_POWER4_32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, + 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_FTRS_8XX = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + CPU_FTRS_40X = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + CPU_FTRS_44X = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + CPU_FTRS_E200 = CPU_FTR_USE_TB, + CPU_FTRS_E500 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + CPU_FTRS_E500_2 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_BIG_PHYS, + CPU_FTRS_GENERIC_32 = CPU_FTR_COMMON, +#ifdef __powerpc64__ + CPU_FTRS_POWER3 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, + 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, + CPU_FTRS_POWER4 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, + CPU_FTRS_PPC970 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | + CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, + CPU_FTRS_POWER5 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + 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_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, + CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2, +#endif + + CPU_FTRS_POSSIBLE = +#if CLASSIC_PPC + CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU | + CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 | + CPU_FTRS_750FX2 | CPU_FTRS_750FX | CPU_FTRS_750GX | + CPU_FTRS_7400_NOTAU | CPU_FTRS_7400 | CPU_FTRS_7450_20 | + CPU_FTRS_7450_21 | CPU_FTRS_7450_23 | CPU_FTRS_7455_1 | + CPU_FTRS_7455_20 | CPU_FTRS_7455 | CPU_FTRS_7447_10 | + CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX | + CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_CLASSIC32 | +#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 +#ifdef CONFIG_40x + CPU_FTRS_40X | +#endif +#ifdef CONFIG_44x + CPU_FTRS_44X | +#endif +#ifdef CONFIG_E200 + CPU_FTRS_E200 | +#endif +#ifdef CONFIG_E500 + CPU_FTRS_E500 | CPU_FTRS_E500_2 | +#endif +#ifdef __powerpc64__ + CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | + CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL | +#endif + 0, + + CPU_FTRS_ALWAYS = +#if CLASSIC_PPC + CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU & + CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 & + CPU_FTRS_750FX2 & CPU_FTRS_750FX & CPU_FTRS_750GX & + CPU_FTRS_7400_NOTAU & CPU_FTRS_7400 & CPU_FTRS_7450_20 & + CPU_FTRS_7450_21 & CPU_FTRS_7450_23 & CPU_FTRS_7455_1 & + CPU_FTRS_7455_20 & CPU_FTRS_7455 & CPU_FTRS_7447_10 & + CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX & + CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_CLASSIC32 & +#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 +#ifdef CONFIG_40x + CPU_FTRS_40X & +#endif +#ifdef CONFIG_44x + CPU_FTRS_44X & +#endif +#ifdef CONFIG_E200 + CPU_FTRS_E200 & +#endif +#ifdef CONFIG_E500 + CPU_FTRS_E500 & CPU_FTRS_E500_2 & +#endif +#ifdef __powerpc64__ + CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & + CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL & +#endif + CPU_FTRS_POSSIBLE, +}; + +static inline int cpu_has_feature(unsigned long feature) +{ + return (CPU_FTRS_ALWAYS & feature) || + (CPU_FTRS_POSSIBLE +#ifndef __powerpc64__ + & cur_cpu_spec[0]->cpu_features +#else + & cur_cpu_spec->cpu_features +#endif + & feature); +} + +#endif /* !__ASSEMBLY__ */ + +#ifdef __ASSEMBLY__ + +#define BEGIN_FTR_SECTION 98: + +#ifndef __powerpc64__ +#define END_FTR_SECTION(msk, val) \ +99: \ + .section __ftr_fixup,"a"; \ + .align 2; \ + .long msk; \ + .long val; \ + .long 98b; \ + .long 99b; \ + .previous +#else /* __powerpc64__ */ +#define END_FTR_SECTION(msk, val) \ +99: \ + .section __ftr_fixup,"a"; \ + .align 3; \ + .llong msk; \ + .llong val; \ + .llong 98b; \ + .llong 99b; \ + .previous +#endif /* __powerpc64__ */ + +#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk)) +#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0) +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ +#endif /* __ASM_POWERPC_CPUTABLE_H */ diff --git a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h deleted file mode 100644 index 41d8f8425c04..000000000000 --- a/include/asm-ppc/cputable.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * include/asm-ppc/cputable.h - * - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * 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_PPC_CPUTABLE_H -#define __ASM_PPC_CPUTABLE_H - -/* Exposed to userland CPU features */ -#define PPC_FEATURE_32 0x80000000 -#define PPC_FEATURE_64 0x40000000 -#define PPC_FEATURE_601_INSTR 0x20000000 -#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 -#define PPC_FEATURE_HAS_FPU 0x08000000 -#define PPC_FEATURE_HAS_MMU 0x04000000 -#define PPC_FEATURE_HAS_4xxMAC 0x02000000 -#define PPC_FEATURE_UNIFIED_CACHE 0x01000000 -#define PPC_FEATURE_HAS_SPE 0x00800000 -#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 -#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -/* This structure can grow, it's real size is used by head.S code - * via the mkdefs mecanism. - */ -struct cpu_spec; - -typedef void (*cpu_setup_t)(unsigned long offset, int cpu_nr, struct cpu_spec* spec); - -struct cpu_spec { - /* CPU is matched via (PVR & pvr_mask) == pvr_value */ - unsigned int pvr_mask; - unsigned int pvr_value; - - char *cpu_name; - unsigned int cpu_features; /* Kernel features */ - unsigned int cpu_user_features; /* Userland features */ - - /* cache line sizes */ - unsigned int icache_bsize; - unsigned int dcache_bsize; - - /* number of performance monitor counters */ - unsigned int num_pmcs; - - /* this is called to initialize various CPU bits like L1 cache, - * BHT, SPD, etc... from head.S before branching to identify_machine - */ - cpu_setup_t cpu_setup; -}; - -extern struct cpu_spec cpu_specs[]; -extern struct cpu_spec *cur_cpu_spec[]; - -static inline unsigned int cpu_has_feature(unsigned int feature) -{ - return cur_cpu_spec[0]->cpu_features & feature; -} - -#endif /* __ASSEMBLY__ */ - -/* CPU kernel features */ -#define CPU_FTR_SPLIT_ID_CACHE 0x00000001 -#define CPU_FTR_L2CR 0x00000002 -#define CPU_FTR_SPEC7450 0x00000004 -#define CPU_FTR_ALTIVEC 0x00000008 -#define CPU_FTR_TAU 0x00000010 -#define CPU_FTR_CAN_DOZE 0x00000020 -#define CPU_FTR_USE_TB 0x00000040 -#define CPU_FTR_604_PERF_MON 0x00000080 -#define CPU_FTR_601 0x00000100 -#define CPU_FTR_HPTE_TABLE 0x00000200 -#define CPU_FTR_CAN_NAP 0x00000400 -#define CPU_FTR_L3CR 0x00000800 -#define CPU_FTR_L3_DISABLE_NAP 0x00001000 -#define CPU_FTR_NAP_DISABLE_L2_PR 0x00002000 -#define CPU_FTR_DUAL_PLL_750FX 0x00004000 -#define CPU_FTR_NO_DPM 0x00008000 -#define CPU_FTR_HAS_HIGH_BATS 0x00010000 -#define CPU_FTR_NEED_COHERENT 0x00020000 -#define CPU_FTR_NO_BTIC 0x00040000 -#define CPU_FTR_BIG_PHYS 0x00080000 - -#ifdef __ASSEMBLY__ - -#define BEGIN_FTR_SECTION 98: - -#define END_FTR_SECTION(msk, val) \ -99: \ - .section __ftr_fixup,"a"; \ - .align 2; \ - .long msk; \ - .long val; \ - .long 98b; \ - .long 99b; \ - .previous - -#else - -#define BEGIN_FTR_SECTION "98:\n" -#define END_FTR_SECTION(msk, val) \ -"99:\n" \ -" .section __ftr_fixup,\"a\";\n" \ -" .align 2;\n" \ -" .long "#msk";\n" \ -" .long "#val";\n" \ -" .long 98b;\n" \ -" .long 99b;\n" \ -" .previous\n" - - -#endif /* __ASSEMBLY__ */ - -#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk)) -#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0) - -#endif /* __ASM_PPC_CPUTABLE_H */ -#endif /* __KERNEL__ */ - diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index afe26ffc2e2d..4f152cca13c1 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -164,13 +164,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { #ifdef CONFIG_ALTIVEC - asm volatile ( - BEGIN_FTR_SECTION - "dssall;\n" + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + asm volatile ("dssall;\n" #ifndef CONFIG_POWER4 "sync;\n" /* G4 needs a sync here, G5 apparently not */ #endif - END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) : : ); #endif /* CONFIG_ALTIVEC */ diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h deleted file mode 100644 index 3eef40efd082..000000000000 --- a/include/asm-ppc64/cputable.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * include/asm-ppc64/cputable.h - * - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * Modifications for ppc64: - * Copyright (C) 2003 Dave Engebretsen - * - * 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_PPC_CPUTABLE_H -#define __ASM_PPC_CPUTABLE_H - -#include -#include /* for ASM_CONST */ - -/* Exposed to userland CPU features - Must match ppc32 definitions */ -#define PPC_FEATURE_32 0x80000000 -#define PPC_FEATURE_64 0x40000000 -#define PPC_FEATURE_601_INSTR 0x20000000 -#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 -#define PPC_FEATURE_HAS_FPU 0x08000000 -#define PPC_FEATURE_HAS_MMU 0x04000000 -#define PPC_FEATURE_HAS_4xxMAC 0x02000000 -#define PPC_FEATURE_UNIFIED_CACHE 0x01000000 - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -/* This structure can grow, it's real size is used by head.S code - * via the mkdefs mechanism. - */ -struct cpu_spec; -struct op_powerpc_model; - -typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec); - -struct cpu_spec { - /* CPU is matched via (PVR & pvr_mask) == pvr_value */ - unsigned int pvr_mask; - unsigned int pvr_value; - - char *cpu_name; - unsigned long cpu_features; /* Kernel features */ - unsigned int cpu_user_features; /* Userland features */ - - /* cache line sizes */ - unsigned int icache_bsize; - unsigned int dcache_bsize; - - /* number of performance monitor counters */ - unsigned int num_pmcs; - - /* this is called to initialize various CPU bits like L1 cache, - * BHT, SPD, etc... from head.S before branching to identify_machine - */ - cpu_setup_t cpu_setup; - - /* Used by oprofile userspace to select the right counters */ - char *oprofile_cpu_type; - - /* Processor specific oprofile operations */ - struct op_powerpc_model *oprofile_model; -}; - -extern struct cpu_spec cpu_specs[]; -extern struct cpu_spec *cur_cpu_spec; - -static inline unsigned long cpu_has_feature(unsigned long feature) -{ - return cur_cpu_spec->cpu_features & feature; -} - -#endif /* __ASSEMBLY__ */ - -/* CPU kernel features */ - -/* Retain the 32b definitions for the time being - use bottom half of word */ -#define CPU_FTR_SPLIT_ID_CACHE ASM_CONST(0x0000000000000001) -#define CPU_FTR_L2CR ASM_CONST(0x0000000000000002) -#define CPU_FTR_SPEC7450 ASM_CONST(0x0000000000000004) -#define CPU_FTR_ALTIVEC ASM_CONST(0x0000000000000008) -#define CPU_FTR_TAU ASM_CONST(0x0000000000000010) -#define CPU_FTR_CAN_DOZE ASM_CONST(0x0000000000000020) -#define CPU_FTR_USE_TB ASM_CONST(0x0000000000000040) -#define CPU_FTR_604_PERF_MON ASM_CONST(0x0000000000000080) -#define CPU_FTR_601 ASM_CONST(0x0000000000000100) -#define CPU_FTR_HPTE_TABLE ASM_CONST(0x0000000000000200) -#define CPU_FTR_CAN_NAP ASM_CONST(0x0000000000000400) -#define CPU_FTR_L3CR ASM_CONST(0x0000000000000800) -#define CPU_FTR_L3_DISABLE_NAP ASM_CONST(0x0000000000001000) -#define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x0000000000002000) -#define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x0000000000004000) - -/* Add the 64b processor unique features in the top half of the word */ -#define CPU_FTR_SLB ASM_CONST(0x0000000100000000) -#define CPU_FTR_16M_PAGE ASM_CONST(0x0000000200000000) -#define CPU_FTR_TLBIEL ASM_CONST(0x0000000400000000) -#define CPU_FTR_NOEXECUTE ASM_CONST(0x0000000800000000) -#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000001000000000) -#define CPU_FTR_IABR ASM_CONST(0x0000002000000000) -#define CPU_FTR_MMCRA ASM_CONST(0x0000004000000000) -/* unused ASM_CONST(0x0000008000000000) */ -#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_CTRL ASM_CONST(0x0000100000000000) - -#ifndef __ASSEMBLY__ - -#define COMMON_USER_PPC64 (PPC_FEATURE_32 | PPC_FEATURE_64 | \ - PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_MMU) - -#define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \ - CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \ - CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL) - -/* iSeries doesn't support large pages */ -#ifdef CONFIG_PPC_ISERIES -#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_PPCAS_ARCH_V2_BASE) -#else -#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_PPCAS_ARCH_V2_BASE | CPU_FTR_16M_PAGE) -#endif /* CONFIG_PPC_ISERIES */ - -#endif /* __ASSEMBLY */ - -#ifdef __ASSEMBLY__ - -#define BEGIN_FTR_SECTION 98: - -#define END_FTR_SECTION(msk, val) \ -99: \ - .section __ftr_fixup,"a"; \ - .align 3; \ - .llong msk; \ - .llong val; \ - .llong 98b; \ - .llong 99b; \ - .previous - -#else - -#define BEGIN_FTR_SECTION "98:\n" -#define END_FTR_SECTION(msk, val) \ -"99:\n" \ -" .section __ftr_fixup,\"a\";\n" \ -" .align 3;\n" \ -" .llong "#msk";\n" \ -" .llong "#val";\n" \ -" .llong 98b;\n" \ -" .llong 99b;\n" \ -" .previous\n" - -#endif /* __ASSEMBLY__ */ - -#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk)) -#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0) - -#endif /* __ASM_PPC_CPUTABLE_H */ -#endif /* __KERNEL__ */ - From 400d221274426958f1e1c7081a247bea9cede696 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 27 Sep 2005 15:13:12 -0500 Subject: [PATCH 0226/1939] [PATCH] ppc32: make cur_cpu_spec a single pointer instead of an array Changed ppc32 so that cur_cpu_spec is just a single pointer for all CPUs. Additionally, made call_setup_cpu check to see if the cpu_setup pointer is NULL or not before calling the function. This lets remove the dummy cpu_setup calls that just return. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head.S | 6 ---- arch/powerpc/oprofile/common.c | 6 ++-- arch/powerpc/platforms/powermac/pmac_setup.c | 2 +- arch/ppc/kernel/cpu_setup_6xx.S | 2 -- arch/ppc/kernel/cpu_setup_power4.S | 2 -- arch/ppc/kernel/cputable.c | 33 ++++++++------------ arch/ppc/kernel/head.S | 6 ---- arch/ppc/kernel/misc.S | 22 ++++++------- arch/ppc/kernel/setup.c | 14 ++++----- arch/ppc/platforms/4xx/ebony.c | 2 +- arch/ppc/platforms/pmac_setup.c | 2 +- arch/ppc/platforms/radstone_ppc7d.c | 8 ++--- arch/ppc/syslib/ibm440gx_common.c | 6 ++-- include/asm-powerpc/cputable.h | 16 ---------- include/asm-powerpc/elf.h | 4 +-- 15 files changed, 43 insertions(+), 88 deletions(-) diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S index d05509f197d0..8cdac7385e7f 100644 --- a/arch/powerpc/kernel/head.S +++ b/arch/powerpc/kernel/head.S @@ -1059,7 +1059,6 @@ __secondary_start: lis r3,-KERNELBASE@h mr r4,r24 - bl identify_cpu bl call_setup_cpu /* Call setup_cpu for this CPU */ #ifdef CONFIG_6xx lis r3,-KERNELBASE@h @@ -1109,11 +1108,6 @@ __secondary_start: * Those generic dummy functions are kept for CPUs not * included in CONFIG_6xx */ -_GLOBAL(__setup_cpu_power3) - blr -_GLOBAL(__setup_cpu_generic) - blr - #if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) _GLOBAL(__save_cpu_setup) blr diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 88b4118fd0c5..0ec12c8f2c01 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -155,8 +155,6 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) int __init oprofile_arch_init(struct oprofile_operations *ops) { #ifndef __powerpc64__ - int cpu_id = smp_processor_id(); - #ifdef CONFIG_FSL_BOOKE model = &op_model_fsl_booke; #else @@ -167,9 +165,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) if (NULL == cpu_type) return -ENOMEM; - sprintf(cpu_type, "ppc/%s", cur_cpu_spec[cpu_id]->cpu_name); + sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name); - model->num_counters = cur_cpu_spec[cpu_id]->num_pmcs; + model->num_counters = cur_cpu_spec->num_pmcs; ops->cpu_type = cpu_type; #else /* __powerpc64__ */ diff --git a/arch/powerpc/platforms/powermac/pmac_setup.c b/arch/powerpc/platforms/powermac/pmac_setup.c index dbc921a084cd..3667e0b2b8e3 100644 --- a/arch/powerpc/platforms/powermac/pmac_setup.c +++ b/arch/powerpc/platforms/powermac/pmac_setup.c @@ -445,7 +445,7 @@ static int pmac_pm_enter(suspend_state_t state) enable_kernel_fp(); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) enable_kernel_altivec(); #endif /* CONFIG_ALTIVEC */ diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index ba396438ede3..a5333c07fc3c 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -17,8 +17,6 @@ #include #include -_GLOBAL(__setup_cpu_601) - blr _GLOBAL(__setup_cpu_603) b setup_common_caches _GLOBAL(__setup_cpu_604) diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S index 7e4fbb653724..0abb5f25b2ca 100644 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ b/arch/ppc/kernel/cpu_setup_power4.S @@ -63,8 +63,6 @@ _GLOBAL(__970_cpu_preinit) isync blr -_GLOBAL(__setup_cpu_power4) - blr _GLOBAL(__setup_cpu_ppc970) mfspr r0,SPRN_HID0 li r11,5 /* clear DOZE and SLEEP */ diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index 97663d5d96ca..207d4dd059d9 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -14,23 +14,22 @@ #include #include #include +#include + +#include #include -struct cpu_spec* cur_cpu_spec[NR_CPUS]; +struct cpu_spec* cur_cpu_spec = NULL; -extern void __setup_cpu_601(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_603(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_604(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_750(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_750cx(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_750fx(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_7400(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_7410(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_745x(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_power3(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_power4(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_ppc970(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spec* spec); +extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_750cx(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_750fx(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_7400(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); #define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \ !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \ @@ -62,7 +61,6 @@ struct cpu_spec cpu_specs[] = { PPC_FEATURE_UNIFIED_CACHE, .icache_bsize = 32, .dcache_bsize = 32, - .cpu_setup = __setup_cpu_601 }, { /* 603 */ .pvr_mask = 0xffff0000, @@ -451,7 +449,6 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_PPC, .icache_bsize = 32, .dcache_bsize = 32, - .cpu_setup = __setup_cpu_generic }, #endif /* CLASSIC_PPC */ #ifdef CONFIG_PPC64BRIDGE @@ -464,7 +461,6 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3 }, { /* Power3+ */ .pvr_mask = 0xffff0000, @@ -475,7 +471,6 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3 }, { /* I-star */ .pvr_mask = 0xffff0000, @@ -486,7 +481,6 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3 }, { /* S-star */ .pvr_mask = 0xffff0000, @@ -497,7 +491,6 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3 }, #endif /* CONFIG_PPC64BRIDGE */ #ifdef CONFIG_POWER4 diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index d05509f197d0..8cdac7385e7f 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1059,7 +1059,6 @@ __secondary_start: lis r3,-KERNELBASE@h mr r4,r24 - bl identify_cpu bl call_setup_cpu /* Call setup_cpu for this CPU */ #ifdef CONFIG_6xx lis r3,-KERNELBASE@h @@ -1109,11 +1108,6 @@ __secondary_start: * Those generic dummy functions are kept for CPUs not * included in CONFIG_6xx */ -_GLOBAL(__setup_cpu_power3) - blr -_GLOBAL(__setup_cpu_generic) - blr - #if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) _GLOBAL(__save_cpu_setup) blr diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 9d2cb79475c6..2b9a16274b0b 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -125,9 +125,8 @@ _GLOBAL(identify_cpu) 1: addis r6,r3,cur_cpu_spec@ha addi r6,r6,cur_cpu_spec@l - slwi r4,r4,2 sub r8,r8,r3 - stwx r8,r4,r6 + stw r8,0(r6) blr /* @@ -186,19 +185,18 @@ _GLOBAL(do_cpu_ftr_fixups) * * Setup function is called with: * r3 = data offset - * r4 = CPU number - * r5 = ptr to CPU spec (relocated) + * r4 = ptr to CPU spec (relocated) */ _GLOBAL(call_setup_cpu) - addis r5,r3,cur_cpu_spec@ha - addi r5,r5,cur_cpu_spec@l - slwi r4,r24,2 - lwzx r5,r4,r5 + addis r4,r3,cur_cpu_spec@ha + addi r4,r4,cur_cpu_spec@l + lwz r4,0(r4) + add r4,r4,r3 + lwz r5,CPU_SPEC_SETUP(r4) + cmpi 0,r5,0 add r5,r5,r3 - lwz r6,CPU_SPEC_SETUP(r5) - add r6,r6,r3 - mtctr r6 - mr r4,r24 + beqlr + mtctr r5 bctr #if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 1b891b806f3d..62022eacf63e 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -188,18 +188,18 @@ int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t: %d\n", i); seq_printf(m, "cpu\t\t: "); - if (cur_cpu_spec[i]->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec[i]->cpu_name); + if (cur_cpu_spec->pvr_mask) + seq_printf(m, "%s", cur_cpu_spec->cpu_name); else seq_printf(m, "unknown (%08x)", pvr); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[i]->cpu_features & CPU_FTR_ALTIVEC) + if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) seq_printf(m, ", altivec supported"); #endif seq_printf(m, "\n"); #ifdef CONFIG_TAU - if (cur_cpu_spec[i]->cpu_features & CPU_FTR_TAU) { + if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { #ifdef CONFIG_TAU_AVERAGE /* more straightforward, but potentially misleading */ seq_printf(m, "temperature \t: %u C (uncalibrated)\n", @@ -754,12 +754,12 @@ void __init setup_arch(char **cmdline_p) * for a possibly more accurate value. */ if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { - dcache_bsize = cur_cpu_spec[0]->dcache_bsize; - icache_bsize = cur_cpu_spec[0]->icache_bsize; + dcache_bsize = cur_cpu_spec->dcache_bsize; + icache_bsize = cur_cpu_spec->icache_bsize; ucache_bsize = 0; } else ucache_bsize = dcache_bsize = icache_bsize - = cur_cpu_spec[0]->dcache_bsize; + = cur_cpu_spec->dcache_bsize; /* reboot on panic */ panic_timeout = 180; diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index d6b2b1965dcb..9decb72e7aaf 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -91,7 +91,7 @@ ebony_calibrate_decr(void) * on Rev. C silicon then errata forces us to * use the internal clock. */ - if (strcmp(cur_cpu_spec[0]->cpu_name, "440GP Rev. B") == 0) + if (strcmp(cur_cpu_spec->cpu_name, "440GP Rev. B") == 0) freq = EBONY_440GP_RB_SYSCLK; else freq = EBONY_440GP_RC_SYSCLK; diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index 1ad779ecc8fc..e6a12182bfbb 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -448,7 +448,7 @@ static int pmac_pm_enter(suspend_state_t state) enable_kernel_fp(); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) enable_kernel_altivec(); #endif /* CONFIG_ALTIVEC */ diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index c30607a972d8..06ec30f7e2f4 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -1185,18 +1185,18 @@ static void __init ppc7d_setup_arch(void) ROOT_DEV = Root_HDA1; #endif - if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) || - (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)) + if ((cur_cpu_spec->cpu_features & CPU_FTR_SPEC7450) || + (cur_cpu_spec->cpu_features & CPU_FTR_L3CR)) /* 745x is different. We only want to pass along enable. */ _set_L2CR(L2CR_L2E); - else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) + else if (cur_cpu_spec->cpu_features & CPU_FTR_L2CR) /* All modules have 1MB of L2. We also assume that an * L2 divisor of 3 will work. */ _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3 | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF); - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) + if (cur_cpu_spec->cpu_features & CPU_FTR_L3CR) /* No L3 cache */ _set_L3CR(0); diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c index 0bb919859b8b..c36db279b43d 100644 --- a/arch/ppc/syslib/ibm440gx_common.c +++ b/arch/ppc/syslib/ibm440gx_common.c @@ -236,9 +236,9 @@ void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p) /* Disable L2C on rev.A, rev.B and 800MHz version of rev.C, enable it on all other revisions */ - if (strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. A") == 0 || - strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. B") == 0 - || (strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. C") + if (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. A") == 0 || + strcmp(cur_cpu_spec->cpu_name, "440GX Rev. B") == 0 + || (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C") == 0 && p->cpu > 667000000)) ibm440gx_l2c_disable(); else diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 5f81d44963f1..1e50efab091d 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -25,11 +25,7 @@ struct cpu_spec; struct op_powerpc_model; -#ifdef __powerpc64__ typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec); -#else /* __powerpc64__ */ -typedef void (*cpu_setup_t)(unsigned long offset, int cpu_nr, struct cpu_spec* spec); -#endif /* __powerpc64__ */ struct cpu_spec { /* CPU is matched via (PVR & pvr_mask) == pvr_value */ @@ -51,23 +47,15 @@ struct cpu_spec { * BHT, SPD, etc... from head.S before branching to identify_machine */ cpu_setup_t cpu_setup; -#ifdef __powerpc64__ /* Used by oprofile userspace to select the right counters */ char *oprofile_cpu_type; /* Processor specific oprofile operations */ struct op_powerpc_model *oprofile_model; -#endif /* __powerpc64__ */ }; -extern struct cpu_spec cpu_specs[]; - -#ifdef __powerpc64__ extern struct cpu_spec *cur_cpu_spec; -#else /* __powerpc64__ */ -extern struct cpu_spec *cur_cpu_spec[]; -#endif /* __powerpc64__ */ #endif /* __ASSEMBLY__ */ @@ -398,11 +386,7 @@ static inline int cpu_has_feature(unsigned long feature) { return (CPU_FTRS_ALWAYS & feature) || (CPU_FTRS_POSSIBLE -#ifndef __powerpc64__ - & cur_cpu_spec[0]->cpu_features -#else & cur_cpu_spec->cpu_features -#endif & feature); } diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index 36b9d5cec50c..f0a6779fbe52 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -212,15 +212,13 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); /* ELF_HWCAP yields a mask that user programs can use to figure out what instruction set this cpu supports. This could be done in userspace, but it's not easy, and we've already done it here. */ -#ifdef __powerpc64__ # define ELF_HWCAP (cur_cpu_spec->cpu_user_features) +#ifdef __powerpc64__ # define ELF_PLAT_INIT(_r, load_addr) do { \ memset(_r->gpr, 0, sizeof(_r->gpr)); \ _r->ctr = _r->link = _r->xer = _r->ccr = 0; \ _r->gpr[2] = load_addr; \ } while (0) -#else -# define ELF_HWCAP (cur_cpu_spec[0]->cpu_user_features) #endif /* __powerpc64__ */ /* This yields a string that ld.so will use to load implementation From a3a9e99e36b2897b3e038869e61f363d62434086 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 28 Sep 2005 15:53:36 +1000 Subject: [PATCH 0227/1939] powerpc: Fix building in the old arch's boot directory for now Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index d94878193cd9..92751ca6f8b1 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -152,13 +152,13 @@ CPPFLAGS_vmlinux.lds := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage -boot := arch/$(ARCH)/boot +boot := arch/$(OLDARCH)/boot $(BOOT_TARGETS): vmlinux - $(Q)$(MAKE) $(build)=$(boot) $@ + $(Q)$(MAKE) ARCH=$(OLDARCH) $(build)=$(boot) $@ uImage: vmlinux - $(Q)$(MAKE) $(build)=$(boot)/images $(boot)/images/$@ + $(Q)$(MAKE) ARCH=$(OLDARCH) $(build)=$(boot)/images $(boot)/images/$@ define archhelp @echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/images/zImage.*)' @@ -171,7 +171,7 @@ define archhelp endef archclean: - $(Q)$(MAKE) $(clean)=arch/ppc/boot + $(Q)$(MAKE) $(clean)=$(boot) # Temporary hack until we have migrated to asm-powerpc $(Q)rm -rf arch/$(ARCH)/include From 20c8c2106305729e7d5e06f6c3d390e965a3dd34 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 28 Sep 2005 20:28:14 +1000 Subject: [PATCH 0228/1939] powerpc: Fixes to get the merged kernel to boot on powermac. This merges ppc_ksyms.c, puts back the actual do_execve call in sys_execve, makes init_MMU call find_end_of_memory rather than ppc_md.find_end_of_memory (every platform has a device tree with a /memory node now, right?) and fixes some problems with the mpic initialization on newworld powermacs. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/ppc_ksyms.c | 338 +++++++++++++++++++++ arch/powerpc/kernel/process.c | 2 + arch/powerpc/mm/init.c | 2 +- arch/powerpc/platforms/powermac/pmac_pic.c | 17 ++ arch/ppc/kernel/Makefile | 2 +- 6 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 arch/powerpc/kernel/ppc_ksyms.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 62c4a51a23d7..58c130b10ec8 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -14,5 +14,5 @@ extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y := semaphore.o traps.o process.o - +obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c new file mode 100644 index 000000000000..7bfa0f0121ff --- /dev/null +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -0,0 +1,338 @@ +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_8xx +#include +#endif + +extern void transfer_to_handler(void); +extern void do_IRQ(struct pt_regs *regs); +extern void MachineCheckException(struct pt_regs *regs); +extern void AlignmentException(struct pt_regs *regs); +extern void ProgramCheckException(struct pt_regs *regs); +extern void SingleStepException(struct pt_regs *regs); +extern int do_signal(sigset_t *, struct pt_regs *); +extern int pmac_newworld; +extern int sys_sigreturn(struct pt_regs *regs); + +long long __ashrdi3(long long, int); +long long __ashldi3(long long, int); +long long __lshrdi3(long long, int); + +extern unsigned long mm_ptov (unsigned long paddr); + +EXPORT_SYMBOL(clear_pages); +EXPORT_SYMBOL(clear_user_page); +EXPORT_SYMBOL(do_signal); +EXPORT_SYMBOL(transfer_to_handler); +EXPORT_SYMBOL(do_IRQ); +EXPORT_SYMBOL(MachineCheckException); +EXPORT_SYMBOL(AlignmentException); +EXPORT_SYMBOL(ProgramCheckException); +EXPORT_SYMBOL(SingleStepException); +EXPORT_SYMBOL(sys_sigreturn); +EXPORT_SYMBOL(ppc_n_lost_interrupts); +EXPORT_SYMBOL(ppc_lost_interrupts); + +EXPORT_SYMBOL(ISA_DMA_THRESHOLD); +EXPORT_SYMBOL(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_WRITE); +#if defined(CONFIG_PPC_PREP) +EXPORT_SYMBOL(_prep_type); +EXPORT_SYMBOL(ucSystemType); +#endif + +#if !defined(__INLINE_BITOPS) +EXPORT_SYMBOL(set_bit); +EXPORT_SYMBOL(clear_bit); +EXPORT_SYMBOL(change_bit); +EXPORT_SYMBOL(test_and_set_bit); +EXPORT_SYMBOL(test_and_clear_bit); +EXPORT_SYMBOL(test_and_change_bit); +#endif /* __INLINE_BITOPS */ + +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strcasecmp); +EXPORT_SYMBOL(__div64_32); + +EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(ip_fast_csum); +EXPORT_SYMBOL(csum_tcpudp_magic); + +EXPORT_SYMBOL(__copy_tofrom_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__strnlen_user); + +EXPORT_SYMBOL(_insb); +EXPORT_SYMBOL(_outsb); +EXPORT_SYMBOL(_insw); +EXPORT_SYMBOL(_outsw); +EXPORT_SYMBOL(_insl); +EXPORT_SYMBOL(_outsl); +EXPORT_SYMBOL(_insw_ns); +EXPORT_SYMBOL(_outsw_ns); +EXPORT_SYMBOL(_insl_ns); +EXPORT_SYMBOL(_outsl_ns); +EXPORT_SYMBOL(iopa); +EXPORT_SYMBOL(mm_ptov); +EXPORT_SYMBOL(ioremap); +#ifdef CONFIG_44x +EXPORT_SYMBOL(ioremap64); +#endif +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */ + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +EXPORT_SYMBOL(ppc_ide_md); +#endif + +#ifdef CONFIG_PCI +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(isa_mem_base); +EXPORT_SYMBOL(pci_dram_offset); +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); +EXPORT_SYMBOL(pci_bus_io_base); +EXPORT_SYMBOL(pci_bus_io_base_phys); +EXPORT_SYMBOL(pci_bus_mem_base_phys); +EXPORT_SYMBOL(pci_bus_to_hose); +EXPORT_SYMBOL(pci_resource_to_bus); +EXPORT_SYMBOL(pci_phys_to_bus); +EXPORT_SYMBOL(pci_bus_to_phys); +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_NOT_COHERENT_CACHE +EXPORT_SYMBOL(flush_dcache_all); +#endif + +EXPORT_SYMBOL(start_thread); +EXPORT_SYMBOL(kernel_thread); + +EXPORT_SYMBOL(flush_instruction_cache); +EXPORT_SYMBOL(giveup_fpu); +#ifdef CONFIG_PPC64 +EXPORT_SYMBOL(__flush_icache_range); +#else +EXPORT_SYMBOL(flush_icache_range); +#endif +EXPORT_SYMBOL(flush_dcache_range); +EXPORT_SYMBOL(flush_icache_user_range); +EXPORT_SYMBOL(flush_dcache_page); +EXPORT_SYMBOL(flush_tlb_kernel_range); +EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(_tlbie); +#ifdef CONFIG_ALTIVEC +EXPORT_SYMBOL(last_task_used_altivec); +EXPORT_SYMBOL(giveup_altivec); +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE +EXPORT_SYMBOL(last_task_used_spe); +EXPORT_SYMBOL(giveup_spe); +#endif /* CONFIG_SPE */ +#ifdef CONFIG_SMP +EXPORT_SYMBOL(smp_call_function); +EXPORT_SYMBOL(smp_hw_index); +#endif + +EXPORT_SYMBOL(ppc_md); + +#ifdef CONFIG_ADB +EXPORT_SYMBOL(adb_request); +EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(adb_unregister); +EXPORT_SYMBOL(adb_poll); +EXPORT_SYMBOL(adb_try_handler_change); +#endif /* CONFIG_ADB */ +#ifdef CONFIG_ADB_CUDA +EXPORT_SYMBOL(cuda_request); +EXPORT_SYMBOL(cuda_poll); +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_PPC_MULTIPLATFORM +EXPORT_SYMBOL(_machine); +#endif +#ifdef CONFIG_PPC_PMAC +EXPORT_SYMBOL(sys_ctrler); +EXPORT_SYMBOL(pmac_newworld); +#endif +#ifdef CONFIG_PPC_OF +EXPORT_SYMBOL(find_devices); +EXPORT_SYMBOL(find_type_devices); +EXPORT_SYMBOL(find_compatible_devices); +EXPORT_SYMBOL(find_path_device); +EXPORT_SYMBOL(device_is_compatible); +EXPORT_SYMBOL(machine_is_compatible); +EXPORT_SYMBOL(find_all_nodes); +EXPORT_SYMBOL(get_property); +EXPORT_SYMBOL(request_OF_resource); +EXPORT_SYMBOL(release_OF_resource); +EXPORT_SYMBOL(pci_busdev_to_OF_node); +EXPORT_SYMBOL(pci_device_to_OF_node); +EXPORT_SYMBOL(pci_device_from_OF_node); +EXPORT_SYMBOL(of_find_node_by_name); +EXPORT_SYMBOL(of_find_node_by_type); +EXPORT_SYMBOL(of_find_compatible_node); +EXPORT_SYMBOL(of_find_node_by_path); +EXPORT_SYMBOL(of_find_all_nodes); +EXPORT_SYMBOL(of_get_parent); +EXPORT_SYMBOL(of_get_next_child); +EXPORT_SYMBOL(of_node_get); +EXPORT_SYMBOL(of_node_put); +#endif /* CONFIG_PPC_OF */ +#if defined(CONFIG_BOOTX_TEXT) +EXPORT_SYMBOL(btext_update_display); +#endif +#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC) +EXPORT_SYMBOL(note_scsi_host); +#endif +#ifdef CONFIG_VT +EXPORT_SYMBOL(kd_mksound); +#endif +EXPORT_SYMBOL(to_tm); + +EXPORT_SYMBOL(pm_power_off); + +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(cacheable_memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); + +#if defined(CONFIG_FB_VGA16_MODULE) +EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL(__delay); +EXPORT_SYMBOL(timer_interrupt); +EXPORT_SYMBOL(irq_desc); +EXPORT_SYMBOL(tb_ticks_per_jiffy); +EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(console_drivers); + +#ifdef CONFIG_PPC_ISERIES +EXPORT_SYMBOL(local_irq_disable); +EXPORT_SYMBOL(local_irq_enable); +EXPORT_SYMBOL(local_get_flags); +#endif + +#ifdef CONFIG_XMON +EXPORT_SYMBOL(xmon); +EXPORT_SYMBOL(xmon_printf); +#endif +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); + +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) +extern void (*debugger)(struct pt_regs *regs); +extern int (*debugger_bpt)(struct pt_regs *regs); +extern int (*debugger_sstep)(struct pt_regs *regs); +extern int (*debugger_iabr_match)(struct pt_regs *regs); +extern int (*debugger_dabr_match)(struct pt_regs *regs); +extern void (*debugger_fault_handler)(struct pt_regs *regs); + +EXPORT_SYMBOL(debugger); +EXPORT_SYMBOL(debugger_bpt); +EXPORT_SYMBOL(debugger_sstep); +EXPORT_SYMBOL(debugger_iabr_match); +EXPORT_SYMBOL(debugger_dabr_match); +EXPORT_SYMBOL(debugger_fault_handler); +#endif + +#ifdef CONFIG_8xx +EXPORT_SYMBOL(cpm_install_handler); +EXPORT_SYMBOL(cpm_free_handler); +#endif /* CONFIG_8xx */ +#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) ||\ + defined(CONFIG_83xx) +EXPORT_SYMBOL(__res); +#endif + +EXPORT_SYMBOL(next_mmu_context); +EXPORT_SYMBOL(set_context); +EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */ +EXPORT_SYMBOL(disarm_decr); +#ifdef CONFIG_PPC_STD_MMU +extern long mol_trampoline; +EXPORT_SYMBOL(mol_trampoline); /* For MOL */ +EXPORT_SYMBOL(flush_hash_pages); /* For MOL */ +#ifdef CONFIG_SMP +extern int mmu_hash_lock; +EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ +#endif /* CONFIG_SMP */ +extern long *intercept_table; +EXPORT_SYMBOL(intercept_table); +#endif /* CONFIG_PPC_STD_MMU */ +EXPORT_SYMBOL(cur_cpu_spec); +#ifdef CONFIG_PPC_PMAC +extern unsigned long agp_special_page; +EXPORT_SYMBOL(agp_special_page); +#endif +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +EXPORT_SYMBOL(__mtdcr); +EXPORT_SYMBOL(__mfdcr); +#endif diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f5a9d2a84fa1..e3946769dd8e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -601,6 +601,8 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, flush_fp_to_thread(current); flush_altivec_to_thread(current); flush_spe_to_thread(current); + error = do_execve(filename, (char __user * __user *) a1, + (char __user * __user *) a2, regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; diff --git a/arch/powerpc/mm/init.c b/arch/powerpc/mm/init.c index f4d983a6e521..3a81ef15c67e 100644 --- a/arch/powerpc/mm/init.c +++ b/arch/powerpc/mm/init.c @@ -239,7 +239,7 @@ void __init MMU_init(void) if (boot_mem_size) total_memory = boot_mem_size; else - total_memory = ppc_md.find_end_of_memory(); + total_memory = find_end_of_memory(); if (__max_memory && total_memory > __max_memory) total_memory = __max_memory; diff --git a/arch/powerpc/platforms/powermac/pmac_pic.c b/arch/powerpc/platforms/powermac/pmac_pic.c index bf3e1899a4cc..a6b1b577e19f 100644 --- a/arch/powerpc/platforms/powermac/pmac_pic.c +++ b/arch/powerpc/platforms/powermac/pmac_pic.c @@ -424,6 +424,8 @@ void __init pmac_pic_init(void) printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", (unsigned int)irqctrler->addrs[0].address); + ppc_md.get_irq = mpic_get_irq; + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); prom_get_irq_senses(senses, 0, 128); mpic1 = mpic_alloc(irqctrler->addrs[0].address, @@ -452,7 +454,22 @@ void __init pmac_pic_init(void) mpic_setup_cascade(irqctrler2->intrs[0].line, pmac_u3_cascade, mpic2); } +#ifdef CONFIG_XMON + { + struct device_node* pswitch; + int nmi_irq; + + pswitch = find_devices("programmer-switch"); + if (pswitch && pswitch->n_intrs) { + nmi_irq = pswitch->intrs[0].line; + openpic_init_nmi_irq(nmi_irq); + setup_irq(nmi_irq, &xmon_action); + } + } +#endif /* CONFIG_XMON */ + return; } + irqctrler = NULL; /* Get the level/edge settings, assume if it's not * a Grand Central nor an OHare, then it's an Heathrow diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0649540bc7d9..467f96480355 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -47,7 +47,7 @@ obj-y := entry.o irq.o idle.o time.o misc.o \ obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o -obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_KGDB) += ppc-stub.o From beeca08738c4c4024c81a591812bfe38f8c436c0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 28 Sep 2005 20:29:44 +1000 Subject: [PATCH 0229/1939] Don't call a NULL ack function in the generic IRQ code. Some IRQ controllers don't need an ack function (e.g. OpenPIC on PPC platforms) and for them we'd rather not have the overhead of doing an indirect call to a function that does nothing. Signed-off-by: Paul Mackerras --- kernel/irq/handle.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 3ff7b925c387..51df337b37db 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -117,14 +117,16 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) /* * No locking required for CPU-local interrupts: */ - desc->handler->ack(irq); + if (desc->handler->ack) + desc->handler->ack(irq); action_ret = handle_IRQ_event(irq, regs, desc->action); desc->handler->end(irq); return 1; } spin_lock(&desc->lock); - desc->handler->ack(irq); + if (desc->handler->ack) + desc->handler->ack(irq); /* * REPLAY is when Linux resends an IRQ that was dropped earlier * WAITING is used by probe to mark irqs that are being tested From ee500aabf10323a7e313731b8c0be7c2c6dd27c7 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:34:38 +0800 Subject: [PATCH 0230/1939] [PATCH] libata: indent and whitespace change Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 2 +- drivers/scsi/sata_promise.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e5b01997117a..cc68f5706acf 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3586,7 +3586,7 @@ u8 ata_bmdma_status(struct ata_port *ap) void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); return host_stat; } diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 538ad727bd2e..def7e0d9dacb 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -438,11 +438,11 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, break; default: - ap->stats.idle_irq++; - break; + ap->stats.idle_irq++; + break; } - return handled; + return handled; } static void pdc_irq_clear(struct ata_port *ap) From 14be71f4c5c5ad1e222c5202ee6d234e9c8828b7 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:36:35 +0800 Subject: [PATCH 0231/1939] [PATCH] libata: rename host states Changes: s/PIO_ST_/HSM_ST_/ and s/pio_task_state/hsm_task_state/. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 76 +++++++++++++++++++------------------- include/linux/libata.h | 20 +++++----- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cc68f5706acf..c4fcdc30f18c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2425,20 +2425,20 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) static unsigned long ata_pio_poll(struct ata_port *ap) { u8 status; - unsigned int poll_state = PIO_ST_UNKNOWN; - unsigned int reg_state = PIO_ST_UNKNOWN; - const unsigned int tmout_state = PIO_ST_TMOUT; + unsigned int poll_state = HSM_ST_UNKNOWN; + unsigned int reg_state = HSM_ST_UNKNOWN; + const unsigned int tmout_state = HSM_ST_TMOUT; - switch (ap->pio_task_state) { - case PIO_ST: - case PIO_ST_POLL: - poll_state = PIO_ST_POLL; - reg_state = PIO_ST; + switch (ap->hsm_task_state) { + case HSM_ST: + case HSM_ST_POLL: + poll_state = HSM_ST_POLL; + reg_state = HSM_ST; break; - case PIO_ST_LAST: - case PIO_ST_LAST_POLL: - poll_state = PIO_ST_LAST_POLL; - reg_state = PIO_ST_LAST; + case HSM_ST_LAST: + case HSM_ST_LAST_POLL: + poll_state = HSM_ST_LAST_POLL; + reg_state = HSM_ST_LAST; break; default: BUG(); @@ -2448,14 +2448,14 @@ static unsigned long ata_pio_poll(struct ata_port *ap) status = ata_chk_status(ap); if (status & ATA_BUSY) { if (time_after(jiffies, ap->pio_task_timeout)) { - ap->pio_task_state = tmout_state; + ap->hsm_task_state = tmout_state; return 0; } - ap->pio_task_state = poll_state; + ap->hsm_task_state = poll_state; return ATA_SHORT_PAUSE; } - ap->pio_task_state = reg_state; + ap->hsm_task_state = reg_state; return 0; } @@ -2480,14 +2480,14 @@ 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 - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { msleep(2); drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { - ap->pio_task_state = PIO_ST_LAST_POLL; + ap->hsm_task_state = HSM_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return 0; } @@ -2495,14 +2495,14 @@ static int ata_pio_complete (struct ata_port *ap) drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; ata_poll_qc_complete(qc, drv_stat); @@ -2662,7 +2662,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned char *buf; if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; @@ -2712,7 +2712,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) unsigned int offset, count; if (qc->curbytes + bytes >= qc->nbytes) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; next_sg: if (unlikely(qc->cursg >= qc->n_elem)) { @@ -2734,7 +2734,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) for (i = 0; i < words; i++) ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2815,7 +2815,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) err_out: printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", ap->id, dev->devno); - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; } /** @@ -2837,14 +2837,14 @@ static void ata_pio_block(struct ata_port *ap) * 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 - * PIO_ST_POLL state. + * 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->pio_task_state = PIO_ST_POLL; + ap->hsm_task_state = HSM_ST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return; } @@ -2856,7 +2856,7 @@ static void ata_pio_block(struct ata_port *ap) if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2864,7 +2864,7 @@ static void ata_pio_block(struct ata_port *ap) } else { /* handle BSY=0, DRQ=0 as error */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return; } @@ -2884,7 +2884,7 @@ static void ata_pio_error(struct ata_port *ap) printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", ap->id, drv_stat); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; ata_poll_qc_complete(qc, drv_stat | ATA_ERR); } @@ -2899,25 +2899,25 @@ static void ata_pio_task(void *_data) timeout = 0; qc_completed = 0; - switch (ap->pio_task_state) { - case PIO_ST_IDLE: + switch (ap->hsm_task_state) { + case HSM_ST_IDLE: return; - case PIO_ST: + case HSM_ST: ata_pio_block(ap); break; - case PIO_ST_LAST: + case HSM_ST_LAST: qc_completed = ata_pio_complete(ap); break; - case PIO_ST_POLL: - case PIO_ST_LAST_POLL: + case HSM_ST_POLL: + case HSM_ST_LAST_POLL: timeout = ata_pio_poll(ap); break; - case PIO_ST_TMOUT: - case PIO_ST_ERR: + case HSM_ST_TMOUT: + case HSM_ST_ERR: ata_pio_error(ap); return; } @@ -3360,7 +3360,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ ata_qc_set_polling(qc); ata_tf_to_host_nolock(ap, &qc->tf); - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); break; @@ -3806,7 +3806,7 @@ static void atapi_packet_task(void *_data) ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* PIO commands are handled by polling */ - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); } diff --git a/include/linux/libata.h b/include/linux/libata.h index ceee1fc42c60..bb2d916bce44 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -156,15 +156,15 @@ enum { ATA_SHIFT_PIO = 11, }; -enum pio_task_states { - PIO_ST_UNKNOWN, - PIO_ST_IDLE, - PIO_ST_POLL, - PIO_ST_TMOUT, - PIO_ST, - PIO_ST_LAST, - PIO_ST_LAST_POLL, - PIO_ST_ERR, +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, }; /* forward declarations */ @@ -319,7 +319,7 @@ struct ata_port { struct work_struct packet_task; struct work_struct pio_task; - unsigned int pio_task_state; + unsigned int hsm_task_state; unsigned long pio_task_timeout; void *private_data; From bfd00722ac230a39bc5234c5f7a514ea6a77996d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 26 Sep 2005 11:28:47 +0900 Subject: [PATCH 0232/1939] [PATCH] libata EH document update Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- Documentation/DocBook/libata.tmpl | 356 ++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index 375ae760dc1e..fcbb58fc0fee 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -413,6 +413,362 @@ and other resources, etc. + + Error handling + + + This chapter describes how errors are handled under libata. + Readers are advised to read SCSI EH + (Documentation/scsi/scsi_eh.txt) and ATA exceptions doc first. + + + Origins of commands + + In libata, a command is represented with struct ata_queued_cmd + or qc. qc's are preallocated during port initialization and + repetitively used for command executions. Currently only one + qc is allocated per port but yet-to-be-merged NCQ branch + allocates one for each tag and maps each qc to NCQ tag 1-to-1. + + + libata commands can originate from two sources - libata itself + and SCSI midlayer. libata internal commands are used for + initialization and error handling. All normal blk requests + and commands for SCSI emulation are passed as SCSI commands + through queuecommand callback of SCSI host template. + + + + How commands are issued + + + + Internal commands + + + First, qc is allocated and initialized using + ata_qc_new_init(). Although ata_qc_new_init() doesn't + implement any wait or retry mechanism when qc is not + available, internal commands are currently issued only during + initialization and error recovery, so no other command is + active and allocation is guaranteed to succeed. + + + Once allocated qc's taskfile is initialized for the command to + be executed. qc currently has two mechanisms to notify + completion. One is via qc->complete_fn() callback and the + other is completion qc->waiting. qc->complete_fn() callback + is the asynchronous path used by normal SCSI translated + commands and qc->waiting is the synchronous (issuer sleeps in + process context) path used by internal commands. + + + Once initialization is complete, host_set lock is acquired + and the qc is issued. + + + + + SCSI commands + + + All libata drivers use ata_scsi_queuecmd() as + hostt->queuecommand callback. scmds can either be simulated + or translated. No qc is involved in processing a simulated + scmd. The result is computed right away and the scmd is + completed. + + + For a translated scmd, ata_qc_new_init() is invoked to + allocate a qc and the scmd is translated into the qc. SCSI + midlayer's completion notification function pointer is stored + into qc->scsidone. + + + qc->complete_fn() callback is used for completion + notification. ATA commands use ata_scsi_qc_complete() while + ATAPI commands use atapi_qc_complete(). Both functions end up + calling qc->scsidone to notify upper layer when the qc is + finished. After translation is completed, the qc is issued + with ata_qc_issue(). + + + Note that SCSI midlayer invokes hostt->queuecommand while + holding host_set lock, so all above occur while holding + host_set lock. + + + + + + + + How commands are processed + + Depending on which protocol and which controller are used, + commands are processed differently. For the purpose of + discussion, a controller which uses taskfile interface and all + standard callbacks is assumed. + + + Currently 6 ATA command protocols are used. They can be + sorted into the following four categories according to how + they are processed. + + + + ATA NO DATA or DMA + + + ATA_PROT_NODATA and ATA_PROT_DMA fall into this category. + These types of commands don't require any software + intervention once issued. Device will raise interrupt on + completion. + + + + + ATA PIO + + + ATA_PROT_PIO is in this category. libata currently + implements PIO with polling. ATA_NIEN bit is set to turn + off interrupt and pio_task on ata_wq performs polling and + IO. + + + + + ATAPI NODATA or DMA + + + ATA_PROT_ATAPI_NODATA and ATA_PROT_ATAPI_DMA are in this + category. packet_task is used to poll BSY bit after + issuing PACKET command. Once BSY is turned off by the + device, packet_task transfers CDB and hands off processing + to interrupt handler. + + + + + ATAPI PIO + + + ATA_PROT_ATAPI is in this category. ATA_NIEN bit is set + and, as in ATAPI NODATA or DMA, packet_task submits cdb. + However, after submitting cdb, further processing (data + transfer) is handed off to pio_task. + + + + + + + How commands are completed + + Once issued, all qc's are either completed with + ata_qc_complete() or time out. For commands which are handled + by interrupts, ata_host_intr() invokes ata_qc_complete(), and, + for PIO tasks, pio_task invokes ata_qc_complete(). In error + cases, packet_task may also complete commands. + + + ata_qc_complete() does the following. + + + + + + + DMA memory is unmapped. + + + + + + ATA_QCFLAG_ACTIVE is clared from qc->flags. + + + + + + qc->complete_fn() callback is invoked. If the return value of + the callback is not zero. Completion is short circuited and + ata_qc_complete() returns. + + + + + + __ata_qc_complete() is called, which does + + + + + qc->flags is cleared to zero. + + + + + + ap->active_tag and qc->tag are poisoned. + + + + + + qc->waiting is claread & completed (in that order). + + + + + + qc is deallocated by clearing appropriate bit in ap->qactive. + + + + + + + + + + + So, it basically notifies upper layer and deallocates qc. One + exception is short-circuit path in #3 which is used by + atapi_qc_complete(). + + + For all non-ATAPI commands, whether it fails or not, almost + the same code path is taken and very little error handling + takes place. A qc is completed with success status if it + succeeded, with failed status otherwise. + + + However, failed ATAPI commands require more handling as + REQUEST SENSE is needed to acquire sense data. If an ATAPI + command fails, ata_qc_complete() is invoked with error status, + which in turn invokes atapi_qc_complete() via + qc->complete_fn() callback. + + + This makes atapi_qc_complete() set scmd->result to + SAM_STAT_CHECK_CONDITION, complete the scmd and return 1. As + the sense data is empty but scmd->result is CHECK CONDITION, + SCSI midlayer will invoke EH for the scmd, and returning 1 + makes ata_qc_complete() to return without deallocating the qc. + This leads us to ata_scsi_error() with partially completed qc. + + + + + ata_scsi_error() + + ata_scsi_error() is the current hostt->eh_strategy_handler() + for libata. As discussed above, this will be entered in two + cases - timeout and ATAPI error completion. This function + calls low level libata driver's eng_timeout() callback, the + standard callback for which is ata_eng_timeout(). It checks + if a qc is active and calls ata_qc_timeout() on the qc if so. + Actual error handling occurs in ata_qc_timeout(). + + + If EH is invoked for timeout, ata_qc_timeout() stops BMDMA and + completes the qc. Note that as we're currently in EH, we + cannot call scsi_done. As described in SCSI EH doc, a + recovered scmd should be either retried with + scsi_queue_insert() or finished with scsi_finish_command(). + Here, we override qc->scsidone with scsi_finish_command() and + calls ata_qc_complete(). + + + If EH is invoked due to a failed ATAPI qc, the qc here is + completed but not deallocated. The purpose of this + half-completion is to use the qc as place holder to make EH + code reach this place. This is a bit hackish, but it works. + + + Once control reaches here, the qc is deallocated by invoking + __ata_qc_complete() explicitly. Then, internal qc for REQUEST + SENSE is issued. Once sense data is acquired, scmd is + finished by directly invoking scsi_finish_command() on the + scmd. Note that as we already have completed and deallocated + the qc which was associated with the scmd, we don't need + to/cannot call ata_qc_complete() again. + + + + + Problems with the current EH + + + + + + Error representation is too crude. Currently any and all + error conditions are represented with ATA STATUS and ERROR + registers. Errors which aren't ATA device errors are treated + as ATA device errors by setting ATA_ERR bit. Better error + descriptor which can properly represent ATA and other + errors/exceptions is needed. + + + + + + When handling timeouts, no action is taken to make device + forget about the timed out command and ready for new commands. + + + + + + EH handling via ata_scsi_error() is not properly protected + from usual command processing. On EH entrance, the device is + not in quiescent state. Timed out commands may succeed or + fail any time. pio_task and atapi_task may still be running. + + + + + + Too weak error recovery. Devices / controllers causing HSM + mismatch errors and other errors quite often require reset to + return to known state. Also, advanced error handling is + necessary to support features like NCQ and hotplug. + + + + + + ATA errors are directly handled in the interrupt handler and + PIO errors in pio_task. This is problematic for advanced + error handling for the following reasons. + + + First, advanced error handling often requires context and + internal qc execution. + + + Second, even a simple failure (say, CRC error) needs + information gathering and could trigger complex error handling + (say, resetting & reconfiguring). Having multiple code + paths to gather information, enter EH and trigger actions + makes life painful. + + + Third, scattered EH code makes implementing low level drivers + difficult. Low level drivers override libata callbacks. If + EH is scattered over several places, each affected callbacks + should perform its part of error handling. This can be error + prone and painful. + + + + + + + From a1213499b0ef75d8c627b461047805a235c9dd00 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 28 Sep 2005 13:26:47 -0400 Subject: [PATCH 0233/1939] libata: move EH docs to separate DocBook chapter --- Documentation/DocBook/libata.tmpl | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index fcbb58fc0fee..b2ec780bcda1 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -413,7 +413,9 @@ and other resources, etc. - + + + Error handling @@ -422,7 +424,7 @@ and other resources, etc. (Documentation/scsi/scsi_eh.txt) and ATA exceptions doc first. - Origins of commands + Origins of commands In libata, a command is represented with struct ata_queued_cmd or qc. qc's are preallocated during port initialization and @@ -437,9 +439,9 @@ and other resources, etc. and commands for SCSI emulation are passed as SCSI commands through queuecommand callback of SCSI host template. - + - How commands are issued + How commands are issued @@ -501,9 +503,9 @@ and other resources, etc. - + - How commands are processed + How commands are processed Depending on which protocol and which controller are used, commands are processed differently. For the purpose of @@ -562,9 +564,9 @@ and other resources, etc. - + - How commands are completed + How commands are completed Once issued, all qc's are either completed with ata_qc_complete() or time out. For commands which are handled @@ -660,9 +662,9 @@ and other resources, etc. This leads us to ata_scsi_error() with partially completed qc. - + - ata_scsi_error() + ata_scsi_error() ata_scsi_error() is the current hostt->eh_strategy_handler() for libata. As discussed above, this will be entered in two @@ -697,9 +699,9 @@ and other resources, etc. to/cannot call ata_qc_complete() again. - + - Problems with the current EH + Problems with the current EH @@ -766,9 +768,7 @@ and other resources, etc. - - - + From b4b52db71529bbe46da914eda772fb574914c94d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 26 Sep 2005 12:48:41 +0100 Subject: [PATCH 0234/1939] [PATCH] ata: re-order speeds sensibly. Signed-off-by: Jeff Garzik --- include/linux/ata.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/ata.h b/include/linux/ata.h index 85169ea9eb01..ecb7346d0c16 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -147,14 +147,14 @@ enum { XFER_MW_DMA_2 = 0x22, XFER_MW_DMA_1 = 0x21, XFER_MW_DMA_0 = 0x20, + XFER_SW_DMA_2 = 0x12, + XFER_SW_DMA_1 = 0x11, + XFER_SW_DMA_0 = 0x10, XFER_PIO_4 = 0x0C, XFER_PIO_3 = 0x0B, XFER_PIO_2 = 0x0A, XFER_PIO_1 = 0x09, XFER_PIO_0 = 0x08, - XFER_SW_DMA_2 = 0x12, - XFER_SW_DMA_1 = 0x11, - XFER_SW_DMA_0 = 0x10, XFER_PIO_SLOW = 0x00, /* ATAPI stuff */ From 604116a32eaef4e10d05ae3361450b3f4a4e6a90 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Wed, 28 Sep 2005 15:16:46 -0500 Subject: [PATCH 0235/1939] This patch fixes a typo in ieee80211.h: ieee82011_deauth -> ieee80211_deauth Signed-off-by: Michael Wu Signed-off-by: James Ketrenos --- include/net/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4851756202c5..33b595ebef1f 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -613,7 +613,7 @@ struct ieee80211_disassoc { } __attribute__ ((packed)); /* Alias deauth for disassoc */ -#define ieee82011_deauth ieee80211_disassoc +#define ieee80211_deauth ieee80211_disassoc struct ieee80211_probe_request { struct ieee80211_hdr_3addr header; From 59c422358d6573716f2bf2e78e5b12c20eff5a31 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 27 Sep 2005 08:25:32 -0500 Subject: [PATCH 0236/1939] [IA64-SGI] Increase max system size of SGI SN systems Increase the maximum system size of SGI SN systems. Note that this is not the maximum SSI size. The maximum system size is the number of nodes in the numalink domain. Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- include/asm-ia64/sn/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h index 8fce5a6db951..1a3831c04af6 100644 --- a/include/asm-ia64/sn/arch.h +++ b/include/asm-ia64/sn/arch.h @@ -41,7 +41,7 @@ * This value is also the value of the maximum number of NASIDs in the numalink * fabric. */ -#define MAX_NUMALINK_NODES 2048 +#define MAX_NUMALINK_NODES 16384 /* * The following defines attributes of the HUB chip. These attributes are From d719948e623622cf9fc8016f7ec63422d929eb3b Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 28 Sep 2005 16:09:46 -0700 Subject: [PATCH 0237/1939] [IA64] end of kernel 'data' is at _end, not _edata /proc/iomem describes a block of memory as "Kernel data", but the end address is derived from "_edata". The kernel actually has many other sections beyond _edata. Get the real end address from _end. Acked-by: Khalid Aziz Signed-off-by: Tony Luck --- arch/ia64/kernel/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 83b37c410ccd..3e9b797e6588 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -89,7 +89,7 @@ static struct resource code_resource = { }; extern void efi_initialize_iomem_resources(struct resource *, struct resource *); -extern char _text[], _edata[], _etext[]; +extern char _text[], _end[], _etext[]; unsigned long ia64_max_cacheline_size; unsigned long ia64_iobase; /* virtual address for I/O accesses */ @@ -192,7 +192,7 @@ static int __init register_memory(void) code_resource.start = ia64_tpa(_text); code_resource.end = ia64_tpa(_etext) - 1; data_resource.start = ia64_tpa(_etext); - data_resource.end = ia64_tpa(_edata) - 1; + data_resource.end = ia64_tpa(_end) - 1; efi_initialize_iomem_resources(&code_resource, &data_resource); return 0; From b08567cb680686cdea9e362c0ccf0a08d77b9f0c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 28 Sep 2005 23:37:01 +1000 Subject: [PATCH 0238/1939] ppc64 iseries: move some iSeries include files These files are only referenced from within arch/powerpc/platforms/iseries, so move them there. Signed-off-by: Stephen Rothwell --- .../powerpc/platforms/iseries/call_sm.h | 7 +++---- .../powerpc/platforms/iseries/ipl_parms.h | 7 +++---- arch/powerpc/platforms/iseries/irq.c | 3 ++- .../powerpc/platforms/iseries/irq.h | 6 +++--- arch/powerpc/platforms/iseries/lpardata.c | 10 +++++----- .../powerpc/platforms/iseries/main_store.h | 7 +++---- arch/powerpc/platforms/iseries/pci.c | 3 ++- arch/powerpc/platforms/iseries/proc.c | 5 +++-- .../powerpc/platforms/iseries/processor_vpd.h | 7 +++---- .../powerpc/platforms/iseries/release_data.h | 7 +++---- arch/powerpc/platforms/iseries/setup.c | 10 +++++----- .../powerpc/platforms/iseries/spcomm_area.h | 7 +++---- .../powerpc/platforms/iseries/vpd_areas.h | 7 +++---- 13 files changed, 41 insertions(+), 45 deletions(-) rename include/asm-ppc64/iSeries/HvCallSm.h => arch/powerpc/platforms/iseries/call_sm.h (93%) rename include/asm-ppc64/iSeries/ItIplParmsReal.h => arch/powerpc/platforms/iseries/ipl_parms.h (96%) rename include/asm-ppc64/iSeries/iSeries_irq.h => arch/powerpc/platforms/iseries/irq.h (64%) rename include/asm-ppc64/iSeries/IoHriMainStore.h => arch/powerpc/platforms/iseries/main_store.h (97%) rename include/asm-ppc64/iSeries/IoHriProcessorVpd.h => arch/powerpc/platforms/iseries/processor_vpd.h (96%) rename include/asm-ppc64/iSeries/HvReleaseData.h => arch/powerpc/platforms/iseries/release_data.h (95%) rename include/asm-ppc64/iSeries/ItSpCommArea.h => arch/powerpc/platforms/iseries/spcomm_area.h (93%) rename include/asm-ppc64/iSeries/ItVpdAreas.h => arch/powerpc/platforms/iseries/vpd_areas.h (97%) diff --git a/include/asm-ppc64/iSeries/HvCallSm.h b/arch/powerpc/platforms/iseries/call_sm.h similarity index 93% rename from include/asm-ppc64/iSeries/HvCallSm.h rename to arch/powerpc/platforms/iseries/call_sm.h index 8a3dbb071a43..ef223166cf22 100644 --- a/include/asm-ppc64/iSeries/HvCallSm.h +++ b/arch/powerpc/platforms/iseries/call_sm.h @@ -1,5 +1,4 @@ /* - * HvCallSm.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _HVCALLSM_H -#define _HVCALLSM_H +#ifndef _ISERIES_CALL_SM_H +#define _ISERIES_CALL_SM_H /* * This file contains the "hypervisor call" interface which is used to @@ -35,4 +34,4 @@ static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); } -#endif /* _HVCALLSM_H */ +#endif /* _ISERIES_CALL_SM_H */ diff --git a/include/asm-ppc64/iSeries/ItIplParmsReal.h b/arch/powerpc/platforms/iseries/ipl_parms.h similarity index 96% rename from include/asm-ppc64/iSeries/ItIplParmsReal.h rename to arch/powerpc/platforms/iseries/ipl_parms.h index ae3417dc599e..77c135ddbf1b 100644 --- a/include/asm-ppc64/iSeries/ItIplParmsReal.h +++ b/arch/powerpc/platforms/iseries/ipl_parms.h @@ -1,5 +1,4 @@ /* - * ItIplParmsReal.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _ITIPLPARMSREAL_H -#define _ITIPLPARMSREAL_H +#ifndef _ISERIES_IPL_PARMS_H +#define _ISERIES_IPL_PARMS_H /* * This struct maps the IPL Parameters DMA'd from the SP. @@ -68,4 +67,4 @@ struct ItIplParmsReal { extern struct ItIplParmsReal xItIplParmsReal; -#endif /* _ITIPLPARMSREAL_H */ +#endif /* _ISERIES_IPL_PARMS_H */ diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 5a8a0056b31f..31fb5fa67fa3 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -40,7 +40,8 @@ #include #include #include -#include + +#include "irq.h" /* This maps virtual irq numbers to real irqs */ unsigned int virt_irq_to_real_map[NR_IRQS]; diff --git a/include/asm-ppc64/iSeries/iSeries_irq.h b/arch/powerpc/platforms/iseries/irq.h similarity index 64% rename from include/asm-ppc64/iSeries/iSeries_irq.h rename to arch/powerpc/platforms/iseries/irq.h index 6c9767ac1302..5f643f16ecc0 100644 --- a/include/asm-ppc64/iSeries/iSeries_irq.h +++ b/arch/powerpc/platforms/iseries/irq.h @@ -1,8 +1,8 @@ -#ifndef __ISERIES_IRQ_H__ -#define __ISERIES_IRQ_H__ +#ifndef _ISERIES_IRQ_H +#define _ISERIES_IRQ_H extern void iSeries_init_IRQ(void); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); extern void iSeries_activate_IRQs(void); -#endif /* __ISERIES_IRQ_H__ */ +#endif /* _ISERIES_IRQ_H */ diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c index 87b7ad8ca465..ed2ffee6f731 100644 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ b/arch/powerpc/platforms/iseries/lpardata.c @@ -19,15 +19,15 @@ #include #include #include -#include #include -#include -#include #include #include -#include -#include +#include "vpd_areas.h" +#include "spcomm_area.h" +#include "ipl_parms.h" +#include "processor_vpd.h" +#include "release_data.h" /* The HvReleaseData is the root of the information shared between * the hypervisor and Linux. diff --git a/include/asm-ppc64/iSeries/IoHriMainStore.h b/arch/powerpc/platforms/iseries/main_store.h similarity index 97% rename from include/asm-ppc64/iSeries/IoHriMainStore.h rename to arch/powerpc/platforms/iseries/main_store.h index 45ed3ea67d06..74f6889f834f 100644 --- a/include/asm-ppc64/iSeries/IoHriMainStore.h +++ b/arch/powerpc/platforms/iseries/main_store.h @@ -1,5 +1,4 @@ /* - * IoHriMainStore.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _IOHRIMAINSTORE_H -#define _IOHRIMAINSTORE_H +#ifndef _ISERIES_MAIN_STORE_H +#define _ISERIES_MAIN_STORE_H /* Main Store Vpd for Condor,iStar,sStar */ struct IoHriMainStoreSegment4 { @@ -163,4 +162,4 @@ struct IoHriMainStoreSegment5 { extern u64 xMsVpd[]; -#endif /* _IOHRIMAINSTORE_H */ +#endif /* _ISERIES_MAIN_STORE_H */ diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 501b1dcbfac5..70185dec940b 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -37,12 +37,13 @@ #include #include -#include #include #include #include +#include "irq.h" + extern unsigned long io_page_mask; /* diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c index d46b473ce4dd..6f1929cac66b 100644 --- a/arch/powerpc/platforms/iseries/proc.c +++ b/arch/powerpc/platforms/iseries/proc.c @@ -26,8 +26,9 @@ #include #include #include -#include -#include + +#include "processor_vpd.h" +#include "main_store.h" static int __init iseries_proc_create(void) { diff --git a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h similarity index 96% rename from include/asm-ppc64/iSeries/IoHriProcessorVpd.h rename to arch/powerpc/platforms/iseries/processor_vpd.h index 73b73d80b8b1..7ac5d0d0dbfa 100644 --- a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h +++ b/arch/powerpc/platforms/iseries/processor_vpd.h @@ -1,5 +1,4 @@ /* - * IoHriProcessorVpd.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _IOHRIPROCESSORVPD_H -#define _IOHRIPROCESSORVPD_H +#ifndef _ISERIES_PROCESSOR_VPD_H +#define _ISERIES_PROCESSOR_VPD_H #include @@ -83,4 +82,4 @@ struct IoHriProcessorVpd { extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; -#endif /* _IOHRIPROCESSORVPD_H */ +#endif /* _ISERIES_PROCESSOR_VPD_H */ diff --git a/include/asm-ppc64/iSeries/HvReleaseData.h b/arch/powerpc/platforms/iseries/release_data.h similarity index 95% rename from include/asm-ppc64/iSeries/HvReleaseData.h rename to arch/powerpc/platforms/iseries/release_data.h index c8162e5ccb21..c68b9c3e5caf 100644 --- a/include/asm-ppc64/iSeries/HvReleaseData.h +++ b/arch/powerpc/platforms/iseries/release_data.h @@ -1,5 +1,4 @@ /* - * HvReleaseData.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _HVRELEASEDATA_H -#define _HVRELEASEDATA_H +#ifndef _ISERIES_RELEASE_DATA_H +#define _ISERIES_RELEASE_DATA_H /* * This control block contains the critical information about the @@ -61,4 +60,4 @@ struct HvReleaseData { extern struct HvReleaseData hvReleaseData; -#endif /* _HVRELEASEDATA_H */ +#endif /* _ISERIES_RELEASE_DATA_H */ diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index ad78c8581a5a..c3e532b766ef 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -48,18 +48,18 @@ #include #include #include -#include #include #include -#include #include #include -#include -#include -#include #include #include "setup.h" +#include "irq.h" +#include "vpd_areas.h" +#include "processor_vpd.h" +#include "main_store.h" +#include "call_sm.h" extern void hvlog(char *fmt, ...); diff --git a/include/asm-ppc64/iSeries/ItSpCommArea.h b/arch/powerpc/platforms/iseries/spcomm_area.h similarity index 93% rename from include/asm-ppc64/iSeries/ItSpCommArea.h rename to arch/powerpc/platforms/iseries/spcomm_area.h index 5535f8271c9f..6e3b685115c9 100644 --- a/include/asm-ppc64/iSeries/ItSpCommArea.h +++ b/arch/powerpc/platforms/iseries/spcomm_area.h @@ -1,5 +1,4 @@ /* - * ItSpCommArea.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _ITSPCOMMAREA_H -#define _ITSPCOMMAREA_H +#ifndef _ISERIES_SPCOMM_AREA_H +#define _ISERIES_SPCOMM_AREA_H struct SpCommArea { @@ -34,4 +33,4 @@ struct SpCommArea { extern struct SpCommArea xSpCommArea; -#endif /* _ITSPCOMMAREA_H */ +#endif /* _ISERIES_SPCOMM_AREA_H */ diff --git a/include/asm-ppc64/iSeries/ItVpdAreas.h b/arch/powerpc/platforms/iseries/vpd_areas.h similarity index 97% rename from include/asm-ppc64/iSeries/ItVpdAreas.h rename to arch/powerpc/platforms/iseries/vpd_areas.h index 71b3ad24f95a..601e6dd860ed 100644 --- a/include/asm-ppc64/iSeries/ItVpdAreas.h +++ b/arch/powerpc/platforms/iseries/vpd_areas.h @@ -1,5 +1,4 @@ /* - * ItVpdAreas.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _ITVPDAREAS_H -#define _ITVPDAREAS_H +#ifndef _ISERIES_VPD_AREAS_H +#define _ISERIES_VPD_AREAS_H /* * This file defines the address and length of all of the VPD area passed to @@ -86,4 +85,4 @@ struct ItVpdAreas { extern struct ItVpdAreas itVpdAreas; -#endif /* _ITVPDAREAS_H */ +#endif /* _ISERIES_VPD_AREAS_H */ From d1dead5c5f016ebadb4b87c2c9fa13dfc2c99bf0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Sep 2005 00:35:31 +1000 Subject: [PATCH 0239/1939] powerpc: merge asm-offsets.c Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/asm-offsets.c | 224 ++++++++++++++++-------------- 1 file changed, 119 insertions(+), 105 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 16cf0b7ee2b7..3a247c033e8b 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -20,17 +20,20 @@ #include #include #include -#include -#include #include #include +#ifdef CONFIG_PPC64 #include #include +#else +#include +#include +#endif + #include #include #include #include - #include #include #ifdef CONFIG_PPC64 @@ -50,63 +53,117 @@ int main(void) { - /* thread struct on stack */ - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); -#ifdef CONFIG_PPC32 - DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); -#endif -#ifdef CONFIG_PPC64 - DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); - DEFINE(THREAD_SHIFT, THREAD_SHIFT); -#endif - DEFINE(THREAD_SIZE, THREAD_SIZE); - - /* task_struct->thread */ DEFINE(THREAD, offsetof(struct task_struct, thread)); - DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); DEFINE(MM, offsetof(struct task_struct, mm)); +#ifdef CONFIG_PPC64 + DEFINE(THREAD_SHIFT, THREAD_SHIFT); + DEFINE(THREAD_SIZE, THREAD_SIZE); + DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); +#else + DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); +#endif /* CONFIG_PPC64 */ + DEFINE(KSP, offsetof(struct thread_struct, ksp)); - DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); - DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); - DEFINE(PT_PTRACED, PT_PTRACED); -#endif -#ifdef CONFIG_PPC64 - DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); -#endif - #ifdef CONFIG_ALTIVEC DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_PPC64 + DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); +#else /* CONFIG_PPC64 */ + DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); + DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); + DEFINE(PT_PTRACED, PT_PTRACED); +#endif #ifdef CONFIG_SPE DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0])); DEFINE(THREAD_ACC, offsetof(struct thread_struct, acc)); DEFINE(THREAD_SPEFSCR, offsetof(struct thread_struct, spefscr)); DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe)); #endif /* CONFIG_SPE */ +#endif /* CONFIG_PPC64 */ + + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); +#ifdef CONFIG_PPC64 + DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); +#else + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); +#endif /* CONFIG_PPC64 */ + +#ifdef CONFIG_PPC64 + DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); + DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); + DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page)); + DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); + DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); + DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); + DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); + + /* paca */ + DEFINE(PACA_SIZE, sizeof(struct paca_struct)); + DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); + DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start)); + DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack)); + DEFINE(PACACURRENT, offsetof(struct paca_struct, __current)); + DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, saved_msr)); + DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real)); + DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr)); + DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); + DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); + DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); + DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); + 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_HUGETLB_PAGE + DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); + DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); +#endif /* CONFIG_HUGETLB_PAGE */ + DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); + DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); + DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); + DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); + DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); + DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); + DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); + DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); + + DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); + DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); + DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); + DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); + + /* RTAS */ + DEFINE(RTASBASE, offsetof(struct rtas_t, base)); + DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); +#endif /* CONFIG_PPC64 */ + /* Interrupt register frame */ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); #ifndef CONFIG_PPC64 DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); -#else +#else /* CONFIG_PPC64 */ DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); - /* 288 = # of volatile regs, int & fp, for leaf routines */ /* which do not stack a frame. See the PPC64 ABI. */ DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); -#endif - /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */ + /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ + DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); + DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); +#endif /* CONFIG_PPC64 */ DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); @@ -121,6 +178,7 @@ int main(void) DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); +#ifndef CONFIG_PPC64 DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); @@ -139,6 +197,7 @@ int main(void) DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); +#endif /* CONFIG_PPC64 */ /* * Note: these symbols include _ because they overlap with special * register names @@ -148,23 +207,37 @@ int main(void) DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); - DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - /* The PowerPC 400-class & Book-E processors have neither the DAR nor the DSISR - * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs - * for such processors. For critical interrupts we use them to - * hold SRR0 and SRR1. + DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); + DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); +#ifndef CONFIG_PPC64 + DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); + /* + * The PowerPC 400-class & Book-E processors have neither the DAR + * nor the DSISR SPRs. Hence, we overload them to hold the similar + * DEAR and ESR SPRs for such processors. For critical interrupts + * we use them to hold SRR0 and SRR1. */ DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); - DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); +#else /* CONFIG_PPC64 */ + DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); + + /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ + DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); + DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); +#endif /* CONFIG_PPC64 */ + DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); + +#ifndef CONFIG_PPC64 DEFINE(MM_PGD, offsetof(struct mm_struct, pgd)); +#endif /* ! CONFIG_PPC64 */ /* About the CPU features table */ DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); @@ -173,66 +246,13 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); -#ifdef CONFIG_PPC64 - DEFINE(MM, offsetof(struct task_struct, mm)); - DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); - - DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); - DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); - DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page)); - DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); - DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); - DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); - DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); - - /* paca */ - DEFINE(PACA_SIZE, sizeof(struct paca_struct)); - DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); - DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start)); - DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack)); - DEFINE(PACACURRENT, offsetof(struct paca_struct, __current)); - DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, saved_msr)); - DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real)); - DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr)); - DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); - DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); - DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); - DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); - 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_HUGETLB_PAGE - DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); - DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); -#endif /* CONFIG_HUGETLB_PAGE */ - DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); - DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); - DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); - DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); - DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); - DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); - DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); - DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); - DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); - DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); - DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); - DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); - - /* RTAS */ - DEFINE(RTASBASE, offsetof(struct rtas_t, base)); - DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); - - DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); - DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); - - /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ - DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - - /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ - DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); - DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); +#ifndef CONFIG_PPC64 + DEFINE(pbe_address, offsetof(struct pbe, address)); + DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); + DEFINE(pbe_next, offsetof(struct pbe, next)); + DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); +#else /* CONFIG_PPC64 */ /* systemcfg offsets for use by vdso */ DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp)); DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec)); @@ -251,12 +271,6 @@ int main(void) DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec)); DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); -#endif - - DEFINE(pbe_address, offsetof(struct pbe, address)); - DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); - DEFINE(pbe_next, offsetof(struct pbe, next)); - - DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); +#endif /* CONFIG_PPC64 */ return 0; } From dcff1b170b43d9b8cb83e275cb3451dfd261c23e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Sep 2005 00:59:39 +1000 Subject: [PATCH 0240/1939] powerpc: remove old vector.S files Update old kernel/Makefiles to cope Signed-off-by: Stephen Rothwell --- arch/ppc/kernel/Makefile | 1 + arch/ppc/kernel/vector.S | 217 ------------------------------------- arch/ppc64/kernel/Makefile | 1 + arch/ppc64/kernel/vector.S | 172 ----------------------------- 4 files changed, 2 insertions(+), 389 deletions(-) delete mode 100644 arch/ppc/kernel/vector.S delete mode 100644 arch/ppc64/kernel/vector.S diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 467f96480355..09067fe5772c 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -38,6 +38,7 @@ endif # These are here while we do the architecture merge vecemu-y += ../../powerpc/kernel/vecemu.o +vector-y += ../../powerpc/kernel/vector.o else obj-y := entry.o irq.o idle.o time.o misc.o \ diff --git a/arch/ppc/kernel/vector.S b/arch/ppc/kernel/vector.S deleted file mode 100644 index 82a21346bf80..000000000000 --- a/arch/ppc/kernel/vector.S +++ /dev/null @@ -1,217 +0,0 @@ -#include -#include - -/* - * The routines below are in assembler so we can closely control the - * usage of floating-point registers. These routines must be called - * with preempt disabled. - */ - .data -fpzero: - .long 0 -fpone: - .long 0x3f800000 /* 1.0 in single-precision FP */ -fphalf: - .long 0x3f000000 /* 0.5 in single-precision FP */ - - .text -/* - * Internal routine to enable floating point and set FPSCR to 0. - * Don't call it from C; it doesn't use the normal calling convention. - */ -fpenable: - mfmsr r10 - ori r11,r10,MSR_FP - mtmsr r11 - isync - stfd fr0,24(r1) - stfd fr1,16(r1) - stfd fr31,8(r1) - lis r11,fpzero@ha - mffs fr31 - lfs fr1,fpzero@l(r11) - mtfsf 0xff,fr1 - blr - -fpdisable: - mtfsf 0xff,fr31 - lfd fr31,8(r1) - lfd fr1,16(r1) - lfd fr0,24(r1) - mtmsr r10 - isync - blr - -/* - * Vector add, floating point. - */ - .globl vaddfp -vaddfp: - stwu r1,-32(r1) - mflr r0 - stw r0,36(r1) - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fadds fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - bl fpdisable - lwz r0,36(r1) - mtlr r0 - addi r1,r1,32 - blr - -/* - * Vector subtract, floating point. - */ - .globl vsubfp -vsubfp: - stwu r1,-32(r1) - mflr r0 - stw r0,36(r1) - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fsubs fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - bl fpdisable - lwz r0,36(r1) - mtlr r0 - addi r1,r1,32 - blr - -/* - * Vector multiply and add, floating point. - */ - .globl vmaddfp -vmaddfp: - stwu r1,-48(r1) - mflr r0 - stw r0,52(r1) - bl fpenable - stfd fr2,32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fmadds fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,32(r1) - bl fpdisable - lwz r0,52(r1) - mtlr r0 - addi r1,r1,48 - blr - -/* - * Vector negative multiply and subtract, floating point. - */ - .globl vnmsubfp -vnmsubfp: - stwu r1,-48(r1) - mflr r0 - stw r0,52(r1) - bl fpenable - stfd fr2,32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,32(r1) - bl fpdisable - lwz r0,52(r1) - mtlr r0 - addi r1,r1,48 - blr - -/* - * Vector reciprocal estimate. We just compute 1.0/x. - * r3 -> destination, r4 -> source. - */ - .globl vrefp -vrefp: - stwu r1,-32(r1) - mflr r0 - stw r0,36(r1) - bl fpenable - lis r9,fpone@ha - li r0,4 - lfs fr1,fpone@l(r9) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - fdivs fr0,fr1,fr0 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - bl fpdisable - lwz r0,36(r1) - mtlr r0 - addi r1,r1,32 - blr - -/* - * Vector reciprocal square-root estimate, floating point. - * We use the frsqrte instruction for the initial estimate followed - * by 2 iterations of Newton-Raphson to get sufficient accuracy. - * r3 -> destination, r4 -> source. - */ - .globl vrsqrtefp -vrsqrtefp: - stwu r1,-48(r1) - mflr r0 - stw r0,52(r1) - bl fpenable - stfd fr2,32(r1) - stfd fr3,40(r1) - stfd fr4,48(r1) - stfd fr5,56(r1) - lis r9,fpone@ha - lis r8,fphalf@ha - li r0,4 - lfs fr4,fpone@l(r9) - lfs fr5,fphalf@l(r8) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - frsqrte fr1,fr0 /* r = frsqrte(s) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - stfsx fr1,r3,r6 - addi r6,r6,4 - bdnz 1b - lfd fr5,56(r1) - lfd fr4,48(r1) - lfd fr3,40(r1) - lfd fr2,32(r1) - bl fpdisable - lwz r0,36(r1) - mtlr r0 - addi r1,r1,32 - blr diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index bb5946b88b8b..9d4836fe3720 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -76,3 +76,4 @@ endif # These are here while we do the architecture merge vecemu-y += ../../powerpc/kernel/vecemu.o +vector-y += ../../powerpc/kernel/vector.o diff --git a/arch/ppc64/kernel/vector.S b/arch/ppc64/kernel/vector.S deleted file mode 100644 index b79d33e4001e..000000000000 --- a/arch/ppc64/kernel/vector.S +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include - -/* - * The routines below are in assembler so we can closely control the - * usage of floating-point registers. These routines must be called - * with preempt disabled. - */ - .section ".toc","aw" -fpzero: - .tc FD_0_0[TC],0 -fpone: - .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */ -fphalf: - .tc FD_3fe00000_0[TC],0x3fe0000000000000 /* 0.5 */ - - .text -/* - * Internal routine to enable floating point and set FPSCR to 0. - * Don't call it from C; it doesn't use the normal calling convention. - */ -fpenable: - mfmsr r10 - ori r11,r10,MSR_FP - mtmsr r11 - isync - stfd fr31,-8(r1) - stfd fr0,-16(r1) - stfd fr1,-24(r1) - mffs fr31 - lfd fr1,fpzero@toc(r2) - mtfsf 0xff,fr1 - blr - -fpdisable: - mtlr r12 - mtfsf 0xff,fr31 - lfd fr1,-24(r1) - lfd fr0,-16(r1) - lfd fr31,-8(r1) - mtmsr r10 - isync - blr - -/* - * Vector add, floating point. - */ -_GLOBAL(vaddfp) - mflr r12 - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fadds fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector subtract, floating point. - */ -_GLOBAL(vsubfp) - mflr r12 - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fsubs fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector multiply and add, floating point. - */ -_GLOBAL(vmaddfp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fmadds fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,-32(r1) - b fpdisable - -/* - * Vector negative multiply and subtract, floating point. - */ -_GLOBAL(vnmsubfp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,-32(r1) - b fpdisable - -/* - * Vector reciprocal estimate. We just compute 1.0/x. - * r3 -> destination, r4 -> source. - */ -_GLOBAL(vrefp) - mflr r12 - bl fpenable - li r0,4 - lfd fr1,fpone@toc(r2) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - fdivs fr0,fr1,fr0 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector reciprocal square-root estimate, floating point. - * We use the frsqrte instruction for the initial estimate followed - * by 2 iterations of Newton-Raphson to get sufficient accuracy. - * r3 -> destination, r4 -> source. - */ -_GLOBAL(vrsqrtefp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - stfd fr3,-40(r1) - stfd fr4,-48(r1) - stfd fr5,-56(r1) - li r0,4 - lfd fr4,fpone@toc(r2) - lfd fr5,fphalf@toc(r2) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - frsqrte fr1,fr0 /* r = frsqrte(s) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - stfsx fr1,r3,r6 - addi r6,r6,4 - bdnz 1b - lfd fr5,-56(r1) - lfd fr4,-48(r1) - lfd fr3,-40(r1) - lfd fr2,-32(r1) - b fpdisable From ee400b63f37120987bd12a2fada850c6212d7563 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Sep 2005 11:50:22 +1000 Subject: [PATCH 0241/1939] powerpc: more cleanup of powerpc/kernel Update head_64.S from arch/ppc64 Remove arc/ppc/kernel/fpu.S Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/head_64.S | 9 ++- arch/ppc/kernel/Makefile | 1 + arch/ppc/kernel/fpu.S | 133 ---------------------------------- 3 files changed, 7 insertions(+), 136 deletions(-) delete mode 100644 arch/ppc/kernel/fpu.S diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 22a5ee07e1ea..db0cd3587627 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1253,7 +1253,7 @@ unrecov_slb: * * On iSeries, the hypervisor must fill in at least one entry before * we get control (with relocate on). The address is give to the hv - * as a page number (see xLparMap in LparData.c), so this must be at a + * as a page number (see xLparMap in lpardata.c), so this must be at a * fixed address (the linker can't compute (u64)&initial_stab >> * PAGE_SHIFT). */ @@ -1364,6 +1364,7 @@ _STATIC(__start_initialization_iSeries) addi r2,r2,0x4000 bl .iSeries_early_setup + bl .early_setup /* relocation is on at this point */ @@ -1970,20 +1971,22 @@ _GLOBAL(hmt_start_secondary) blr #endif -#if defined(CONFIG_KEXEC) || (defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)) +#if defined(CONFIG_KEXEC) || defined(CONFIG_SMP) _GLOBAL(smp_release_cpus) /* All secondary cpus are spinning on a common * spinloop, release them all now so they can start * to spin on their individual paca spinloops. * For non SMP kernels, the secondary cpus never * get out of the common spinloop. + * XXX This does nothing useful on iSeries, secondaries are + * already waiting on their paca. */ li r3,1 LOADADDR(r5,__secondary_hold_spinloop) std r3,0(r5) sync blr -#endif /* CONFIG_SMP && !CONFIG_PPC_ISERIES */ +#endif /* CONFIG_SMP */ /* diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 09067fe5772c..da2dc08c4c1b 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -39,6 +39,7 @@ endif # These are here while we do the architecture merge vecemu-y += ../../powerpc/kernel/vecemu.o vector-y += ../../powerpc/kernel/vector.o +fpu-y += ../../powerpc/kernel/fpu.o else obj-y := entry.o irq.o idle.o time.o misc.o \ diff --git a/arch/ppc/kernel/fpu.S b/arch/ppc/kernel/fpu.S deleted file mode 100644 index 665d7d34304c..000000000000 --- a/arch/ppc/kernel/fpu.S +++ /dev/null @@ -1,133 +0,0 @@ -/* - * FPU support code, moved here from head.S so that it can be used - * by chips which use other head-whatever.S files. - * - * 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 - -/* - * This task wants to use the FPU now. - * On UP, disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. - * Load up this task's FP registers from its thread_struct, - * enable the FPU for the current task and return to the task. - */ - .globl load_up_fpu -load_up_fpu: - mfmsr r5 - ori r5,r5,MSR_FP -#ifdef CONFIG_PPC64BRIDGE - clrldi r5,r5,1 /* turn off 64-bit mode */ -#endif /* CONFIG_PPC64BRIDGE */ - SYNC - MTMSRD(r5) /* enable use of fpu now */ - isync -/* - * For SMP, we don't do lazy FPU switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_fpu in switch_to. - */ -#ifndef CONFIG_SMP - tophys(r6,0) /* get __pa constant */ - addis r3,r6,last_task_used_math@ha - lwz r4,last_task_used_math@l(r3) - cmpwi 0,r4,0 - beq 1f - add r4,r4,r6 - addi r4,r4,THREAD /* want last_task_used_math->thread */ - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,THREAD_FPSCR-4(r4) - lwz r5,PT_REGS(r4) - add r5,r5,r6 - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r10,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r10 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of FP after return */ - mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ - lwz r4,THREAD_FPEXC_MODE(r5) - ori r9,r9,MSR_FP /* enable FP for current */ - or r9,r9,r4 - lfd fr0,THREAD_FPSCR-4(r5) - mtfsf 0xff,fr0 - REST_32FPRS(0, r5) -#ifndef CONFIG_SMP - subi r4,r5,THREAD - sub r4,r4,r6 - stw r4,last_task_used_math@l(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - /* we haven't used ctr or xer or lr */ - b fast_exception_return - -/* - * FP unavailable trap from kernel - print a message, but let - * the task use FP in the kernel until it returns to user mode. - */ - .globl KernelFP -KernelFP: - lwz r3,_MSR(r1) - ori r3,r3,MSR_FP - stw r3,_MSR(r1) /* enable use of FP after return */ - lis r3,86f@h - ori r3,r3,86f@l - mr r4,r2 /* current */ - lwz r5,_NIP(r1) - bl printk - b ret_from_except -86: .string "floating point used in kernel (task=%p, pc=%x)\n" - .align 4,0 - -/* - * giveup_fpu(tsk) - * Disable FP for the task given as the argument, - * and save the floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - */ - .globl giveup_fpu -giveup_fpu: - mfmsr r5 - ori r5,r5,MSR_FP - SYNC_601 - ISYNC_601 - MTMSRD(r5) /* enable use of fpu now */ - SYNC_601 - isync - cmpwi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - lwz r5,PT_REGS(r3) - cmpwi 0,r5,0 - SAVE_32FPRS(0, r3) - mffs fr0 - stfd fr0,THREAD_FPSCR-4(r3) - beq 1f - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r3,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r3 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - lis r4,last_task_used_math@ha - stw r5,last_task_used_math@l(r4) -#endif /* CONFIG_SMP */ - blr From d96024c688b59d4d1e60dbb0e226964eb758aa01 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 29 Sep 2005 01:46:29 +1000 Subject: [PATCH 0242/1939] powerpc: Move lparmap.c to powerpc/platforms Signed-off-by: Stephen Rothwell --- arch/{ppc64/kernel => powerpc/platforms/iseries}/lparmap.c | 0 arch/ppc64/kernel/Makefile | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/{ppc64/kernel => powerpc/platforms/iseries}/lparmap.c (100%) diff --git a/arch/ppc64/kernel/lparmap.c b/arch/powerpc/platforms/iseries/lparmap.c similarity index 100% rename from arch/ppc64/kernel/lparmap.c rename to arch/powerpc/platforms/iseries/lparmap.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 9d4836fe3720..16e34de34178 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -70,8 +70,8 @@ obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ ifeq ($(CONFIG_PPC_ISERIES),y) -arch/ppc64/kernel/head.o: arch/ppc64/kernel/lparmap.s -AFLAGS_head.o += -Iarch/ppc64/kernel +arch/ppc64/kernel/head.o: arch/powerpc/platforms/iseries/lparmap.s +AFLAGS_head.o += -Iarch/powerpc/platforms/iseries endif # These are here while we do the architecture merge From c0c0d996d08e450164adedc249c1bbbca63524ce Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 1 Oct 2005 13:49:08 +1000 Subject: [PATCH 0243/1939] powerpc: Get merged kernel to compile and run on 32-bit SMP powermac. This updates the powermac SMP code to use the mpic driver instead of the openpic driver and fixes the SMP-dependent context switch code. We had a subtle bug where we were using interrupt numbers 256-259 for IPIs, but ppc32 had NR_IRQS = 256. Moved the IPIs down to use interrupt numbers 252-255 instead. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ppc_ksyms.c | 2 -- arch/powerpc/kernel/process.c | 17 ++++++++++++----- arch/powerpc/platforms/powermac/pmac_pic.c | 7 ++++--- arch/powerpc/platforms/powermac/pmac_smp.c | 10 +++++----- arch/powerpc/sysdev/mpic.c | 3 +++ 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 7bfa0f0121ff..e73b0699b5f0 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -182,11 +182,9 @@ EXPORT_SYMBOL(flush_tlb_kernel_range); EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(_tlbie); #ifdef CONFIG_ALTIVEC -EXPORT_SYMBOL(last_task_used_altivec); EXPORT_SYMBOL(giveup_altivec); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE -EXPORT_SYMBOL(last_task_used_spe); EXPORT_SYMBOL(giveup_spe); #endif /* CONFIG_SPE */ #ifdef CONFIG_SMP diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e3946769dd8e..ae316e9ed581 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -272,11 +272,6 @@ struct task_struct *__switch_to(struct task_struct *prev, */ if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) giveup_altivec(prev); - /* Avoid the trap. On smp this this never happens since - * we don't set last_task_used_altivec -- Cort - */ - if (new->thread.regs && last_task_used_altivec == new) - new->thread.regs->msr |= MSR_VEC; #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE /* @@ -288,12 +283,24 @@ struct task_struct *__switch_to(struct task_struct *prev, */ if ((prev->thread.regs && (prev->thread.regs->msr & MSR_SPE))) giveup_spe(prev); +#endif /* CONFIG_SPE */ + +#else /* CONFIG_SMP */ +#ifdef CONFIG_ALTIVEC + /* Avoid the trap. On smp this this never happens since + * we don't set last_task_used_altivec -- Cort + */ + if (new->thread.regs && last_task_used_altivec == new) + new->thread.regs->msr |= MSR_VEC; +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_spe */ if (new->thread.regs && last_task_used_spe == new) new->thread.regs->msr |= MSR_SPE; #endif /* CONFIG_SPE */ + #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC64 /* for now */ diff --git a/arch/powerpc/platforms/powermac/pmac_pic.c b/arch/powerpc/platforms/powermac/pmac_pic.c index a6b1b577e19f..7ddd5264cc6e 100644 --- a/arch/powerpc/platforms/powermac/pmac_pic.c +++ b/arch/powerpc/platforms/powermac/pmac_pic.c @@ -430,7 +430,7 @@ void __init pmac_pic_init(void) prom_get_irq_senses(senses, 0, 128); mpic1 = mpic_alloc(irqctrler->addrs[0].address, MPIC_PRIMARY | MPIC_WANTS_RESET, - 0, 0, 128, 256, senses, 128, " K2-MPIC "); + 0, 0, 128, 252, senses, 128, " OpenPIC "); BUG_ON(mpic1 == NULL); mpic_init(mpic1); @@ -441,14 +441,15 @@ void __init pmac_pic_init(void) irqctrler2->intrs[0].line); pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); - prom_get_irq_senses(senses, 128, 128 + 128); + prom_get_irq_senses(senses, 128, 128 + 124); /* We don't need to set MPIC_BROKEN_U3 here since we don't have * hypertransport interrupts routed to it */ mpic2 = mpic_alloc(irqctrler2->addrs[0].address, MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, - 0, 128, 128, 0, senses, 128, " U3-MPIC "); + 0, 128, 124, 0, senses, 124, + " U3-MPIC "); BUG_ON(mpic2 == NULL); mpic_init(mpic2); mpic_setup_cascade(irqctrler2->intrs[0].line, diff --git a/arch/powerpc/platforms/powermac/pmac_smp.c b/arch/powerpc/platforms/powermac/pmac_smp.c index 995e9095d865..fb996336c58b 100644 --- a/arch/powerpc/platforms/powermac/pmac_smp.c +++ b/arch/powerpc/platforms/powermac/pmac_smp.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include @@ -638,14 +638,14 @@ void smp_core99_message_pass(int target, int msg, unsigned long data, int wait) } switch (target) { case MSG_ALL: - mpic_send_ipi(msg, mask); + mpic_send_ipi(msg, cpus_addr(mask)[0]); break; case MSG_ALL_BUT_SELF: cpu_clear(smp_processor_id(), mask); - mpic_send_ipi(msg, mask); + mpic_send_ipi(msg, cpus_addr(mask)[0]); break; default: - mpic_send_ipi(msg, cpumask_of_cpu(target)); + mpic_send_ipi(msg, 1 << target); break; } } @@ -678,7 +678,7 @@ int __cpu_disable(void) cpu_clear(smp_processor_id(), cpu_online_map); /* XXX reset cpu affinity here */ - openpic_set_priority(0xf); + mpic_cpu_set_priority(0xf); asm volatile("mtdec %0" : : "r" (0x7fffffff)); mb(); udelay(20); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c660e7d7c643..02b4d2488bfd 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -44,6 +44,9 @@ static struct mpic *mpics; static struct mpic *mpic_primary; static DEFINE_SPINLOCK(mpic_lock); +#ifdef CONFIG_PPC32 /* XXX for now */ +#define distribute_irqs CONFIG_IRQ_ALL_CPUS +#endif /* * Register accessor functions From dc1c1ca3dcd94c545c5e01d7c06b46824d43f4d0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sat, 1 Oct 2005 18:43:42 +1000 Subject: [PATCH 0244/1939] powerpc: merge idle_power4.S and trapc.s Use idle_power4.S from ppc64 as we are not going to support 32 bit power4 in the merged tree. Merge ppc64 traps.c into powerpc traps.c: use ppc64 versions of exception routine names (as they don't have StudlyCaps) make all the versions if die() have the same prototype Signed-off-by: Stephen Rothwell --- arch/powerpc/Kconfig | 4 +- arch/powerpc/kernel/head.S | 84 +-- arch/powerpc/kernel/head_44x.S | 14 +- arch/powerpc/kernel/head_4xx.S | 52 +- arch/powerpc/kernel/head_8xx.S | 42 +- arch/powerpc/kernel/head_fsl_booke.S | 24 +- arch/{ppc64 => powerpc}/kernel/idle_power4.S | 5 +- arch/powerpc/kernel/ppc_ksyms.c | 16 +- arch/powerpc/kernel/traps.c | 407 +++++++++---- arch/ppc/kernel/head.S | 84 +-- arch/ppc/kernel/head_44x.S | 14 +- arch/ppc/kernel/head_4xx.S | 52 +- arch/ppc/kernel/head_8xx.S | 42 +- arch/ppc/kernel/head_booke.h | 4 +- arch/ppc/kernel/head_fsl_booke.S | 24 +- arch/ppc/kernel/ppc_ksyms.c | 16 +- arch/ppc/kernel/traps.c | 20 +- arch/ppc/syslib/ibm44x_common.c | 2 +- arch/ppc/syslib/ppc4xx_setup.c | 2 +- arch/ppc64/kernel/Makefile | 8 + arch/ppc64/kernel/traps.c | 568 ------------------- include/asm-ppc/system.h | 2 +- 22 files changed, 564 insertions(+), 922 deletions(-) rename arch/{ppc64 => powerpc}/kernel/idle_power4.S (98%) delete mode 100644 arch/ppc64/kernel/traps.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index edfac467b9e0..953a74be57b6 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -142,8 +142,8 @@ config POWER4 def_bool y config PPC_FPU - bool - default y if PPC64 + depends on PPC32 + def_bool y config BOOKE bool diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S index 8cdac7385e7f..2c3a1d34e3c7 100644 --- a/arch/powerpc/kernel/head.S +++ b/arch/powerpc/kernel/head.S @@ -349,12 +349,12 @@ i##n: \ /* System reset */ /* core99 pmac starts the seconary here by changing the vector, and - putting it back to what it was (UnknownException) when done. */ + putting it back to what it was (unknown_exception) when done. */ #if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) . = 0x100 b __secondary_start_gemini #else - EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) + EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) #endif /* Machine check */ @@ -389,7 +389,7 @@ i##n: \ cmpwi cr1,r4,0 bne cr1,1f #endif - EXC_XFER_STD(0x200, MachineCheckException) + EXC_XFER_STD(0x200, machine_check_exception) #ifdef CONFIG_PPC_CHRP 1: b machine_check_in_rtas #endif @@ -456,10 +456,10 @@ Alignment: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* Program check exception */ - EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) /* Floating-point unavailable */ . = 0x800 @@ -472,8 +472,8 @@ FPUnavailable: /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) /* System call */ . = 0xc00 @@ -482,8 +482,8 @@ SystemCall: EXC_XFER_EE_LITE(0xc00, DoSyscall) /* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) + EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) /* * The Altivec unavailable trap is at 0x0f20. Foo. @@ -502,7 +502,7 @@ SystemCall: Trap_0f: EXCEPTION_PROLOG addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0xf00, UnknownException) + EXC_XFER_EE(0xf00, unknown_exception) /* * Handle TLB miss for instruction on 603/603e. @@ -702,44 +702,44 @@ DataStoreTLBMiss: rfi #ifndef CONFIG_ALTIVEC -#define AltivecAssistException UnknownException +#define altivec_assist_exception unknown_exception #endif - EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, EXC_XFER_EE) + EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE) EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) #ifdef CONFIG_POWER4 - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD) #else /* !CONFIG_POWER4 */ - EXCEPTION(0x1600, Trap_16, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_POWER4 */ - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE) - EXCEPTION(0x2100, Trap_21, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2200, Trap_22, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2300, Trap_23, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2400, Trap_24, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2500, Trap_25, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2600, Trap_26, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2700, Trap_27, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2800, Trap_28, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2900, Trap_29, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2a00, Trap_2a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2b00, Trap_2b, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2c00, Trap_2c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2d00, Trap_2d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2e00, Trap_2e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2f00, MOLTrampoline, UnknownException, EXC_XFER_EE_LITE) + EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE) .globl mol_trampoline .set mol_trampoline, i0x2f00 @@ -751,7 +751,7 @@ AltiVecUnavailable: #ifdef CONFIG_ALTIVEC bne load_up_altivec /* if from user, just load it up */ #endif /* CONFIG_ALTIVEC */ - EXC_XFER_EE_LITE(0xf20, AltivecUnavailException) + EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) #ifdef CONFIG_PPC64BRIDGE DataAccess: @@ -767,12 +767,12 @@ DataSegment: addi r3,r1,STACK_FRAME_OVERHEAD mfspr r4,SPRN_DAR stw r4,_DAR(r11) - EXC_XFER_STD(0x380, UnknownException) + EXC_XFER_STD(0x380, unknown_exception) InstructionSegment: EXCEPTION_PROLOG addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x480, UnknownException) + EXC_XFER_STD(0x480, unknown_exception) #endif /* CONFIG_PPC64BRIDGE */ #ifdef CONFIG_ALTIVEC diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 599245b0407e..b1b9dc08abca 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -309,13 +309,13 @@ skpinv: addi r4,r4,1 /* Increment */ interrupt_base: /* Critical Input Interrupt */ - CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) /* Machine Check Interrupt */ #ifdef CONFIG_440A - MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #else - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #endif /* Data Storage Interrupt */ @@ -442,7 +442,7 @@ interrupt_base: #ifdef CONFIG_PPC_FPU FP_UNAVAILABLE_EXCEPTION #else - EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) #endif /* System Call Interrupt */ @@ -451,21 +451,21 @@ interrupt_base: EXC_XFER_EE_LITE(0x0c00, DoSyscall) /* Auxillary Processor Unavailable Interrupt */ - EXCEPTION(0x2020, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) /* Decrementer Interrupt */ DECREMENTER_EXCEPTION /* Fixed Internal Timer Interrupt */ /* TODO: Add FIT support */ - EXCEPTION(0x1010, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) /* Watchdog Timer Interrupt */ /* TODO: Add watchdog support */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) #else - CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException) + CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception) #endif /* Data TLB Error Interrupt */ diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S index 8562b807b37c..5772ce97e24e 100644 --- a/arch/powerpc/kernel/head_4xx.S +++ b/arch/powerpc/kernel/head_4xx.S @@ -245,12 +245,12 @@ label: /* * 0x0100 - Critical Interrupt Exception */ - CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, unknown_exception) /* * 0x0200 - Machine Check Exception */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) /* * 0x0300 - Data Storage Exception @@ -405,7 +405,7 @@ label: mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ stw r4,_DEAR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* 0x0700 - Program Exception */ START_EXCEPTION(0x0700, ProgramCheck) @@ -413,21 +413,21 @@ label: mfspr r4,SPRN_ESR /* Grab the ESR and save it */ stw r4,_ESR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x700, ProgramCheckException) + EXC_XFER_STD(0x700, program_check_exception) - EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0A00, Trap_0A, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0B00, Trap_0B, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0800, Trap_08, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0900, Trap_09, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0A00, Trap_0A, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0B00, Trap_0B, unknown_exception, EXC_XFER_EE) /* 0x0C00 - System Call Exception */ START_EXCEPTION(0x0C00, SystemCall) NORMAL_EXCEPTION_PROLOG EXC_XFER_EE_LITE(0xc00, DoSyscall) - EXCEPTION(0x0D00, Trap_0D, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0E00, Trap_0E, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0F00, Trap_0F, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0D00, Trap_0D, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0E00, Trap_0E, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0F00, Trap_0F, unknown_exception, EXC_XFER_EE) /* 0x1000 - Programmable Interval Timer (PIT) Exception */ START_EXCEPTION(0x1000, Decrementer) @@ -444,14 +444,14 @@ label: /* 0x1010 - Fixed Interval Timer (FIT) Exception */ - STND_EXCEPTION(0x1010, FITException, UnknownException) + STND_EXCEPTION(0x1010, FITException, unknown_exception) /* 0x1020 - Watchdog Timer (WDT) Exception */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException) #else - CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException) + CRITICAL_EXCEPTION(0x1020, WDTException, unknown_exception) #endif #endif @@ -656,25 +656,25 @@ label: mfspr r10, SPRN_SPRG0 b InstructionAccess - EXCEPTION(0x1300, Trap_13, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1400, Trap_14, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1300, Trap_13, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1400, Trap_14, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) #ifdef CONFIG_IBM405_ERR51 /* 405GP errata 51 */ START_EXCEPTION(0x1700, Trap_17) b DTLBMiss #else - EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) #endif - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1A00, Trap_1A, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1B00, Trap_1B, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1C00, Trap_1C, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1D00, Trap_1D, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1A00, Trap_1A, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1B00, Trap_1B, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1C00, Trap_1C, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1D00, Trap_1D, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1E00, Trap_1E, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1F00, Trap_1F, unknown_exception, EXC_XFER_EE) /* Check for a single step debug exception while in an exception * handler before state has been saved. This is to catch the case diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index cb1a3a54a026..de0978742221 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -203,7 +203,7 @@ i##n: \ ret_from_except) /* System reset */ - EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) + EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) /* Machine check */ . = 0x200 @@ -214,7 +214,7 @@ MachineCheck: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x200, MachineCheckException) + EXC_XFER_STD(0x200, machine_check_exception) /* Data access exception. * This is "never generated" by the MPC8xx. We jump to it for other @@ -252,20 +252,20 @@ Alignment: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* Program check exception */ - EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) /* No FPU on MPC8xx. This exception is not supposed to happen. */ - EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD) + EXCEPTION(0x800, FPUnavailable, unknown_exception, EXC_XFER_STD) /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) /* System call */ . = 0xc00 @@ -274,9 +274,9 @@ SystemCall: EXC_XFER_EE_LITE(0xc00, DoSyscall) /* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) - EXCEPTION(0xf00, Trap_0f, UnknownException, EXC_XFER_EE) + EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xf00, Trap_0f, unknown_exception, EXC_XFER_EE) /* On the MPC8xx, this is a software emulation interrupt. It occurs * for all unimplemented and illegal instructions. @@ -540,22 +540,22 @@ DataTLBError: #endif b DataAccess - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) /* On the MPC8xx, these next four traps are used for development * support of breakpoints and such. Someday I will get around to * using them. */ - EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) . = 0x2000 diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index eba5a5f8ff08..53949811efda 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -426,14 +426,14 @@ skpinv: addi r6,r6,1 /* Increment */ interrupt_base: /* Critical Input Interrupt */ - CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) /* Machine Check Interrupt */ #ifdef CONFIG_E200 /* no RFMCI, MCSRRs on E200 */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #else - MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #endif /* Data Storage Interrupt */ @@ -542,9 +542,9 @@ interrupt_base: #else #ifdef CONFIG_E200 /* E200 treats 'normal' floating point instructions as FP Unavail exception */ - EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE) + EXCEPTION(0x0800, FloatingPointUnavailable, program_check_exception, EXC_XFER_EE) #else - EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0800, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) #endif #endif @@ -554,20 +554,20 @@ interrupt_base: EXC_XFER_EE_LITE(0x0c00, DoSyscall) /* Auxillary Processor Unavailable Interrupt */ - EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2900, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) /* Decrementer Interrupt */ DECREMENTER_EXCEPTION /* Fixed Internal Timer Interrupt */ /* TODO: Add FIT support */ - EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + EXCEPTION(0x3100, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) /* Watchdog Timer Interrupt */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException) #else - CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) + CRITICAL_EXCEPTION(0x3200, WatchdogTimer, unknown_exception) #endif /* Data TLB Error Interrupt */ @@ -696,21 +696,21 @@ interrupt_base: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x2010, KernelSPE) #else - EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2020, SPEUnavailable, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_SPE */ /* SPE Floating Point Data */ #ifdef CONFIG_SPE EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE); #else - EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_SPE */ /* SPE Floating Point Round */ - EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception, EXC_XFER_EE) /* Performance Monitor */ - EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD) + EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) /* Debug Interrupt */ diff --git a/arch/ppc64/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S similarity index 98% rename from arch/ppc64/kernel/idle_power4.S rename to arch/powerpc/kernel/idle_power4.S index ca02afe2a795..5596fad6c87c 100644 --- a/arch/ppc64/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -63,8 +63,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) beq 1f mtmsrd r7 /* out of line this ? */ blr -1: - /* Go to NAP now */ +1: + /* Go to NAP now */ BEGIN_FTR_SECTION DSSALL sync @@ -76,4 +76,3 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) isync sync blr - diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 7bfa0f0121ff..07c994585c0b 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -53,10 +53,10 @@ extern void transfer_to_handler(void); extern void do_IRQ(struct pt_regs *regs); -extern void MachineCheckException(struct pt_regs *regs); -extern void AlignmentException(struct pt_regs *regs); -extern void ProgramCheckException(struct pt_regs *regs); -extern void SingleStepException(struct pt_regs *regs); +extern void machine_check_exception(struct pt_regs *regs); +extern void alignment_exception(struct pt_regs *regs); +extern void program_check_exception(struct pt_regs *regs); +extern void single_step_exception(struct pt_regs *regs); extern int do_signal(sigset_t *, struct pt_regs *); extern int pmac_newworld; extern int sys_sigreturn(struct pt_regs *regs); @@ -72,10 +72,10 @@ EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); -EXPORT_SYMBOL(MachineCheckException); -EXPORT_SYMBOL(AlignmentException); -EXPORT_SYMBOL(ProgramCheckException); -EXPORT_SYMBOL(SingleStepException); +EXPORT_SYMBOL(machine_check_exception); +EXPORT_SYMBOL(alignment_exception); +EXPORT_SYMBOL(program_check_exception); +EXPORT_SYMBOL(single_step_exception); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(ppc_lost_interrupts); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c7afbbba0f36..37b961f1e279 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1,6 +1,4 @@ /* - * arch/powerpc/kernel/traps.c - * * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * This program is free software; you can redistribute it and/or @@ -23,29 +21,46 @@ #include #include #include -#include #include #include #include #include -#include #include #include -#include #include #include #include +#ifdef CONFIG_PPC32 +#include +#include +#endif #include #include #include #include +#ifdef CONFIG_PPC32 #include #include #ifdef CONFIG_PMAC_BACKLIGHT #include #endif #include +#endif +#ifdef CONFIG_PPC64 +#include +#include +#include +#include +#include +#include +#endif + +#ifdef CONFIG_PPC64 +#define __KPROBES __kprobes +#else +#define __KPROBES +#endif #ifdef CONFIG_DEBUGGER int (*__debugger)(struct pt_regs *regs); @@ -96,7 +111,7 @@ int die(const char *str, struct pt_regs *regs, long err) console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); -#ifdef CONFIG_PMAC_BACKLIGHT +#if defined(CONFIG_PPC32) && defined(CONFIG_PMAC_BACKLIGHT) if (_machine == _MACH_Pmac) { set_backlight_enable(1); set_backlight_level(BACKLIGHT_MAX); @@ -154,9 +169,17 @@ int die(const char *str, struct pt_regs *regs, long err) panic("Fatal exception in interrupt"); if (panic_on_oops) { +#ifdef CONFIG_PPC64 + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); +#endif panic("Fatal exception"); } +#ifdef CONFIG_PPC32 do_exit(err); +#else + do_exit(SIGSEGV); +#endif return 0; } @@ -176,6 +199,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) info.si_addr = (void __user *) addr; force_sig_info(signr, &info, current); +#ifdef CONFIG_PPC32 /* * Init gets no signals that it doesn't have a handler for. * That's all very well, but if it has caused a synchronous @@ -197,6 +221,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) do_exit(signr); } } +#endif } #ifdef CONFIG_PPC64 @@ -206,7 +231,7 @@ void system_reset_exception(struct pt_regs *regs) if (ppc_md.system_reset_exception) ppc_md.system_reset_exception(regs); - die("System Reset", regs, SIGABRT); + die("System Reset", regs, 0); /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) @@ -216,6 +241,7 @@ void system_reset_exception(struct pt_regs *regs) } #endif +#ifdef CONFIG_PPC32 /* * I/O accesses can cause machine checks on powermacs. * Check if the NIP corresponds to the address of a sync @@ -264,8 +290,10 @@ static inline int check_io_access(struct pt_regs *regs) #endif /* CONFIG_PPC_PMAC */ return 0; } +#endif /* CONFIG_PPC32 */ #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + /* On 4xx, the reason for the machine check or program exception is in the ESR. */ #define get_reason(regs) ((regs)->dsisr) @@ -284,6 +312,7 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC) #else + /* On non-4xx, the reason for the machine check or program exception is in the MSR. */ #define get_reason(regs) ((regs)->msr) @@ -297,6 +326,7 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) #endif +#ifdef CONFIG_PPC32 /* * This is "fall-back" implementation for configurations * which don't provide platform-specific machine check info @@ -305,8 +335,9 @@ void __attribute__ ((weak)) platform_machine_check(struct pt_regs *regs) { } +#endif -void MachineCheckException(struct pt_regs *regs) +void machine_check_exception(struct pt_regs *regs) { #ifdef CONFIG_PPC64 int recover = 0; @@ -462,23 +493,31 @@ void MachineCheckException(struct pt_regs *regs) * additional info, e.g. bus error registers. */ platform_machine_check(regs); -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC32 */ if (debugger_fault_handler(regs)) return; - die("Machine check", regs, SIGBUS); + die("Machine check", regs, +#ifdef CONFIG_PPC32 + SIGBUS +#else + 0 +#endif + ); /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) panic("Unrecoverable Machine check"); } +#ifdef CONFIG_PPC32 void SMIException(struct pt_regs *regs) { die("System Management Interrupt", regs, SIGABRT); } +#endif -void UnknownException(struct pt_regs *regs) +void unknown_exception(struct pt_regs *regs) { printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", regs->nip, regs->msr, regs->trap); @@ -486,7 +525,7 @@ void UnknownException(struct pt_regs *regs) _exception(SIGTRAP, regs, 0, 0); } -void InstructionBreakpoint(struct pt_regs *regs) +void instruction_breakpoint_exception(struct pt_regs *regs) { if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, 5, SIGTRAP) == NOTIFY_STOP) @@ -496,14 +535,20 @@ void InstructionBreakpoint(struct pt_regs *regs) _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); } +#ifdef CONFIG_PPC32 void RunModeException(struct pt_regs *regs) { _exception(SIGTRAP, regs, 0, 0); } +#endif -void SingleStepException(struct pt_regs *regs) +void __KPROBES single_step_exception(struct pt_regs *regs) { +#ifdef CONFIG_PPC32 regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ +#else + regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ +#endif if (notify_die(DIE_SSTEP, "single_step", regs, 5, 5, SIGTRAP) == NOTIFY_STOP) @@ -520,15 +565,62 @@ void SingleStepException(struct pt_regs *regs) * pretend we got a single-step exception. This was pointed out * by Kumar Gala. -- paulus */ -static void emulate_single_step(struct pt_regs *regs) +static inline void emulate_single_step(struct pt_regs *regs) { if (single_stepping(regs)) { +#ifdef CONFIG_PPC32 clear_single_step(regs); _exception(SIGTRAP, regs, TRAP_TRACE, 0); +#else + single_step_exception(regs); +#endif } } -/* Illegal instruction emulation support. Originally written to +static void parse_fpe(struct pt_regs *regs) +{ + int code = 0; + unsigned long fpscr; + +#ifdef CONFIG_PPC32 + /* We must make sure the FP state is consistent with + * our MSR_FP in regs + */ + preempt_disable(); + if (regs->msr & MSR_FP) + giveup_fpu(current); + preempt_enable(); +#else + flush_fp_to_thread(current); +#endif + + fpscr = current->thread.fpscr; + + /* Invalid operation */ + if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) + code = FPE_FLTINV; + + /* Overflow */ + else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) + code = FPE_FLTOVF; + + /* Underflow */ + else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) + code = FPE_FLTUND; + + /* Divide by zero */ + else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) + code = FPE_FLTDIV; + + /* Inexact result */ + else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) + code = FPE_FLTRES; + + _exception(SIGFPE, regs, code, regs->nip); +} + +/* + * Illegal instruction emulation support. Originally written to * provide the PVR to user applications using the mfspr rd, PVR. * Return non-zero if we can't emulate, or -EFAULT if the associated * memory access caused an access fault. Return zero on success. @@ -536,7 +628,6 @@ static void emulate_single_step(struct pt_regs *regs) * There are a couple of ways to do this, either "decode" the instruction * or directly match lots of bits. In this case, matching lots of * bits is faster and easier. - * */ #define INST_MFSPR_PVR 0x7c1f42a6 #define INST_MFSPR_PVR_MASK 0xfc1fffff @@ -547,6 +638,8 @@ static void emulate_single_step(struct pt_regs *regs) #define INST_MCRXR 0x7c000400 #define INST_MCRXR_MASK 0x7c0007fe +#ifdef CONFIG_PPC32 + #define INST_STRING 0x7c00042a #define INST_STRING_MASK 0x7c0007fe #define INST_STRING_GEN_MASK 0x7c00067e @@ -622,6 +715,7 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) return 0; } +#endif /* CONFIG_PPC32 */ static int emulate_instruction(struct pt_regs *regs) { @@ -643,22 +737,44 @@ static int emulate_instruction(struct pt_regs *regs) } /* Emulating the dcba insn is just a no-op. */ - if ((instword & INST_DCBA_MASK) == INST_DCBA) + if ((instword & INST_DCBA_MASK) == INST_DCBA) { +#ifdef CONFIG_PPC64 + static int warned; + + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'dcba' insn\n", + current->pid, current->comm); + warned = 1; + } +#endif /* CONFIG_PPC64 */ return 0; + } /* Emulate the mcrxr insn. */ if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { - int shift = (instword >> 21) & 0x1c; + unsigned int shift = (instword >> 21) & 0x1c; unsigned long msk = 0xf0000000UL >> shift; +#ifdef CONFIG_PPC64 + static int warned; + if (!warned) { + printk(KERN_WARNING + "process %d (%s) uses obsolete 'mcrxr' insn\n", + current->pid, current->comm); + warned = 1; + } +#endif regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); regs->xer &= ~0xf0000000UL; return 0; } +#ifdef CONFIG_PPC32 /* Emulate load/store string insn. */ if ((instword & INST_STRING_GEN_MASK) == INST_STRING) return emulate_string_inst(regs, instword); +#endif return -EINVAL; } @@ -686,7 +802,7 @@ struct bug_entry *find_bug(unsigned long bugaddr) return module_find_bug(bugaddr); } -int check_bug_trap(struct pt_regs *regs) +static int check_bug_trap(struct pt_regs *regs) { struct bug_entry *bug; unsigned long addr; @@ -701,34 +817,38 @@ int check_bug_trap(struct pt_regs *regs) return 0; if (bug->line & BUG_WARNING_TRAP) { /* this is a WARN_ON rather than BUG/BUG_ON */ -#ifdef CONFIG_XMON +#if defined(CONFIG_PPC32) && defined(CONFIG_XMON) xmon_printf(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); -#endif /* CONFIG_XMON */ +#endif printk(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); +#ifdef CONFIG_PPC32 dump_stack(); +#else + show_stack(current, (void *)regs->gpr[1]); +#endif return 1; } -#ifdef CONFIG_XMON +#if defined(CONFIG_PPC32) && defined(CONFIG_XMON) xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n", bug->function, bug->file, bug->line); xmon(regs); -#endif /* CONFIG_XMON */ +#endif printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", bug->function, bug->file, bug->line); return 0; } -void ProgramCheckException(struct pt_regs *regs) +void __KPROBES program_check_exception(struct pt_regs *regs) { unsigned int reason = get_reason(regs); +#if defined(CONFIG_PPC32) && defined(CONFIG_MATH_EMULATION) extern int do_mathemu(struct pt_regs *regs); -#ifdef CONFIG_MATH_EMULATION /* (reason & REASON_ILLEGAL) would be the obvious thing here, * but there seems to be a hardware bug on the 405GP (RevD) * that means ESR is sometimes set incorrectly - either to @@ -740,69 +860,61 @@ void ProgramCheckException(struct pt_regs *regs) emulate_single_step(regs); return; } -#endif /* CONFIG_MATH_EMULATION */ +#endif + +#ifdef CONFIG_PPC64 + if (debugger_fault_handler(regs)) + return; +#endif if (reason & REASON_FP) { /* IEEE FP exception */ - int code = 0; - u32 fpscr; - - /* We must make sure the FP state is consistent with - * our MSR_FP in regs - */ - preempt_disable(); - if (regs->msr & MSR_FP) - giveup_fpu(current); - preempt_enable(); - - fpscr = current->thread.fpscr; - fpscr &= fpscr << 22; /* mask summary bits with enables */ - if (fpscr & FPSCR_VX) - code = FPE_FLTINV; - else if (fpscr & FPSCR_OX) - code = FPE_FLTOVF; - else if (fpscr & FPSCR_UX) - code = FPE_FLTUND; - else if (fpscr & FPSCR_ZX) - code = FPE_FLTDIV; - else if (fpscr & FPSCR_XX) - code = FPE_FLTRES; - _exception(SIGFPE, regs, code, regs->nip); - return; - } - - if (reason & REASON_TRAP) { + parse_fpe(regs); + } else if (reason & REASON_TRAP) { /* trap exception */ +#ifdef CONFIG_PPC64 + if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP) + == NOTIFY_STOP) + return; +#endif if (debugger_bpt(regs)) return; if (check_bug_trap(regs)) { regs->nip += 4; return; } - _exception(SIGTRAP, regs, TRAP_BRKPT, 0); - return; - } - - /* Try to emulate it if we should. */ - if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { + _exception(SIGTRAP, regs, TRAP_BRKPT, +#ifdef CONFIG_PPC32 + 0 +#else + regs->nip +#endif + ); + } else +#ifdef CONFIG_PPC32 + if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) +#endif + { + /* Privileged or illegal instruction; try to emulate it. */ switch (emulate_instruction(regs)) { case 0: regs->nip += 4; emulate_single_step(regs); - return; + break; case -EFAULT: _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); - return; + break; + default: + if (reason & REASON_PRIVILEGED) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + break; } } - - if (reason & REASON_PRIVILEGED) - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - else - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } -void AlignmentException(struct pt_regs *regs) +void alignment_exception(struct pt_regs *regs) { int fixed; @@ -814,18 +926,31 @@ void AlignmentException(struct pt_regs *regs) return; } - /* Operand address was bad */ + /* Operand address was bad */ if (fixed == -EFAULT) { if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); + _exception(SIGSEGV, regs, +#ifdef CONFIG_PPC32 + SEGV_ACCERR, +#else + SEGV_MAPERR, +#endif + regs->dar); else /* Search exception table */ bad_page_fault(regs, regs->dar, SIGSEGV); return; } - _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); + _exception(SIGBUS, regs, BUS_ADRALN, +#ifdef CONFIG_PPC32 + regs->dar +#else + regs->nip +#endif + ); } +#ifdef CONFIG_PPC32 void StackOverflow(struct pt_regs *regs) { printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", @@ -849,8 +974,58 @@ void trace_syscall(struct pt_regs *regs) current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); } +#endif /* CONFIG_PPC32 */ -#ifdef CONFIG_8xx +#ifdef CONFIG_PPC64 +void kernel_fp_unavailable_exception(struct pt_regs *regs) +{ + printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " + "%lx at %lx\n", regs->trap, regs->nip); + die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); +} +#endif + +void altivec_unavailable_exception(struct pt_regs *regs) +{ +#if !defined(CONFIG_ALTIVEC) || defined(CONFIG_PPC64) + if (user_mode(regs)) { + /* A user program has executed an altivec instruction, + but this kernel doesn't support altivec. */ + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + return; + } +#endif +#ifdef CONFIG_PPC32 + { + static int kernel_altivec_count; + + /* The kernel has executed an altivec instruction without + first enabling altivec. Whinge but let it do it. */ + if (++kernel_altivec_count < 10) + printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", + current, regs->nip); + regs->msr |= MSR_VEC; + } +#else + printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " + "%lx at %lx\n", regs->trap, regs->nip); + die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); +#endif +} + +#ifdef CONFIG_PPC64 +extern perf_irq_t perf_irq; +#endif + +#if defined(CONFIG_PPC64) || defined(CONFIG_E500) +void performance_monitor_exception(struct pt_regs *regs) +{ + perf_irq(regs); +} +#endif + + +#if defined(CONFIG_PPC32) && defined(CONFIG_8xx) void SoftwareEmulation(struct pt_regs *regs) { extern int do_mathemu(struct pt_regs *); @@ -879,8 +1054,9 @@ void SoftwareEmulation(struct pt_regs *regs) } else emulate_single_step(regs); } -#endif /* CONFIG_8xx */ +#endif /* defined(CONFIG_PPC32) && defined(CONFIG_8xx) */ +#ifdef CONFIG_PPC32 #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) void DebugException(struct pt_regs *regs, unsigned long debug_status) @@ -909,42 +1085,36 @@ void TAUException(struct pt_regs *regs) regs->nip, regs->msr, regs->trap, print_tainted()); } #endif /* CONFIG_INT_TAU */ - -void AltivecUnavailException(struct pt_regs *regs) -{ - static int kernel_altivec_count; - -#ifndef CONFIG_ALTIVEC - if (user_mode(regs)) { - /* A user program has executed an altivec instruction, - but this kernel doesn't support altivec. */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return; - } -#endif - /* The kernel has executed an altivec instruction without - first enabling altivec. Whinge but let it do it. */ - if (++kernel_altivec_count < 10) - printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", - current, regs->nip); - regs->msr |= MSR_VEC; -} +#endif /* CONFIG_PPC32*/ #ifdef CONFIG_ALTIVEC -void AltivecAssistException(struct pt_regs *regs) +void altivec_assist_exception(struct pt_regs *regs) { int err; +#ifdef CONFIG_PPC64 + siginfo_t info; +#endif +#ifdef CONFIG_PPC32 preempt_disable(); if (regs->msr & MSR_VEC) giveup_altivec(current); preempt_enable(); +#endif if (!user_mode(regs)) { printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" " at %lx\n", regs->nip); - die("Kernel Altivec assist exception", regs, SIGILL); + die("Kernel " +#ifdef CONFIG_PPC64 + "VMX/" +#endif + "Altivec assist exception", regs, SIGILL); } +#ifdef CONFIG_PPC64 + flush_altivec_to_thread(current); +#endif /* CONFIG_PPC64 */ + err = emulate_altivec(regs); if (err == 0) { regs->nip += 4; /* skip emulated instruction */ @@ -954,7 +1124,15 @@ void AltivecAssistException(struct pt_regs *regs) if (err == -EFAULT) { /* got an error reading the instruction */ +#ifdef CONFIG_PPC32 _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); +#else + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = (void __user *) regs->nip; + force_sig_info(SIGSEGV, &info, current); +#endif } else { /* didn't recognize the instruction */ /* XXX quick hack for now: set the non-Java bit in the VSCR */ @@ -966,13 +1144,7 @@ void AltivecAssistException(struct pt_regs *regs) } #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_E500 -void PerformanceMonitorException(struct pt_regs *regs) -{ - perf_irq(regs); -} -#endif - +#ifdef CONFIG_PPC32 #ifdef CONFIG_FSL_BOOKE void CacheLockingException(struct pt_regs *regs, unsigned long address, unsigned long error_code) @@ -1022,7 +1194,24 @@ void SPEFloatingPointException(struct pt_regs *regs) return; } #endif +#endif /* CONFIG_PPC32 */ +#ifdef CONFIG_PPC64 +/* + * We enter here if we get an unrecoverable exception, that is, one + * that happened at a point where the RI (recoverable interrupt) bit + * in the MSR is 0. This indicates that SRR0/1 are live, and that + * we therefore lost state by taking this exception. + */ +void unrecoverable_exception(struct pt_regs *regs) +{ + printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n", + regs->trap, regs->nip); + die("Unrecoverable exception", regs, SIGABRT); +} +#endif /* CONFIG_PPC64 */ + +#ifdef CONFIG_PPC32 #ifdef CONFIG_BOOKE_WDT /* * Default handler for a Watchdog exception, @@ -1041,6 +1230,20 @@ void WatchdogException(struct pt_regs *regs) WatchdogHandler(regs); } #endif +#endif /* CONFIG_PPC32 */ + +#ifdef CONFIG_PPC64 +/* + * We enter here if we discover during exception entry that we are + * running in supervisor mode with a userspace value in the stack pointer. + */ +void kernel_bad_stack(struct pt_regs *regs) +{ + printk(KERN_EMERG "Bad kernel stack pointer %lx at %lx\n", + regs->gpr[1], regs->nip); + die("Bad kernel stack pointer", regs, SIGABRT); +} +#endif void __init trap_init(void) { diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 8cdac7385e7f..2c3a1d34e3c7 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -349,12 +349,12 @@ i##n: \ /* System reset */ /* core99 pmac starts the seconary here by changing the vector, and - putting it back to what it was (UnknownException) when done. */ + putting it back to what it was (unknown_exception) when done. */ #if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) . = 0x100 b __secondary_start_gemini #else - EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) + EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) #endif /* Machine check */ @@ -389,7 +389,7 @@ i##n: \ cmpwi cr1,r4,0 bne cr1,1f #endif - EXC_XFER_STD(0x200, MachineCheckException) + EXC_XFER_STD(0x200, machine_check_exception) #ifdef CONFIG_PPC_CHRP 1: b machine_check_in_rtas #endif @@ -456,10 +456,10 @@ Alignment: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* Program check exception */ - EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) /* Floating-point unavailable */ . = 0x800 @@ -472,8 +472,8 @@ FPUnavailable: /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) /* System call */ . = 0xc00 @@ -482,8 +482,8 @@ SystemCall: EXC_XFER_EE_LITE(0xc00, DoSyscall) /* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) + EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) /* * The Altivec unavailable trap is at 0x0f20. Foo. @@ -502,7 +502,7 @@ SystemCall: Trap_0f: EXCEPTION_PROLOG addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0xf00, UnknownException) + EXC_XFER_EE(0xf00, unknown_exception) /* * Handle TLB miss for instruction on 603/603e. @@ -702,44 +702,44 @@ DataStoreTLBMiss: rfi #ifndef CONFIG_ALTIVEC -#define AltivecAssistException UnknownException +#define altivec_assist_exception unknown_exception #endif - EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, EXC_XFER_EE) + EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE) EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) #ifdef CONFIG_POWER4 - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD) #else /* !CONFIG_POWER4 */ - EXCEPTION(0x1600, Trap_16, AltivecAssistException, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_POWER4 */ - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE) - EXCEPTION(0x2100, Trap_21, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2200, Trap_22, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2300, Trap_23, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2400, Trap_24, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2500, Trap_25, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2600, Trap_26, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2700, Trap_27, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2800, Trap_28, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2900, Trap_29, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2a00, Trap_2a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2b00, Trap_2b, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2c00, Trap_2c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2d00, Trap_2d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2e00, Trap_2e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x2f00, MOLTrampoline, UnknownException, EXC_XFER_EE_LITE) + EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE) .globl mol_trampoline .set mol_trampoline, i0x2f00 @@ -751,7 +751,7 @@ AltiVecUnavailable: #ifdef CONFIG_ALTIVEC bne load_up_altivec /* if from user, just load it up */ #endif /* CONFIG_ALTIVEC */ - EXC_XFER_EE_LITE(0xf20, AltivecUnavailException) + EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) #ifdef CONFIG_PPC64BRIDGE DataAccess: @@ -767,12 +767,12 @@ DataSegment: addi r3,r1,STACK_FRAME_OVERHEAD mfspr r4,SPRN_DAR stw r4,_DAR(r11) - EXC_XFER_STD(0x380, UnknownException) + EXC_XFER_STD(0x380, unknown_exception) InstructionSegment: EXCEPTION_PROLOG addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x480, UnknownException) + EXC_XFER_STD(0x480, unknown_exception) #endif /* CONFIG_PPC64BRIDGE */ #ifdef CONFIG_ALTIVEC diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 599245b0407e..b1b9dc08abca 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -309,13 +309,13 @@ skpinv: addi r4,r4,1 /* Increment */ interrupt_base: /* Critical Input Interrupt */ - CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) /* Machine Check Interrupt */ #ifdef CONFIG_440A - MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #else - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #endif /* Data Storage Interrupt */ @@ -442,7 +442,7 @@ interrupt_base: #ifdef CONFIG_PPC_FPU FP_UNAVAILABLE_EXCEPTION #else - EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) #endif /* System Call Interrupt */ @@ -451,21 +451,21 @@ interrupt_base: EXC_XFER_EE_LITE(0x0c00, DoSyscall) /* Auxillary Processor Unavailable Interrupt */ - EXCEPTION(0x2020, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) /* Decrementer Interrupt */ DECREMENTER_EXCEPTION /* Fixed Internal Timer Interrupt */ /* TODO: Add FIT support */ - EXCEPTION(0x1010, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) /* Watchdog Timer Interrupt */ /* TODO: Add watchdog support */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) #else - CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException) + CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception) #endif /* Data TLB Error Interrupt */ diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index 8562b807b37c..5772ce97e24e 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -245,12 +245,12 @@ label: /* * 0x0100 - Critical Interrupt Exception */ - CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, unknown_exception) /* * 0x0200 - Machine Check Exception */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) /* * 0x0300 - Data Storage Exception @@ -405,7 +405,7 @@ label: mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ stw r4,_DEAR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* 0x0700 - Program Exception */ START_EXCEPTION(0x0700, ProgramCheck) @@ -413,21 +413,21 @@ label: mfspr r4,SPRN_ESR /* Grab the ESR and save it */ stw r4,_ESR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x700, ProgramCheckException) + EXC_XFER_STD(0x700, program_check_exception) - EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0A00, Trap_0A, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0B00, Trap_0B, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0800, Trap_08, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0900, Trap_09, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0A00, Trap_0A, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0B00, Trap_0B, unknown_exception, EXC_XFER_EE) /* 0x0C00 - System Call Exception */ START_EXCEPTION(0x0C00, SystemCall) NORMAL_EXCEPTION_PROLOG EXC_XFER_EE_LITE(0xc00, DoSyscall) - EXCEPTION(0x0D00, Trap_0D, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0E00, Trap_0E, UnknownException, EXC_XFER_EE) - EXCEPTION(0x0F00, Trap_0F, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0D00, Trap_0D, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0E00, Trap_0E, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x0F00, Trap_0F, unknown_exception, EXC_XFER_EE) /* 0x1000 - Programmable Interval Timer (PIT) Exception */ START_EXCEPTION(0x1000, Decrementer) @@ -444,14 +444,14 @@ label: /* 0x1010 - Fixed Interval Timer (FIT) Exception */ - STND_EXCEPTION(0x1010, FITException, UnknownException) + STND_EXCEPTION(0x1010, FITException, unknown_exception) /* 0x1020 - Watchdog Timer (WDT) Exception */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException) #else - CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException) + CRITICAL_EXCEPTION(0x1020, WDTException, unknown_exception) #endif #endif @@ -656,25 +656,25 @@ label: mfspr r10, SPRN_SPRG0 b InstructionAccess - EXCEPTION(0x1300, Trap_13, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1400, Trap_14, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1300, Trap_13, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1400, Trap_14, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) #ifdef CONFIG_IBM405_ERR51 /* 405GP errata 51 */ START_EXCEPTION(0x1700, Trap_17) b DTLBMiss #else - EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) #endif - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1A00, Trap_1A, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1B00, Trap_1B, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1C00, Trap_1C, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1D00, Trap_1D, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1A00, Trap_1A, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1B00, Trap_1B, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1C00, Trap_1C, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1D00, Trap_1D, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1E00, Trap_1E, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1F00, Trap_1F, unknown_exception, EXC_XFER_EE) /* Check for a single step debug exception while in an exception * handler before state has been saved. This is to catch the case diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index cb1a3a54a026..de0978742221 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -203,7 +203,7 @@ i##n: \ ret_from_except) /* System reset */ - EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD) + EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) /* Machine check */ . = 0x200 @@ -214,7 +214,7 @@ MachineCheck: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x200, MachineCheckException) + EXC_XFER_STD(0x200, machine_check_exception) /* Data access exception. * This is "never generated" by the MPC8xx. We jump to it for other @@ -252,20 +252,20 @@ Alignment: mfspr r5,SPRN_DSISR stw r5,_DSISR(r11) addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, AlignmentException) + EXC_XFER_EE(0x600, alignment_exception) /* Program check exception */ - EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD) + EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) /* No FPU on MPC8xx. This exception is not supposed to happen. */ - EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD) + EXCEPTION(0x800, FPUnavailable, unknown_exception, EXC_XFER_STD) /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE) + EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) /* System call */ . = 0xc00 @@ -274,9 +274,9 @@ SystemCall: EXC_XFER_EE_LITE(0xc00, DoSyscall) /* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) - EXCEPTION(0xf00, Trap_0f, UnknownException, EXC_XFER_EE) + EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) + EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0xf00, Trap_0f, unknown_exception, EXC_XFER_EE) /* On the MPC8xx, this is a software emulation interrupt. It occurs * for all unimplemented and illegal instructions. @@ -540,22 +540,22 @@ DataTLBError: #endif b DataAccess - EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) /* On the MPC8xx, these next four traps are used for development * support of breakpoints and such. Someday I will get around to * using them. */ - EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE) + EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) + EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) . = 0x2000 diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index 9342acf12e72..aeb349b47af3 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h @@ -335,7 +335,7 @@ mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \ stw r4,_DEAR(r11); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_EE(0x0600, AlignmentException) + EXC_XFER_EE(0x0600, alignment_exception) #define PROGRAM_EXCEPTION \ START_EXCEPTION(Program) \ @@ -343,7 +343,7 @@ mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \ stw r4,_ESR(r11); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_STD(0x0700, ProgramCheckException) + EXC_XFER_STD(0x0700, program_check_exception) #define DECREMENTER_EXCEPTION \ START_EXCEPTION(Decrementer) \ diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index eba5a5f8ff08..53949811efda 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -426,14 +426,14 @@ skpinv: addi r6,r6,1 /* Increment */ interrupt_base: /* Critical Input Interrupt */ - CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) /* Machine Check Interrupt */ #ifdef CONFIG_E200 /* no RFMCI, MCSRRs on E200 */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #else - MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) #endif /* Data Storage Interrupt */ @@ -542,9 +542,9 @@ interrupt_base: #else #ifdef CONFIG_E200 /* E200 treats 'normal' floating point instructions as FP Unavail exception */ - EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE) + EXCEPTION(0x0800, FloatingPointUnavailable, program_check_exception, EXC_XFER_EE) #else - EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x0800, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) #endif #endif @@ -554,20 +554,20 @@ interrupt_base: EXC_XFER_EE_LITE(0x0c00, DoSyscall) /* Auxillary Processor Unavailable Interrupt */ - EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2900, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) /* Decrementer Interrupt */ DECREMENTER_EXCEPTION /* Fixed Internal Timer Interrupt */ /* TODO: Add FIT support */ - EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + EXCEPTION(0x3100, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) /* Watchdog Timer Interrupt */ #ifdef CONFIG_BOOKE_WDT CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException) #else - CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) + CRITICAL_EXCEPTION(0x3200, WatchdogTimer, unknown_exception) #endif /* Data TLB Error Interrupt */ @@ -696,21 +696,21 @@ interrupt_base: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x2010, KernelSPE) #else - EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2020, SPEUnavailable, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_SPE */ /* SPE Floating Point Data */ #ifdef CONFIG_SPE EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE); #else - EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE) #endif /* CONFIG_SPE */ /* SPE Floating Point Round */ - EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE) + EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception, EXC_XFER_EE) /* Performance Monitor */ - EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD) + EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) /* Debug Interrupt */ diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 1545621d44d2..7872c6c45732 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -53,10 +53,10 @@ extern void transfer_to_handler(void); extern void do_IRQ(struct pt_regs *regs); -extern void MachineCheckException(struct pt_regs *regs); -extern void AlignmentException(struct pt_regs *regs); -extern void ProgramCheckException(struct pt_regs *regs); -extern void SingleStepException(struct pt_regs *regs); +extern void machine_check_exception(struct pt_regs *regs); +extern void alignment_exception(struct pt_regs *regs); +extern void program_check_exception(struct pt_regs *regs); +extern void single_step_exception(struct pt_regs *regs); extern int do_signal(sigset_t *, struct pt_regs *); extern int pmac_newworld; extern int sys_sigreturn(struct pt_regs *regs); @@ -72,10 +72,10 @@ EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); -EXPORT_SYMBOL(MachineCheckException); -EXPORT_SYMBOL(AlignmentException); -EXPORT_SYMBOL(ProgramCheckException); -EXPORT_SYMBOL(SingleStepException); +EXPORT_SYMBOL(machine_check_exception); +EXPORT_SYMBOL(alignment_exception); +EXPORT_SYMBOL(program_check_exception); +EXPORT_SYMBOL(single_step_exception); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(ppc_lost_interrupts); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 82e4d70e6dbb..26606aa33de6 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -74,7 +74,7 @@ void (*debugger_fault_handler)(struct pt_regs *regs); DEFINE_SPINLOCK(die_lock); -void die(const char * str, struct pt_regs * fp, long err) +int die(const char * str, struct pt_regs * fp, long err) { static int die_counter; int nl = 0; @@ -232,7 +232,7 @@ platform_machine_check(struct pt_regs *regs) { } -void MachineCheckException(struct pt_regs *regs) +void machine_check_exception(struct pt_regs *regs) { unsigned long reason = get_mc_reason(regs); @@ -393,14 +393,14 @@ void SMIException(struct pt_regs *regs) #endif } -void UnknownException(struct pt_regs *regs) +void unknown_exception(struct pt_regs *regs) { printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n", regs->nip, regs->msr, regs->trap, print_tainted()); _exception(SIGTRAP, regs, 0, 0); } -void InstructionBreakpoint(struct pt_regs *regs) +void instruction_breakpoint_exception(struct pt_regs *regs) { if (debugger_iabr_match(regs)) return; @@ -622,7 +622,7 @@ int check_bug_trap(struct pt_regs *regs) return 0; } -void ProgramCheckException(struct pt_regs *regs) +void program_check_exception(struct pt_regs *regs) { unsigned int reason = get_reason(regs); extern int do_mathemu(struct pt_regs *regs); @@ -701,7 +701,7 @@ void ProgramCheckException(struct pt_regs *regs) _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } -void SingleStepException(struct pt_regs *regs) +void single_step_exception(struct pt_regs *regs) { regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ if (debugger_sstep(regs)) @@ -709,7 +709,7 @@ void SingleStepException(struct pt_regs *regs) _exception(SIGTRAP, regs, TRAP_TRACE, 0); } -void AlignmentException(struct pt_regs *regs) +void alignment_exception(struct pt_regs *regs) { int fixed; @@ -814,7 +814,7 @@ void TAUException(struct pt_regs *regs) } #endif /* CONFIG_INT_TAU */ -void AltivecUnavailException(struct pt_regs *regs) +void altivec_unavailable_exception(struct pt_regs *regs) { static int kernel_altivec_count; @@ -835,7 +835,7 @@ void AltivecUnavailException(struct pt_regs *regs) } #ifdef CONFIG_ALTIVEC -void AltivecAssistException(struct pt_regs *regs) +void altivec_assist_exception(struct pt_regs *regs) { int err; @@ -872,7 +872,7 @@ void AltivecAssistException(struct pt_regs *regs) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_E500 -void PerformanceMonitorException(struct pt_regs *regs) +void performance_monitor_exception(struct pt_regs *regs) { perf_irq(regs); } diff --git a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c index 7612e0623f99..95e11f93c15d 100644 --- a/arch/ppc/syslib/ibm44x_common.c +++ b/arch/ppc/syslib/ibm44x_common.c @@ -178,7 +178,7 @@ void __init ibm44x_platform_init(void) #endif } -/* Called from MachineCheckException */ +/* Called from machine_check_exception */ void platform_machine_check(struct pt_regs *regs) { printk("PLB0: BEAR=0x%08x%08x ACR= 0x%08x BESR= 0x%08x\n", diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c index b843c4fef25e..def724b6e1c9 100644 --- a/arch/ppc/syslib/ppc4xx_setup.c +++ b/arch/ppc/syslib/ppc4xx_setup.c @@ -279,7 +279,7 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */ } -/* Called from MachineCheckException */ +/* Called from machine_check_exception */ void platform_machine_check(struct pt_regs *regs) { #if defined(DCRN_PLB0_BEAR) diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 16e34de34178..9457fe63d125 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -2,6 +2,8 @@ # Makefile for the linux ppc64 kernel. # +ifneq ($(CONFIG_PPC_MERGE),y) + EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds @@ -77,3 +79,9 @@ endif # These are here while we do the architecture merge vecemu-y += ../../powerpc/kernel/vecemu.o vector-y += ../../powerpc/kernel/vector.o +idle_power4-y += ../../powerpc/kernel/idle_power4.o +traps-y += ../../powerpc/kernel/traps.o + +else + +endif diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c deleted file mode 100644 index a728c9f0b53f..000000000000 --- a/arch/ppc64/kernel/traps.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * linux/arch/ppc64/kernel/traps.c - * - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * 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. - * - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au) - */ - -/* - * This file handles the architecture-dependent parts of hardware exceptions - */ - -#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 - -#ifdef CONFIG_DEBUGGER -int (*__debugger)(struct pt_regs *regs); -int (*__debugger_ipi)(struct pt_regs *regs); -int (*__debugger_bpt)(struct pt_regs *regs); -int (*__debugger_sstep)(struct pt_regs *regs); -int (*__debugger_iabr_match)(struct pt_regs *regs); -int (*__debugger_dabr_match)(struct pt_regs *regs); -int (*__debugger_fault_handler)(struct pt_regs *regs); - -EXPORT_SYMBOL(__debugger); -EXPORT_SYMBOL(__debugger_ipi); -EXPORT_SYMBOL(__debugger_bpt); -EXPORT_SYMBOL(__debugger_sstep); -EXPORT_SYMBOL(__debugger_iabr_match); -EXPORT_SYMBOL(__debugger_dabr_match); -EXPORT_SYMBOL(__debugger_fault_handler); -#endif - -struct notifier_block *powerpc_die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); - -int register_die_notifier(struct notifier_block *nb) -{ - int err = 0; - unsigned long flags; - - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&powerpc_die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; -} - -/* - * Trap & Exception support - */ - -static DEFINE_SPINLOCK(die_lock); - -int die(const char *str, struct pt_regs *regs, long err) -{ - static int die_counter; - int nl = 0; - - if (debugger(regs)) - return 1; - - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); - nl = 1; -#endif -#ifdef CONFIG_SMP - printk("SMP NR_CPUS=%d ", NR_CPUS); - nl = 1; -#endif -#ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC "); - nl = 1; -#endif -#ifdef CONFIG_NUMA - printk("NUMA "); - nl = 1; -#endif - switch(systemcfg->platform) { - case PLATFORM_PSERIES: - printk("PSERIES "); - nl = 1; - break; - case PLATFORM_PSERIES_LPAR: - printk("PSERIES LPAR "); - nl = 1; - break; - case PLATFORM_ISERIES_LPAR: - printk("ISERIES LPAR "); - nl = 1; - break; - case PLATFORM_POWERMAC: - printk("POWERMAC "); - nl = 1; - break; - case PLATFORM_BPA: - printk("BPA "); - nl = 1; - break; - } - if (nl) - printk("\n"); - print_modules(); - show_regs(regs); - bust_spinlocks(0); - spin_unlock_irq(&die_lock); - - if (in_interrupt()) - panic("Fatal exception in interrupt"); - - if (panic_on_oops) { - printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); - ssleep(5); - panic("Fatal exception"); - } - do_exit(SIGSEGV); - - return 0; -} - -void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) -{ - siginfo_t info; - - if (!user_mode(regs)) { - if (die("Exception in kernel mode", regs, signr)) - return; - } - - memset(&info, 0, sizeof(info)); - info.si_signo = signr; - info.si_code = code; - info.si_addr = (void __user *) addr; - force_sig_info(signr, &info, current); -} - -void system_reset_exception(struct pt_regs *regs) -{ - /* See if any machine dependent calls */ - if (ppc_md.system_reset_exception) - ppc_md.system_reset_exception(regs); - - die("System Reset", regs, 0); - - /* Must die if the interrupt is not recoverable */ - if (!(regs->msr & MSR_RI)) - panic("Unrecoverable System Reset"); - - /* What should we do here? We could issue a shutdown or hard reset. */ -} - -void machine_check_exception(struct pt_regs *regs) -{ - int recover = 0; - - /* See if any machine dependent calls */ - if (ppc_md.machine_check_exception) - recover = ppc_md.machine_check_exception(regs); - - if (recover) - return; - - if (debugger_fault_handler(regs)) - return; - die("Machine check", regs, 0); - - /* Must die if the interrupt is not recoverable */ - if (!(regs->msr & MSR_RI)) - panic("Unrecoverable Machine check"); -} - -void unknown_exception(struct pt_regs *regs) -{ - printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", - regs->nip, regs->msr, regs->trap); - - _exception(SIGTRAP, regs, 0, 0); -} - -void instruction_breakpoint_exception(struct pt_regs *regs) -{ - if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_iabr_match(regs)) - return; - _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); -} - -void __kprobes single_step_exception(struct pt_regs *regs) -{ - regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ - - if (notify_die(DIE_SSTEP, "single_step", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_sstep(regs)) - return; - - _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); -} - -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static inline void emulate_single_step(struct pt_regs *regs) -{ - if (regs->msr & MSR_SE) - single_step_exception(regs); -} - -static void parse_fpe(struct pt_regs *regs) -{ - int code = 0; - unsigned long fpscr; - - flush_fp_to_thread(current); - - fpscr = current->thread.fpscr; - - /* Invalid operation */ - if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) - code = FPE_FLTINV; - - /* Overflow */ - else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) - code = FPE_FLTOVF; - - /* Underflow */ - else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) - code = FPE_FLTUND; - - /* Divide by zero */ - else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) - code = FPE_FLTDIV; - - /* Inexact result */ - else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) - code = FPE_FLTRES; - - _exception(SIGFPE, regs, code, regs->nip); -} - -/* - * Illegal instruction emulation support. Return non-zero if we can't - * emulate, or -EFAULT if the associated memory access caused an access - * fault. Return zero on success. - */ - -#define INST_MFSPR_PVR 0x7c1f42a6 -#define INST_MFSPR_PVR_MASK 0xfc1fffff - -#define INST_DCBA 0x7c0005ec -#define INST_DCBA_MASK 0x7c0007fe - -#define INST_MCRXR 0x7c000400 -#define INST_MCRXR_MASK 0x7c0007fe - -static int emulate_instruction(struct pt_regs *regs) -{ - unsigned int instword; - - if (!user_mode(regs)) - return -EINVAL; - - CHECK_FULL_REGS(regs); - - if (get_user(instword, (unsigned int __user *)(regs->nip))) - return -EFAULT; - - /* Emulate the mfspr rD, PVR. */ - if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { - unsigned int rd; - - rd = (instword >> 21) & 0x1f; - regs->gpr[rd] = mfspr(SPRN_PVR); - return 0; - } - - /* Emulating the dcba insn is just a no-op. */ - if ((instword & INST_DCBA_MASK) == INST_DCBA) { - static int warned; - - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'dcba' insn\n", - current->pid, current->comm); - warned = 1; - } - return 0; - } - - /* Emulate the mcrxr insn. */ - if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { - static int warned; - unsigned int shift; - - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'mcrxr' insn\n", - current->pid, current->comm); - warned = 1; - } - - shift = (instword >> 21) & 0x1c; - regs->ccr &= ~(0xf0000000 >> shift); - regs->ccr |= (regs->xer & 0xf0000000) >> shift; - regs->xer &= ~0xf0000000; - return 0; - } - - return -EINVAL; -} - -/* - * Look through the list of trap instructions that are used for BUG(), - * BUG_ON() and WARN_ON() and see if we hit one. At this point we know - * that the exception was caused by a trap instruction of some kind. - * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 - * otherwise. - */ -extern struct bug_entry __start___bug_table[], __stop___bug_table[]; - -#ifndef CONFIG_MODULES -#define module_find_bug(x) NULL -#endif - -struct bug_entry *find_bug(unsigned long bugaddr) -{ - struct bug_entry *bug; - - for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) - if (bugaddr == bug->bug_addr) - return bug; - return module_find_bug(bugaddr); -} - -static int -check_bug_trap(struct pt_regs *regs) -{ - struct bug_entry *bug; - unsigned long addr; - - if (regs->msr & MSR_PR) - return 0; /* not in kernel */ - addr = regs->nip; /* address of trap instruction */ - if (addr < PAGE_OFFSET) - return 0; - bug = find_bug(regs->nip); - if (bug == NULL) - return 0; - if (bug->line & BUG_WARNING_TRAP) { - /* this is a WARN_ON rather than BUG/BUG_ON */ - printk(KERN_ERR "Badness in %s at %s:%d\n", - bug->function, bug->file, - bug->line & ~BUG_WARNING_TRAP); - show_stack(current, (void *)regs->gpr[1]); - return 1; - } - printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", - bug->function, bug->file, bug->line); - return 0; -} - -void __kprobes program_check_exception(struct pt_regs *regs) -{ - if (debugger_fault_handler(regs)) - return; - - if (regs->msr & 0x100000) { - /* IEEE FP exception */ - parse_fpe(regs); - } else if (regs->msr & 0x20000) { - /* trap exception */ - - if (notify_die(DIE_BPT, "breakpoint", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_bpt(regs)) - return; - - if (check_bug_trap(regs)) { - regs->nip += 4; - return; - } - _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); - - } else { - /* Privileged or illegal instruction; try to emulate it. */ - switch (emulate_instruction(regs)) { - case 0: - regs->nip += 4; - emulate_single_step(regs); - break; - - case -EFAULT: - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); - break; - - default: - if (regs->msr & 0x40000) - /* priveleged */ - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - else - /* illegal */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - break; - } - } -} - -void kernel_fp_unavailable_exception(struct pt_regs *regs) -{ - printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " - "%lx at %lx\n", regs->trap, regs->nip); - die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); -} - -void altivec_unavailable_exception(struct pt_regs *regs) -{ - if (user_mode(regs)) { - /* A user program has executed an altivec instruction, - but this kernel doesn't support altivec. */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return; - } - printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " - "%lx at %lx\n", regs->trap, regs->nip); - die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); -} - -extern perf_irq_t perf_irq; - -void performance_monitor_exception(struct pt_regs *regs) -{ - perf_irq(regs); -} - -void alignment_exception(struct pt_regs *regs) -{ - int fixed; - - fixed = fix_alignment(regs); - - if (fixed == 1) { - regs->nip += 4; /* skip over emulated instruction */ - emulate_single_step(regs); - return; - } - - /* Operand address was bad */ - if (fixed == -EFAULT) { - if (user_mode(regs)) { - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->dar); - } else { - /* Search exception table */ - bad_page_fault(regs, regs->dar, SIGSEGV); - } - - return; - } - - _exception(SIGBUS, regs, BUS_ADRALN, regs->nip); -} - -#ifdef CONFIG_ALTIVEC -void altivec_assist_exception(struct pt_regs *regs) -{ - int err; - siginfo_t info; - - if (!user_mode(regs)) { - printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" - " at %lx\n", regs->nip); - die("Kernel VMX/Altivec assist exception", regs, SIGILL); - } - - flush_altivec_to_thread(current); - - err = emulate_altivec(regs); - if (err == 0) { - regs->nip += 4; /* skip emulated instruction */ - emulate_single_step(regs); - return; - } - - if (err == -EFAULT) { - /* got an error reading the instruction */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *) regs->nip; - force_sig_info(SIGSEGV, &info, current); - } else { - /* didn't recognize the instruction */ - /* XXX quick hack for now: set the non-Java bit in the VSCR */ - if (printk_ratelimit()) - printk(KERN_ERR "Unrecognized altivec instruction " - "in %s at %lx\n", current->comm, regs->nip); - current->thread.vscr.u[3] |= 0x10000; - } -} -#endif /* CONFIG_ALTIVEC */ - -/* - * We enter here if we get an unrecoverable exception, that is, one - * that happened at a point where the RI (recoverable interrupt) bit - * in the MSR is 0. This indicates that SRR0/1 are live, and that - * we therefore lost state by taking this exception. - */ -void unrecoverable_exception(struct pt_regs *regs) -{ - printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n", - regs->trap, regs->nip); - die("Unrecoverable exception", regs, SIGABRT); -} - -/* - * We enter here if we discover during exception entry that we are - * running in supervisor mode with a userspace value in the stack pointer. - */ -void kernel_bad_stack(struct pt_regs *regs) -{ - printk(KERN_EMERG "Bad kernel stack pointer %lx at %lx\n", - regs->gpr[1], regs->nip); - die("Bad kernel stack pointer", regs, SIGABRT); -} - -void __init trap_init(void) -{ -} diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index d754ab570fe0..6a49b138c218 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -87,7 +87,7 @@ extern void cacheable_memzero(void *p, unsigned int nb); extern void *cacheable_memcpy(void *, const void *, unsigned int); extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); extern void bad_page_fault(struct pt_regs *, unsigned long, int); -extern void die(const char *, struct pt_regs *, long); +extern int die(const char *, struct pt_regs *, long); extern void _exception(int, struct pt_regs *, int, unsigned long); #ifdef CONFIG_BOOKE_WDT extern u32 booke_wdt_enabled; From bd142b70a6bd5522f7d95f0cec06091b93bb0715 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 30 Sep 2005 13:51:25 +1000 Subject: [PATCH 0245/1939] ppc64: simplify the build a little Signed-off-by: Stephen Rothwell --- arch/powerpc/Makefile | 1 - arch/powerpc/kernel/Makefile | 11 +++++++++-- arch/ppc64/Makefile | 2 +- arch/ppc64/kernel/Makefile | 11 ++--------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 92751ca6f8b1..9f80deb05ecc 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -121,7 +121,6 @@ head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o ifeq ($(CONFIG_PPC32),y) head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o -head-$(CONFIG_POWER4) += arch/powerpc/kernel/idle_power4.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o endif diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 58c130b10ec8..b5eff3ef2f3d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -2,6 +2,10 @@ # Makefile for the linux kernel. # +ifeq ($(CONFIG_PPC64),y) +EXTRA_CFLAGS += -mno-minimal-toc +endif + extra-$(CONFIG_PPC_STD_MMU) := head.o extra_$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_4xx.o @@ -9,10 +13,13 @@ extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o -extra-$(CONFIG_POWER4) += idle_power4.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds -obj-y := semaphore.o traps.o process.o +obj-y := traps.o +obj-$(CONFIG_PPC32) += semaphore.o process.o +obj-$(CONFIG_PPC64) += idle_power4.o +ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_MODULES) += ppc_ksyms.o +endif obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index d4eb55f82f03..fa889204d6ae 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -82,7 +82,7 @@ CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/ppc64/kernel/head.o libs-y += arch/ppc64/lib/ -core-y += arch/ppc64/kernel/ +core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ core-y += arch/ppc64/mm/ core-y += arch/powerpc/platforms/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 9457fe63d125..90a1519342da 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -7,12 +7,12 @@ ifneq ($(CONFIG_PPC_MERGE),y) EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds -obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ +obj-y := setup.o entry.o irq.o idle.o dma.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ align.o semaphore.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ - lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ + lmb.o cputable.o cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o prom.o obj-y += vdso32/ vdso64/ @@ -66,7 +66,6 @@ obj-$(CONFIG_PPC_BPA) += pSeries_smp.o obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o endif -obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ @@ -76,12 +75,6 @@ arch/ppc64/kernel/head.o: arch/powerpc/platforms/iseries/lparmap.s AFLAGS_head.o += -Iarch/powerpc/platforms/iseries endif -# These are here while we do the architecture merge -vecemu-y += ../../powerpc/kernel/vecemu.o -vector-y += ../../powerpc/kernel/vector.o -idle_power4-y += ../../powerpc/kernel/idle_power4.o -traps-y += ../../powerpc/kernel/traps.o - else endif From cabb558714945e92000f627dda562aa5e86a31af Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 30 Sep 2005 16:16:52 +1000 Subject: [PATCH 0246/1939] powerpc: make iSeries build Merge vmlinux.lds.S. Also remove arch/powerpc/kernel/vmlinux.lds which is a generated file. Signed-off-by: Stephen Rothwell --- arch/powerpc/Kconfig | 6 + arch/powerpc/Makefile | 27 +-- arch/powerpc/kernel/Makefile | 9 +- arch/powerpc/kernel/vmlinux.lds | 174 ------------------- arch/powerpc/kernel/vmlinux.lds.S | 196 ++++++++++++++++++++-- arch/powerpc/platforms/iseries/lpevents.c | 2 + arch/ppc64/kernel/Makefile | 8 +- include/asm-powerpc/system.h | 4 +- 8 files changed, 217 insertions(+), 209 deletions(-) delete mode 100644 arch/powerpc/kernel/vmlinux.lds diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 953a74be57b6..7f891ebfbd85 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -833,6 +833,12 @@ config PIN_TLB depends on ADVANCED_OPTIONS && 8xx endmenu +if PPC64 +config KERNEL_START + hex + default "0xc0000000" +endif + source "net/Kconfig" source "drivers/Kconfig" diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 9f80deb05ecc..eb1224c24e3e 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -124,12 +124,14 @@ head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o endif -core-y += arch/powerpc/kernel/ \ - arch/$(OLDARCH)/kernel/ \ - arch/powerpc/mm/ \ - arch/powerpc/lib/ \ - arch/powerpc/sysdev/ \ - arch/powerpc/platforms/ +core-y += arch/powerpc/kernel/ +core-y += arch/$(OLDARCH)/kernel/ +core-$(CONFIG_PPC32) += arch/powerpc/mm/ +core-$(CONFIG_PPC64) += arch/$(OLDARCH)/mm/ +core-$(CONFIG_PPC32) += arch/powerpc/lib/ +libs-$(CONFIG_PPC64) += arch/$(OLDARCH)/lib/ +core-y += arch/powerpc/sysdev/ +core-y += arch/powerpc/platforms/ core-$(CONFIG_PPC32) += arch/ppc/syslib/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ @@ -140,17 +142,20 @@ drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ -BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm - -.PHONY: $(BOOT_TARGETS) - -all: uImage zImage +defaultimage-$(CONFIG_PPC32) := uImage zImage +defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux +KBUILD_IMAGE := $(defaultimage-y) +all: $(KBUILD_IMAGE) CPPFLAGS_vmlinux.lds := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm + +.PHONY: $(BOOT_TARGETS) + boot := arch/$(OLDARCH)/boot $(BOOT_TARGETS): vmlinux diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b5eff3ef2f3d..be3f9d123a6d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -6,8 +6,10 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif +ifeq ($(CONFIG_PPC32),y) extra-$(CONFIG_PPC_STD_MMU) := head.o -extra_$(CONFIG_PPC64) := head_64.o +endif +extra-$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o @@ -23,3 +25,8 @@ ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_MODULES) += ppc_ksyms.o endif obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o + +ifeq ($(CONFIG_PPC_ISERIES),y) +arch/powerpc/kernel/head_64.o: arch/powerpc/platforms/iseries/lparmap.s +AFLAGS_head_64.o += -Iarch/powerpc/platforms/iseries +endif diff --git a/arch/powerpc/kernel/vmlinux.lds b/arch/powerpc/kernel/vmlinux.lds deleted file mode 100644 index d62c288a81d0..000000000000 --- a/arch/powerpc/kernel/vmlinux.lds +++ /dev/null @@ -1,174 +0,0 @@ -/* Align . to a 8 byte boundary equals to maximum function alignment. */ -/* sched.text is aling to function alignment to secure we have same - * address even at second ld pass when generating System.map */ -/* spinlock.text is aling to function alignment to secure we have same - * address even at second ld pass when generating System.map */ - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to - the beginning of the section so we begin them at 0. */ - /* Stabs debugging sections. */ -OUTPUT_ARCH(powerpc:common) -jiffies = jiffies_64 + 4; -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } -/* .init : { *(.init) } =0*/ - .plt : { *(.plt) } - .text : - { - *(.text) - . = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .; - . = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .; - *(.fixup) - *(.got1) - __got2_start = .; - *(.got2) - __got2_end = .; - } - _etext = .; - PROVIDE (etext = .); - .rodata : AT(ADDR(.rodata) - 0) { *(.rodata) *(.rodata.*) *(__vermagic) } .rodata1 : AT(ADDR(.rodata1) - 0) { *(.rodata1) } .pci_fixup : AT(ADDR(.pci_fixup) - 0) { __start_pci_fixups_early = .; *(.pci_fixup_early) __end_pci_fixups_early = .; __start_pci_fixups_header = .; *(.pci_fixup_header) __end_pci_fixups_header = .; __start_pci_fixups_final = .; *(.pci_fixup_final) __end_pci_fixups_final = .; __start_pci_fixups_enable = .; *(.pci_fixup_enable) __end_pci_fixups_enable = .; } __ksymtab : AT(ADDR(__ksymtab) - 0) { __start___ksymtab = .; *(__ksymtab) __stop___ksymtab = .; } __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - 0) { __start___ksymtab_gpl = .; *(__ksymtab_gpl) __stop___ksymtab_gpl = .; } __kcrctab : AT(ADDR(__kcrctab) - 0) { __start___kcrctab = .; *(__kcrctab) __stop___kcrctab = .; } __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - 0) { __start___kcrctab_gpl = .; *(__kcrctab_gpl) __stop___kcrctab_gpl = .; } __ksymtab_strings : AT(ADDR(__ksymtab_strings) - 0) { *(__ksymtab_strings) } __param : AT(ADDR(__param) - 0) { __start___param = .; *(__param) __stop___param = .; } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - .fixup : { *(.fixup) } - __ex_table : { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } - __bug_table : { - __start___bug_table = .; - *(__bug_table) - __stop___bug_table = .; - } - /* Read-write section, merged into data segment: */ - . = ALIGN(4096); - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - _edata = .; - PROVIDE (edata = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - - . = ALIGN(4096); - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } - /* .exit.text is discarded at runtime, not link time, - to deal with references from __bug_table */ - .exit.text : { *(.exit.text) } - .init.data : { - *(.init.data); - __vtop_table_begin = .; - *(.vtop_fixup); - __vtop_table_end = .; - __ptov_table_begin = .; - *(.ptov_fixup); - __ptov_table_end = .; - } - . = ALIGN(16); - __setup_start = .; - .init.setup : { *(.init.setup) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { - *(.initcall1.init) - *(.initcall2.init) - *(.initcall3.init) - *(.initcall4.init) - *(.initcall5.init) - *(.initcall6.init) - *(.initcall7.init) - } - __initcall_end = .; - - __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } - __con_initcall_end = .; - - .security_initcall.init : AT(ADDR(.security_initcall.init) - 0) { __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; } - - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; - - . = ALIGN(32); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; - - . = ALIGN(4096); - __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } - __initramfs_end = .; - - . = ALIGN(4096); - __init_end = .; - - . = ALIGN(4096); - _sextratext = .; - _eextratext = .; - - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - __bss_stop = .; - - _end = . ; - PROVIDE (end = .); - - /* Sections to be discarded. */ - /DISCARD/ : { - *(.exitcall.exit) - *(.exit.data) - } -} diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 09c6525cfa61..0587d9c4609d 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -1,10 +1,29 @@ +#include +#ifdef CONFIG_PPC64 +#include +#endif #include +#ifdef CONFIG_PPC64 +OUTPUT_ARCH(powerpc:common64) +jiffies = jiffies_64; +#else OUTPUT_ARCH(powerpc:common) jiffies = jiffies_64 + 4; +#endif SECTIONS { + /* Sections to be discarded. */ + /DISCARD/ : { + *(.exitcall.exit) +#ifdef CONFIG_PPC32 + *(.exit.data) +#endif + } + + /* Read-only sections, merged into text segment: */ +#ifdef CONFIG_PPC32 . = + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } @@ -28,17 +47,30 @@ SECTIONS .rela.plt : { *(.rela.plt) } /* .init : { *(.init) } =0*/ .plt : { *(.plt) } - .text : - { +#endif + .text : { +#ifdef CONFIG_PPC64 + *(.text .text.*) +#else *(.text) +#endif SCHED_TEXT LOCK_TEXT +#ifdef CONFIG_PPC64 + KPROBES_TEXT +#endif *(.fixup) +#ifdef CONFIG_PPC32 *(.got1) __got2_start = .; *(.got2) __got2_end = .; +#else + . = ALIGN(PAGE_SIZE); + _etext = .; +#endif } +#ifdef CONFIG_PPC32 _etext = .; PROVIDE (etext = .); @@ -48,6 +80,7 @@ SECTIONS .dtors : { *(.dtors) } .fixup : { *(.fixup) } +#endif __ex_table : { __start___ex_table = .; @@ -61,6 +94,17 @@ SECTIONS __stop___bug_table = .; } +#ifdef CONFIG_PPC64 + __ftr_fixup : { + __start___ftr_fixup = .; + *(__ftr_fixup) + __stop___ftr_fixup = .; + } + + RODATA +#endif + +#ifdef CONFIG_PPC32 /* Read-write section, merged into data segment: */ . = ALIGN(4096); .data : @@ -90,16 +134,25 @@ SECTIONS .data.init_task : { *(.data.init_task) } . = ALIGN(4096); +#else + /* will be freed after init */ + . = ALIGN(PAGE_SIZE); +#endif __init_begin = .; .init.text : { _sinittext = .; *(.init.text) _einittext = .; } +#ifdef CONFIG_PPC32 /* .exit.text is discarded at runtime, not link time, to deal with references from __bug_table */ .exit.text : { *(.exit.text) } +#endif .init.data : { +#ifdef CONFIG_PPC64 + *(.init.data) +#else *(.init.data); __vtop_table_begin = .; *(.vtop_fixup); @@ -107,13 +160,31 @@ SECTIONS __ptov_table_begin = .; *(.ptov_fixup); __ptov_table_end = .; +#endif } + . = ALIGN(16); +#ifdef CONFIG_PPC32 __setup_start = .; - .init.setup : { *(.init.setup) } +#endif + .init.setup : { +#ifdef CONFIG_PPC64 + __setup_start = .; +#endif + *(.init.setup) +#ifdef CONFIG_PPC64 + __setup_end = .; +#endif + } +#ifdef CONFIG_PPC32 __setup_end = .; + __initcall_start = .; +#endif .initcall.init : { +#ifdef CONFIG_PPC64 + __initcall_start = .; +#endif *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) @@ -121,27 +192,109 @@ SECTIONS *(.initcall5.init) *(.initcall6.init) *(.initcall7.init) +#ifdef CONFIG_PPC64 + __initcall_end = .; +#endif } +#ifdef CONFIG_PPC32 __initcall_end = .; __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } +#endif + .con_initcall.init : { +#ifdef CONFIG_PPC64 + __con_initcall_start = .; +#endif + *(.con_initcall.init) +#ifdef CONFIG_PPC64 + __con_initcall_end = .; +#endif + } +#ifdef CONFIG_PPC32 __con_initcall_end = .; +#endif SECURITY_INIT +#ifdef CONFIG_PPC32 __start___ftr_fixup = .; __ftr_fixup : { *(__ftr_fixup) } __stop___ftr_fixup = .; +#else + . = ALIGN(PAGE_SIZE); + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif +#ifdef CONFIG_PPC32 . = ALIGN(32); __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } +#endif + .data.percpu : { +#ifdef CONFIG_PPC64 + __per_cpu_start = .; +#endif + *(.data.percpu) +#ifdef CONFIG_PPC64 + __per_cpu_end = .; +#endif + } +#ifdef CONFIG_PPC32 __per_cpu_end = .; +#endif +#ifdef CONFIG_PPC64 + . = ALIGN(PAGE_SIZE); + . = ALIGN(16384); + __init_end = .; + /* freed after init ends here */ + + + /* Read/write sections */ + . = ALIGN(PAGE_SIZE); + . = ALIGN(16384); + /* The initial task and kernel stack */ + .data.init_task : { + *(.data.init_task) + } + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : { + *(.data.page_aligned) + } + + .data.cacheline_aligned : { + *(.data.cacheline_aligned) + } + + .data : { + *(.data .data.rel* .toc1) + *(.branch_lt) + } + + .opd : { + *(.opd) + } + + .got : { + __toc_start = .; + *(.got) + *(.toc) + . = ALIGN(PAGE_SIZE); + _edata = .; + } + + + . = ALIGN(PAGE_SIZE); +#else . = ALIGN(4096); __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } + .init.ramfs : { + *(.init.ramfs) + } __initramfs_end = .; . = ALIGN(4096); @@ -152,21 +305,30 @@ SECTIONS _eextratext = .; __bss_start = .; - .bss : - { +#endif + .bss : { +#ifdef CONFIG_PPC64 + __bss_start = .; +#else *(.sbss) *(.scommon) *(.dynbss) +#endif *(.bss) +#ifdef CONFIG_PPC32 *(COMMON) - } +#else __bss_stop = .; - - _end = . ; - PROVIDE (end = .); - - /* Sections to be discarded. */ - /DISCARD/ : { - *(.exitcall.exit) - *(.exit.data) +#endif } +#ifdef CONFIG_PPC32 + __bss_stop = .; +#endif + +#ifdef CONFIG_PPC64 + . = ALIGN(PAGE_SIZE); +#endif + _end = . ; +#ifdef CONFIG_PPC32 + PROVIDE (end = .); +#endif } diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index 883603027ccf..f8b4155b0481 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -13,6 +13,8 @@ #include #include #include +#include + #include #include #include diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 90a1519342da..2fdcc4b63d40 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -2,10 +2,10 @@ # Makefile for the linux ppc64 kernel. # -ifneq ($(CONFIG_PPC_MERGE),y) - EXTRA_CFLAGS += -mno-minimal-toc +ifneq ($(CONFIG_PPC_MERGE),y) extra-y := head.o vmlinux.lds +endif obj-y := setup.o entry.o irq.o idle.o dma.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ @@ -70,11 +70,9 @@ obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ +ifneq ($(CONFIG_PPC_MERGE),y) ifeq ($(CONFIG_PPC_ISERIES),y) arch/ppc64/kernel/head.o: arch/powerpc/platforms/iseries/lparmap.s AFLAGS_head.o += -Iarch/powerpc/platforms/iseries endif - -else - endif diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 1b64879a02c3..027479dcbf43 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -118,10 +118,10 @@ extern void _set_L3CR(unsigned long); #endif extern void via_cuda_init(void); -extern void pmac_nvram_init(void); extern void read_rtc_time(void); extern void pmac_find_display(void); extern void giveup_fpu(struct task_struct *); +extern void disable_kernel_fp(void); extern void enable_kernel_fp(void); extern void flush_fp_to_thread(struct task_struct *); extern void enable_kernel_altivec(void); @@ -346,5 +346,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, #define arch_align_stack(x) (x) +extern unsigned long reloc_offset(void); + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYSTEM_H */ From eeb2d21806123a67d957783c4a0c8b020a378cf0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 30 Sep 2005 17:24:15 +1000 Subject: [PATCH 0247/1939] powerpc: make iSeries boot Now that we use the device tree, it helps to build it in. It helps to links the kernel at the correct address. Signed-off-by: Stephen Rothwell --- arch/powerpc/Kconfig | 4 ++-- arch/powerpc/Kconfig.debug | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 7f891ebfbd85..34be3247fca4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -317,7 +317,7 @@ config PPC_BPA config PPC_OF bool - depends on PPC_MULTIPLATFORM # for now + depends on PPC_MULTIPLATFORM || PPC_ISERIES default y config XICS @@ -836,7 +836,7 @@ endmenu if PPC64 config KERNEL_START hex - default "0xc0000000" + default "0xc000000000000000" endif source "net/Kconfig" diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 61653cb60c4e..19df881bf67b 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -55,7 +55,7 @@ config BDI_SWITCH config BOOTX_TEXT bool "Support for early boot text console (BootX or OpenFirmware only)" - depends PPC_OF + depends PPC_OF && !PPC_ISERIES help Say Y here to see progress messages from the boot firmware in text mode. Requires either BootX or Open Firmware. From 7c254d3dba0fae124b1d33f784ca23572ac386b0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 3 Oct 2005 09:50:40 -0500 Subject: [PATCH 0248/1939] This will move the ieee80211_is_ofdm_rate function to the ieee80211.h header, and I also added the ieee80211_is_cck_rate counterpart. Various drivers currently create there own version of these functions, but I guess the ieee80211 stack is the best place to provide such routines. Signed-off-by: Ivo van Doorn Signed-off-by: James Ketrenos --- include/net/ieee80211.h | 28 ++++++++++++++++++++++++++++ net/ieee80211/ieee80211_rx.c | 16 ---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 33b595ebef1f..58f62224e7ea 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -1045,6 +1045,34 @@ static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) } +static inline int ieee80211_is_ofdm_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_9MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_18MB: + case IEEE80211_OFDM_RATE_24MB: + case IEEE80211_OFDM_RATE_36MB: + case IEEE80211_OFDM_RATE_48MB: + case IEEE80211_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int ieee80211_is_cck_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + return 1; + } + return 0; +} + /* ieee80211.c */ extern void free_ieee80211(struct net_device *dev); extern struct net_device *alloc_ieee80211(int sizeof_priv); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index fcf05bf677b8..2f4b16c1c143 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1020,22 +1020,6 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee /***************************************************/ -static inline int ieee80211_is_ofdm_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_OFDM_RATE_6MB: - case IEEE80211_OFDM_RATE_9MB: - case IEEE80211_OFDM_RATE_12MB: - case IEEE80211_OFDM_RATE_18MB: - case IEEE80211_OFDM_RATE_24MB: - case IEEE80211_OFDM_RATE_36MB: - case IEEE80211_OFDM_RATE_48MB: - case IEEE80211_OFDM_RATE_54MB: - return 1; - } - return 0; -} - static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_network *network, From e846cbb11245e648983b50349a1c715202d5ccf0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Oct 2005 10:02:14 -0500 Subject: [PATCH 0249/1939] Fix implicit nocast warnings in ieee80211 code: net/ieee80211/ieee80211_tx.c:215:9: warning: implicit cast to nocast type Signed-off-by: Randy Dunlap Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 8d87897d7eb7..e860777ab8d3 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -187,7 +187,7 @@ void ieee80211_txb_free(struct ieee80211_txb *txb) } static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, - int gfp_mask) + unsigned int gfp_mask) { struct ieee80211_txb *txb; int i; From ff9e00f1b09d594004f91700a371870f729ffc02 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 3 Oct 2005 10:19:25 -0500 Subject: [PATCH 0250/1939] Currently the info_element is parsed by 2 seperate functions, this results in a lot of duplicate code. This will move the parsing stage into a seperate function. Signed-off-by: Ivo van Doorn Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_rx.c | 355 ++++++++++++++--------------------- 1 file changed, 143 insertions(+), 212 deletions(-) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 2f4b16c1c143..3bf04d6d2b13 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -917,38 +917,23 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element return rc; } -static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response - *frame, struct ieee80211_rx_stats *stats) +static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, + u16 length, struct ieee80211_network *network) { - struct ieee80211_network network_resp; - struct ieee80211_network *network = &network_resp; - struct ieee80211_info_element *info_element; - struct net_device *dev = ieee->dev; - u16 left; + u8 i; +#ifdef CONFIG_IEEE80211_DEBUG + char rates_str[64]; + char *p; +#endif - network->flags = 0; - network->qos_data.active = 0; - network->qos_data.supported = 0; - network->qos_data.param_count = 0; - network->qos_data.old_param_count = 0; - - //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); - network->atim_window = le16_to_cpu(frame->aid); - network->listen_interval = le16_to_cpu(frame->status); - - info_element = frame->info_element; - left = stats->len - sizeof(*frame); - - while (left >= sizeof(struct ieee80211_info_element)) { - if (sizeof(struct ieee80211_info_element) + - info_element->len > left) { - IEEE80211_DEBUG_QOS("ASSOC RESP: parse failed: " + while (length >= sizeof(*info_element)) { + if (sizeof(*info_element) + info_element->len > length) { + IEEE80211_DEBUG_MGMT("Info elem: parse failed: " "info_element->len + 2 > left : " "info_element->len+2=%zd left=%d, id=%d.\n", info_element->len + - sizeof(struct - ieee80211_info_element), - left, info_element->id); + sizeof(*info_element), + length, info_element->id); return 1; } @@ -968,50 +953,163 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee memset(network->ssid + network->ssid_len, 0, IW_ESSID_MAX_SIZE - network->ssid_len); - IEEE80211_DEBUG_QOS("MFIE_TYPE_SSID: '%s' len=%d.\n", + IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", network->ssid, network->ssid_len); break; + case MFIE_TYPE_RATES: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_len = min(info_element->len, + MAX_RATES_LENGTH); + for (i = 0; i < network->rates_len; i++) { + network->rates[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n", + rates_str, network->rates_len); + break; + + case MFIE_TYPE_RATES_EX: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_ex_len = min(info_element->len, + MAX_RATES_EX_LENGTH); + for (i = 0; i < network->rates_ex_len; i++) { + network->rates_ex[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n", + rates_str, network->rates_ex_len); + break; + + case MFIE_TYPE_DS_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n", + info_element->data[0]); + network->channel = info_element->data[0]; + break; + + case MFIE_TYPE_FH_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n"); + break; + + case MFIE_TYPE_CF_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n"); + break; + case MFIE_TYPE_TIM: - IEEE80211_DEBUG_QOS("MFIE_TYPE_TIM: ignored\n"); + IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: ignored\n"); + break; + + case MFIE_TYPE_ERP_INFO: + network->erp_value = info_element->data[0]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + network->erp_value); break; case MFIE_TYPE_IBSS_SET: - IEEE80211_DEBUG_QOS("MFIE_TYPE_IBSS_SET: ignored\n"); + network->atim_window = info_element->data[0]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n", + network->atim_window); break; case MFIE_TYPE_CHALLENGE: - IEEE80211_DEBUG_QOS("MFIE_TYPE_CHALLENGE: ignored\n"); + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n"); break; case MFIE_TYPE_GENERIC: - IEEE80211_DEBUG_QOS("MFIE_TYPE_GENERIC: %d bytes\n", - info_element->len); - ieee80211_parse_qos_info_param_IE(info_element, - network); + IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + if (!ieee80211_parse_qos_info_param_IE(info_element, + network)) + break; + + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x01) { + network->wpa_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->wpa_ie, info_element, + network->wpa_ie_len); + } break; case MFIE_TYPE_RSN: - IEEE80211_DEBUG_QOS("MFIE_TYPE_RSN: %d bytes\n", - info_element->len); + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + network->rsn_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->rsn_ie, info_element, + network->rsn_ie_len); break; case MFIE_TYPE_QOS_PARAMETER: - printk("QoS Error need to parse QOS_PARAMETER IE\n"); + printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n"); break; default: - IEEE80211_DEBUG_QOS("unsupported IE %d\n", + IEEE80211_DEBUG_MGMT("unsupported IE %d\n", info_element->id); break; } - left -= sizeof(struct ieee80211_info_element) + - info_element->len; - info_element = (struct ieee80211_info_element *) - &info_element->data[info_element->len]; + length -= sizeof(*info_element) + info_element->len; + info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len]; } + return 0; +} + +static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response + *frame, struct ieee80211_rx_stats *stats) +{ + struct ieee80211_network network_resp; + struct ieee80211_network *network = &network_resp; + struct net_device *dev = ieee->dev; + + network->flags = 0; + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; + + //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); + network->atim_window = le16_to_cpu(frame->aid); + network->listen_interval = le16_to_cpu(frame->status); + + if(ieee80211_parse_info_param(frame->info_element, stats->len - sizeof(*frame), network)) + return 1; + if (ieee->handle_assoc_response != NULL) ieee->handle_assoc_response(dev, frame, network); @@ -1025,13 +1123,6 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i struct ieee80211_network *network, struct ieee80211_rx_stats *stats) { -#ifdef CONFIG_IEEE80211_DEBUG - char rates_str[64]; - char *p; -#endif - struct ieee80211_info_element *info_element; - u16 left; - u8 i; network->qos_data.active = 0; network->qos_data.supported = 0; network->qos_data.param_count = 0; @@ -1062,168 +1153,8 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->wpa_ie_len = 0; network->rsn_ie_len = 0; - info_element = beacon->info_element; - left = stats->len - sizeof(*beacon); - while (left >= sizeof(*info_element)) { - if (sizeof(*info_element) + info_element->len > left) { - IEEE80211_DEBUG_SCAN - ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", - info_element->len + sizeof(*info_element), left); - return 1; - } - - switch (info_element->id) { - case MFIE_TYPE_SSID: - if (ieee80211_is_empty_essid(info_element->data, - info_element->len)) { - network->flags |= NETWORK_EMPTY_ESSID; - break; - } - - network->ssid_len = min(info_element->len, - (u8) IW_ESSID_MAX_SIZE); - memcpy(network->ssid, info_element->data, - network->ssid_len); - if (network->ssid_len < IW_ESSID_MAX_SIZE) - memset(network->ssid + network->ssid_len, 0, - IW_ESSID_MAX_SIZE - network->ssid_len); - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); - break; - - case MFIE_TYPE_RATES: -#ifdef CONFIG_IEEE80211_DEBUG - p = rates_str; -#endif - network->rates_len = min(info_element->len, - MAX_RATES_LENGTH); - for (i = 0; i < network->rates_len; i++) { - network->rates[i] = info_element->data[i]; -#ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - - (p - rates_str), "%02X ", - network->rates[i]); -#endif - if (ieee80211_is_ofdm_rate - (info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - } - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", - rates_str, network->rates_len); - break; - - case MFIE_TYPE_RATES_EX: -#ifdef CONFIG_IEEE80211_DEBUG - p = rates_str; -#endif - network->rates_ex_len = min(info_element->len, - MAX_RATES_EX_LENGTH); - for (i = 0; i < network->rates_ex_len; i++) { - network->rates_ex[i] = info_element->data[i]; -#ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - - (p - rates_str), "%02X ", - network->rates[i]); -#endif - if (ieee80211_is_ofdm_rate - (info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - } - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", - rates_str, network->rates_ex_len); - break; - - case MFIE_TYPE_DS_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", - info_element->data[0]); - if (stats->freq == IEEE80211_24GHZ_BAND) - network->channel = info_element->data[0]; - break; - - case MFIE_TYPE_FH_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); - break; - - case MFIE_TYPE_CF_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); - break; - - case MFIE_TYPE_TIM: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n"); - break; - - case MFIE_TYPE_ERP_INFO: - network->erp_value = info_element->data[0]; - IEEE80211_DEBUG_SCAN("MFIE_TYPE_ERP_SET: %d\n", - network->erp_value); - break; - - case MFIE_TYPE_IBSS_SET: - network->atim_window = info_element->data[0]; - IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: %d\n", - network->atim_window); - break; - - case MFIE_TYPE_CHALLENGE: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); - break; - - case MFIE_TYPE_GENERIC: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", - info_element->len); - if (!ieee80211_parse_qos_info_param_IE(info_element, - network)) - break; - - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { - network->wpa_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->wpa_ie, info_element, - network->wpa_ie_len); - } - break; - - case MFIE_TYPE_RSN: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", - info_element->len); - network->rsn_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->rsn_ie, info_element, - network->rsn_ie_len); - break; - - case MFIE_TYPE_QOS_PARAMETER: - printk(KERN_ERR - "QoS Error need to parse QOS_PARAMETER IE\n"); - break; - - default: - IEEE80211_DEBUG_SCAN("unsupported IE %d\n", - info_element->id); - break; - } - - left -= sizeof(*info_element) + info_element->len; - info_element = (struct ieee80211_info_element *) - &info_element->data[info_element->len]; - } + if(ieee80211_parse_info_param(beacon->info_element, stats->len - sizeof(*beacon), network)) + return 1; network->mode = 0; if (stats->freq == IEEE80211_52GHZ_BAND) From c1bda44a4aedf13251b2704e6e67afb4909195c8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 3 Oct 2005 10:20:47 -0500 Subject: [PATCH 0251/1939] When an assoc_resp is received the network structure is not completely initialized which can cause problems for drivers that expect the network structure to be completely filled in. This patch will make sure the network is filled in as much as possible. Signed-off-by: Ivo van Doorn Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_rx.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 3bf04d6d2b13..8d87d66c2a34 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1106,10 +1106,41 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); network->atim_window = le16_to_cpu(frame->aid); network->listen_interval = le16_to_cpu(frame->status); + memcpy(network->bssid, frame->header.addr3, ETH_ALEN); + network->capability = le16_to_cpu(frame->capability); + network->last_scanned = jiffies; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; + + if (stats->freq == IEEE80211_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; if(ieee80211_parse_info_param(frame->info_element, stats->len - sizeof(*frame), network)) return 1; + network->mode = 0; + if (stats->freq == IEEE80211_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) + network->flags |= NETWORK_EMPTY_ESSID; + + memcpy(&network->stats, stats, sizeof(network->stats)); + if (ieee->handle_assoc_response != NULL) ieee->handle_assoc_response(dev, frame, network); @@ -1126,6 +1157,7 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->qos_data.active = 0; network->qos_data.supported = 0; network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; /* Pull out fixed field data */ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); From ff0037b259e8b47843176142131844bc80fd2887 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Mon, 3 Oct 2005 10:23:42 -0500 Subject: [PATCH 0252/1939] Lindent and trailing whitespace script executed ieee80211 subsystem Signed-off-by: James Ketrenos --- include/net/ieee80211_crypt.h | 6 +++--- net/ieee80211/ieee80211_rx.c | 35 +++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 0c9d859d912e..0a1c2d82ca4b 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -26,7 +26,7 @@ #include enum { - IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1<<0), + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), }; struct ieee80211_crypto_ops { @@ -65,8 +65,8 @@ struct ieee80211_crypto_ops { char *(*print_stats) (char *p, void *priv); /* Crypto specific flag get/set for configuration settings */ - unsigned long (*get_flags)(void *priv); - unsigned long (*set_flags)(unsigned long flags, void *priv); + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 8d87d66c2a34..6b005cb0caa0 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -917,8 +917,9 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element return rc; } -static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, - u16 length, struct ieee80211_network *network) +static int ieee80211_parse_info_param(struct ieee80211_info_element + *info_element, u16 length, + struct ieee80211_network *network) { u8 i; #ifdef CONFIG_IEEE80211_DEBUG @@ -929,11 +930,11 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen while (length >= sizeof(*info_element)) { if (sizeof(*info_element) + info_element->len > length) { IEEE80211_DEBUG_MGMT("Info elem: parse failed: " - "info_element->len + 2 > left : " - "info_element->len+2=%zd left=%d, id=%d.\n", - info_element->len + - sizeof(*info_element), - length, info_element->id); + "info_element->len + 2 > left : " + "info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(*info_element), + length, info_element->id); return 1; } @@ -954,7 +955,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen IW_ESSID_MAX_SIZE - network->ssid_len); IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); + network->ssid, network->ssid_len); break; case MFIE_TYPE_RATES: @@ -1074,17 +1075,20 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen break; case MFIE_TYPE_QOS_PARAMETER: - printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n"); + printk(KERN_ERR + "QoS Error need to parse QOS_PARAMETER IE\n"); break; default: IEEE80211_DEBUG_MGMT("unsupported IE %d\n", - info_element->id); + info_element->id); break; } length -= sizeof(*info_element) + info_element->len; - info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len]; + info_element = + (struct ieee80211_info_element *)&info_element-> + data[info_element->len]; } return 0; @@ -1112,7 +1116,8 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->rates_len = network->rates_ex_len = 0; network->last_associate = 0; network->ssid_len = 0; - network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; + network->erp_value = + (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; if (stats->freq == IEEE80211_52GHZ_BAND) { /* for A band (No DS info) */ @@ -1123,7 +1128,8 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if(ieee80211_parse_info_param(frame->info_element, stats->len - sizeof(*frame), network)) + if (ieee80211_parse_info_param + (frame->info_element, stats->len - sizeof(*frame), network)) return 1; network->mode = 0; @@ -1185,7 +1191,8 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if(ieee80211_parse_info_param(beacon->info_element, stats->len - sizeof(*beacon), network)) + if (ieee80211_parse_info_param + (beacon->info_element, stats->len - sizeof(*beacon), network)) return 1; network->mode = 0; From 644dd0cc494702ecd0698f467de113ace9593888 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 3 Oct 2005 15:55:19 -0400 Subject: [PATCH 0253/1939] [libata] improve device scan Replace SCSI's legacy "bang at the door" method of probing with one directly controlled by the underlying ATA transport layer. We now only call scsi_scan_target() for devices we find, rather than probing every possible channel/id within a certain range. --- drivers/scsi/libata-core.c | 2 +- drivers/scsi/libata-scsi.c | 12 ++++++++++++ drivers/scsi/libata.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e5b01997117a..902c76364af7 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4113,7 +4113,7 @@ int ata_device_add(struct ata_probe_ent *ent) for (i = 0; i < count; i++) { struct ata_port *ap = host_set->ports[i]; - scsi_scan_host(ap->host); + ata_scsi_scan_host(ap); } dev_set_drvdata(dev, host_set); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 104fd9a63e73..4fc0134d4272 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1678,3 +1678,15 @@ void ata_scsi_simulate(u16 *id, } } +void ata_scsi_scan_host(struct ata_port *ap) +{ + unsigned int i; + + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_present(&ap->device[i])) + scsi_scan_target(&ap->host->shost_gendev, 0, i, ~0, 0); +} + diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index d608b3a0f6fe..c7a1fa1c9abc 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -51,6 +51,7 @@ extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ +extern void ata_scsi_scan_host(struct ata_port *ap); extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, From ac17b8b57013a3e38d1958f66a218f15659e5752 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Mon, 3 Oct 2005 15:32:11 -0500 Subject: [PATCH 0254/1939] JFS: make special inodes play nicely with page balancing This patch fixes up a few problems with jfs's reserved inodes. 1. There is no need for the jfs code setting the I_DIRTY bits in i_state. I am ashamed that the code ever did this, and surprised it hasn't been noticed until now. 2. Make sure special inodes are on an inode hash list. If the inodes are unhashed, __mark_inode_dirty will fail to put the inode on the superblock's dirty list, and the data will not be flushed under memory pressure. 3. Force writing journal data to disk when metapage_writepage is unable to write a metadata page due to pending journal I/O. Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dmap.c | 1 - fs/jfs/jfs_imap.c | 10 ++++++++-- fs/jfs/jfs_metapage.c | 6 ++++++ fs/jfs/jfs_txnmgr.c | 2 -- fs/jfs/super.c | 1 + 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index eadf319bee22..51c02bf07878 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -305,7 +305,6 @@ int dbSync(struct inode *ipbmap) filemap_fdatawrite(ipbmap->i_mapping); filemap_fdatawait(ipbmap->i_mapping); - ipbmap->i_state |= I_DIRTY; diWriteSpecial(ipbmap, 0); return (0); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 4021d46da7e3..28201b194f53 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -56,6 +56,12 @@ #include "jfs_superblock.h" #include "jfs_debug.h" +/* + * __mark_inode_dirty expects inodes to be hashed. Since we don't want + * special inodes in the fileset inode space, we hash them to a dummy head + */ +static HLIST_HEAD(aggregate_hash); + /* * imap locks */ @@ -491,6 +497,8 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary) /* release the page */ release_metapage(mp); + hlist_add_head(&ip->i_hash, &aggregate_hash); + return (ip); } @@ -514,8 +522,6 @@ void diWriteSpecial(struct inode *ip, int secondary) ino_t inum = ip->i_ino; struct metapage *mp; - ip->i_state &= ~I_DIRTY; - if (secondary) address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage; else diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 13d7e3f1feb4..c81c6438fce5 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -395,6 +395,12 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) { redirty = 1; + /* + * Make sure this page isn't blocked indefinitely. + * If the journal isn't undergoing I/O, push it + */ + if (mp->log && !(mp->log->cflag & logGC_PAGEOUT)) + jfs_flush_journal(mp->log, 0); continue; } diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 9b71ed2674fe..b660c93c92de 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -2396,7 +2396,6 @@ static void txUpdateMap(struct tblock * tblk) */ if (tblk->xflag & COMMIT_CREATE) { diUpdatePMap(ipimap, tblk->ino, FALSE, tblk); - ipimap->i_state |= I_DIRTY; /* update persistent block allocation map * for the allocation of inode extent; */ @@ -2407,7 +2406,6 @@ static void txUpdateMap(struct tblock * tblk) } else if (tblk->xflag & COMMIT_DELETE) { ip = tblk->u.ip; diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk); - ipimap->i_state |= I_DIRTY; iput(ip); } } diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 71bc34b96b2b..4226af3ea91b 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -442,6 +442,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) inode->i_nlink = 1; inode->i_size = sb->s_bdev->bd_inode->i_size; inode->i_mapping->a_ops = &jfs_metapage_aops; + insert_inode_hash(inode); mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); sbi->direct_inode = inode; From 3f19ee8cb3a1003cb5183696bc55934f5865f868 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 3 Oct 2005 21:36:41 -0400 Subject: [PATCH 0255/1939] [libata] improve device scan even more Since our max_lun is unconditionally set to 1, we might as well hardcode a LUN 0 probe, rather than a wildcard LUN scan. The ide-scsi driver sets max_lun to a value greater than under certain conditions: if ((drive->id->last_lun & 0x7) != 7) host->max_lun = (drive->id->last_lun & 0x7) + 1; else host->max_lun = 1; last_lun is Word 126 of IDENTIFY PACKET DEVICE, marked as obsolete and undocumented in non-ancient specs. We'll leave it out for now. Should the need arise to support multi-LUN ATAPI devices, we'll probably want to add the above code. Finally, there have been reports of REPORT LUNS commands locking up ATAPI drives. Eliminating the wildcard LUN scan could help reduce the trouble from problematic drives. --- drivers/scsi/libata-scsi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 4fc0134d4272..8295a656e521 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1680,13 +1680,17 @@ void ata_scsi_simulate(u16 *id, void ata_scsi_scan_host(struct ata_port *ap) { + struct ata_device *dev; unsigned int i; if (ap->flags & ATA_FLAG_PORT_DISABLED) return; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) - scsi_scan_target(&ap->host->shost_gendev, 0, i, ~0, 0); + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ata_dev_present(dev)) + scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); + } } From bab76198b3111bd0328be3c1fa208237eb12f86e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 2 Oct 2005 17:18:58 -0700 Subject: [PATCH 0256/1939] [PATCH] hostap: Remove hw specific dev_open/close handlers Host AP driver used hardware model specific dev_open/close handlers that were called on dev_open/close if the hardware driver had registered the handler. These were only used for hostap_cs and only for tracking whether any of the netdevs were UP. This information is already available from local->num_dev_open, so there is not need for the special open/close handler. Let's get rid of these handlers. In addition to cleaning up the code, this fixes a module refcounting issue for hostap_cs where ejecting the card while any of the netdevs were open did not decrement refcount properly. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap.c | 6 --- drivers/net/wireless/hostap/hostap_cs.c | 45 +++++------------------ drivers/net/wireless/hostap/hostap_pci.c | 2 - drivers/net/wireless/hostap/hostap_plx.c | 2 - drivers/net/wireless/hostap/hostap_wlan.h | 2 - 5 files changed, 10 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c index e7f5821b4942..6a96cd9f2685 100644 --- a/drivers/net/wireless/hostap/hostap.c +++ b/drivers/net/wireless/hostap/hostap.c @@ -716,9 +716,6 @@ static int prism2_close(struct net_device *dev) hostap_deauth_all_stas(dev, local->ap, 1); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - if (local->func->dev_close && local->func->dev_close(local)) - return 0; - if (dev == local->dev) { local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); } @@ -766,9 +763,6 @@ static int prism2_open(struct net_device *dev) local->hw_downloading) return -ENODEV; - if (local->func->dev_open && local->func->dev_open(local)) - return 1; - if (!try_module_get(local->hw_module)) return -ENODEV; local->num_dev_open++; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index faa83badf0a1..23bcc51b7131 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -492,42 +492,10 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) } -static int prism2_pccard_dev_open(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - hw_priv->link->open++; - return 0; -} - - -static int prism2_pccard_dev_close(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv; - - if (local == NULL || local->hw_priv == NULL) - return 1; - hw_priv = local->hw_priv; - if (hw_priv->link == NULL) - return 1; - - if (!hw_priv->link->open) { - printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " - "link not open?!\n", local->dev->name); - return 1; - } - - hw_priv->link->open--; - - return 0; -} - - static struct prism2_helper_functions prism2_pccard_funcs = { .card_present = prism2_pccard_card_present, .cor_sreset = prism2_pccard_cor_sreset, - .dev_open = prism2_pccard_dev_open, - .dev_close = prism2_pccard_dev_close, .genesis_reset = prism2_pccard_genesis_reset, .hw_type = HOSTAP_HW_PCCARD, }; @@ -883,6 +851,13 @@ static int prism2_event(event_t event, int priority, { dev_link_t *link = args->client_data; struct net_device *dev = (struct net_device *) link->priv; + int dev_open = 0; + + if (link->state & DEV_CONFIG) { + struct hostap_interface *iface = netdev_priv(dev); + if (iface && iface->local) + dev_open = iface->local->num_dev_open > 0; + } switch (event) { case CS_EVENT_CARD_INSERTION: @@ -911,7 +886,7 @@ static int prism2_event(event_t event, int priority, case CS_EVENT_RESET_PHYSICAL: PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); if (link->state & DEV_CONFIG) { - if (link->open) { + if (dev_open) { netif_stop_queue(dev); netif_device_detach(dev); } @@ -931,8 +906,8 @@ static int prism2_event(event_t event, int priority, pcmcia_request_configuration(link->handle, &link->conf); prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, link->open ? 0 : 1); - if (link->open) { + prism2_hw_config(dev, dev_open ? 0 : 1); + if (dev_open) { netif_device_attach(dev); netif_start_queue(dev); } diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index b9254f73fbaf..594cc29c6175 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -277,8 +277,6 @@ static struct prism2_helper_functions prism2_pci_funcs = { .card_present = NULL, .cor_sreset = prism2_pci_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_pci_genesis_reset, .hw_type = HOSTAP_HW_PCI, }; diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 1abebdf48b20..85d3f8a29539 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -328,8 +328,6 @@ static struct prism2_helper_functions prism2_plx_funcs = { .card_present = NULL, .cor_sreset = prism2_plx_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_plx_genesis_reset, .hw_type = HOSTAP_HW_PLX, }; diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index cc061e1560d3..cfd801559492 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -552,8 +552,6 @@ struct prism2_helper_functions { * (hostap_{cs,plx,pci}.c */ int (*card_present)(local_info_t *local); void (*cor_sreset)(local_info_t *local); - int (*dev_open)(local_info_t *local); - int (*dev_close)(local_info_t *local); void (*genesis_reset)(local_info_t *local, int hcr); /* the following functions are from hostap_hw.c, but they may have some From f7a74447553d698795ba74b7e17e916000b0cb08 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 2 Oct 2005 17:18:59 -0700 Subject: [PATCH 0257/1939] [PATCH] hostap: Fix hostap_pci build with PRISM2_IO_DEBUG The debug version of I/O functions in hostap_pci had not survived the change to start using hw_priv pointer, so let's fix them to actually define the local hw_priv variable. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 594cc29c6175..0d7305dfa690 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -59,11 +59,13 @@ static struct pci_device_id prism2_pci_id_table[] __devinitdata = { static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); @@ -74,12 +76,14 @@ static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u8 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readb(hw_priv->mem_start + a); @@ -91,11 +95,13 @@ static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); @@ -106,12 +112,14 @@ static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u16 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readw(hw_priv->mem_start + a); From c355184cd3cd58c9ffc78f2a17e0ac3563312ea7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 2 Oct 2005 17:19:00 -0700 Subject: [PATCH 0258/1939] [PATCH] hostap: Do not free local->hw_priv before unregistering netdev local->hw_priv was being freed and set to NULL just before calling prism2_free_local_data(). However, this may expose a race condition in which something ends up trying to use hw_priv during shutdown. I haven't noticed this happening, but better be safe than sorry, so let's postpone hw_priv freeing to happen only after prism2_free_local_data() has returned. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_cs.c | 5 +++-- drivers/net/wireless/hostap/hostap_pci.c | 9 ++------- drivers/net/wireless/hostap/hostap_plx.c | 7 ++----- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 23bcc51b7131..2643976a6677 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -565,13 +565,14 @@ static void prism2_detach(dev_link_t *link) *linkp = link->next; /* release net devices */ if (link->priv) { + struct hostap_cs_priv *hw_priv; struct net_device *dev; struct hostap_interface *iface; dev = link->priv; iface = netdev_priv(dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; + hw_priv = iface->local->hw_priv; prism2_free_local_data(dev); + kfree(hw_priv); } kfree(link); } diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 0d7305dfa690..da0c80fb941c 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -358,8 +358,6 @@ static int prism2_pci_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (irq_registered && dev) free_irq(dev->irq, dev); @@ -370,10 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev, err_out_disable: pci_disable_device(pdev); - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); return -ENODEV; } @@ -398,9 +394,8 @@ static void prism2_pci_remove(struct pci_dev *pdev) free_irq(dev->irq, dev); mem_start = hw_priv->mem_start; - kfree(hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); iounmap(mem_start); diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 85d3f8a29539..78d67b408b2f 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -568,10 +568,8 @@ static int prism2_plx_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); if (irq_registered && dev) free_irq(dev->irq, dev); @@ -604,9 +602,8 @@ static void prism2_plx_remove(struct pci_dev *pdev) if (dev->irq) free_irq(dev->irq, dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); pci_disable_device(pdev); } From 7cb3cd090c2725b80561958a362c2ba15a7a8c86 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 2 Oct 2005 17:19:01 -0700 Subject: [PATCH 0259/1939] [PATCH] hostap: Unregister netdevs before freeing local data Unregister all netdevs before freeing local data. I was unable to trigger any crashes without this change when running busy loops for driver operations when ejecting a Prism2 PC Card. Anyway, should there be a race condition with this, better make it less likely to happen by unregistering the netdevs first. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_hw.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index e533a663deda..59fc15572395 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3322,6 +3322,18 @@ static void prism2_free_local_data(struct net_device *dev) iface = netdev_priv(dev); local = iface->local; + /* Unregister all netdevs before freeing local data. */ + list_for_each_safe(ptr, n, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type == HOSTAP_INTERFACE_MASTER) { + /* special handling for this interface below */ + continue; + } + hostap_remove_interface(iface->dev, 0, 1); + } + + unregister_netdev(local->dev); + flush_scheduled_work(); if (timer_pending(&local->crypt_deinit_timer)) @@ -3382,15 +3394,6 @@ static void prism2_free_local_data(struct net_device *dev) prism2_download_free_data(local->dl_sec); #endif /* PRISM2_DOWNLOAD_SUPPORT */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - prism2_clear_set_tim_queue(local); list_for_each_safe(ptr, n, &local->bss_list) { @@ -3403,7 +3406,6 @@ static void prism2_free_local_data(struct net_device *dev) kfree(local->last_scan_results); kfree(local->generic_elem); - unregister_netdev(local->dev); free_netdev(local->dev); } From 500f83abdc83d6bd472f3d103a9a9cd85df29a29 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 30 Sep 2005 10:19:19 +0200 Subject: [PATCH 0260/1939] [PATCH] s390: introducing support in qeth for new OSA CHPID type OSN This patch introduces new feature in qeth: qeth enhancement provides the device driver support for the Communication Controller for Linux on System z9 and zSeries (CCL), which is software that enables running the Network Control Program (NCP) on a zSeries machine. The OSA CDLC support is based on a new IBM mainframe CHPID type called Open Systems Adaper for NCP (OSN). In case of OSN qeth communicates with the type-OSN OSA-card on one hand, and with the CCL-kernel-component Network Device Handler (NDH) on the other. Signed-off-by: Frank Pavlic Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth.h | 45 +++- drivers/s390/net/qeth_fs.h | 12 +- drivers/s390/net/qeth_main.c | 419 ++++++++++++++++++++++++++--------- drivers/s390/net/qeth_mpc.c | 6 +- drivers/s390/net/qeth_mpc.h | 15 +- drivers/s390/net/qeth_sys.c | 28 ++- 6 files changed, 413 insertions(+), 112 deletions(-) diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 9963479ba89f..38a2441564d7 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -275,6 +275,10 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \ QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \ QETH_MAX_QUEUES,0x103}, \ + {0x1731,0x06,0x1732,0x06,QETH_CARD_TYPE_OSN,0, \ + QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \ + QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \ + QETH_MAX_QUEUES,0}, \ {0,0,0,0,0,0,0,0,0}} #define QETH_REAL_CARD 1 @@ -363,10 +367,22 @@ struct qeth_hdr_layer2 { __u8 reserved2[16]; } __attribute__ ((packed)); +struct qeth_hdr_osn { + __u8 id; + __u8 reserved; + __u16 seq_no; + __u16 reserved2; + __u16 control_flags; + __u16 pdu_length; + __u8 reserved3[18]; + __u32 ccid; +} __attribute__ ((packed)); + struct qeth_hdr { union { struct qeth_hdr_layer2 l2; struct qeth_hdr_layer3 l3; + struct qeth_hdr_osn osn; } hdr; } __attribute__ ((packed)); @@ -413,6 +429,7 @@ enum qeth_header_ids { QETH_HEADER_TYPE_LAYER3 = 0x01, QETH_HEADER_TYPE_LAYER2 = 0x02, QETH_HEADER_TYPE_TSO = 0x03, + QETH_HEADER_TYPE_OSN = 0x04, }; /* flags for qeth_hdr.ext_flags */ #define QETH_HDR_EXT_VLAN_FRAME 0x01 @@ -582,7 +599,6 @@ enum qeth_card_states { * Protocol versions */ enum qeth_prot_versions { - QETH_PROT_SNA = 0x0001, QETH_PROT_IPV4 = 0x0004, QETH_PROT_IPV6 = 0x0006, }; @@ -761,6 +777,11 @@ enum qeth_threads { QETH_RECOVER_THREAD = 2, }; +struct qeth_osn_info { + int (*assist_cb)(struct net_device *dev, void *data); + int (*data_cb)(struct sk_buff *skb); +}; + struct qeth_card { struct list_head list; enum qeth_card_states state; @@ -803,6 +824,7 @@ struct qeth_card { int use_hard_stop; int (*orig_hard_header)(struct sk_buff *,struct net_device *, unsigned short,void *,void *,unsigned); + struct qeth_osn_info osn_info; }; struct qeth_card_list_struct { @@ -916,10 +938,12 @@ qeth_get_hlen(__u8 link_type) static inline unsigned short qeth_get_netdev_flags(struct qeth_card *card) { - if (card->options.layer2) + if (card->options.layer2 && + (card->info.type == QETH_CARD_TYPE_OSAE)) return 0; switch (card->info.type) { case QETH_CARD_TYPE_IQD: + case QETH_CARD_TYPE_OSN: return IFF_NOARP; #ifdef CONFIG_QETH_IPV6 default: @@ -956,9 +980,10 @@ static inline int qeth_get_max_mtu_for_card(int cardtype) { switch (cardtype) { + case QETH_CARD_TYPE_UNKNOWN: - return 61440; case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: return 61440; case QETH_CARD_TYPE_IQD: return 57344; @@ -1004,6 +1029,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu) case QETH_CARD_TYPE_IQD: return ((mtu >= 576) && (mtu <= card->info.max_mtu + 4096 - 32)); + case QETH_CARD_TYPE_OSN: case QETH_CARD_TYPE_UNKNOWN: default: return 1; @@ -1015,6 +1041,7 @@ qeth_get_arphdr_type(int cardtype, int linktype) { switch (cardtype) { case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: switch (linktype) { case QETH_LINK_TYPE_LANE_TR: case QETH_LINK_TYPE_HSTR: @@ -1182,4 +1209,16 @@ qeth_fill_header(struct qeth_card *, struct qeth_hdr *, extern void qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int); +extern int +qeth_osn_assist(struct net_device *, void *, int); + +extern int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)); + +extern void +qeth_osn_deregister(struct net_device *); + #endif /* __QETH_H__ */ diff --git a/drivers/s390/net/qeth_fs.h b/drivers/s390/net/qeth_fs.h index 5c9a51ce91b6..c0b4c8d82c45 100644 --- a/drivers/s390/net/qeth_fs.h +++ b/drivers/s390/net/qeth_fs.h @@ -12,7 +12,7 @@ #ifndef __QETH_FS_H__ #define __QETH_FS_H__ -#define VERSION_QETH_FS_H "$Revision: 1.9 $" +#define VERSION_QETH_FS_H "$Revision: 1.10 $" extern const char *VERSION_QETH_PROC_C; extern const char *VERSION_QETH_SYS_C; @@ -42,6 +42,12 @@ qeth_create_device_attributes(struct device *dev); extern void qeth_remove_device_attributes(struct device *dev); +extern int +qeth_create_device_attributes_osn(struct device *dev); + +extern void +qeth_remove_device_attributes_osn(struct device *dev); + extern int qeth_create_driver_attributes(void); @@ -108,6 +114,8 @@ qeth_get_cardname(struct qeth_card *card) return " OSD Express"; case QETH_CARD_TYPE_IQD: return " HiperSockets"; + case QETH_CARD_TYPE_OSN: + return " OSN QDIO"; default: return " unknown"; } @@ -153,6 +161,8 @@ qeth_get_cardname_short(struct qeth_card *card) } case QETH_CARD_TYPE_IQD: return "HiperSockets"; + case QETH_CARD_TYPE_OSN: + return "OSN"; default: return "unknown"; } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index bd28e2438d7f..692003c9f896 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -196,7 +196,6 @@ qeth_notifier_register(struct task_struct *p, int signum) { struct qeth_notify_list_struct *n_entry; - /*check first if entry already exists*/ spin_lock(&qeth_notify_lock); list_for_each_entry(n_entry, &qeth_notify_list, list) { @@ -1024,7 +1023,10 @@ qeth_set_intial_options(struct qeth_card *card) card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.fake_ll = 0; - card->options.layer2 = 0; + if (card->info.type == QETH_CARD_TYPE_OSN) + card->options.layer2 = 1; + else + card->options.layer2 = 0; } /** @@ -1113,19 +1115,20 @@ qeth_determine_card_type(struct qeth_card *card) QETH_DBF_TEXT(setup, 2, "detcdtyp"); + card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; while (known_devices[i][4]) { if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) && (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) { card->info.type = known_devices[i][4]; + card->qdio.no_out_queues = known_devices[i][8]; + card->info.is_multicast_different = known_devices[i][9]; if (is_1920_device(card)) { PRINT_INFO("Priority Queueing not able " "due to hardware limitations!\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; - } else { - card->qdio.no_out_queues = known_devices[i][8]; - } - card->info.is_multicast_different = known_devices[i][9]; + } return 0; } i++; @@ -1149,6 +1152,8 @@ qeth_probe_device(struct ccwgroup_device *gdev) if (!get_device(dev)) return -ENODEV; + QETH_DBF_TEXT_(setup, 2, "%s", gdev->dev.bus_id); + card = qeth_alloc_card(); if (!card) { put_device(dev); @@ -1158,28 +1163,27 @@ qeth_probe_device(struct ccwgroup_device *gdev) card->read.ccwdev = gdev->cdev[0]; card->write.ccwdev = gdev->cdev[1]; card->data.ccwdev = gdev->cdev[2]; - - if ((rc = qeth_setup_card(card))){ - QETH_DBF_TEXT_(setup, 2, "2err%d", rc); - put_device(dev); - qeth_free_card(card); - return rc; - } gdev->dev.driver_data = card; card->gdev = gdev; gdev->cdev[0]->handler = qeth_irq; gdev->cdev[1]->handler = qeth_irq; gdev->cdev[2]->handler = qeth_irq; - rc = qeth_create_device_attributes(dev); - if (rc) { + if ((rc = qeth_determine_card_type(card))){ + PRINT_WARN("%s: not a valid card type\n", __func__); + QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + put_device(dev); + qeth_free_card(card); + return rc; + } + if ((rc = qeth_setup_card(card))){ + QETH_DBF_TEXT_(setup, 2, "2err%d", rc); put_device(dev); qeth_free_card(card); return rc; } - if ((rc = qeth_determine_card_type(card))){ - PRINT_WARN("%s: not a valid card type\n", __func__); - QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + rc = qeth_create_device_attributes(dev); + if (rc) { put_device(dev); qeth_free_card(card); return rc; @@ -1660,6 +1664,8 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) netif_carrier_on(card->dev); qeth_schedule_recovery(card); return NULL; + case IPA_CMD_MODCCID: + return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: QETH_DBF_TEXT(trace,3, "irla"); break; @@ -1721,6 +1727,14 @@ qeth_send_control_data_cb(struct qeth_channel *channel, cmd = qeth_check_ipa_data(card, iob); if ((cmd == NULL) && (card->state != CARD_STATE_DOWN)) goto out; + /*in case of OSN : check if cmd is set */ + if (card->info.type == QETH_CARD_TYPE_OSN && + cmd && + cmd->hdr.command != IPA_CMD_STARTLAN && + card->osn_info.assist_cb != NULL) { + card->osn_info.assist_cb(card->dev, cmd); + goto out; + } spin_lock_irqsave(&card->lock, flags); list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { @@ -1737,8 +1751,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel, keep_reply = reply->callback(card, reply, (unsigned long)cmd); - } - else + } else keep_reply = reply->callback(card, reply, (unsigned long)iob); @@ -1768,6 +1781,24 @@ qeth_send_control_data_cb(struct qeth_channel *channel, qeth_release_buffer(channel,iob); } +static inline void +qeth_prepare_control_data(struct qeth_card *card, int len, +struct qeth_cmd_buffer *iob) +{ + qeth_setup_ccw(&card->write,iob->data,len); + iob->callback = qeth_release_buffer; + + memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), + &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.trans_hdr++; + memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), + &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.pdu_hdr++; + memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), + &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); + QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); +} + static int qeth_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob, @@ -1778,24 +1809,11 @@ qeth_send_control_data(struct qeth_card *card, int len, { int rc; unsigned long flags; - struct qeth_reply *reply; + struct qeth_reply *reply = NULL; struct timer_list timer; QETH_DBF_TEXT(trace, 2, "sendctl"); - qeth_setup_ccw(&card->write,iob->data,len); - - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.trans_hdr++; - - memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), - &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.pdu_hdr++; - memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), - &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); - iob->callback = qeth_release_buffer; - reply = qeth_alloc_reply(card); if (!reply) { PRINT_WARN("Could no alloc qeth_reply!\n"); @@ -1810,10 +1828,6 @@ qeth_send_control_data(struct qeth_card *card, int len, init_timer(&timer); timer.function = qeth_cmd_timeout; timer.data = (unsigned long) reply; - if (IS_IPA(iob->data)) - timer.expires = jiffies + QETH_IPA_TIMEOUT; - else - timer.expires = jiffies + QETH_TIMEOUT; init_waitqueue_head(&reply->wait_q); spin_lock_irqsave(&card->lock, flags); list_add_tail(&reply->list, &card->cmd_waiter_list); @@ -1821,6 +1835,11 @@ qeth_send_control_data(struct qeth_card *card, int len, QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); wait_event(card->wait_q, atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + if (IS_IPA(iob->data)) + timer.expires = jiffies + QETH_IPA_TIMEOUT; + else + timer.expires = jiffies + QETH_TIMEOUT; QETH_DBF_TEXT(trace, 6, "noirqpnd"); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, @@ -1847,6 +1866,62 @@ qeth_send_control_data(struct qeth_card *card, int len, return rc; } +static int +qeth_osn_send_control_data(struct qeth_card *card, int len, + struct qeth_cmd_buffer *iob) +{ + unsigned long flags; + int rc = 0; + + QETH_DBF_TEXT(trace, 5, "osndctrd"); + + wait_event(card->wait_q, + atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + QETH_DBF_TEXT(trace, 6, "osnoirqp"); + spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); + rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, + (addr_t) iob, 0, 0); + spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); + if (rc){ + PRINT_WARN("qeth_osn_send_control_data: " + "ccw_device_start rc = %i\n", rc); + QETH_DBF_TEXT_(trace, 2, " err%d", rc); + qeth_release_buffer(iob->channel, iob); + atomic_set(&card->write.irq_pending, 0); + wake_up(&card->wait_q); + } + return rc; +} + +static inline void +qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + char prot_type) +{ + memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); + memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), + &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); +} + +static int +qeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + int data_len) +{ + u16 s1, s2; + +QETH_DBF_TEXT(trace,4,"osndipa"); + + qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2); + s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len); + s2 = (u16)data_len; + memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); + memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); + return qeth_osn_send_control_data(card, s1, iob); +} + static int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int (*reply_cb) @@ -1858,17 +1933,14 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, QETH_DBF_TEXT(trace,4,"sendipa"); - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; - - memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); - + qeth_prepare_ipa_cmd(card,iob,prot_type); rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob, reply_cb, reply_param); return rc; @@ -2010,7 +2082,10 @@ qeth_ulp_enable(struct qeth_card *card) *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (__u8) card->info.portno; if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; @@ -2100,15 +2175,21 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf, } static inline struct sk_buff * -qeth_get_skb(unsigned int length) +qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; + int add_len; + + add_len = 0; + if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) + add_len = sizeof(struct qeth_hdr); #ifdef CONFIG_QETH_VLAN - if ((skb = dev_alloc_skb(length + VLAN_HLEN))) - skb_reserve(skb, VLAN_HLEN); -#else - skb = dev_alloc_skb(length); + else + add_len = VLAN_HLEN; #endif + skb = dev_alloc_skb(length + add_len); + if (skb && add_len) + skb_reserve(skb, add_len); return skb; } @@ -2138,7 +2219,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, offset += sizeof(struct qeth_hdr); if (card->options.layer2) - skb_len = (*hdr)->hdr.l2.pkt_length; + if (card->info.type == QETH_CARD_TYPE_OSN) + skb_len = (*hdr)->hdr.osn.pdu_length; + else + skb_len = (*hdr)->hdr.l2.pkt_length; else skb_len = (*hdr)->hdr.l3.length; @@ -2146,15 +2230,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, return NULL; if (card->options.fake_ll){ if(card->dev->type == ARPHRD_IEEE802_TR){ - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_TR); } else { - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_ETH); } - } else if (!(skb = qeth_get_skb(skb_len))) + } else if (!(skb = qeth_get_skb(skb_len, *hdr))) goto no_mem; data_ptr = element->addr + offset; while (skb_len) { @@ -2453,8 +2537,12 @@ qeth_process_inbound_buffer(struct qeth_card *card, skb->dev = card->dev; if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); - else + else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) qeth_rebuild_skb(card, skb, hdr); + else { /*in case of OSN*/ + skb_push(skb, sizeof(struct qeth_hdr)); + memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); + } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ dev_kfree_skb_any(skb); @@ -2465,7 +2553,10 @@ qeth_process_inbound_buffer(struct qeth_card *card, vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); else #endif - rxrc = netif_rx(skb); + if (card->info.type == QETH_CARD_TYPE_OSN) + rxrc = card->osn_info.data_cb(skb); + else + rxrc = netif_rx(skb); card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += skb->len; @@ -3150,8 +3241,6 @@ qeth_init_qdio_info(struct qeth_card *card) INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); /* outbound */ - card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; - card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } static int @@ -3466,7 +3555,7 @@ qeth_mpc_initialize(struct qeth_card *card) return 0; out_qdio: - qeth_qdio_clear_card(card, card->info.type==QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type!=QETH_CARD_TYPE_IQD); return rc; } @@ -3491,6 +3580,9 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) case QETH_CARD_TYPE_IQD: dev = alloc_netdev(0, "hsi%d", ether_setup); break; + case QETH_CARD_TYPE_OSN: + dev = alloc_netdev(0, "osn%d", ether_setup); + break; default: dev = alloc_etherdev(0); } @@ -3655,7 +3747,8 @@ qeth_open(struct net_device *dev) if (card->state != CARD_STATE_SOFTSETUP) return -ENODEV; - if ( (card->options.layer2) && + if ( (card->info.type != QETH_CARD_TYPE_OSN) && + (card->options.layer2) && (!card->info.layer2_mac_registered)) { QETH_DBF_TEXT(trace,4,"nomacadr"); return -EPERM; @@ -3693,6 +3786,9 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; + if (card->info.type == QETH_CARD_TYPE_OSN) + return cast_type; + if (skb->dst && skb->dst->neighbour){ cast_type = skb->dst->neighbour->type; if ((cast_type == RTN_BROADCAST) || @@ -3782,13 +3878,16 @@ static inline int qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, struct qeth_hdr **hdr, int ipv) { - int rc; + int rc = 0; #ifdef CONFIG_QETH_VLAN u16 *tag; #endif QETH_DBF_TEXT(trace, 6, "prepskb"); - + if (card->info.type == QETH_CARD_TYPE_OSN) { + *hdr = (struct qeth_hdr *)(*skb)->data; + return rc; + } rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); if (rc) return rc; @@ -4291,8 +4390,14 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) } } } + if ((card->info.type == QETH_CARD_TYPE_OSN) && + (skb->protocol == htons(ETH_P_IPV6))) { + dev_kfree_skb_any(skb); + return 0; + } cast_type = qeth_get_cast_type(card, skb); - if ((cast_type == RTN_BROADCAST) && (card->info.broadcast_capable == 0)){ + if ((cast_type == RTN_BROADCAST) && + (card->info.broadcast_capable == 0)){ card->stats.tx_dropped++; card->stats.tx_errors++; dev_kfree_skb_any(skb); @@ -4320,7 +4425,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); return rc; } - qeth_fill_header(card, hdr, skb, ipv, cast_type); + if (card->info.type != QETH_CARD_TYPE_OSN) + qeth_fill_header(card, hdr, skb, ipv, cast_type); } if (large_send == QETH_LARGE_SEND_EDDP) { @@ -4381,6 +4487,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) case MII_BMCR: /* Basic mode control register */ rc = BMCR_FULLDPLX; if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)&& + (card->info.link_type != QETH_LINK_TYPE_OSN) && (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH)) rc |= BMCR_SPEED100; break; @@ -5004,6 +5111,9 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) (card->state != CARD_STATE_SOFTSETUP)) return -ENODEV; + if (card->info.type == QETH_CARD_TYPE_OSN) + return -EPERM; + switch (cmd){ case SIOC_QETH_ARP_SET_NO_ENTRIES: if ( !capable(CAP_NET_ADMIN) || @@ -5329,6 +5439,9 @@ qeth_set_multicast_list(struct net_device *dev) { struct qeth_card *card = (struct qeth_card *) dev->priv; + if (card->info.type == QETH_CARD_TYPE_OSN) + return ; + QETH_DBF_TEXT(trace,3,"setmulti"); qeth_delete_mc_addresses(card); qeth_add_multicast_ipv4(card); @@ -5370,6 +5483,94 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot) return addr; } +int +qeth_osn_assist(struct net_device *dev, + void *data, + int data_len) +{ + struct qeth_cmd_buffer *iob; + struct qeth_card *card; + int rc; + + QETH_DBF_TEXT(trace, 2, "osnsdmc"); + if (!dev) + return -ENODEV; + card = (struct qeth_card *)dev->priv; + if (!card) + return -ENODEV; + if ((card->state != CARD_STATE_UP) && + (card->state != CARD_STATE_SOFTSETUP)) + return -ENODEV; + iob = qeth_wait_for_buffer(&card->write); + memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len); + rc = qeth_osn_send_ipa_cmd(card, iob, data_len); + return rc; +} + +static struct net_device * +qeth_netdev_by_devno(unsigned char *read_dev_no) +{ + struct qeth_card *card; + struct net_device *ndev; + unsigned char *readno; + __u16 temp_dev_no, card_dev_no; + char *endp; + unsigned long flags; + + ndev = NULL; + memcpy(&temp_dev_no, read_dev_no, 2); + read_lock_irqsave(&qeth_card_list.rwlock, flags); + list_for_each_entry(card, &qeth_card_list.list, list) { + readno = CARD_RDEV_ID(card); + readno += (strlen(readno) - 4); + card_dev_no = simple_strtoul(readno, &endp, 16); + if (card_dev_no == temp_dev_no) { + ndev = card->dev; + break; + } + } + read_unlock_irqrestore(&qeth_card_list.rwlock, flags); + return ndev; +} + +int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **dev, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)) +{ + struct qeth_card * card; + + QETH_DBF_TEXT(trace, 2, "osnreg"); + *dev = qeth_netdev_by_devno(read_dev_no); + if (*dev == NULL) + return -ENODEV; + card = (struct qeth_card *)(*dev)->priv; + if (!card) + return -ENODEV; + if ((assist_cb == NULL) || (data_cb == NULL)) + return -EINVAL; + card->osn_info.assist_cb = assist_cb; + card->osn_info.data_cb = data_cb; + return 0; +} + +void +qeth_osn_deregister(struct net_device * dev) +{ + struct qeth_card *card; + + QETH_DBF_TEXT(trace, 2, "osndereg"); + if (!dev) + return; + card = (struct qeth_card *)dev->priv; + if (!card) + return; + card->osn_info.assist_cb = NULL; + card->osn_info.data_cb = NULL; + return; +} + static void qeth_delete_mc_addresses(struct qeth_card *card) { @@ -5700,6 +5901,12 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p) QETH_DBF_TEXT(trace, 3, "setmcLY3"); return -EOPNOTSUPP; } + if (card->info.type == QETH_CARD_TYPE_OSN) { + PRINT_WARN("Setting MAC address on %s is not supported.\n", + dev->name); + QETH_DBF_TEXT(trace, 3, "setmcOSN"); + return -EOPNOTSUPP; + } QETH_DBF_TEXT_(trace, 3, "%s", CARD_BUS_ID(card)); QETH_DBF_HEX(trace, 3, addr->sa_data, OSA_ADDR_LEN); rc = qeth_layer2_send_delmac(card, &card->dev->dev_addr[0]); @@ -6076,9 +6283,8 @@ qeth_netdev_init(struct net_device *dev) qeth_get_hlen(card->info.link_type) + card->options.add_hhlen; dev->addr_len = OSA_ADDR_LEN; dev->mtu = card->info.initial_mtu; - - SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); - + if (card->info.type != QETH_CARD_TYPE_OSN) + SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); SET_MODULE_OWNER(dev); return 0; } @@ -6095,6 +6301,7 @@ qeth_init_func_level(struct qeth_card *card) QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT; } else { if (card->info.type == QETH_CARD_TYPE_IQD) + /*FIXME:why do we have same values for dis and ena for osae??? */ card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT; else @@ -6124,7 +6331,7 @@ qeth_hardsetup_card(struct qeth_card *card) ccw_device_set_online(CARD_WDEV(card)); ccw_device_set_online(CARD_DDEV(card)); } - rc = qeth_qdio_clear_card(card,card->info.type==QETH_CARD_TYPE_OSAE); + rc = qeth_qdio_clear_card(card,card->info.type!=QETH_CARD_TYPE_IQD); if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(setup, 2, "break1"); return rc; @@ -6176,8 +6383,8 @@ qeth_hardsetup_card(struct qeth_card *card) card->dev = qeth_get_netdevice(card->info.type, card->info.link_type); if (!card->dev){ - qeth_qdio_clear_card(card, card->info.type == - QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type != + QETH_CARD_TYPE_IQD); rc = -ENODEV; QETH_DBF_TEXT_(setup, 2, "6err%d", rc); goto out; @@ -7084,6 +7291,8 @@ qeth_softsetup_card(struct qeth_card *card) return rc; } else card->lan_online = 1; + if (card->info.type==QETH_CARD_TYPE_OSN) + goto out; if (card->options.layer2) { card->dev->features |= NETIF_F_HW_VLAN_FILTER | @@ -7255,7 +7464,8 @@ qeth_stop_card(struct qeth_card *card, int recovery_mode) if (card->read.state == CH_STATE_UP && card->write.state == CH_STATE_UP && (card->state == CARD_STATE_UP)) { - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_stop(card->dev); } else { rtnl_lock(); @@ -7437,7 +7647,8 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) { QETH_DBF_TEXT(setup ,2, "startag"); - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_open(card->dev); } else { rtnl_lock(); @@ -7469,33 +7680,36 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) static void qeth_make_parameters_consistent(struct qeth_card *card) { - if (card->options.layer2) { - if (card->info.type == QETH_CARD_TYPE_IQD) { - PRINT_ERR("Device %s does not support " \ - "layer 2 functionality. " \ - "Ignoring layer2 option.\n",CARD_BUS_ID(card)); - } - IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + if (card->options.layer2 == 0) + return; + if (card->info.type == QETH_CARD_TYPE_OSN) + return; + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_ERR("Device %s does not support layer 2 functionality." \ + " Ignoring layer2 option.\n",CARD_BUS_ID(card)); + card->options.layer2 = 0; + return; + } + IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #ifdef CONFIG_QETH_IPV6 - IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #endif - IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, - QETH_CHECKSUM_DEFAULT, - "Checksumming options are"); - IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, - QETH_TR_BROADCAST_ALLRINGS, - "Broadcast mode options are"); - IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, - QETH_TR_MACADDR_NONCANONICAL, - "Canonical MAC addr options are"); - IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, - "Broadcast faking options are"); - IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, - DEFAULT_ADD_HHLEN,"Option add_hhlen is"); - IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); - } + IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, + QETH_CHECKSUM_DEFAULT, + "Checksumming options are"); + IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, + QETH_TR_BROADCAST_ALLRINGS, + "Broadcast mode options are"); + IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, + QETH_TR_MACADDR_NONCANONICAL, + "Canonical MAC addr options are"); + IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, + "Broadcast faking options are"); + IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, + DEFAULT_ADD_HHLEN,"Option add_hhlen is"); + IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); } @@ -7525,8 +7739,7 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode) return -EIO; } - if (card->options.layer2) - qeth_make_parameters_consistent(card); + qeth_make_parameters_consistent(card); if ((rc = qeth_hardsetup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); @@ -7585,6 +7798,7 @@ qeth_set_online(struct ccwgroup_device *gdev) static struct ccw_device_id qeth_ids[] = { {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, + {CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN}, {}, }; MODULE_DEVICE_TABLE(ccw, qeth_ids); @@ -8329,6 +8543,9 @@ __exit qeth_exit(void) printk("qeth: removed\n"); } +EXPORT_SYMBOL(qeth_osn_register); +EXPORT_SYMBOL(qeth_osn_deregister); +EXPORT_SYMBOL(qeth_osn_assist); module_init(qeth_init); module_exit(qeth_exit); MODULE_AUTHOR("Frank Pavlic "); diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c index f685ecc7da99..30e053d3cac2 100644 --- a/drivers/s390/net/qeth_mpc.c +++ b/drivers/s390/net/qeth_mpc.c @@ -11,7 +11,7 @@ #include #include "qeth_mpc.h" -const char *VERSION_QETH_MPC_C = "$Revision: 1.11 $"; +const char *VERSION_QETH_MPC_C = "$Revision: 1.12 $"; unsigned char IDX_ACTIVATE_READ[]={ 0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00, @@ -138,7 +138,9 @@ unsigned char IPA_PDU_HEADER[]={ sizeof(struct qeth_ipa_cmd)%256, 0x00, sizeof(struct qeth_ipa_cmd)/256, - sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77, + sizeof(struct qeth_ipa_cmd)%256, + 0x05, + 0x77,0x77,0x77,0x77, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x01,0x00, sizeof(struct qeth_ipa_cmd)/256, diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h index 3d916b5c5d09..7edc5f1fc0d2 100644 --- a/drivers/s390/net/qeth_mpc.h +++ b/drivers/s390/net/qeth_mpc.h @@ -46,13 +46,16 @@ extern unsigned char IPA_PDU_HEADER[]; /* IP Assist related definitions */ /*****************************************************************************/ #define IPA_CMD_INITIATOR_HOST 0x00 -#define IPA_CMD_INITIATOR_HYDRA 0x01 +#define IPA_CMD_INITIATOR_OSA 0x01 +#define IPA_CMD_INITIATOR_HOST_REPLY 0x80 +#define IPA_CMD_INITIATOR_OSA_REPLY 0x81 #define IPA_CMD_PRIM_VERSION_NO 0x01 enum qeth_card_types { QETH_CARD_TYPE_UNKNOWN = 0, QETH_CARD_TYPE_OSAE = 10, QETH_CARD_TYPE_IQD = 1234, + QETH_CARD_TYPE_OSN = 11, }; #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 @@ -61,6 +64,7 @@ enum qeth_link_types { QETH_LINK_TYPE_FAST_ETH = 0x01, QETH_LINK_TYPE_HSTR = 0x02, QETH_LINK_TYPE_GBIT_ETH = 0x03, + QETH_LINK_TYPE_OSN = 0x04, QETH_LINK_TYPE_10GBIT_ETH = 0x10, QETH_LINK_TYPE_LANE_ETH100 = 0x81, QETH_LINK_TYPE_LANE_TR = 0x82, @@ -111,6 +115,9 @@ enum qeth_ipa_cmds { IPA_CMD_DELGMAC = 0x24, IPA_CMD_SETVLAN = 0x25, IPA_CMD_DELVLAN = 0x26, + IPA_CMD_SETCCID = 0x41, + IPA_CMD_DELCCID = 0x42, + IPA_CMD_MODCCID = 0x43, IPA_CMD_SETIP = 0xb1, IPA_CMD_DELIP = 0xb7, IPA_CMD_QIPASSIST = 0xb2, @@ -437,8 +444,9 @@ enum qeth_ipa_arp_return_codes { #define QETH_ARP_DATA_SIZE 3968 #define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8) /* Helper functions */ -#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) - +#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \ + (cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY)) + /*****************************************************************************/ /* END OF IP Assist related definitions */ /*****************************************************************************/ @@ -483,6 +491,7 @@ extern unsigned char ULP_ENABLE[]; /* Layer 2 defintions */ #define QETH_PROT_LAYER2 0x08 #define QETH_PROT_TCPIP 0x03 +#define QETH_PROT_OSN2 0x0a #define QETH_ULP_ENABLE_PROT_TYPE(buffer) (buffer+0x50) #define QETH_IPA_CMD_PROT_TYPE(buffer) (buffer+0x19) diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index dda105b73063..f91a02db5743 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.54 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.55 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.54 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.55 $"; /*****************************************************************************/ /* */ @@ -937,6 +937,19 @@ static struct attribute_group qeth_device_attr_group = { .attrs = (struct attribute **)qeth_device_attrs, }; +static struct device_attribute * qeth_osn_device_attrs[] = { + &dev_attr_state, + &dev_attr_chpid, + &dev_attr_if_name, + &dev_attr_card_type, + &dev_attr_buffer_count, + &dev_attr_recover, + NULL, +}; + +static struct attribute_group qeth_osn_device_attr_group = { + .attrs = (struct attribute **)qeth_osn_device_attrs, +}; #define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_id = { \ @@ -1667,7 +1680,12 @@ int qeth_create_device_attributes(struct device *dev) { int ret; + struct qeth_card *card = dev->driver_data; + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_create_group(&dev->kobj, + &qeth_osn_device_attr_group); + if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group))) return ret; if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){ @@ -1693,6 +1711,12 @@ qeth_create_device_attributes(struct device *dev) void qeth_remove_device_attributes(struct device *dev) { + struct qeth_card *card = dev->driver_data; + + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_remove_group(&dev->kobj, + &qeth_osn_device_attr_group); + sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); From 31961943e3110c5a1c36b1e0069c29f7c4380e51 Mon Sep 17 00:00:00 2001 From: Brett Russ Date: Fri, 30 Sep 2005 01:36:00 -0400 Subject: [PATCH 0261/1939] [PATCH] libata: Marvell SATA support (DMA mode) (resend: v0.22) This is my libata compatible low level driver for the Marvell SATA family. Currently it runs in DMA mode on a 6081 chip. The 5xxx series parts are not yet DMA capable in this driver because the registers have differences that haven't been accounted for yet. Basically, I'm focused on the 6xxx series right now. I apologize for those seeing problems on the 5xxx series, I've not had a chance to look at those problems yet. For those curious, the previous bug causing the SCSI timeout and subsequent panics was caused by an improper clear of hc_irq_cause in mv_host_intr(). This version is running well in my environment (6081 chips, with/without SW raid1) and is showing equal or better performance compared to the Marvell driver (mv_sata) in my initial tests (timed dd's of reads/writes to/from memory/disk). I still need to look at the causes of occasional problems such as this: ata11: translating stat 0x35 err 0x00 to sense ata11: status=0x35 { DeviceFault SeekComplete CorrectedError Error } SCSI error : <10 0 0 0> return code = 0x8000002 Current sda: sense key Hardware Error end_request: I/O error, dev sda, sector 3155010 and this, seen at init time: ATA: abnormal status 0x80 on port 0xE093911C but they aren't showstoppers. Signed-off-by: Brett Russ Signed-off-by: Jeff Garzik --- drivers/scsi/sata_mv.c | 946 ++++++++++++++++++++++++++++++++--------- 1 file changed, 753 insertions(+), 193 deletions(-) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ea76fe44585e..ecda7df21142 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.12" +#define DRV_VERSION "0.22" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -55,31 +55,61 @@ enum { MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ, - MV_Q_CT = 32, - MV_CRQB_SZ = 32, - MV_CRPB_SZ = 8, + MV_USE_Q_DEPTH = ATA_DEF_QUEUE, - MV_DMA_BOUNDARY = 0xffffffffU, - SATAHC_MASK = (~(MV_SATAHC_REG_SZ - 1)), + MV_MAX_Q_DEPTH = 32, + MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1, + + /* CRQB needs alignment on a 1KB boundary. Size == 1KB + * CRPB needs alignment on a 256B boundary. Size == 256B + * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB + * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B + */ + MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH), + MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH), + MV_MAX_SG_CT = 176, + MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), + MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), + + /* Our DMA boundary is determined by an ePRD being unable to handle + * anything larger than 64KB + */ + MV_DMA_BOUNDARY = 0xffffU, MV_PORTS_PER_HC = 4, /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ MV_PORT_HC_SHIFT = 2, - /* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */ + /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */ MV_PORT_MASK = 3, /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ - MV_FLAG_BDMA = (1 << 28), /* Basic DMA */ + MV_FLAG_GLBL_SFT_RST = (1 << 28), /* Global Soft Reset support */ + MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), + MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | + MV_FLAG_GLBL_SFT_RST), chip_504x = 0, chip_508x = 1, chip_604x = 2, chip_608x = 3, + CRQB_FLAG_READ = (1 << 0), + CRQB_TAG_SHIFT = 1, + CRQB_CMD_ADDR_SHIFT = 8, + CRQB_CMD_CS = (0x2 << 11), + CRQB_CMD_LAST = (1 << 15), + + CRPB_FLAG_STATUS_SHIFT = 8, + + EPRD_FLAG_END_OF_TBL = (1 << 31), + /* PCI interface registers */ + PCI_COMMAND_OFS = 0xc00, + PCI_MAIN_CMD_STS_OFS = 0xd30, STOP_PCI_MASTER = (1 << 2), PCI_MASTER_EMPTY = (1 << 3), @@ -111,20 +141,13 @@ enum { HC_CFG_OFS = 0, HC_IRQ_CAUSE_OFS = 0x14, - CRBP_DMA_DONE = (1 << 0), /* shift by port # */ + CRPB_DMA_DONE = (1 << 0), /* shift by port # */ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */ DEV_IRQ = (1 << 8), /* shift by port # */ /* Shadow block registers */ - SHD_PIO_DATA_OFS = 0x100, - SHD_FEA_ERR_OFS = 0x104, - SHD_SECT_CNT_OFS = 0x108, - SHD_LBA_L_OFS = 0x10C, - SHD_LBA_M_OFS = 0x110, - SHD_LBA_H_OFS = 0x114, - SHD_DEV_HD_OFS = 0x118, - SHD_CMD_STA_OFS = 0x11C, - SHD_CTL_AST_OFS = 0x120, + SHD_BLK_OFS = 0x100, + SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ @@ -132,6 +155,11 @@ enum { /* Port registers */ EDMA_CFG_OFS = 0, + EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */ + EDMA_CFG_NCQ = (1 << 5), + EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ + EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ + EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ EDMA_ERR_IRQ_CAUSE_OFS = 0x8, EDMA_ERR_IRQ_MASK_OFS = 0xc, @@ -161,33 +189,85 @@ enum { EDMA_ERR_LNK_DATA_TX | EDMA_ERR_TRANS_PROTO), + EDMA_REQ_Q_BASE_HI_OFS = 0x10, + EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */ + EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, + + EDMA_REQ_Q_OUT_PTR_OFS = 0x18, + EDMA_REQ_Q_PTR_SHIFT = 5, + + EDMA_RSP_Q_BASE_HI_OFS = 0x1c, + EDMA_RSP_Q_IN_PTR_OFS = 0x20, + EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ + EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, + EDMA_RSP_Q_PTR_SHIFT = 3, + EDMA_CMD_OFS = 0x28, EDMA_EN = (1 << 0), EDMA_DS = (1 << 1), ATA_RST = (1 << 2), - /* BDMA is 6xxx part only */ - BDMA_CMD_OFS = 0x224, - BDMA_START = (1 << 0), + /* Host private flags (hp_flags) */ + MV_HP_FLAG_MSI = (1 << 0), - MV_UNDEF = 0, + /* Port private flags (pp_flags) */ + MV_PP_FLAG_EDMA_EN = (1 << 0), + MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), +}; + +/* Command ReQuest Block: 32B */ +struct mv_crqb { + u32 sg_addr; + u32 sg_addr_hi; + u16 ctrl_flags; + u16 ata_cmd[11]; +}; + +/* Command ResPonse Block: 8B */ +struct mv_crpb { + u16 id; + u16 flags; + u32 tmstmp; +}; + +/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */ +struct mv_sg { + u32 addr; + u32 flags_size; + u32 addr_hi; + u32 reserved; }; struct mv_port_priv { + struct mv_crqb *crqb; + dma_addr_t crqb_dma; + struct mv_crpb *crpb; + dma_addr_t crpb_dma; + struct mv_sg *sg_tbl; + dma_addr_t sg_tbl_dma; + unsigned req_producer; /* cp of req_in_ptr */ + unsigned rsp_consumer; /* cp of rsp_out_ptr */ + u32 pp_flags; }; struct mv_host_priv { - + u32 hp_flags; }; static void mv_irq_clear(struct ata_port *ap); static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static u8 mv_check_err(struct ata_port *ap); static void mv_phy_reset(struct ata_port *ap); -static int mv_master_reset(void __iomem *mmio_base); +static void mv_host_stop(struct ata_host_set *host_set); +static int mv_port_start(struct ata_port *ap); +static void mv_port_stop(struct ata_port *ap); +static void mv_qc_prep(struct ata_queued_cmd *qc); +static int mv_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static Scsi_Host_Template mv_sht = { @@ -196,13 +276,13 @@ static Scsi_Host_Template mv_sht = { .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, - .can_queue = ATA_DEF_QUEUE, + .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_UNDEF, + .sg_tablesize = MV_MAX_SG_CT, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, - .use_clustering = MV_UNDEF, + .use_clustering = ATA_SHT_USE_CLUSTERING, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, @@ -216,15 +296,16 @@ static struct ata_port_operations mv_ops = { .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, + .check_err = mv_check_err, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, .phy_reset = mv_phy_reset, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_prep = mv_qc_prep, + .qc_issue = mv_qc_issue, - .eng_timeout = ata_eng_timeout, + .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, @@ -232,46 +313,39 @@ static struct ata_port_operations mv_ops = { .scr_read = mv_scr_read, .scr_write = mv_scr_write, - .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .port_start = mv_port_start, + .port_stop = mv_port_stop, + .host_stop = mv_host_stop, }; 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), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = MV_COMMON_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_508x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_DUAL_HC), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_604x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, { /* chip_608x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC | - MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | + MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, }; @@ -306,12 +380,6 @@ static inline void writelfl(unsigned long data, void __iomem *addr) (void) readl(addr); /* flush to avoid PCI posted write */ } -static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio) -{ - return ((void __iomem *)((unsigned long)port_mmio & - (unsigned long)SATAHC_MASK)); -} - static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) { return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ)); @@ -329,26 +397,143 @@ static inline void __iomem *mv_ap_base(struct ata_port *ap) return mv_port_base(ap->host_set->mmio_base, ap->port_no); } -static inline int mv_get_hc_count(unsigned long flags) +static inline int mv_get_hc_count(unsigned long hp_flags) { - return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1); -} - -static inline int mv_is_edma_active(struct ata_port *ap) -{ - void __iomem *port_mmio = mv_ap_base(ap); - return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); -} - -static inline int mv_port_bdma_capable(struct ata_port *ap) -{ - return (ap->flags & MV_FLAG_BDMA); + return ((hp_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } static void mv_irq_clear(struct ata_port *ap) { } +static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp, + struct ata_port *ap) +{ + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + writelfl(EDMA_EN, base + EDMA_CMD_OFS); + pp->pp_flags |= MV_PP_FLAG_EDMA_EN; + + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +static void mv_stop_dma(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + unsigned long flags; + u32 reg; + int i; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + if (!(MV_PP_FLAG_EDMA_DS_ACT & pp->pp_flags) && + ((MV_PP_FLAG_EDMA_EN & pp->pp_flags) || + (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)))) { + /* Disable EDMA if we're not already trying to disable it + * and it is currently active. The disable bit auto clears. + */ + pp->pp_flags |= MV_PP_FLAG_EDMA_DS_ACT; + writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + /* now properly wait for the eDMA to stop */ + for (i = 1000; i > 0; i--) { + reg = readl(port_mmio + EDMA_CMD_OFS); + if (!(EDMA_EN & reg)) { + break; + } + udelay(100); + } + + spin_lock_irqsave(&ap->host_set->lock, flags); + pp->pp_flags &= ~MV_PP_FLAG_EDMA_DS_ACT; + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (EDMA_EN & reg) { + printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); + } +} + +static void mv_dump_mem(void __iomem *start, unsigned bytes) +{ +#ifdef ATA_DEBUG + int b, w; + for (b = 0; b < bytes; ) { + DPRINTK("%p: ", start + b); + for (w = 0; b < bytes && w < 4; w++) { + printk("%08x ",readl(start + b)); + b += sizeof(u32); + } + printk("\n"); + } +#endif +} +static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) +{ +#ifdef ATA_DEBUG + int b, w; + u32 dw; + for (b = 0; b < bytes; ) { + DPRINTK("%02x: ", b); + for (w = 0; b < bytes && w < 4; w++) { + (void) pci_read_config_dword(pdev,b,&dw); + printk("%08x ",dw); + b += sizeof(u32); + } + printk("\n"); + } +#endif +} +static void mv_dump_all_regs(void __iomem *mmio_base, int port, + struct pci_dev *pdev) +{ +#ifdef ATA_DEBUG + void __iomem *hc_base = mv_hc_base(mmio_base, + port >> MV_PORT_HC_SHIFT); + void __iomem *port_base; + int start_port, num_ports, p, start_hc, num_hcs, hc; + + if (0 > port) { + start_hc = start_port = 0; + num_ports = 8; /* shld be benign for 4 port devs */ + num_hcs = 2; + } else { + start_hc = port >> MV_PORT_HC_SHIFT; + start_port = port; + num_ports = num_hcs = 1; + } + DPRINTK("All registers for port(s) %u-%u:\n", start_port, + num_ports > 1 ? num_ports - 1 : start_port); + + if (NULL != pdev) { + DPRINTK("PCI config space regs:\n"); + mv_dump_pci_cfg(pdev, 0x68); + } + DPRINTK("PCI regs:\n"); + mv_dump_mem(mmio_base+0xc00, 0x3c); + mv_dump_mem(mmio_base+0xd00, 0x34); + mv_dump_mem(mmio_base+0xf00, 0x4); + mv_dump_mem(mmio_base+0x1d00, 0x6c); + for (hc = start_hc; hc < start_hc + num_hcs; hc++) { + hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT); + DPRINTK("HC regs (HC %i):\n", hc); + mv_dump_mem(hc_base, 0x1c); + } + for (p = start_port; p < start_port + num_ports; p++) { + port_base = mv_port_base(mmio_base, p); + DPRINTK("EDMA regs (port %i):\n",p); + mv_dump_mem(port_base, 0x54); + DPRINTK("SATA regs (port %i):\n",p); + mv_dump_mem(port_base+0x300, 0x60); + } +#endif +} + static unsigned int mv_scr_offset(unsigned int sc_reg_in) { unsigned int ofs; @@ -389,30 +574,29 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } -static int mv_master_reset(void __iomem *mmio_base) +/* This routine only applies to 6xxx parts */ +static int mv_global_soft_reset(void __iomem *mmio_base) { void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS; int i, rc = 0; u32 t; - VPRINTK("ENTER\n"); - /* Following procedure defined in PCI "main command and status * register" table. */ t = readl(reg); writel(t | STOP_PCI_MASTER, reg); - for (i = 0; i < 100; i++) { - msleep(10); + for (i = 0; i < 1000; i++) { + udelay(1); t = readl(reg); if (PCI_MASTER_EMPTY & t) { break; } } if (!(PCI_MASTER_EMPTY & t)) { - printk(KERN_ERR DRV_NAME "PCI master won't flush\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); + rc = 1; goto done; } @@ -425,40 +609,312 @@ static int mv_master_reset(void __iomem *mmio_base) } while (!(GLOB_SFT_RST & t) && (i-- > 0)); if (!(GLOB_SFT_RST & t)) { - printk(KERN_ERR DRV_NAME "can't set global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't set global reset\n"); + rc = 1; goto done; } - /* clear reset */ + /* clear reset and *reenable the PCI master* (not mentioned in spec) */ i = 5; do { - writel(t & ~GLOB_SFT_RST, reg); + writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); t = readl(reg); udelay(1); } while ((GLOB_SFT_RST & t) && (i-- > 0)); if (GLOB_SFT_RST & t) { - printk(KERN_ERR DRV_NAME "can't clear global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); + rc = 1; + } +done: + return rc; +} + +static void mv_host_stop(struct ata_host_set *host_set) +{ + struct mv_host_priv *hpriv = host_set->private_data; + struct pci_dev *pdev = to_pci_dev(host_set->dev); + + if (hpriv->hp_flags & MV_HP_FLAG_MSI) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } + kfree(hpriv); + ata_host_stop(host_set); +} + +static int mv_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp; + void __iomem *port_mmio = mv_ap_base(ap); + void *mem; + dma_addr_t mem_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + return -ENOMEM; + } + memset(pp, 0, sizeof(*pp)); + + mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); + if (!mem) { + kfree(pp); + return -ENOMEM; + } + memset(mem, 0, MV_PORT_PRIV_DMA_SZ); + + /* First item in chunk of DMA memory: + * 32-slot command request table (CRQB), 32 bytes each in size + */ + pp->crqb = mem; + pp->crqb_dma = mem_dma; + mem += MV_CRQB_Q_SZ; + mem_dma += MV_CRQB_Q_SZ; + + /* Second item: + * 32-slot command response table (CRPB), 8 bytes each in size + */ + pp->crpb = mem; + pp->crpb_dma = mem_dma; + mem += MV_CRPB_Q_SZ; + mem_dma += MV_CRPB_Q_SZ; + + /* Third item: + * Table of scatter-gather descriptors (ePRD), 16 bytes each + */ + pp->sg_tbl = mem; + pp->sg_tbl_dma = mem_dma; + + writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | + EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS); + + writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); + writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, + port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); + writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); + + writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); + writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, + port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + pp->req_producer = pp->rsp_consumer = 0; + + /* Don't turn on EDMA here...do it before DMA commands only. Else + * we'll be unable to send non-data, PIO, etc due to restricted access + * to shadow regs. + */ + ap->private_data = pp; + return 0; +} + +static void mv_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp = ap->private_data; + + mv_stop_dma(ap); + + ap->private_data = NULL; + dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); + kfree(pp); +} + +static void mv_fill_sg(struct ata_queued_cmd *qc) +{ + struct mv_port_priv *pp = qc->ap->private_data; + unsigned int i; + + for (i = 0; i < qc->n_elem; i++) { + u32 sg_len; + dma_addr_t addr; + + addr = sg_dma_address(&qc->sg[i]); + sg_len = sg_dma_len(&qc->sg[i]); + + pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); + pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); + assert(0 == (sg_len & ~MV_DMA_BOUNDARY)); + pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); + } + if (0 < qc->n_elem) { + pp->sg_tbl[qc->n_elem - 1].flags_size |= EPRD_FLAG_END_OF_TBL; + } +} + +static inline unsigned mv_inc_q_index(unsigned *index) +{ + *index = (*index + 1) & MV_MAX_Q_DEPTH_MASK; + return *index; +} + +static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last) +{ + *cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS | + (last ? CRQB_CMD_LAST : 0); +} + +static void mv_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mv_port_priv *pp = ap->private_data; + u16 *cw; + struct ata_taskfile *tf; + u16 flags = 0; + + if (ATA_PROT_DMA != qc->tf.protocol) { + return; } - done: - VPRINTK("EXIT, rc = %i\n", rc); - return rc; + /* the req producer index should be the same as we remember it */ + assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + + /* Fill in command request block + */ + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + flags |= CRQB_FLAG_READ; + } + assert(MV_MAX_Q_DEPTH > qc->tag); + flags |= qc->tag << CRQB_TAG_SHIFT; + + pp->crqb[pp->req_producer].sg_addr = + cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); + pp->crqb[pp->req_producer].sg_addr_hi = + cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); + pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags); + + cw = &pp->crqb[pp->req_producer].ata_cmd[0]; + tf = &qc->tf; + + /* Sadly, the CRQB cannot accomodate all registers--there are + * only 11 bytes...so we must pick and choose required + * registers based on the command. So, we drop feature and + * hob_feature for [RW] DMA commands, but they are needed for + * NCQ. NCQ will drop hob_nsect. + */ + switch (tf->command) { + case ATA_CMD_READ: + case ATA_CMD_READ_EXT: + case ATA_CMD_WRITE: + case ATA_CMD_WRITE_EXT: + mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0); + break; +#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ + case ATA_CMD_FPDMA_READ: + case ATA_CMD_FPDMA_WRITE: + mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); + mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); + break; +#endif /* FIXME: remove this line when NCQ added */ + default: + /* The only other commands EDMA supports in non-queued and + * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none + * of which are defined/used by Linux. If we get here, this + * driver needs work. + * + * FIXME: modify libata to give qc_prep a return value and + * return error here. + */ + BUG_ON(tf->command); + break; + } + mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0); + mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */ + + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) { + return; + } + mv_fill_sg(qc); +} + +static int mv_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *port_mmio = mv_ap_base(qc->ap); + struct mv_port_priv *pp = qc->ap->private_data; + u32 in_ptr; + + if (ATA_PROT_DMA != qc->tf.protocol) { + /* We're about to send a non-EDMA capable command to the + * port. Turn off EDMA so there won't be problems accessing + * shadow block, etc registers. + */ + mv_stop_dma(qc->ap); + return ata_qc_issue_prot(qc); + } + + in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + /* the req producer index should be the same as we remember it */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + /* until we do queuing, the queue should be empty at this point */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); + + mv_inc_q_index(&pp->req_producer); /* now incr producer index */ + + if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { + /* turn on EDMA if not already on */ + mv_start_dma(port_mmio, pp, qc->ap); + } + assert(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); + + /* and write the request in pointer to kick the EDMA to life */ + in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; + in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT; + writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + return 0; +} + +static u8 mv_get_crpb_status(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + u32 out_ptr; + + out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* the response consumer index should be the same as we remember it */ + assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* increment our consumer index... */ + pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer); + + /* and, until we do NCQ, there should only be 1 CRPB waiting */ + assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> + EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* write out our inc'd consumer index so EDMA knows we're caught up */ + out_ptr &= EDMA_RSP_Q_BASE_LO_MASK; + out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT; + writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* Return ATA status register for completed CRPB */ + return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT); } static void mv_err_intr(struct ata_port *ap) { - void __iomem *port_mmio; + void __iomem *port_mmio = mv_ap_base(ap); u32 edma_err_cause, serr = 0; - /* bug here b/c we got an err int on a port we don't know about, - * so there's no way to clear it - */ - BUG_ON(NULL == ap); - port_mmio = mv_ap_base(ap); - edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); if (EDMA_ERR_SERR & edma_err_cause) { @@ -477,8 +933,7 @@ static void mv_err_intr(struct ata_port *ap) } } -/* Handle any outstanding interrupts in a single SATAHC - */ +/* Handle any outstanding interrupts in a single SATAHC */ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, unsigned int hc) { @@ -487,8 +942,8 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, struct ata_port *ap; struct ata_queued_cmd *qc; u32 hc_irq_cause; - int shift, port, port0, hard_port; - u8 ata_status; + int shift, port, port0, hard_port, handled; + u8 ata_status = 0; if (hc == 0) { port0 = 0; @@ -499,7 +954,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, /* we'll need the HC success int register in most cases */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); if (hc_irq_cause) { - writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); + writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); } VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", @@ -508,35 +963,38 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { ap = host_set->ports[port]; hard_port = port & MV_PORT_MASK; /* range 0-3 */ - ata_status = 0xffU; + handled = 0; /* ensure ata_status is set if handled++ */ - if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) { - BUG_ON(NULL == ap); - /* rcv'd new resp, basic DMA complete, or ATA IRQ */ - /* This is needed to clear the ATA INTRQ. - * FIXME: don't read the status reg in EDMA mode! + if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { + /* new CRPB on the queue; just one at a time until NCQ + */ + ata_status = mv_get_crpb_status(ap); + handled++; + } else if ((DEV_IRQ << hard_port) & hc_irq_cause) { + /* received ATA IRQ; read the status reg to clear INTRQ */ ata_status = readb((void __iomem *) ap->ioaddr.status_addr); + handled++; } - shift = port * 2; + shift = port << 1; /* (port * 2) */ if (port >= MV_PORTS_PER_HC) { shift++; /* skip bit 8 in the HC Main IRQ reg */ } if ((PORT0_ERR << shift) & relevant) { mv_err_intr(ap); - /* FIXME: smart to OR in ATA_ERR? */ + /* OR in ATA_ERR to ensure libata knows we took one */ ata_status = readb((void __iomem *) ap->ioaddr.status_addr) | ATA_ERR; + handled++; } - if (ap) { + if (handled && ap) { qc = ata_qc_from_tag(ap, ap->active_tag); if (NULL != qc) { VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); - BUG_ON(0xffU == ata_status); /* mark qc status appropriately */ ata_qc_complete(qc, ata_status); } @@ -550,12 +1008,10 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, { struct ata_host_set *host_set = dev_instance; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio; + void __iomem *mmio = host_set->mmio_base; u32 irq_stat; - mmio = host_set->mmio_base; irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); - n_hcs = mv_get_hc_count(host_set->ports[0]->flags); /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault @@ -564,64 +1020,87 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_NONE; } + n_hcs = mv_get_hc_count(host_set->ports[0]->flags); spin_lock(&host_set->lock); for (hc = 0; hc < n_hcs; hc++) { u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT)); if (relevant) { mv_host_intr(host_set, relevant, hc); - handled = 1; + handled++; } } if (PCI_ERR & irq_stat) { - /* FIXME: these are all masked by default, but still need - * to recover from them properly. - */ - } + printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", + readl(mmio + PCI_IRQ_CAUSE_OFS)); + VPRINTK("All regs @ PCI error\n"); + mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev)); + + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + handled++; + } spin_unlock(&host_set->lock); return IRQ_RETVAL(handled); } +static u8 mv_check_err(struct ata_port *ap) +{ + mv_stop_dma(ap); /* can't read shadow regs if DMA on */ + return readb((void __iomem *) ap->ioaddr.error_addr); +} + +/* Part of this is taken from __sata_phy_reset and modified to not sleep + * since this routine gets called from interrupt level. + */ static void mv_phy_reset(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; - u32 edma = 0, bdma; + unsigned long timeout; VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - edma = readl(port_mmio + EDMA_CMD_OFS); - if (EDMA_EN & edma) { - /* disable EDMA if active */ - edma &= ~EDMA_EN; - writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS); - udelay(1); - } else if (mv_port_bdma_capable(ap) && - (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) { - /* disable BDMA if active */ - writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS); - } + mv_stop_dma(ap); - writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); udelay(25); /* allow reset propagation */ /* Spec never mentions clearing the bit. Marvell's driver does * clear the bit, however. */ - writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(0, port_mmio + EDMA_CMD_OFS); - VPRINTK("Done. Now calling __sata_phy_reset()\n"); + VPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); /* proceed to init communications via the scr_control reg */ - __sata_phy_reset(ap); + scr_write_flush(ap, SCR_CONTROL, 0x301); + mdelay(1); + scr_write_flush(ap, SCR_CONTROL, 0x300); + timeout = jiffies + (HZ * 1); + do { + mdelay(10); + if ((scr_read(ap, SCR_STATUS) & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); - if (ap->flags & ATA_FLAG_PORT_DISABLED) { - VPRINTK("Port disabled pre-sig. Exiting.\n"); + VPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); + + if (sata_dev_present(ap)) { + ata_port_probe(ap); + } else { + printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n", + ap->id, scr_read(ap, SCR_STATUS)); + ata_port_disable(ap); return; } + ap->cbl = ATA_CBL_SATA; tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); @@ -636,28 +1115,76 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("EXIT\n"); } -static void mv_port_init(struct ata_ioports *port, unsigned long base) +static void mv_eng_timeout(struct ata_port *ap) { - /* PIO related setup */ - port->data_addr = base + SHD_PIO_DATA_OFS; - port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS; - port->nsect_addr = base + SHD_SECT_CNT_OFS; - port->lbal_addr = base + SHD_LBA_L_OFS; - port->lbam_addr = base + SHD_LBA_M_OFS; - port->lbah_addr = base + SHD_LBA_H_OFS; - port->device_addr = base + SHD_DEV_HD_OFS; - port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS; - port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS; - /* unused */ + struct ata_queued_cmd *qc; + unsigned long flags; + + printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id); + DPRINTK("All regs @ start of eng_timeout\n"); + mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, + to_pci_dev(ap->host_set->dev)); + + qc = ata_qc_from_tag(ap, ap->active_tag); + printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", + ap->host_set->mmio_base, ap, qc, qc->scsicmd, + &qc->scsicmd->cmnd); + + mv_err_intr(ap); + mv_phy_reset(ap); + + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + } else { + /* hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, ATA_ERR); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } +} + +static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) +{ + unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; + unsigned serr_ofs; + + /* PIO related setup + */ + port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); + port->error_addr = + port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR); + port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT); + port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL); + port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM); + port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH); + port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE); + port->status_addr = + port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS); + /* special case: control/altstatus doesn't have ATA_REG_ address */ + port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; + + /* unused: */ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0; + /* Clear any currently outstanding port interrupt conditions */ + serr_ofs = mv_scr_offset(SCR_ERROR); + writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); + writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + /* unmask all EDMA error interrupts */ - writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS); + writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", - readl((void __iomem *)base + EDMA_CFG_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS)); + readl(port_mmio + EDMA_CFG_OFS), + readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS), + readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } static int mv_host_init(struct ata_probe_ent *probe_ent) @@ -666,7 +1193,8 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) void __iomem *mmio = probe_ent->mmio_base; void __iomem *port_mmio; - if (mv_master_reset(probe_ent->mmio_base)) { + if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && + mv_global_soft_reset(probe_ent->mmio_base)) { rc = 1; goto done; } @@ -676,17 +1204,27 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) for (port = 0; port < probe_ent->n_ports; port++) { port_mmio = mv_port_base(mmio, port); - mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio); + mv_port_init(&probe_ent->port[port], port_mmio); } for (hc = 0; hc < n_hc; hc++) { - VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc, - readl(mv_hc_base(mmio, hc) + HC_CFG_OFS), - readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS)); + void __iomem *hc_mmio = mv_hc_base(mmio, hc); + + VPRINTK("HC%i: HC config=0x%08x HC IRQ cause " + "(before clear)=0x%08x\n", hc, + readl(hc_mmio + HC_CFG_OFS), + readl(hc_mmio + HC_IRQ_CAUSE_OFS)); + + /* Clear any currently outstanding hc interrupt conditions */ + writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); - writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + /* Clear any currently outstanding host interrupt conditions */ + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + + /* and unmask interrupt generation for host regs */ + writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", @@ -694,11 +1232,37 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + PCI_IRQ_CAUSE_OFS), readl(mmio + PCI_IRQ_MASK_OFS)); - - done: +done: return rc; } +/* FIXME: complete this */ +static void mv_print_info(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + struct mv_host_priv *hpriv = probe_ent->private_data; + u8 rev_id, scc; + const char *scc_s; + + /* Use this to determine the HW stepping of the chip so we know + * what errata to workaround + */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + + pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc); + if (scc == 0) + scc_s = "SCSI"; + else if (scc == 0x01) + scc_s = "RAID"; + else + scc_s = "unknown"; + + printk(KERN_INFO DRV_NAME + "(%s) %u slots %u ports %s mode IRQ via %s\n", + pci_name(pdev), (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, + scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); +} + static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -706,16 +1270,12 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mv_host_priv *hpriv; unsigned int board_idx = (unsigned int)ent->driver_data; void __iomem *mmio_base; - int pci_dev_busy = 0; - int rc; + int pci_dev_busy = 0, rc; if (!printed_version++) { - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME " version " DRV_VERSION "\n"); } - VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - rc = pci_enable_device(pdev); if (rc) { return rc; @@ -727,8 +1287,6 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out; } - pci_intx(pdev, 1); - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { rc = -ENOMEM; @@ -739,8 +1297,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR), - pci_resource_len(pdev, MV_PRIMARY_BAR)); + mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -769,37 +1326,40 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_out_hpriv; } -/* mv_print_info(probe_ent); */ - { - int b, w; - u32 dw[4]; /* hold a line of 16b */ - VPRINTK("PCI config space:\n"); - for (b = 0; b < 0x40; ) { - for (w = 0; w < 4; w++) { - (void) pci_read_config_dword(pdev,b,&dw[w]); - b += sizeof(*dw); - } - VPRINTK("%08x %08x %08x %08x\n", - dw[0],dw[1],dw[2],dw[3]); - } + /* Enable interrupts */ + if (pci_enable_msi(pdev) == 0) { + hpriv->hp_flags |= MV_HP_FLAG_MSI; + } else { + pci_intx(pdev, 1); } - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + mv_dump_pci_cfg(pdev, 0x68); + mv_print_info(probe_ent); + if (ata_device_add(probe_ent) == 0) { + rc = -ENODEV; /* No devices discovered */ + goto err_out_dev_add; + } + + kfree(probe_ent); return 0; - err_out_hpriv: +err_out_dev_add: + if (MV_HP_FLAG_MSI & hpriv->hp_flags) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } +err_out_hpriv: kfree(hpriv); - err_out_iounmap: - iounmap(mmio_base); - err_out_free_ent: +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_free_ent: kfree(probe_ent); - err_out_regions: +err_out_regions: pci_release_regions(pdev); - err_out: +err_out: if (!pci_dev_busy) { pci_disable_device(pdev); } From fe998aa7e27f125f6768ec6b137b0ce2c9790509 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Oct 2005 11:54:29 +0900 Subject: [PATCH 0262/1939] [PATCH] libata: add ATA exceptions chapter to doc Hello, Jeff. This patch adds ATA errors & exceptions chapter to Documentation/DocBook/libata.tmpl. As suggested, the chapter is placed before low level driver specific chapters. Contents are unchanged from the last posting. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- Documentation/DocBook/libata.tmpl | 716 ++++++++++++++++++++++++++++++ 1 file changed, 716 insertions(+) diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index b2ec780bcda1..d260d92089ad 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -787,6 +787,722 @@ and other resources, etc. !Idrivers/scsi/libata-scsi.c + + ATA errors & exceptions + + + This chapter tries to identify what error/exception conditions exist + for ATA/ATAPI devices and describe how they should be handled in + implementation-neutral way. + + + + The term 'error' is used to describe conditions where either an + explicit error condition is reported from device or a command has + timed out. + + + + The term 'exception' is either used to describe exceptional + conditions which are not errors (say, power or hotplug events), or + to describe both errors and non-error exceptional conditions. Where + explicit distinction between error and exception is necessary, the + term 'non-error exception' is used. + + + + Exception categories + + Exceptions are described primarily with respect to legacy + taskfile + bus master IDE interface. If a controller provides + other better mechanism for error reporting, mapping those into + categories described below shouldn't be difficult. + + + + In the following sections, two recovery actions - reset and + reconfiguring transport - are mentioned. These are described + further in . + + + + HSM violation + + This error is indicated when STATUS value doesn't match HSM + requirement during issuing or excution any ATA/ATAPI command. + + + + Examples + + + + ATA_STATUS doesn't contain !BSY && DRDY && !DRQ while trying + to issue a command. + + + + + + !BSY && !DRQ during PIO data transfer. + + + + + + DRQ on command completion. + + + + + + !BSY && ERR after CDB tranfer starts but before the + last byte of CDB is transferred. ATA/ATAPI standard states + that "The device shall not terminate the PACKET command + with an error before the last byte of the command packet has + been written" in the error outputs description of PACKET + command and the state diagram doesn't include such + transitions. + + + + + + + In these cases, HSM is violated and not much information + regarding the error can be acquired from STATUS or ERROR + register. IOW, this error can be anything - driver bug, + faulty device, controller and/or cable. + + + + As HSM is violated, reset is necessary to restore known state. + Reconfiguring transport for lower speed might be helpful too + as transmission errors sometimes cause this kind of errors. + + + + + ATA/ATAPI device error (non-NCQ / non-CHECK CONDITION) + + + These are errors detected and reported by ATA/ATAPI devices + indicating device problems. For this type of errors, STATUS + and ERROR register values are valid and describe error + condition. Note that some of ATA bus errors are detected by + ATA/ATAPI devices and reported using the same mechanism as + device errors. Those cases are described later in this + section. + + + + For ATA commands, this type of errors are indicated by !BSY + && ERR during command execution and on completion. + + + For ATAPI commands, + + + + + + !BSY && ERR && ABRT right after issuing PACKET + indicates that PACKET command is not supported and falls in + this category. + + + + + + !BSY && ERR(==CHK) && !ABRT after the last + byte of CDB is transferred indicates CHECK CONDITION and + doesn't fall in this category. + + + + + + !BSY && ERR(==CHK) && ABRT after the last byte + of CDB is transferred *probably* indicates CHECK CONDITION and + doesn't fall in this category. + + + + + + + Of errors detected as above, the followings are not ATA/ATAPI + device errors but ATA bus errors and should be handled + according to . + + + + + + CRC error during data transfer + + + This is indicated by ICRC bit in the ERROR register and + means that corruption occurred during data transfer. Upto + ATA/ATAPI-7, the standard specifies that this bit is only + applicable to UDMA transfers but ATA/ATAPI-8 draft revision + 1f says that the bit may be applicable to multiword DMA and + PIO. + + + + + + ABRT error during data transfer or on completion + + + Upto ATA/ATAPI-7, the standard specifies that ABRT could be + set on ICRC errors and on cases where a device is not able + to complete a command. Combined with the fact that MWDMA + and PIO transfer errors aren't allowed to use ICRC bit upto + ATA/ATAPI-7, it seems to imply that ABRT bit alone could + indicate tranfer errors. + + + However, ATA/ATAPI-8 draft revision 1f removes the part + that ICRC errors can turn on ABRT. So, this is kind of + gray area. Some heuristics are needed here. + + + + + + + + ATA/ATAPI device errors can be further categorized as follows. + + + + + + Media errors + + + This is indicated by UNC bit in the ERROR register. ATA + devices reports UNC error only after certain number of + retries cannot recover the data, so there's nothing much + else to do other than notifying upper layer. + + + READ and WRITE commands report CHS or LBA of the first + failed sector but ATA/ATAPI standard specifies that the + amount of transferred data on error completion is + indeterminate, so we cannot assume that sectors preceding + the failed sector have been transferred and thus cannot + complete those sectors successfully as SCSI does. + + + + + + Media changed / media change requested error + + + <<TODO: fill here>> + + + + + Address error + + + This is indicated by IDNF bit in the ERROR register. + Report to upper layer. + + + + + Other errors + + + This can be invalid command or parameter indicated by ABRT + ERROR bit or some other error condition. Note that ABRT + bit can indicate a lot of things including ICRC and Address + errors. Heuristics needed. + + + + + + + + Depending on commands, not all STATUS/ERROR bits are + applicable. These non-applicable bits are marked with + "na" in the output descriptions but upto ATA/ATAPI-7 + no definition of "na" can be found. However, + ATA/ATAPI-8 draft revision 1f describes "N/A" as + follows. + + +
+ + 3.2.3.3a N/A + + + A keyword the indicates a field has no defined value in + this standard and should not be checked by the host or + device. N/A fields should be cleared to zero. + + + + +
+ + + So, it seems reasonable to assume that "na" bits are + cleared to zero by devices and thus need no explicit masking. + + +
+ + + ATAPI device CHECK CONDITION + + + ATAPI device CHECK CONDITION error is indicated by set CHK bit + (ERR bit) in the STATUS register after the last byte of CDB is + transferred for a PACKET command. For this kind of errors, + sense data should be acquired to gather information regarding + the errors. REQUEST SENSE packet command should be used to + acquire sense data. + + + + Once sense data is acquired, this type of errors can be + handled similary to other SCSI errors. Note that sense data + may indicate ATA bus error (e.g. Sense Key 04h HARDWARE ERROR + && ASC/ASCQ 47h/00h SCSI PARITY ERROR). In such + cases, the error should be considered as an ATA bus error and + handled according to . + + + + + + ATA device error (NCQ) + + + NCQ command error is indicated by cleared BSY and set ERR bit + during NCQ command phase (one or more NCQ commands + outstanding). Although STATUS and ERROR registers will + contain valid values describing the error, READ LOG EXT is + required to clear the error condition, determine which command + has failed and acquire more information. + + + + READ LOG EXT Log Page 10h reports which tag has failed and + taskfile register values describing the error. With this + information the failed command can be handled as a normal ATA + command error as in and all + other in-flight commands must be retried. Note that this + retry should not be counted - it's likely that commands + retried this way would have completed normally if it were not + for the failed command. + + + + Note that ATA bus errors can be reported as ATA device NCQ + errors. This should be handled as described in . + + + + If READ LOG EXT Log Page 10h fails or reports NQ, we're + thoroughly screwed. This condition should be treated + according to . + + + + + + ATA bus error + + + ATA bus error means that data corruption occurred during + transmission over ATA bus (SATA or PATA). This type of errors + can be indicated by + + + + + + + ICRC or ABRT error as described in . + + + + + + Controller-specific error completion with error information + indicating transmission error. + + + + + + On some controllers, command timeout. In this case, there may + be a mechanism to determine that the timeout is due to + transmission error. + + + + + + Unknown/random errors, timeouts and all sorts of weirdities. + + + + + + + As described above, transmission errors can cause wide variety + of symptoms ranging from device ICRC error to random device + lockup, and, for many cases, there is no way to tell if an + error condition is due to transmission error or not; + therefore, it's necessary to employ some kind of heuristic + when dealing with errors and timeouts. For example, + encountering repetitive ABRT errors for known supported + command is likely to indicate ATA bus error. + + + + Once it's determined that ATA bus errors have possibly + occurred, lowering ATA bus transmission speed is one of + actions which may alleviate the problem. See for more information. + + + + + + PCI bus error + + + Data corruption or other failures during transmission over PCI + (or other system bus). For standard BMDMA, this is indicated + by Error bit in the BMDMA Status register. This type of + errors must be logged as it indicates something is very wrong + with the system. Resetting host controller is recommended. + + + + + + Late completion + + + This occurs when timeout occurs and the timeout handler finds + out that the timed out command has completed successfully or + with error. This is usually caused by lost interrupts. This + type of errors must be logged. Resetting host controller is + recommended. + + + + + + Unknown error (timeout) + + + This is when timeout occurs and the command is still + processing or the host and device are in unknown state. When + this occurs, HSM could be in any valid or invalid state. To + bring the device to known state and make it forget about the + timed out command, resetting is necessary. The timed out + command may be retried. + + + + Timeouts can also be caused by transmission errors. Refer to + for more details. + + + + + + Hotplug and power management exceptions + + + <<TODO: fill here>> + + + + +
+ + + EH recovery actions + + + This section discusses several important recovery actions. + + + + Clearing error condition + + + Many controllers require its error registers to be cleared by + error handler. Different controllers may have different + requirements. + + + + For SATA, it's strongly recommended to clear at least SError + register during error handling. + + + + + Reset + + + During EH, resetting is necessary in the following cases. + + + + + + + HSM is in unknown or invalid state + + + + + + HBA is in unknown or invalid state + + + + + + EH needs to make HBA/device forget about in-flight commands + + + + + + HBA/device behaves weirdly + + + + + + + Resetting during EH might be a good idea regardless of error + condition to improve EH robustness. Whether to reset both or + either one of HBA and device depends on situation but the + following scheme is recommended. + + + + + + + When it's known that HBA is in ready state but ATA/ATAPI + device in in unknown state, reset only device. + + + + + + If HBA is in unknown state, reset both HBA and device. + + + + + + + HBA resetting is implementation specific. For a controller + complying to taskfile/BMDMA PCI IDE, stopping active DMA + transaction may be sufficient iff BMDMA state is the only HBA + context. But even mostly taskfile/BMDMA PCI IDE complying + controllers may have implementation specific requirements and + mechanism to reset themselves. This must be addressed by + specific drivers. + + + + OTOH, ATA/ATAPI standard describes in detail ways to reset + ATA/ATAPI devices. + + + + + PATA hardware reset + + + This is hardware initiated device reset signalled with + asserted PATA RESET- signal. There is no standard way to + initiate hardware reset from software although some + hardware provides registers that allow driver to directly + tweak the RESET- signal. + + + + + Software reset + + + This is achieved by turning CONTROL SRST bit on for at + least 5us. Both PATA and SATA support it but, in case of + SATA, this may require controller-specific support as the + second Register FIS to clear SRST should be transmitted + while BSY bit is still set. Note that on PATA, this resets + both master and slave devices on a channel. + + + + + EXECUTE DEVICE DIAGNOSTIC command + + + Although ATA/ATAPI standard doesn't describe exactly, EDD + implies some level of resetting, possibly similar level + with software reset. Host-side EDD protocol can be handled + with normal command processing and most SATA controllers + should be able to handle EDD's just like other commands. + As in software reset, EDD affects both devices on a PATA + bus. + + + Although EDD does reset devices, this doesn't suit error + handling as EDD cannot be issued while BSY is set and it's + unclear how it will act when device is in unknown/weird + state. + + + + + ATAPI DEVICE RESET command + + + This is very similar to software reset except that reset + can be restricted to the selected device without affecting + the other device sharing the cable. + + + + + SATA phy reset + + + This is the preferred way of resetting a SATA device. In + effect, it's identical to PATA hardware reset. Note that + this can be done with the standard SCR Control register. + As such, it's usually easier to implement than software + reset. + + + + + + + + One more thing to consider when resetting devices is that + resetting clears certain configuration parameters and they + need to be set to their previous or newly adjusted values + after reset. + + + + Parameters affected are. + + + + + + + CHS set up with INITIALIZE DEVICE PARAMETERS (seldomly used) + + + + + + Parameters set with SET FEATURES including transfer mode setting + + + + + + Block count set with SET MULTIPLE MODE + + + + + + Other parameters (SET MAX, MEDIA LOCK...) + + + + + + + ATA/ATAPI standard specifies that some parameters must be + maintained across hardware or software reset, but doesn't + strictly specify all of them. Always reconfiguring needed + parameters after reset is required for robustness. Note that + this also applies when resuming from deep sleep (power-off). + + + + Also, ATA/ATAPI standard requires that IDENTIFY DEVICE / + IDENTIFY PACKET DEVICE is issued after any configuration + parameter is updated or a hardware reset and the result used + for further operation. OS driver is required to implement + revalidation mechanism to support this. + + + + + + Reconfigure transport + + + For both PATA and SATA, a lot of corners are cut for cheap + connectors, cables or controllers and it's quite common to see + high transmission error rate. This can be mitigated by + lowering transmission speed. + + + + The following is a possible scheme Jeff Garzik suggested. + + +
+ + If more than $N (3?) transmission errors happen in 15 minutes, + + + + + if SATA, decrease SATA PHY speed. if speed cannot be decreased, + + + + + decrease UDMA xfer speed. if at UDMA0, switch to PIO4, + + + + + decrease PIO xfer speed. if at PIO3, complain, but continue + + + +
+ +
+ +
+ +
+ ata_piix Internals !Idrivers/scsi/ata_piix.c From dd8cad6be2822c7df4ecc5eba12903ba43e09f06 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 4 Oct 2005 14:28:29 +1000 Subject: [PATCH 0263/1939] ppc32: export a few more things where they are defined ... and remove the exports from ppc_ksyms.c. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/pci.c | 3 +++ arch/ppc/kernel/ppc_ksyms.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 2d3c557538b5..b5cf52f5909e 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -813,12 +813,14 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) /* Now, lookup childs of the hose */ return scan_OF_childs_for_device(node->child, busnr, devfn); } +EXPORT_SYMBOL(pci_busdev_to_OF_node); struct device_node* pci_device_to_OF_node(struct pci_dev *dev) { return pci_busdev_to_OF_node(dev->bus, dev->devfn); } +EXPORT_SYMBOL(pci_device_to_OF_node); /* This routine is meant to be used early during boot, when the * PCI bus numbers have not yet been assigned, and you need to @@ -890,6 +892,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) } return -ENODEV; } +EXPORT_SYMBOL(pci_device_from_OF_node); void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 7872c6c45732..f4373fb9181f 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -230,9 +230,6 @@ EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(request_OF_resource); EXPORT_SYMBOL(release_OF_resource); -EXPORT_SYMBOL(pci_busdev_to_OF_node); -EXPORT_SYMBOL(pci_device_to_OF_node); -EXPORT_SYMBOL(pci_device_from_OF_node); EXPORT_SYMBOL(of_find_node_by_name); EXPORT_SYMBOL(of_find_node_by_type); EXPORT_SYMBOL(of_find_compatible_node); From 6ce52e6438fd2921891648ceab700d9b867e5ed2 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 4 Oct 2005 14:30:07 +1000 Subject: [PATCH 0264/1939] ppc32: remove obsolete klock_info definition klock_info isn't used or referenced anywhere else in the kernel. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/smp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 726fe7ce1747..a8cc96b0d332 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -38,7 +38,6 @@ volatile int smp_commenced; int smp_tb_synchronized; struct cpuinfo_PPC cpu_data[NR_CPUS]; -struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; atomic_t ipi_recv; atomic_t ipi_sent; cpumask_t cpu_online_map; From cc6e7c44f4b8ab13acf5521cd4b312848122179f Mon Sep 17 00:00:00 2001 From: Ravinandan Arakali Date: Tue, 4 Oct 2005 06:41:24 -0400 Subject: [PATCH 0265/1939] [PATCH] S2io: MSI/MSI-X support (runtime configurable) This patch adds support for MSI/MSI-X feature to the driver. It is a runtime parameter(for now, loadable parameter). Default is INTA. Patch has been tested on IA64 platform with Xframe II adapter, both of which support MSI-X feature. An improvement of about 7% in throughput(both Tx and Rx) was observed and a reduction by 7% in CPU utilization during Tx test. Signed-off-by: Ravinandan Arakali Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 543 ++++++++++++++++++++++++++++++++++++++++++--- drivers/net/s2io.h | 50 ++++- 2 files changed, 556 insertions(+), 37 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd451e099a4c..4b9f1828845e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -67,7 +67,7 @@ /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; -static char s2io_driver_version[] = "Version 2.0.8.1"; +static char s2io_driver_version[] = "Version 2.0.9.1"; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -307,6 +307,8 @@ static unsigned int indicate_max_pkts; #endif /* Frequency of Rx desc syncs expressed as power of 2 */ static unsigned int rxsync_frequency = 3; +/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ +static unsigned int intr_type = 0; /* * S2IO device table. @@ -1396,8 +1398,13 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->rti_data1_mem); val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) | - RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); + RTI_DATA2_MEM_RX_UFC_B(0x2) ; + if (nic->intr_type == MSI_X) + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ + RTI_DATA2_MEM_RX_UFC_D(0x40)); + else + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ + RTI_DATA2_MEM_RX_UFC_D(0x80)); writeq(val64, &bar0->rti_data2_mem); for (i = 0; i < config->rx_ring_num; i++) { @@ -1507,17 +1514,15 @@ static int init_nic(struct s2io_nic *nic) #define LINK_UP_DOWN_INTERRUPT 1 #define MAC_RMAC_ERR_TIMER 2 -#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) -#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER -#else int s2io_link_fault_indication(nic_t *nic) { + if (nic->intr_type != INTA) + return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; else return MAC_RMAC_ERR_TIMER; } -#endif /** * en_dis_able_nic_intrs - Enable or Disable the interrupts @@ -1941,11 +1946,14 @@ static int start_nic(struct s2io_nic *nic) } /* Enable select interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; - - en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + if (nic->intr_type != INTA) + en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS); + else { + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; + en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + } /* * With some switches, link might be already up at this point. @@ -2633,11 +2641,11 @@ static void tx_intr_handler(fifo_info_t *fifo_data) err = txdlp->Control_1 & TXD_T_CODE; if ((err >> 48) == 0xA) { DBG_PRINT(TX_DBG, "TxD returned due \ - to loss of link\n"); +to loss of link\n"); } else { DBG_PRINT(ERR_DBG, "***TxD error \ - %llx\n", err); +%llx\n", err); } } @@ -2854,6 +2862,9 @@ void s2io_reset(nic_t * sp) /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); + /* Restore the MSIX table entries from local variables */ + restore_xmsi_data(sp); + /* Clear certain PCI/PCI-X fields after reset */ if (sp->device_type == XFRAME_II_DEVICE) { /* Clear parity err detect bit */ @@ -2983,8 +2994,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_FE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (nic->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else /* @@ -3005,8 +3017,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_SE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (sp->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #endif val64 = readq(&bar0->swapper_ctrl); @@ -3028,6 +3041,201 @@ int s2io_set_swapper(nic_t * sp) return SUCCESS; } +int wait_for_msix_trans(nic_t *nic, int i) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int ret = 0, cnt = 0; + + do { + val64 = readq(&bar0->xmsi_access); + if (!(val64 & BIT(15))) + break; + mdelay(1); + cnt++; + } while(cnt < 5); + if (cnt == 5) { + DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); + ret = 1; + } + + return ret; +} + +void restore_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int i; + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + writeq(nic->msix_info[i].addr, &bar0->xmsi_address); + writeq(nic->msix_info[i].data, &bar0->xmsi_data); + val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + } +} + +void store_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64, addr, data; + int i; + + /* Store and display */ + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + val64 = (BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + addr = readq(&bar0->xmsi_address); + data = readq(&bar0->xmsi_data); + if (addr && data) { + nic->msix_info[i].addr = addr; + nic->msix_info[i].data = data; + } + } +} + +int s2io_enable_msi(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u16 msi_ctrl, msg_val; + struct config_param *config = &nic->config; + struct net_device *dev = nic->dev; + u64 val64, tx_mat, rx_mat; + int i, err; + + val64 = readq(&bar0->pic_control); + val64 &= ~BIT(1); + writeq(val64, &bar0->pic_control); + + err = pci_enable_msi(nic->pdev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n", + nic->dev->name); + return err; + } + + /* + * Enable MSI and use MSI-1 in stead of the standard MSI-0 + * for interrupt handling. + */ + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + msg_val ^= 0x1; + pci_write_config_word(nic->pdev, 0x4c, msg_val); + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + + pci_read_config_word(nic->pdev, 0x42, &msi_ctrl); + msi_ctrl |= 0x10; + pci_write_config_word(nic->pdev, 0x42, msi_ctrl); + + /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */ + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; itx_fifo_num; i++) { + tx_mat |= TX_MAT_SET(i, 1); + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + rx_mat = readq(&bar0->rx_mat); + for (i=0; irx_ring_num; i++) { + rx_mat |= RX_MAT_SET(i, 1); + } + writeq(rx_mat, &bar0->rx_mat); + + dev->irq = nic->pdev->irq; + return 0; +} + +int s2io_enable_msi_x(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 tx_mat, rx_mat; + u16 msi_control; /* Temp variable */ + int ret, i, j, msix_indx = 1; + + nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), + GFP_KERNEL); + if (nic->entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + return -ENOMEM; + } + memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); + + nic->s2io_entries = + kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), + GFP_KERNEL); + if (nic->s2io_entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + kfree(nic->entries); + return -ENOMEM; + } + memset(nic->s2io_entries, 0, + MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + nic->entries[i].entry = i; + nic->s2io_entries[i].entry = i; + nic->s2io_entries[i].arg = NULL; + nic->s2io_entries[i].in_use = 0; + } + + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; iconfig.tx_fifo_num; i++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i]; + nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + if (!nic->config.bimodal) { + rx_mat = readq(&bar0->rx_mat); + for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { + rx_mat |= RX_MAT_SET(j, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(rx_mat, &bar0->rx_mat); + } else { + tx_mat = readq(&bar0->tx_mat0_n[7]); + for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[7]); + } + + ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); + kfree(nic->entries); + kfree(nic->s2io_entries); + nic->entries = NULL; + nic->s2io_entries = NULL; + return -ENOMEM; + } + + /* + * To enable MSI-X, MSI also needs to be enabled, due to a bug + * in the herc NIC. (Temp change, needs to be removed later) + */ + pci_read_config_word(nic->pdev, 0x42, &msi_control); + msi_control |= 0x1; /* Enable MSI */ + pci_write_config_word(nic->pdev, 0x42, msi_control); + + return 0; +} + /* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* */ @@ -3048,6 +3256,8 @@ int s2io_open(struct net_device *dev) { nic_t *sp = dev->priv; int err = 0; + int i; + u16 msi_control; /* Temp variable */ /* * Make sure you have link off by default every time @@ -3064,13 +3274,55 @@ int s2io_open(struct net_device *dev) goto hw_init_failed; } + /* Store the values of the MSIX table in the nic_t structure */ + store_xmsi_data(sp); + /* After proper initialization of H/W, register ISR */ - err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, - sp->name, dev); - if (err) { - DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", - dev->name); - goto isr_registration_failed; + if (sp->intr_type == MSI) { + err = request_irq((int) sp->pdev->irq, s2io_msi_handle, + SA_SHIRQ, sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI registration \ +failed\n", dev->name); + goto isr_registration_failed; + } + } + if (sp->intr_type == MSI_X) { + for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { + if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) { + sprintf(sp->desc1, "%s:MSI-X-%d-TX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_fifo_handle, 0, sp->desc1, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1, + sp->msix_info[i].addr); + } else { + sprintf(sp->desc2, "%s:MSI-X-%d-RX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_ring_handle, 0, sp->desc2, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2, + sp->msix_info[i].addr); + } + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \ +failed\n", dev->name, i); + DBG_PRINT(ERR_DBG, "Returned: %d\n", err); + goto isr_registration_failed; + } + sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; + } + } + if (sp->intr_type == INTA) { + err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, + sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", + dev->name); + goto isr_registration_failed; + } } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { @@ -3083,11 +3335,37 @@ int s2io_open(struct net_device *dev) return 0; setting_mac_address_failed: - free_irq(sp->pdev->irq, dev); + if (sp->intr_type != MSI_X) + free_irq(sp->pdev->irq, dev); isr_registration_failed: del_timer_sync(&sp->alarm_timer); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_disable_msix(sp->pdev); + + /* Temp */ + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + } + } + else if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); s2io_reset(sp); hw_init_failed: + if (sp->intr_type == MSI_X) { + if (sp->entries) + kfree(sp->entries); + if (sp->s2io_entries) + kfree(sp->s2io_entries); + } return err; } @@ -3107,12 +3385,35 @@ int s2io_open(struct net_device *dev) int s2io_close(struct net_device *dev) { nic_t *sp = dev->priv; + int i; + u16 msi_control; + flush_scheduled_work(); netif_stop_queue(dev); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); - free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + + pci_disable_msix(sp->pdev); + } + } + else { + free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); + } sp->device_close_flag = TRUE; /* Device is shut down. */ return 0; } @@ -3278,6 +3579,104 @@ s2io_alarm_handle(unsigned long data) mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } +static irqreturn_t +s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + nic_t *sp = dev->priv; + int i; + int ret; + mac_info_t *mac_control; + struct config_param *config; + + atomic_inc(&sp->isr_cnt); + mac_control = &sp->mac_control; + config = &sp->config; + DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__); + + /* If Intr is because of Rx Traffic */ + for (i = 0; i < config->rx_ring_num; i++) + rx_intr_handler(&mac_control->rings[i]); + + /* If Intr is because of Tx Traffic */ + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + + /* + * If the Rx buffer count is below the panic threshold then + * reallocate the buffers from the interrupt handler itself, + * else schedule a tasklet to reallocate the buffers. + */ + for (i = 0; i < config->rx_ring_num; i++) { + int rxb_size = atomic_read(&sp->rx_bufs_left[i]); + int level = rx_buffer_level(sp, rxb_size, i); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in ISR!!\n"); + clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + } + + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + ring_info_t *ring = (ring_info_t *)dev_id; + nic_t *sp = ring->nic; + int rxb_size, level, rng_n; + + atomic_inc(&sp->isr_cnt); + rx_intr_handler(ring); + + rng_n = ring->ring_no; + rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); + level = rx_buffer_level(sp, rxb_size, rng_n); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + int ret; + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "Out of memory in %s", + __FUNCTION__); + clear_bit(0, (&sp->tasklet_status)); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + atomic_dec(&sp->isr_cnt); + + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + fifo_info_t *fifo = (fifo_info_t *)dev_id; + nic_t *sp = fifo->nic; + + atomic_inc(&sp->isr_cnt); + tx_intr_handler(fifo); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + static void s2io_txpic_intr_handle(nic_t *sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; @@ -4932,7 +5331,7 @@ static void s2io_card_down(nic_t * sp) static int s2io_card_up(nic_t * sp) { - int i, ret; + int i, ret = 0; mac_info_t *mac_control; struct config_param *config; struct net_device *dev = (struct net_device *) sp->dev; @@ -4944,6 +5343,15 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } + if (sp->intr_type == MSI) + ret = s2io_enable_msi(sp); + else if (sp->intr_type == MSI_X) + ret = s2io_enable_msi_x(sp); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); + sp->intr_type = INTA; + } + /* * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks @@ -5245,6 +5653,7 @@ module_param(bimodal, bool, 0); module_param(indicate_max_pkts, int, 0); #endif module_param(rxsync_frequency, int, 0); +module_param(intr_type, int, 0); /** * s2io_init_nic - Initialization of the adapter . @@ -5274,9 +5683,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mac_info_t *mac_control; struct config_param *config; int mode; + u8 dev_intr_type = intr_type; #ifdef CONFIG_S2IO_NAPI - DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); + if (dev_intr_type != INTA) { + DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \ +is enabled. Defaulting to INTA\n"); + dev_intr_type = INTA; + } + else + DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); #endif if ((ret = pci_enable_device(pdev))) { @@ -5303,10 +5719,35 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } - if (pci_request_regions(pdev, s2io_driver_name)) { - DBG_PRINT(ERR_DBG, "Request Regions failed\n"), - pci_disable_device(pdev); - return -ENODEV; + if ((dev_intr_type == MSI_X) && + ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && + (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { + DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \ +Defaulting to INTA\n"); + dev_intr_type = INTA; + } + if (dev_intr_type != MSI_X) { + if (pci_request_regions(pdev, s2io_driver_name)) { + DBG_PRINT(ERR_DBG, "Request Regions failed\n"), + pci_disable_device(pdev); + return -ENODEV; + } + } + else { + if (!(request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n"); + pci_disable_device(pdev); + return -ENODEV; + } + if (!(request_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n"); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + pci_disable_device(pdev); + return -ENODEV; + } } dev = alloc_etherdev(sizeof(nic_t)); @@ -5329,6 +5770,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->pdev = pdev; sp->high_dma_flag = dma_flag; sp->device_enabled_once = FALSE; + sp->intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || (pdev->device == PCI_DEVICE_ID_HERC_UNI)) @@ -5336,6 +5778,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) else sp->device_type = XFRAME_I_DEVICE; + /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -5577,6 +6020,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -5601,6 +6055,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", sp->def_mac_addr[0].mac_addr[0], @@ -5644,7 +6109,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mem_alloc_failed: free_shared_mem(sp); pci_disable_device(pdev); - pci_release_regions(pdev); + if (dev_intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); @@ -5678,7 +6150,14 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) iounmap(sp->bar0); iounmap(sp->bar1); pci_disable_device(pdev); - pci_release_regions(pdev); + if (sp->intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 89151cb52181..1cc24b56760e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -652,6 +652,30 @@ typedef struct { #define SMALL_BLK_CNT 30 #define LARGE_BLK_CNT 100 +/* + * Structure to keep track of the MSI-X vectors and the corresponding + * argument registered against each vector + */ +#define MAX_REQUESTED_MSI_X 17 +struct s2io_msix_entry +{ + u16 vector; + u16 entry; + void *arg; + + u8 type; +#define MSIX_FIFO_TYPE 1 +#define MSIX_RING_TYPE 2 + + u8 in_use; +#define MSIX_REGISTERED_SUCCESS 0xAA +}; + +struct msix_info_st { + u64 addr; + u64 data; +}; + /* Structure representing one instance of the NIC */ struct s2io_nic { #ifdef CONFIG_S2IO_NAPI @@ -719,13 +743,8 @@ struct s2io_nic { * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. */ -#ifdef INIT_TQUEUE - struct tq_struct rst_timer_task; - struct tq_struct set_link_task; -#else struct work_struct rst_timer_task; struct work_struct set_link_task; -#endif /* Flag that can be used to turn on or turn off the Rx checksum * offload feature. @@ -748,10 +767,23 @@ struct s2io_nic { atomic_t card_state; volatile unsigned long link_state; struct vlan_group *vlgrp; +#define MSIX_FLG 0xA5 + struct msix_entry *entries; + struct s2io_msix_entry *s2io_entries; + char desc1[35]; + char desc2[35]; + + struct msix_info_st msix_info[0x3f]; + #define XFRAME_I_DEVICE 1 #define XFRAME_II_DEVICE 2 u8 device_type; +#define INTA 0 +#define MSI 1 +#define MSI_X 2 + u8 intr_type; + spinlock_t rx_lock; atomic_t isr_cnt; }; @@ -886,6 +918,13 @@ static int s2io_poll(struct net_device *dev, int *budget); static void s2io_init_pci(nic_t * sp); int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); +static int s2io_enable_msi(nic_t *nic); +static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs); +int s2io_enable_msi_x(nic_t *nic); static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; @@ -894,4 +933,5 @@ int s2io_set_swapper(nic_t * sp); static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); int get_xena_rev_id(struct pci_dev *pdev); +void restore_xmsi_data(nic_t *nic); #endif /* _S2IO_H */ From 868d5309942927dc86f57009420c5d366ec05daa Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 06:58:59 -0400 Subject: [PATCH 0266/1939] e1000: Support for 82571 and 82572 controllers Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 9 +- drivers/net/e1000/e1000_hw.c | 219 +++++++++++++++++++++++++----- drivers/net/e1000/e1000_hw.h | 96 +++++++++++-- drivers/net/e1000/e1000_main.c | 102 ++++++++++++-- 4 files changed, 372 insertions(+), 54 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 8f3a13420278..5f9a36bb77f5 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -696,6 +696,11 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) * Some bits that get toggled are ignored. */ switch (adapter->hw.mac_type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + toggle = 0x7FFFF3FF; + break; case e1000_82573: toggle = 0x7FFFF033; break; @@ -1245,6 +1250,8 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82541_rev_2: case e1000_82547: case e1000_82547_rev_2: + case e1000_82571: + case e1000_82572: case e1000_82573: return e1000_integrated_phy_loopback(adapter); break; @@ -1625,7 +1632,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); - if(adapter->hw.mac_type < e1000_82573) { + if(adapter->hw.mac_type < e1000_82571) { if(!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 045f5426ab9a..7d627dd89a3d 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -83,14 +83,14 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = static const uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = - { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, - 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, - 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, - 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, - 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, - 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, - 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, - 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; /****************************************************************************** @@ -286,7 +286,6 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: - case E1000_DEV_ID_82546GB_QUAD_COPPER: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -305,8 +304,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = e1000_82547_rev_2; break; + case E1000_DEV_ID_82571EB_COPPER: + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82571EB_SERDES: + hw->mac_type = e1000_82571; + break; + case E1000_DEV_ID_82572EI_COPPER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82572EI_SERDES: + hw->mac_type = e1000_82572; + break; case E1000_DEV_ID_82573E: case E1000_DEV_ID_82573E_IAMT: + case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; default: @@ -315,6 +325,8 @@ e1000_set_mac_type(struct e1000_hw *hw) } switch(hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: hw->eeprom_semaphore_present = TRUE; /* fall through */ @@ -351,6 +363,8 @@ e1000_set_media_type(struct e1000_hw *hw) switch (hw->device_id) { case E1000_DEV_ID_82545GM_SERDES: case E1000_DEV_ID_82546GB_SERDES: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -523,6 +537,8 @@ e1000_reset_hw(struct e1000_hw *hw) E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); E1000_WRITE_FLUSH(hw); /* fall through */ + case e1000_82571: + case e1000_82572: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) /* We don't want to continue accessing MAC registers. */ @@ -683,6 +699,9 @@ e1000_init_hw(struct e1000_hw *hw) switch (hw->mac_type) { default: break; + case e1000_82571: + case e1000_82572: + ctrl |= (1 << 22); case e1000_82573: ctrl |= E1000_TXDCTL_COUNT_DESC; break; @@ -694,6 +713,25 @@ e1000_init_hw(struct e1000_hw *hw) e1000_enable_tx_pkt_filtering(hw); } + switch (hw->mac_type) { + default: + break; + case e1000_82571: + ctrl = E1000_READ_REG(hw, TXDCTL1); + ctrl &= ~E1000_TXDCTL_WTHRESH; + ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; + ctrl |= (1 << 22); + E1000_WRITE_REG(hw, TXDCTL1, ctrl); + break; + } + + + + if (hw->mac_type == e1000_82573) { + uint32_t gcr = E1000_READ_REG(hw, GCR); + gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, GCR, gcr); + } /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -878,6 +916,14 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_fiber_serdes_link"); + /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists + * until explicitly turned off or a power cycle is performed. A read to + * the register does not indicate its status. Therefore, we ensure + * loopback mode is disabled during initialization. + */ + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) + E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK); + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal. This applies to fiber media only. @@ -2943,6 +2989,8 @@ e1000_phy_reset(struct e1000_hw *hw) switch (hw->mac_type) { case e1000_82541_rev_2: + case e1000_82571: + case e1000_82572: ret_val = e1000_phy_hw_reset(hw); if(ret_val) return ret_val; @@ -2981,6 +3029,16 @@ e1000_detect_gig_phy(struct e1000_hw *hw) DEBUGFUNC("e1000_detect_gig_phy"); + /* The 82571 firmware may still be configuring the PHY. In this + * case, we cannot access the PHY until the configuration is done. So + * we explicitly set the PHY values. */ + if(hw->mac_type == e1000_82571 || + hw->mac_type == e1000_82572) { + hw->phy_id = IGP01E1000_I_PHY_ID; + hw->phy_type = e1000_phy_igp_2; + return E1000_SUCCESS; + } + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); if(ret_val) @@ -3334,6 +3392,21 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->use_eerd = FALSE; eeprom->use_eewr = FALSE; break; + case e1000_82571: + case e1000_82572: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; case e1000_82573: eeprom->type = e1000_eeprom_spi; eeprom->opcode_bits = 8; @@ -3543,25 +3616,26 @@ e1000_acquire_eeprom(struct e1000_hw *hw) eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != e1000_82573) { - /* Request EEPROM Access */ - if(hw->mac_type > e1000_82544) { - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && - (i < E1000_EEPROM_GRANT_ATTEMPTS)) { - i++; - udelay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; + /* Request EEPROM Access */ + if(hw->mac_type > e1000_82544) { + eecd |= E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + udelay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + e1000_put_hw_eeprom_semaphore(hw); + return -E1000_ERR_EEPROM; + } } } - } /* Setup EEPROM for Read/Write */ @@ -4064,7 +4138,7 @@ e1000_write_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* 82573 reads only through eerd */ + /* 82573 writes only through eewr */ if(eeprom->use_eewr == TRUE) return e1000_write_eeprom_eewr(hw, offset, words, data); @@ -4353,9 +4427,16 @@ e1000_read_mac_addr(struct e1000_hw * hw) hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } - if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + switch (hw->mac_type) { + default: + break; + case e1000_82546: + case e1000_82546_rev_3: + case e1000_82571: + if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; + break; + } for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; @@ -4385,6 +4466,12 @@ e1000_init_rx_addrs(struct e1000_hw *hw) e1000_rar_set(hw, hw->mac_addr, 0); rar_num = E1000_RAR_ENTRIES; + + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + rar_num -= 1; /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < rar_num; i++) { @@ -4427,6 +4514,12 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); num_rar_entry = E1000_RAR_ENTRIES; + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + num_rar_entry -= 1; + for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); @@ -4984,7 +5077,6 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, ICTXQEC); temp = E1000_READ_REG(hw, ICTXQMTC); temp = E1000_READ_REG(hw, ICRXDMTC); - } /****************************************************************************** @@ -5151,6 +5243,8 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; + case e1000_82571: + case e1000_82572: case e1000_82573: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; @@ -5250,6 +5344,7 @@ e1000_get_cable_length(struct e1000_hw *hw, int32_t ret_val; uint16_t agc_value = 0; uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t max_agc = 0; uint16_t i, phy_data; uint16_t cable_length; @@ -5338,6 +5433,40 @@ e1000_get_cable_length(struct e1000_hw *hw, IGP01E1000_AGC_RANGE) : 0; *max_length = e1000_igp_cable_length_table[agc_value] + IGP01E1000_AGC_RANGE; + } else if (hw->phy_type == e1000_phy_igp_2) { + uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of course and + * fine gain values. The result is a number that can be put into + * the lookup table to obtain the approximate cable length. */ + cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc]) + min_agc = cur_agc; + if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc]) + max_agc = cur_agc; + + agc_value += e1000_igp_2_cable_length_table[cur_agc]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + *max_length = agc_value + IGP02E1000_AGC_RANGE; } return E1000_SUCCESS; @@ -6465,6 +6594,8 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) default: msec_delay(5); break; + case e1000_82571: + case e1000_82572: case e1000_82573: while(timeout) { if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; @@ -6494,10 +6625,31 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw) { + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t cfg_mask = E1000_EEPROM_CFG_DONE; + DEBUGFUNC("e1000_get_phy_cfg_done"); - /* Simply wait for 10ms */ - msec_delay(10); + switch (hw->mac_type) { + default: + msec_delay(10); + break; + case e1000_82571: + case e1000_82572: + while (timeout) { + if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask) + break; + else + msec_delay(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } return E1000_SUCCESS; } @@ -6569,8 +6721,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) return; swsm = E1000_READ_REG(hw, SWSM); - /* Release both semaphores. */ - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); } @@ -6606,6 +6757,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) * if this is the case. We read FWSM to determine the manageability mode. */ switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: fwsm = E1000_READ_REG(hw, FWSM); if((fwsm & E1000_FWSM_MODE_MASK) != 0) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 51c2b3a18b6f..4f2c196dc314 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -57,6 +57,8 @@ typedef enum { e1000_82541_rev_2, e1000_82547, e1000_82547_rev_2, + e1000_82571, + e1000_82572, e1000_82573, e1000_num_macs } e1000_mac_type; @@ -478,10 +480,16 @@ uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A #define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -833,6 +841,8 @@ struct e1000_ffvt_entry { #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_DISABLE_SERDES_LOOPBACK 0x0400 + /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. @@ -853,6 +863,7 @@ struct e1000_ffvt_entry { #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -864,6 +875,12 @@ struct e1000_ffvt_entry { #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ +#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ +#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ +#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ +#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ +#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ @@ -895,6 +912,12 @@ struct e1000_ffvt_entry { #define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ #define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ #define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ +#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ +#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ +#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ +#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ +#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ #define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ @@ -980,15 +1003,15 @@ struct e1000_ffvt_entry { #define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ -#define E1000_IAC 0x4100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */ -#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */ -#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */ -#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */ -#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ -#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ -#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ @@ -1018,6 +1041,14 @@ struct e1000_ffvt_entry { #define E1000_FWSM 0x05B54 /* FW Semaphore */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ +#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ /* Register Set (82542) * * Some of the 82542 registers are located at different offsets than they are @@ -1032,6 +1063,7 @@ struct e1000_ffvt_entry { #define E1000_82542_CTRL_EXT E1000_CTRL_EXT #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_SCTL E1000_SCTL #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1049,6 +1081,18 @@ struct e1000_ffvt_entry { #define E1000_82542_RDLEN 0x00118 #define E1000_82542_RDH 0x00120 #define E1000_82542_RDT 0x00128 +#define E1000_82542_RDTR0 E1000_82542_RDTR +#define E1000_82542_RDBAL0 E1000_82542_RDBAL +#define E1000_82542_RDBAH0 E1000_82542_RDBAH +#define E1000_82542_RDLEN0 E1000_82542_RDLEN +#define E1000_82542_RDH0 E1000_82542_RDH +#define E1000_82542_RDT0 E1000_82542_RDT +#define E1000_82542_RDTR1 0x00130 +#define E1000_82542_RDBAL1 0x00138 +#define E1000_82542_RDBAH1 0x0013C +#define E1000_82542_RDLEN1 0x00140 +#define E1000_82542_RDH1 0x00148 +#define E1000_82542_RDT1 0x00150 #define E1000_82542_FCRTH 0x00160 #define E1000_82542_FCRTL 0x00168 #define E1000_82542_FCTTV E1000_FCTTV @@ -1197,6 +1241,13 @@ struct e1000_ffvt_entry { #define E1000_82542_ICRXOC E1000_ICRXOC #define E1000_82542_HICR E1000_HICR +#define E1000_82542_CPUVEC E1000_CPUVEC +#define E1000_82542_MRQC E1000_MRQC +#define E1000_82542_RETA E1000_RETA +#define E1000_82542_RSSRK E1000_RSSRK +#define E1000_82542_RSSIM E1000_RSSIM +#define E1000_82542_RSSIR E1000_RSSIR + /* Statistics counters collected by the MAC */ struct e1000_hw_stats { uint64_t crcerrs; @@ -1336,6 +1387,7 @@ struct e1000_hw { boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; + boolean_t laa_is_present; boolean_t phy_reset_disable; boolean_t fc_send_xon; boolean_t fc_strict_ieee; @@ -1374,6 +1426,7 @@ struct e1000_hw { #define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ #define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ @@ -1491,6 +1544,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ @@ -1524,6 +1579,7 @@ struct e1000_hw { #define E1000_LEDCTL_LED2_BLINK 0x00800000 #define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 #define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 #define E1000_LEDCTL_LED3_IVRT 0x40000000 #define E1000_LEDCTL_LED3_BLINK 0x80000000 @@ -1784,6 +1840,16 @@ struct e1000_hw { #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ +/* Multiple Receive Queue Control */ +#define E1000_MRQC_ENABLE_MASK 0x00000003 +#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 +#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 +#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -1928,6 +1994,7 @@ struct e1000_host_command_info { #define E1000_MDALIGN 4096 #define E1000_GCR_BEM32 0x00400000 +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 #define E1000_FACTPS_LAN0_VALID 0x00000004 @@ -1980,6 +2047,7 @@ struct e1000_host_command_info { /* EEPROM Word Offsets */ #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_VERSION 0x0005 #define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ #define EEPROM_PHY_CLASS_WORD 0x0007 #define EEPROM_INIT_CONTROL1_REG 0x000A @@ -1990,6 +2058,8 @@ struct e1000_host_command_info { #define EEPROM_FLASH_VERSION 0x0032 #define EEPROM_CHECKSUM_REG 0x003F +#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 #define ID_LED_RESERVED_FFFF 0xFFFF @@ -2108,6 +2178,8 @@ struct e1000_host_command_info { #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 #define E1000_PBA_30K 0x001E +#define E1000_PBA_32K 0x0020 +#define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ @@ -2592,11 +2664,11 @@ struct e1000_host_command_info { /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 -#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128 +#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113 /* The precision error of the cable length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 -#define IGP02E1000_AGC_RANGE 10 +#define IGP02E1000_AGC_RANGE 15 /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c062b0ad8262..407abb2c0548 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -398,6 +398,10 @@ e1000_reset(struct e1000_adapter *adapter) case e1000_82547_rev_2: pba = E1000_PBA_30K; break; + case e1000_82571: + case e1000_82572: + pba = E1000_PBA_38K; + break; case e1000_82573: pba = E1000_PBA_12K; break; @@ -475,6 +479,7 @@ e1000_probe(struct pci_dev *pdev, struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; + uint32_t ctrl_ext; uint32_t swsm; static int cards_found = 0; @@ -688,6 +693,12 @@ e1000_probe(struct pci_dev *pdev, /* Let firmware know the driver has taken over */ switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -732,6 +743,7 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + uint32_t ctrl_ext; uint32_t manc, swsm; flush_scheduled_work(); @@ -746,6 +758,12 @@ e1000_remove(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -1236,7 +1254,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl |= E1000_RCTL_LPE; /* Setup buffer sizes */ - if(adapter->hw.mac_type == e1000_82573) { + if(adapter->hw.mac_type >= e1000_82571) { /* We can now specify buffers in 1K increments. * BSIZE and BSEX are ignored in this case. */ rctl |= adapter->rx_buffer_len << 0x11; @@ -1352,7 +1370,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) if(adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; - /* Enable 82573 IPv4 payload checksum for UDP fragments + /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ if((adapter->hw.mac_type > e1000_82547_rev_2) && (adapter->rx_ps)) { @@ -1608,6 +1626,22 @@ e1000_set_mac(struct net_device *netdev, void *p) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* With 82571 controllers, LAA may be overwritten (with the default) + * due to controller reset from the other port. */ + if (adapter->hw.mac_type == e1000_82571) { + /* activate the work around */ + adapter->hw.laa_is_present = 1; + + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventaully the LAA will be in RAR[0] and + * RAR[14] */ + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, + E1000_RAR_ENTRIES - 1); + } + if(adapter->hw.mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); @@ -1633,9 +1667,12 @@ e1000_set_multi(struct net_device *netdev) unsigned long flags; uint32_t rctl; uint32_t hash_value; - int i; + int i, rar_entries = E1000_RAR_ENTRIES; spin_lock_irqsave(&adapter->tx_lock, flags); + /* reserve RAR[14] for LAA over-write work-around */ + if (adapter->hw.mac_type == e1000_82571) + rar_entries--; /* Check for Promiscuous and All Multicast modes */ @@ -1660,11 +1697,12 @@ e1000_set_multi(struct net_device *netdev) /* load the first 14 multicast address into the exact filters 1-14 * RAR 0 is used for the station MAC adddress * if there are not 14 addresses, go ahead and clear the filters + * -- with 82571 controllers only 0-13 entries are filled here */ mc_ptr = netdev->mc_list; - for(i = 1; i < E1000_RAR_ENTRIES; i++) { - if(mc_ptr) { + for(i = 1; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->dmi_addr, i); mc_ptr = mc_ptr->next; } else { @@ -1848,6 +1886,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter) /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = TRUE; + /* With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] */ + if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present) + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* Reset the timer */ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } @@ -2269,6 +2312,27 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) local_irq_restore(flags); return NETDEV_TX_LOCKED; } +#ifdef NETIF_F_TSO + /* TSO Workaround for 82571/2 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + if (skb_shinfo(skb)->tso_size) { + uint8_t hdr_len; + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) && + (adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572)) { + unsigned int pull_size; + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; + } + } + } +#endif + if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); @@ -2310,7 +2374,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= E1000_TX_FLAGS_CSUM; /* Old method was to assume IPv4 packet by default if TSO was enabled. - * 82573 hardware supports TSO capabilities for IPv6 as well... + * 82571 hardware supports TSO capabilities for IPv6 as well... * no longer assume, we must. */ if(likely(skb->protocol == ntohs(ETH_P_IP))) tx_flags |= E1000_TX_FLAGS_IPV4; @@ -2389,9 +2453,18 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } -#define MAX_STD_JUMBO_FRAME_SIZE 9216 +#define MAX_STD_JUMBO_FRAME_SIZE 9234 /* might want this to be bigger enum check... */ - if (adapter->hw.mac_type == e1000_82573 && + /* 82571 controllers limit jumbo frame size to 10500 bytes */ + if ((adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572) && + max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported " + "on 82571 and 82572 controllers.\n"); + return -EINVAL; + } + + if(adapter->hw.mac_type == e1000_82573 && max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported " "on 82573\n"); @@ -3716,6 +3789,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -3738,6 +3817,7 @@ e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t manc, ret_val, swsm; + uint32_t ctrl_ext; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); @@ -3763,6 +3843,12 @@ e1000_resume(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, From 581d708eb47cccb5f41bc0817e50c9b004011ba8 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:01:55 -0400 Subject: [PATCH 0267/1939] e1000: multi-queue defines/modification to data structures defines/modifies data structures, function prototypes and changes to the driver rendering it capable of handling tx/rx queues Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 67 ++- drivers/net/e1000/e1000_ethtool.c | 75 ++-- drivers/net/e1000/e1000_main.c | 663 ++++++++++++++++++++---------- drivers/net/e1000/e1000_param.c | 10 +- 4 files changed, 568 insertions(+), 247 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 092757bc721f..9b7274b111f3 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -72,6 +72,10 @@ #include #include #include +#ifdef CONFIG_E1000_MQ +#include +#include +#endif #define BAR_0 0 #define BAR_1 1 @@ -168,7 +172,30 @@ struct e1000_buffer { struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; }; struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; }; -struct e1000_desc_ring { +struct e1000_tx_ring { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical address of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; + /* number of descriptors in the ring */ + unsigned int count; + /* next descriptor to associate a buffer with */ + unsigned int next_to_use; + /* next descriptor to check for DD status bit */ + unsigned int next_to_clean; + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + + struct e1000_buffer previous_buffer_info; + spinlock_t tx_lock; + uint16_t tdh; + uint16_t tdt; + uint64_t pkt; +}; + +struct e1000_rx_ring { /* pointer to the descriptor ring memory */ void *desc; /* physical address of the descriptor ring */ @@ -186,6 +213,10 @@ struct e1000_desc_ring { /* arrays of page information for packet split */ struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; + + uint16_t rdh; + uint16_t rdt; + uint64_t pkt; }; #define E1000_DESC_UNUSED(R) \ @@ -227,9 +258,10 @@ struct e1000_adapter { unsigned long led_status; /* TX */ - struct e1000_desc_ring tx_ring; - struct e1000_buffer previous_buffer_info; - spinlock_t tx_lock; + struct e1000_tx_ring *tx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_MQ + struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */ +#endif uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; @@ -246,13 +278,26 @@ struct e1000_adapter { /* RX */ #ifdef CONFIG_E1000_NAPI - boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done, - int work_to_do); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); #else - boolean_t (*clean_rx) (struct e1000_adapter *adapter); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif - void (*alloc_rx_buf) (struct e1000_adapter *adapter); - struct e1000_desc_ring rx_ring; + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_NAPI + struct net_device *polling_netdev; /* One per active queue */ +#endif +#ifdef CONFIG_E1000_MQ + struct net_device **cpu_netdev; /* per-cpu */ + struct call_async_data_struct rx_sched_call_data; + int cpu_for_queue[4]; +#endif + int num_queues; + uint64_t hw_csum_err; uint64_t hw_csum_good; uint32_t rx_int_delay; @@ -278,8 +323,8 @@ struct e1000_adapter { struct e1000_phy_stats phy_stats; uint32_t test_icr; - struct e1000_desc_ring test_tx_ring; - struct e1000_desc_ring test_rx_ring; + struct e1000_tx_ring test_tx_ring; + struct e1000_rx_ring test_rx_ring; int msg_enable; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 5f9a36bb77f5..6e7e34f59a34 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -39,10 +39,10 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); -extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); -extern void e1000_free_rx_resources(struct e1000_adapter *adapter); -extern void e1000_free_tx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_update_stats(struct e1000_adapter *adapter); struct e1000_stats { @@ -576,8 +576,8 @@ e1000_get_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; + struct e1000_tx_ring *txdr = adapter->tx_ring; + struct e1000_rx_ring *rxdr = adapter->rx_ring; ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -597,20 +597,40 @@ e1000_set_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; - int err; + struct e1000_tx_ring *txdr, *tx_old, *tx_new; + struct e1000_rx_ring *rxdr, *rx_old, *rx_new; + int i, err, tx_ring_size, rx_ring_size; + + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + + if (netif_running(adapter->netdev)) + e1000_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; + adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL); + if (!adapter->tx_ring) { + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->tx_ring, 0, tx_ring_size); + + adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->rx_ring, 0, rx_ring_size); + + txdr = adapter->tx_ring; + rxdr = adapter->rx_ring; + if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - if(netif_running(adapter->netdev)) - e1000_down(adapter); - rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); @@ -621,11 +641,16 @@ e1000_set_ringparam(struct net_device *netdev, E1000_MAX_TXD : E1000_MAX_82544_TXD)); E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + for (i = 0; i < adapter->num_queues; i++) { + txdr[i].count = txdr->count; + rxdr[i].count = rxdr->count; + } + if(netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, @@ -635,8 +660,10 @@ e1000_set_ringparam(struct net_device *netdev, tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; - e1000_free_rx_resources(adapter); - e1000_free_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; if((err = e1000_up(adapter))) @@ -645,7 +672,7 @@ e1000_set_ringparam(struct net_device *netdev, return 0; err_setup_tx: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; @@ -903,8 +930,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) static void e1000_free_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; @@ -946,8 +973,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) static int e1000_setup_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; int size, i, ret_val; @@ -1347,8 +1374,8 @@ e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) static int e1000_run_loopback_test(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i, j, k, l, lc, good_cnt, ret_val=0; unsigned long time; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 407abb2c0548..5145b7345c22 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -102,10 +102,18 @@ int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -int e1000_setup_tx_resources(struct e1000_adapter *adapter); -int e1000_setup_rx_resources(struct e1000_adapter *adapter); -void e1000_free_tx_resources(struct e1000_adapter *adapter); -void e1000_free_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +void e1000_free_all_tx_resources(struct e1000_adapter *adapter); +void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr); +int e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr); +void e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +void e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -114,14 +122,22 @@ static int e1000_init_module(void); static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void __devexit e1000_remove(struct pci_dev *pdev); +static int e1000_alloc_queues(struct e1000_adapter *adapter); +#ifdef CONFIG_E1000_MQ +static void e1000_setup_queue_mapping(struct e1000_adapter *adapter); +#endif static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); -static void e1000_clean_tx_ring(struct e1000_adapter *adapter); -static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter); +static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -132,19 +148,26 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); -static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI -static int e1000_clean(struct net_device *netdev, int *budget); +static int e1000_clean(struct net_device *poll_dev, int *budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); #else -static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); -static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter); +static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif -static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); -static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -289,7 +312,7 @@ int e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int err; + int i, err; /* hardware has been reset, we need to reload some things */ @@ -308,7 +331,8 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); - adapter->alloc_rx_buf(adapter); + for (i = 0; i < adapter->num_queues; i++) + adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2) { @@ -363,8 +387,8 @@ e1000_down(struct e1000_adapter *adapter) netif_stop_queue(netdev); e1000_reset(adapter); - e1000_clean_tx_ring(adapter); - e1000_clean_rx_ring(adapter); + e1000_clean_all_tx_rings(adapter); + e1000_clean_all_rx_rings(adapter); /* If WoL is not enabled * and management mode is not IAMT @@ -747,6 +771,9 @@ e1000_remove(struct pci_dev *pdev) uint32_t manc, swsm; flush_scheduled_work(); +#ifdef CONFIG_E1000_NAPI + int i; +#endif if(adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper) { @@ -775,6 +802,10 @@ e1000_remove(struct pci_dev *pdev) } unregister_netdev(netdev); +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) + __dev_put(&adapter->polling_netdev[i]); +#endif if(!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); @@ -802,6 +833,9 @@ e1000_sw_init(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; +#ifdef CONFIG_E1000_NAPI + int i; +#endif /* PCI config space info */ @@ -859,13 +893,70 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->master_slave = E1000_MASTER_SLAVE; } + adapter->num_queues = 1; + + if (e1000_alloc_queues(adapter)) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) { + adapter->polling_netdev[i].priv = adapter; + adapter->polling_netdev[i].poll = &e1000_clean; + adapter->polling_netdev[i].weight = 64; + dev_hold(&adapter->polling_netdev[i]); + set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); + } +#endif atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); - spin_lock_init(&adapter->tx_lock); return 0; } +/** + * e1000_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ + +static int __devinit +e1000_alloc_queues(struct e1000_adapter *adapter) +{ + int size; + + size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + adapter->tx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + memset(adapter->tx_ring, 0, size); + + size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + adapter->rx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + memset(adapter->rx_ring, 0, size); + +#ifdef CONFIG_E1000_NAPI + size = sizeof(struct net_device) * adapter->num_queues; + adapter->polling_netdev = kmalloc(size, GFP_KERNEL); + if (!adapter->polling_netdev) { + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + return -ENOMEM; + } + memset(adapter->polling_netdev, 0, size); +#endif + + return E1000_SUCCESS; +} + /** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure @@ -887,12 +978,12 @@ e1000_open(struct net_device *netdev) /* allocate transmit descriptors */ - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* allocate receive descriptors */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_up(adapter))) @@ -906,9 +997,9 @@ e1000_open(struct net_device *netdev) return E1000_SUCCESS; err_up: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: - e1000_free_tx_resources(adapter); + e1000_free_all_tx_resources(adapter); err_setup_tx: e1000_reset(adapter); @@ -934,8 +1025,8 @@ e1000_close(struct net_device *netdev) e1000_down(adapter); - e1000_free_tx_resources(adapter); - e1000_free_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); if((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { @@ -970,14 +1061,15 @@ e1000_check_64k_bound(struct e1000_adapter *adapter, /** * e1000_setup_tx_resources - allocate Tx resources (Descriptors) * @adapter: board private structure + * @txdr: tx descriptor ring (for a specific queue) to setup * * Return 0 on success, negative on failure **/ int -e1000_setup_tx_resources(struct e1000_adapter *adapter) +e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr) { - struct e1000_desc_ring *txdr = &adapter->tx_ring; struct pci_dev *pdev = adapter->pdev; int size; @@ -1041,6 +1133,35 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) return 0; } +/** + * e1000_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_tx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); + break; + } + } + + return err; +} + /** * e1000_configure_tx - Configure 8254x Transmit Unit after Reset * @adapter: board private structure @@ -1051,23 +1172,28 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) static void e1000_configure_tx(struct e1000_adapter *adapter) { - uint64_t tdba = adapter->tx_ring.dma; - uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); - uint32_t tctl, tipg; - - E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32)); - - E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen); + uint64_t tdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t tdlen, tctl, tipg, tarc; /* Setup the HW Tx Head and Tail descriptor pointers */ E1000_WRITE_REG(&adapter->hw, TDH, 0); E1000_WRITE_REG(&adapter->hw, TDT, 0); + tdba = adapter->tx_ring[0].dma; + tdlen = adapter->tx_ring[0].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN, tdlen); + E1000_WRITE_REG(hw, TDH, 0); + E1000_WRITE_REG(hw, TDT, 0); + adapter->tx_ring[0].tdh = E1000_TDH; + adapter->tx_ring[0].tdt = E1000_TDT; /* Set the default values for the Tx Inter Packet Gap timer */ - switch (adapter->hw.mac_type) { + switch (hw->mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: tipg = DEFAULT_82542_TIPG_IPGT; @@ -1075,67 +1201,68 @@ e1000_configure_tx(struct e1000_adapter *adapter) tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; break; default: - if(adapter->hw.media_type == e1000_media_type_fiber || - adapter->hw.media_type == e1000_media_type_internal_serdes) + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else tipg = DEFAULT_82543_TIPG_IPGT_COPPER; tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; } - E1000_WRITE_REG(&adapter->hw, TIPG, tipg); + E1000_WRITE_REG(hw, TIPG, tipg); /* Set the Tx Interrupt Delay register */ - E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) - E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); + E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay); + if (hw->mac_type >= e1000_82540) + E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay); /* Program the Transmit Control Register */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_CT; tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + E1000_WRITE_REG(hw, TCTL, tctl); - e1000_config_collision_dist(&adapter->hw); + e1000_config_collision_dist(hw); /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.mac_type < e1000_82543) + if (hw->mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; else adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ - if(adapter->hw.mac_type == e1000_82544 && - adapter->hw.bus_type == e1000_bus_type_pcix) + if (hw->mac_type == e1000_82544 && + hw->bus_type == e1000_bus_type_pcix) adapter->pcix_82544 = 1; } /** * e1000_setup_rx_resources - allocate Rx resources (Descriptors) * @adapter: board private structure + * @rxdr: rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure **/ int -e1000_setup_rx_resources(struct e1000_adapter *adapter) +e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr) { - struct e1000_desc_ring *rxdr = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; rxdr->buffer_info = vmalloc(size); - if(!rxdr->buffer_info) { + if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; @@ -1175,13 +1302,13 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { + if (!rxdr->desc) { + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); setup_rx_desc_die: vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } @@ -1193,9 +1320,12 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) "at %p\n", rxdr->size, rxdr->desc); /* Try again, without freeing the previous */ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { /* Failed allocation, critical failure */ + if (!rxdr->desc) { pci_free_consistent(pdev, rxdr->size, olddesc, olddma); + DPRINTK(PROBE, ERR, + "Unable to allocate memory " + "for the receive descriptor ring\n"); goto setup_rx_desc_die; } @@ -1207,10 +1337,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) DPRINTK(PROBE, ERR, "Unable to allocate aligned memory " "for the receive descriptor ring\n"); - vfree(rxdr->buffer_info); - kfree(rxdr->ps_page); - kfree(rxdr->ps_page_dma); - return -ENOMEM; + goto setup_rx_desc_die; } else { /* Free old allocation, new allocation was successful */ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); @@ -1224,6 +1351,35 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) return 0; } +/** + * e1000_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_rx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); + break; + } + } + + return err; +} + /** * e1000_setup_rctl - configure the receive control registers * @adapter: Board private structure @@ -1326,47 +1482,55 @@ e1000_setup_rctl(struct e1000_adapter *adapter) static void e1000_configure_rx(struct e1000_adapter *adapter) { - uint64_t rdba = adapter->rx_ring.dma; - uint32_t rdlen, rctl, rxcsum; + uint64_t rdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t rdlen, rctl, rxcsum, ctrl_ext; +#ifdef CONFIG_E1000_MQ + uint32_t reta, mrqc; + int i; +#endif if(adapter->rx_ps) { - rdlen = adapter->rx_ring.count * + rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; } else { - rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); adapter->clean_rx = e1000_clean_rx_irq; adapter->alloc_rx_buf = e1000_alloc_rx_buffers; } /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); - E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); + rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); + E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + if (hw->mac_type >= e1000_82540) { + E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); if(adapter->itr > 1) - E1000_WRITE_REG(&adapter->hw, ITR, + E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256)); } - /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); - - E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen); - - /* Setup the HW Rx Head and Tail Descriptor Pointers */ - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + rdba = adapter->rx_ring[0].dma; + E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN, rdlen); + E1000_WRITE_REG(hw, RDH, 0); + E1000_WRITE_REG(hw, RDT, 0); + adapter->rx_ring[0].rdh = E1000_RDH; + adapter->rx_ring[0].rdt = E1000_RDT; + break; /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if(adapter->hw.mac_type >= e1000_82543) { - rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); + if (hw->mac_type >= e1000_82543) { + rxcsum = E1000_READ_REG(hw, RXCSUM); if(adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; @@ -1380,37 +1544,54 @@ e1000_configure_rx(struct e1000_adapter *adapter) rxcsum &= ~E1000_RXCSUM_TUOFL; /* don't need to clear IPPCSE as it defaults to 0 */ } - E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum); + E1000_WRITE_REG(hw, RXCSUM, rxcsum); } - if (adapter->hw.mac_type == e1000_82573) - E1000_WRITE_REG(&adapter->hw, ERT, 0x0100); + if (hw->mac_type == e1000_82573) + E1000_WRITE_REG(hw, ERT, 0x0100); /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + E1000_WRITE_REG(hw, RCTL, rctl); } /** - * e1000_free_tx_resources - Free Tx Resources + * e1000_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ + +void +e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + e1000_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * e1000_free_all_tx_resources - Free Tx Resources for All Queues * @adapter: board private structure * * Free all transmit software resources **/ void -e1000_free_tx_resources(struct e1000_adapter *adapter) +e1000_free_all_tx_resources(struct e1000_adapter *adapter) { - struct pci_dev *pdev = adapter->pdev; + int i; - e1000_clean_tx_ring(adapter); - - vfree(adapter->tx_ring.buffer_info); - adapter->tx_ring.buffer_info = NULL; - - pci_free_consistent(pdev, adapter->tx_ring.size, - adapter->tx_ring.desc, adapter->tx_ring.dma); - - adapter->tx_ring.desc = NULL; + for (i = 0; i < adapter->num_queues; i++) + e1000_free_tx_resources(adapter, &adapter->tx_ring[i]); } static inline void @@ -1433,21 +1614,22 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, /** * e1000_clean_tx_ring - Free Tx Buffers * @adapter: board private structure + * @tx_ring: ring to be cleaned **/ static void -e1000_clean_tx_ring(struct e1000_adapter *adapter) +e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned long size; unsigned int i; /* Free all the Tx ring sk_buffs */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(i = 0; i < tx_ring->count; i++) { @@ -1465,24 +1647,39 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + writel(0, adapter->hw.hw_addr + tx_ring->tdh); + writel(0, adapter->hw.hw_addr + tx_ring->tdt); +} + +/** + * e1000_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_tx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]); } /** * e1000_free_rx_resources - Free Rx Resources * @adapter: board private structure + * @rx_ring: ring to clean the resources from * * Free all receive software resources **/ void -e1000_free_rx_resources(struct e1000_adapter *adapter) +e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; - e1000_clean_rx_ring(adapter); + e1000_clean_rx_ring(adapter, rx_ring); vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; @@ -1497,14 +1694,31 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) } /** - * e1000_clean_rx_ring - Free Rx Buffers + * e1000_free_all_rx_resources - Free Rx Resources for All Queues * @adapter: board private structure + * + * Free all receive software resources + **/ + +void +e1000_free_all_rx_resources(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + * @rx_ring: ring to free buffers from **/ static void -e1000_clean_rx_ring(struct e1000_adapter *adapter) +e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct e1000_buffer *buffer_info; struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; @@ -1553,8 +1767,22 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); + writel(0, adapter->hw.hw_addr + rx_ring->rdh); + writel(0, adapter->hw.hw_addr + rx_ring->rdt); +} + +/** + * e1000_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_rx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]); } /* The 82542 2.0 (revision 2) needs to have the receive unit in reset @@ -1575,7 +1803,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter) mdelay(5); if(netif_running(netdev)) - e1000_clean_rx_ring(adapter); + e1000_clean_all_rx_rings(adapter); } static void @@ -1595,7 +1823,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter) if(netif_running(netdev)) { e1000_configure_rx(adapter); - e1000_alloc_rx_buffers(adapter); + e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]); } } @@ -1664,12 +1892,10 @@ e1000_set_multi(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; - unsigned long flags; uint32_t rctl; uint32_t hash_value; int i, rar_entries = E1000_RAR_ENTRIES; - spin_lock_irqsave(&adapter->tx_lock, flags); /* reserve RAR[14] for LAA over-write work-around */ if (adapter->hw.mac_type == e1000_82571) rar_entries--; @@ -1725,8 +1951,6 @@ e1000_set_multi(struct net_device *netdev) if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); - - spin_unlock_irqrestore(&adapter->tx_lock, flags); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -1798,7 +2022,7 @@ static void e1000_watchdog_task(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_tx_ring *txdr = &adapter->tx_ring[0]; uint32_t link; e1000_check_for_link(&adapter->hw); @@ -1857,8 +2081,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_update_adaptive(&adapter->hw); - if(!netif_carrier_ok(netdev)) { - if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { + if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) { + if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, * but we've got queued Tx work that's never going * to get done, so reset controller to flush Tx. @@ -1903,7 +2127,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline int -e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; @@ -1954,8 +2179,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; @@ -1967,8 +2192,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; context_desc->cmd_and_length = cpu_to_le32(cmd_length); - if(++i == adapter->tx_ring.count) i = 0; - adapter->tx_ring.next_to_use = i; + if (++i == tx_ring->count) i = 0; + tx_ring->next_to_use = i; return 1; } @@ -1978,7 +2203,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) } static inline boolean_t -e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { struct e1000_context_desc *context_desc; unsigned int i; @@ -1987,8 +2213,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; @@ -1996,8 +2222,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(unlikely(++i == adapter->tx_ring.count)) i = 0; - adapter->tx_ring.next_to_use = i; + if (unlikely(++i == tx_ring->count)) i = 0; + tx_ring->next_to_use = i; return TRUE; } @@ -2009,11 +2235,10 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) #define E1000_MAX_DATA_PER_TXD (1<tx_ring; struct e1000_buffer *buffer_info; unsigned int len = skb->len; unsigned int offset = 0, size, count = 0, i; @@ -2109,9 +2334,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, } static inline void -e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) +e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + int tx_flags, int count) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; @@ -2157,7 +2382,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) wmb(); tx_ring->next_to_use = i; - E1000_WRITE_REG(&adapter->hw, TDT, i); + writel(i, adapter->hw.hw_addr + tx_ring->tdt); } /** @@ -2250,6 +2475,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_tx_ring *tx_ring; unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; @@ -2262,7 +2488,8 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; len -= skb->data_len; - if(unlikely(skb->len <= 0)) { + tx_ring = adapter->tx_ring; + if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2306,12 +2533,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count += nr_frags; - local_irq_save(flags); - if (!spin_trylock(&adapter->tx_lock)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } #ifdef NETIF_F_TSO /* TSO Workaround for 82571/2 Controllers -- if skb->data * points to just header, pull a few bytes of payload from @@ -2336,12 +2557,18 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); + local_irq_save(flags); + if (!spin_trylock(&tx_ring->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) { + if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) { netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -2349,7 +2576,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } } @@ -2359,37 +2586,37 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } - first = adapter->tx_ring.next_to_use; + first = tx_ring->next_to_use; - tso = e1000_tso(adapter, skb); + tso = e1000_tso(adapter, tx_ring, skb); if (tso < 0) { dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } if (likely(tso)) tx_flags |= E1000_TX_FLAGS_TSO; - else if(likely(e1000_tx_csum(adapter, skb))) + else if (likely(e1000_tx_csum(adapter, tx_ring, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; /* Old method was to assume IPv4 packet by default if TSO was enabled. * 82571 hardware supports TSO capabilities for IPv6 as well... * no longer assume, we must. */ - if(likely(skb->protocol == ntohs(ETH_P_IP))) + if (likely(skb->protocol == ntohs(ETH_P_IP))) tx_flags |= E1000_TX_FLAGS_IPV4; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), - tx_flags); + e1000_tx_queue(adapter, tx_ring, tx_flags, + e1000_tx_map(adapter, tx_ring, skb, first, + max_per_txd, nr_frags, mss)); netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2)) + if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2)) netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } @@ -2666,9 +2893,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); -#ifndef CONFIG_E1000_NAPI - unsigned int i; -#endif + int i; if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ @@ -2679,17 +2904,15 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #ifdef CONFIG_E1000_NAPI - if(likely(netif_rx_schedule_prep(netdev))) { - - /* Disable interrupts and register for poll. The flush - of the posted write is intentionally left out. - */ - - atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(hw, IMC, ~0); - __netif_rx_schedule(netdev); + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(hw, IMC, ~0); + E1000_WRITE_FLUSH(hw); } #else + if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) + __netif_rx_schedule(&adapter->polling_netdev[0]); + else + e1000_irq_enable(adapter); /* Writing IMC and IMS is needed for 82547. Due to Hub Link bus being occupied, an interrupt de-assertion message is not able to be sent. @@ -2706,12 +2929,13 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } for(i = 0; i < E1000_MAX_INTR; i++) - if(unlikely(!adapter->clean_rx(adapter) & - !e1000_clean_tx_irq(adapter))) + if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & + !e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); + #endif return IRQ_HANDLED; @@ -2724,22 +2948,37 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) **/ static int -e1000_clean(struct net_device *netdev, int *budget) +e1000_clean(struct net_device *poll_dev, int *budget) { - struct e1000_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); - int tx_cleaned; - int work_done = 0; + struct e1000_adapter *adapter; + int work_to_do = min(*budget, poll_dev->quota); + int tx_cleaned, i = 0, work_done = 0; - tx_cleaned = e1000_clean_tx_irq(adapter); - adapter->clean_rx(adapter, &work_done, work_to_do); + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + + while (poll_dev != &adapter->polling_netdev[i]) { + i++; + if (unlikely(i == adapter->num_queues)) + BUG(); + } + + tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]); + adapter->clean_rx(adapter, &adapter->rx_ring[i], + &work_done, work_to_do); *budget -= work_done; - netdev->quota -= work_done; + poll_dev->quota -= work_done; - if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { /* If no Tx and not enough Rx work done, exit the polling mode */ - netif_rx_complete(netdev); + if((!tx_cleaned && (work_done == 0)) || + !netif_running(adapter->netdev)) { +quit_polling: + netif_rx_complete(poll_dev); e1000_irq_enable(adapter); return 0; } @@ -2754,9 +2993,9 @@ e1000_clean(struct net_device *netdev, int *budget) **/ static boolean_t -e1000_clean_tx_irq(struct e1000_adapter *adapter) +e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; @@ -2767,12 +3006,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); - while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { /* Premature writeback of Tx descriptors clear (free buffers * and unmap pci_mapping) previous_buffer_info */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(cleaned = FALSE; !cleaned; ) { @@ -2788,7 +3027,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) #ifdef NETIF_F_TSO } else { if (cleaned) { - memcpy(&adapter->previous_buffer_info, + memcpy(&tx_ring->previous_buffer_info, buffer_info, sizeof(struct e1000_buffer)); memset(buffer_info, 0, @@ -2806,6 +3045,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) if(unlikely(++i == tx_ring->count)) i = 0; } + + tx_ring->pkt++; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -2813,15 +3054,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_ring->next_to_clean = i; - spin_lock(&adapter->tx_lock); + spin_lock(&tx_ring->tx_lock); if(unlikely(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))) netif_wake_queue(netdev); - spin_unlock(&adapter->tx_lock); - if(adapter->detect_tx_hung) { + spin_unlock(&tx_ring->tx_lock); + if (adapter->detect_tx_hung) { /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; @@ -2845,8 +3086,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) " next_to_watch <%x>\n" " jiffies <%lx>\n" " next_to_watch.status <%x>\n", - E1000_READ_REG(&adapter->hw, TDH), - E1000_READ_REG(&adapter->hw, TDT), + readl(adapter->hw.hw_addr + tx_ring->tdh), + readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, i, (unsigned long long)tx_ring->buffer_info[i].dma, @@ -2858,12 +3099,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) } } #ifdef NETIF_F_TSO - - if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && - time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ))) + if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && + time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ))) e1000_unmap_and_free_tx_resource( - adapter, &adapter->previous_buffer_info); - + adapter, &tx_ring->previous_buffer_info); #endif return cleaned; } @@ -2926,13 +3165,14 @@ e1000_rx_checksum(struct e1000_adapter *adapter, static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq(struct e1000_adapter *adapter) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -3018,6 +3258,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->status = 0; @@ -3027,7 +3268,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) rx_desc = E1000_RX_DESC(*rx_ring, i); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -3039,13 +3280,14 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; union e1000_rx_desc_packet_split *rx_desc; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3145,6 +3387,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->wb.middle.status_error &= ~0xFF; @@ -3155,7 +3398,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) staterr = le32_to_cpu(rx_desc->wb.middle.status_error); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -3166,9 +3409,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) **/ static void -e1000_alloc_rx_buffers(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -3252,7 +3495,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); - E1000_WRITE_REG(&adapter->hw, RDT, i); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; @@ -3268,9 +3511,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) **/ static void -e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union e1000_rx_desc_packet_split *rx_desc; @@ -3338,7 +3581,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) * descriptors are 32 bytes...so we increment tail * twice as much. */ - E1000_WRITE_REG(&adapter->hw, RDT, i<<1); + writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 676247f9f1cc..38695d5b4637 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -306,7 +306,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_TXD, .arg = { .r = { .min = E1000_MIN_TXD }} }; - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct e1000_tx_ring *tx_ring = adapter->tx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD; @@ -319,6 +320,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { tx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + tx_ring[i].count = tx_ring->count; } { /* Receive Descriptor Count */ struct e1000_option opt = { @@ -329,7 +332,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_RXD, .arg = { .r = { .min = E1000_MIN_RXD }} }; - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct e1000_rx_ring *rx_ring = adapter->rx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -342,6 +346,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { rx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + rx_ring[i].count = rx_ring->count; } { /* Checksum Offload Enable/Disable */ struct e1000_option opt = { From 24025e4ecf88743e1b3d46451b0e3f9de4bbcba5 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:03:23 -0400 Subject: [PATCH 0268/1939] e1000: implementation of the multi-queue feature Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 191 ++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5145b7345c22..ce1044a80bd2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -195,6 +195,11 @@ static int e1000_resume(struct pci_dev *pdev); static void e1000_netpoll (struct net_device *netdev); #endif +#ifdef CONFIG_E1000_MQ +/* for multiple Rx queues */ +void e1000_rx_schedule(void *data); +#endif + /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -368,6 +373,9 @@ e1000_down(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); +#ifdef CONFIG_E1000_MQ + while (atomic_read(&adapter->rx_sched_call_data.count) != 0); +#endif free_irq(adapter->pdev->irq, netdev); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2 && @@ -810,9 +818,19 @@ e1000_remove(struct pci_dev *pdev) if(!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +#ifdef CONFIG_E1000_NAPI + kfree(adapter->polling_netdev); +#endif + iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); +#ifdef CONFIG_E1000_MQ + free_percpu(adapter->cpu_netdev); + free_percpu(adapter->cpu_tx_ring); +#endif free_netdev(netdev); pci_disable_device(pdev); @@ -893,7 +911,21 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->master_slave = E1000_MASTER_SLAVE; } +#ifdef CONFIG_E1000_MQ + /* Number of supported queues */ + switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: + adapter->num_queues = 2; + break; + default: + adapter->num_queues = 1; + break; + } + adapter->num_queues = min(adapter->num_queues, num_online_cpus()); +#else adapter->num_queues = 1; +#endif if (e1000_alloc_queues(adapter)) { DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); @@ -909,6 +941,11 @@ e1000_sw_init(struct e1000_adapter *adapter) set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); } #endif + +#ifdef CONFIG_E1000_MQ + e1000_setup_queue_mapping(adapter); +#endif + atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); @@ -957,6 +994,39 @@ e1000_alloc_queues(struct e1000_adapter *adapter) return E1000_SUCCESS; } +#ifdef CONFIG_E1000_MQ +static void __devinit +e1000_setup_queue_mapping(struct e1000_adapter *adapter) +{ + int i, cpu; + + adapter->rx_sched_call_data.func = e1000_rx_schedule; + adapter->rx_sched_call_data.info = adapter->netdev; + cpus_clear(adapter->rx_sched_call_data.cpumask); + + adapter->cpu_netdev = alloc_percpu(struct net_device *); + adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); + + lock_cpu_hotplug(); + i = 0; + for_each_online_cpu(cpu) { + *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues]; + /* This is incomplete because we'd like to assign separate + * physical cpus to these netdev polling structures and + * avoid saturating a subset of cpus. + */ + if (i < adapter->num_queues) { + *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; + adapter->cpu_for_queue[i] = cpu; + } else + *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; + + i++; + } + unlock_cpu_hotplug(); +} +#endif + /** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure @@ -1178,8 +1248,21 @@ e1000_configure_tx(struct e1000_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + switch (adapter->num_queues) { + case 2: + tdba = adapter->tx_ring[1].dma; + tdlen = adapter->tx_ring[1].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN1, tdlen); + E1000_WRITE_REG(hw, TDH1, 0); + E1000_WRITE_REG(hw, TDT1, 0); + adapter->tx_ring[1].tdh = E1000_TDH1; + adapter->tx_ring[1].tdt = E1000_TDT1; + /* Fall Through */ + case 1: + default: tdba = adapter->tx_ring[0].dma; tdlen = adapter->tx_ring[0].count * sizeof(struct e1000_tx_desc); @@ -1190,6 +1273,8 @@ e1000_configure_tx(struct e1000_adapter *adapter) E1000_WRITE_REG(hw, TDT, 0); adapter->tx_ring[0].tdh = E1000_TDH; adapter->tx_ring[0].tdt = E1000_TDT; + break; + } /* Set the default values for the Tx Inter Packet Gap timer */ @@ -1222,7 +1307,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | + tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); E1000_WRITE_REG(hw, TCTL, tctl); @@ -1518,6 +1603,21 @@ e1000_configure_rx(struct e1000_adapter *adapter) /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ + switch (adapter->num_queues) { +#ifdef CONFIG_E1000_MQ + case 2: + rdba = adapter->rx_ring[1].dma; + E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN1, rdlen); + E1000_WRITE_REG(hw, RDH1, 0); + E1000_WRITE_REG(hw, RDT1, 0); + adapter->rx_ring[1].rdh = E1000_RDH1; + adapter->rx_ring[1].rdt = E1000_RDT1; + /* Fall Through */ +#endif + case 1: + default: rdba = adapter->rx_ring[0].dma; E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); @@ -1527,6 +1627,47 @@ e1000_configure_rx(struct e1000_adapter *adapter) adapter->rx_ring[0].rdh = E1000_RDH; adapter->rx_ring[0].rdt = E1000_RDT; break; + } + +#ifdef CONFIG_E1000_MQ + if (adapter->num_queues > 1) { + uint32_t random[10]; + + get_random_bytes(&random[0], 40); + + if (hw->mac_type <= e1000_82572) { + E1000_WRITE_REG(hw, RSSIR, 0); + E1000_WRITE_REG(hw, RSSIM, 0); + } + + switch (adapter->num_queues) { + case 2: + default: + reta = 0x00800080; + mrqc = E1000_MRQC_ENABLE_RSS_2Q; + break; + } + + /* Fill out redirection table */ + for (i = 0; i < 32; i++) + E1000_WRITE_REG_ARRAY(hw, RETA, i, reta); + /* Fill out hash function seeds */ + for (i = 0; i < 10; i++) + E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]); + + mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP); + E1000_WRITE_REG(hw, MRQC, mrqc); + } + + /* Multiqueue and packet checksumming are mutually exclusive. */ + if (hw->mac_type >= e1000_82571) { + rxcsum = E1000_READ_REG(hw, RXCSUM); + rxcsum |= E1000_RXCSUM_PCSD; + E1000_WRITE_REG(hw, RXCSUM, rxcsum); + } + +#else /* Enable 82543 Receive Checksum Offload for TCP and UDP */ if (hw->mac_type >= e1000_82543) { @@ -1546,6 +1687,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) } E1000_WRITE_REG(hw, RXCSUM, rxcsum); } +#endif /* CONFIG_E1000_MQ */ if (hw->mac_type == e1000_82573) E1000_WRITE_REG(hw, ERT, 0x0100); @@ -2488,7 +2630,12 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; len -= skb->data_len; +#ifdef CONFIG_E1000_MQ + tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); +#else tx_ring = adapter->tx_ring; +#endif + if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -2879,6 +3026,29 @@ e1000_update_stats(struct e1000_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } +#ifdef CONFIG_E1000_MQ +void +e1000_rx_schedule(void *data) +{ + struct net_device *poll_dev, *netdev = data; + struct e1000_adapter *adapter = netdev->priv; + int this_cpu = get_cpu(); + + poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu); + if (poll_dev == NULL) { + put_cpu(); + return; + } + + if (likely(netif_rx_schedule_prep(poll_dev))) + __netif_rx_schedule(poll_dev); + else + e1000_irq_enable(adapter); + + put_cpu(); +} +#endif + /** * e1000_intr - Interrupt Handler * @irq: interrupt number @@ -2907,12 +3077,27 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(hw, IMC, ~0); E1000_WRITE_FLUSH(hw); +#ifdef CONFIG_E1000_MQ + if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { + cpu_set(adapter->cpu_for_queue[0], + adapter->rx_sched_call_data.cpumask); + for (i = 1; i < adapter->num_queues; i++) { + cpu_set(adapter->cpu_for_queue[i], + adapter->rx_sched_call_data.cpumask); + atomic_inc(&adapter->irq_sem); + } + atomic_set(&adapter->rx_sched_call_data.count, i); + smp_call_async_mask(&adapter->rx_sched_call_data); + } else { + printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); } #else if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) __netif_rx_schedule(&adapter->polling_netdev[0]); else e1000_irq_enable(adapter); +#endif +#else /* Writing IMC and IMS is needed for 82547. Due to Hub Link bus being occupied, an interrupt de-assertion message is not able to be sent. From 2ae76d98fb9f0a9226dd62cf0a0b7547507d2862 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:04:22 -0400 Subject: [PATCH 0269/1939] e1000: Enable custom configuration bits for 82571/2 controllers Enable custom configuration bits for 82571/2 controllers. The bits are required for correct functionality of these controllers. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ce1044a80bd2..ad92115f20a0 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1151,6 +1151,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, return -ENOMEM; } memset(txdr->buffer_info, 0, size); + memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer)); /* round up to nearest 4K */ @@ -1199,6 +1200,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, txdr->next_to_use = 0; txdr->next_to_clean = 0; + spin_lock_init(&txdr->tx_lock); return 0; } @@ -1312,6 +1314,19 @@ e1000_configure_tx(struct e1000_adapter *adapter) E1000_WRITE_REG(hw, TCTL, tctl); + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) { + tarc = E1000_READ_REG(hw, TARC0); + tarc |= ((1 << 25) | (1 << 21)); + E1000_WRITE_REG(hw, TARC0, tarc); + tarc = E1000_READ_REG(hw, TARC1); + tarc |= (1 << 25); + if (tctl & E1000_TCTL_MULR) + tarc &= ~(1 << 28); + else + tarc |= (1 << 28); + E1000_WRITE_REG(hw, TARC1, tarc); + } + e1000_config_collision_dist(hw); /* Setup Transmit Descriptor Settings for eop descriptor */ @@ -1601,6 +1616,14 @@ e1000_configure_rx(struct e1000_adapter *adapter) 1000000000 / (adapter->itr * 256)); } + if (hw->mac_type >= e1000_82571) { + /* Reset delay timers after every interrupt */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_CANC; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + } + /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ switch (adapter->num_queues) { From e4c811c9d2f2728ce15440c99b3b44b72799b43f Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:05:44 -0400 Subject: [PATCH 0270/1939] e1000: Fixes for packet split related issues Fixes for packet split related issues * On platforms where PAGE_SIZE > 4K, driver will use only required number of pages compared to always using 3 pages. * Packet split won't be used if the PAGE_SIZE is > 16K * Adds a statistics counter to splits. * Setting the non Null ptr to zero sized buffers to solve packet split receive descriptor error * When the no of pages needed is calculated, the header buffer is not included for a given MTU. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 7 +-- drivers/net/e1000/e1000_ethtool.c | 3 +- drivers/net/e1000/e1000_main.c | 88 +++++++++++++++++++------------ 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 9b7274b111f3..3f653a93e1bc 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -169,8 +169,8 @@ struct e1000_buffer { uint16_t next_to_watch; }; -struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; }; -struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; }; +struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; +struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; struct e1000_tx_ring { /* pointer to the descriptor ring memory */ @@ -300,10 +300,11 @@ struct e1000_adapter { uint64_t hw_csum_err; uint64_t hw_csum_good; + uint64_t rx_hdr_split; uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; - boolean_t rx_ps; + unsigned int rx_ps_pages; uint32_t gorcl; uint64_t gorcl_old; uint16_t rx_ps_bsize0; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 6e7e34f59a34..183b583df1d7 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ad92115f20a0..090229f7a95c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1484,12 +1484,16 @@ e1000_setup_all_rx_resources(struct e1000_adapter *adapter) * e1000_setup_rctl - configure the receive control registers * @adapter: Board private structure **/ - +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) static void e1000_setup_rctl(struct e1000_adapter *adapter) { uint32_t rctl, rfctl; uint32_t psrctl = 0; +#ifdef CONFIG_E1000_PACKET_SPLIT + uint32_t pages = 0; +#endif rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1543,11 +1547,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter) * followed by the page buffers. Therefore, skb->data is * sized to hold the largest protocol header. */ - adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2) - && (adapter->netdev->mtu - < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0)); + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) && + PAGE_SIZE <= 16384) + adapter->rx_ps_pages = pages; + else + adapter->rx_ps_pages = 0; #endif - if(adapter->rx_ps) { + if (adapter->rx_ps_pages) { /* Configure extra packet-split registers */ rfctl = E1000_READ_REG(&adapter->hw, RFCTL); rfctl |= E1000_RFCTL_EXTEN; @@ -1559,12 +1566,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter) psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; - psrctl |= PAGE_SIZE >> - E1000_PSRCTL_BSIZE1_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE2_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE3_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); } @@ -1590,7 +1604,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) int i; #endif - if(adapter->rx_ps) { + if (adapter->rx_ps_pages) { rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; @@ -1700,8 +1714,8 @@ e1000_configure_rx(struct e1000_adapter *adapter) /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ - if((adapter->hw.mac_type > e1000_82547_rev_2) && - (adapter->rx_ps)) { + if ((hw->mac_type >= e1000_82571) && + (adapter->rx_ps_pages)) { rxcsum |= E1000_RXCSUM_IPPCSE; } } else { @@ -1906,7 +1920,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter, dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!ps_page->ps_page[j]) break; pci_unmap_single(pdev, ps_page_dma->ps_page_dma[j], @@ -3551,7 +3565,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, /* Good Receive */ skb_put(skb, length); - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) break; @@ -3572,11 +3586,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); skb->protocol = eth_type_trans(skb, netdev); -#ifdef HAVE_RX_ZERO_COPY if(likely(rx_desc->wb.upper.header_status & - E1000_RXDPS_HDRSTAT_HDRSP)) + E1000_RXDPS_HDRSTAT_HDRSP)) { + adapter->rx_hdr_split++; +#ifdef HAVE_RX_ZERO_COPY skb_shinfo(skb)->zero_copy = TRUE; #endif + } #ifdef CONFIG_E1000_NAPI if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, @@ -3740,22 +3756,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, rx_desc = E1000_RX_DESC_PS(*rx_ring, i); for(j = 0; j < PS_PAGE_BUFFERS; j++) { - if(unlikely(!ps_page->ps_page[j])) { - ps_page->ps_page[j] = - alloc_page(GFP_ATOMIC); - if(unlikely(!ps_page->ps_page[j])) - goto no_buffers; - ps_page_dma->ps_page_dma[j] = - pci_map_page(pdev, - ps_page->ps_page[j], - 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - } - /* Refresh the desc even if buffer_addrs didn't - * change because each write-back erases this info. - */ - rx_desc->read.buffer_addr[j+1] = - cpu_to_le64(ps_page_dma->ps_page_dma[j]); + if (j < adapter->rx_ps_pages) { + if (likely(!ps_page->ps_page[j])) { + ps_page->ps_page[j] = + alloc_page(GFP_ATOMIC); + if (unlikely(!ps_page->ps_page[j])) + goto no_buffers; + ps_page_dma->ps_page_dma[j] = + pci_map_page(pdev, + ps_page->ps_page[j], + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't + * change because each write-back erases + * this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page_dma->ps_page_dma[j]); + } else + rx_desc->read.buffer_addr[j+1] = ~0; } skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); From 352c9f854cb197581d7135d1276742fd76b53c25 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:07:24 -0400 Subject: [PATCH 0271/1939] e1000: Added msleep_interruptible delay added msleep_interruptible delay right before returning from diag_test to allow the phy to recover from reset Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 183b583df1d7..ee66947e5043 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1544,6 +1544,7 @@ e1000_diag_test(struct net_device *netdev, data[2] = 0; data[3] = 0; } + msleep_interruptible(4 * 1000); } static void From a7990ba60adc46a808c737443393fdfecdc82593 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 4 Oct 2005 07:08:19 -0400 Subject: [PATCH 0272/1939] e1000: Flush shadow RAM Flush shadow RAM to save updates to ASF related bits for 82573 controllers. These bits are past the first 63 words of NVM. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 6 ++++-- drivers/net/e1000/e1000_hw.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index ee66947e5043..6b9acc7f94a3 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -547,8 +547,10 @@ e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); - /* Update the checksum over the first part of the EEPROM if needed */ - if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG) + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 conrollers */ + if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || + (hw->mac_type == e1000_82573))) e1000_update_eeprom_checksum(hw); kfree(eeprom_buff); diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 7d627dd89a3d..8fc876da43b4 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -717,6 +717,7 @@ e1000_init_hw(struct e1000_hw *hw) default: break; case e1000_82571: + case e1000_82572: ctrl = E1000_READ_REG(hw, TXDCTL1); ctrl &= ~E1000_TXDCTL_WTHRESH; ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; From be2b28ed3bb3dd3952e10fb72623b23c5d8b4795 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 4 Oct 2005 07:13:43 -0400 Subject: [PATCH 0273/1939] e1000: fix warnings --- drivers/net/e1000/e1000_main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 090229f7a95c..dd79449f9a99 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -777,12 +777,12 @@ e1000_remove(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t ctrl_ext; uint32_t manc, swsm; - - flush_scheduled_work(); #ifdef CONFIG_E1000_NAPI int i; #endif + flush_scheduled_work(); + if(adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); @@ -3100,7 +3100,9 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); +#ifdef CONFIG_E1000_MQ int i; +#endif if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ @@ -3128,13 +3130,14 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } else { printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); } -#else +#else /* if !CONFIG_E1000_MQ */ if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) __netif_rx_schedule(&adapter->polling_netdev[0]); else e1000_irq_enable(adapter); -#endif -#else +#endif /* CONFIG_E1000_MQ */ + +#else /* if !CONFIG_E1000_NAPI */ /* Writing IMC and IMS is needed for 82547. Due to Hub Link bus being occupied, an interrupt de-assertion message is not able to be sent. @@ -3158,7 +3161,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); -#endif +#endif /* CONFIG_E1000_NAPI */ return IRQ_HANDLED; } From 96eb549c0c20cf63ca13fac71d9d406701f744a6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 4 Oct 2005 12:20:24 +0100 Subject: [PATCH 0274/1939] [PATCH] AX.25: Delete debug printk from mkiss driver Signed-off-by: Ralf Baechle DL5RB -- drivers/net/hamradio/mkiss.c | 1 - 1 files changed, 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/hamradio/mkiss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d9fe64b46f4b..793ae12a2571 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -765,7 +765,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, case SIOCSIFHWADDR: { char addr[AX25_ADDR_LEN]; -printk(KERN_INFO "In SIOCSIFHWADDR"); if (copy_from_user(&addr, (void __user *) arg, AX25_ADDR_LEN)) { From d5919586265d36c6694a5d10ba589c02806873b6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 4 Oct 2005 12:22:16 +0100 Subject: [PATCH 0275/1939] [PATCH] AX.25: Convert mkiss.c to DEFINE_RWLOCK Signed-off-by: Ingo Molnar Signed-off-by: Ralf Baechle DL5RB drivers/net/hamradio/mkiss.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/hamradio/mkiss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 793ae12a2571..331a75c8aee2 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -622,7 +622,7 @@ static void ax_setup(struct net_device *dev) * best way to fix this is to use a rwlock in the tty struct, but for now we * use a single global rwlock for all ttys in ppp line discipline. */ -static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(disc_data_lock); static struct mkiss *mkiss_get(struct tty_struct *tty) { From 53232803241ae0f26b39897a4d4b37775837de00 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Tue, 4 Oct 2005 07:46:21 -0400 Subject: [PATCH 0276/1939] airo: fix resume Cisco Aironet doesn't resume properly from swsusp, because the resume method confuses a PM_EVENT_* for a PCI power state. It thinks that it is resuming from PCI_D1 and doesn't do the necessary initialization of the card. Signed-off-by: Michal Schmidt --- drivers/net/wireless/airo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 746456c34df8..cb429e783749 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5504,12 +5504,13 @@ static int airo_pci_resume(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; Resp rsp; + pci_power_t prev_state = pdev->current_state; - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0); + pci_enable_wake(pdev, PCI_D0, 0); - if (ai->power.event > 1) { + if (prev_state != PCI_D1) { reset_card(dev, 0); mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); From dbc2309d90b59fbb2676dc2e39150aa095e8c222 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Sep 2005 17:50:51 -0400 Subject: [PATCH 0277/1939] [PATCH] s2io: change strncpy length arg to use size of target Use the size of the target array for the length argument to strncpy instead of the size of the source or a magic number. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 4b9f1828845e..eff747cf3113 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4177,11 +4177,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, { nic_t *sp = dev->priv; - strncpy(info->driver, s2io_driver_name, sizeof(s2io_driver_name)); - strncpy(info->version, s2io_driver_version, - sizeof(s2io_driver_version)); - strncpy(info->fw_version, "", 32); - strncpy(info->bus_info, pci_name(sp->pdev), 32); + strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); + strncpy(info->version, s2io_driver_version, sizeof(info->version)); + strncpy(info->fw_version, "", sizeof(info->fw_version)); + strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; info->testinfo_len = S2IO_TEST_LEN; From 6c1792f4e8cf2ca03a8dd5ec4b162b9219e9268a Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 4 Oct 2005 07:51:45 -0400 Subject: [PATCH 0278/1939] [netdrvr s2io] Add a MODULE_VERSION entry --- drivers/net/s2io.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index eff747cf3113..fcf61107046e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -65,9 +65,11 @@ #include "s2io.h" #include "s2io-regs.h" +#define DRV_VERSION "Version 2.0.9.1" + /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; -static char s2io_driver_version[] = "Version 2.0.9.1"; +static char s2io_driver_version[] = DRV_VERSION; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -5635,6 +5637,8 @@ static void s2io_init_pci(nic_t * sp) MODULE_AUTHOR("Raghavendra Koushik "); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + module_param(tx_fifo_num, int, 0); module_param(rx_ring_num, int, 0); module_param_array(tx_fifo_len, uint, NULL, 0); @@ -6013,7 +6017,7 @@ Defaulting to INTA\n"); if (sp->device_type & XFRAME_II_DEVICE) { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE @@ -6048,7 +6052,7 @@ Defaulting to INTA\n"); } else { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE From 075897ce3b1027fccb98f36dd1f18c07f5c374ef Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Sep 2005 17:50:53 -0400 Subject: [PATCH 0279/1939] [PATCH] bonding: replicate IGMP traffic in activebackup mode Replicate IGMP frames across all slaves in activebackup mode. This ensures fail-over is rapid for multicast traffic as well. Otherwise, multicast traffic will be lost until the next IGMP membership report poll timeout. This is conceptually similar to the treatment of IGMP traffic in bond_alb_xmit. In that case, IGMP traffic transmitted on any slave is re-routed to the active slave in order to ensure that multicast traffic continues to be directed to the active receiver. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 53 +++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fd62e43a3510..2c9e63a14596 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4240,6 +4240,39 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev return 0; } +static void bond_activebackup_xmit_copy(struct sk_buff *skb, + struct bonding *bond, + struct slave *slave) +{ + struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); + struct ethhdr *eth_data; + u8 *hwaddr; + int res; + + if (!skb2) { + printk(KERN_ERR DRV_NAME ": Error: " + "bond_activebackup_xmit_copy(): skb_copy() failed\n"); + return; + } + + skb2->mac.raw = (unsigned char *)skb2->data; + eth_data = eth_hdr(skb2); + + /* Pick an appropriate source MAC address */ + hwaddr = slave->perm_hwaddr; + if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN)) + hwaddr = bond->curr_active_slave->perm_hwaddr; + + /* Set source MAC address appropriately */ + memcpy(eth_data->h_source, hwaddr, ETH_ALEN); + + res = bond_dev_queue_xmit(bond, skb2, slave->dev); + if (res) + dev_kfree_skb(skb2); + + return; +} + /* * in active-backup mode, we know that bond->curr_active_slave is always valid if * the bond has a usable interface. @@ -4256,10 +4289,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d goto out; } - if (bond->curr_active_slave) { /* one usable interface */ - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + if (!bond->curr_active_slave) + goto out; + + /* Xmit IGMP frames on all slaves to ensure rapid fail-over + for multicast traffic on snooping switches */ + if (skb->protocol == __constant_htons(ETH_P_IP) && + skb->nh.iph->protocol == IPPROTO_IGMP) { + struct slave *slave, *active_slave; + int i; + + active_slave = bond->curr_active_slave; + bond_for_each_slave_from_to(bond, slave, i, active_slave->next, + active_slave->prev) + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP)) + bond_activebackup_xmit_copy(skb, bond, slave); } + res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + out: if (res) { /* no suitable interface, frame not sent */ From 47a8659380d40d5c0786ddb62a89b3f7f1392430 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Oct 2005 08:09:19 -0400 Subject: [PATCH 0280/1939] libata: bitmask based pci init functions for one or two ports This redoes the n_ports logic I proposed before as a bitmask. ata_pci_init_native_mode is now used with a mask allowing for mixed mode stuff later on. ata_pci_init_legacy_port is called with port number and does one port now not two. Instead it is called twice by the ata init logic which cleans both of them up. There are stil limits in the original code left over - IRQ/port mapping for legacy mode should be arch specific values - You can have one legacy mode IDE adapter per PCI root bridge on some systems - Doesn't handle mixed mode devices yet (but is now a lot closer to it) --- drivers/scsi/libata-core.c | 131 +++++++++++++++++++++---------------- drivers/scsi/sata_nv.c | 2 +- drivers/scsi/sata_sis.c | 2 +- drivers/scsi/sata_uli.c | 2 +- drivers/scsi/sata_via.c | 2 +- include/linux/libata.h | 6 +- 6 files changed, 84 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 03d422e99e58..82ec7f30bf3f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4363,85 +4363,87 @@ void ata_pci_host_stop (struct ata_host_set *host_set) * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized * @port: array[2] of pointers to port info structures. + * @ports: bitmap of ports present * * Utility function which allocates and initializes an * ata_probe_ent structure for a standard dual-port * PIO-based IDE controller. The returned ata_probe_ent * structure can be passed to ata_device_add(). The returned * ata_probe_ent structure should then be freed with kfree(). + * + * The caller need only pass the address of the primary port, the + * secondary will be deduced automatically. If the device has non + * standard secondary port mappings this function can be called twice, + * once for each interface. */ struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + int p = 0; + if (!probe_ent) return NULL; - probe_ent->n_ports = 2; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + if (ports & ATA_PORT_PRIMARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); + ata_std_ports(&probe_ent->port[p]); + p++; + } - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - - ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent->port[1]); + if (ports & ATA_PORT_SECONDARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; + ata_std_ports(&probe_ent->port[p]); + p++; + } + probe_ent->n_ports = p; return probe_ent; } -static struct ata_probe_ent * -ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, - struct ata_probe_ent **ppe2) +static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info **port, int port_num) { - struct ata_probe_ent *probe_ent, *probe_ent2; + struct ata_probe_ent *probe_ent; probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; - probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]); - if (!probe_ent2) { - kfree(probe_ent); - return NULL; - } - probe_ent->n_ports = 1; - probe_ent->irq = 14; - - probe_ent->hard_port_no = 0; + probe_ent->legacy_mode = 1; + probe_ent->n_ports = 1; + probe_ent->hard_port_no = port_num; - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - - probe_ent2->hard_port_no = 1; - probe_ent2->legacy_mode = 1; - - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - + switch(port_num) + { + case 0: + probe_ent->irq = 14; + probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x3f6; + break; + case 1: + probe_ent->irq = 15; + probe_ent->port[0].cmd_addr = 0x170; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x376; + break; + } + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num; ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent2->port[0]); - - *ppe2 = probe_ent2; return probe_ent; } @@ -4470,7 +4472,7 @@ ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { - struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; + struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL; struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; @@ -4487,7 +4489,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0 && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - /* TODO: support transitioning to native mode? */ + /* TODO: What if one channel is in native mode ... */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) @@ -4495,11 +4497,20 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } /* FIXME... */ - if ((!legacy_mode) && (n_ports > 1)) { - printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n"); - return -EINVAL; + if ((!legacy_mode) && (n_ports > 2)) { + printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n"); + n_ports = 2; + /* For now */ } + /* FIXME: Really for ATA it isn't safe because the device may be + multi-purpose and we want to leave it alone if it was already + enabled. Secondly for shared use as Arjan says we want refcounting + + Checking dev->is_enabled is insufficient as this is not set at + boot for the primary video which is BIOS enabled + */ + rc = pci_enable_device(pdev); if (rc) return rc; @@ -4510,6 +4521,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out; } + /* FIXME: Should use platform specific mappers for legacy port ranges */ if (legacy_mode) { if (!request_region(0x1f0, 8, "libata")) { struct resource *conflict, res; @@ -4554,10 +4566,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out_regions; if (legacy_mode) { - probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2); - } else - probe_ent = ata_pci_init_native_mode(pdev, port); - if (!probe_ent) { + if (legacy_mode & (1 << 0)) + probe_ent = ata_pci_init_legacy_port(pdev, port, 0); + if (legacy_mode & (1 << 1)) + probe_ent2 = ata_pci_init_legacy_port(pdev, port, 1); + } else { + if (n_ports == 2) + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + else + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY); + } + if (!probe_ent && !probe_ent2) { rc = -ENOMEM; goto err_out_regions; } diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index c05653c7779d..749ff92d8c63 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -405,7 +405,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = -ENOMEM; ppi = &nv_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index b227e51d12f4..0761a3234fcf 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -263,7 +263,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &sis_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 4c9fb8b71be1..9c06f2abe7f7 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -202,7 +202,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &uli_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 128b996b07b7..565872479b9a 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -212,7 +212,7 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) struct ata_probe_ent *probe_ent; struct ata_port_info *ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; diff --git a/include/linux/libata.h b/include/linux/libata.h index 4739a75b983d..4d45179872cc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -155,6 +155,10 @@ enum { ATA_SHIFT_UDMA = 0, ATA_SHIFT_MWDMA = 8, ATA_SHIFT_PIO = 11, + + /* Masks for port functions */ + ATA_PORT_PRIMARY = (1 << 0), + ATA_PORT_SECONDARY = (1 << 1), }; enum hsm_task_states { @@ -458,7 +462,7 @@ struct pci_bits { extern void ata_pci_host_stop (struct ata_host_set *host_set); extern struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port); +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask); extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); #endif /* CONFIG_PCI */ From e2608361be343e6220e0a87e04ff224eb037df31 Mon Sep 17 00:00:00 2001 From: Mateusz Berezecki Date: Tue, 4 Oct 2005 08:14:00 -0400 Subject: [PATCH 0281/1939] [wireless ipw2200] remove redundant return statement --- drivers/net/wireless/ipw2200.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 7ea9bd58f65f..de4e6c23e4b8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5318,8 +5318,6 @@ static int ipw_wx_set_freq(struct net_device *dev, IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); return ipw_set_channel(priv, (u8) fwrq->m); - - return 0; } static int ipw_wx_get_freq(struct net_device *dev, From fd9d63678d42ffd4312815ac720a12920642eb36 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 13:44:48 +0100 Subject: [PATCH 0282/1939] NTFS: Change ntfs_map_runlist_nolock() to also take an optional attribute search context. This allows calling it with the mft record mapped. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 5 + fs/ntfs/Makefile | 2 +- fs/ntfs/attrib.c | 232 +++++++++++++++++++++++++++++++++++++++------- fs/ntfs/attrib.h | 3 +- 4 files changed, 209 insertions(+), 33 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index de58579a1d0e..85f797a2edad 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -22,6 +22,11 @@ ToDo/Notes: - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.25-WIP + + - Change ntfs_map_runlist_nolock() to also take an optional attribute + search context. This allows calling it with the mft record mapped. + 2.1.24 - Lots of bug fixes and support more clean journal states. - Support journals ($LogFile) which have been modified by chkdsk. This diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 894b2b876d35..a3ce2c0e7dd9 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25-WIP\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 3f9a4ff42ee5..b194197b72f7 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -36,9 +36,27 @@ * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode * @ni: ntfs inode for which to map (part of) a runlist * @vcn: map runlist part containing this vcn + * @ctx: active attribute search context if present or NULL if not * * Map the part of a runlist containing the @vcn of the ntfs inode @ni. * + * If @ctx is specified, it is an active search context of @ni and its base mft + * record. This is needed when ntfs_map_runlist_nolock() encounters unmapped + * runlist fragments and allows their mapping. If you do not have the mft + * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock() + * will perform the necessary mapping and unmapping. + * + * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and + * restores it before returning. Thus, @ctx will be left pointing to the same + * attribute on return as on entry. However, the actual pointers in @ctx may + * point to different memory locations on return, so you must remember to reset + * any cached pointers from the @ctx, i.e. after the call to + * ntfs_map_runlist_nolock(), you will probably want to do: + * m = ctx->mrec; + * a = ctx->attr; + * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that + * you cache ctx->mrec in a variable @m of type MFT_RECORD *. + * * Return 0 on success and -errno on error. There is one special error code * which is not an error as such. This is -ENOENT. It means that @vcn is out * of bounds of the runlist. @@ -46,19 +64,32 @@ * Note the runlist can be NULL after this function returns if @vcn is zero and * the attribute has zero allocated size, i.e. there simply is no runlist. * - * Locking: - The runlist must be locked for writing. - * - This function modifies the runlist. + * WARNING: If @ctx is supplied, regardless of whether success or failure is + * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx + * is no longer valid, i.e. you need to either call + * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. + * In that case PTR_ERR(@ctx->mrec) will give you the error code for + * why the mapping of the old inode failed. + * + * Locking: - The runlist described by @ni must be locked for writing on entry + * and is locked on return. Note the runlist will be modified. + * - If @ctx is NULL, the base mft record of @ni must not be mapped on + * entry and it will be left unmapped on return. + * - If @ctx is not NULL, the base mft record must be mapped on entry + * and it will be left mapped on return. */ -int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) +int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx) { VCN end_vcn; + unsigned long flags; ntfs_inode *base_ni; MFT_RECORD *m; ATTR_RECORD *a; - ntfs_attr_search_ctx *ctx; runlist_element *rl; - unsigned long flags; + struct page *put_this_page = NULL; int err = 0; + BOOL ctx_is_temporary, ctx_needs_reset; + ntfs_attr_search_ctx old_ctx; ntfs_debug("Mapping runlist part containing vcn 0x%llx.", (unsigned long long)vcn); @@ -66,20 +97,77 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) base_ni = ni; else base_ni = ni->ext.base_ntfs_ino; - m = map_mft_record(base_ni); - if (IS_ERR(m)) - return PTR_ERR(m); - ctx = ntfs_attr_get_search_ctx(base_ni, m); - if (unlikely(!ctx)) { - err = -ENOMEM; - goto err_out; + if (!ctx) { + ctx_is_temporary = ctx_needs_reset = TRUE; + m = map_mft_record(base_ni); + if (IS_ERR(m)) + return PTR_ERR(m); + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + } else { + VCN allocated_size_vcn; + + BUG_ON(IS_ERR(ctx->mrec)); + a = ctx->attr; + BUG_ON(!a->non_resident); + ctx_is_temporary = FALSE; + end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); + read_lock_irqsave(&ni->size_lock, flags); + allocated_size_vcn = ni->allocated_size >> + ni->vol->cluster_size_bits; + read_unlock_irqrestore(&ni->size_lock, flags); + if (!a->data.non_resident.lowest_vcn && end_vcn <= 0) + end_vcn = allocated_size_vcn - 1; + /* + * If we already have the attribute extent containing @vcn in + * @ctx, no need to look it up again. We slightly cheat in + * that if vcn exceeds the allocated size, we will refuse to + * map the runlist below, so there is definitely no need to get + * the right attribute extent. + */ + if (vcn >= allocated_size_vcn || (a->type == ni->type && + a->name_length == ni->name_len && + !memcmp((u8*)a + le16_to_cpu(a->name_offset), + ni->name, ni->name_len) && + sle64_to_cpu(a->data.non_resident.lowest_vcn) + <= vcn && end_vcn >= vcn)) + ctx_needs_reset = FALSE; + else { + /* Save the old search context. */ + old_ctx = *ctx; + /* + * If the currently mapped (extent) inode is not the + * base inode we will unmap it when we reinitialize the + * search context which means we need to get a + * reference to the page containing the mapped mft + * record so we do not accidentally drop changes to the + * mft record when it has not been marked dirty yet. + */ + if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino != + old_ctx.base_ntfs_ino) { + put_this_page = old_ctx.ntfs_ino->page; + page_cache_get(put_this_page); + } + /* + * Reinitialize the search context so we can lookup the + * needed attribute extent. + */ + ntfs_attr_reinit_search_ctx(ctx); + ctx_needs_reset = TRUE; + } } - err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, - CASE_SENSITIVE, vcn, NULL, 0, ctx); - if (unlikely(err)) { - if (err == -ENOENT) - err = -EIO; - goto err_out; + if (ctx_needs_reset) { + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, vcn, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + BUG_ON(!ctx->attr->non_resident); } a = ctx->attr; /* @@ -89,11 +177,9 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) * ntfs_mapping_pairs_decompress() fails. */ end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; - if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) { - read_lock_irqsave(&ni->size_lock, flags); - end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; - read_unlock_irqrestore(&ni->size_lock, flags); - } + if (!a->data.non_resident.lowest_vcn && end_vcn == 1) + end_vcn = sle64_to_cpu(a->data.non_resident.allocated_size) >> + ni->vol->cluster_size_bits; if (unlikely(vcn >= end_vcn)) { err = -ENOENT; goto err_out; @@ -104,9 +190,93 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) else ni->runlist.rl = rl; err_out: - if (likely(ctx)) - ntfs_attr_put_search_ctx(ctx); - unmap_mft_record(base_ni); + if (ctx_is_temporary) { + if (likely(ctx)) + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + } else if (ctx_needs_reset) { + /* + * If there is no attribute list, restoring the search context + * is acomplished simply by copying the saved context back over + * the caller supplied context. If there is an attribute list, + * things are more complicated as we need to deal with mapping + * of mft records and resulting potential changes in pointers. + */ + if (NInoAttrList(base_ni)) { + /* + * If the currently mapped (extent) inode is not the + * one we had before, we need to unmap it and map the + * old one. + */ + if (ctx->ntfs_ino != old_ctx.ntfs_ino) { + /* + * If the currently mapped inode is not the + * base inode, unmap it. + */ + if (ctx->base_ntfs_ino && ctx->ntfs_ino != + ctx->base_ntfs_ino) { + unmap_extent_mft_record(ctx->ntfs_ino); + ctx->mrec = ctx->base_mrec; + BUG_ON(!ctx->mrec); + } + /* + * If the old mapped inode is not the base + * inode, map it. + */ + if (old_ctx.base_ntfs_ino && + old_ctx.ntfs_ino != + old_ctx.base_ntfs_ino) { +retry_map: + ctx->mrec = map_mft_record( + old_ctx.ntfs_ino); + /* + * Something bad has happened. If out + * of memory retry till it succeeds. + * Any other errors are fatal and we + * return the error code in ctx->mrec. + * Let the caller deal with it... We + * just need to fudge things so the + * caller can reinit and/or put the + * search context safely. + */ + if (IS_ERR(ctx->mrec)) { + if (PTR_ERR(ctx->mrec) == + -ENOMEM) { + schedule(); + goto retry_map; + } else + old_ctx.ntfs_ino = + old_ctx. + base_ntfs_ino; + } + } + } + /* Update the changed pointers in the saved context. */ + if (ctx->mrec != old_ctx.mrec) { + if (!IS_ERR(ctx->mrec)) + old_ctx.attr = (ATTR_RECORD*)( + (u8*)ctx->mrec + + ((u8*)old_ctx.attr - + (u8*)old_ctx.mrec)); + old_ctx.mrec = ctx->mrec; + } + } + /* Restore the search context to the saved one. */ + *ctx = old_ctx; + /* + * We drop the reference on the page we took earlier. In the + * case that IS_ERR(ctx->mrec) is true this means we might lose + * some changes to the mft record that had been made between + * the last time it was marked dirty/written out and now. This + * at this stage is not a problem as the mapping error is fatal + * enough that the mft record cannot be written out anyway and + * the caller is very likely to shutdown the whole inode + * immediately and mark the volume dirty for chkdsk to pick up + * the pieces anyway. + */ + if (put_this_page) + page_cache_release(put_this_page); + } return err; } @@ -122,8 +292,8 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) * of bounds of the runlist. * * Locking: - The runlist must be unlocked on entry and is unlocked on return. - * - This function takes the runlist lock for writing and modifies the - * runlist. + * - This function takes the runlist lock for writing and may modify + * the runlist. */ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) { @@ -133,7 +303,7 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) /* Make sure someone else didn't do the work while we were sleeping. */ if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= LCN_RL_NOT_MAPPED)) - err = ntfs_map_runlist_nolock(ni, vcn); + err = ntfs_map_runlist_nolock(ni, vcn, NULL); up_write(&ni->runlist.lock); return err; } @@ -212,7 +382,7 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, goto retry_remap; } } - err = ntfs_map_runlist_nolock(ni, vcn); + err = ntfs_map_runlist_nolock(ni, vcn, NULL); if (!write_locked) { up_write(&ni->runlist.lock); down_read(&ni->runlist.lock); @@ -325,7 +495,7 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, goto retry_remap; } } - err = ntfs_map_runlist_nolock(ni, vcn); + err = ntfs_map_runlist_nolock(ni, vcn, NULL); if (!write_locked) { up_write(&ni->runlist.lock); down_read(&ni->runlist.lock); diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index 0618ed6fd7b3..eeca8e500971 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h @@ -60,7 +60,8 @@ typedef struct { ATTR_RECORD *base_attr; } ntfs_attr_search_ctx; -extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn); +extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, + ntfs_attr_search_ctx *ctx); extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, From c187c4b58a9caff660a4c8ae39d0def88cc449af Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 4 Oct 2005 08:46:51 -0400 Subject: [PATCH 0283/1939] libata: minor whitespace, comment, debug message updates --- drivers/scsi/libata-scsi.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 03b7a6dd95fe..d67c3fc98f7b 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -589,7 +589,8 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) head = track % dev->heads; sect = (u32)block % dev->sectors + 1; - DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect); + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); /* Check whether the converted CHS can fit. Cylinder: 0-65535 @@ -665,6 +666,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) block |= ((u64)scsicmd[3]); n_block |= ((u32)scsicmd[4]); + + /* for 6-byte r/w commands, transfer length 0 + * means 256 blocks of data, not 0 block. + */ if (!n_block) n_block = 256; @@ -692,7 +697,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* Check and compose ATA command */ if (!n_block) - /* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */ + /* For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + */ return 1; if (lba) { @@ -715,7 +724,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->device |= (block >> 24) & 0xf; } - + qc->nsect = n_block; tf->nsect = n_block & 0xff; @@ -731,23 +740,23 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* The request -may- be too large for CHS addressing. */ if ((block >> 28) || (n_block > 256)) return 1; - + /* Convert LBA to CHS */ track = (u32)block / dev->sectors; cyl = track / dev->heads; head = track % dev->heads; sect = (u32)block % dev->sectors + 1; - DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", + DPRINTK("block %u track %u cyl %u head %u sect %u\n", (u32)block, track, cyl, head, sect); - + /* Check whether the converted CHS can fit. Cylinder: 0-65535 Head: 0-15 Sector: 1-255*/ - if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) return 1; - + qc->nsect = n_block; tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ tf->lbal = sect; From 3aef52311bcb1f88aa5c786302f1ae14a787f61e Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 4 Oct 2005 08:47:43 -0400 Subject: [PATCH 0284/1939] [libata scsi] tidy up SCSI lba and xfer len calculations move the redundant SCSI lba and transfer length calculation code from ata_scsi_verify_xlat() and ata_scsi_rw_xlat() to common functions. --- drivers/scsi/libata-scsi.c | 179 ++++++++++++++++++++++++------------- 1 file changed, 115 insertions(+), 64 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index d67c3fc98f7b..22434e0d4e75 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -487,6 +487,99 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) return 0; } +/** + * scsi_6_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 6-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_6_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("six-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 8; + lba |= ((u64)scsicmd[3]); + + len |= ((u32)scsicmd[4]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_10_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 10-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_10_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("ten-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 24; + lba |= ((u64)scsicmd[3]) << 16; + lba |= ((u64)scsicmd[4]) << 8; + lba |= ((u64)scsicmd[5]); + + len |= ((u32)scsicmd[7]) << 8; + len |= ((u32)scsicmd[8]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_16_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 16-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_16_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("sixteen-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 56; + lba |= ((u64)scsicmd[3]) << 48; + lba |= ((u64)scsicmd[4]) << 40; + lba |= ((u64)scsicmd[5]) << 32; + lba |= ((u64)scsicmd[6]) << 24; + lba |= ((u64)scsicmd[7]) << 16; + lba |= ((u64)scsicmd[8]) << 8; + lba |= ((u64)scsicmd[9]); + + len |= ((u32)scsicmd[10]) << 24; + len |= ((u32)scsicmd[11]) << 16; + len |= ((u32)scsicmd[12]) << 8; + len |= ((u32)scsicmd[13]); + + *plba = lba; + *plen = len; +} + /** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile @@ -508,38 +601,16 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 dev_sectors = qc->dev->n_sectors; - u64 block = 0; - u32 n_block = 0; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if (scsicmd[0] == VERIFY) { - block |= ((u64)scsicmd[2]) << 24; - block |= ((u64)scsicmd[3]) << 16; - block |= ((u64)scsicmd[4]) << 8; - block |= ((u64)scsicmd[5]); - - n_block |= ((u32)scsicmd[7]) << 8; - n_block |= ((u32)scsicmd[8]); - } - - else if (scsicmd[0] == VERIFY_16) { - block |= ((u64)scsicmd[2]) << 56; - block |= ((u64)scsicmd[3]) << 48; - block |= ((u64)scsicmd[4]) << 40; - block |= ((u64)scsicmd[5]) << 32; - block |= ((u64)scsicmd[6]) << 24; - block |= ((u64)scsicmd[7]) << 16; - block |= ((u64)scsicmd[8]) << 8; - block |= ((u64)scsicmd[9]); - - n_block |= ((u32)scsicmd[10]) << 24; - n_block |= ((u32)scsicmd[11]) << 16; - n_block |= ((u32)scsicmd[12]) << 8; - n_block |= ((u32)scsicmd[13]); - } - + if (scsicmd[0] == VERIFY) + scsi_10_lba_len(scsicmd, &block, &n_block); + else if (scsicmd[0] == VERIFY_16) + scsi_16_lba_len(scsicmd, &block, &n_block); else return 1; @@ -636,8 +707,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) struct ata_device *dev = qc->dev; unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; - u64 block = 0; - u32 n_block = 0; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = qc->dev->xfer_protocol; @@ -651,46 +722,26 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } /* Calculate the SCSI LBA and transfer length. */ - if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - block |= ((u64)scsicmd[2]) << 24; - block |= ((u64)scsicmd[3]) << 16; - block |= ((u64)scsicmd[4]) << 8; - block |= ((u64)scsicmd[5]); - - n_block |= ((u32)scsicmd[7]) << 8; - n_block |= ((u32)scsicmd[8]); - - VPRINTK("ten-byte command\n"); - } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - block |= ((u64)scsicmd[2]) << 8; - block |= ((u64)scsicmd[3]); - - n_block |= ((u32)scsicmd[4]); + switch (scsicmd[0]) { + case READ_10: + case WRITE_10: + scsi_10_lba_len(scsicmd, &block, &n_block); + break; + case READ_6: + case WRITE_6: + scsi_6_lba_len(scsicmd, &block, &n_block); /* for 6-byte r/w commands, transfer length 0 * means 256 blocks of data, not 0 block. */ if (!n_block) n_block = 256; - - VPRINTK("six-byte command\n"); - } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - block |= ((u64)scsicmd[2]) << 56; - block |= ((u64)scsicmd[3]) << 48; - block |= ((u64)scsicmd[4]) << 40; - block |= ((u64)scsicmd[5]) << 32; - block |= ((u64)scsicmd[6]) << 24; - block |= ((u64)scsicmd[7]) << 16; - block |= ((u64)scsicmd[8]) << 8; - block |= ((u64)scsicmd[9]); - - n_block |= ((u32)scsicmd[10]) << 24; - n_block |= ((u32)scsicmd[11]) << 16; - n_block |= ((u32)scsicmd[12]) << 8; - n_block |= ((u32)scsicmd[13]); - - VPRINTK("sixteen-byte command\n"); - } else { + break; + case READ_16: + case WRITE_16: + scsi_16_lba_len(scsicmd, &block, &n_block); + break; + default: DPRINTK("no-byte command\n"); return 1; } From 9d5b13021375cad2d64d56105e5f4b5f1509ced2 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 4 Oct 2005 08:48:17 -0400 Subject: [PATCH 0285/1939] [libata scsi] add CHS support to ata_scsi_start_stop_xlat() --- drivers/scsi/libata-scsi.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 22434e0d4e75..4982e6eff700 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -435,10 +435,21 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, return 1; /* power conditions not supported */ if (scsicmd[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ - tf->lbah = 0x0; - tf->lbam = 0x0; - tf->lbal = 0x0; - tf->device |= ATA_LBA; + + if (qc->dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + } else { + /* CHS */ + tf->lbal = 0x1; /* sect */ + tf->lbam = 0x0; /* cyl low */ + tf->lbah = 0x0; /* cyl high */ + } + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ } else { tf->nsect = 0; /* time period value (0 implies now) */ From 69b41e3c0223bd38cf23e3d8f1385963089fbf22 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 14:01:14 +0100 Subject: [PATCH 0286/1939] NTFS: Change ntfs_attr_find_vcn_nolock() to also take an optional attribute search context as argument. This allows calling it with the mft record mapped. Update all callers. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 6 ++-- fs/ntfs/attrib.c | 84 ++++++++++++++++++++++++++-------------------- fs/ntfs/attrib.h | 2 +- fs/ntfs/lcnalloc.c | 4 +-- fs/ntfs/mft.c | 7 ++-- 5 files changed, 59 insertions(+), 44 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 85f797a2edad..0a361ddb3b45 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -24,8 +24,10 @@ ToDo/Notes: 2.1.25-WIP - - Change ntfs_map_runlist_nolock() to also take an optional attribute - search context. This allows calling it with the mft record mapped. + - Change ntfs_map_runlist_nolock() and ntfs_attr_find_vcn_nolock() to + also take an optional attribute search context as argument. This + allows calling these functions with the mft record mapped. Update + all callers. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index b194197b72f7..2aafc87e9601 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -406,9 +406,9 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, /** * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode - * @ni: ntfs inode describing the runlist to search - * @vcn: vcn to find - * @write_locked: true if the runlist is locked for writing + * @ni: ntfs inode describing the runlist to search + * @vcn: vcn to find + * @ctx: active attribute search context if present or NULL if not * * Find the virtual cluster number @vcn in the runlist described by the ntfs * inode @ni and return the address of the runlist element containing the @vcn. @@ -416,9 +416,22 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, * If the @vcn is not mapped yet, the attempt is made to map the attribute * extent containing the @vcn and the vcn to lcn conversion is retried. * - * If @write_locked is true the caller has locked the runlist for writing and - * if false for reading. + * If @ctx is specified, it is an active search context of @ni and its base mft + * record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped + * runlist fragments and allows their mapping. If you do not have the mft + * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() + * will perform the necessary mapping and unmapping. * + * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and + * restores it before returning. Thus, @ctx will be left pointing to the same + * attribute on return as on entry. However, the actual pointers in @ctx may + * point to different memory locations on return, so you must remember to reset + * any cached pointers from the @ctx, i.e. after the call to + * ntfs_attr_find_vcn_nolock(), you will probably want to do: + * m = ctx->mrec; + * a = ctx->attr; + * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that + * you cache ctx->mrec in a variable @m of type MFT_RECORD *. * Note you need to distinguish between the lcn of the returned runlist element * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on * read and allocate clusters on write. @@ -433,22 +446,31 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, * -ENOMEM - Not enough memory to map runlist. * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). * - * Locking: - The runlist must be locked on entry and is left locked on return. - * - If @write_locked is FALSE, i.e. the runlist is locked for reading, - * the lock may be dropped inside the function so you cannot rely on - * the runlist still being the same when this function returns. + * WARNING: If @ctx is supplied, regardless of whether success or failure is + * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx + * is no longer valid, i.e. you need to either call + * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. + * In that case PTR_ERR(@ctx->mrec) will give you the error code for + * why the mapping of the old inode failed. + * + * Locking: - The runlist described by @ni must be locked for writing on entry + * and is locked on return. Note the runlist may be modified when + * needed runlist fragments need to be mapped. + * - If @ctx is NULL, the base mft record of @ni must not be mapped on + * entry and it will be left unmapped on return. + * - If @ctx is not NULL, the base mft record must be mapped on entry + * and it will be left mapped on return. */ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, - const BOOL write_locked) + ntfs_attr_search_ctx *ctx) { unsigned long flags; runlist_element *rl; int err = 0; BOOL is_retry = FALSE; - ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", - ni->mft_no, (unsigned long long)vcn, - write_locked ? "write" : "read"); + ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.", + ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out"); BUG_ON(!ni); BUG_ON(!NInoNonResident(ni)); BUG_ON(vcn < 0); @@ -482,33 +504,22 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, } if (!err && !is_retry) { /* - * The @vcn is in an unmapped region, map the runlist and - * retry. + * If the search context is invalid we cannot map the unmapped + * region. */ - if (!write_locked) { - up_read(&ni->runlist.lock); - down_write(&ni->runlist.lock); - if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != - LCN_RL_NOT_MAPPED)) { - up_write(&ni->runlist.lock); - down_read(&ni->runlist.lock); + if (IS_ERR(ctx->mrec)) + err = PTR_ERR(ctx->mrec); + else { + /* + * The @vcn is in an unmapped region, map the runlist + * and retry. + */ + err = ntfs_map_runlist_nolock(ni, vcn, ctx); + if (likely(!err)) { + is_retry = TRUE; goto retry_remap; } } - err = ntfs_map_runlist_nolock(ni, vcn, NULL); - if (!write_locked) { - up_write(&ni->runlist.lock); - down_read(&ni->runlist.lock); - } - if (likely(!err)) { - is_retry = TRUE; - goto retry_remap; - } - /* - * -EINVAL coming from a failed mapping attempt is equivalent - * to i/o error for us as it should not happen in our code - * paths. - */ if (err == -EINVAL) err = -EIO; } else if (!err) @@ -1181,6 +1192,7 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, ntfs_inode *base_ni; ntfs_debug("Entering."); + BUG_ON(IS_ERR(ctx->mrec)); if (ctx->base_ntfs_ino) base_ni = ctx->base_ntfs_ino; else diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index eeca8e500971..62f76258d9c3 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h @@ -68,7 +68,7 @@ extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, const BOOL write_locked); extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, - const VCN vcn, const BOOL write_locked); + const VCN vcn, ntfs_attr_search_ctx *ctx); int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, const u32 name_len, const IGNORE_CASE_BOOL ic, diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 5af3bf0b7eee..8e60c47fafac 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c @@ -839,7 +839,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, total_freed = real_freed = 0; - rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE); + rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, NULL); if (IS_ERR(rl)) { if (!is_rollback) ntfs_error(vol->sb, "Failed to find first runlist " @@ -893,7 +893,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, /* Attempt to map runlist. */ vcn = rl->vcn; - rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE); + rl = ntfs_attr_find_vcn_nolock(ni, vcn, NULL); if (IS_ERR(rl)) { err = PTR_ERR(rl); if (!is_rollback) diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index b011369b5956..15df34f62038 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -49,7 +49,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) ntfs_volume *vol = ni->vol; struct inode *mft_vi = vol->mft_ino; struct page *page; - unsigned long index, ofs, end_index; + unsigned long index, end_index; + unsigned ofs; BUG_ON(ni->page); /* @@ -1308,7 +1309,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) ll = mftbmp_ni->allocated_size; read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, - (ll - 1) >> vol->cluster_size_bits, TRUE); + (ll - 1) >> vol->cluster_size_bits, NULL); if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to determine last allocated " @@ -1738,7 +1739,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) ll = mft_ni->allocated_size; read_unlock_irqrestore(&mft_ni->size_lock, flags); rl = ntfs_attr_find_vcn_nolock(mft_ni, - (ll - 1) >> vol->cluster_size_bits, TRUE); + (ll - 1) >> vol->cluster_size_bits, NULL); if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { up_write(&mft_ni->runlist.lock); ntfs_error(vol->sb, "Failed to determine last allocated " From 511bea5ea2b2b330e67c9e58ffb5027caebf9052 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 14:24:21 +0100 Subject: [PATCH 0287/1939] NTFS: - Change {__,}ntfs_cluster_free() to also take an optional attribute search context as argument. This allows calling it with the mft record mapped. Update all callers. - Fix potential deadlock in ntfs_mft_data_extend_allocation_nolock() error handling by passing in the active search context when calling ntfs_cluster_free(). Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 11 +++++++---- fs/ntfs/lcnalloc.c | 41 +++++++++++++++++++++++++++++++++++------ fs/ntfs/lcnalloc.h | 40 +++++++++++++++++++++++++++++++++++----- fs/ntfs/mft.c | 13 +++++++++---- 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 0a361ddb3b45..6e4f44eed6fa 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -24,10 +24,13 @@ ToDo/Notes: 2.1.25-WIP - - Change ntfs_map_runlist_nolock() and ntfs_attr_find_vcn_nolock() to - also take an optional attribute search context as argument. This - allows calling these functions with the mft record mapped. Update - all callers. + - Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and + {__,}ntfs_cluster_free() to also take an optional attribute search + context as argument. This allows calling these functions with the + mft record mapped. Update all callers. + - Fix potential deadlock in ntfs_mft_data_extend_allocation_nolock() + error handling by passing in the active search context when calling + ntfs_cluster_free(). 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 8e60c47fafac..75313f4307e3 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c @@ -782,6 +782,7 @@ switch_to_data1_zone: search_zone = 2; * @ni: ntfs inode whose runlist describes the clusters to free * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters * @count: number of clusters to free or -1 for all clusters + * @ctx: active attribute search context if present or NULL if not * @is_rollback: true if this is a rollback operation * * Free @count clusters starting at the cluster @start_vcn in the runlist @@ -791,15 +792,39 @@ switch_to_data1_zone: search_zone = 2; * deallocated. Thus, to completely free all clusters in a runlist, use * @start_vcn = 0 and @count = -1. * + * If @ctx is specified, it is an active search context of @ni and its base mft + * record. This is needed when __ntfs_cluster_free() encounters unmapped + * runlist fragments and allows their mapping. If you do not have the mft + * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will + * perform the necessary mapping and unmapping. + * + * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it + * before returning. Thus, @ctx will be left pointing to the same attribute on + * return as on entry. However, the actual pointers in @ctx may point to + * different memory locations on return, so you must remember to reset any + * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(), + * you will probably want to do: + * m = ctx->mrec; + * a = ctx->attr; + * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that + * you cache ctx->mrec in a variable @m of type MFT_RECORD *. + * * @is_rollback should always be FALSE, it is for internal use to rollback * errors. You probably want to use ntfs_cluster_free() instead. * - * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller - * has to deal with it later. + * Note, __ntfs_cluster_free() does not modify the runlist, so you have to + * remove from the runlist or mark sparse the freed runs later. * * Return the number of deallocated clusters (not counting sparse ones) on * success and -errno on error. * + * WARNING: If @ctx is supplied, regardless of whether success or failure is + * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx + * is no longer valid, i.e. you need to either call + * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. + * In that case PTR_ERR(@ctx->mrec) will give you the error code for + * why the mapping of the old inode failed. + * * Locking: - The runlist described by @ni must be locked for writing on entry * and is locked on return. Note the runlist may be modified when * needed runlist fragments need to be mapped. @@ -807,9 +832,13 @@ switch_to_data1_zone: search_zone = 2; * on return. * - This function takes the volume lcn bitmap lock for writing and * modifies the bitmap contents. + * - If @ctx is NULL, the base mft record of @ni must not be mapped on + * entry and it will be left unmapped on return. + * - If @ctx is not NULL, the base mft record must be mapped on entry + * and it will be left mapped on return. */ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, - const BOOL is_rollback) + ntfs_attr_search_ctx *ctx, const BOOL is_rollback) { s64 delta, to_free, total_freed, real_freed; ntfs_volume *vol; @@ -839,7 +868,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, total_freed = real_freed = 0; - rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, NULL); + rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); if (IS_ERR(rl)) { if (!is_rollback) ntfs_error(vol->sb, "Failed to find first runlist " @@ -893,7 +922,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, /* Attempt to map runlist. */ vcn = rl->vcn; - rl = ntfs_attr_find_vcn_nolock(ni, vcn, NULL); + rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); if (IS_ERR(rl)) { err = PTR_ERR(rl); if (!is_rollback) @@ -961,7 +990,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, * If rollback fails, set the volume errors flag, emit an error * message, and return the error code. */ - delta = __ntfs_cluster_free(ni, start_vcn, total_freed, TRUE); + delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, TRUE); if (delta < 0) { ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " "inconsistent metadata! Unmount and run " diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h index a6a8827882e7..aa0518509cd3 100644 --- a/fs/ntfs/lcnalloc.h +++ b/fs/ntfs/lcnalloc.h @@ -27,6 +27,7 @@ #include +#include "attrib.h" #include "types.h" #include "inode.h" #include "runlist.h" @@ -44,13 +45,14 @@ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const NTFS_CLUSTER_ALLOCATION_ZONES zone); extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, - s64 count, const BOOL is_rollback); + s64 count, ntfs_attr_search_ctx *ctx, const BOOL is_rollback); /** * ntfs_cluster_free - free clusters on an ntfs volume * @ni: ntfs inode whose runlist describes the clusters to free * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters * @count: number of clusters to free or -1 for all clusters + * @ctx: active attribute search context if present or NULL if not * * Free @count clusters starting at the cluster @start_vcn in the runlist * described by the ntfs inode @ni. @@ -59,12 +61,36 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, * deallocated. Thus, to completely free all clusters in a runlist, use * @start_vcn = 0 and @count = -1. * - * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller - * has to deal with it later. + * If @ctx is specified, it is an active search context of @ni and its base mft + * record. This is needed when ntfs_cluster_free() encounters unmapped runlist + * fragments and allows their mapping. If you do not have the mft record + * mapped, you can specify @ctx as NULL and ntfs_cluster_free() will perform + * the necessary mapping and unmapping. + * + * Note, ntfs_cluster_free() saves the state of @ctx on entry and restores it + * before returning. Thus, @ctx will be left pointing to the same attribute on + * return as on entry. However, the actual pointers in @ctx may point to + * different memory locations on return, so you must remember to reset any + * cached pointers from the @ctx, i.e. after the call to ntfs_cluster_free(), + * you will probably want to do: + * m = ctx->mrec; + * a = ctx->attr; + * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that + * you cache ctx->mrec in a variable @m of type MFT_RECORD *. + * + * Note, ntfs_cluster_free() does not modify the runlist, so you have to remove + * from the runlist or mark sparse the freed runs later. * * Return the number of deallocated clusters (not counting sparse ones) on * success and -errno on error. * + * WARNING: If @ctx is supplied, regardless of whether success or failure is + * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx + * is no longer valid, i.e. you need to either call + * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. + * In that case PTR_ERR(@ctx->mrec) will give you the error code for + * why the mapping of the old inode failed. + * * Locking: - The runlist described by @ni must be locked for writing on entry * and is locked on return. Note the runlist may be modified when * needed runlist fragments need to be mapped. @@ -72,11 +98,15 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, * on return. * - This function takes the volume lcn bitmap lock for writing and * modifies the bitmap contents. + * - If @ctx is NULL, the base mft record of @ni must not be mapped on + * entry and it will be left unmapped on return. + * - If @ctx is not NULL, the base mft record must be mapped on entry + * and it will be left mapped on return. */ static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, - s64 count) + s64 count, ntfs_attr_search_ctx *ctx) { - return __ntfs_cluster_free(ni, start_vcn, count, FALSE); + return __ntfs_cluster_free(ni, start_vcn, count, ctx, FALSE); } extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 15df34f62038..5577fc6e190f 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -1952,20 +1952,21 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) NVolSetErrors(vol); return ret; } - a = ctx->attr; - a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); + ctx->attr->data.non_resident.highest_vcn = + cpu_to_sle64(old_last_vcn - 1); undo_alloc: - if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) { + if (ntfs_cluster_free(mft_ni, old_last_vcn, -1, ctx) < 0) { ntfs_error(vol->sb, "Failed to free clusters from mft data " "attribute.%s", es); NVolSetErrors(vol); } + a = ctx->attr; if (ntfs_rl_truncate_nolock(vol, &mft_ni->runlist, old_last_vcn)) { ntfs_error(vol->sb, "Failed to truncate mft data attribute " "runlist.%s", es); NVolSetErrors(vol); } - if (mp_rebuilt) { + if (mp_rebuilt && !IS_ERR(ctx->mrec)) { if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( a->data.non_resident.mapping_pairs_offset), old_alen - le16_to_cpu( @@ -1982,6 +1983,10 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) } flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); + } else if (IS_ERR(ctx->mrec)) { + ntfs_error(vol->sb, "Failed to restore attribute search " + "context.%s", es); + NVolSetErrors(vol); } if (ctx) ntfs_attr_put_search_ctx(ctx); From fc0fa7dc7d243afabdb3fb6a11d59a944a9c91f8 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 14:36:56 +0100 Subject: [PATCH 0288/1939] NTFS: - Change ntfs_cluster_alloc() to take an extra boolean parameter specifying whether the cluster are being allocated to extend an attribute or to fill a hole. - Change ntfs_attr_make_non_resident() to call ntfs_cluster_alloc() with @is_extension set to TRUE and remove the runlist terminator fixup code as this is now done by ntfs_cluster_alloc(). Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 6 ++++++ fs/ntfs/attrib.c | 10 +--------- fs/ntfs/lcnalloc.c | 15 ++++++++++++--- fs/ntfs/lcnalloc.h | 3 ++- fs/ntfs/mft.c | 6 ++++-- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 6e4f44eed6fa..aad2a3f2d1f8 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -31,6 +31,12 @@ ToDo/Notes: - Fix potential deadlock in ntfs_mft_data_extend_allocation_nolock() error handling by passing in the active search context when calling ntfs_cluster_free(). + - Change ntfs_cluster_alloc() to take an extra boolean parameter + specifying whether the cluster are being allocated to extend an + attribute or to fill a hole. + - Change ntfs_attr_make_non_resident() to call ntfs_cluster_alloc() + with @is_extension set to TRUE and remove the runlist terminator + fixup code as this is now done by ntfs_cluster_alloc(). 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 2aafc87e9601..33e689f82a55 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1566,8 +1566,6 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) new_size = (i_size_read(vi) + vol->cluster_size - 1) & ~(vol->cluster_size - 1); if (new_size > 0) { - runlist_element *rl2; - /* * Will need the page later and since the page lock nests * outside all ntfs locks, we need to get the page now. @@ -1578,7 +1576,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) return -ENOMEM; /* Start by allocating clusters to hold the attribute value. */ rl = ntfs_cluster_alloc(vol, 0, new_size >> - vol->cluster_size_bits, -1, DATA_ZONE); + vol->cluster_size_bits, -1, DATA_ZONE, TRUE); if (IS_ERR(rl)) { err = PTR_ERR(rl); ntfs_debug("Failed to allocate cluster%s, error code " @@ -1587,12 +1585,6 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) err); goto page_err_out; } - /* Change the runlist terminator to LCN_ENOENT. */ - rl2 = rl; - while (rl2->length) - rl2++; - BUG_ON(rl2->lcn != LCN_RL_NOT_MAPPED); - rl2->lcn = LCN_ENOENT; } else { rl = NULL; page = NULL; diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 75313f4307e3..29cabf93d2d2 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c @@ -76,6 +76,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, * @count: number of clusters to allocate * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) * @zone: zone from which to allocate the clusters + * @is_extension: if TRUE, this is an attribute extension * * Allocate @count clusters preferably starting at cluster @start_lcn or at the * current allocator position if @start_lcn is -1, on the mounted ntfs volume @@ -86,6 +87,13 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, * @start_vcn specifies the vcn of the first allocated cluster. This makes * merging the resulting runlist with the old runlist easier. * + * If @is_extension is TRUE, the caller is allocating clusters to extend an + * attribute and if it is FALSE, the caller is allocating clusters to fill a + * hole in an attribute. Practically the difference is that if @is_extension + * is TRUE the returned runlist will be terminated with LCN_ENOENT and if + * @is_extension is FALSE the runlist will be terminated with + * LCN_RL_NOT_MAPPED. + * * You need to check the return value with IS_ERR(). If this is false, the * function was successful and the return value is a runlist describing the * allocated cluster(s). If IS_ERR() is true, the function failed and @@ -137,7 +145,8 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, */ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, const s64 count, const LCN start_lcn, - const NTFS_CLUSTER_ALLOCATION_ZONES zone) + const NTFS_CLUSTER_ALLOCATION_ZONES zone, + const BOOL is_extension) { LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size; @@ -310,7 +319,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, continue; } bit = 1 << (lcn & 7); - ntfs_debug("bit %i.", bit); + ntfs_debug("bit 0x%x.", bit); /* If the bit is already set, go onto the next one. */ if (*byte & bit) { lcn++; @@ -729,7 +738,7 @@ switch_to_data1_zone: search_zone = 2; /* Add runlist terminator element. */ if (likely(rl)) { rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; - rl[rlpos].lcn = LCN_RL_NOT_MAPPED; + rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED; rl[rlpos].length = 0; } if (likely(page && !IS_ERR(page))) { diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h index aa0518509cd3..72cbca7003b2 100644 --- a/fs/ntfs/lcnalloc.h +++ b/fs/ntfs/lcnalloc.h @@ -42,7 +42,8 @@ typedef enum { extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, const s64 count, const LCN start_lcn, - const NTFS_CLUSTER_ALLOCATION_ZONES zone); + const NTFS_CLUSTER_ALLOCATION_ZONES zone, + const BOOL is_extension); extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, ntfs_attr_search_ctx *ctx, const BOOL is_rollback); diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 5577fc6e190f..0c65cbb8c5cf 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -1355,7 +1355,8 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) up_write(&vol->lcnbmp_lock); ntfs_unmap_page(page); /* Allocate a cluster from the DATA_ZONE. */ - rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE); + rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE, + TRUE); if (IS_ERR(rl2)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to allocate a cluster for " @@ -1780,7 +1781,8 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) nr > min_nr ? "default" : "minimal", (long long)nr); old_last_vcn = rl[1].vcn; do { - rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE); + rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE, + TRUE); if (likely(!IS_ERR(rl2))) break; if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) { From 8925d4f0d3479b9c5ed7e49acc648beccca95f21 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 14:48:20 +0100 Subject: [PATCH 0289/1939] NTFS: Change ntfs_attr_make_non_resident to take the attribute value size as an extra parameter. This is needed since we need to know the size before we can map the mft record and our callers always know it. The reason we cannot simply read the size from the vfs inode i_size is that this is not necessarily uptodate. This happens when ntfs_attr_make_non_resident() is called in the ->truncate call path. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 6 ++++++ fs/ntfs/attrib.c | 13 ++++++++++--- fs/ntfs/attrib.h | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index aad2a3f2d1f8..60ba3c5cb2ea 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -37,6 +37,12 @@ ToDo/Notes: - Change ntfs_attr_make_non_resident() to call ntfs_cluster_alloc() with @is_extension set to TRUE and remove the runlist terminator fixup code as this is now done by ntfs_cluster_alloc(). + - Change ntfs_attr_make_non_resident to take the attribute value size + as an extra parameter. This is needed since we need to know the size + before we can map the mft record and our callers always know it. The + reason we cannot simply read the size from the vfs inode i_size is + that this is not necessarily uptodate. This happens when + ntfs_attr_make_non_resident() is called in the ->truncate call path. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 33e689f82a55..380f70a5f2e1 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1501,10 +1501,17 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, /** * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute * @ni: ntfs inode describing the attribute to convert + * @data_size: size of the resident data to copy to the non-resident attribute * * Convert the resident ntfs attribute described by the ntfs inode @ni to a * non-resident one. * + * @data_size must be equal to the attribute value size. This is needed since + * we need to know the size before we can map the mft record and our callers + * always know it. The reason we cannot simply read the size from the vfs + * inode i_size is that this is not necessarily uptodate. This happens when + * ntfs_attr_make_non_resident() is called in the ->truncate call path(s). + * * Return 0 on success and -errno on error. The following error return codes * are defined: * -EPERM - The attribute is not allowed to be non-resident. @@ -1525,7 +1532,7 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, * * Locking: - The caller must hold i_sem on the inode. */ -int ntfs_attr_make_non_resident(ntfs_inode *ni) +int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) { s64 new_size; struct inode *vi = VFS_I(ni); @@ -1563,7 +1570,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) * The size needs to be aligned to a cluster boundary for allocation * purposes. */ - new_size = (i_size_read(vi) + vol->cluster_size - 1) & + new_size = (data_size + vol->cluster_size - 1) & ~(vol->cluster_size - 1); if (new_size > 0) { /* @@ -1647,7 +1654,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) * attribute value. */ attr_size = le32_to_cpu(a->data.resident.value_length); - BUG_ON(attr_size != i_size_read(vi)); + BUG_ON(attr_size != data_size); if (page && !PageUptodate(page)) { kaddr = kmap_atomic(page, KM_USER0); memcpy(kaddr, (u8*)a + diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index 62f76258d9c3..a959af9cef12 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h @@ -103,7 +103,7 @@ extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size); -extern int ntfs_attr_make_non_resident(ntfs_inode *ni); +extern int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size); extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val); From 2a6fc4e1b0f7d2ec3711d5b1782fb30f78cca765 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 14:57:15 +0100 Subject: [PATCH 0290/1939] NTFS: Fix ntfs_attr_make_non_resident() to update the vfs inode i_blocks which is zero for a resident attribute but should no longer be zero once the attribute is non-resident as it then has real clusters allocated. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 4 ++++ fs/ntfs/attrib.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 60ba3c5cb2ea..045beda82942 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -43,6 +43,10 @@ ToDo/Notes: reason we cannot simply read the size from the vfs inode i_size is that this is not necessarily uptodate. This happens when ntfs_attr_make_non_resident() is called in the ->truncate call path. + - Fix ntfs_attr_make_non_resident() to update the vfs inode i_blocks + which is zero for a resident attribute but should no longer be zero + once the attribute is non-resident as it then has real clusters + allocated. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 380f70a5f2e1..8821e2d088b7 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1719,7 +1719,9 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) ffs(ni->itype.compressed.block_size) - 1; ni->itype.compressed.block_clusters = 1U << a->data.non_resident.compression_unit; - } + vi->i_blocks = ni->itype.compressed.size >> 9; + } else + vi->i_blocks = ni->allocated_size >> 9; write_unlock_irqrestore(&ni->size_lock, flags); /* * This needs to be last since the address space operations ->readpage From 2d86829b846d1447a6ab5af4060fc9f301521317 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 15:18:56 +0100 Subject: [PATCH 0291/1939] NTFS: Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to extend the allocation of an attributes. Optionally, the data size, but not the initialized size can be extended, too. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 3 + fs/ntfs/attrib.c | 634 ++++++++++++++++++++++++++++++++++++++++++++++ fs/ntfs/attrib.h | 3 + 3 files changed, 640 insertions(+) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 045beda82942..6c5bdfbb7bbf 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -47,6 +47,9 @@ ToDo/Notes: which is zero for a resident attribute but should no longer be zero once the attribute is non-resident as it then has real clusters allocated. + - Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to + extend the allocation of an attributes. Optionally, the data size, + but not the initialized size can be extended, too. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 8821e2d088b7..bc25e88ad468 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1834,6 +1834,640 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) return err; } +/** + * ntfs_attr_extend_allocation - extend the allocated space of an attribute + * @ni: ntfs inode of the attribute whose allocation to extend + * @new_alloc_size: new size in bytes to which to extend the allocation to + * @new_data_size: new size in bytes to which to extend the data to + * @data_start: beginning of region which is required to be non-sparse + * + * Extend the allocated space of an attribute described by the ntfs inode @ni + * to @new_alloc_size bytes. If @data_start is -1, the whole extension may be + * implemented as a hole in the file (as long as both the volume and the ntfs + * inode @ni have sparse support enabled). If @data_start is >= 0, then the + * region between the old allocated size and @data_start - 1 may be made sparse + * but the regions between @data_start and @new_alloc_size must be backed by + * actual clusters. + * + * If @new_data_size is -1, it is ignored. If it is >= 0, then the data size + * of the attribute is extended to @new_data_size. Note that the i_size of the + * vfs inode is not updated. Only the data size in the base attribute record + * is updated. The caller has to update i_size separately if this is required. + * WARNING: It is a BUG() for @new_data_size to be smaller than the old data + * size as well as for @new_data_size to be greater than @new_alloc_size. + * + * For resident attributes this involves resizing the attribute record and if + * necessary moving it and/or other attributes into extent mft records and/or + * converting the attribute to a non-resident attribute which in turn involves + * extending the allocation of a non-resident attribute as described below. + * + * For non-resident attributes this involves allocating clusters in the data + * zone on the volume (except for regions that are being made sparse) and + * extending the run list to describe the allocated clusters as well as + * updating the mapping pairs array of the attribute. This in turn involves + * resizing the attribute record and if necessary moving it and/or other + * attributes into extent mft records and/or splitting the attribute record + * into multiple extent attribute records. + * + * Also, the attribute list attribute is updated if present and in some of the + * above cases (the ones where extent mft records/attributes come into play), + * an attribute list attribute is created if not already present. + * + * Return the new allocated size on success and -errno on error. In the case + * that an error is encountered but a partial extension at least up to + * @data_start (if present) is possible, the allocation is partially extended + * and this is returned. This means the caller must check the returned size to + * determine if the extension was partial. If @data_start is -1 then partial + * allocations are not performed. + * + * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA. + * + * Locking: This function takes the runlist lock of @ni for writing as well as + * locking the mft record of the base ntfs inode. These locks are maintained + * throughout execution of the function. These locks are required so that the + * attribute can be resized safely and so that it can for example be converted + * from resident to non-resident safely. + * + * TODO: At present attribute list attribute handling is not implemented. + * + * TODO: At present it is not safe to call this function for anything other + * than the $DATA attribute(s) of an uncompressed and unencrypted file. + */ +s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, + const s64 new_data_size, const s64 data_start) +{ + VCN vcn; + s64 ll, allocated_size, start = data_start; + struct inode *vi = VFS_I(ni); + ntfs_volume *vol = ni->vol; + ntfs_inode *base_ni; + MFT_RECORD *m; + ATTR_RECORD *a; + ntfs_attr_search_ctx *ctx; + runlist_element *rl, *rl2; + unsigned long flags; + int err, mp_size; + u32 attr_len = 0; /* Silence stupid gcc warning. */ + BOOL mp_rebuilt; + +#ifdef NTFS_DEBUG + read_lock_irqsave(&ni->size_lock, flags); + allocated_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " + "old_allocated_size 0x%llx, " + "new_allocated_size 0x%llx, new_data_size 0x%llx, " + "data_start 0x%llx.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), + (unsigned long long)allocated_size, + (unsigned long long)new_alloc_size, + (unsigned long long)new_data_size, + (unsigned long long)start); +#endif +retry_extend: + /* + * For non-resident attributes, @start and @new_size need to be aligned + * to cluster boundaries for allocation purposes. + */ + if (NInoNonResident(ni)) { + if (start > 0) + start &= ~(s64)vol->cluster_size_mask; + new_alloc_size = (new_alloc_size + vol->cluster_size - 1) & + ~(s64)vol->cluster_size_mask; + } + BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size); + /* Check if new size is allowed in $AttrDef. */ + err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size); + if (unlikely(err)) { + /* Only emit errors when the write will fail completely. */ + read_lock_irqsave(&ni->size_lock, flags); + allocated_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (start < 0 || start >= allocated_size) { + if (err == -ERANGE) { + ntfs_error(vol->sb, "Cannot extend allocation " + "of inode 0x%lx, attribute " + "type 0x%x, because the new " + "allocation would exceed the " + "maximum allowed size for " + "this attribute type.", + vi->i_ino, (unsigned) + le32_to_cpu(ni->type)); + } else { + ntfs_error(vol->sb, "Cannot extend allocation " + "of inode 0x%lx, attribute " + "type 0x%x, because this " + "attribute type is not " + "defined on the NTFS volume. " + "Possible corruption! You " + "should run chkdsk!", + vi->i_ino, (unsigned) + le32_to_cpu(ni->type)); + } + } + /* Translate error code to be POSIX conformant for write(2). */ + if (err == -ERANGE) + err = -EFBIG; + else + err = -EIO; + return err; + } + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + /* + * We will be modifying both the runlist (if non-resident) and the mft + * record so lock them both down. + */ + down_write(&ni->runlist.lock); + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + ctx = NULL; + goto err_out; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + read_lock_irqsave(&ni->size_lock, flags); + allocated_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + /* + * If non-resident, seek to the last extent. If resident, there is + * only one extent, so seek to that. + */ + vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits : + 0; + /* + * Abort if someone did the work whilst we waited for the locks. If we + * just converted the attribute from resident to non-resident it is + * likely that exactly this has happened already. We cannot quite + * abort if we need to update the data size. + */ + if (unlikely(new_alloc_size <= allocated_size)) { + ntfs_debug("Allocated size already exceeds requested size."); + new_alloc_size = allocated_size; + if (new_data_size < 0) + goto done; + /* + * We want the first attribute extent so that we can update the + * data size. + */ + vcn = 0; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, vcn, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + m = ctx->mrec; + a = ctx->attr; + /* Use goto to reduce indentation. */ + if (a->non_resident) + goto do_non_resident_extend; + BUG_ON(NInoNonResident(ni)); + /* The total length of the attribute value. */ + attr_len = le32_to_cpu(a->data.resident.value_length); + /* + * Extend the attribute record to be able to store the new attribute + * size. ntfs_attr_record_resize() will not do anything if the size is + * not changing. + */ + if (new_alloc_size < vol->mft_record_size && + !ntfs_attr_record_resize(m, a, + le16_to_cpu(a->data.resident.value_offset) + + new_alloc_size)) { + /* The resize succeeded! */ + write_lock_irqsave(&ni->size_lock, flags); + ni->allocated_size = le32_to_cpu(a->length) - + le16_to_cpu(a->data.resident.value_offset); + write_unlock_irqrestore(&ni->size_lock, flags); + if (new_data_size >= 0) { + BUG_ON(new_data_size < attr_len); + a->data.resident.value_length = + cpu_to_le32((u32)new_data_size); + } + goto flush_done; + } + /* + * We have to drop all the locks so we can call + * ntfs_attr_make_non_resident(). This could be optimised by try- + * locking the first page cache page and only if that fails dropping + * the locks, locking the page, and redoing all the locking and + * lookups. While this would be a huge optimisation, it is not worth + * it as this is definitely a slow code path. + */ + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); + /* + * Not enough space in the mft record, try to make the attribute + * non-resident and if successful restart the extension process. + */ + err = ntfs_attr_make_non_resident(ni, attr_len); + if (likely(!err)) + goto retry_extend; + /* + * Could not make non-resident. If this is due to this not being + * permitted for this attribute type or there not being enough space, + * try to make other attributes non-resident. Otherwise fail. + */ + if (unlikely(err != -EPERM && err != -ENOSPC)) { + /* Only emit errors when the write will fail completely. */ + read_lock_irqsave(&ni->size_lock, flags); + allocated_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation of " + "inode 0x%lx, attribute type 0x%x, " + "because the conversion from resident " + "to non-resident attribute failed " + "with error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + if (err != -ENOMEM) + err = -EIO; + goto conv_err_out; + } + /* TODO: Not implemented from here, abort. */ + read_lock_irqsave(&ni->size_lock, flags); + allocated_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (start < 0 || start >= allocated_size) { + if (err == -ENOSPC) + ntfs_error(vol->sb, "Not enough space in the mft " + "record/on disk for the non-resident " + "attribute value. This case is not " + "implemented yet."); + else /* if (err == -EPERM) */ + ntfs_error(vol->sb, "This attribute type may not be " + "non-resident. This case is not " + "implemented yet."); + } + err = -EOPNOTSUPP; + goto conv_err_out; +#if 0 + // TODO: Attempt to make other attributes non-resident. + if (!err) + goto do_resident_extend; + /* + * Both the attribute list attribute and the standard information + * attribute must remain in the base inode. Thus, if this is one of + * these attributes, we have to try to move other attributes out into + * extent mft records instead. + */ + if (ni->type == AT_ATTRIBUTE_LIST || + ni->type == AT_STANDARD_INFORMATION) { + // TODO: Attempt to move other attributes into extent mft + // records. + err = -EOPNOTSUPP; + if (!err) + goto do_resident_extend; + goto err_out; + } + // TODO: Attempt to move this attribute to an extent mft record, but + // only if it is not already the only attribute in an mft record in + // which case there would be nothing to gain. + err = -EOPNOTSUPP; + if (!err) + goto do_resident_extend; + /* There is nothing we can do to make enough space. )-: */ + goto err_out; +#endif +do_non_resident_extend: + BUG_ON(!NInoNonResident(ni)); + if (new_alloc_size == allocated_size) { + BUG_ON(vcn); + goto alloc_done; + } + /* + * If the data starts after the end of the old allocation, this is a + * $DATA attribute and sparse attributes are enabled on the volume and + * for this inode, then create a sparse region between the old + * allocated size and the start of the data. Otherwise simply proceed + * with filling the whole space between the old allocated size and the + * new allocated size with clusters. + */ + if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA || + !NVolSparseEnabled(vol) || NInoSparseDisabled(ni)) + goto skip_sparse; + // TODO: This is not implemented yet. We just fill in with real + // clusters for now... + ntfs_debug("Inserting holes is not-implemented yet. Falling back to " + "allocating real clusters instead."); +skip_sparse: + rl = ni->runlist.rl; + if (likely(rl)) { + /* Seek to the end of the runlist. */ + while (rl->length) + rl++; + } + /* If this attribute extent is not mapped, map it now. */ + if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED || + (rl->lcn == LCN_ENOENT && rl > ni->runlist.rl && + (rl-1)->lcn == LCN_RL_NOT_MAPPED))) { + if (!rl && !allocated_size) + goto first_alloc; + rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl); + if (IS_ERR(rl)) { + err = PTR_ERR(rl); + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation " + "of inode 0x%lx, attribute " + "type 0x%x, because the " + "mapping of a runlist " + "fragment failed with error " + "code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), + err); + if (err != -ENOMEM) + err = -EIO; + goto err_out; + } + ni->runlist.rl = rl; + /* Seek to the end of the runlist. */ + while (rl->length) + rl++; + } + /* + * We now know the runlist of the last extent is mapped and @rl is at + * the end of the runlist. We want to begin allocating clusters + * starting at the last allocated cluster to reduce fragmentation. If + * there are no valid LCNs in the attribute we let the cluster + * allocator choose the starting cluster. + */ + /* If the last LCN is a hole or simillar seek back to last real LCN. */ + while (rl->lcn < 0 && rl > ni->runlist.rl) + rl--; +first_alloc: + // FIXME: Need to implement partial allocations so at least part of the + // write can be performed when start >= 0. (Needed for POSIX write(2) + // conformance.) + rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits, + (new_alloc_size - allocated_size) >> + vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ? + rl->lcn + rl->length : -1, DATA_ZONE, TRUE); + if (IS_ERR(rl2)) { + err = PTR_ERR(rl2); + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation of " + "inode 0x%lx, attribute type 0x%x, " + "because the allocation of clusters " + "failed with error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + if (err != -ENOMEM && err != -ENOSPC) + err = -EIO; + goto err_out; + } + rl = ntfs_runlists_merge(ni->runlist.rl, rl2); + if (IS_ERR(rl)) { + err = PTR_ERR(rl); + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation of " + "inode 0x%lx, attribute type 0x%x, " + "because the runlist merge failed " + "with error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + if (err != -ENOMEM) + err = -EIO; + if (ntfs_cluster_free_from_rl(vol, rl2)) { + ntfs_error(vol->sb, "Failed to release allocated " + "cluster(s) in error code path. Run " + "chkdsk to recover the lost " + "cluster(s)."); + NVolSetErrors(vol); + } + ntfs_free(rl2); + goto err_out; + } + ni->runlist.rl = rl; + ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size - + allocated_size) >> vol->cluster_size_bits); + /* Find the runlist element with which the attribute extent starts. */ + ll = sle64_to_cpu(a->data.non_resident.lowest_vcn); + rl2 = ntfs_rl_find_vcn_nolock(rl, ll); + BUG_ON(!rl2); + BUG_ON(!rl2->length); + BUG_ON(rl2->lcn < LCN_HOLE); + mp_rebuilt = FALSE; + /* Get the size for the new mapping pairs array for this extent. */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); + if (unlikely(mp_size <= 0)) { + err = mp_size; + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation of " + "inode 0x%lx, attribute type 0x%x, " + "because determining the size for the " + "mapping pairs failed with error code " + "%i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + err = -EIO; + goto undo_alloc; + } + /* Extend the attribute record to fit the bigger mapping pairs array. */ + attr_len = le32_to_cpu(a->length); + err = ntfs_attr_record_resize(m, a, mp_size + + le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); + if (unlikely(err)) { + BUG_ON(err != -ENOSPC); + // TODO: Deal with this by moving this extent to a new mft + // record or by starting a new extent in a new mft record, + // possibly by extending this extent partially and filling it + // and creating a new extent for the remainder, or by making + // other attributes non-resident and/or by moving other + // attributes out of this mft record. + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Not enough space in the mft " + "record for the extended attribute " + "record. This case is not " + "implemented yet."); + err = -EOPNOTSUPP; + goto undo_alloc; + } + mp_rebuilt = TRUE; + /* Generate the mapping pairs array directly into the attr record. */ + err = ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->data.non_resident.mapping_pairs_offset), + mp_size, rl2, ll, -1, NULL); + if (unlikely(err)) { + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot extend allocation of " + "inode 0x%lx, attribute type 0x%x, " + "because building the mapping pairs " + "failed with error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + err = -EIO; + goto undo_alloc; + } + /* Update the highest_vcn. */ + a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> + vol->cluster_size_bits) - 1); + /* + * We now have extended the allocated size of the attribute. Reflect + * this in the ntfs_inode structure and the attribute record. + */ + if (a->data.non_resident.lowest_vcn) { + /* + * We are not in the first attribute extent, switch to it, but + * first ensure the changes will make it to disk later. + */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + ntfs_attr_reinit_search_ctx(ctx); + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) + goto restore_undo_alloc; + /* @m is not used any more so no need to set it. */ + a = ctx->attr; + } + write_lock_irqsave(&ni->size_lock, flags); + ni->allocated_size = new_alloc_size; + a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); + /* + * FIXME: This would fail if @ni is a directory, $MFT, or an index, + * since those can have sparse/compressed set. For example can be + * set compressed even though it is not compressed itself and in that + * case the bit means that files are to be created compressed in the + * directory... At present this is ok as this code is only called for + * regular files, and only for their $DATA attribute(s). + * FIXME: The calculation is wrong if we created a hole above. For now + * it does not matter as we never create holes. + */ + if (NInoSparse(ni) || NInoCompressed(ni)) { + ni->itype.compressed.size += new_alloc_size - allocated_size; + a->data.non_resident.compressed_size = + cpu_to_sle64(ni->itype.compressed.size); + vi->i_blocks = ni->itype.compressed.size >> 9; + } else + vi->i_blocks = new_alloc_size >> 9; + write_unlock_irqrestore(&ni->size_lock, flags); +alloc_done: + if (new_data_size >= 0) { + BUG_ON(new_data_size < + sle64_to_cpu(a->data.non_resident.data_size)); + a->data.non_resident.data_size = cpu_to_sle64(new_data_size); + } +flush_done: + /* Ensure the changes make it to disk. */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); +done: + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); + ntfs_debug("Done, new_allocated_size 0x%llx.", + (unsigned long long)new_alloc_size); + return new_alloc_size; +restore_undo_alloc: + if (start < 0 || start >= allocated_size) + ntfs_error(vol->sb, "Cannot complete extension of allocation " + "of inode 0x%lx, attribute type 0x%x, because " + "lookup of first attribute extent failed with " + "error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + if (err == -ENOENT) + err = -EIO; + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, + allocated_size >> vol->cluster_size_bits, NULL, 0, + ctx)) { + ntfs_error(vol->sb, "Failed to find last attribute extent of " + "attribute in error code path. Run chkdsk to " + "recover."); + write_lock_irqsave(&ni->size_lock, flags); + ni->allocated_size = new_alloc_size; + /* + * FIXME: This would fail if @ni is a directory... See above. + * FIXME: The calculation is wrong if we created a hole above. + * For now it does not matter as we never create holes. + */ + if (NInoSparse(ni) || NInoCompressed(ni)) { + ni->itype.compressed.size += new_alloc_size - + allocated_size; + vi->i_blocks = ni->itype.compressed.size >> 9; + } else + vi->i_blocks = new_alloc_size >> 9; + write_unlock_irqrestore(&ni->size_lock, flags); + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); + /* + * The only thing that is now wrong is the allocated size of the + * base attribute extent which chkdsk should be able to fix. + */ + NVolSetErrors(vol); + return err; + } + ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64( + (allocated_size >> vol->cluster_size_bits) - 1); +undo_alloc: + ll = allocated_size >> vol->cluster_size_bits; + if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) { + ntfs_error(vol->sb, "Failed to release allocated cluster(s) " + "in error code path. Run chkdsk to recover " + "the lost cluster(s)."); + NVolSetErrors(vol); + } + m = ctx->mrec; + a = ctx->attr; + /* + * If the runlist truncation fails and/or the search context is no + * longer valid, we cannot resize the attribute record or build the + * mapping pairs array thus we mark the inode bad so that no access to + * the freed clusters can happen. + */ + if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) { + ntfs_error(vol->sb, "Failed to %s in error code path. Run " + "chkdsk to recover.", IS_ERR(m) ? + "restore attribute search context" : + "truncate attribute runlist"); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } else if (mp_rebuilt) { + if (ntfs_attr_record_resize(m, a, attr_len)) { + ntfs_error(vol->sb, "Failed to restore attribute " + "record in error code path. Run " + "chkdsk to recover."); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } else /* if (success) */ { + if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( + a->data.non_resident. + mapping_pairs_offset), attr_len - + le16_to_cpu(a->data.non_resident. + mapping_pairs_offset), rl2, ll, -1, + NULL)) { + ntfs_error(vol->sb, "Failed to restore " + "mapping pairs array in error " + "code path. Run chkdsk to " + "recover."); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + } + } +err_out: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); +conv_err_out: + ntfs_debug("Failed. Returning error code %i.", err); + return err; +} + /** * ntfs_attr_set - fill (a part of) an attribute with a byte * @ni: ntfs inode describing the attribute to fill diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index a959af9cef12..9074886b44ba 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h @@ -105,6 +105,9 @@ extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, extern int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size); +extern s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, + const s64 new_data_size, const s64 data_start); + extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val); From 54dac83c426a1a03bd139c5ac7e938890bd2693e Mon Sep 17 00:00:00 2001 From: Jeff Raubitschek Date: Tue, 4 Oct 2005 10:21:19 -0400 Subject: [PATCH 0292/1939] [libata passthru] fix leak on error --- drivers/scsi/libata-scsi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 98057563a3cc..75cb685e320b 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -116,8 +116,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) if (args[3]) { argsize = SECTOR_SIZE * args[3]; argbuf = kmalloc(argsize, GFP_KERNEL); - if (argbuf == NULL) - return -ENOMEM; + if (argbuf == NULL) { + rc = -ENOMEM; + goto error; + } scsi_cmd[1] = (4 << 1); /* PIO Data-in */ scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, From dd072330d1a60be11a5c284fa1e645350750a4fc Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 15:39:02 +0100 Subject: [PATCH 0293/1939] NTFS: Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports uncompressed and unencrypted files. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 20 +- fs/ntfs/inode.c | 497 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 471 insertions(+), 46 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 6c5bdfbb7bbf..70ad4be7a7fe 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -3,16 +3,14 @@ ToDo/Notes: - In between ntfs_prepare/commit_write, need exclusion between simultaneous file extensions. This is given to us by holding i_sem on the inode. The only places in the kernel when a file is resized - are prepare/commit write and truncate for both of which i_sem is - held. Just have to be careful in readpage/writepage and all other - helpers not running under i_sem that we play nice... - Also need to be careful with initialized_size extention in - ntfs_prepare_write. Basically, just be _very_ careful in this code... - UPDATE: The only things that need to be checked are read/writepage - which do not hold i_sem. Note writepage cannot change i_size but it - needs to cope with a concurrent i_size change, just like readpage. - Also both need to cope with concurrent changes to the other sizes, - i.e. initialized/allocated/compressed size, as well. + are prepare/commit write and ntfs_truncate() for both of which i_sem + is held. Just have to be careful in read-/writepage and other helpers + not running under i_sem that we play nice... Also need to be careful + with initialized_size extention in ntfs_prepare_write and writepage. + UPDATE: The only things that need to be checked are + prepare/commit_write as well as the compressed write and the other + attribute resize/write cases like index attributes, etc. For now + none of these are implemented so are safe. - Implement mft.c::sync_mft_mirror_umount(). We currently will just leave the volume dirty on umount if the final iput(vol->mft_ino) causes a write of any mirrored mft records due to the mft mirror @@ -50,6 +48,8 @@ ToDo/Notes: - Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to extend the allocation of an attributes. Optionally, the data size, but not the initialized size can be extended, too. + - Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports + uncompressed and unencrypted files. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 7ec045131808..a1682342baa6 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -30,6 +30,7 @@ #include "debug.h" #include "inode.h" #include "attrib.h" +#include "lcnalloc.h" #include "malloc.h" #include "mft.h" #include "time.h" @@ -2291,11 +2292,16 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) #ifdef NTFS_RW +static const char *es = " Leaving inconsistent metadata. Unmount and run " + "chkdsk."; + /** * ntfs_truncate - called when the i_size of an ntfs inode is changed * @vi: inode for which the i_size was changed * - * We do not support i_size changes yet. + * We only support i_size changes for normal files at present, i.e. not + * compressed and not encrypted. This is enforced in ntfs_setattr(), see + * below. * * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and * that the change is allowed. @@ -2306,80 +2312,499 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) * Returns 0 on success or -errno on error. * * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for - * writing. The only case where ->i_alloc_sem is not held is + * writing. The only case in the kernel where ->i_alloc_sem is not held is * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called - * with the current i_size as the offset which means that it is a noop as far - * as ntfs_truncate() is concerned. + * with the current i_size as the offset. The analogous place in NTFS is in + * fs/ntfs/file.c::ntfs_file_buffered_write() where we call vmtruncate() again + * without holding ->i_alloc_sem. */ int ntfs_truncate(struct inode *vi) { - ntfs_inode *ni = NTFS_I(vi); + s64 new_size, old_size, nr_freed, new_alloc_size, old_alloc_size; + VCN highest_vcn; + unsigned long flags; + ntfs_inode *base_ni, *ni = NTFS_I(vi); ntfs_volume *vol = ni->vol; ntfs_attr_search_ctx *ctx; MFT_RECORD *m; ATTR_RECORD *a; const char *te = " Leaving file length out of sync with i_size."; - int err; + int err, mp_size, size_change, alloc_change; + u32 attr_len; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); BUG_ON(NInoAttr(ni)); + BUG_ON(S_ISDIR(vi->i_mode)); + BUG_ON(NInoMstProtected(ni)); BUG_ON(ni->nr_extents < 0); - m = map_mft_record(ni); +retry_truncate: + /* + * Lock the runlist for writing and map the mft record to ensure it is + * safe to mess with the attribute runlist and sizes. + */ + down_write(&ni->runlist.lock); + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + m = map_mft_record(base_ni); if (IS_ERR(m)) { err = PTR_ERR(m); ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " "(error code %d).%s", vi->i_ino, err, te); ctx = NULL; m = NULL; - goto err_out; + goto old_bad_out; } - ctx = ntfs_attr_get_search_ctx(ni, m); + ctx = ntfs_attr_get_search_ctx(base_ni, m); if (unlikely(!ctx)) { ntfs_error(vi->i_sb, "Failed to allocate a search context for " "inode 0x%lx (not enough memory).%s", vi->i_ino, te); err = -ENOMEM; - goto err_out; + goto old_bad_out; } err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { - if (err == -ENOENT) + if (err == -ENOENT) { ntfs_error(vi->i_sb, "Open attribute is missing from " "mft record. Inode 0x%lx is corrupt. " - "Run chkdsk.", vi->i_ino); - else + "Run chkdsk.%s", vi->i_ino, te); + err = -EIO; + } else ntfs_error(vi->i_sb, "Failed to lookup attribute in " - "inode 0x%lx (error code %d).", - vi->i_ino, err); + "inode 0x%lx (error code %d).%s", + vi->i_ino, err, te); + goto old_bad_out; + } + m = ctx->mrec; + a = ctx->attr; + /* + * The i_size of the vfs inode is the new size for the attribute value. + */ + new_size = i_size_read(vi); + /* The current size of the attribute value is the old size. */ + old_size = ntfs_attr_size(a); + /* Calculate the new allocated size. */ + if (NInoNonResident(ni)) + new_alloc_size = (new_size + vol->cluster_size - 1) & + ~(s64)vol->cluster_size_mask; + else + new_alloc_size = (new_size + 7) & ~7; + /* The current allocated size is the old allocated size. */ + read_lock_irqsave(&ni->size_lock, flags); + old_alloc_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + /* + * The change in the file size. This will be 0 if no change, >0 if the + * size is growing, and <0 if the size is shrinking. + */ + size_change = -1; + if (new_size - old_size >= 0) { + size_change = 1; + if (new_size == old_size) + size_change = 0; + } + /* As above for the allocated size. */ + alloc_change = -1; + if (new_alloc_size - old_alloc_size >= 0) { + alloc_change = 1; + if (new_alloc_size == old_alloc_size) + alloc_change = 0; + } + /* + * If neither the size nor the allocation are being changed there is + * nothing to do. + */ + if (!size_change && !alloc_change) + goto unm_done; + /* If the size is changing, check if new size is allowed in $AttrDef. */ + if (size_change) { + err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); + if (unlikely(err)) { + if (err == -ERANGE) { + ntfs_error(vol->sb, "Truncate would cause the " + "inode 0x%lx to %simum size " + "for its attribute type " + "(0x%x). Aborting truncate.", + vi->i_ino, + new_size > old_size ? "exceed " + "the max" : "go under the min", + le32_to_cpu(ni->type)); + err = -EFBIG; + } else { + ntfs_error(vol->sb, "Inode 0x%lx has unknown " + "attribute type 0x%x. " + "Aborting truncate.", + vi->i_ino, + le32_to_cpu(ni->type)); + err = -EIO; + } + /* Reset the vfs inode size to the old size. */ + i_size_write(vi, old_size); + goto err_out; + } + } + if (NInoCompressed(ni) || NInoEncrypted(ni)) { + ntfs_warning(vi->i_sb, "Changes in inode size are not " + "supported yet for %s files, ignoring.", + NInoCompressed(ni) ? "compressed" : + "encrypted"); + err = -EOPNOTSUPP; + goto bad_out; + } + if (a->non_resident) + goto do_non_resident_truncate; + BUG_ON(NInoNonResident(ni)); + /* Resize the attribute record to best fit the new attribute size. */ + if (new_size < vol->mft_record_size && + !ntfs_resident_attr_value_resize(m, a, new_size)) { + unsigned long flags; + + /* The resize succeeded! */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + write_lock_irqsave(&ni->size_lock, flags); + /* Update the sizes in the ntfs inode and all is done. */ + ni->allocated_size = le32_to_cpu(a->length) - + le16_to_cpu(a->data.resident.value_offset); + /* + * Note ntfs_resident_attr_value_resize() has already done any + * necessary data clearing in the attribute record. When the + * file is being shrunk vmtruncate() will already have cleared + * the top part of the last partial page, i.e. since this is + * the resident case this is the page with index 0. However, + * when the file is being expanded, the page cache page data + * between the old data_size, i.e. old_size, and the new_size + * has not been zeroed. Fortunately, we do not need to zero it + * either since on one hand it will either already be zero due + * to both readpage and writepage clearing partial page data + * beyond i_size in which case there is nothing to do or in the + * case of the file being mmap()ped at the same time, POSIX + * specifies that the behaviour is unspecified thus we do not + * have to do anything. This means that in our implementation + * in the rare case that the file is mmap()ped and a write + * occured into the mmap()ped region just beyond the file size + * and writepage has not yet been called to write out the page + * (which would clear the area beyond the file size) and we now + * extend the file size to incorporate this dirty region + * outside the file size, a write of the page would result in + * this data being written to disk instead of being cleared. + * Given both POSIX and the Linux mmap(2) man page specify that + * this corner case is undefined, we choose to leave it like + * that as this is much simpler for us as we cannot lock the + * relevant page now since we are holding too many ntfs locks + * which would result in a lock reversal deadlock. + */ + ni->initialized_size = new_size; + write_unlock_irqrestore(&ni->size_lock, flags); + goto unm_done; + } + /* If the above resize failed, this must be an attribute extension. */ + BUG_ON(size_change < 0); + /* + * We have to drop all the locks so we can call + * ntfs_attr_make_non_resident(). This could be optimised by try- + * locking the first page cache page and only if that fails dropping + * the locks, locking the page, and redoing all the locking and + * lookups. While this would be a huge optimisation, it is not worth + * it as this is definitely a slow code path as it only ever can happen + * once for any given file. + */ + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); + /* + * Not enough space in the mft record, try to make the attribute + * non-resident and if successful restart the truncation process. + */ + err = ntfs_attr_make_non_resident(ni, old_size); + if (likely(!err)) + goto retry_truncate; + /* + * Could not make non-resident. If this is due to this not being + * permitted for this attribute type or there not being enough space, + * try to make other attributes non-resident. Otherwise fail. + */ + if (unlikely(err != -EPERM && err != -ENOSPC)) { + ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, attribute " + "type 0x%x, because the conversion from " + "resident to non-resident attribute failed " + "with error code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + if (err != -ENOMEM) + err = -EIO; + goto conv_err_out; + } + /* TODO: Not implemented from here, abort. */ + if (err == -ENOSPC) + ntfs_error(vol->sb, "Not enough space in the mft record/on " + "disk for the non-resident attribute value. " + "This case is not implemented yet."); + else /* if (err == -EPERM) */ + ntfs_error(vol->sb, "This attribute type may not be " + "non-resident. This case is not implemented " + "yet."); + err = -EOPNOTSUPP; + goto conv_err_out; +#if 0 + // TODO: Attempt to make other attributes non-resident. + if (!err) + goto do_resident_extend; + /* + * Both the attribute list attribute and the standard information + * attribute must remain in the base inode. Thus, if this is one of + * these attributes, we have to try to move other attributes out into + * extent mft records instead. + */ + if (ni->type == AT_ATTRIBUTE_LIST || + ni->type == AT_STANDARD_INFORMATION) { + // TODO: Attempt to move other attributes into extent mft + // records. + err = -EOPNOTSUPP; + if (!err) + goto do_resident_extend; goto err_out; } - a = ctx->attr; - /* If the size has not changed there is nothing to do. */ - if (ntfs_attr_size(a) == i_size_read(vi)) - goto done; - // TODO: Implement the truncate... - ntfs_error(vi->i_sb, "Inode size has changed but this is not " - "implemented yet. Resetting inode size to old value. " - " This is most likely a bug in the ntfs driver!"); - i_size_write(vi, ntfs_attr_size(a)); -done: - ntfs_attr_put_search_ctx(ctx); - unmap_mft_record(ni); - NInoClearTruncateFailed(ni); - ntfs_debug("Done."); - return 0; -err_out: - if (err != -ENOMEM) { - NVolSetErrors(vol); - make_bad_inode(vi); + // TODO: Attempt to move this attribute to an extent mft record, but + // only if it is not already the only attribute in an mft record in + // which case there would be nothing to gain. + err = -EOPNOTSUPP; + if (!err) + goto do_resident_extend; + /* There is nothing we can do to make enough space. )-: */ + goto err_out; +#endif +do_non_resident_truncate: + BUG_ON(!NInoNonResident(ni)); + if (alloc_change < 0) { + highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); + if (highest_vcn > 0 && + old_alloc_size >> vol->cluster_size_bits > + highest_vcn + 1) { + /* + * This attribute has multiple extents. Not yet + * supported. + */ + ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, " + "attribute type 0x%x, because the " + "attribute is highly fragmented (it " + "consists of multiple extents) and " + "this case is not implemented yet.", + vi->i_ino, + (unsigned)le32_to_cpu(ni->type)); + err = -EOPNOTSUPP; + goto bad_out; + } } + /* + * If the size is shrinking, need to reduce the initialized_size and + * the data_size before reducing the allocation. + */ + if (size_change < 0) { + /* + * Make the valid size smaller (i_size is already up-to-date). + */ + write_lock_irqsave(&ni->size_lock, flags); + if (new_size < ni->initialized_size) { + ni->initialized_size = new_size; + a->data.non_resident.initialized_size = + cpu_to_sle64(new_size); + } + a->data.non_resident.data_size = cpu_to_sle64(new_size); + write_unlock_irqrestore(&ni->size_lock, flags); + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + /* If the allocated size is not changing, we are done. */ + if (!alloc_change) + goto unm_done; + /* + * If the size is shrinking it makes no sense for the + * allocation to be growing. + */ + BUG_ON(alloc_change > 0); + } else /* if (size_change >= 0) */ { + /* + * The file size is growing or staying the same but the + * allocation can be shrinking, growing or staying the same. + */ + if (alloc_change > 0) { + /* + * We need to extend the allocation and possibly update + * the data size. If we are updating the data size, + * since we are not touching the initialized_size we do + * not need to worry about the actual data on disk. + * And as far as the page cache is concerned, there + * will be no pages beyond the old data size and any + * partial region in the last page between the old and + * new data size (or the end of the page if the new + * data size is outside the page) does not need to be + * modified as explained above for the resident + * attribute truncate case. To do this, we simply drop + * the locks we hold and leave all the work to our + * friendly helper ntfs_attr_extend_allocation(). + */ + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); + err = ntfs_attr_extend_allocation(ni, new_size, + size_change > 0 ? new_size : -1, -1); + /* + * ntfs_attr_extend_allocation() will have done error + * output already. + */ + goto done; + } + if (!alloc_change) + goto alloc_done; + } + /* alloc_change < 0 */ + /* Free the clusters. */ + nr_freed = ntfs_cluster_free(ni, new_alloc_size >> + vol->cluster_size_bits, -1, ctx); + m = ctx->mrec; + a = ctx->attr; + if (unlikely(nr_freed < 0)) { + ntfs_error(vol->sb, "Failed to release cluster(s) (error code " + "%lli). Unmount and run chkdsk to recover " + "the lost cluster(s).", (long long)nr_freed); + NVolSetErrors(vol); + nr_freed = 0; + } + /* Truncate the runlist. */ + err = ntfs_rl_truncate_nolock(vol, &ni->runlist, + new_alloc_size >> vol->cluster_size_bits); + /* + * If the runlist truncation failed and/or the search context is no + * longer valid, we cannot resize the attribute record or build the + * mapping pairs array thus we mark the inode bad so that no access to + * the freed clusters can happen. + */ + if (unlikely(err || IS_ERR(m))) { + ntfs_error(vol->sb, "Failed to %s (error code %li).%s", + IS_ERR(m) ? + "restore attribute search context" : + "truncate attribute runlist", + IS_ERR(m) ? PTR_ERR(m) : err, es); + err = -EIO; + goto bad_out; + } + /* Get the size for the shrunk mapping pairs array for the runlist. */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, ni->runlist.rl, 0, -1); + if (unlikely(mp_size <= 0)) { + ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " + "attribute type 0x%x, because determining the " + "size for the mapping pairs failed with error " + "code %i.%s", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), mp_size, es); + err = -EIO; + goto bad_out; + } + /* + * Shrink the attribute record for the new mapping pairs array. Note, + * this cannot fail since we are making the attribute smaller thus by + * definition there is enough space to do so. + */ + attr_len = le32_to_cpu(a->length); + err = ntfs_attr_record_resize(m, a, mp_size + + le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); + BUG_ON(err); + /* + * Generate the mapping pairs array directly into the attribute record. + */ + err = ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->data.non_resident.mapping_pairs_offset), + mp_size, ni->runlist.rl, 0, -1, NULL); + if (unlikely(err)) { + ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " + "attribute type 0x%x, because building the " + "mapping pairs failed with error code %i.%s", + vi->i_ino, (unsigned)le32_to_cpu(ni->type), + err, es); + err = -EIO; + goto bad_out; + } + /* Update the allocated/compressed size as well as the highest vcn. */ + a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> + vol->cluster_size_bits) - 1); + write_lock_irqsave(&ni->size_lock, flags); + ni->allocated_size = new_alloc_size; + a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); + if (NInoSparse(ni) || NInoCompressed(ni)) { + if (nr_freed) { + ni->itype.compressed.size -= nr_freed << + vol->cluster_size_bits; + BUG_ON(ni->itype.compressed.size < 0); + a->data.non_resident.compressed_size = cpu_to_sle64( + ni->itype.compressed.size); + vi->i_blocks = ni->itype.compressed.size >> 9; + } + } else + vi->i_blocks = new_alloc_size >> 9; + write_unlock_irqrestore(&ni->size_lock, flags); + /* + * We have shrunk the allocation. If this is a shrinking truncate we + * have already dealt with the initialized_size and the data_size above + * and we are done. If the truncate is only changing the allocation + * and not the data_size, we are also done. If this is an extending + * truncate, need to extend the data_size now which is ensured by the + * fact that @size_change is positive. + */ +alloc_done: + /* + * If the size is growing, need to update it now. If it is shrinking, + * we have already updated it above (before the allocation change). + */ + if (size_change > 0) + a->data.non_resident.data_size = cpu_to_sle64(new_size); + /* Ensure the modified mft record is written out. */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); +unm_done: + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); +done: + /* Update the mtime and ctime on the base inode. */ + inode_update_time(VFS_I(base_ni), 1); + if (likely(!err)) { + NInoClearTruncateFailed(ni); + ntfs_debug("Done."); + } + return err; +old_bad_out: + old_size = -1; +bad_out: + if (err != -ENOMEM && err != -EOPNOTSUPP) { + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } + if (err != -EOPNOTSUPP) + NInoSetTruncateFailed(ni); + else if (old_size >= 0) + i_size_write(vi, old_size); +err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); if (m) - unmap_mft_record(ni); - NInoSetTruncateFailed(ni); + unmap_mft_record(base_ni); + up_write(&ni->runlist.lock); +out: + ntfs_debug("Failed. Returning error code %i.", err); return err; +conv_err_out: + if (err != -ENOMEM && err != -EOPNOTSUPP) { + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } + if (err != -EOPNOTSUPP) + NInoSetTruncateFailed(ni); + else + i_size_write(vi, old_size); + goto out; } /** From e9438250b635f7832e99a8c8d2e394dd1522ce65 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 4 Oct 2005 16:01:06 +0100 Subject: [PATCH 0294/1939] NTFS: Enable ATTR_SIZE attribute changes in ntfs_setattr(). This completes the initial implementation of file truncation. Now both open(2)ing a file with the O_TRUNC flag and the {,f}truncate(2) system calls will resize a file appropriately. The limitations are that only uncompressed and unencrypted files are supported. Also, there is only very limited support for highly fragmented files (the ones whose $DATA attribute is split into multiple attribute extents). Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 7 +++++++ fs/ntfs/inode.c | 23 +++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 70ad4be7a7fe..9f4674a026f2 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -50,6 +50,13 @@ ToDo/Notes: but not the initialized size can be extended, too. - Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports uncompressed and unencrypted files. + - Enable ATTR_SIZE attribute changes in ntfs_setattr(). This completes + the initial implementation of file truncation. Now both open(2)ing + a file with the O_TRUNC flag and the {,f}truncate(2) system calls + will resize a file appropriately. The limitations are that only + uncompressed and unencrypted files are supported. Also, there is + only very limited support for highly fragmented files (the ones whose + $DATA attribute is split into multiple attribute extents). 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index a1682342baa6..b24f4c4b2c5c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2845,8 +2845,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) err = inode_change_ok(vi, attr); if (err) - return err; - + goto out; /* We do not support NTFS ACLs yet. */ if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) { ntfs_warning(vi->i_sb, "Changes in user/group/mode are not " @@ -2854,14 +2853,22 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) err = -EOPNOTSUPP; goto out; } - if (ia_valid & ATTR_SIZE) { if (attr->ia_size != i_size_read(vi)) { - ntfs_warning(vi->i_sb, "Changes in inode size are not " - "supported yet, ignoring."); - err = -EOPNOTSUPP; - // TODO: Implement... - // err = vmtruncate(vi, attr->ia_size); + ntfs_inode *ni = NTFS_I(vi); + /* + * FIXME: For now we do not support resizing of + * compressed or encrypted files yet. + */ + if (NInoCompressed(ni) || NInoEncrypted(ni)) { + ntfs_warning(vi->i_sb, "Changes in inode size " + "are not supported yet for " + "%s files, ignoring.", + NInoCompressed(ni) ? + "compressed" : "encrypted"); + err = -EOPNOTSUPP; + } else + err = vmtruncate(vi, attr->ia_size); if (err || ia_valid == ATTR_SIZE) goto out; } else { From 36735554571ea619e38210a20f429798de90adc1 Mon Sep 17 00:00:00 2001 From: Dean Roe Date: Mon, 3 Oct 2005 11:51:45 -0500 Subject: [PATCH 0295/1939] [IA64-SGI] Remove references to the SN bist_lock Remove all references to the bist_lock in the SN code as it is not used for anything. Signed-off-by: Dean Roe Signed-off-by: Tony Luck --- include/asm-ia64/sn/nodepda.h | 1 - include/asm-ia64/sn/sn_sal.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h index 47bb8100fd00..6f6d69e39ff5 100644 --- a/include/asm-ia64/sn/nodepda.h +++ b/include/asm-ia64/sn/nodepda.h @@ -55,7 +55,6 @@ struct nodepda_s { */ struct phys_cpuid phys_cpuid[NR_CPUS]; spinlock_t ptc_lock ____cacheline_aligned_in_smp; - spinlock_t bist_lock; }; typedef struct nodepda_s nodepda_t; diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index fea35b33d4e4..33aa4043f87d 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -694,12 +694,10 @@ sn_change_memprotect(u64 paddr, u64 len, u64 perms, u64 *nasid_array) unsigned long irq_flags; cnodeid = nasid_to_cnodeid(get_node_number(paddr)); - // spin_lock(&NODEPDA(cnodeid)->bist_lock); local_irq_save(irq_flags); ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_MEMPROTECT, paddr, len, (u64)nasid_array, perms, 0, 0, 0); local_irq_restore(irq_flags); - // spin_unlock(&NODEPDA(cnodeid)->bist_lock); return ret_stuff.status; } #define SN_MEMPROT_ACCESS_CLASS_0 0x14a080 From da9577c531f17f744f3eab40f700e07933d26361 Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 4 Oct 2005 15:13:37 -0400 Subject: [PATCH 0296/1939] [PATCH] V5 ia64 SPARSEMEM - Kconfig and Makefile The patch modifies the Kconfig file to introduce the new memory model options and other related SPARSEMEM changes. There is also a minor change in the Makefile. Signed-off-by: Bob Picco Signed-off-by: Tony Luck --- arch/ia64/Kconfig | 94 ++++++++++++++++++++++++++----------------- arch/ia64/mm/Makefile | 5 +-- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 945c15a0722b..a86236d6ba5d 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -63,8 +63,6 @@ config IA64_GENERIC select ACPI select NUMA select ACPI_NUMA - select VIRTUAL_MEM_MAP - select DISCONTIGMEM help This selects the system type of your hardware. A "generic" kernel will run on any supported IA-64 system. However, if you configure @@ -176,40 +174,6 @@ config IA64_L1_CACHE_SHIFT default "6" if ITANIUM # align cache-sensitive data to 64 bytes -config NUMA - bool "NUMA support" - depends on !IA64_HP_SIM - default y if IA64_SGI_SN2 - select ACPI_NUMA - help - Say Y to compile the kernel to support NUMA (Non-Uniform Memory - Access). This option is for configuring high-end multiprocessor - server systems. If in doubt, say N. - -config VIRTUAL_MEM_MAP - bool "Virtual mem map" - default y if !IA64_HP_SIM - help - Say Y to compile the kernel with support for a virtual mem map. - This code also only takes effect if a memory hole of greater than - 1 Gb is found during boot. You must turn this option on if you - require the DISCONTIGMEM option for your machine. If you are - unsure, say Y. - -config HOLES_IN_ZONE - bool - default y if VIRTUAL_MEM_MAP - -config ARCH_DISCONTIGMEM_ENABLE - bool "Discontiguous memory support" - depends on (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB) && NUMA && VIRTUAL_MEM_MAP - default y if (IA64_SGI_SN2 || IA64_GENERIC) && NUMA - help - Say Y to support efficient handling of discontiguous physical memory, - for architectures which are either NUMA (Non-Uniform Memory Access) - or have huge holes in the physical address space for other reasons. - See for more. - config IA64_CYCLONE bool "Cyclone (EXA) Time Source support" help @@ -232,8 +196,10 @@ config IA64_SGI_SN_XP based on a network adapter and DMA messaging. config FORCE_MAX_ZONEORDER - int - default "18" + int "MAX_ORDER (11 - 17)" if !HUGETLB_PAGE + range 11 17 if !HUGETLB_PAGE + default "17" if HUGETLB_PAGE + default "11" config SMP bool "Symmetric multi-processing support" @@ -298,6 +264,58 @@ config PREEMPT source "mm/Kconfig" +config ARCH_SELECT_MEMORY_MODEL + def_bool y + +config ARCH_DISCONTIGMEM_ENABLE + def_bool y + help + Say Y to support efficient handling of discontiguous physical memory, + for architectures which are either NUMA (Non-Uniform Memory Access) + or have huge holes in the physical address space for other reasons. + See for more. + +config ARCH_FLATMEM_ENABLE + def_bool y + +config ARCH_SPARSEMEM_ENABLE + def_bool y + depends on ARCH_DISCONTIGMEM_ENABLE + +config ARCH_DISCONTIGMEM_DEFAULT + def_bool y if (IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB) + depends on ARCH_DISCONTIGMEM_ENABLE + +config NUMA + bool "NUMA support" + depends on !IA64_HP_SIM && !FLATMEM + default y if IA64_SGI_SN2 + help + Say Y to compile the kernel to support NUMA (Non-Uniform Memory + Access). This option is for configuring high-end multiprocessor + server systems. If in doubt, say N. + +# VIRTUAL_MEM_MAP and FLAT_NODE_MEM_MAP are functionally equivalent. +# VIRTUAL_MEM_MAP has been retained for historical reasons. +config VIRTUAL_MEM_MAP + bool "Virtual mem map" + depends on !SPARSEMEM + default y if !IA64_HP_SIM + help + Say Y to compile the kernel with support for a virtual mem map. + This code also only takes effect if a memory hole of greater than + 1 Gb is found during boot. You must turn this option on if you + require the DISCONTIGMEM option for your machine. If you are + unsure, say Y. + +config HOLES_IN_ZONE + bool + default y if VIRTUAL_MEM_MAP + +config HAVE_ARCH_EARLY_PFN_TO_NID + def_bool y + depends on NEED_MULTIPLE_NODES + config IA32_SUPPORT bool "Support for Linux/x86 binaries" help diff --git a/arch/ia64/mm/Makefile b/arch/ia64/mm/Makefile index 7078f67887ec..d78d20f0a0f0 100644 --- a/arch/ia64/mm/Makefile +++ b/arch/ia64/mm/Makefile @@ -7,6 +7,5 @@ obj-y := init.o fault.o tlb.o extable.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o -ifndef CONFIG_DISCONTIGMEM -obj-y += contig.o -endif +obj-$(CONFIG_SPARSEMEM) += discontig.o +obj-$(CONFIG_FLATMEM) += contig.o From c678796cab4b5288ad578802a54cb1480ae20a08 Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 4 Oct 2005 15:13:44 -0400 Subject: [PATCH 0297/1939] [PATCH] V5 ia64 SPARSEMEM - eliminate contig_page_data For FLATMEM contig_page_data has been made transparent to the arch code. This patch conforms to that change. Signed-off-by: Bob Picco Signed-off-by: Tony Luck --- arch/ia64/mm/contig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 91a055f5731f..acaaec4e4681 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -269,7 +269,7 @@ paging_init (void) efi_memmap_walk(find_largest_hole, (u64 *)&max_gap); if (max_gap < LARGE_GAP) { vmem_map = (struct page *) 0; - free_area_init_node(0, &contig_page_data, zones_size, 0, + free_area_init_node(0, NODE_DATA(0), zones_size, 0, zholes_size); } else { unsigned long map_size; @@ -282,7 +282,7 @@ paging_init (void) efi_memmap_walk(create_mem_map_page_table, NULL); NODE_DATA(0)->node_mem_map = vmem_map; - free_area_init_node(0, &contig_page_data, zones_size, + free_area_init_node(0, NODE_DATA(0), zones_size, 0, zholes_size); printk("Virtual mem_map starts at 0x%p\n", mem_map); From 1be7d9935b9c7fb9bd5964bfaf3ac543381277db Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 4 Oct 2005 15:13:50 -0400 Subject: [PATCH 0298/1939] [PATCH] V5 ia64 SPARSEMEM - conditional changes for SPARSEMEM This patch introduces the conditional changes required for the three memory models. With [patch 1/4] there are three memory models; FLATMEM, DISCONTIG and SPARSEMEM. Also a new arch include file sparemem.h is introduced for defining SPARSEMEM parameters. Signed-off-by: Bob Picco Signed-off-by: Tony Luck --- include/asm-ia64/meminit.h | 2 +- include/asm-ia64/mmzone.h | 10 +++++++--- include/asm-ia64/nodedata.h | 4 ++-- include/asm-ia64/page.h | 6 +++--- include/asm-ia64/sparsemem.h | 20 ++++++++++++++++++++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 include/asm-ia64/sparsemem.h diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h index 1590dc65b30b..74477fc31d51 100644 --- a/include/asm-ia64/meminit.h +++ b/include/asm-ia64/meminit.h @@ -41,7 +41,7 @@ extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg #define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1)) #define ORDERROUNDDOWN(n) ((n) & ~((PAGE_SIZE< #include -#ifdef CONFIG_DISCONTIGMEM +#ifdef CONFIG_NUMA static inline int pfn_to_nid(unsigned long pfn) { @@ -31,6 +31,10 @@ static inline int pfn_to_nid(unsigned long pfn) #endif } +#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID +extern int early_pfn_to_nid(unsigned long pfn); +#endif + #ifdef CONFIG_IA64_DIG /* DIG systems are small */ # define MAX_PHYSNODE_ID 8 # define NR_NODE_MEMBLKS (MAX_NUMNODES * 8) @@ -39,8 +43,8 @@ static inline int pfn_to_nid(unsigned long pfn) # define NR_NODE_MEMBLKS (MAX_NUMNODES * 4) #endif -#else /* CONFIG_DISCONTIGMEM */ +#else /* CONFIG_NUMA */ # define NR_NODE_MEMBLKS (MAX_NUMNODES * 4) -#endif /* CONFIG_DISCONTIGMEM */ +#endif /* CONFIG_NUMA */ #endif /* _ASM_IA64_MMZONE_H */ diff --git a/include/asm-ia64/nodedata.h b/include/asm-ia64/nodedata.h index 6b0f3ed89b7e..9978c7ce7549 100644 --- a/include/asm-ia64/nodedata.h +++ b/include/asm-ia64/nodedata.h @@ -17,7 +17,7 @@ #include #include -#ifdef CONFIG_DISCONTIGMEM +#ifdef CONFIG_NUMA /* * Node Data. One of these structures is located on each node of a NUMA system. @@ -47,6 +47,6 @@ struct ia64_node_data { */ #define NODE_DATA(nid) (local_node_data->pg_data_ptrs[nid]) -#endif /* CONFIG_DISCONTIGMEM */ +#endif /* CONFIG_NUMA */ #endif /* _ASM_IA64_NODEDATA_H */ diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 9edffad8c28b..ef436b9d06ad 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -102,15 +102,15 @@ do { \ #ifdef CONFIG_VIRTUAL_MEM_MAP extern int ia64_pfn_valid (unsigned long pfn); -#else +#elif defined(CONFIG_FLATMEM) # define ia64_pfn_valid(pfn) 1 #endif -#ifndef CONFIG_DISCONTIGMEM +#ifdef CONFIG_FLATMEM # define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) # define page_to_pfn(page) ((unsigned long) (page - mem_map)) # define pfn_to_page(pfn) (mem_map + (pfn)) -#else +#elif defined(CONFIG_DISCONTIGMEM) extern struct page *vmem_map; extern unsigned long max_low_pfn; # define pfn_valid(pfn) (((pfn) < max_low_pfn) && ia64_pfn_valid(pfn)) diff --git a/include/asm-ia64/sparsemem.h b/include/asm-ia64/sparsemem.h new file mode 100644 index 000000000000..67a7c40ec27f --- /dev/null +++ b/include/asm-ia64/sparsemem.h @@ -0,0 +1,20 @@ +#ifndef _ASM_IA64_SPARSEMEM_H +#define _ASM_IA64_SPARSEMEM_H + +#ifdef CONFIG_SPARSEMEM +/* + * SECTION_SIZE_BITS 2^N: how big each section will be + * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space + */ + +#define SECTION_SIZE_BITS (30) +#define MAX_PHYSMEM_BITS (50) +#ifdef CONFIG_FORCE_MAX_ZONEORDER +#if ((CONFIG_FORCE_MAX_ZONEORDER - 1 + PAGE_SHIFT) > SECTION_SIZE_BITS) +#undef SECTION_SIZE_BITS +#define SECTION_SIZE_BITS (CONFIG_FORCE_MAX_ZONEORDER - 1 + PAGE_SHIFT) +#endif +#endif + +#endif /* CONFIG_SPARSEMEM */ +#endif /* _ASM_IA64_SPARSEMEM_H */ From 2d4b1fa234417b902c9d3034442387c1805bfa7b Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 4 Oct 2005 15:13:57 -0400 Subject: [PATCH 0299/1939] [PATCH] V5 ia64 SPARSEMEM - SPARSEMEM code changes This patch is the minimal set of changes required by ia64 to use SPARSEMEM. Signed-off-by: Bob Picco Signed-off-by: Tony Luck --- arch/ia64/mm/discontig.c | 43 ++++++++++++++++++++++++++++++++++++++-- arch/ia64/mm/init.c | 2 +- arch/ia64/mm/numa.c | 24 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index b5c90e548195..a3788fb84809 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -421,6 +421,37 @@ static void __init memory_less_nodes(void) return; } +#ifdef CONFIG_SPARSEMEM +/** + * register_sparse_mem - notify SPARSEMEM that this memory range exists. + * @start: physical start of range + * @end: physical end of range + * @arg: unused + * + * Simply calls SPARSEMEM to register memory section(s). + */ +static int __init register_sparse_mem(unsigned long start, unsigned long end, + void *arg) +{ + int nid; + + start = __pa(start) >> PAGE_SHIFT; + end = __pa(end) >> PAGE_SHIFT; + nid = early_pfn_to_nid(start); + memory_present(nid, start, end); + + return 0; +} + +static void __init arch_sparse_init(void) +{ + efi_memmap_walk(register_sparse_mem, NULL); + sparse_init(); +} +#else +#define arch_sparse_init() do {} while (0) +#endif + /** * find_memory - walk the EFI memory map and setup the bootmem allocator * @@ -528,8 +559,10 @@ void show_mem(void) int shared = 0, cached = 0, reserved = 0; printk("Node ID: %d\n", pgdat->node_id); for(i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page = pgdat_page_nr(pgdat, i); - if (!ia64_pfn_valid(pgdat->node_start_pfn+i)) + struct page *page; + if (pfn_valid(pgdat->node_start_pfn + i)) + page = pfn_to_page(pgdat->node_start_pfn + i); + else continue; if (PageReserved(page)) reserved++; @@ -648,12 +681,16 @@ void __init paging_init(void) max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + arch_sparse_init(); + efi_memmap_walk(filter_rsvd_memory, count_node_pages); +#ifdef CONFIG_VIRTUAL_MEM_MAP vmalloc_end -= PAGE_ALIGN(max_low_pfn * sizeof(struct page)); vmem_map = (struct page *) vmalloc_end; efi_memmap_walk(create_mem_map_page_table, NULL); printk("Virtual mem_map starts at 0x%p\n", vmem_map); +#endif for_each_online_node(node) { memset(zones_size, 0, sizeof(zones_size)); @@ -690,7 +727,9 @@ void __init paging_init(void) pfn_offset = mem_data[node].min_pfn; +#ifdef CONFIG_VIRTUAL_MEM_MAP NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset; +#endif free_area_init_node(node, NODE_DATA(node), zones_size, pfn_offset, zholes_size); } diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 1281c609ee98..98246acd4991 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -593,7 +593,7 @@ mem_init (void) platform_dma_init(); #endif -#ifndef CONFIG_DISCONTIGMEM +#ifdef CONFIG_FLATMEM if (!mem_map) BUG(); max_mapnr = max_low_pfn; diff --git a/arch/ia64/mm/numa.c b/arch/ia64/mm/numa.c index 77118bbf3d8b..4e5c8b36ad93 100644 --- a/arch/ia64/mm/numa.c +++ b/arch/ia64/mm/numa.c @@ -47,3 +47,27 @@ paddr_to_nid(unsigned long paddr) return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0); } + +#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA) +/* + * Because of holes evaluate on section limits. + * If the section of memory exists, then return the node where the section + * resides. Otherwise return node 0 as the default. This is used by + * SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where + * the section resides. + */ +int early_pfn_to_nid(unsigned long pfn) +{ + int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec; + + for (i = 0; i < num_node_memblks; i++) { + ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT; + esec = (node_memblk[i].start_paddr + node_memblk[i].size + + ((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT; + if (section >= ssec && section < esec) + return node_memblk[i].nid; + } + + return 0; +} +#endif From 1e5c936e3cc2ab745f66c0ae296c42f892ffd42a Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 4 Oct 2005 15:14:05 -0400 Subject: [PATCH 0300/1939] [PATCH] V5 ia64 SPARSEMEM - gensparse_defconfig gensparse_defconfig is a config generated file for SPARSEMEM and GENERIC kernel configuration (defconfig). Signed-off-by: Bob Picco Signed-off-by: Tony Luck --- arch/ia64/configs/gensparse_defconfig | 1319 +++++++++++++++++++++++++ 1 file changed, 1319 insertions(+) create mode 100644 arch/ia64/configs/gensparse_defconfig diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig new file mode 100644 index 000000000000..80f8663bc6d9 --- /dev/null +++ b/arch/ia64/configs/gensparse_defconfig @@ -0,0 +1,1319 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.14-rc2 +# Wed Sep 28 08:27:29 2005 +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +CONFIG_GENERIC_IOMAP=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_IA64_GENERIC=y +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_CYCLONE=y +CONFIG_IOSAPIC=y +# CONFIG_IA64_SGI_SN_XP is not set +CONFIG_FORCE_MAX_ZONEORDER=17 +CONFIG_SMP=y +CONFIG_NR_CPUS=512 +CONFIG_HOTPLUG_CPU=y +# CONFIG_SCHED_SMT is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_HAVE_MEMORY_PRESENT=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_NUMA=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_IA64_MCA_RECOVERY=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +CONFIG_EFI_PCDP=y +# CONFIG_DELL_RBU is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# Power management and ACPI +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_BLACKLIST_YEAR=0 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_CONTAINER=m + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# Bus options (PCI, PCMCIA) +# +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_DEBUG is not set + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=m +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_ACPI=m +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HOTPLUG_PCI_SGI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_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_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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=m +# 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 +# +# CONFIG_PNP is not set + +# +# Block devices +# +# 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=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# 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=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=m +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK 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=y +# 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=y +# 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_SGIIOC4=y +# 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 is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=y +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +CONFIG_SCSI_SATA=y +# CONFIG_SCSI_SATA_AHCI is not set +# CONFIG_SCSI_SATA_SVW is not set +# CONFIG_SCSI_ATA_PIIX is not set +# CONFIG_SCSI_SATA_MV is not set +# CONFIG_SCSI_SATA_NV is not set +# CONFIG_SCSI_SATA_PROMISE is not set +# CONFIG_SCSI_SATA_QSTOR is not set +# CONFIG_SCSI_SATA_SX4 is not set +# CONFIG_SCSI_SATA_SIL is not set +# CONFIG_SCSI_SATA_SIS is not set +# CONFIG_SCSI_SATA_ULI is not set +# CONFIG_SCSI_SATA_VIA is not set +CONFIG_SCSI_SATA_VITESSE=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_1280_1040 is not set +CONFIG_SCSI_QLA2XXX=y +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +# CONFIG_MD_FAULTY is not set +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_EMC is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_SPI=y +CONFIG_FUSION_FC=m +CONFIG_FUSION_MAX_SGE=128 +# CONFIG_FUSION_CTL is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# 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 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +CONFIG_EEPRO100=m +CONFIG_E100=m +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_E1000_NAPI 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_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_TIGON3=y +# CONFIG_BNX2 is not set + +# +# 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_NET_FC is not set +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y + +# +# 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=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# 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=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA 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=y +CONFIG_SERIO_I8042=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +CONFIG_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_FM801 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_STALDRV is not set +CONFIG_SGI_SNSC=y +CONFIG_SGI_TIOCX=y +CONFIG_SGI_MBCS=m + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_ACPI=y +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_SGI_L1_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_SGI_IOC4=y +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_HW_RANDOM is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_I460=m +CONFIG_AGP_HP_ZX1=m +CONFIG_AGP_SGI_TIOCA=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set +CONFIG_RAW_DRIVER=m +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set +CONFIG_MMTIMER=y + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C 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_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_VERBOSE_PRINTK=y +# CONFIG_SND_DEBUG is not set +CONFIG_SND_GENERIC_DRIVER=y + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_BUS=m + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_FM801=m +# CONFIG_SND_FM801_TEA575X is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETKIT is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +CONFIG_INFINIBAND=m +# CONFIG_INFINIBAND_USER_MAD is not set +# CONFIG_INFINIBAND_USER_ACCESS is not set +CONFIG_INFINIBAND_MTHCA=m +# CONFIG_INFINIBAND_MTHCA_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +# CONFIG_INFINIBAND_IPOIB_DEBUG is not set + +# +# SN Devices +# +CONFIG_SGI_IOC4=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_EXPORT=y +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT 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=y +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_RELAYFS_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=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_EXPERIMENTAL 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=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y + +# +# HP Simulator drivers +# +# CONFIG_HP_SIMETH is not set +# CONFIG_HP_SIMSERIAL is not set +# CONFIG_HP_SIMSCSI is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# 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_KPROBES is not set +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# From 67846b30171cc4d706125f630193a76a26bb334a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 02:58:32 -0400 Subject: [PATCH 0301/1939] libata: add ata_ratelimit(), use it in AHCI driver irq handler --- drivers/scsi/ahci.c | 31 +++++++++++++++++++++++++------ drivers/scsi/libata-core.c | 23 +++++++++++++++++++++++ include/linux/libata.h | 2 ++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2c8fa828e24..5ec866b00479 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -672,17 +672,36 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * for (i = 0; i < host_set->n_ports; i++) { struct ata_port *ap; - u32 tmp; - VPRINTK("port %u\n", i); + if (!(irq_stat & (1 << i))) + continue; + ap = host_set->ports[i]; - tmp = irq_stat & (1 << i); - if (tmp && ap) { + if (ap) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (ahci_host_intr(ap, qc)) - irq_ack |= (1 << i); + if (!ahci_host_intr(ap, qc)) + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + printk(KERN_WARNING + "ahci(%s): unhandled interrupt on port %u\n", + pci_name(pdev), i); + } + + VPRINTK("port %u\n", i); + } else { + VPRINTK("port %u (no irq)\n", i); + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + printk(KERN_WARNING + "ahci(%s): interrupt on disabled port %u\n", + pci_name(pdev), i); + } } + + irq_ack |= (1 << i); } if (irq_ack) { diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f0894bfa908b..ceffaef37d17 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "scsi.h" #include "scsi_priv.h" @@ -4688,6 +4689,27 @@ static void __exit ata_exit(void) module_init(ata_init); module_exit(ata_exit); +static unsigned long ratelimit_time; +static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED; + +int ata_ratelimit(void) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&ata_ratelimit_lock, flags); + + if (time_after(jiffies, ratelimit_time)) { + rc = 1; + ratelimit_time = jiffies + (HZ/5); + } else + rc = 0; + + spin_unlock_irqrestore(&ata_ratelimit_lock, flags); + + return rc; +} + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -4729,6 +4751,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); +EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); diff --git a/include/linux/libata.h b/include/linux/libata.h index 4d45179872cc..7929cfc9318d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -410,6 +410,8 @@ extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmn extern int ata_scsi_error(struct Scsi_Host *host); 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_ratelimit(void); + /* * Default driver ops implementations */ From a15dbeb4772626a015337dea06da67095aec3862 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 15:02:14 -0400 Subject: [PATCH 0302/1939] libata: ATAPI command completion tweaks and notes 1) note urgent bug, that completes command twice 2) only fix up INQUIRY data if the SCSI version is zero (typically indicates ATAPI MMC-ish device) 3) if there is a problem on the ATA bus, don't bother with REQUEST SENSE, just directly handle the error based on Status/Error registers. --- drivers/scsi/libata-scsi.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 45ebe9fd52ea..1a1ef3429e55 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1483,9 +1483,18 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { + if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); + /* FIXME: command completion with check condition + * but no sense causes the error handler to run, + * which then issues REQUEST SENSE, fills in the sense + * buffer, and completes the command (for the second + * time). We need to issue REQUEST SENSE some other + * way, to avoid completing the command twice. + */ cmd->result = SAM_STAT_CHECK_CONDITION; qc->scsidone(cmd); @@ -1499,10 +1508,26 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) unsigned int buflen; buflen = ata_scsi_rbuf_get(cmd, &buf); - buf[2] = 0x5; - buf[3] = (buf[3] & 0xf0) | 2; + + /* ATAPI devices typically report zero for their SCSI version, + * and sometimes deviate from the spec WRT response data + * format. If SCSI version is reported as zero like normal, + * then we make the following fixups: 1) Fake MMC-5 version, + * to indicate to the Linux scsi midlayer this is a modern + * device. 2) Ensure response data format / ATAPI information + * are always correct. + */ + /* FIXME: do we ever override EVPD pages and the like, with + * this code? + */ + if (buf[2] == 0) { + buf[2] = 0x5; + buf[3] = 0x32; + } + ata_scsi_rbuf_put(cmd, buf); } + cmd->result = SAM_STAT_GOOD; } From a939c9631527053aa38aa8795a6f7203c7f20b69 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 17:09:16 -0400 Subject: [PATCH 0303/1939] libata: move atapi_request_sense() to libata-scsi module No content changes, just moving code around. --- drivers/scsi/libata-core.c | 49 +------------------------------------- drivers/scsi/libata-scsi.c | 46 +++++++++++++++++++++++++++++++++++ drivers/scsi/libata.h | 3 +++ 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ceffaef37d17..f731bbdd4236 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -71,7 +71,6 @@ static int fgb(u32 bitmap); static int ata_choose_xfer_mode(struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static void __ata_qc_complete(struct ata_queued_cmd *qc); static unsigned int ata_unique_id = 1; @@ -3015,52 +3014,6 @@ static void ata_pio_task(void *_data) goto fsm_start; } -static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd) -{ - DECLARE_COMPLETION(wait); - struct ata_queued_cmd *qc; - unsigned long flags; - int rc; - - DPRINTK("ATAPI request sense\n"); - - qc = ata_qc_new_init(ap, dev); - BUG_ON(qc == NULL); - - /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - - ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); - qc->dma_dir = DMA_FROM_DEVICE; - - memset(&qc->cdb, 0, ap->cdb_len); - qc->cdb[0] = REQUEST_SENSE; - qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - qc->tf.command = ATA_CMD_PACKET; - - qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - - qc->waiting = &wait; - qc->complete_fn = ata_qc_complete_noop; - - spin_lock_irqsave(&ap->host_set->lock, flags); - rc = ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - if (rc) - ata_port_disable(ap); - else - wait_for_completion(&wait); - - DPRINTK("EXIT\n"); -} - /** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out @@ -3254,7 +3207,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, return qc; } -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) { return 0; } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 1a1ef3429e55..c58a7a19780f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1479,6 +1479,52 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 done(cmd); } +void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + DPRINTK("ATAPI request sense\n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + /* FIXME: is this needed? */ + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + + ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); + qc->dma_dir = DMA_FROM_DEVICE; + + memset(&qc->cdb, 0, ap->cdb_len); + qc->cdb[0] = REQUEST_SENSE; + qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; + + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.command = ATA_CMD_PACKET; + + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + qc->nbytes = SCSI_SENSE_BUFFERSIZE; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index c7a1fa1c9abc..a4b55dc9c698 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -39,6 +39,7 @@ struct ata_scsi_args { /* libata-core.c */ extern int atapi_enabled; +extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); extern void ata_qc_free(struct ata_queued_cmd *qc); @@ -51,6 +52,8 @@ extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ +extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd); extern void ata_scsi_scan_host(struct ata_port *ap); extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); From afb0edd922c7ed6e73678730921dfcccebec17e8 Mon Sep 17 00:00:00 2001 From: Brett Russ Date: Wed, 5 Oct 2005 17:08:42 -0400 Subject: [PATCH 0304/1939] [PATCH] libata: Marvell spinlock fixes and simplification This should fix up lockups that people were seeing due to improper spinlock placement. Also, the start/stop DMA routines put guarded trust in the cached state of DMA. Signed-off-by: Brett Russ Signed-off-by: Jeff Garzik --- drivers/scsi/sata_mv.c | 58 +++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ecda7df21142..c3084f8b3ee7 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.22" +#define DRV_VERSION "0.23" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -406,40 +406,30 @@ static void mv_irq_clear(struct ata_port *ap) { } -static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp, - struct ata_port *ap) +static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) { - unsigned long flags; - - spin_lock_irqsave(&ap->host_set->lock, flags); - - writelfl(EDMA_EN, base + EDMA_CMD_OFS); - pp->pp_flags |= MV_PP_FLAG_EDMA_EN; - - spin_unlock_irqrestore(&ap->host_set->lock, flags); + if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { + writelfl(EDMA_EN, base + EDMA_CMD_OFS); + pp->pp_flags |= MV_PP_FLAG_EDMA_EN; + } + assert(EDMA_EN & readl(base + EDMA_CMD_OFS)); } static void mv_stop_dma(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); struct mv_port_priv *pp = ap->private_data; - unsigned long flags; u32 reg; int i; - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (!(MV_PP_FLAG_EDMA_DS_ACT & pp->pp_flags) && - ((MV_PP_FLAG_EDMA_EN & pp->pp_flags) || - (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)))) { - /* Disable EDMA if we're not already trying to disable it - * and it is currently active. The disable bit auto clears. + if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) { + /* Disable EDMA if active. The disable bit auto clears. */ - pp->pp_flags |= MV_PP_FLAG_EDMA_DS_ACT; writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else { + assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS))); + } /* now properly wait for the eDMA to stop */ for (i = 1000; i > 0; i--) { @@ -450,12 +440,9 @@ static void mv_stop_dma(struct ata_port *ap) udelay(100); } - spin_lock_irqsave(&ap->host_set->lock, flags); - pp->pp_flags &= ~MV_PP_FLAG_EDMA_DS_ACT; - spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (EDMA_EN & reg) { printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); + /* FIXME: Consider doing a reset here to recover */ } } @@ -716,8 +703,11 @@ static void mv_port_stop(struct ata_port *ap) { struct device *dev = ap->host_set->dev; struct mv_port_priv *pp = ap->private_data; + unsigned long flags; + spin_lock_irqsave(&ap->host_set->lock, flags); mv_stop_dma(ap); + spin_unlock_irqrestore(&ap->host_set->lock, flags); ap->private_data = NULL; dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); @@ -867,11 +857,7 @@ static int mv_qc_issue(struct ata_queued_cmd *qc) mv_inc_q_index(&pp->req_producer); /* now incr producer index */ - if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { - /* turn on EDMA if not already on */ - mv_start_dma(port_mmio, pp, qc->ap); - } - assert(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); + mv_start_dma(port_mmio, pp); /* and write the request in pointer to kick the EDMA to life */ in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; @@ -921,8 +907,12 @@ static void mv_err_intr(struct ata_port *ap) serr = scr_read(ap, SCR_ERROR); scr_write_flush(ap, SCR_ERROR, serr); } - DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", - ap->port_no, edma_err_cause, serr); + if (EDMA_ERR_SELF_DIS & edma_err_cause) { + struct mv_port_priv *pp = ap->private_data; + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } + DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x " + "SERR: 0x%08x\n", ap->id, edma_err_cause, serr); /* Clear EDMA now that SERR cleanup done */ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -1034,7 +1024,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", readl(mmio + PCI_IRQ_CAUSE_OFS)); - VPRINTK("All regs @ PCI error\n"); + DPRINTK("All regs @ PCI error\n"); mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev)); writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); From 05b308e1df6d9d673daedb517969241f41278b52 Mon Sep 17 00:00:00 2001 From: Brett Russ Date: Wed, 5 Oct 2005 17:08:53 -0400 Subject: [PATCH 0305/1939] [PATCH] libata: Marvell function headers adds helpful function header comments. Signed-off-by: Brett Russ Signed-off-by: Jeff Garzik --- drivers/scsi/sata_mv.c | 225 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index c3084f8b3ee7..84b488f81c75 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.23" +#define DRV_VERSION "0.24" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -406,6 +406,17 @@ static void mv_irq_clear(struct ata_port *ap) { } +/** + * mv_start_dma - Enable eDMA engine + * @base: port base address + * @pp: port private data + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) { if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { @@ -415,6 +426,16 @@ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) assert(EDMA_EN & readl(base + EDMA_CMD_OFS)); } +/** + * mv_stop_dma - Disable eDMA engine + * @ap: ATA channel to manipulate + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ static void mv_stop_dma(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); @@ -561,7 +582,15 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } -/* This routine only applies to 6xxx parts */ +/** + * mv_global_soft_reset - Perform the 6xxx global soft reset + * @mmio_base: base address of the HBA + * + * This routine only applies to 6xxx parts. + * + * LOCKING: + * Inherited from caller. + */ static int mv_global_soft_reset(void __iomem *mmio_base) { void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS; @@ -617,6 +646,16 @@ static int mv_global_soft_reset(void __iomem *mmio_base) return rc; } +/** + * mv_host_stop - Host specific cleanup/stop routine. + * @host_set: host data structure + * + * Disable ints, cleanup host memory, call general purpose + * host_stop. + * + * LOCKING: + * Inherited from caller. + */ static void mv_host_stop(struct ata_host_set *host_set) { struct mv_host_priv *hpriv = host_set->private_data; @@ -631,6 +670,16 @@ static void mv_host_stop(struct ata_host_set *host_set) ata_host_stop(host_set); } +/** + * mv_port_start - Port specific init/start routine. + * @ap: ATA channel to manipulate + * + * Allocate and point to DMA memory, init port private memory, + * zero indices. + * + * LOCKING: + * Inherited from caller. + */ static int mv_port_start(struct ata_port *ap) { struct device *dev = ap->host_set->dev; @@ -699,6 +748,15 @@ static int mv_port_start(struct ata_port *ap) return 0; } +/** + * mv_port_stop - Port specific cleanup/stop routine. + * @ap: ATA channel to manipulate + * + * Stop DMA, cleanup port memory. + * + * LOCKING: + * This routine uses the host_set lock to protect the DMA stop. + */ static void mv_port_stop(struct ata_port *ap) { struct device *dev = ap->host_set->dev; @@ -714,6 +772,15 @@ static void mv_port_stop(struct ata_port *ap) kfree(pp); } +/** + * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries + * @qc: queued command whose SG list to source from + * + * Populate the SG list and mark the last entry. + * + * LOCKING: + * Inherited from caller. + */ static void mv_fill_sg(struct ata_queued_cmd *qc) { struct mv_port_priv *pp = qc->ap->private_data; @@ -748,6 +815,18 @@ static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last) (last ? CRQB_CMD_LAST : 0); } +/** + * mv_qc_prep - Host specific command preparation. + * @qc: queued command to prepare + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it handles prep of the CRQB + * (command request block), does some sanity checking, and calls + * the SG load routine. + * + * LOCKING: + * Inherited from caller. + */ static void mv_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -830,6 +909,18 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) mv_fill_sg(qc); } +/** + * mv_qc_issue - Initiate a command to the host + * @qc: queued command to start + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it sanity checks our local + * caches of the request producer/consumer indices then enables + * DMA and bumps the request producer index. + * + * LOCKING: + * Inherited from caller. + */ static int mv_qc_issue(struct ata_queued_cmd *qc) { void __iomem *port_mmio = mv_ap_base(qc->ap); @@ -867,6 +958,19 @@ static int mv_qc_issue(struct ata_queued_cmd *qc) return 0; } +/** + * mv_get_crpb_status - get status from most recently completed cmd + * @ap: ATA channel to manipulate + * + * This routine is for use when the port is in DMA mode, when it + * will be using the CRPB (command response block) method of + * returning command completion information. We assert indices + * are good, grab status, and bump the response consumer index to + * prove that we're up to date. + * + * LOCKING: + * Inherited from caller. + */ static u8 mv_get_crpb_status(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); @@ -896,6 +1000,19 @@ static u8 mv_get_crpb_status(struct ata_port *ap) return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT); } +/** + * mv_err_intr - Handle error interrupts on the port + * @ap: ATA channel to manipulate + * + * In most cases, just clear the interrupt and move on. However, + * some cases require an eDMA reset, which is done right before + * the COMRESET in mv_phy_reset(). The SERR case requires a + * clear of pending errors in the SATA SERROR register. Finally, + * if the port disabled DMA, update our cached copy to match. + * + * LOCKING: + * Inherited from caller. + */ static void mv_err_intr(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); @@ -923,7 +1040,22 @@ static void mv_err_intr(struct ata_port *ap) } } -/* Handle any outstanding interrupts in a single SATAHC */ +/** + * mv_host_intr - Handle all interrupts on the given host controller + * @host_set: host specific structure + * @relevant: port error bits relevant to this host controller + * @hc: which host controller we're to look at + * + * Read then write clear the HC interrupt status then walk each + * port connected to the HC and see if it needs servicing. Port + * success ints are reported in the HC interrupt status reg, the + * port error ints are reported in the higher level main + * interrupt status register and thus are passed in via the + * 'relevant' argument. + * + * LOCKING: + * Inherited from caller. + */ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, unsigned int hc) { @@ -993,6 +1125,21 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, VPRINTK("EXIT\n"); } +/** + * mv_interrupt - + * @irq: unused + * @dev_instance: private data; in this case the host structure + * @regs: unused + * + * Read the read only register to determine if any host + * controllers have pending interrupts. If so, call lower level + * routine to handle. Also check for PCI errors which are only + * reported here. + * + * LOCKING: + * This routine holds the host_set lock while processing pending + * interrupts. + */ static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { @@ -1035,14 +1182,32 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +/** + * mv_check_err - Return the error shadow register to caller. + * @ap: ATA channel to manipulate + * + * Marvell requires DMA to be stopped before accessing shadow + * registers. So we do that, then return the needed register. + * + * LOCKING: + * Inherited from caller. FIXME: protect mv_stop_dma with lock? + */ static u8 mv_check_err(struct ata_port *ap) { mv_stop_dma(ap); /* can't read shadow regs if DMA on */ return readb((void __iomem *) ap->ioaddr.error_addr); } -/* Part of this is taken from __sata_phy_reset and modified to not sleep - * since this routine gets called from interrupt level. +/** + * mv_phy_reset - Perform eDMA reset followed by COMRESET + * @ap: ATA channel to manipulate + * + * Part of this is taken from __sata_phy_reset and modified to + * not sleep since this routine gets called from interrupt level. + * + * LOCKING: + * Inherited from caller. This is coded to safe to call at + * interrupt level, i.e. it does not sleep. */ static void mv_phy_reset(struct ata_port *ap) { @@ -1105,6 +1270,16 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("EXIT\n"); } +/** + * mv_eng_timeout - Routine called by libata when SCSI times out I/O + * @ap: ATA channel to manipulate + * + * Intent is to clear all pending error conditions, reset the + * chip/bus, fail the command, and move on. + * + * LOCKING: + * This routine holds the host_set lock while failing the command. + */ static void mv_eng_timeout(struct ata_port *ap) { struct ata_queued_cmd *qc; @@ -1140,6 +1315,18 @@ static void mv_eng_timeout(struct ata_port *ap) } } +/** + * mv_port_init - Perform some early initialization on a single port. + * @port: libata data structure storing shadow register addresses + * @port_mmio: base address of the port + * + * Initialize shadow register mmio addresses, clear outstanding + * interrupts on the port, and unmask interrupts for the future + * start of the port. + * + * LOCKING: + * Inherited from caller. + */ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) { unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; @@ -1177,6 +1364,16 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } +/** + * mv_host_init - Perform some early initialization of the host. + * @probe_ent: early data struct representing the host + * + * If possible, do an early global reset of the host. Then do + * our port init and clear/unmask all/relevant host interrupts. + * + * LOCKING: + * Inherited from caller. + */ static int mv_host_init(struct ata_probe_ent *probe_ent) { int rc = 0, n_hc, port, hc; @@ -1226,7 +1423,15 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) return rc; } -/* FIXME: complete this */ +/** + * mv_print_info - Dump key info to kernel log for perusal. + * @probe_ent: early data struct representing the host + * + * FIXME: complete this. + * + * LOCKING: + * Inherited from caller. + */ static void mv_print_info(struct ata_probe_ent *probe_ent) { struct pci_dev *pdev = to_pci_dev(probe_ent->dev); @@ -1253,6 +1458,14 @@ static void mv_print_info(struct ata_probe_ent *probe_ent) scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); } +/** + * mv_init_one - handle a positive probe of a Marvell host + * @pdev: PCI device found + * @ent: PCI device ID entry for the matched host + * + * LOCKING: + * Inherited from caller. + */ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; From 8a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 17:19:47 -0400 Subject: [PATCH 0306/1939] [libata sata_mv] fix warning shuffle ifdef location to fix the following warning: drivers/scsi/sata_mv.c:471: warning: 'mv_dump_mem' defined but not used --- drivers/scsi/sata_mv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 84b488f81c75..d457f5673476 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -467,9 +467,9 @@ static void mv_stop_dma(struct ata_port *ap) } } +#ifdef ATA_DEBUG static void mv_dump_mem(void __iomem *start, unsigned bytes) { -#ifdef ATA_DEBUG int b, w; for (b = 0; b < bytes; ) { DPRINTK("%p: ", start + b); @@ -479,8 +479,9 @@ static void mv_dump_mem(void __iomem *start, unsigned bytes) } printk("\n"); } -#endif } +#endif + static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) { #ifdef ATA_DEBUG From e12669e774be403c84baa651306d305752a35cd8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 18:39:23 -0400 Subject: [PATCH 0307/1939] libata: minor cleanups A few code shuffles, to make merging future code easier. Add (DRIVER_SENSE << 24) to certain result codes, as noted by Douglas Gilbert. --- drivers/scsi/libata-core.c | 6 +++--- drivers/scsi/libata-scsi.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f731bbdd4236..d568914c4344 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3131,14 +3131,14 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("ENTER\n"); qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { + if (qc) + ata_qc_timeout(qc); + else { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); goto out; } - ata_qc_timeout(qc); - out: DPRINTK("EXIT\n"); } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index c58a7a19780f..1c3a10fb3c44 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -225,7 +225,7 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) }; int i = 0; - cmd->result = SAM_STAT_CHECK_CONDITION; + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse @@ -1468,7 +1468,7 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = SAM_STAT_CHECK_CONDITION; + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; cmd->sense_buffer[0] = 0x70; cmd->sense_buffer[2] = ILLEGAL_REQUEST; @@ -1529,8 +1529,11 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat); + if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) ata_to_sense_error(qc, drv_stat); + else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); @@ -1546,7 +1549,9 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) qc->scsidone(cmd); return 1; - } else { + } + + else { u8 *scsicmd = cmd->cmnd; if (scsicmd[0] == INQUIRY) { @@ -1578,7 +1583,6 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) } qc->scsidone(cmd); - return 0; } /** From b85a046af3a260e079505e8023ccd10e01cf4f2b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 10:59:19 +1000 Subject: [PATCH 0308/1939] powerpc: Define 32/64 bit asm macros and use them in fpu.S These macros help in writing assembly code that works for both ppc32 and ppc64. With this we now have a common fpu.S. This takes out load_up_fpu from head_64.S. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/fpu.S | 72 ++++++++++++++--------------------- arch/powerpc/kernel/head_64.S | 58 +--------------------------- include/asm-powerpc/ppc_asm.h | 28 +++++++++++--- 3 files changed, 53 insertions(+), 105 deletions(-) diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 665d7d34304c..04e95e810b21 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -27,13 +27,9 @@ * Load up this task's FP registers from its thread_struct, * enable the FPU for the current task and return to the task. */ - .globl load_up_fpu -load_up_fpu: +_GLOBAL(load_up_fpu) mfmsr r5 ori r5,r5,MSR_FP -#ifdef CONFIG_PPC64BRIDGE - clrldi r5,r5,1 /* turn off 64-bit mode */ -#endif /* CONFIG_PPC64BRIDGE */ SYNC MTMSRD(r5) /* enable use of fpu now */ isync @@ -43,67 +39,57 @@ load_up_fpu: * to another. Instead we call giveup_fpu in switch_to. */ #ifndef CONFIG_SMP - tophys(r6,0) /* get __pa constant */ - addis r3,r6,last_task_used_math@ha - lwz r4,last_task_used_math@l(r3) - cmpwi 0,r4,0 + LOADBASE(r3, last_task_used_math) + tophys(r3,r3) + LDL r4,OFF(last_task_used_math)(r3) + CMPI 0,r4,0 beq 1f - add r4,r4,r6 + tophys(r4,r4) addi r4,r4,THREAD /* want last_task_used_math->thread */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,THREAD_FPSCR-4(r4) - lwz r5,PT_REGS(r4) - add r5,r5,r6 - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + LDL r5,PT_REGS(r4) + tophys(r5,r5) + LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r10,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r10 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) + STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1: #endif /* CONFIG_SMP */ /* enable use of FP after return */ +#ifdef CONFIG_PPC32 mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ lwz r4,THREAD_FPEXC_MODE(r5) ori r9,r9,MSR_FP /* enable FP for current */ or r9,r9,r4 +#else + ld r4,PACACURRENT(r13) + addi r5,r4,THREAD /* Get THREAD */ + ld r4,THREAD_FPEXC_MODE(r5) + ori r12,r12,MSR_FP + or r12,r12,r4 + std r12,_MSR(r1) +#endif lfd fr0,THREAD_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) #ifndef CONFIG_SMP subi r4,r5,THREAD - sub r4,r4,r6 - stw r4,last_task_used_math@l(r3) + tovirt(r4,r4) + STL r4,OFF(last_task_used_math)(r3) #endif /* CONFIG_SMP */ /* restore registers and return */ /* we haven't used ctr or xer or lr */ b fast_exception_return -/* - * FP unavailable trap from kernel - print a message, but let - * the task use FP in the kernel until it returns to user mode. - */ - .globl KernelFP -KernelFP: - lwz r3,_MSR(r1) - ori r3,r3,MSR_FP - stw r3,_MSR(r1) /* enable use of FP after return */ - lis r3,86f@h - ori r3,r3,86f@l - mr r4,r2 /* current */ - lwz r5,_NIP(r1) - bl printk - b ret_from_except -86: .string "floating point used in kernel (task=%p, pc=%x)\n" - .align 4,0 - /* * giveup_fpu(tsk) * Disable FP for the task given as the argument, * and save the floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. */ - .globl giveup_fpu -giveup_fpu: +_GLOBAL(giveup_fpu) mfmsr r5 ori r5,r5,MSR_FP SYNC_601 @@ -111,23 +97,23 @@ giveup_fpu: MTMSRD(r5) /* enable use of fpu now */ SYNC_601 isync - cmpwi 0,r3,0 + CMPI 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ - lwz r5,PT_REGS(r3) - cmpwi 0,r5,0 + LDL r5,PT_REGS(r3) + CMPI 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 stfd fr0,THREAD_FPSCR-4(r3) beq 1f - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r3,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r3 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) + STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1: #ifndef CONFIG_SMP li r5,0 - lis r4,last_task_used_math@ha - stw r5,last_task_used_math@l(r4) + LOADBASE(r4,last_task_used_math) + STL r5,OFF(last_task_used_math)(r4) #endif /* CONFIG_SMP */ blr diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index db0cd3587627..a36ee6ecbaea 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -80,7 +80,7 @@ _stext: _GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION - b .__start_initialization_multiplatform + b .__start_initialization_multiplatform END_FTR_SECTION(0, 1) #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -857,62 +857,6 @@ fp_unavailable_common: bl .kernel_fp_unavailable_exception BUG_OPCODE -/* - * load_up_fpu(unused, unused, tsk) - * Disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - * On SMP we know the fpu is free, since we give it up every - * switch (ie, no lazy save of the FP registers). - * On entry: r13 == 'current' && last_task_used_math != 'current' - */ -_STATIC(load_up_fpu) - mfmsr r5 /* grab the current MSR */ - ori r5,r5,MSR_FP - mtmsrd r5 /* enable use of fpu now */ - isync -/* - * For SMP, we don't do lazy FPU switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_fpu in switch_to. - * - */ -#ifndef CONFIG_SMP - ld r3,last_task_used_math@got(r2) - ld r4,0(r3) - cmpdi 0,r4,0 - beq 1f - /* Save FP state to last_task_used_math's THREAD struct */ - addi r4,r4,THREAD - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,THREAD_FPSCR(r4) - /* Disable FP for last_task_used_math */ - ld r5,PT_REGS(r4) - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r6,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r6 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of FP after return */ - ld r4,PACACURRENT(r13) - addi r5,r4,THREAD /* Get THREAD */ - ld r4,THREAD_FPEXC_MODE(r5) - ori r12,r12,MSR_FP - or r12,r12,r4 - std r12,_MSR(r1) - lfd fr0,THREAD_FPSCR(r5) - mtfsf 0xff,fr0 - REST_32FPRS(0, r5) -#ifndef CONFIG_SMP - /* Update last_task_used_math to 'current' */ - subi r4,r5,THREAD /* Back to 'current' */ - std r4,0(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - b fast_exception_return - .align 7 .globl altivec_unavailable_common altivec_unavailable_common: diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 4efa71878fa9..6cd52c130332 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -103,12 +103,13 @@ oris rn,rn,name##@h; \ ori rn,rn,name##@l -#define LOADBASE(rn,name) \ - lis rn,name@highest; \ - ori rn,rn,name@higher; \ - rldicr rn,rn,32,31; \ - oris rn,rn,name@ha +#define LOADBASE(rn,name) \ + .section .toc,"aw"; \ +1: .tc name[TC],name; \ + .previous; \ + ld rn,1b@toc(r2) +#define OFF(name) 0 #define SET_REG_TO_CONST(reg, value) \ lis reg,(((value)>>48)&0xFFFF); \ @@ -123,6 +124,23 @@ rldicr reg,reg,32,31; \ oris reg,reg,(label)@h; \ ori reg,reg,(label)@l; + +/* operations for longs and pointers */ +#define LDL ld +#define STL std +#define CMPI cmpdi + +#else /* 32-bit */ +#define LOADBASE(rn,name) \ + lis rn,name@ha + +#define OFF(name) name@l + +/* operations for longs and pointers */ +#define LDL lwz +#define STL stw +#define CMPI cmpwi + #endif /* various errata or part fixups */ From 9b6b563c0d2d25ecc3111916031aa7255543fbfb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 12:06:20 +1000 Subject: [PATCH 0309/1939] powerpc: Merge in the ppc64 version of the prom code. This brings in the ppc64 version of prom_init.c, prom.c and btext.c and makes them work for ppc32. This also brings in the new calling convention, where the first entry to the kernel (with r5 != 0) goes to the prom_init code, which then restarts from the beginning (with r5 == 0) after it has done its stuff. For now this also brings in the ppc32 version of setup.c. It also merges lmb.h. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 11 +- arch/powerpc/kernel/btext.c | 852 +++++++ arch/powerpc/kernel/head.S | 16 +- arch/powerpc/kernel/ppc_ksyms.c | 30 - arch/powerpc/kernel/prom.c | 2141 ++++++++++++++++++ arch/powerpc/kernel/prom_init.c | 2126 +++++++++++++++++ arch/powerpc/kernel/setup.c | 678 ++++++ arch/powerpc/platforms/powermac/pmac_setup.c | 11 +- include/asm-powerpc/cputable.h | 3 + include/asm-powerpc/iommu.h | 112 + include/asm-powerpc/lmb.h | 81 + include/asm-powerpc/pSeries_reconfig.h | 25 + include/asm-powerpc/prom.h | 215 ++ include/asm-powerpc/rtas.h | 249 ++ include/asm-powerpc/system.h | 5 + 15 files changed, 6507 insertions(+), 48 deletions(-) create mode 100644 arch/powerpc/kernel/btext.c create mode 100644 arch/powerpc/kernel/prom.c create mode 100644 arch/powerpc/kernel/prom_init.c create mode 100644 arch/powerpc/kernel/setup.c create mode 100644 include/asm-powerpc/iommu.h create mode 100644 include/asm-powerpc/lmb.h create mode 100644 include/asm-powerpc/pSeries_reconfig.h create mode 100644 include/asm-powerpc/prom.h create mode 100644 include/asm-powerpc/rtas.h diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index be3f9d123a6d..4842e82dbc2b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -5,10 +5,11 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif - ifeq ($(CONFIG_PPC32),y) -extra-$(CONFIG_PPC_STD_MMU) := head.o +CFLAGS_prom_init.o += -fPIC endif + +extra-$(CONFIG_PPC_STD_MMU) := head.o extra-$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o @@ -18,13 +19,15 @@ extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds -obj-y := traps.o -obj-$(CONFIG_PPC32) += semaphore.o process.o +obj-y := traps.o prom.o semaphore.o +obj-$(CONFIG_PPC32) += setup.o process.o obj-$(CONFIG_PPC64) += idle_power4.o ifeq ($(CONFIG_PPC32),y) +obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o endif obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o +obj-$(CONFIG_BOOTX_TEXT) += btext.o ifeq ($(CONFIG_PPC_ISERIES),y) arch/powerpc/kernel/head_64.o: arch/powerpc/platforms/iseries/lparmap.s diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c new file mode 100644 index 000000000000..44f5d98e27c0 --- /dev/null +++ b/arch/powerpc/kernel/btext.c @@ -0,0 +1,852 @@ +/* + * Procedures for drawing on the screen early on in the boot process. + * + * Benjamin Herrenschmidt + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NO_SCROLL + +#ifndef NO_SCROLL +static void scrollscreen(void); +#endif + +static void draw_byte(unsigned char c, long locX, long locY); +static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); +static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); +static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); + +static int g_loc_X; +static int g_loc_Y; +static int g_max_loc_X; +static int g_max_loc_Y; + +static int dispDeviceRowBytes; +static int dispDeviceDepth; +static int dispDeviceRect[4]; +static unsigned char *dispDeviceBase, *logicalDisplayBase; + +unsigned long disp_BAT[2] __initdata = {0, 0}; + +#define cmapsz (16*256) + +static unsigned char vga_font[cmapsz]; + +int boot_text_mapped; +int force_printk_to_btext = 0; + + +/* Calc BAT values for mapping the display and store them + * in disp_BAT. Those values are then used from head.S to map + * the display during identify_machine() and MMU_Init() + * + * The display is mapped to virtual address 0xD0000000, rather + * than 1:1, because some some CHRP machines put the frame buffer + * in the region starting at 0xC0000000 (KERNELBASE). + * This mapping is temporary and will disappear as soon as the + * setup done by MMU_Init() is applied. + * + * For now, we align the BAT and then map 8Mb on 601 and 16Mb + * on other PPCs. This may cause trouble if the framebuffer + * is really badly aligned, but I didn't encounter this case + * yet. + */ +void __init +btext_prepare_BAT(void) +{ + unsigned long vaddr = KERNELBASE + 0x10000000; + unsigned long addr; + unsigned long lowbits; + + addr = (unsigned long)dispDeviceBase; + if (!addr) { + boot_text_mapped = 0; + return; + } + if (PVR_VER(mfspr(SPRN_PVR)) != 1) { + /* 603, 604, G3, G4, ... */ + lowbits = addr & ~0xFF000000UL; + addr &= 0xFF000000UL; + disp_BAT[0] = vaddr | (BL_16M<<2) | 2; + disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + } else { + /* 601 */ + lowbits = addr & ~0xFF800000UL; + addr &= 0xFF800000UL; + disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + disp_BAT[1] = addr | BL_8M | 0x40; + } + logicalDisplayBase = (void *) (vaddr + lowbits); +} + +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +void __init +btext_setup_display(int width, int height, int depth, int pitch, + unsigned long address) +{ + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; + logicalDisplayBase = (unsigned char *)address; + dispDeviceBase = (unsigned char *)address; + dispDeviceRowBytes = pitch; + dispDeviceDepth = depth; + dispDeviceRect[0] = dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + boot_text_mapped = 1; +} + +/* Here's a small text engine to use during early boot + * or for debugging purposes + * + * todo: + * + * - build some kind of vgacon with it to enable early printk + * - move to a separate file + * - add a few video driver hooks to keep in sync with display + * changes. + */ + +void map_boot_text(void) +{ + unsigned long base, offset, size; + unsigned char *vbase; + + /* By default, we are no longer mapped */ + boot_text_mapped = 0; + if (dispDeviceBase == 0) + return; + base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) dispDeviceBase) - base; + size = dispDeviceRowBytes * dispDeviceRect[3] + offset + + dispDeviceRect[0]; + vbase = __ioremap(base, size, _PAGE_NO_CACHE); + if (vbase == 0) + return; + logicalDisplayBase = vbase + offset; + boot_text_mapped = 1; +} + +int btext_initialize(struct device_node *np) +{ + unsigned int width, height, depth, pitch; + unsigned long address = 0; + u32 *prop; + + prop = (u32 *)get_property(np, "width", NULL); + if (prop == NULL) + return -EINVAL; + width = *prop; + prop = (u32 *)get_property(np, "height", NULL); + if (prop == NULL) + return -EINVAL; + height = *prop; + prop = (u32 *)get_property(np, "depth", NULL); + if (prop == NULL) + return -EINVAL; + depth = *prop; + pitch = width * ((depth + 7) / 8); + prop = (u32 *)get_property(np, "linebytes", NULL); + if (prop) + pitch = *prop; + if (pitch == 1) + pitch = 0x1000; + prop = (u32 *)get_property(np, "address", NULL); + if (prop) + address = *prop; + + /* FIXME: Add support for PCI reg properties */ + + if (address == 0) + return -EINVAL; + + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; + logicalDisplayBase = (unsigned char *)address; + dispDeviceBase = (unsigned char *)address; + dispDeviceRowBytes = pitch; + dispDeviceDepth = depth; + dispDeviceRect[0] = dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + + map_boot_text(); + + return 0; +} + +void __init init_boot_display(void) +{ + char *name; + struct device_node *np = NULL; + int rc = -ENODEV; + + printk("trying to initialize btext ...\n"); + + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name != NULL) { + np = of_find_node_by_path(name); + if (np != NULL) { + if (strcmp(np->type, "display") != 0) { + printk("boot stdout isn't a display !\n"); + of_node_put(np); + np = NULL; + } + } + } + if (np) + rc = btext_initialize(np); + if (rc == 0) + return; + + for (np = NULL; (np = of_find_node_by_type(np, "display"));) { + if (get_property(np, "linux,opened", NULL)) { + printk("trying %s ...\n", np->full_name); + rc = btext_initialize(np); + printk("result: %d\n", rc); + } + if (rc == 0) + return; + } +} + +/* Calc the base address of a given point (x,y) */ +static unsigned char * calc_base(int x, int y) +{ + unsigned char *base; + + base = logicalDisplayBase; + if (base == 0) + base = dispDeviceBase; + base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); + base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; + return base; +} + +/* Adjust the display to a new resolution */ +void btext_update_display(unsigned long phys, int width, int height, + int depth, int pitch) +{ + if (dispDeviceBase == 0) + return; + + /* check it's the same frame buffer (within 256MB) */ + if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) + return; + + dispDeviceBase = (__u8 *) phys; + dispDeviceRect[0] = 0; + dispDeviceRect[1] = 0; + dispDeviceRect[2] = width; + dispDeviceRect[3] = height; + dispDeviceDepth = depth; + dispDeviceRowBytes = pitch; + if (boot_text_mapped) { + iounmap(logicalDisplayBase); + boot_text_mapped = 0; + } + map_boot_text(); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; +} +EXPORT_SYMBOL(btext_update_display); + +void btext_clearscreen(void) +{ + unsigned long *base = (unsigned long *)calc_base(0, 0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; + int i,j; + + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) + { + unsigned long *ptr = base; + for(j=width; j; --j) + *(ptr++) = 0; + base += (dispDeviceRowBytes >> 3); + } +} + +#ifndef NO_SCROLL +static void scrollscreen(void) +{ + unsigned long *src = (unsigned long *)calc_base(0,16); + unsigned long *dst = (unsigned long *)calc_base(0,0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 3; + int i,j; + + for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) + { + unsigned long *src_ptr = src; + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = *(src_ptr++); + src += (dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 3); + } + for (i=0; i<16; i++) + { + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = 0; + dst += (dispDeviceRowBytes >> 3); + } +} +#endif /* ndef NO_SCROLL */ + +void btext_drawchar(char c) +{ + int cline = 0; +#ifdef NO_SCROLL + int x; +#endif + if (!boot_text_mapped) + return; + + switch (c) { + case '\b': + if (g_loc_X > 0) + --g_loc_X; + break; + case '\t': + g_loc_X = (g_loc_X & -8) + 8; + break; + case '\r': + g_loc_X = 0; + break; + case '\n': + g_loc_X = 0; + g_loc_Y++; + cline = 1; + break; + default: + draw_byte(c, g_loc_X++, g_loc_Y); + } + if (g_loc_X >= g_max_loc_X) { + g_loc_X = 0; + g_loc_Y++; + cline = 1; + } +#ifndef NO_SCROLL + while (g_loc_Y >= g_max_loc_Y) { + scrollscreen(); + g_loc_Y--; + } +#else + /* wrap around from bottom to top of screen so we don't + waste time scrolling each line. -- paulus. */ + if (g_loc_Y >= g_max_loc_Y) + g_loc_Y = 0; + if (cline) { + for (x = 0; x < g_max_loc_X; ++x) + draw_byte(' ', x, g_loc_Y); + } +#endif +} + +void btext_drawstring(const char *c) +{ + if (!boot_text_mapped) + return; + while (*c) + btext_drawchar(*c++); +} + +void btext_drawhex(unsigned long v) +{ + char *hex_table = "0123456789abcdef"; + + if (!boot_text_mapped) + return; +#ifdef CONFIG_PPC64 + btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]); +#endif + btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); + btext_drawchar(' '); +} + +static void draw_byte(unsigned char c, long locX, long locY) +{ + unsigned char *base = calc_base(locX << 3, locY << 4); + unsigned char *font = &vga_font[((unsigned int)c) * 16]; + int rb = dispDeviceRowBytes; + + switch(dispDeviceDepth) { + case 24: + case 32: + draw_byte_32(font, (unsigned int *)base, rb); + break; + case 15: + case 16: + draw_byte_16(font, (unsigned int *)base, rb); + break; + case 8: + draw_byte_8(font, (unsigned int *)base, rb); + break; + } +} + +static unsigned int expand_bits_8[16] = { + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +static unsigned int expand_bits_16[4] = { + 0x00000000, + 0x0000ffff, + 0xffff0000, + 0xffffffff +}; + + +static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) +{ + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (-(bits >> 7) & fg) ^ bg; + base[1] = (-((bits >> 6) & 1) & fg) ^ bg; + base[2] = (-((bits >> 5) & 1) & fg) ^ bg; + base[3] = (-((bits >> 4) & 1) & fg) ^ bg; + base[4] = (-((bits >> 3) & 1) & fg) ^ bg; + base[5] = (-((bits >> 2) & 1) & fg) ^ bg; + base[6] = (-((bits >> 1) & 1) & fg) ^ bg; + base[7] = (-(bits & 1) & fg) ^ bg; + base = (unsigned int *) ((char *)base + rb); + } +} + +static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) +{ + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + unsigned int *eb = (int *)expand_bits_16; + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 6] & fg) ^ bg; + base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; + base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; + base[3] = (eb[bits & 3] & fg) ^ bg; + base = (unsigned int *) ((char *)base + rb); + } +} + +static void draw_byte_8(unsigned char *font, unsigned int *base, int rb) +{ + int l, bits; + int fg = 0x0F0F0F0FUL; + int bg = 0x00000000UL; + unsigned int *eb = (int *)expand_bits_8; + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 4] & fg) ^ bg; + base[1] = (eb[bits & 0xf] & fg) ^ bg; + base = (unsigned int *) ((char *)base + rb); + } +} + +static unsigned char vga_font[cmapsz] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, +0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, +0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, +0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, +0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, +0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, +0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, +0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, +0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, +0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, +0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, +0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, +0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, +0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, +0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, +0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, +0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, +0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, +0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, +0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, +0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, +0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, +0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, +0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, +0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, +0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, +0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, +0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, +0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, +0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, +0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, +0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, +0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, +0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, +0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, +0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, +0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, +0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, +0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, +0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, +0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, +0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, +0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, +0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, +0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, +0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, +0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, +0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, +0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, +0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, +0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, +0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, +0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, +0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, +0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, +0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, +0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, +0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, +0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, +0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, +0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S index 2c3a1d34e3c7..d49bff1a7d51 100644 --- a/arch/powerpc/kernel/head.S +++ b/arch/powerpc/kernel/head.S @@ -134,11 +134,13 @@ __start: * because OF may have I/O devices mapped into that area * (particularly on CHRP). */ - mr r31,r3 /* save parameters */ + cmpwi 0,r5,0 + beq 1f + bl prom_init + trap + +1: mr r31,r3 /* save parameters */ mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 li r24,0 /* cpu # */ /* @@ -204,8 +206,7 @@ __after_mmu_off: * On CHRP, we are loaded at 0x10000 since OF on CHRP uses * the exception vectors at 0 (and therefore this copy * overwrites OF's exception vectors with our own). - * If the MMU is already turned on, we copy stuff to KERNELBASE, - * otherwise we copy it to 0. + * The MMU is off at this point. */ bl reloc_offset mr r26,r3 @@ -1187,9 +1188,6 @@ start_here: */ mr r3,r31 mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 bl machine_init bl MMU_init diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 33f742cf979b..91a562e3257b 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -212,36 +212,6 @@ EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(sys_ctrler); EXPORT_SYMBOL(pmac_newworld); #endif -#ifdef CONFIG_PPC_OF -EXPORT_SYMBOL(find_devices); -EXPORT_SYMBOL(find_type_devices); -EXPORT_SYMBOL(find_compatible_devices); -EXPORT_SYMBOL(find_path_device); -EXPORT_SYMBOL(device_is_compatible); -EXPORT_SYMBOL(machine_is_compatible); -EXPORT_SYMBOL(find_all_nodes); -EXPORT_SYMBOL(get_property); -EXPORT_SYMBOL(request_OF_resource); -EXPORT_SYMBOL(release_OF_resource); -EXPORT_SYMBOL(pci_busdev_to_OF_node); -EXPORT_SYMBOL(pci_device_to_OF_node); -EXPORT_SYMBOL(pci_device_from_OF_node); -EXPORT_SYMBOL(of_find_node_by_name); -EXPORT_SYMBOL(of_find_node_by_type); -EXPORT_SYMBOL(of_find_compatible_node); -EXPORT_SYMBOL(of_find_node_by_path); -EXPORT_SYMBOL(of_find_all_nodes); -EXPORT_SYMBOL(of_get_parent); -EXPORT_SYMBOL(of_get_next_child); -EXPORT_SYMBOL(of_node_get); -EXPORT_SYMBOL(of_node_put); -#endif /* CONFIG_PPC_OF */ -#if defined(CONFIG_BOOTX_TEXT) -EXPORT_SYMBOL(btext_update_display); -#endif -#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC) -EXPORT_SYMBOL(note_scsi_host); -#endif #ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); #endif diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c new file mode 100644 index 000000000000..dc3d24ea3bff --- /dev/null +++ b/arch/powerpc/kernel/prom.c @@ -0,0 +1,2141 @@ +/* + * Procedures for creating, accessing and interpreting the device tree. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.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. + */ + +#undef DEBUG + +#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 + +#ifdef DEBUG +#define DBG(fmt...) printk(KERN_ERR fmt) +#else +#define DBG(fmt...) +#endif + +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + +struct isa_reg_property { + u32 space; + u32 address; + u32 size; +}; + + +typedef int interpret_func(struct device_node *, unsigned long *, + int, int, int); + +extern struct rtas_t rtas; +extern struct lmb lmb; +extern unsigned long klimit; + +static unsigned long memory_limit; + +static int __initdata dt_root_addr_cells; +static int __initdata dt_root_size_cells; + +#ifdef CONFIG_PPC64 +static int __initdata iommu_is_off; +int __initdata iommu_force_on; +extern unsigned long tce_alloc_start, tce_alloc_end; +#endif + +typedef u32 cell_t; + +#if 0 +static struct boot_param_header *initial_boot_params __initdata; +#else +struct boot_param_header *initial_boot_params; +#endif + +static struct device_node *allnodes = NULL; + +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static DEFINE_RWLOCK(devtree_lock); + +/* export that to outside world */ +struct device_node *of_chosen; + +struct device_node *dflt_interrupt_controller; +int num_interrupt_controllers; + +u32 rtas_data; +u32 rtas_entry; + +/* + * Wrapper for allocating memory for various data that needs to be + * attached to device nodes as they are processed at boot or when + * added to the device tree later (e.g. DLPAR). At boot there is + * already a region reserved so we just increment *mem_start by size; + * otherwise we call kmalloc. + */ +static void * prom_alloc(unsigned long size, unsigned long *mem_start) +{ + unsigned long tmp; + + if (!mem_start) + return kmalloc(size, GFP_KERNEL); + + tmp = *mem_start; + *mem_start += size; + return (void *)tmp; +} + +/* + * Find the device_node with a given phandle. + */ +static struct device_node * find_phandle(phandle ph) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->linux_phandle == ph) + return np; + return NULL; +} + +/* + * Find the interrupt parent of a node. + */ +static struct device_node * __devinit intr_parent(struct device_node *p) +{ + phandle *parp; + + parp = (phandle *) get_property(p, "interrupt-parent", NULL); + if (parp == NULL) + return p->parent; + p = find_phandle(*parp); + if (p != NULL) + return p; + /* + * On a powermac booted with BootX, we don't get to know the + * phandles for any nodes, so find_phandle will return NULL. + * Fortunately these machines only have one interrupt controller + * so there isn't in fact any ambiguity. -- paulus + */ + if (num_interrupt_controllers == 1) + p = dflt_interrupt_controller; + return p; +} + +/* + * Find out the size of each entry of the interrupts property + * for a node. + */ +int __devinit prom_n_intr_cells(struct device_node *np) +{ + struct device_node *p; + unsigned int *icp; + + for (p = np; (p = intr_parent(p)) != NULL; ) { + icp = (unsigned int *) + get_property(p, "#interrupt-cells", NULL); + if (icp != NULL) + return *icp; + if (get_property(p, "interrupt-controller", NULL) != NULL + || get_property(p, "interrupt-map", NULL) != NULL) { + printk("oops, node %s doesn't have #interrupt-cells\n", + p->full_name); + return 1; + } + } +#ifdef DEBUG_IRQ + printk("prom_n_intr_cells failed for %s\n", np->full_name); +#endif + return 1; +} + +/* + * Map an interrupt from a device up to the platform interrupt + * descriptor. + */ +static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, + struct device_node *np, unsigned int *ints, + int nintrc) +{ + struct device_node *p, *ipar; + unsigned int *imap, *imask, *ip; + int i, imaplen, match; + int newintrc = 0, newaddrc = 0; + unsigned int *reg; + int naddrc; + + reg = (unsigned int *) get_property(np, "reg", NULL); + naddrc = prom_n_addr_cells(np); + p = intr_parent(np); + while (p != NULL) { + if (get_property(p, "interrupt-controller", NULL) != NULL) + /* this node is an interrupt controller, stop here */ + break; + imap = (unsigned int *) + get_property(p, "interrupt-map", &imaplen); + if (imap == NULL) { + p = intr_parent(p); + continue; + } + imask = (unsigned int *) + get_property(p, "interrupt-map-mask", NULL); + if (imask == NULL) { + printk("oops, %s has interrupt-map but no mask\n", + p->full_name); + return 0; + } + imaplen /= sizeof(unsigned int); + match = 0; + ipar = NULL; + while (imaplen > 0 && !match) { + /* check the child-interrupt field */ + match = 1; + for (i = 0; i < naddrc && match; ++i) + match = ((reg[i] ^ imap[i]) & imask[i]) == 0; + for (; i < naddrc + nintrc && match; ++i) + match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; + imap += naddrc + nintrc; + imaplen -= naddrc + nintrc; + /* grab the interrupt parent */ + ipar = find_phandle((phandle) *imap++); + --imaplen; + if (ipar == NULL && num_interrupt_controllers == 1) + /* cope with BootX not giving us phandles */ + ipar = dflt_interrupt_controller; + if (ipar == NULL) { + printk("oops, no int parent %x in map of %s\n", + imap[-1], p->full_name); + return 0; + } + /* find the parent's # addr and intr cells */ + ip = (unsigned int *) + get_property(ipar, "#interrupt-cells", NULL); + if (ip == NULL) { + printk("oops, no #interrupt-cells on %s\n", + ipar->full_name); + return 0; + } + newintrc = *ip; + ip = (unsigned int *) + get_property(ipar, "#address-cells", NULL); + newaddrc = (ip == NULL)? 0: *ip; + imap += newaddrc + newintrc; + imaplen -= newaddrc + newintrc; + } + if (imaplen < 0) { + printk("oops, error decoding int-map on %s, len=%d\n", + p->full_name, imaplen); + return 0; + } + if (!match) { +#ifdef DEBUG_IRQ + printk("oops, no match in %s int-map for %s\n", + p->full_name, np->full_name); +#endif + return 0; + } + p = ipar; + naddrc = newaddrc; + nintrc = newintrc; + ints = imap - nintrc; + reg = ints - naddrc; + } + if (p == NULL) { +#ifdef DEBUG_IRQ + printk("hmmm, int tree for %s doesn't have ctrler\n", + np->full_name); +#endif + return 0; + } + *irq = ints; + *ictrler = p; + return nintrc; +} + +static int __devinit finish_node_interrupts(struct device_node *np, + unsigned long *mem_start, + int measure_only) +{ + unsigned int *ints; + int intlen, intrcells, intrcount; + int i, j, n; + unsigned int *irq, virq; + struct device_node *ic; + + ints = (unsigned int *) get_property(np, "interrupts", &intlen); + if (ints == NULL) + return 0; + intrcells = prom_n_intr_cells(np); + intlen /= intrcells * sizeof(unsigned int); + + np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); + if (!np->intrs) + return -ENOMEM; + + if (measure_only) + return 0; + + intrcount = 0; + for (i = 0; i < intlen; ++i, ints += intrcells) { + n = map_interrupt(&irq, &ic, np, ints, intrcells); + if (n <= 0) + continue; + + /* don't map IRQ numbers under a cascaded 8259 controller */ + if (ic && device_is_compatible(ic, "chrp,iic")) { + np->intrs[intrcount].line = irq[0]; + } else { +#ifdef CONFIG_PPC64 + virq = virt_irq_create_mapping(irq[0]); + if (virq == NO_IRQ) { + printk(KERN_CRIT "Could not allocate interrupt" + " number for %s\n", np->full_name); + continue; + } + virq = irq_offset_up(virq); +#else + virq = irq[0]; +#endif + np->intrs[intrcount].line = virq; + } + +#ifdef CONFIG_PPC64 + /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ + if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { + char *name = get_property(ic->parent, "name", NULL); + if (name && !strcmp(name, "u3")) + np->intrs[intrcount].line += 128; + else if (!(name && !strcmp(name, "mac-io"))) + /* ignore other cascaded controllers, such as + the k2-sata-root */ + break; + } +#endif + np->intrs[intrcount].sense = 1; + if (n > 1) + np->intrs[intrcount].sense = irq[1]; + if (n > 2) { + printk("hmmm, got %d intr cells for %s:", n, + np->full_name); + for (j = 0; j < n; ++j) + printk(" %d", irq[j]); + printk("\n"); + } + ++intrcount; + } + np->n_intrs = intrcount; + + return 0; +} + +static int __devinit interpret_pci_props(struct device_node *np, + unsigned long *mem_start, + int naddrc, int nsizec, + int measure_only) +{ + struct address_range *adr; + struct pci_reg_property *pci_addrs; + int i, l, n_addrs; + + pci_addrs = (struct pci_reg_property *) + get_property(np, "assigned-addresses", &l); + if (!pci_addrs) + return 0; + + n_addrs = l / sizeof(*pci_addrs); + + adr = prom_alloc(n_addrs * sizeof(*adr), mem_start); + if (!adr) + return -ENOMEM; + + if (measure_only) + return 0; + + np->addrs = adr; + np->n_addrs = n_addrs; + + for (i = 0; i < n_addrs; i++) { + adr[i].space = pci_addrs[i].addr.a_hi; + adr[i].address = pci_addrs[i].addr.a_lo | + ((u64)pci_addrs[i].addr.a_mid << 32); + adr[i].size = pci_addrs[i].size_lo; + } + + return 0; +} + +static int __init interpret_dbdma_props(struct device_node *np, + unsigned long *mem_start, + int naddrc, int nsizec, + int measure_only) +{ + struct reg_property32 *rp; + struct address_range *adr; + unsigned long base_address; + int i, l; + struct device_node *db; + + base_address = 0; + if (!measure_only) { + for (db = np->parent; db != NULL; db = db->parent) { + if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { + base_address = db->addrs[0].address; + break; + } + } + } + + rp = (struct reg_property32 *) get_property(np, "reg", &l); + if (rp != 0 && l >= sizeof(struct reg_property32)) { + i = 0; + adr = (struct address_range *) (*mem_start); + while ((l -= sizeof(struct reg_property32)) >= 0) { + if (!measure_only) { + adr[i].space = 2; + adr[i].address = rp[i].address + base_address; + adr[i].size = rp[i].size; + } + ++i; + } + np->addrs = adr; + np->n_addrs = i; + (*mem_start) += i * sizeof(struct address_range); + } + + return 0; +} + +static int __init interpret_macio_props(struct device_node *np, + unsigned long *mem_start, + int naddrc, int nsizec, + int measure_only) +{ + struct reg_property32 *rp; + struct address_range *adr; + unsigned long base_address; + int i, l; + struct device_node *db; + + base_address = 0; + if (!measure_only) { + for (db = np->parent; db != NULL; db = db->parent) { + if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { + base_address = db->addrs[0].address; + break; + } + } + } + + rp = (struct reg_property32 *) get_property(np, "reg", &l); + if (rp != 0 && l >= sizeof(struct reg_property32)) { + i = 0; + adr = (struct address_range *) (*mem_start); + while ((l -= sizeof(struct reg_property32)) >= 0) { + if (!measure_only) { + adr[i].space = 2; + adr[i].address = rp[i].address + base_address; + adr[i].size = rp[i].size; + } + ++i; + } + np->addrs = adr; + np->n_addrs = i; + (*mem_start) += i * sizeof(struct address_range); + } + + return 0; +} + +static int __init interpret_isa_props(struct device_node *np, + unsigned long *mem_start, + int naddrc, int nsizec, + int measure_only) +{ + struct isa_reg_property *rp; + struct address_range *adr; + int i, l; + + rp = (struct isa_reg_property *) get_property(np, "reg", &l); + if (rp != 0 && l >= sizeof(struct isa_reg_property)) { + i = 0; + adr = (struct address_range *) (*mem_start); + while ((l -= sizeof(struct isa_reg_property)) >= 0) { + if (!measure_only) { + adr[i].space = rp[i].space; + adr[i].address = rp[i].address; + adr[i].size = rp[i].size; + } + ++i; + } + np->addrs = adr; + np->n_addrs = i; + (*mem_start) += i * sizeof(struct address_range); + } + + return 0; +} + +static int __init interpret_root_props(struct device_node *np, + unsigned long *mem_start, + int naddrc, int nsizec, + int measure_only) +{ + struct address_range *adr; + int i, l; + unsigned int *rp; + int rpsize = (naddrc + nsizec) * sizeof(unsigned int); + + rp = (unsigned int *) get_property(np, "reg", &l); + if (rp != 0 && l >= rpsize) { + i = 0; + adr = (struct address_range *) (*mem_start); + while ((l -= rpsize) >= 0) { + if (!measure_only) { + adr[i].space = 0; + adr[i].address = rp[naddrc - 1]; + adr[i].size = rp[naddrc + nsizec - 1]; + } + ++i; + rp += naddrc + nsizec; + } + np->addrs = adr; + np->n_addrs = i; + (*mem_start) += i * sizeof(struct address_range); + } + + return 0; +} + +static int __devinit finish_node(struct device_node *np, + unsigned long *mem_start, + interpret_func *ifunc, + int naddrc, int nsizec, + int measure_only) +{ + struct device_node *child; + int *ip, rc = 0; + + /* get the device addresses and interrupts */ + if (ifunc != NULL) + rc = ifunc(np, mem_start, naddrc, nsizec, measure_only); + if (rc) + goto out; + + rc = finish_node_interrupts(np, mem_start, measure_only); + if (rc) + goto out; + + /* Look for #address-cells and #size-cells properties. */ + ip = (int *) get_property(np, "#address-cells", NULL); + if (ip != NULL) + naddrc = *ip; + ip = (int *) get_property(np, "#size-cells", NULL); + if (ip != NULL) + nsizec = *ip; + + if (!strcmp(np->name, "device-tree") || np->parent == NULL) + ifunc = interpret_root_props; + else if (np->type == 0) + ifunc = NULL; + else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) + ifunc = interpret_pci_props; + else if (!strcmp(np->type, "dbdma")) + ifunc = interpret_dbdma_props; + else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) + ifunc = interpret_macio_props; + else if (!strcmp(np->type, "isa")) + ifunc = interpret_isa_props; + else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) + ifunc = interpret_root_props; + else if (!((ifunc == interpret_dbdma_props + || ifunc == interpret_macio_props) + && (!strcmp(np->type, "escc") + || !strcmp(np->type, "media-bay")))) + ifunc = NULL; + + for (child = np->child; child != NULL; child = child->sibling) { + rc = finish_node(child, mem_start, ifunc, + naddrc, nsizec, measure_only); + if (rc) + goto out; + } +out: + return rc; +} + +static void __init scan_interrupt_controllers(void) +{ + struct device_node *np; + int n = 0; + char *name, *ic; + int iclen; + + for (np = allnodes; np != NULL; np = np->allnext) { + ic = get_property(np, "interrupt-controller", &iclen); + name = get_property(np, "name", NULL); + /* checking iclen makes sure we don't get a false + match on /chosen.interrupt_controller */ + if ((name != NULL + && strcmp(name, "interrupt-controller") == 0) + || (ic != NULL && iclen == 0 + && strcmp(name, "AppleKiwi"))) { + if (n == 0) + dflt_interrupt_controller = np; + ++n; + } + } + num_interrupt_controllers = n; +} + +/** + * finish_device_tree is called once things are running normally + * (i.e. with text and data mapped to the address they were linked at). + * It traverses the device tree and fills in some of the additional, + * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt + * mapping is also initialized at this point. + */ +void __init finish_device_tree(void) +{ + unsigned long start, end, size = 0; + + DBG(" -> finish_device_tree\n"); + +#ifdef CONFIG_PPC64 + /* Initialize virtual IRQ map */ + virt_irq_init(); +#endif + scan_interrupt_controllers(); + + /* + * Finish device-tree (pre-parsing some properties etc...) + * We do this in 2 passes. One with "measure_only" set, which + * will only measure the amount of memory needed, then we can + * allocate that memory, and call finish_node again. However, + * we must be careful as most routines will fail nowadays when + * prom_alloc() returns 0, so we must make sure our first pass + * doesn't start at 0. We pre-initialize size to 16 for that + * reason and then remove those additional 16 bytes + */ + size = 16; + finish_node(allnodes, &size, NULL, 0, 0, 1); + size -= 16; + end = start = (unsigned long) __va(lmb_alloc(size, 128)); + finish_node(allnodes, &end, NULL, 0, 0, 0); + BUG_ON(end != start + size); + + DBG(" <- finish_device_tree\n"); +} + +static inline char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + + initial_boot_params->off_dt_strings + offset; +} + +/** + * This function is used to scan the flattened device-tree, it is + * used to extract the memory informations at boot before we can + * unflatten the tree + */ +static int __init scan_flat_dt(int (*it)(unsigned long node, + const char *uname, int depth, + void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + int depth = -1; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) { + depth --; + continue; + } + if (tag == OF_DT_NOP) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + printk(KERN_WARNING "Invalid tag %x scanning flattened" + " device tree !\n", tag); + return -EINVAL; + } + depth++; + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); + if (rc != 0) + break; + } while(1); + + return rc; +} + +/** + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +static void* __init get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag == OF_DT_NOP) + continue; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + printk(KERN_WARNING "Can't find property index" + " name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while(1); +} + +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +static unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = allocl = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } else { + /* account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char*)np) + sizeof(struct device_node); + if (new_format) { + char *p = np->full_name; + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(p, dad->full_name); +#ifdef DEBUG + if ((strlen(p) + l + 1) != allocl) { + DBG("%s: p: %d, l: %d, a: %d\n", + pathp, strlen(p), l, allocl); + } +#endif + p += strlen(p); + } + *(p++) = '/'; + memcpy(p, pathp, l); + } else + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the next field as `last_child'*/ + if (dad->next == 0) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + kref_init(&np->kref); + } + while(1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag == OF_DT_NOP) { + *p += 4; + continue; + } + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p += 8; + if (initial_boot_params->version < 0x10) + *p = _ALIGN(*p, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + printk("Can't find property name in list !\n"); + break; + } + if (strcmp(pname, "name") == 0) + has_name = 1; + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + char *p = pathp, *ps = pathp, *pa = NULL; + int sz; + + while (*p) { + if ((*p) == '@') + pa = p; + if ((*p) == '/') + ps = p + 1; + p++; + } + if (pa < ps) + pa = p; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (allnextpp) { + pp->name = "name"; + pp->length = sz; + pp->value = (unsigned char *)(pp + 1); + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + DBG("fixed up name for %s -> %s\n", pathp, pp->value); + } + } + if (allnextpp) { + *prev_pp = NULL; + np->name = get_property(np, "name", NULL); + np->type = get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + printk("Weird tag at end of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} + + +/** + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used (this used to be done by finish_device_tree) + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + char *p = NULL; + int l = 0; + + DBG(" -> unflatten_device_tree()\n"); + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + DBG(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = lmb_alloc(size + 4, __alignof__(struct device_node)); + if (!mem) { + DBG("Couldn't allocate memory with lmb_alloc()!\n"); + panic("Couldn't allocate memory with lmb_alloc()!\n"); + } + mem = (unsigned long) __va(mem); + + ((u32 *)mem)[size / 4] = 0xdeadbeef; + + DBG(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp, 0); + if (*((u32 *)start) != OF_DT_END) + printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (((u32 *)mem)[size / 4] != 0xdeadbeef) + printk(KERN_WARNING "End of tree marker overwritten: %08x\n", + ((u32 *)mem)[size / 4] ); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + + /* Retreive command line */ + if (of_chosen != NULL) { + p = (char *)get_property(of_chosen, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); + } +#ifdef CONFIG_CMDLINE + if (l == 0 || (l == 1 && (*p) == 0)) + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + DBG("Command line is: %s\n", cmd_line); + + DBG(" <- unflatten_device_tree()\n"); +} + + +static int __init early_init_dt_scan_cpus(unsigned long node, + const char *uname, int depth, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + u32 *prop; + unsigned long size = 0; + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + +#ifdef CONFIG_PPC_PSERIES + /* On LPAR, look for the first ibm,pft-size property for the hash table size + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) { + u32 *pft_size; + pft_size = get_flat_dt_prop(node, "ibm,pft-size", NULL); + if (pft_size != NULL) { + /* pft_size[0] is the NUMA CEC cookie */ + ppc64_pft_size = pft_size[1]; + } + } +#endif + +#ifdef CONFIG_PPC64 + if (initial_boot_params && initial_boot_params->version >= 2) { + /* version 2 of the kexec param format adds the phys cpuid + * of booted proc. + */ + boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; + boot_cpuid = 0; + } else { + /* Check if it's the boot-cpu, set it's hw index in paca now */ + if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { + u32 *prop = get_flat_dt_prop(node, "reg", NULL); + set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); + boot_cpuid_phys = get_hard_smp_processor_id(0); + } + } +#endif + +#ifdef CONFIG_ALTIVEC + /* Check if we have a VMX and eventually update CPU features */ + prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", &size); + if (prop && (*prop) > 0) { + cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; + cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; + } + + /* Same goes for Apple's "altivec" property */ + prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL); + if (prop) { + cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; + cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; + } +#endif /* CONFIG_ALTIVEC */ + +#ifdef CONFIG_PPC_PSERIES + /* + * Check for an SMT capable CPU and set the CPU feature. We do + * this by looking at the size of the ibm,ppc-interrupt-server#s + * property + */ + prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", + &size); + cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; + if (prop && ((size / sizeof(u32)) > 1)) + cur_cpu_spec->cpu_features |= CPU_FTR_SMT; +#endif + + return 0; +} + +static int __init early_init_dt_scan_chosen(unsigned long node, + const char *uname, int depth, void *data) +{ + u32 *prop; + unsigned long *lprop; + + DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + + if (depth != 1 || strcmp(uname, "chosen") != 0) + return 0; + + /* get platform type */ + prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); + if (prop == NULL) + return 0; +#ifdef CONFIG_PPC64 + systemcfg->platform = *prop; +#else + _machine = *prop; +#endif + +#ifdef CONFIG_PPC64 + /* check if iommu is forced on or off */ + if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) + iommu_is_off = 1; + if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) + iommu_force_on = 1; +#endif + + lprop = get_flat_dt_prop(node, "linux,memory-limit", NULL); + if (lprop) + memory_limit = *lprop; + +#ifdef CONFIG_PPC64 + lprop = get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); + if (lprop) + tce_alloc_start = *lprop; + lprop = get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); + if (lprop) + tce_alloc_end = *lprop; +#endif + +#ifdef CONFIG_PPC_RTAS + /* To help early debugging via the front panel, we retreive a minimal + * set of RTAS infos now if available + */ + { + u64 *basep, *entryp; + + basep = get_flat_dt_prop(node, "linux,rtas-base", NULL); + entryp = get_flat_dt_prop(node, "linux,rtas-entry", NULL); + prop = get_flat_dt_prop(node, "linux,rtas-size", NULL); + if (basep && entryp && prop) { + rtas.base = *basep; + rtas.entry = *entryp; + rtas.size = *prop; + } + } +#endif /* CONFIG_PPC_RTAS */ + + /* break now */ + return 1; +} + +static int __init early_init_dt_scan_root(unsigned long node, + const char *uname, int depth, void *data) +{ + u32 *prop; + + if (depth != 0) + return 0; + + prop = get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + DBG("dt_root_size_cells = %x\n", dt_root_size_cells); + + prop = get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); + + /* break now */ + return 1; +} + +static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r; + + /* Ignore more than 2 cells */ + while (s > sizeof(unsigned long) / 4) { + p++; + s--; + } + r = *p++; +#ifdef CONFIG_PPC64 + if (s > 1) { + r <<= 32; + r |= *(p++); + s--; + } +#endif + + *cellp = p; + return r; +} + + +static int __init early_init_dt_scan_memory(unsigned long node, + const char *uname, int depth, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + cell_t *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL || strcmp(type, "memory") != 0) + return 0; + + reg = (cell_t *)get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(cell_t)); + + DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n", + uname, l, reg[0], reg[1], reg[2], reg[3]); + + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + unsigned long base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + DBG(" - %lx , %lx\n", base, size); +#ifdef CONFIG_PPC64 + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } +#endif + lmb_add(base, size); + } + return 0; +} + +static void __init early_reserve_mem(void) +{ + unsigned long base, size; + unsigned long *reserve_map; + + reserve_map = (unsigned long *)(((unsigned long)initial_boot_params) + + initial_boot_params->off_mem_rsvmap); + while (1) { + base = *(reserve_map++); + size = *(reserve_map++); + if (size == 0) + break; + DBG("reserving: %lx -> %lx\n", base, size); + lmb_reserve(base, size); + } + +#if 0 + DBG("memory reserved, lmbs :\n"); + lmb_dump_all(); +#endif +} + +void __init early_init_devtree(void *params) +{ + DBG(" -> early_init_devtree()\n"); + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* Retrieve various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size, TCE reserve, and more ... + */ + scan_flat_dt(early_init_dt_scan_chosen, NULL); + + /* Scan memory nodes and rebuild LMBs */ + lmb_init(); + scan_flat_dt(early_init_dt_scan_root, NULL); + scan_flat_dt(early_init_dt_scan_memory, NULL); + lmb_enforce_memory_limit(memory_limit); + lmb_analyze(); +#ifdef CONFIG_PPC64 + systemcfg->physicalMemorySize = lmb_phys_mem_size(); +#endif + lmb_reserve(0, __pa(klimit)); + + DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); + + /* Reserve LMB regions used by kernel, initrd, dt, etc... */ + early_reserve_mem(); + + DBG("Scanning CPUs ...\n"); + + /* Retreive hash table size from flattened tree plus other + * CPU related informations (altivec support, boot CPU ID, ...) + */ + scan_flat_dt(early_init_dt_scan_cpus, NULL); + +#ifdef CONFIG_PPC_PSERIES + /* If hash size wasn't obtained above, we calculate it now based on + * the total RAM size + */ + if (ppc64_pft_size == 0) { + unsigned long rnd_mem_size, pteg_count; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); + if (rnd_mem_size < systemcfg->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); + + ppc64_pft_size = __ilog2(pteg_count << 7); + } + + DBG("Hash pftSize: %x\n", (int)ppc64_pft_size); +#endif + DBG(" <- early_init_devtree()\n"); +} + +#undef printk + +int +prom_n_addr_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#address-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 1 */ + return 1; +} + +int +prom_n_size_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#size-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} + +/** + * Work out the sense (active-low level / active-high edge) + * of each interrupt from the device tree. + */ +void __init prom_get_irq_senses(unsigned char *senses, int off, int max) +{ + struct device_node *np; + int i, j; + + /* default to level-triggered */ + memset(senses, 1, max - off); + + for (np = allnodes; np != 0; np = np->allnext) { + for (j = 0; j < np->n_intrs; j++) { + i = np->intrs[j].line; + if (i >= off && i < max) + senses[i-off] = np->intrs[j].sense ? + IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE : + IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE; + } + } +} + +/** + * Construct and return a list of the device_nodes with a given name. + */ +struct device_node *find_devices(const char *name) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->name != 0 && strcasecmp(np->name, name) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_devices); + +/** + * Construct and return a list of the device_nodes with a given type. + */ +struct device_node *find_type_devices(const char *type) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->type != 0 && strcasecmp(np->type, type) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_type_devices); + +/** + * Returns all nodes linked together + */ +struct device_node *find_all_nodes(void) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + *prevp = np; + prevp = &np->next; + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_all_nodes); + +/** Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +int device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncasecmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} +EXPORT_SYMBOL(device_is_compatible); + + +/** + * Indicates whether the root node has a given value in its + * compatible property. + */ +int machine_is_compatible(const char *compat) +{ + struct device_node *root; + int rc = 0; + + root = of_find_node_by_path("/"); + if (root) { + rc = device_is_compatible(root, compat); + of_node_put(root); + } + return rc; +} +EXPORT_SYMBOL(machine_is_compatible); + +/** + * Construct and return a list of the device_nodes with a given type + * and compatible property. + */ +struct device_node *find_compatible_devices(const char *type, + const char *compat) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcasecmp(np->type, type) == 0)) + continue; + if (device_is_compatible(np, compat)) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_compatible_devices); + +/** + * Find the device_node with a given full_name. + */ +struct device_node *find_path_device(const char *path) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) + return np; + return NULL; +} +EXPORT_SYMBOL(find_path_device); + +/******* + * + * New implementation of the OF "find" APIs, return a refcounted + * object, call of_node_put() when done. The device tree and list + * are protected by a rw_lock. + * + * Note that property management will need some locking as well, + * this isn't dealt with yet. + * + *******/ + +/** + * of_find_node_by_name - Find a node by its "name" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @name: The name string to match against + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_name(struct device_node *from, + const char *name) +{ + struct device_node *np; + + read_lock(&devtree_lock); + np = from ? from->allnext : allnodes; + for (; np != 0; np = np->allnext) + if (np->name != 0 && strcasecmp(np->name, name) == 0 + && of_node_get(np)) + break; + if (from) + of_node_put(from); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_name); + +/** + * of_find_node_by_type - Find a node by its "device_type" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @name: The type string to match against + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_type(struct device_node *from, + const char *type) +{ + struct device_node *np; + + read_lock(&devtree_lock); + np = from ? from->allnext : allnodes; + for (; np != 0; np = np->allnext) + if (np->type != 0 && strcasecmp(np->type, type) == 0 + && of_node_get(np)) + break; + if (from) + of_node_put(from); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_type); + +/** + * of_find_compatible_node - Find a node based on type and one of the + * tokens in its "compatible" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @type: The type string to match "device_type" or NULL to ignore + * @compatible: The string to match to one of the tokens in the device + * "compatible" list. + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compatible) +{ + struct device_node *np; + + read_lock(&devtree_lock); + np = from ? from->allnext : allnodes; + for (; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcasecmp(np->type, type) == 0)) + continue; + if (device_is_compatible(np, compatible) && of_node_get(np)) + break; + } + if (from) + of_node_put(from); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_compatible_node); + +/** + * of_find_node_by_path - Find a node matching a full OF path + * @path: The full path to match + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_path(const char *path) +{ + struct device_node *np = allnodes; + + read_lock(&devtree_lock); + for (; np != 0; np = np->allnext) { + if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 + && of_node_get(np)) + break; + } + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_path); + +/** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np != 0; np = np->allnext) + if (np->linux_phandle == handle) + break; + if (np) + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + +/** + * of_find_all_nodes - Get next node in global list + * @prev: Previous node or NULL to start iteration + * of_node_put() will be called on it + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_all_nodes(struct device_node *prev) +{ + struct device_node *np; + + read_lock(&devtree_lock); + np = prev ? prev->allnext : allnodes; + for (; np != 0; np = np->allnext) + if (of_node_get(np)) + break; + if (prev) + of_node_put(prev); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_all_nodes); + +/** + * of_get_parent - Get a node's parent if any + * @node: Node to get parent + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_get_parent(const struct device_node *node) +{ + struct device_node *np; + + if (!node) + return NULL; + + read_lock(&devtree_lock); + np = of_node_get(node->parent); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_get_parent); + +/** + * of_get_next_child - Iterate a node childs + * @node: parent node + * @prev: previous child of the parent node, or NULL to get first + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_get_next_child(const struct device_node *node, + struct device_node *prev) +{ + struct device_node *next; + + read_lock(&devtree_lock); + next = prev ? prev->sibling : node->child; + for (; next != 0; next = next->sibling) + if (of_node_get(next)) + break; + if (prev) + of_node_put(prev); + read_unlock(&devtree_lock); + return next; +} +EXPORT_SYMBOL(of_get_next_child); + +/** + * of_node_get - Increment refcount of a node + * @node: Node to inc refcount, NULL is supported to + * simplify writing of callers + * + * Returns node. + */ +struct device_node *of_node_get(struct device_node *node) +{ + if (node) + kref_get(&node->kref); + return node; +} +EXPORT_SYMBOL(of_node_get); + +static inline struct device_node * kref_to_device_node(struct kref *kref) +{ + return container_of(kref, struct device_node, kref); +} + +/** + * of_node_release - release a dynamically allocated node + * @kref: kref element of the node to be released + * + * In of_node_put() this function is passed to kref_put() + * as the destructor. + */ +static void of_node_release(struct kref *kref) +{ + struct device_node *node = kref_to_device_node(kref); + struct property *prop = node->properties; + + if (!OF_IS_DYNAMIC(node)) + return; + while (prop) { + struct property *next = prop->next; + kfree(prop->name); + kfree(prop->value); + kfree(prop); + prop = next; + } + kfree(node->intrs); + kfree(node->addrs); + kfree(node->full_name); + kfree(node->data); + kfree(node); +} + +/** + * of_node_put - Decrement refcount of a node + * @node: Node to dec refcount, NULL is supported to + * simplify writing of callers + * + */ +void of_node_put(struct device_node *node) +{ + if (node) + kref_put(&node->kref, of_node_release); +} +EXPORT_SYMBOL(of_node_put); + +/* + * Plug a device node into the tree and global list. + */ +void of_attach_node(struct device_node *np) +{ + write_lock(&devtree_lock); + np->sibling = np->parent->child; + np->allnext = allnodes; + np->parent->child = np; + allnodes = np; + write_unlock(&devtree_lock); +} + +/* + * "Unplug" a node from the device tree. The caller must hold + * a reference to the node. The memory associated with the node + * is not freed until its refcount goes to zero. + */ +void of_detach_node(const struct device_node *np) +{ + struct device_node *parent; + + write_lock(&devtree_lock); + + parent = np->parent; + + if (allnodes == np) + allnodes = np->allnext; + else { + struct device_node *prev; + for (prev = allnodes; + prev->allnext != np; + prev = prev->allnext) + ; + prev->allnext = np->allnext; + } + + if (parent->child == np) + parent->child = np->sibling; + else { + struct device_node *prevsib; + for (prevsib = np->parent->child; + prevsib->sibling != np; + prevsib = prevsib->sibling) + ; + prevsib->sibling = np->sibling; + } + + write_unlock(&devtree_lock); +} + +#ifdef CONFIG_PPC_PSERIES +/* + * Fix up the uninitialized fields in a new device node: + * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields + * + * A lot of boot-time code is duplicated here, because functions such + * as finish_node_interrupts, interpret_pci_props, etc. cannot use the + * slab allocator. + * + * This should probably be split up into smaller chunks. + */ + +static int of_finish_dynamic_node(struct device_node *node, + unsigned long *unused1, int unused2, + int unused3, int unused4) +{ + struct device_node *parent = of_get_parent(node); + int err = 0; + phandle *ibm_phandle; + + node->name = get_property(node, "name", NULL); + node->type = get_property(node, "device_type", NULL); + + if (!parent) { + err = -ENODEV; + goto out; + } + + /* We don't support that function on PowerMac, at least + * not yet + */ + if (systemcfg->platform == PLATFORM_POWERMAC) + return -ENODEV; + + /* fix up new node's linux_phandle field */ + if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) + node->linux_phandle = *ibm_phandle; + +out: + of_node_put(parent); + return err; +} + +static int prom_reconfig_notifier(struct notifier_block *nb, + unsigned long action, void *node) +{ + int err; + + switch (action) { + case PSERIES_RECONFIG_ADD: + err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); + if (err < 0) { + printk(KERN_ERR "finish_node returned %d\n", err); + err = NOTIFY_BAD; + } + break; + default: + err = NOTIFY_DONE; + break; + } + return err; +} + +static struct notifier_block prom_reconfig_nb = { + .notifier_call = prom_reconfig_notifier, + .priority = 10, /* This one needs to run first */ +}; + +static int __init prom_reconfig_setup(void) +{ + return pSeries_reconfig_notifier_register(&prom_reconfig_nb); +} +__initcall(prom_reconfig_setup); +#endif + +/* + * Find a property with a given name for a given node + * and return the value. + */ +unsigned char *get_property(struct device_node *np, const char *name, + int *lenp) +{ + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) + if (strcmp(pp->name, name) == 0) { + if (lenp != 0) + *lenp = pp->length; + return pp->value; + } + return NULL; +} +EXPORT_SYMBOL(get_property); + +/* + * Add a property to a node + */ +void prom_add_property(struct device_node* np, struct property* prop) +{ + struct property **next = &np->properties; + + prop->next = NULL; + while (*next) + next = &(*next)->next; + *next = prop; +} + +/* I quickly hacked that one, check against spec ! */ +static inline unsigned long +bus_space_to_resource_flags(unsigned int bus_space) +{ + u8 space = (bus_space >> 24) & 0xf; + if (space == 0) + space = 0x02; + if (space == 0x02) + return IORESOURCE_MEM; + else if (space == 0x01) + return IORESOURCE_IO; + else { + printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", + bus_space); + return 0; + } +} + +static struct resource *find_parent_pci_resource(struct pci_dev* pdev, + struct address_range *range) +{ + unsigned long mask; + int i; + + /* Check this one */ + mask = bus_space_to_resource_flags(range->space); + for (i=0; iresource[i].flags & mask) == mask && + pdev->resource[i].start <= range->address && + pdev->resource[i].end > range->address) { + if ((range->address + range->size - 1) > pdev->resource[i].end) { + /* Add better message */ + printk(KERN_WARNING "PCI/OF resource overlap !\n"); + return NULL; + } + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) + return NULL; + return &pdev->resource[i]; +} + +/* + * Request an OF device resource. Currently handles child of PCI devices, + * or other nodes attached to the root node. Ultimately, put some + * link to resources in the OF node. + */ +struct resource *request_OF_resource(struct device_node* node, int index, + const char* name_postfix) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + int nlen, plen; + + if (index >= node->n_addrs) + goto fail; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + goto fail; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while (nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + node->name); + goto fail; + } + + res = __request_region(parent, node->addrs[index].address, + node->addrs[index].size, NULL); + if (!res) + goto fail; + nlen = strlen(node->name); + plen = name_postfix ? strlen(name_postfix) : 0; + res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); + if (res->name) { + strcpy((char *)res->name, node->name); + if (plen) + strcpy((char *)res->name+nlen, name_postfix); + } + return res; +fail: + return NULL; +} +EXPORT_SYMBOL(request_OF_resource); + +int release_OF_resource(struct device_node *node, int index) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask, start, end; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + + if (index >= node->n_addrs) + return -EINVAL; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + return -EINVAL; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while(nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", + node->name); + return -ENODEV; + } + + /* Find us in the parent and its childs */ + res = parent->child; + start = node->addrs[index].address; + end = start + node->addrs[index].size - 1; + while (res) { + if (res->start == start && res->end == end && + (res->flags & IORESOURCE_BUSY)) + break; + if (res->start <= start && res->end >= end) + res = res->child; + else + res = res->sibling; + } + if (!res) + return -ENODEV; + + if (res->name) { + kfree(res->name); + res->name = NULL; + } + release_resource(res); + kfree(res); + + return 0; +} +EXPORT_SYMBOL(release_OF_resource); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c new file mode 100644 index 000000000000..e01cda1454c9 --- /dev/null +++ b/arch/powerpc/kernel/prom_init.c @@ -0,0 +1,2126 @@ +/* + * Procedures for interfacing to Open Firmware. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.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. + */ + +#undef DEBUG_PROM + +#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 + +#ifdef CONFIG_LOGO_LINUX_CLUT224 +#include +extern const struct linux_logo logo_linux_clut224; +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This value does need to be big enough to + * ensure that we don't lose things like the interrupt-map property + * on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) + +/* + * Eventually bump that one up + */ +#define DEVTREE_CHUNK_SIZE 0x100000 + +/* + * This is the size of the local memory reserve map that gets copied + * into the boot params passed to the kernel. That size is totally + * flexible as the kernel just reads the list until it encounters an + * entry with size 0, so it can be changed without breaking binary + * compatibility + */ +#define MEM_RESERVE_MAP_SIZE 8 + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at. + * On ppc32 we compile with -mrelocatable, which means that references + * to extern and static variables get relocated automatically. + * On ppc64 we have to relocate the references explicitly with + * RELOC. (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls must be done within prom_init(). + * + * ADDR is used in calls to call_prom. The 4th and following + * arguments to call_prom should be 32-bit values. + * On ppc64, 64 bit values are truncated to 32 bits (and + * fortunately don't get interpreted as two arguments). + */ +#ifdef CONFIG_PPC64 +#define RELOC(x) (*PTRRELOC(&(x))) +#define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) +#else +#define RELOC(x) (x) +#define ADDR(x) (u32) (x) +#endif + +#define PROM_BUG() do { \ + prom_printf("kernel BUG at %s line 0x%x!\n", \ + RELOC(__FILE__), __LINE__); \ + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ +} while (0) + +#ifdef DEBUG_PROM +#define prom_debug(x...) prom_printf(x) +#else +#define prom_debug(x...) +#endif + +#ifdef CONFIG_PPC32 +#define PLATFORM_POWERMAC _MACH_Pmac +#define PLATFORM_CHRP _MACH_chrp +#endif + + +typedef u32 prom_arg_t; + +struct prom_args { + u32 service; + u32 nargs; + u32 nret; + prom_arg_t args[10]; +}; + +struct prom_t { + ihandle root; + ihandle chosen; + int cpu; + ihandle stdout; +}; + +struct mem_map_entry { + unsigned long base; + unsigned long size; +}; + +typedef u32 cell_t; + +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); + +#ifdef CONFIG_PPC64 +extern void enter_prom(struct prom_args *args, unsigned long entry); +#else +static inline void enter_prom(struct prom_args *args, unsigned long entry) +{ + ((void (*)(struct prom_args *))entry)(args); +} +#endif + +extern void copy_and_flush(unsigned long dest, unsigned long src, + unsigned long size, unsigned long offset); + +/* prom structure */ +static struct prom_t __initdata prom; + +static unsigned long prom_entry __initdata; + +#define PROM_SCRATCH_SIZE 256 + +static char __initdata of_stdout_device[256]; +static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; + +static unsigned long __initdata dt_header_start; +static unsigned long __initdata dt_struct_start, dt_struct_end; +static unsigned long __initdata dt_string_start, dt_string_end; + +static unsigned long __initdata prom_initrd_start, prom_initrd_end; + +#ifdef CONFIG_PPC64 +static int __initdata iommu_force_on; +static int __initdata ppc64_iommu_off; +static unsigned long __initdata prom_tce_alloc_start; +static unsigned long __initdata prom_tce_alloc_end; +#endif + +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; +static unsigned long __initdata rmo_top; +static unsigned long __initdata ram_top; + +static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; +static int __initdata mem_reserve_cnt; + +static cell_t __initdata regbuf[1024]; + + +#define MAX_CPU_THREADS 2 + +/* TO GO */ +#ifdef CONFIG_HMT +struct { + unsigned int pir; + unsigned int threadid; +} hmt_thread_data[NR_CPUS]; +#endif /* CONFIG_HMT */ + +/* + * Error results ... some OF calls will return "-1" on error, some + * will return 0, some will return either. To simplify, here are + * macros to use with any ihandle or phandle return value to check if + * it is valid + */ + +#define PROM_ERROR (-1u) +#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR) +#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR) + + +/* This is the one and *ONLY* place where we actually call open + * firmware. + */ + +static int __init call_prom(const char *service, int nargs, int nret, ...) +{ + int i; + struct prom_args args; + va_list list; + + args.service = ADDR(service); + args.nargs = nargs; + args.nret = nret; + + va_start(list, nret); + for (i = 0; i < nargs; i++) + args.args[i] = va_arg(list, prom_arg_t); + va_end(list); + + for (i = 0; i < nret; i++) + args.args[nargs+i] = 0; + + enter_prom(&args, RELOC(prom_entry)); + + return (nret > 0) ? args.args[nargs] : 0; +} + +static int __init call_prom_ret(const char *service, int nargs, int nret, + prom_arg_t *rets, ...) +{ + int i; + struct prom_args args; + va_list list; + + args.service = ADDR(service); + args.nargs = nargs; + args.nret = nret; + + va_start(list, rets); + for (i = 0; i < nargs; i++) + args.args[i] = va_arg(list, prom_arg_t); + va_end(list); + + for (i = 0; i < nret; i++) + rets[nargs+i] = 0; + + enter_prom(&args, RELOC(prom_entry)); + + if (rets != NULL) + for (i = 1; i < nret; ++i) + rets[i] = args.args[nargs+i]; + + return (nret > 0) ? args.args[nargs] : 0; +} + + +static unsigned int __init prom_claim(unsigned long virt, unsigned long size, + unsigned long align) +{ + return (unsigned int)call_prom("claim", 3, 1, + (prom_arg_t)virt, (prom_arg_t)size, + (prom_arg_t)align); +} + +static void __init prom_print(const char *msg) +{ + const char *p, *q; + struct prom_t *_prom = &RELOC(prom); + + if (_prom->stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + ++q; + call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); + } +} + + +static void __init prom_print_hex(unsigned long val) +{ + int i, nibbles = sizeof(val)*2; + char buf[sizeof(val)*2+1]; + struct prom_t *_prom = &RELOC(prom); + + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + call_prom("write", 3, 1, _prom->stdout, buf, nibbles); +} + + +static void __init prom_printf(const char *format, ...) +{ + const char *p, *q, *s; + va_list args; + unsigned long v; + struct prom_t *_prom = &RELOC(prom); + + va_start(args, format); +#ifdef CONFIG_PPC64 + format = PTRRELOC(format); +#endif + for (p = format; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + if (*q == '\n') { + ++q; + call_prom("write", 3, 1, _prom->stdout, + ADDR("\r\n"), 2); + continue; + } + ++q; + if (*q == 0) + break; + switch (*q) { + case 's': + ++q; + s = va_arg(args, const char *); + prom_print(s); + break; + case 'x': + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + break; + } + } +} + + +static void __init __attribute__((noreturn)) prom_panic(const char *reason) +{ +#ifdef CONFIG_PPC64 + reason = PTRRELOC(reason); +#endif + prom_print(reason); + /* ToDo: should put up an SRC here on p/iSeries */ + call_prom("exit", 0, 0); + + for (;;) /* should never get here */ + ; +} + + +static int __init prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +static int __init prom_getprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + return call_prom("getprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + +static int __init prom_getproplen(phandle node, const char *pname) +{ + return call_prom("getproplen", 2, 1, node, ADDR(pname)); +} + +static int __init prom_setprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + return call_prom("setprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + +/* We can't use the standard versions because of RELOC headaches. */ +#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'f') \ + || ('A' <= (c) && (c) <= 'F')) + +#define isdigit(c) ('0' <= (c) && (c) <= '9') +#define islower(c) ('a' <= (c) && (c) <= 'z') +#define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c)) + +unsigned long prom_strtoul(const char *cp, const char **endp) +{ + unsigned long result = 0, base = 10, value; + + if (*cp == '0') { + base = 8; + cp++; + if (toupper(*cp) == 'X') { + cp++; + base = 16; + } + } + + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) { + result = result * base + value; + cp++; + } + + if (endp) + *endp = cp; + + return result; +} + +unsigned long prom_memparse(const char *ptr, const char **retptr) +{ + unsigned long ret = prom_strtoul(ptr, retptr); + int shift = 0; + + /* + * We can't use a switch here because GCC *may* generate a + * jump table which won't work, because we're not running at + * the address we're linked at. + */ + if ('G' == **retptr || 'g' == **retptr) + shift = 30; + + if ('M' == **retptr || 'm' == **retptr) + shift = 20; + + if ('K' == **retptr || 'k' == **retptr) + shift = 10; + + if (shift) { + ret <<= shift; + (*retptr)++; + } + + return ret; +} + +/* + * Early parsing of the command line passed to the kernel, used for + * "mem=x" and the options that affect the iommu + */ +static void __init early_cmdline_parse(void) +{ + struct prom_t *_prom = &RELOC(prom); + char *opt, *p; + int l = 0; + + RELOC(prom_cmd_line[0]) = 0; + p = RELOC(prom_cmd_line); + if ((long)_prom->chosen > 0) + l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(RELOC(prom_cmd_line), + RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); +#endif /* CONFIG_CMDLINE */ + prom_printf("command line: %s\n", RELOC(prom_cmd_line)); + +#ifdef CONFIG_PPC64 + opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); + if (opt) { + prom_printf("iommu opt is: %s\n", opt); + opt += 6; + while (*opt && *opt == ' ') + opt++; + if (!strncmp(opt, RELOC("off"), 3)) + RELOC(ppc64_iommu_off) = 1; + else if (!strncmp(opt, RELOC("force"), 5)) + RELOC(iommu_force_on) = 1; + } +#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_PPC_PSERIES +/* + * To tell the firmware what our capabilities are, we have to pass + * it a fake 32-bit ELF header containing a couple of PT_NOTE sections + * that contain structures that contain the actual values. + */ +static struct fake_elf { + Elf32_Ehdr elfhdr; + Elf32_Phdr phdr[2]; + struct chrpnote { + u32 namesz; + u32 descsz; + u32 type; + char name[8]; /* "PowerPC" */ + struct chrpdesc { + u32 real_mode; + u32 real_base; + u32 real_size; + u32 virt_base; + u32 virt_size; + u32 load_base; + } chrpdesc; + } chrpnote; + struct rpanote { + u32 namesz; + u32 descsz; + u32 type; + char name[24]; /* "IBM,RPA-Client-Config" */ + struct rpadesc { + u32 lpar_affinity; + u32 min_rmo_size; + u32 min_rmo_percent; + u32 max_pft_size; + u32 splpar; + u32 min_load; + u32 new_mem_def; + u32 ignore_me; + } rpadesc; + } rpanote; +} fake_elf = { + .elfhdr = { + .e_ident = { 0x7f, 'E', 'L', 'F', + ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, + .e_type = ET_EXEC, /* yeah right */ + .e_machine = EM_PPC, + .e_version = EV_CURRENT, + .e_phoff = offsetof(struct fake_elf, phdr), + .e_phentsize = sizeof(Elf32_Phdr), + .e_phnum = 2 + }, + .phdr = { + [0] = { + .p_type = PT_NOTE, + .p_offset = offsetof(struct fake_elf, chrpnote), + .p_filesz = sizeof(struct chrpnote) + }, [1] = { + .p_type = PT_NOTE, + .p_offset = offsetof(struct fake_elf, rpanote), + .p_filesz = sizeof(struct rpanote) + } + }, + .chrpnote = { + .namesz = sizeof("PowerPC"), + .descsz = sizeof(struct chrpdesc), + .type = 0x1275, + .name = "PowerPC", + .chrpdesc = { + .real_mode = ~0U, /* ~0 means "don't care" */ + .real_base = ~0U, + .real_size = ~0U, + .virt_base = ~0U, + .virt_size = ~0U, + .load_base = ~0U + }, + }, + .rpanote = { + .namesz = sizeof("IBM,RPA-Client-Config"), + .descsz = sizeof(struct rpadesc), + .type = 0x12759999, + .name = "IBM,RPA-Client-Config", + .rpadesc = { + .lpar_affinity = 0, + .min_rmo_size = 64, /* in megabytes */ + .min_rmo_percent = 0, + .max_pft_size = 48, /* 2^48 bytes max PFT size */ + .splpar = 1, + .min_load = ~0U, + .new_mem_def = 0 + } + } +}; + +static void __init prom_send_capabilities(void) +{ + ihandle elfloader; + + elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); + if (elfloader == 0) { + prom_printf("couldn't open /packages/elf-loader\n"); + return; + } + call_prom("call-method", 3, 1, ADDR("process-elf-header"), + elfloader, ADDR(&fake_elf)); + call_prom("close", 1, 0, elfloader); +} +#endif + +/* + * Memory allocation strategy... our layout is normally: + * + * at 14Mb or more we have vmlinux, then a gap and initrd. In some + * rare cases, initrd might end up being before the kernel though. + * We assume this won't override the final kernel at 0, we have no + * provision to handle that in this version, but it should hopefully + * never happen. + * + * alloc_top is set to the top of RMO, eventually shrink down if the + * TCEs overlap + * + * alloc_bottom is set to the top of kernel/initrd + * + * from there, allocations are done this way : rtas is allocated + * topmost, and the device-tree is allocated from the bottom. We try + * to grow the device-tree allocation as we progress. If we can't, + * then we fail, we don't currently have a facility to restart + * elsewhere, but that shouldn't be necessary. + * + * Note that calls to reserve_mem have to be done explicitly, memory + * allocated with either alloc_up or alloc_down isn't automatically + * reserved. + */ + + +/* + * Allocates memory in the RMO upward from the kernel/initrd + * + * When align is 0, this is a special case, it means to allocate in place + * at the current location of alloc_bottom or fail (that is basically + * extending the previous allocation). Used for the device-tree flattening + */ +static unsigned long __init alloc_up(unsigned long size, unsigned long align) +{ + unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); + unsigned long addr = 0; + + prom_debug("alloc_up(%x, %x)\n", size, align); + if (RELOC(ram_top) == 0) + prom_panic("alloc_up() called with mem not initialized\n"); + + if (align) + base = _ALIGN_UP(RELOC(alloc_bottom), align); + else + base = RELOC(alloc_bottom); + + for(; (base + size) <= RELOC(alloc_top); + base = _ALIGN_UP(base + 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if (addr != PROM_ERROR) + break; + addr = 0; + if (align == 0) + break; + } + if (addr == 0) + return 0; + RELOC(alloc_bottom) = addr; + + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Allocates memory downward, either from top of RMO, or if highmem + * is set, from the top of RAM. Note that this one doesn't handle + * failures. It does claim memory if highmem is not set. + */ +static unsigned long __init alloc_down(unsigned long size, unsigned long align, + int highmem) +{ + unsigned long base, addr = 0; + + prom_debug("alloc_down(%x, %x, %s)\n", size, align, + highmem ? RELOC("(high)") : RELOC("(low)")); + if (RELOC(ram_top) == 0) + prom_panic("alloc_down() called with mem not initialized\n"); + + if (highmem) { + /* Carve out storage for the TCE table. */ + addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); + if (addr <= RELOC(alloc_bottom)) + return 0; + /* Will we bump into the RMO ? If yes, check out that we + * didn't overlap existing allocations there, if we did, + * we are dead, we must be the first in town ! + */ + if (addr < RELOC(rmo_top)) { + /* Good, we are first */ + if (RELOC(alloc_top) == RELOC(rmo_top)) + RELOC(alloc_top) = RELOC(rmo_top) = addr; + else + return 0; + } + RELOC(alloc_top_high) = addr; + goto bail; + } + + base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); + for (; base > RELOC(alloc_bottom); + base = _ALIGN_DOWN(base - 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if (addr != PROM_ERROR) + break; + addr = 0; + } + if (addr == 0) + return 0; + RELOC(alloc_top) = addr; + + bail: + prom_debug(" -> %x\n", addr); + prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); + prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); + prom_debug(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Parse a "reg" cell + */ +static unsigned long __init prom_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > sizeof(unsigned long) / 4) { + p++; + s--; + } + r = *p++; +#ifdef CONFIG_PPC64 + if (s) { + r <<= 32; + r |= *(p++); + } +#endif + *cellp = p; + return r; +} + +/* + * Very dumb function for adding to the memory reserve list, but + * we don't need anything smarter at this point + * + * XXX Eventually check for collisions. They should NEVER happen. + * If problems seem to show up, it would be a good start to track + * them down. + */ +static void reserve_mem(unsigned long base, unsigned long size) +{ + unsigned long top = base + size; + unsigned long cnt = RELOC(mem_reserve_cnt); + + if (size == 0) + return; + + /* We need to always keep one empty entry so that we + * have our terminator with "size" set to 0 since we are + * dumb and just copy this entire array to the boot params + */ + base = _ALIGN_DOWN(base, PAGE_SIZE); + top = _ALIGN_UP(top, PAGE_SIZE); + size = top - base; + + if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) + prom_panic("Memory reserve map exhausted !\n"); + RELOC(mem_reserve_map)[cnt].base = base; + RELOC(mem_reserve_map)[cnt].size = size; + RELOC(mem_reserve_cnt) = cnt + 1; +} + +/* + * Initialize memory allocation mecanism, parse "memory" nodes and + * obtain that way the top of memory and RMO to setup out local allocator + */ +static void __init prom_init_mem(void) +{ + phandle node; + char *path, type[64]; + unsigned int plen; + cell_t *p, *endp; + struct prom_t *_prom = &RELOC(prom); + u32 rac, rsc; + + /* + * We iterate the memory nodes to find + * 1) top of RMO (first node) + * 2) top of memory + */ + rac = 2; + prom_getprop(_prom->root, "#address-cells", &rac, sizeof(rac)); + rsc = 1; + prom_getprop(_prom->root, "#size-cells", &rsc, sizeof(rsc)); + prom_debug("root_addr_cells: %x\n", (unsigned long) rac); + prom_debug("root_size_cells: %x\n", (unsigned long) rsc); + + prom_debug("scanning memory:\n"); + path = RELOC(prom_scratch); + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + + if (strcmp(type, RELOC("memory"))) + continue; + + plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); + if (plen > sizeof(regbuf)) { + prom_printf("memory node too large for buffer !\n"); + plen = sizeof(regbuf); + } + p = RELOC(regbuf); + endp = p + (plen / sizeof(cell_t)); + +#ifdef DEBUG_PROM + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + prom_debug(" node %s :\n", path); +#endif /* DEBUG_PROM */ + + while ((endp - p) >= (rac + rsc)) { + unsigned long base, size; + + base = prom_next_cell(rac, &p); + size = prom_next_cell(rsc, &p); + + if (size == 0) + continue; + prom_debug(" %x %x\n", base, size); + if (base == 0) + RELOC(rmo_top) = size; + if ((base + size) > RELOC(ram_top)) + RELOC(ram_top) = base + size; + } + } + + RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000); + + /* Check if we have an initrd after the kernel, if we do move our bottom + * point to after it + */ + if (RELOC(prom_initrd_start)) { + if (RELOC(prom_initrd_end) > RELOC(alloc_bottom)) + 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. + * Some RS64 machines have buggy firmware where claims up at + * 1GB fail. Cap at 768MB as a workaround. + * Since 768MB is plenty of room, and we need to cap to something + * reasonable on 32-bit, cap at 768MB on all machines. + */ + if (!RELOC(rmo_top)) + RELOC(rmo_top) = RELOC(ram_top); + RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top)); + RELOC(alloc_top) = RELOC(rmo_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)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); +} + + +/* + * Allocate room for and instantiate RTAS + */ +static void __init prom_instantiate_rtas(void) +{ + phandle rtas_node; + ihandle rtas_inst; + u32 base, entry = 0; + u32 size = 0; + + prom_debug("prom_instantiate_rtas: start...\n"); + + rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas")); + prom_debug("rtas_node: %x\n", rtas_node); + if (!PHANDLE_VALID(rtas_node)) + return; + + prom_getprop(rtas_node, "rtas-size", &size, sizeof(size)); + if (size == 0) + return; + + base = alloc_down(size, PAGE_SIZE, 0); + if (base == 0) { + prom_printf("RTAS allocation failed !\n"); + return; + } + + rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); + if (!IHANDLE_VALID(rtas_inst)) { + prom_printf("opening rtas package failed"); + return; + } + + prom_printf("instantiating rtas at 0x%x ...", base); + + if (call_prom_ret("call-method", 3, 2, &entry, + ADDR("instantiate-rtas"), + rtas_inst, base) == PROM_ERROR + || entry == 0) { + prom_printf(" failed\n"); + return; + } + prom_printf(" done\n"); + + reserve_mem(base, size); + + prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); + prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); + + prom_debug("rtas base = 0x%x\n", base); + prom_debug("rtas entry = 0x%x\n", entry); + prom_debug("rtas size = 0x%x\n", (long)size); + + prom_debug("prom_instantiate_rtas: end...\n"); +} + +#ifdef CONFIG_PPC64 +/* + * Allocate room for and initialize TCE tables + */ +static void __init prom_initialize_tce_table(void) +{ + phandle node; + ihandle phb_node; + char compatible[64], type[64], model[64]; + char *path = RELOC(prom_scratch); + u64 base, align; + u32 minalign, minsize; + u64 tce_entry, *tce_entryp; + u64 local_alloc_top, local_alloc_bottom; + u64 i; + + if (RELOC(ppc64_iommu_off)) + return; + + prom_debug("starting prom_initialize_tce_table\n"); + + /* Cache current top of allocs so we reserve a single block */ + local_alloc_top = RELOC(alloc_top_high); + local_alloc_bottom = local_alloc_top; + + /* Search all nodes looking for PHBs. */ + for (node = 0; prom_next_node(&node); ) { + compatible[0] = 0; + type[0] = 0; + model[0] = 0; + prom_getprop(node, "compatible", + compatible, sizeof(compatible)); + prom_getprop(node, "device_type", type, sizeof(type)); + prom_getprop(node, "model", model, sizeof(model)); + + if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) + continue; + + /* Keep the old logic in tack to avoid regression. */ + if (compatible[0] != 0) { + if ((strstr(compatible, RELOC("python")) == NULL) && + (strstr(compatible, RELOC("Speedwagon")) == NULL) && + (strstr(compatible, RELOC("Winnipeg")) == NULL)) + continue; + } else if (model[0] != 0) { + if ((strstr(model, RELOC("ython")) == NULL) && + (strstr(model, RELOC("peedwagon")) == NULL) && + (strstr(model, RELOC("innipeg")) == NULL)) + continue; + } + + if (prom_getprop(node, "tce-table-minalign", &minalign, + sizeof(minalign)) == PROM_ERROR) + minalign = 0; + if (prom_getprop(node, "tce-table-minsize", &minsize, + sizeof(minsize)) == PROM_ERROR) + minsize = 4UL << 20; + + /* + * Even though we read what OF wants, we just set the table + * size to 4 MB. This is enough to map 2GB of PCI DMA space. + * By doing this, we avoid the pitfalls of trying to DMA to + * MMIO space and the DMA alias hole. + * + * On POWER4, firmware sets the TCE region by assuming + * each TCE table is 8MB. Using this memory for anything + * else will impact performance, so we always allocate 8MB. + * Anton + */ + if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) + minsize = 8UL << 20; + else + minsize = 4UL << 20; + + /* Align to the greater of the align or size */ + align = max(minalign, minsize); + base = alloc_down(minsize, align, 1); + if (base == 0) + prom_panic("ERROR, cannot find space for TCE table.\n"); + if (base < local_alloc_bottom) + local_alloc_bottom = base; + + /* Save away the TCE table attributes for later use. */ + prom_setprop(node, "linux,tce-base", &base, sizeof(base)); + prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); + + /* It seems OF doesn't null-terminate the path :-( */ + memset(path, 0, sizeof(path)); + /* Call OF to setup the TCE hardware */ + if (call_prom("package-to-path", 3, 1, node, + path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { + prom_printf("package-to-path failed\n"); + } + + prom_debug("TCE table: %s\n", path); + prom_debug("\tnode = 0x%x\n", node); + prom_debug("\tbase = 0x%x\n", base); + prom_debug("\tsize = 0x%x\n", minsize); + + /* Initialize the table to have a one-to-one mapping + * over the allocated size. + */ + tce_entryp = (unsigned long *)base; + for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { + tce_entry = (i << PAGE_SHIFT); + tce_entry |= 0x3; + *tce_entryp = tce_entry; + } + + prom_printf("opening PHB %s", path); + phb_node = call_prom("open", 1, 1, path); + if (phb_node == 0) + prom_printf("... failed\n"); + else + prom_printf("... done\n"); + + call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), + phb_node, -1, minsize, + (u32) base, (u32) (base >> 32)); + call_prom("close", 1, 0, phb_node); + } + + 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; + } + + /* Flag the first invalid entry */ + prom_debug("ending prom_initialize_tce_table\n"); +} +#endif + +/* + * With CHRP SMP we need to use the OF to start the other processors. + * We can't wait until smp_boot_cpus (the OF is trashed by then) + * so we have to put the processors into a holding pattern controlled + * by the kernel (not OF) before we destroy the OF. + * + * This uses a chunk of low memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. The holding pattern + * checks that address until its cpu # is there, when it is that + * cpu jumps to __secondary_start(). smp_boot_cpus() takes care + * of setting those values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * -- Cort + */ +static void __init prom_hold_cpus(void) +{ +#ifdef CONFIG_PPC64 + unsigned long i; + unsigned int reg; + phandle node; + char type[64]; + int cpuid = 0; + unsigned int interrupt_server[MAX_CPU_THREADS]; + unsigned int cpu_threads, hw_cpu_num; + int propsize; + extern void __secondary_hold(void); + extern unsigned long __secondary_hold_spinloop; + extern unsigned long __secondary_hold_acknowledge; + unsigned long *spinloop + = (void *) __pa(&__secondary_hold_spinloop); + unsigned long *acknowledge + = (void *) __pa(&__secondary_hold_acknowledge); +#ifdef CONFIG_PPC64 + unsigned long secondary_hold + = __pa(*PTRRELOC((unsigned long *)__secondary_hold)); +#else + unsigned long secondary_hold = __pa(&__secondary_hold); +#endif + struct prom_t *_prom = &RELOC(prom); + + prom_debug("prom_hold_cpus: start...\n"); + prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%x\n", + (unsigned long)acknowledge); + prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + + /* Set the common spinloop variable, so all of the secondary cpus + * will block when they are awakened from their OF spinloop. + * This must occur for both SMP and non SMP kernels, since OF will + * be trashed when we move the kernel. + */ + *spinloop = 0; + +#ifdef CONFIG_HMT + for (i = 0; i < NR_CPUS; i++) { + RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; + } +#endif + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + if (prom_getprop(node, "status", type, sizeof(type)) > 0) + if (strcmp(type, RELOC("okay")) != 0) + continue; + + reg = -1; + prom_getprop(node, "reg", ®, sizeof(reg)); + + prom_debug("\ncpuid = 0x%x\n", cpuid); + prom_debug("cpu hw idx = 0x%x\n", reg); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + *acknowledge = (unsigned long)-1; + + propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", + &interrupt_server, + sizeof(interrupt_server)); + if (propsize < 0) { + /* no property. old hardware has no SMT */ + cpu_threads = 1; + interrupt_server[0] = reg; /* fake it with phys id */ + } else { + /* We have a threaded processor */ + cpu_threads = propsize / sizeof(u32); + if (cpu_threads > MAX_CPU_THREADS) { + prom_printf("SMT: too many threads!\n" + "SMT: found %x, max is %x\n", + cpu_threads, MAX_CPU_THREADS); + cpu_threads = 1; /* ToDo: panic? */ + } + } + + hw_cpu_num = interrupt_server[0]; + if (hw_cpu_num != _prom->cpu) { + /* Primary Thread of non-boot cpu */ + prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); + call_prom("start-cpu", 3, 0, node, + secondary_hold, reg); + + for ( i = 0 ; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) + mb(); + + if (*acknowledge == reg) { + prom_printf("done\n"); + /* We have to get every CPU out of OF, + * even if we never start it. */ + if (cpuid >= NR_CPUS) + goto next; + } else { + prom_printf("failed: %x\n", *acknowledge); + } + } +#ifdef CONFIG_SMP + else + prom_printf("%x : boot cpu %x\n", cpuid, reg); +#endif +next: +#ifdef CONFIG_SMP + /* Init paca for secondary threads. They start later. */ + for (i=1; i < cpu_threads; i++) { + cpuid++; + if (cpuid >= NR_CPUS) + continue; + } +#endif /* CONFIG_SMP */ + cpuid++; + } +#ifdef CONFIG_HMT + /* Only enable HMT on processors that provide support. */ + if (__is_processor(PV_PULSAR) || + __is_processor(PV_ICESTAR) || + __is_processor(PV_SSTAR)) { + prom_printf(" starting secondary threads\n"); + + for (i = 0; i < NR_CPUS; i += 2) { + if (!cpu_online(i)) + continue; + + if (i == 0) { + unsigned long pir = mfspr(SPRN_PIR); + if (__is_processor(PV_PULSAR)) { + RELOC(hmt_thread_data)[i].pir = + pir & 0x1f; + } else { + RELOC(hmt_thread_data)[i].pir = + pir & 0x3ff; + } + } + } + } else { + prom_printf("Processor is not HMT capable\n"); + } +#endif + + if (cpuid > NR_CPUS) + prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) + ") exceeded: ignoring extras\n"); + + prom_debug("prom_hold_cpus: end...\n"); +#endif +} + + +static void __init prom_init_client_services(unsigned long pp) +{ + struct prom_t *_prom = &RELOC(prom); + + /* Get a handle to the prom entry point before anything else */ + RELOC(prom_entry) = pp; + + /* get a handle for the stdout device */ + _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); + if (!PHANDLE_VALID(_prom->chosen)) + prom_panic("cannot find chosen"); /* msg won't be printed :( */ + + /* get device tree root */ + _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); + if (!PHANDLE_VALID(_prom->root)) + prom_panic("cannot find device tree root"); /* msg won't be printed :( */ +} + +static void __init prom_init_stdout(void) +{ + struct prom_t *_prom = &RELOC(prom); + char *path = RELOC(of_stdout_device); + char type[16]; + u32 val; + + if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) + prom_panic("cannot find stdout"); + + _prom->stdout = val; + + /* Get the full OF pathname of the stdout device */ + memset(path, 0, 256); + call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); + val = call_prom("instance-to-package", 1, 1, _prom->stdout); + prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); + prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); + prom_setprop(_prom->chosen, "linux,stdout-path", + RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); + + /* If it's a display, note it */ + memset(type, 0, sizeof(type)); + prom_getprop(val, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) == 0) + prom_setprop(val, "linux,boot-display", NULL, 0); +} + +static void __init prom_close_stdin(void) +{ + struct prom_t *_prom = &RELOC(prom); + ihandle val; + + if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) + call_prom("close", 1, 0, val); +} + +static int __init prom_find_machine_type(void) +{ + struct prom_t *_prom = &RELOC(prom); + char compat[256]; + int len, i = 0; + phandle rtas; + + len = prom_getprop(_prom->root, "compatible", + compat, sizeof(compat)-1); + if (len > 0) { + compat[len] = 0; + while (i < len) { + char *p = &compat[i]; + int sl = strlen(p); + if (sl == 0) + break; + if (strstr(p, RELOC("Power Macintosh")) || + strstr(p, RELOC("MacRISC4"))) + return PLATFORM_POWERMAC; +#ifdef CONFIG_PPC64 + if (strstr(p, RELOC("Momentum,Maple"))) + return PLATFORM_MAPLE; +#endif + i += sl + 1; + } + } +#ifdef CONFIG_PPC64 + /* Default to pSeries. We need to know if we are running LPAR */ + rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (PHANDLE_VALID(rtas)) { + int x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (x != PROM_ERROR) { + prom_printf("Hypertas detected, assuming LPAR !\n"); + return PLATFORM_PSERIES_LPAR; + } + } + return PLATFORM_PSERIES; +#else + return PLATFORM_CHRP; +#endif +} + +static int __init setup_disp(phandle dp) +{ +#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) + int width = 640, height = 480, depth = 8, pitch; + unsigned address; + u32 addrs[8][5]; + int i, naddrs; + char name[32]; + char *getprop = "getprop"; + + prom_printf("Initializing screen: "); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print("\n"); + call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); + pitch = width * ((depth + 7) / 8); + call_prom(getprop, 4, 1, dp, "linebytes", + &pitch, sizeof(pitch)); + if (pitch == 1) + pitch = 0x1000; /* for strange IBM display */ + address = 0; + call_prom(getprop, 4, 1, dp, "address", &address, sizeof(address)); + if (address == 0) { + /* look for an assigned address with a size of >= 1MB */ + naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses", + addrs, sizeof(addrs)); + naddrs /= 20; + for (i = 0; i < naddrs; ++i) { + if (addrs[i][4] >= (1 << 20)) { + address = addrs[i][2]; + /* use the BE aperture if possible */ + if (addrs[i][4] >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print("Failed to get address\n"); + return 0; + } + } + /* kludge for valkyrie */ + if (strcmp(name, "valkyrie") == 0) + address += 0x1000; + + prom_printf("\n\n\n\naddress = %x\n", address); + btext_setup_display(width, height, depth, pitch, address); +#endif /* CONFIG_BOOTX_TEXT && CONFIG_PPC32 */ + return 1; +} + +static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static void __init prom_check_displays(void) +{ + char type[16], *path; + phandle node; + ihandle ih; + int i; + int got_display = 0; + + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + const unsigned char *clut; + + prom_printf("Looking for displays\n"); + for (node = 0; prom_next_node(&node); ) { + memset(type, 0, sizeof(type)); + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) + continue; + + /* It seems OF doesn't null-terminate the path :-( */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + + /* + * leave some room at the end of the path for appending extra + * arguments + */ + if (call_prom("package-to-path", 3, 1, node, path, + PROM_SCRATCH_SIZE-10) == PROM_ERROR) + continue; + prom_printf("found display : %s, opening ... ", path); + + ih = call_prom("open", 1, 1, path); + if (ih == 0) { + prom_printf("failed\n"); + continue; + } + + /* Success */ + prom_printf("done\n"); + prom_setprop(node, "linux,opened", NULL, 0); + + /* Setup a usable color table when the appropriate + * method is available. Should update this to set-colors */ + clut = RELOC(default_colors); + for (i = 0; i < 32; i++, clut += 3) + if (prom_set_color(ih, i, clut[0], clut[1], + clut[2]) != 0) + break; + +#ifdef CONFIG_LOGO_LINUX_CLUT224 + clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); + for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) + if (prom_set_color(ih, i + 32, clut[0], clut[1], + clut[2]) != 0) + break; +#endif /* CONFIG_LOGO_LINUX_CLUT224 */ + if (!got_display) + got_display = setup_disp(node); + } +} + + +/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ +static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, + unsigned long needed, unsigned long align) +{ + void *ret; + + *mem_start = _ALIGN(*mem_start, align); + while ((*mem_start + needed) > *mem_end) { + unsigned long room, chunk; + + prom_debug("Chunk exhausted, claiming more at %x...\n", + RELOC(alloc_bottom)); + room = RELOC(alloc_top) - RELOC(alloc_bottom); + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + if (room < PAGE_SIZE) + prom_panic("No memory for flatten_device_tree (no room)"); + chunk = alloc_up(room, 0); + if (chunk == 0) + prom_panic("No memory for flatten_device_tree (claim failed)"); + *mem_end = RELOC(alloc_top); + } + + ret = (void *)*mem_start; + *mem_start += needed; + + return ret; +} + +#define dt_push_token(token, mem_start, mem_end) \ + do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) + +static unsigned long __init dt_find_string(char *str) +{ + char *s, *os; + + s = os = (char *)RELOC(dt_string_start); + s += 4; + while (s < (char *)RELOC(dt_string_end)) { + if (strcmp(s, str) == 0) + return s - os; + s += strlen(s) + 1; + } + return 0; +} + +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + +static void __init scan_dt_build_strings(phandle node, + unsigned long *mem_start, + unsigned long *mem_end) +{ + char *prev_name, *namep, *sstart; + unsigned long soff; + phandle child; + + sstart = (char *)RELOC(dt_string_start); + + /* get and store all property names */ + prev_name = RELOC(""); + for (;;) { + /* 64 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { + /* No more nodes: unwind alloc */ + *mem_start = (unsigned long)namep; + break; + } + + /* skip "name" */ + if (strcmp(namep, RELOC("name")) == 0) { + *mem_start = (unsigned long)namep; + prev_name = RELOC("name"); + continue; + } + /* get/create string entry */ + soff = dt_find_string(namep); + if (soff != 0) { + *mem_start = (unsigned long)namep; + namep = sstart + soff; + } else { + /* Trim off some if we can */ + *mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = *mem_start; + } + prev_name = namep; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != 0) { + scan_dt_build_strings(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } +} + +static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + phandle child; + char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; + unsigned long soff; + unsigned char *valp; + static char pname[MAX_PROPERTY_NAME]; + int l; + + dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); + + /* get the node's full name */ + namep = (char *)*mem_start; + l = call_prom("package-to-path", 3, 1, node, + namep, *mem_end - *mem_start); + if (l >= 0) { + /* Didn't fit? Get more room. */ + if ((l+1) > (*mem_end - *mem_start)) { + namep = make_room(mem_start, mem_end, l+1, 1); + call_prom("package-to-path", 3, 1, node, namep, l); + } + namep[l] = '\0'; + + /* Fixup an Apple bug where they have bogus \0 chars in the + * middle of the path in some properties + */ + for (p = namep, ep = namep + l; p < ep; p++) + if (*p == '\0') { + memmove(p, p+1, ep - p); + ep--; l--; p--; + } + + /* now try to extract the unit name in that mess */ + for (p = namep, lp = NULL; *p; p++) + if (*p == '/') + lp = p + 1; + if (lp != NULL) + memmove(namep, lp, strlen(lp) + 1); + *mem_start = _ALIGN(((unsigned long) namep) + + strlen(namep) + 1, 4); + } + + /* get it again for debugging */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + + /* get and store all properties */ + prev_name = RELOC(""); + sstart = (char *)RELOC(dt_string_start); + for (;;) { + if (call_prom("nextprop", 3, 1, node, prev_name, + RELOC(pname)) != 1) + break; + + /* skip "name" */ + if (strcmp(RELOC(pname), RELOC("name")) == 0) { + prev_name = RELOC("name"); + continue; + } + + /* find string offset */ + soff = dt_find_string(RELOC(pname)); + if (soff == 0) { + prom_printf("WARNING: Can't find string index for" + " <%s>, node %s\n", RELOC(pname), path); + break; + } + prev_name = sstart + soff; + + /* get length */ + l = call_prom("getproplen", 2, 1, node, RELOC(pname)); + + /* sanity checks */ + if (l == PROM_ERROR) + continue; + if (l > MAX_PROPERTY_LENGTH) { + prom_printf("WARNING: ignoring large property "); + /* It seems OF doesn't null-terminate the path :-( */ + prom_printf("[%s] ", path); + prom_printf("%s length 0x%x\n", RELOC(pname), l); + continue; + } + + /* push property head */ + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(l, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + + /* push property content */ + valp = make_room(mem_start, mem_end, l, 4); + call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); + *mem_start = _ALIGN(*mem_start, 4); + } + + /* Add a "linux,phandle" property. */ + soff = dt_find_string(RELOC("linux,phandle")); + if (soff == 0) + prom_printf("WARNING: Can't find string index for" + " node %s\n", path); + else { + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(4, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + valp = make_room(mem_start, mem_end, 4, 4); + *(u32 *)valp = node; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != 0) { + scan_dt_build_struct(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } + + dt_push_token(OF_DT_END_NODE, mem_start, mem_end); +} + +static void __init flatten_device_tree(void) +{ + phandle root; + unsigned long mem_start, mem_end, room; + struct boot_param_header *hdr; + struct prom_t *_prom = &RELOC(prom); + char *namep; + u64 *rsvmap; + + /* + * Check how much room we have between alloc top & bottom (+/- a + * few pages), crop to 4Mb, as this is our "chuck" size + */ + room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); + + /* Now try to claim that */ + mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); + if (mem_start == 0) + prom_panic("Can't allocate initial device-tree chunk\n"); + mem_end = RELOC(alloc_top); + + /* Get root of tree */ + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) + prom_panic ("couldn't get device tree root\n"); + + /* Build header and make room for mem rsv map */ + mem_start = _ALIGN(mem_start, 4); + hdr = make_room(&mem_start, &mem_end, + sizeof(struct boot_param_header), 4); + RELOC(dt_header_start) = (unsigned long)hdr; + rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); + + /* Start of strings */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_string_start) = mem_start; + mem_start += 4; /* hole */ + + /* Add "linux,phandle" in there, we'll need it */ + namep = make_room(&mem_start, &mem_end, 16, 1); + strcpy(namep, RELOC("linux,phandle")); + mem_start = (unsigned long)namep + strlen(namep) + 1; + + /* Build string array */ + prom_printf("Building dt strings...\n"); + scan_dt_build_strings(root, &mem_start, &mem_end); + RELOC(dt_string_end) = mem_start; + + /* Build structure */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_struct_start) = mem_start; + prom_printf("Building dt structure...\n"); + scan_dt_build_struct(root, &mem_start, &mem_end); + dt_push_token(OF_DT_END, &mem_start, &mem_end); + RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); + + /* Finish header */ + hdr->boot_cpuid_phys = _prom->cpu; + hdr->magic = OF_DT_HEADER; + hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); + hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); + hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); + hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); + hdr->version = OF_DT_VERSION; + /* Version 16 is not backward compatible */ + hdr->last_comp_version = 0x10; + + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + reserve_mem(RELOC(dt_header_start), hdr->totalsize); + memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); + +#ifdef DEBUG_PROM + { + int i; + prom_printf("reserved memory map:\n"); + for (i = 0; i < RELOC(mem_reserve_cnt); i++) + prom_printf(" %x - %x\n", + RELOC(mem_reserve_map)[i].base, + RELOC(mem_reserve_map)[i].size); + } +#endif + RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; + + prom_printf("Device tree strings 0x%x -> 0x%x\n", + RELOC(dt_string_start), RELOC(dt_string_end)); + prom_printf("Device tree struct 0x%x -> 0x%x\n", + RELOC(dt_struct_start), RELOC(dt_struct_end)); + +} + + +static void __init fixup_device_tree(void) +{ +#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC) + phandle u3, i2c, mpic; + u32 u3_rev; + u32 interrupts[2]; + u32 parent; + + /* Some G5s have a missing interrupt definition, fix it up here */ + u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); + if (!PHANDLE_VALID(u3)) + return; + i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); + if (!PHANDLE_VALID(i2c)) + return; + mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); + if (!PHANDLE_VALID(mpic)) + return; + + /* check if proper rev of u3 */ + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) + == PROM_ERROR) + return; + if (u3_rev != 0x35 && u3_rev != 0x37) + return; + /* does it need fixup ? */ + if (prom_getproplen(i2c, "interrupts") > 0) + return; + + prom_printf("fixing up bogus interrupts for u3 i2c...\n"); + + /* interrupt on this revision of u3 is number 0 and level */ + interrupts[0] = 0; + interrupts[1] = 1; + prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); + parent = (u32)mpic; + prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); +#endif +} + + +static void __init prom_find_boot_cpu(void) +{ + struct prom_t *_prom = &RELOC(prom); + u32 getprop_rval; + ihandle prom_cpu; + phandle cpu_pkg; + + if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) + prom_panic("cannot find boot cpu"); + + cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); + + prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); + _prom->cpu = getprop_rval; + + prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); +} + +static void __init prom_check_initrd(unsigned long r3, unsigned long r4) +{ +#ifdef CONFIG_BLK_DEV_INITRD + struct prom_t *_prom = &RELOC(prom); + + if (r3 && r4 && r4 != 0xdeadbeef) { + unsigned long val; + + RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; + RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; + + val = RELOC(prom_initrd_start); + prom_setprop(_prom->chosen, "linux,initrd-start", &val, + sizeof(val)); + val = RELOC(prom_initrd_end); + prom_setprop(_prom->chosen, "linux,initrd-end", &val, + sizeof(val)); + + reserve_mem(RELOC(prom_initrd_start), + RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); + + prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); + prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ + +unsigned long __init prom_init(unsigned long r3, unsigned long r4, + unsigned long pp, + unsigned long r6, unsigned long r7) +{ + struct prom_t *_prom; + extern char _stext[]; + unsigned long hdr; + u32 getprop_rval; + +#ifdef CONFIG_PPC32 + unsigned long offset = reloc_offset(); + reloc_got2(offset); +#endif + + _prom = &RELOC(prom); + + /* + * First zero the BSS + */ + memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start); + + /* + * Init interface to Open Firmware, get some node references, + * like /chosen + */ + prom_init_client_services(pp); + + /* + * Init prom stdout device + */ + prom_init_stdout(); + + /* + * Check for an initrd + */ + prom_check_initrd(r3, r4); + + /* + * Get default machine type. At this point, we do not differentiate + * between pSeries SMP and pSeries LPAR + */ + RELOC(of_platform) = prom_find_machine_type(); + getprop_rval = RELOC(of_platform); + prom_setprop(_prom->chosen, "linux,platform", + &getprop_rval, sizeof(getprop_rval)); + +#ifdef CONFIG_PPC_PSERIES + /* + * On pSeries, inform the firmware about our capabilities + */ + if (RELOC(of_platform) & PLATFORM_PSERIES) + prom_send_capabilities(); +#endif + +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_BPA) + /* + * On pSeries and BPA, copy the CPU hold code + */ + if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) + copy_and_flush(0, KERNELBASE - offset, 0x100, 0); +#endif + + /* + * Do early parsing of command line + */ + early_cmdline_parse(); + + /* + * Initialize memory management within prom_init + */ + prom_init_mem(); + + /* + * Determine which cpu is actually running right _now_ + */ + prom_find_boot_cpu(); + + /* + * Initialize display devices + */ + prom_check_displays(); + +#ifdef CONFIG_PPC64 + /* + * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else + * that uses the allocator, we need to make sure we get the top of memory + * available for us here... + */ + if (RELOC(of_platform) == PLATFORM_PSERIES) + prom_initialize_tce_table(); +#endif + + /* + * On non-powermacs, try to instantiate RTAS and puts all CPUs + * in spin-loops. PowerMacs don't have a working RTAS and use + * a different way to spin CPUs + */ + if (RELOC(of_platform) != PLATFORM_POWERMAC) { + prom_instantiate_rtas(); + prom_hold_cpus(); + } + + /* + * Fill in some infos for use by the kernel later on + */ + if (RELOC(prom_memory_limit)) + prom_setprop(_prom->chosen, "linux,memory-limit", + &RELOC(prom_memory_limit), + sizeof(prom_memory_limit)); +#ifdef CONFIG_PPC64 + if (RELOC(ppc64_iommu_off)) + prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); + + if (RELOC(iommu_force_on)) + prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); + + if (RELOC(prom_tce_alloc_start)) { + prom_setprop(_prom->chosen, "linux,tce-alloc-start", + &RELOC(prom_tce_alloc_start), + sizeof(prom_tce_alloc_start)); + prom_setprop(_prom->chosen, "linux,tce-alloc-end", + &RELOC(prom_tce_alloc_end), + sizeof(prom_tce_alloc_end)); + } +#endif + + /* + * Fixup any known bugs in the device-tree + */ + fixup_device_tree(); + + /* + * Now finally create the flattened device-tree + */ + prom_printf("copying OF device tree ...\n"); + flatten_device_tree(); + + /* in case stdin is USB and still active on IBM machines... */ + prom_close_stdin(); + + /* + * Call OF "quiesce" method to shut down pending DMA's from + * devices etc... + */ + prom_printf("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* + * And finally, call the kernel passing it the flattened device + * tree and NULL as r5, thus triggering the new entry point which + * is common to us and kexec + */ + hdr = RELOC(dt_header_start); + prom_printf("returning from prom_init\n"); + prom_debug("->dt_header_start=0x%x\n", hdr); + +#ifdef CONFIG_PPC32 + reloc_got2(-offset); +#endif + + __start(hdr, 0, 0); + + return 0; +} diff --git a/arch/powerpc/kernel/setup.c b/arch/powerpc/kernel/setup.c new file mode 100644 index 000000000000..27d7f828212b --- /dev/null +++ b/arch/powerpc/kernel/setup.c @@ -0,0 +1,678 @@ +/* + * Common prep/pmac/chrp boot and setup code. + */ + +#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 +#include +#include + +#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \ + defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \ + defined(CONFIG_PPC_MPC52xx)) + +#if USES_PPC_SYS +#include +#endif + +#if defined CONFIG_KGDB +#include +#endif + +extern void platform_init(void); +extern void bootx_init(unsigned long r4, unsigned long phys); + +extern void ppc6xx_idle(void); +extern void power4_idle(void); + +boot_infos_t *boot_infos; +struct ide_machdep_calls ppc_ide_md; + +/* Used with the BI_MEMSIZE bootinfo parameter to store the memory + size value reported by the boot loader. */ +unsigned long boot_mem_size; + +unsigned long ISA_DMA_THRESHOLD; +unsigned int DMA_MODE_READ; +unsigned int DMA_MODE_WRITE; + +#ifdef CONFIG_PPC_MULTIPLATFORM +int _machine = 0; + +extern void prep_init(void); +extern void pmac_init(void); +extern void chrp_init(void); + +dev_t boot_dev; +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned long SYSRQ_KEY = 0x54; +#endif /* CONFIG_MAGIC_SYSRQ */ + +#ifdef CONFIG_VGA_CONSOLE +unsigned long vgacon_remap_base; +#endif + +struct machdep_calls ppc_md; + +/* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; + +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \ + defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA) +struct screen_info screen_info = { + 0, 25, /* orig-x, orig-y */ + 0, /* unused */ + 0, /* orig-video-page */ + 0, /* orig-video-mode */ + 80, /* orig-video-cols */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 25, /* orig-video-lines */ + 1, /* orig-video-isVGA */ + 16 /* orig-video-points */ +}; +#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */ + +void machine_restart(char *cmd) +{ +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif + ppc_md.restart(cmd); +} + +void machine_power_off(void) +{ +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif + ppc_md.power_off(); +} + +void machine_halt(void) +{ +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif + ppc_md.halt(); +} + +void (*pm_power_off)(void) = machine_power_off; + +#ifdef CONFIG_TAU +extern u32 cpu_temp(unsigned long cpu); +extern u32 cpu_temp_both(unsigned long cpu); +#endif /* CONFIG_TAU */ + +int show_cpuinfo(struct seq_file *m, void *v) +{ + int i = (int) v - 1; + int err = 0; + unsigned int pvr; + unsigned short maj, min; + unsigned long lpj; + + if (i >= NR_CPUS) { + /* Show summary information */ +#ifdef CONFIG_SMP + unsigned long bogosum = 0; + for (i = 0; i < NR_CPUS; ++i) + if (cpu_online(i)) + bogosum += cpu_data[i].loops_per_jiffy; + seq_printf(m, "total bogomips\t: %lu.%02lu\n", + bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); +#endif /* CONFIG_SMP */ + + if (ppc_md.show_cpuinfo != NULL) + err = ppc_md.show_cpuinfo(m); + return err; + } + +#ifdef CONFIG_SMP + if (!cpu_online(i)) + return 0; + pvr = cpu_data[i].pvr; + lpj = cpu_data[i].loops_per_jiffy; +#else + pvr = mfspr(SPRN_PVR); + lpj = loops_per_jiffy; +#endif + + seq_printf(m, "processor\t: %d\n", i); + seq_printf(m, "cpu\t\t: "); + + if (cur_cpu_spec->pvr_mask) + seq_printf(m, "%s", cur_cpu_spec->cpu_name); + else + seq_printf(m, "unknown (%08x)", pvr); +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) + seq_printf(m, ", altivec supported"); +#endif + seq_printf(m, "\n"); + +#ifdef CONFIG_TAU + if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { +#ifdef CONFIG_TAU_AVERAGE + /* more straightforward, but potentially misleading */ + seq_printf(m, "temperature \t: %u C (uncalibrated)\n", + cpu_temp(i)); +#else + /* show the actual temp sensor range */ + u32 temp; + temp = cpu_temp_both(i); + seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", + temp & 0xff, temp >> 16); +#endif + } +#endif /* CONFIG_TAU */ + + if (ppc_md.show_percpuinfo != NULL) { + err = ppc_md.show_percpuinfo(m, i); + if (err) + return err; + } + + /* If we are a Freescale core do a simple check so + * we dont have to keep adding cases in the future */ + if ((PVR_VER(pvr) & 0x8000) == 0x8000) { + maj = PVR_MAJ(pvr); + min = PVR_MIN(pvr); + } else { + switch (PVR_VER(pvr)) { + case 0x0020: /* 403 family */ + maj = PVR_MAJ(pvr) + 1; + min = PVR_MIN(pvr); + break; + case 0x1008: /* 740P/750P ?? */ + maj = ((pvr >> 8) & 0xFF) - 1; + min = pvr & 0xFF; + break; + default: + maj = (pvr >> 8) & 0xFF; + min = pvr & 0xFF; + break; + } + } + + seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", + maj, min, PVR_VER(pvr), PVR_REV(pvr)); + + seq_printf(m, "bogomips\t: %lu.%02lu\n", + lpj / (500000/HZ), (lpj / (5000/HZ)) % 100); + +#if USES_PPC_SYS + if (cur_ppc_sys_spec->ppc_sys_name) + seq_printf(m, "chipset\t\t: %s\n", + cur_ppc_sys_spec->ppc_sys_name); +#endif + +#ifdef CONFIG_SMP + seq_printf(m, "\n"); +#endif + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + int i = *pos; + + return i <= NR_CPUS? (void *) (i + 1): NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +/* + * We're called here very early in the boot. We determine the machine + * type and call the appropriate low-level setup functions. + * -- Cort + * + * Note that the kernel may be running at an address which is different + * from the address that it was linked at, so we must use RELOC/PTRRELOC + * to access static data (including strings). -- paulus + */ +unsigned long __init early_init(unsigned long dt_ptr) +{ + unsigned long offset = reloc_offset(); + + reloc_got2(offset); + + /* + * Identify the CPU type and fix up code sections + * that depend on which cpu we have. + */ + identify_cpu(offset, 0); + do_cpu_ftr_fixups(offset); + +#ifdef CONFIG_BOOTX_TEXT + btext_prepare_BAT(); +#endif + + reloc_got2(-offset); + + return KERNELBASE + offset; +} + +#ifdef CONFIG_PPC_OF +/* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ +int +of_show_percpuinfo(struct seq_file *m, int i) +{ + struct device_node *cpu_node; + u32 *fp; + int s; + + cpu_node = find_type_devices("cpu"); + if (!cpu_node) + return 0; + for (s = 0; s < i && cpu_node->next; s++) + cpu_node = cpu_node->next; + fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL); + if (fp) + seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000); + return 0; +} + +void __init +intuit_machine_type(void) +{ + char *model; + struct device_node *root; + + /* ask the OF info if we're a chrp or pmac */ + root = find_path_device("/"); + if (root != 0) { + /* assume pmac unless proven to be chrp -- Cort */ + _machine = _MACH_Pmac; + model = get_property(root, "device_type", NULL); + if (model && !strncmp("chrp", model, 4)) + _machine = _MACH_chrp; + else { + model = get_property(root, "model", NULL); + if (model && !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; + } + } +} +#endif + +#ifdef CONFIG_PPC_MULTIPLATFORM +/* + * The PPC_MULTIPLATFORM version of platform_init... + */ +void __init platform_init(void) +{ + /* if we didn't get any bootinfo telling us what we are... */ + if (_machine == 0) { + /* prep boot loader tells us if we're prep or not */ + if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) + _machine = _MACH_prep; + } + +#ifdef CONFIG_PPC_PREP + /* not much more to do here, if prep */ + if (_machine == _MACH_prep) { + prep_init(); + return; + } +#endif + +#ifdef CONFIG_ADB + if (strstr(cmd_line, "adb_sync")) { + extern int __adb_probe_sync; + __adb_probe_sync = 1; + } +#endif /* CONFIG_ADB */ + + switch (_machine) { +#ifdef CONFIG_PPC_PMAC + case _MACH_Pmac: + pmac_init(); + break; +#endif +#ifdef CONFIG_PPC_CHRP + case _MACH_chrp: + chrp_init(); + break; +#endif + } +} + +#ifdef CONFIG_SERIAL_CORE_CONSOLE +extern char *of_stdout_device; + +static int __init set_preferred_console(void) +{ + struct device_node *prom_stdout; + char *name; + int offset = 0; + + if (of_stdout_device == NULL) + return -ENODEV; + + /* The user has requested a console so this is already set up. */ + if (strstr(saved_command_line, "console=")) + return -EBUSY; + + prom_stdout = find_path_device(of_stdout_device); + if (!prom_stdout) + return -ENODEV; + + name = (char *)get_property(prom_stdout, "name", NULL); + if (!name) + return -ENODEV; + + if (strcmp(name, "serial") == 0) { + int i; + u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); + if (i > 8) { + switch (reg[1]) { + case 0x3f8: + offset = 0; + break; + case 0x2f8: + offset = 1; + break; + case 0x898: + offset = 2; + break; + case 0x890: + offset = 3; + break; + default: + /* We dont recognise the serial port */ + return -ENODEV; + } + } + } else if (strcmp(name, "ch-a") == 0) + offset = 0; + else if (strcmp(name, "ch-b") == 0) + offset = 1; + else + return -ENODEV; + return add_preferred_console("ttyS", offset, NULL); +} +console_initcall(set_preferred_console); +#endif /* CONFIG_SERIAL_CORE_CONSOLE */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +struct bi_record *find_bootinfo(void) +{ + struct bi_record *rec; + + rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); + if ( rec->tag != BI_FIRST ) { + /* + * This 0x10000 offset is a terrible hack but it will go away when + * we have the bootloader handle all the relocation and + * prom calls -- Cort + */ + rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); + if ( rec->tag != BI_FIRST ) + return NULL; + } + return rec; +} + +/* + * Find out what kind of machine we're on and save any data we need + * from the early boot process (devtree is copied on pmac by prom_init()). + * This is called very early on the boot process, after a minimal + * MMU environment has been set up but before MMU_init is called. + */ +void __init machine_init(unsigned long dt_ptr, unsigned long phys) +{ + early_init_devtree(__va(dt_ptr)); + +#ifdef CONFIG_CMDLINE + strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); +#endif /* CONFIG_CMDLINE */ + +#ifdef CONFIG_6xx + ppc_md.power_save = ppc6xx_idle; +#endif +#ifdef CONFIG_POWER4 + ppc_md.power_save = power4_idle; +#endif + + platform_init(); + + if (ppc_md.progress) + ppc_md.progress("id mach(): done", 0x200); +} + +#ifdef CONFIG_BOOKE_WDT +/* Checks wdt=x and wdt_period=xx command-line option */ +int __init early_parse_wdt(char *p) +{ + if (p && strncmp(p, "0", 1) != 0) + booke_wdt_enabled = 1; + + return 0; +} +early_param("wdt", early_parse_wdt); + +int __init early_parse_wdt_period (char *p) +{ + if (p) + booke_wdt_period = simple_strtoul(p, NULL, 0); + + return 0; +} +early_param("wdt_period", early_parse_wdt_period); +#endif /* CONFIG_BOOKE_WDT */ + +/* Checks "l2cr=xxxx" command-line option */ +int __init ppc_setup_l2cr(char *str) +{ + if (cpu_has_feature(CPU_FTR_L2CR)) { + unsigned long val = simple_strtoul(str, NULL, 0); + printk(KERN_INFO "l2cr set to %lx\n", val); + _set_L2CR(0); /* force invalidate by disable cache */ + _set_L2CR(val); /* and enable it */ + } + return 1; +} +__setup("l2cr=", ppc_setup_l2cr); + +#ifdef CONFIG_GENERIC_NVRAM + +/* Generic nvram hooks used by drivers/char/gen_nvram.c */ +unsigned char nvram_read_byte(int addr) +{ + if (ppc_md.nvram_read_val) + return ppc_md.nvram_read_val(addr); + return 0xff; +} +EXPORT_SYMBOL(nvram_read_byte); + +void nvram_write_byte(unsigned char val, int addr) +{ + if (ppc_md.nvram_write_val) + ppc_md.nvram_write_val(addr, val); +} +EXPORT_SYMBOL(nvram_write_byte); + +void nvram_sync(void) +{ + if (ppc_md.nvram_sync) + ppc_md.nvram_sync(); +} +EXPORT_SYMBOL(nvram_sync); + +#endif /* CONFIG_NVRAM */ + +static struct cpu cpu_devices[NR_CPUS]; + +int __init ppc_init(void) +{ + int i; + + /* clear the progress line */ + if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); + + /* register CPU devices */ + for (i = 0; i < NR_CPUS; i++) + if (cpu_possible(i)) + register_cpu(&cpu_devices[i], i, NULL); + + /* call platform init */ + if (ppc_md.init != NULL) { + ppc_md.init(); + } + return 0; +} + +arch_initcall(ppc_init); + +/* Warning, IO base is not yet inited */ +void __init setup_arch(char **cmdline_p) +{ + extern char *klimit; + extern void do_init_bootmem(void); + + /* so udelay does something sensible, assume <= 1000 bogomips */ + loops_per_jiffy = 500000000 / HZ; + +#ifdef CONFIG_BOOTX_TEXT + map_boot_text(); +#endif + + unflatten_device_tree(); + finish_device_tree(); + +#ifdef CONFIG_PPC_MULTIPLATFORM + /* This could be called "early setup arch", it must be done + * now because xmon need it + */ + if (_machine == _MACH_Pmac) + pmac_feature_init(); /* New cool way */ +#endif + +#ifdef CONFIG_XMON + xmon_map_scc(); + if (strstr(cmd_line, "xmon")) + xmon(NULL); +#endif /* CONFIG_XMON */ + if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); + +#if defined(CONFIG_KGDB) + if (ppc_md.kgdb_map_scc) + ppc_md.kgdb_map_scc(); + set_debug_traps(); + if (strstr(cmd_line, "gdb")) { + if (ppc_md.progress) + ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); + printk("kgdb breakpoint activated\n"); + breakpoint(); + } +#endif + + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) + * for a possibly more accurate value. + */ + if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { + dcache_bsize = cur_cpu_spec->dcache_bsize; + icache_bsize = cur_cpu_spec->icache_bsize; + ucache_bsize = 0; + } else + ucache_bsize = dcache_bsize = icache_bsize + = cur_cpu_spec->dcache_bsize; + + /* reboot on panic */ + panic_timeout = 180; + + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) klimit; + + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + *cmdline_p = cmd_line; + + parse_early_param(); + + /* set up the bootmem stuff with available memory */ + do_init_bootmem(); + if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); + +#ifdef CONFIG_PPC_OCP + /* Initialize OCP device list */ + ocp_early_init(); + if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); +#endif + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + ppc_md.setup_arch(); + if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); + + paging_init(); + + /* this is for modules since _machine can be a define -- Cort */ + ppc_md.ppc_machine = _machine; +} diff --git a/arch/powerpc/platforms/powermac/pmac_setup.c b/arch/powerpc/platforms/powermac/pmac_setup.c index 3667e0b2b8e3..1b12bf9956cb 100644 --- a/arch/powerpc/platforms/powermac/pmac_setup.c +++ b/arch/powerpc/platforms/powermac/pmac_setup.c @@ -101,6 +101,8 @@ int ppc_override_l2cr = 0; int ppc_override_l2cr_value; int has_l2cache = 0; +int pmac_newworld = 1; + static int current_root_goodness = -1; extern int pmac_newworld; @@ -355,8 +357,8 @@ static void __init ohare_init(void) } } -extern char *bootpath; -extern char *bootdevice; +char *bootpath; +char *bootdevice; void *boot_host; int boot_target; int boot_part; @@ -391,6 +393,7 @@ note_scsi_host(struct device_node *node, void *host) } } } +EXPORT_SYMBOL(note_scsi_host); #endif #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) @@ -565,9 +568,7 @@ pmac_halt(void) pmac_power_off(); } -void __init -pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +void __init pmac_init(void) { /* isa_io_base gets set in pmac_find_bridges */ isa_mem_base = PMAC_ISA_MEM_BASE; diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 1e50efab091d..a4a50d08d384 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -57,6 +57,9 @@ struct cpu_spec { extern struct cpu_spec *cur_cpu_spec; +extern void identify_cpu(unsigned long offset, unsigned long cpu); +extern void do_cpu_ftr_fixups(unsigned long offset); + #endif /* __ASSEMBLY__ */ /* CPU kernel features */ diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h new file mode 100644 index 000000000000..d096faf4191e --- /dev/null +++ b/include/asm-powerpc/iommu.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * Rewrite, cleanup: + * Copyright (C) 2004 Olof Johansson , 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 + */ + +#ifndef _ASM_IOMMU_H +#define _ASM_IOMMU_H + +#include +#include +#include +#include + +/* + * IOMAP_MAX_ORDER defines the largest contiguous block + * of dma space we can get. IOMAP_MAX_ORDER = 13 + * allows up to 2**12 pages (4096 * 4096) = 16 MB + */ +#define IOMAP_MAX_ORDER 13 + +struct iommu_table { + unsigned long it_busno; /* Bus number this table belongs to */ + unsigned long it_size; /* Size of iommu table in entries */ + unsigned long it_offset; /* Offset into global table */ + unsigned long it_base; /* mapped address of tce table */ + unsigned long it_index; /* which iommu table this is */ + unsigned long it_type; /* type: PCI or Virtual Bus */ + unsigned long it_blocksize; /* Entries in each block (cacheline) */ + unsigned long it_hint; /* Hint for next alloc */ + unsigned long it_largehint; /* Hint for large allocs */ + unsigned long it_halfpoint; /* Breaking point for small/large allocs */ + spinlock_t it_lock; /* Protects it_map */ + unsigned long *it_map; /* A simple allocation bitmap for now */ +}; + +struct scatterlist; +struct device_node; + +#ifdef CONFIG_PPC_MULTIPLATFORM + +/* Walks all buses and creates iommu tables */ +extern void iommu_setup_pSeries(void); +extern void iommu_setup_u3(void); + +/* Frees table for an individual device node */ +extern void iommu_free_table(struct device_node *dn); + +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +#ifdef CONFIG_PPC_PSERIES + +/* Creates table for an individual device node */ +extern void iommu_devnode_init_pSeries(struct device_node *dn); + +#endif /* CONFIG_PPC_PSERIES */ + +#ifdef CONFIG_PPC_ISERIES + +/* Creates table for an individual device node */ +extern void iommu_devnode_init_iSeries(struct device_node *dn); + +#endif /* CONFIG_PPC_ISERIES */ + +/* 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 int iommu_map_sg(struct device *dev, struct iommu_table *tbl, + struct scatterlist *sglist, int nelems, + enum dma_data_direction direction); +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 int __nocast flag); +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, + size_t size, enum dma_data_direction direction); +extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction); + +extern void iommu_init_early_pSeries(void); +extern void iommu_init_early_iSeries(void); +extern void iommu_init_early_u3(void); + +#ifdef CONFIG_PCI +extern void pci_iommu_init(void); +extern void pci_direct_iommu_init(void); +#else +static inline void pci_iommu_init(void) { } +#endif + +extern void alloc_u3_dart_table(void); + +#endif /* _ASM_IOMMU_H */ diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h new file mode 100644 index 000000000000..ea0afe343545 --- /dev/null +++ b/include/asm-powerpc/lmb.h @@ -0,0 +1,81 @@ +#ifndef _PPC64_LMB_H +#define _PPC64_LMB_H + +/* + * Definitions for talking to the Open Firmware PROM on + * Power Macintosh computers. + * + * Copyright (C) 2001 Peter Bergner, 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 + +#define MAX_LMB_REGIONS 128 + +#define LMB_ALLOC_ANYWHERE 0 + +struct lmb_property { + unsigned long base; + unsigned long size; +}; + +struct lmb_region { + unsigned long cnt; + unsigned long size; + struct lmb_property region[MAX_LMB_REGIONS+1]; +}; + +struct lmb { + unsigned long debug; + unsigned long rmo_size; + struct lmb_region memory; + struct lmb_region reserved; +}; + +extern struct lmb lmb; + +extern void __init lmb_init(void); +extern void __init lmb_analyze(void); +extern long __init lmb_add(unsigned long, unsigned long); +extern long __init lmb_reserve(unsigned long, unsigned long); +extern unsigned long __init lmb_alloc(unsigned long, unsigned long); +extern unsigned long __init lmb_alloc_base(unsigned long, unsigned long, + unsigned long); +extern unsigned long __init lmb_phys_mem_size(void); +extern unsigned long __init lmb_end_of_DRAM(void); +extern unsigned long __init lmb_abs_to_phys(unsigned long); +extern void __init lmb_enforce_memory_limit(unsigned long); + +extern void lmb_dump_all(void); + +extern unsigned long io_hole_start; + +static inline unsigned long +lmb_size_bytes(struct lmb_region *type, unsigned long region_nr) +{ + return type->region[region_nr].size; +} +static inline unsigned long +lmb_size_pages(struct lmb_region *type, unsigned long region_nr) +{ + return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT; +} +static inline unsigned long +lmb_start_pfn(struct lmb_region *type, unsigned long region_nr) +{ + return type->region[region_nr].base >> PAGE_SHIFT; +} +static inline unsigned long +lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) +{ + return lmb_start_pfn(type, region_nr) + + lmb_size_pages(type, region_nr); +} + +#endif /* _PPC64_LMB_H */ diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h new file mode 100644 index 000000000000..c0db1ea7f7d1 --- /dev/null +++ b/include/asm-powerpc/pSeries_reconfig.h @@ -0,0 +1,25 @@ +#ifndef _PPC64_PSERIES_RECONFIG_H +#define _PPC64_PSERIES_RECONFIG_H + +#include + +/* + * Use this API if your code needs to know about OF device nodes being + * added or removed on pSeries systems. + */ + +#define PSERIES_RECONFIG_ADD 0x0001 +#define PSERIES_RECONFIG_REMOVE 0x0002 + +#ifdef CONFIG_PPC_PSERIES +extern int pSeries_reconfig_notifier_register(struct notifier_block *); +extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); +#else /* !CONFIG_PPC_PSERIES */ +static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) +{ + return 0; +} +static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } +#endif /* CONFIG_PPC_PSERIES */ + +#endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h new file mode 100644 index 000000000000..194b56ee1693 --- /dev/null +++ b/include/asm-powerpc/prom.h @@ -0,0 +1,215 @@ +#ifndef _POWERPC_PROM_H +#define _POWERPC_PROM_H +#ifdef __KERNEL__ + +/* + * Definitions for talking to the Open Firmware PROM on + * Power Macintosh computers. + * + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Updates for PPC64 by Peter Bergner & David Engebretsen, 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 + +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +/* + * This is what gets passed to the kernel by prom_init or kexec + * + * The dt struct contains the device tree structure, full pathes and + * property contents. The dt strings contain a separate block with just + * the strings for the property names, and is fully page aligned and + * self contained in a page, so that it can be kept around by the kernel, + * each property name appears only once in this page (cheap compression) + * + * the mem_rsvmap contains a map of reserved ranges of physical memory, + * passing it here instead of in the device-tree itself greatly simplifies + * the job of everybody. It's just a list of u64 pairs (base/size) that + * ends when size is 0 + */ +struct boot_param_header +{ + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ +}; + + + +typedef u32 phandle; +typedef u32 ihandle; + +struct address_range { + unsigned long space; + unsigned long address; + unsigned long size; +}; + +struct interrupt_info { + int line; + int sense; /* +ve/-ve logic, edge or level, etc. */ +}; + +struct pci_address { + u32 a_hi; + u32 a_mid; + u32 a_lo; +}; + +struct isa_address { + u32 a_hi; + u32 a_lo; +}; + +struct isa_range { + struct isa_address isa_addr; + struct pci_address pci_addr; + unsigned int size; +}; + +struct reg_property { + unsigned long address; + unsigned long size; +}; + +struct reg_property32 { + unsigned int address; + unsigned int size; +}; + +struct reg_property64 { + unsigned long address; + unsigned long size; +}; + +struct property { + char *name; + int length; + unsigned char *value; + struct property *next; +}; + +struct device_node { + char *name; + char *type; + phandle node; + phandle linux_phandle; + int n_addrs; + struct address_range *addrs; + int n_intrs; + struct interrupt_info *intrs; + char *full_name; + + struct property *properties; + struct device_node *parent; + struct device_node *child; + struct device_node *sibling; + struct device_node *next; /* next device of same type */ + struct device_node *allnext; /* next in list of all nodes */ + struct proc_dir_entry *pde; /* this node's proc directory */ + struct kref kref; + unsigned long _flags; + void *data; +}; + +extern struct device_node *of_chosen; + +/* flag descriptions */ +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ + +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) + +#define HAVE_ARCH_DEVTREE_FIXUPS + +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) +{ + dn->pde = de; +} + + +/* OBSOLETE: Old style node lookup */ +extern struct device_node *find_devices(const char *name); +extern struct device_node *find_type_devices(const char *type); +extern struct device_node *find_path_device(const char *path); +extern struct device_node *find_compatible_devices(const char *type, + const char *compat); +extern struct device_node *find_all_nodes(void); + +/* New style node lookup */ +extern struct device_node *of_find_node_by_name(struct device_node *from, + const char *name); +extern struct device_node *of_find_node_by_type(struct device_node *from, + const char *type); +extern struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compat); +extern struct device_node *of_find_node_by_path(const char *path); +extern struct device_node *of_find_node_by_phandle(phandle handle); +extern struct device_node *of_find_all_nodes(struct device_node *prev); +extern struct device_node *of_get_parent(const struct device_node *node); +extern struct device_node *of_get_next_child(const struct device_node *node, + struct device_node *prev); +extern struct device_node *of_node_get(struct device_node *node); +extern void of_node_put(struct device_node *node); + +/* For updating the device tree at runtime */ +extern void of_attach_node(struct device_node *); +extern void of_detach_node(const struct device_node *); + +/* Other Prototypes */ +extern void finish_device_tree(void); +extern void unflatten_device_tree(void); +extern void early_init_devtree(void *); +extern int device_is_compatible(struct device_node *device, const char *); +extern int machine_is_compatible(const char *compat); +extern unsigned char *get_property(struct device_node *node, const char *name, + int *lenp); +extern void print_properties(struct device_node *node); +extern int prom_n_addr_cells(struct device_node* np); +extern int prom_n_size_cells(struct device_node* np); +extern int prom_n_intr_cells(struct device_node* np); +extern void prom_get_irq_senses(unsigned char *senses, int off, int max); +extern void prom_add_property(struct device_node* np, struct property* prop); + +/* + * PCI <-> OF matching functions + * (XXX should these be here?) + */ +struct pci_bus; +struct pci_dev; +extern int pci_device_from_OF_node(struct device_node *node, + u8* bus, u8* devfn); +extern struct device_node* pci_busdev_to_OF_node(struct pci_bus *, int); +extern struct device_node* pci_device_to_OF_node(struct pci_dev *); +extern void pci_create_OF_bus_map(void); +extern struct resource *request_OF_resource(struct device_node* node, + int index, const char* name_postfix); +extern int release_OF_resource(struct device_node* node, int index); + +#endif /* __KERNEL__ */ +#endif /* _POWERPC_PROM_H */ diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h new file mode 100644 index 000000000000..5c904d371963 --- /dev/null +++ b/include/asm-powerpc/rtas.h @@ -0,0 +1,249 @@ +#ifndef _POWERPC_RTAS_H +#define _POWERPC_RTAS_H + +#include +#include + +/* + * Definitions for talking to the RTAS on CHRP machines. + * + * Copyright (C) 2001 Peter Bergner + * Copyright (C) 2001 PPC 64 Team, 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. + */ + +#define RTAS_UNKNOWN_SERVICE (-1) +#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */ + +/* Buffer size for ppc_rtas system call. */ +#define RTAS_RMOBUF_MAX (64 * 1024) + +/* RTAS return status codes */ +#define RTAS_BUSY -2 /* RTAS Busy */ +#define RTAS_EXTENDED_DELAY_MIN 9900 +#define RTAS_EXTENDED_DELAY_MAX 9905 + +/* + * In general to call RTAS use rtas_token("string") to lookup + * an RTAS token for the given string (e.g. "event-scan"). + * To actually perform the call use + * ret = rtas_call(token, n_in, n_out, ...) + * Where n_in is the number of input parameters and + * n_out is the number of output parameters + * + * If the "string" is invalid on this system, RTAS_UNKNOWN_SERVICE + * will be returned as a token. rtas_call() does look for this + * token and error out gracefully so rtas_call(rtas_token("str"), ...) + * may be safely used for one-shot calls to RTAS. + * + */ + +typedef u32 rtas_arg_t; + +struct rtas_args { + u32 token; + u32 nargs; + u32 nret; + rtas_arg_t args[16]; + rtas_arg_t *rets; /* Pointer to return values in args[]. */ +}; + +extern struct rtas_args rtas_stop_self_args; + +struct rtas_t { + unsigned long entry; /* physical address pointer */ + unsigned long base; /* physical address pointer */ + unsigned long size; + spinlock_t lock; + struct rtas_args args; + struct device_node *dev; /* virtual address pointer */ +}; + +/* RTAS event classes */ +#define RTAS_INTERNAL_ERROR 0x80000000 /* set bit 0 */ +#define RTAS_EPOW_WARNING 0x40000000 /* set bit 1 */ +#define RTAS_POWERMGM_EVENTS 0x20000000 /* set bit 2 */ +#define RTAS_HOTPLUG_EVENTS 0x10000000 /* set bit 3 */ +#define RTAS_EVENT_SCAN_ALL_EVENTS 0xf0000000 + +/* RTAS event severity */ +#define RTAS_SEVERITY_FATAL 0x5 +#define RTAS_SEVERITY_ERROR 0x4 +#define RTAS_SEVERITY_ERROR_SYNC 0x3 +#define RTAS_SEVERITY_WARNING 0x2 +#define RTAS_SEVERITY_EVENT 0x1 +#define RTAS_SEVERITY_NO_ERROR 0x0 + +/* RTAS event disposition */ +#define RTAS_DISP_FULLY_RECOVERED 0x0 +#define RTAS_DISP_LIMITED_RECOVERY 0x1 +#define RTAS_DISP_NOT_RECOVERED 0x2 + +/* RTAS event initiator */ +#define RTAS_INITIATOR_UNKNOWN 0x0 +#define RTAS_INITIATOR_CPU 0x1 +#define RTAS_INITIATOR_PCI 0x2 +#define RTAS_INITIATOR_ISA 0x3 +#define RTAS_INITIATOR_MEMORY 0x4 +#define RTAS_INITIATOR_POWERMGM 0x5 + +/* RTAS event target */ +#define RTAS_TARGET_UNKNOWN 0x0 +#define RTAS_TARGET_CPU 0x1 +#define RTAS_TARGET_PCI 0x2 +#define RTAS_TARGET_ISA 0x3 +#define RTAS_TARGET_MEMORY 0x4 +#define RTAS_TARGET_POWERMGM 0x5 + +/* RTAS event type */ +#define RTAS_TYPE_RETRY 0x01 +#define RTAS_TYPE_TCE_ERR 0x02 +#define RTAS_TYPE_INTERN_DEV_FAIL 0x03 +#define RTAS_TYPE_TIMEOUT 0x04 +#define RTAS_TYPE_DATA_PARITY 0x05 +#define RTAS_TYPE_ADDR_PARITY 0x06 +#define RTAS_TYPE_CACHE_PARITY 0x07 +#define RTAS_TYPE_ADDR_INVALID 0x08 +#define RTAS_TYPE_ECC_UNCORR 0x09 +#define RTAS_TYPE_ECC_CORR 0x0a +#define RTAS_TYPE_EPOW 0x40 +#define RTAS_TYPE_PLATFORM 0xE0 +#define RTAS_TYPE_IO 0xE1 +#define RTAS_TYPE_INFO 0xE2 +#define RTAS_TYPE_DEALLOC 0xE3 +#define RTAS_TYPE_DUMP 0xE4 +/* I don't add PowerMGM events right now, this is a different topic */ +#define RTAS_TYPE_PMGM_POWER_SW_ON 0x60 +#define RTAS_TYPE_PMGM_POWER_SW_OFF 0x61 +#define RTAS_TYPE_PMGM_LID_OPEN 0x62 +#define RTAS_TYPE_PMGM_LID_CLOSE 0x63 +#define RTAS_TYPE_PMGM_SLEEP_BTN 0x64 +#define RTAS_TYPE_PMGM_WAKE_BTN 0x65 +#define RTAS_TYPE_PMGM_BATTERY_WARN 0x66 +#define RTAS_TYPE_PMGM_BATTERY_CRIT 0x67 +#define RTAS_TYPE_PMGM_SWITCH_TO_BAT 0x68 +#define RTAS_TYPE_PMGM_SWITCH_TO_AC 0x69 +#define RTAS_TYPE_PMGM_KBD_OR_MOUSE 0x6a +#define RTAS_TYPE_PMGM_ENCLOS_OPEN 0x6b +#define RTAS_TYPE_PMGM_ENCLOS_CLOSED 0x6c +#define RTAS_TYPE_PMGM_RING_INDICATE 0x6d +#define RTAS_TYPE_PMGM_LAN_ATTENTION 0x6e +#define RTAS_TYPE_PMGM_TIME_ALARM 0x6f +#define RTAS_TYPE_PMGM_CONFIG_CHANGE 0x70 +#define RTAS_TYPE_PMGM_SERVICE_PROC 0x71 + +struct rtas_error_log { + unsigned long version:8; /* Architectural version */ + unsigned long severity:3; /* Severity level of error */ + unsigned long disposition:2; /* Degree of recovery */ + unsigned long extended:1; /* extended log present? */ + unsigned long /* reserved */ :2; /* Reserved for future use */ + unsigned long initiator:4; /* Initiator of event */ + unsigned long target:4; /* Target of failed operation */ + unsigned long type:8; /* General event or error*/ + unsigned long extended_log_length:32; /* length in bytes */ + unsigned char buffer[1]; +}; + +struct flash_block { + char *data; + unsigned long length; +}; + +/* This struct is very similar but not identical to + * that needed by the rtas flash update. + * All we need to do for rtas is rewrite num_blocks + * into a version/length and translate the pointers + * to absolute. + */ +#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block)) +struct flash_block_list { + unsigned long num_blocks; + struct flash_block_list *next; + struct flash_block blocks[FLASH_BLOCKS_PER_NODE]; +}; +struct flash_block_list_header { /* just the header of flash_block_list */ + unsigned long num_blocks; + struct flash_block_list *next; +}; +extern struct flash_block_list_header rtas_firmware_flash_list; + +extern struct rtas_t rtas; + +extern void enter_rtas(unsigned long); +extern int rtas_token(const char *service); +extern int rtas_call(int token, int, int, int *, ...); +extern void call_rtas_display_status(unsigned char); +extern void rtas_restart(char *cmd); +extern void rtas_power_off(void); +extern void rtas_halt(void); +extern void rtas_os_term(char *str); +extern int rtas_get_sensor(int sensor, int index, int *state); +extern int rtas_get_power_level(int powerdomain, int *level); +extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); +extern int rtas_set_indicator(int indicator, int index, int new_value); +extern void rtas_progress(char *s, unsigned short hex); +extern void rtas_initialize(void); + +struct rtc_time; +extern void rtas_get_boot_time(struct rtc_time *rtc_time); +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 void pSeries_log_error(char *buf, unsigned int err_type, int fatal); + +/* Error types logged. */ +#define ERR_FLAG_ALREADY_LOGGED 0x0 +#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ +#define ERR_TYPE_RTAS_LOG 0x2 /* from rtas event-scan */ +#define ERR_TYPE_KERNEL_PANIC 0x4 /* from panic() */ + +/* All the types and not flags */ +#define ERR_TYPE_MASK (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC) + +#define RTAS_DEBUG KERN_DEBUG "RTAS: " + +#define RTAS_ERROR_LOG_MAX 2048 + +/* + * Return the firmware-specified size of the error log buffer + * for all rtas calls that require an error buffer argument. + * This includes 'check-exception' and 'rtas-last-error'. + */ +extern int rtas_get_error_log_max(void); + +/* Event Scan Parameters */ +#define EVENT_SCAN_ALL_EVENTS 0xf0000000 +#define SURVEILLANCE_TOKEN 9000 +#define LOG_NUMBER 64 /* must be a power of two */ +#define LOG_NUMBER_MASK (LOG_NUMBER-1) + +/* Some RTAS ops require a data buffer and that buffer must be < 4G. + * Rather than having a memory allocator, just use this buffer + * (get the lock first), make the RTAS call. Copy the data instead + * of holding the buffer for long. + */ + +#define RTAS_DATA_BUF_SIZE 4096 +extern spinlock_t rtas_data_buf_lock; +extern char rtas_data_buf[RTAS_DATA_BUF_SIZE]; + +extern void rtas_stop_self(void); + +/* RMO buffer reserved for user-space RTAS use */ +extern unsigned long rtas_rmo_buf; + +#define GLOBAL_INTERRUPT_QUEUE 9005 + +#endif /* _POWERPC_RTAS_H */ diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 027479dcbf43..66866f7301a9 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -346,7 +346,12 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, #define arch_align_stack(x) (x) +/* Used in very early kernel initialization. */ extern unsigned long reloc_offset(void); +extern unsigned long add_reloc_offset(unsigned long); +extern void reloc_got2(unsigned long); + +#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x))) #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYSTEM_H */ From 7c8c6b9776fb41134d87ef50706a777a45d61cd4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 12:23:33 +1000 Subject: [PATCH 0310/1939] powerpc: Merge lmb.c and make MM initialization use it. This also creates merged versions of do_init_bootmem, paging_init and mem_init and moves them to arch/powerpc/mm/mem.c. It gets rid of the mem_pieces stuff. I made memory_limit a parameter to lmb_enforce_memory_limit rather than a global referenced by that function. This will require some small changes to ppc64 if we want to continue building ARCH=ppc64 using the merged lmb.c. Signed-off-by: Paul Mackerras --- arch/powerpc/mm/Makefile | 4 +- arch/powerpc/mm/init.c | 363 ++--------------------------------- arch/powerpc/mm/init64.c | 126 ------------ arch/powerpc/mm/lmb.c | 296 ++++++++++++++++++++++++++++ arch/powerpc/mm/mem.c | 185 +++++++++++++++++- arch/powerpc/mm/mem_pieces.c | 163 ---------------- arch/powerpc/mm/mem_pieces.h | 48 ----- arch/powerpc/mm/mmu_decl.h | 2 + arch/powerpc/mm/pgtable.c | 3 +- arch/powerpc/mm/ppc_mmu.c | 17 +- include/asm-ppc/page.h | 18 +- 11 files changed, 519 insertions(+), 706 deletions(-) create mode 100644 arch/powerpc/mm/lmb.c delete mode 100644 arch/powerpc/mm/mem_pieces.c delete mode 100644 arch/powerpc/mm/mem_pieces.h diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 9f52c26acd86..afd3be112b79 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -2,9 +2,9 @@ # Makefile for the linux ppc-specific parts of the memory manager. # -obj-y := fault.o mem.o +obj-y := fault.o mem.o lmb.o obj-$(CONFIG_PPC32) += init.o pgtable.o mmu_context.o \ - mem_pieces.o tlb.o + tlb.o obj-$(CONFIG_PPC64) += init64.o pgtable64.o mmu_context64.o obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu.o hash_32.o obj-$(CONFIG_40x) += 4xx_mmu.o diff --git a/arch/powerpc/mm/init.c b/arch/powerpc/mm/init.c index 3a81ef15c67e..bf13c14e66b3 100644 --- a/arch/powerpc/mm/init.c +++ b/arch/powerpc/mm/init.c @@ -45,8 +45,9 @@ #include #include #include +#include +#include -#include "mem_pieces.h" #include "mmu_decl.h" #if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL) @@ -65,17 +66,11 @@ unsigned long total_lowmem; unsigned long ppc_memstart; unsigned long ppc_memoffset = PAGE_OFFSET; -int mem_init_done; -int init_bootmem_done; int boot_mapsize; #ifdef CONFIG_PPC_PMAC unsigned long agp_special_page; #endif -extern char _end[]; -extern char etext[], _stext[]; -extern char __init_begin, __init_end; - #ifdef CONFIG_HIGHMEM pte_t *kmap_pte; pgprot_t kmap_prot; @@ -85,15 +80,15 @@ EXPORT_SYMBOL(kmap_pte); #endif void MMU_init(void); -void set_phys_avail(unsigned long total_ram); /* XXX should be in current.h -- paulus */ extern struct task_struct *current_set[NR_CPUS]; char *klimit = _end; -struct mem_pieces phys_avail; struct device_node *memory_node; +extern int init_bootmem_done; + /* * this tells the system to map all of ram with the segregs * (i.e. page tables) instead of the bats. @@ -102,84 +97,14 @@ struct device_node *memory_node; int __map_without_bats; int __map_without_ltlbs; -/* max amount of RAM to use */ -unsigned long __max_memory; /* max amount of low RAM to map in */ unsigned long __max_low_memory = MAX_LOW_MEM; /* - * Read in a property describing some pieces of memory. + * limit of what is accessible with initial MMU setup - + * 256MB usually, but only 16MB on 601. */ -static int __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int i, s; - unsigned int *ip; - int nac = prom_n_addr_cells(memory_node); - int nsc = prom_n_size_cells(memory_node); - - ip = (unsigned int *) get_property(memory_node, name, &s); - if (ip == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - return 0; - } - s /= (nsc + nac) * 4; - rp = mp->regions; - for (i = 0; i < s; ++i, ip += nac+nsc) { - if (nac >= 2 && ip[nac-2] != 0) - continue; - rp->address = ip[nac-1]; - if (nsc >= 2 && ip[nac+nsc-2] != 0) - rp->size = ~0U; - else - rp->size = ip[nac+nsc-1]; - ++rp; - } - mp->n_regions = rp - mp->regions; - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); - return 1; -} - -/* - * Collect information about physical RAM and which pieces are - * already in use from the device tree. - */ -unsigned long __init find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - memory_node = find_devices("memory"); - if (memory_node == NULL || !get_mem_prop("reg", &phys_mem) - || phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} +unsigned long __initial_memory_limit = 0x10000000; /* * Check for command-line options that affect what MMU_init will do. @@ -194,27 +119,6 @@ void MMU_setup(void) if (strstr(cmd_line, "noltlbs")) { __map_without_ltlbs = 1; } - - /* Look for mem= option on command line */ - if (strstr(cmd_line, "mem=")) { - char *p, *q; - unsigned long maxmem = 0; - - for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { - q = p + 4; - if (p > cmd_line && p[-1] != ' ') - continue; - maxmem = simple_strtoul(q, &q, 0); - if (*q == 'k' || *q == 'K') { - maxmem <<= 10; - ++q; - } else if (*q == 'm' || *q == 'M') { - maxmem <<= 20; - ++q; - } - } - __max_memory = maxmem; - } } /* @@ -227,23 +131,22 @@ void __init MMU_init(void) if (ppc_md.progress) ppc_md.progress("MMU:enter", 0x111); + /* 601 can only access 16MB at the moment */ + if (PVR_VER(mfspr(SPRN_PVR)) == 1) + __initial_memory_limit = 0x01000000; + /* parse args from command line */ MMU_setup(); - /* - * Figure out how much memory we have, how much - * is lowmem, and how much is highmem. If we were - * passed the total memory size from the bootloader, - * just use it. - */ - if (boot_mem_size) - total_memory = boot_mem_size; - else - total_memory = find_end_of_memory(); + if (lmb.memory.cnt > 1) { + lmb.memory.cnt = 1; + lmb_analyze(); + printk(KERN_WARNING "Only using first contiguous memory region"); + } - if (__max_memory && total_memory > __max_memory) - total_memory = __max_memory; + total_memory = lmb_end_of_DRAM(); total_lowmem = total_memory; + #ifdef CONFIG_FSL_BOOKE /* Freescale Book-E parts expect lowmem to be mapped by fixed TLB * entries, so we need to adjust lowmem to match the amount we can map @@ -256,7 +159,6 @@ void __init MMU_init(void) total_memory = total_lowmem; #endif /* CONFIG_HIGHMEM */ } - set_phys_avail(total_lowmem); /* Initialize the MMU hardware */ if (ppc_md.progress) @@ -303,7 +205,8 @@ void __init *early_get_page(void) if (init_bootmem_done) { p = alloc_bootmem_pages(PAGE_SIZE); } else { - p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE); + p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE, + __initial_memory_limit)); } return p; } @@ -353,229 +256,3 @@ void free_initrd_mem(unsigned long start, unsigned long end) } } #endif - -/* - * Initialize the bootmem system and give it all the memory we - * have available. - */ -void __init do_init_bootmem(void) -{ - unsigned long start, size; - int i; - - /* - * Find an area to use for the bootmem bitmap. - * We look for the first area which is at least - * 128kB in length (128kB is enough for a bitmap - * for 4GB of memory, using 4kB pages), plus 1 page - * (in case the address isn't page-aligned). - */ - start = 0; - size = 0; - for (i = 0; i < phys_avail.n_regions; ++i) { - unsigned long a = phys_avail.regions[i].address; - unsigned long s = phys_avail.regions[i].size; - if (s <= size) - continue; - start = a; - size = s; - if (s >= 33 * PAGE_SIZE) - break; - } - start = PAGE_ALIGN(start); - - min_low_pfn = start >> PAGE_SHIFT; - max_low_pfn = (PPC_MEMSTART + total_lowmem) >> PAGE_SHIFT; - max_pfn = (PPC_MEMSTART + total_memory) >> PAGE_SHIFT; - boot_mapsize = init_bootmem_node(&contig_page_data, min_low_pfn, - PPC_MEMSTART >> PAGE_SHIFT, - max_low_pfn); - - /* remove the bootmem bitmap from the available memory */ - mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); - - /* add everything in phys_avail into the bootmem map */ - for (i = 0; i < phys_avail.n_regions; ++i) - free_bootmem(phys_avail.regions[i].address, - phys_avail.regions[i].size); - - init_bootmem_done = 1; -} - -/* - * paging_init() sets up the page tables - in fact we've already done this. - */ -void __init paging_init(void) -{ - unsigned long zones_size[MAX_NR_ZONES], i; - -#ifdef CONFIG_HIGHMEM - map_page(PKMAP_BASE, 0, 0); /* XXX gross */ - pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k - (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); - map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ - kmap_pte = pte_offset_kernel(pmd_offset(pgd_offset_k - (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); - kmap_prot = PAGE_KERNEL; -#endif /* CONFIG_HIGHMEM */ - - /* - * All pages are DMA-able so we put them all in the DMA zone. - */ - zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; - for (i = 1; i < MAX_NR_ZONES; i++) - zones_size[i] = 0; - -#ifdef CONFIG_HIGHMEM - zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; -#endif /* CONFIG_HIGHMEM */ - - free_area_init(zones_size); -} - -void __init mem_init(void) -{ - unsigned long addr; - int codepages = 0; - int datapages = 0; - int initpages = 0; -#ifdef CONFIG_HIGHMEM - unsigned long highmem_mapnr; - - highmem_mapnr = total_lowmem >> PAGE_SHIFT; -#endif /* CONFIG_HIGHMEM */ - max_mapnr = total_memory >> PAGE_SHIFT; - - high_memory = (void *) __va(PPC_MEMSTART + total_lowmem); - num_physpages = max_mapnr; /* RAM is assumed contiguous */ - - totalram_pages += free_all_bootmem(); - -#ifdef CONFIG_BLK_DEV_INITRD - /* if we are booted from BootX with an initial ramdisk, - make sure the ramdisk pages aren't reserved. */ - if (initrd_start) { - for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE) - ClearPageReserved(virt_to_page(addr)); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - -#ifdef CONFIG_PPC_OF - /* mark the RTAS pages as reserved */ - if ( rtas_data ) - for (addr = (ulong)__va(rtas_data); - addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; - addr += PAGE_SIZE) - SetPageReserved(virt_to_page(addr)); -#endif -#ifdef CONFIG_PPC_PMAC - if (agp_special_page) - SetPageReserved(virt_to_page(agp_special_page)); -#endif - for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory; - addr += PAGE_SIZE) { - if (!PageReserved(virt_to_page(addr))) - continue; - if (addr < (ulong) etext) - codepages++; - else if (addr >= (unsigned long)&__init_begin - && addr < (unsigned long)&__init_end) - initpages++; - else if (addr < (ulong) klimit) - datapages++; - } - -#ifdef CONFIG_HIGHMEM - { - unsigned long pfn; - - for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { - struct page *page = mem_map + pfn; - - ClearPageReserved(page); - set_page_count(page, 1); - __free_page(page); - totalhigh_pages++; - } - totalram_pages += totalhigh_pages; - } -#endif /* CONFIG_HIGHMEM */ - - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", - (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), - initpages<< (PAGE_SHIFT-10), - (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); - -#ifdef CONFIG_PPC_PMAC - if (agp_special_page) - printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); -#endif - - mem_init_done = 1; -} - -/* - * Set phys_avail to the amount of physical memory, - * less the kernel text/data/bss. - */ -void __init -set_phys_avail(unsigned long total_memory) -{ - unsigned long kstart, ksize; - - /* - * Initially, available physical memory is equivalent to all - * physical memory. - */ - - phys_avail.regions[0].address = PPC_MEMSTART; - phys_avail.regions[0].size = total_memory; - phys_avail.n_regions = 1; - - /* - * Map out the kernel text/data/bss from the available physical - * memory. - */ - - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(klimit - _stext); - - mem_pieces_remove(&phys_avail, kstart, ksize, 0); - mem_pieces_remove(&phys_avail, 0, 0x4000, 0); - -#if defined(CONFIG_BLK_DEV_INITRD) - /* Remove the init RAM disk from the available memory. */ - if (initrd_start) { - mem_pieces_remove(&phys_avail, __pa(initrd_start), - initrd_end - initrd_start, 1); - } -#endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_PPC_OF - /* remove the RTAS pages from the available memory */ - if (rtas_data) - mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); -#endif -#ifdef CONFIG_PPC_PMAC - /* Because of some uninorth weirdness, we need a page of - * memory as high as possible (it must be outside of the - * bus address seen as the AGP aperture). It will be used - * by the r128 DRM driver - * - * FIXME: We need to make sure that page doesn't overlap any of the\ - * above. This could be done by improving mem_pieces_find to be able - * to do a backward search from the end of the list. - */ - if (_machine == _MACH_Pmac && find_devices("uni-north-agp")) { - agp_special_page = (total_memory - PAGE_SIZE); - mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0); - agp_special_page = (unsigned long)__va(agp_special_page); - } -#endif /* CONFIG_PPC_PMAC */ -} - -/* Mark some memory as reserved by removing it from phys_avail. */ -void __init reserve_phys_mem(unsigned long start, unsigned long size) -{ - mem_pieces_remove(&phys_avail, start, size, 1); -} diff --git a/arch/powerpc/mm/init64.c b/arch/powerpc/mm/init64.c index 81f6745b31ef..c0ce6a7af3c7 100644 --- a/arch/powerpc/mm/init64.c +++ b/arch/powerpc/mm/init64.c @@ -166,77 +166,6 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif -/* - * Initialize the bootmem system and give it all the memory we - * have available. - */ -#ifndef CONFIG_NEED_MULTIPLE_NODES -void __init do_init_bootmem(void) -{ - unsigned long i; - unsigned long start, bootmap_pages; - unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; - int boot_mapsize; - - /* - * Find an area to use for the bootmem bitmap. Calculate the size of - * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE. - * Add 1 additional page in case the address isn't page-aligned. - */ - bootmap_pages = bootmem_bootmap_pages(total_pages); - - start = lmb_alloc(bootmap_pages<> PAGE_SHIFT, total_pages); - - max_pfn = max_low_pfn; - - /* Add all physical memory to the bootmem map, mark each area - * present. - */ - for (i=0; i < lmb.memory.cnt; i++) - free_bootmem(lmb.memory.region[i].base, - lmb_size_bytes(&lmb.memory, i)); - - /* reserve the sections we're already using */ - for (i=0; i < lmb.reserved.cnt; i++) - reserve_bootmem(lmb.reserved.region[i].base, - lmb_size_bytes(&lmb.reserved, i)); - - for (i=0; i < lmb.memory.cnt; i++) - memory_present(0, lmb_start_pfn(&lmb.memory, i), - lmb_end_pfn(&lmb.memory, i)); -} - -/* - * paging_init() sets up the page tables - in fact we've already done this. - */ -void __init paging_init(void) -{ - unsigned long zones_size[MAX_NR_ZONES]; - unsigned long zholes_size[MAX_NR_ZONES]; - unsigned long total_ram = lmb_phys_mem_size(); - unsigned long top_of_ram = lmb_end_of_DRAM(); - - printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", - top_of_ram, total_ram); - printk(KERN_INFO "Memory hole size: %ldMB\n", - (top_of_ram - total_ram) >> 20); - /* - * All pages are DMA-able so we put them all in the DMA zone. - */ - memset(zones_size, 0, sizeof(zones_size)); - memset(zholes_size, 0, sizeof(zholes_size)); - - zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; - zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; - - free_area_init_node(0, NODE_DATA(0), zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); -} -#endif /* ! CONFIG_NEED_MULTIPLE_NODES */ - static struct kcore_list kcore_vmem; static int __init setup_kcore(void) @@ -264,61 +193,6 @@ static int __init setup_kcore(void) } module_init(setup_kcore); -void __init mem_init(void) -{ -#ifdef CONFIG_NEED_MULTIPLE_NODES - int nid; -#endif - pg_data_t *pgdat; - unsigned long i; - struct page *page; - unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; - - num_physpages = max_low_pfn; /* RAM is assumed contiguous */ - high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); - -#ifdef CONFIG_NEED_MULTIPLE_NODES - for_each_online_node(nid) { - if (NODE_DATA(nid)->node_spanned_pages != 0) { - printk("freeing bootmem node %x\n", nid); - totalram_pages += - free_all_bootmem_node(NODE_DATA(nid)); - } - } -#else - max_mapnr = num_physpages; - totalram_pages += free_all_bootmem(); -#endif - - for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_spanned_pages; i++) { - page = pgdat_page_nr(pgdat, i); - if (PageReserved(page)) - reservedpages++; - } - } - - codesize = (unsigned long)&_etext - (unsigned long)&_stext; - initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; - datasize = (unsigned long)&_edata - (unsigned long)&__init_end; - bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; - - printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " - "%luk reserved, %luk data, %luk bss, %luk init)\n", - (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), - num_physpages << (PAGE_SHIFT-10), - codesize >> 10, - reservedpages << (PAGE_SHIFT-10), - datasize >> 10, - bsssize >> 10, - initsize >> 10); - - mem_init_done = 1; - - /* Initialize the vDSO */ - vdso_init(); -} - void __iomem * reserve_phb_iospace(unsigned long size) { void __iomem *virt_addr; diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c new file mode 100644 index 000000000000..9b5aa6808eb8 --- /dev/null +++ b/arch/powerpc/mm/lmb.c @@ -0,0 +1,296 @@ +/* + * Procedures for maintaining information about logical memory blocks. + * + * Peter Bergner, IBM Corp. June 2001. + * Copyright (C) 2001 Peter Bergner. + * + * 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 +#ifdef CONFIG_PPC32 +#include "mmu_decl.h" /* for __max_low_memory */ +#endif + +struct lmb lmb; + +#undef DEBUG + +void lmb_dump_all(void) +{ +#ifdef DEBUG + unsigned long i; + + udbg_printf("lmb_dump_all:\n"); + udbg_printf(" memory.cnt = 0x%lx\n", + lmb.memory.cnt); + udbg_printf(" memory.size = 0x%lx\n", + lmb.memory.size); + for (i=0; i < lmb.memory.cnt ;i++) { + udbg_printf(" memory.region[0x%x].base = 0x%lx\n", + i, lmb.memory.region[i].base); + udbg_printf(" .size = 0x%lx\n", + lmb.memory.region[i].size); + } + + udbg_printf("\n reserved.cnt = 0x%lx\n", + lmb.reserved.cnt); + udbg_printf(" reserved.size = 0x%lx\n", + lmb.reserved.size); + for (i=0; i < lmb.reserved.cnt ;i++) { + udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", + i, lmb.reserved.region[i].base); + udbg_printf(" .size = 0x%lx\n", + lmb.reserved.region[i].size); + } +#endif /* DEBUG */ +} + +static unsigned long __init lmb_addrs_overlap(unsigned long base1, + unsigned long size1, unsigned long base2, unsigned long size2) +{ + return ((base1 < (base2+size2)) && (base2 < (base1+size1))); +} + +static long __init lmb_addrs_adjacent(unsigned long base1, unsigned long size1, + unsigned long base2, unsigned long size2) +{ + if (base2 == base1 + size1) + return 1; + else if (base1 == base2 + size2) + return -1; + + return 0; +} + +static long __init lmb_regions_adjacent(struct lmb_region *rgn, + unsigned long r1, unsigned long r2) +{ + unsigned long base1 = rgn->region[r1].base; + unsigned long size1 = rgn->region[r1].size; + unsigned long base2 = rgn->region[r2].base; + unsigned long size2 = rgn->region[r2].size; + + 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) +{ + 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; + } + rgn->cnt--; +} + +/* This routine called with relocation disabled. */ +void __init lmb_init(void) +{ + /* Create a dummy zero size LMB which will get coalesced away later. + * This simplifies the lmb_add() code below... + */ + lmb.memory.region[0].base = 0; + lmb.memory.region[0].size = 0; + lmb.memory.cnt = 1; + + /* Ditto. */ + lmb.reserved.region[0].base = 0; + lmb.reserved.region[0].size = 0; + lmb.reserved.cnt = 1; +} + +/* This routine may be called with relocation disabled. */ +void __init lmb_analyze(void) +{ + int i; + + lmb.memory.size = 0; + + for (i = 0; i < lmb.memory.cnt; i++) + lmb.memory.size += lmb.memory.region[i].size; +} + +/* This routine called with relocation disabled. */ +static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base, + unsigned long size) +{ + unsigned long i, coalesced = 0; + long adjacent; + + /* First try and coalesce this LMB with another. */ + for (i=0; i < rgn->cnt; i++) { + unsigned long rgnbase = rgn->region[i].base; + unsigned long rgnsize = rgn->region[i].size; + + adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); + if ( adjacent > 0 ) { + rgn->region[i].base -= size; + rgn->region[i].size += size; + coalesced++; + break; + } + else if ( adjacent < 0 ) { + rgn->region[i].size += size; + coalesced++; + break; + } + } + + if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { + lmb_coalesce_regions(rgn, i, i+1); + coalesced++; + } + + if (coalesced) + return coalesced; + if (rgn->cnt >= MAX_LMB_REGIONS) + return -1; + + /* Couldn't coalesce the LMB, so add it to the sorted table. */ + for (i = rgn->cnt-1; i >= 0; i--) { + if (base < rgn->region[i].base) { + rgn->region[i+1].base = rgn->region[i].base; + rgn->region[i+1].size = rgn->region[i].size; + } else { + rgn->region[i+1].base = base; + rgn->region[i+1].size = size; + break; + } + } + rgn->cnt++; + + return 0; +} + +/* This routine may be called with relocation disabled. */ +long __init lmb_add(unsigned long base, unsigned long size) +{ + struct lmb_region *_rgn = &(lmb.memory); + + /* On pSeries LPAR systems, the first LMB is our RMO region. */ + if (base == 0) + lmb.rmo_size = size; + + return lmb_add_region(_rgn, base, size); + +} + +long __init lmb_reserve(unsigned long base, unsigned long size) +{ + struct lmb_region *_rgn = &(lmb.reserved); + + return lmb_add_region(_rgn, base, size); +} + +long __init lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, + unsigned long size) +{ + unsigned long i; + + for (i=0; i < rgn->cnt; i++) { + unsigned long rgnbase = rgn->region[i].base; + unsigned long rgnsize = rgn->region[i].size; + if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { + break; + } + } + + return (i < rgn->cnt) ? i : -1; +} + +unsigned long __init lmb_alloc(unsigned long size, unsigned long align) +{ + return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); +} + +unsigned long __init lmb_alloc_base(unsigned long size, unsigned long align, + unsigned long max_addr) +{ + long i, j; + unsigned long base = 0; + +#ifdef CONFIG_PPC32 + /* On 32-bit, make sure we allocate lowmem */ + if (max_addr == LMB_ALLOC_ANYWHERE) + max_addr = __max_low_memory; +#endif + for (i = lmb.memory.cnt-1; i >= 0; i--) { + unsigned long lmbbase = lmb.memory.region[i].base; + unsigned long lmbsize = lmb.memory.region[i].size; + + if (max_addr == LMB_ALLOC_ANYWHERE) + base = _ALIGN_DOWN(lmbbase + lmbsize - size, align); + else if (lmbbase < max_addr) { + base = min(lmbbase + lmbsize, max_addr); + base = _ALIGN_DOWN(base - size, align); + } else + continue; + + while ((lmbbase <= base) && + ((j = lmb_overlaps_region(&lmb.reserved, base, size)) >= 0) ) + base = _ALIGN_DOWN(lmb.reserved.region[j].base - size, + align); + + if ((base != 0) && (lmbbase <= base)) + break; + } + + if (i < 0) + return 0; + + lmb_add_region(&lmb.reserved, base, size); + + return base; +} + +/* You must call lmb_analyze() before this. */ +unsigned long __init lmb_phys_mem_size(void) +{ + return lmb.memory.size; +} + +unsigned long __init lmb_end_of_DRAM(void) +{ + int idx = lmb.memory.cnt - 1; + + 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. + */ +void __init lmb_enforce_memory_limit(unsigned long memory_limit) +{ + unsigned long i, limit; + + if (! memory_limit) + return; + + limit = memory_limit; + for (i = 0; i < lmb.memory.cnt; i++) { + if (limit > lmb.memory.region[i].size) { + limit -= lmb.memory.region[i].size; + continue; + } + + lmb.memory.region[i].size = limit; + lmb.memory.cnt = i + 1; + break; + } +} diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 345db08e5d20..0650de74d0b3 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -45,8 +45,9 @@ #include #include #include +#include +#include -#include "mem_pieces.h" #include "mmu_decl.h" #ifndef CPU_FTR_COHERENT_ICACHE @@ -54,6 +55,9 @@ #define CPU_FTR_NOEXECUTE 0 #endif +int init_bootmem_done; +int mem_init_done; + /* * This is called by /dev/mem to know if a given address has to * be mapped non-cacheable or not @@ -130,6 +134,185 @@ void show_mem(void) printk("%ld pages swap cached\n", cached); } +/* + * Initialize the bootmem system and give it all the memory we + * have available. If we are using highmem, we only put the + * lowmem into the bootmem system. + */ +#ifndef CONFIG_NEED_MULTIPLE_NODES +void __init do_init_bootmem(void) +{ + unsigned long i; + unsigned long start, bootmap_pages; + unsigned long total_pages; + int boot_mapsize; + + max_pfn = total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; +#ifdef CONFIG_HIGHMEM + total_pages = total_lowmem >> PAGE_SHIFT; +#endif + + /* + * Find an area to use for the bootmem bitmap. Calculate the size of + * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE. + * Add 1 additional page in case the address isn't page-aligned. + */ + bootmap_pages = bootmem_bootmap_pages(total_pages); + + start = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE); + BUG_ON(!start); + + boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages); + + /* Add all physical memory to the bootmem map, mark each area + * present. + */ + for (i = 0; i < lmb.memory.cnt; i++) { + unsigned long base = lmb.memory.region[i].base; + unsigned long size = lmb_size_bytes(&lmb.memory, i); +#ifdef CONFIG_HIGHMEM + if (base >= total_lowmem) + continue; + if (base + size > total_lowmem) + size = total_lowmem - base; +#endif + free_bootmem(base, size); + } + + /* reserve the sections we're already using */ + for (i = 0; i < lmb.reserved.cnt; i++) + reserve_bootmem(lmb.reserved.region[i].base, + lmb_size_bytes(&lmb.reserved, i)); + + /* XXX need to clip this if using highmem? */ + for (i = 0; i < lmb.memory.cnt; i++) + memory_present(0, lmb_start_pfn(&lmb.memory, i), + lmb_end_pfn(&lmb.memory, i)); + init_bootmem_done = 1; +} + +/* + * paging_init() sets up the page tables - in fact we've already done this. + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long total_ram = lmb_phys_mem_size(); + unsigned long top_of_ram = lmb_end_of_DRAM(); + +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k + (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset_kernel(pmd_offset(pgd_offset_k + (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + + printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", + top_of_ram, total_ram); + printk(KERN_INFO "Memory hole size: %ldMB\n", + (top_of_ram - total_ram) >> 20); + /* + * All pages are DMA-able so we put them all in the DMA zone. + */ + memset(zones_size, 0, sizeof(zones_size)); + memset(zholes_size, 0, sizeof(zholes_size)); + + zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; + zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; + zholes_size[ZONE_HIGHMEM] = (top_of_ram - total_ram) >> PAGE_SHIFT; +#else + zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; + zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + + free_area_init_node(0, NODE_DATA(0), zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); +} +#endif /* ! CONFIG_NEED_MULTIPLE_NODES */ + +void __init mem_init(void) +{ +#ifdef CONFIG_NEED_MULTIPLE_NODES + int nid; +#endif + pg_data_t *pgdat; + unsigned long i; + struct page *page; + unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; + + num_physpages = max_pfn; /* RAM is assumed contiguous */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); + +#ifdef CONFIG_NEED_MULTIPLE_NODES + for_each_online_node(nid) { + if (NODE_DATA(nid)->node_spanned_pages != 0) { + printk("freeing bootmem node %x\n", nid); + totalram_pages += + free_all_bootmem_node(NODE_DATA(nid)); + } + } +#else + max_mapnr = num_physpages; + totalram_pages += free_all_bootmem(); +#endif + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + page = pgdat_page_nr(pgdat, i); + if (PageReserved(page)) + reservedpages++; + } + } + + codesize = (unsigned long)&_sdata - (unsigned long)&_stext; + datasize = (unsigned long)&__init_begin - (unsigned long)&_sdata; + initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; + bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; + +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn, highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = pfn_to_page(pfn); + + ClearPageReserved(page); + set_page_count(page, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + printk(KERN_INFO "High memory: %luk\n", + totalhigh_pages << (PAGE_SHIFT-10)); + } +#endif /* CONFIG_HIGHMEM */ + + printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " + "%luk reserved, %luk data, %luk bss, %luk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + bsssize >> 10, + initsize >> 10); + + mem_init_done = 1; + +#ifdef CONFIG_PPC64 + /* Initialize the vDSO */ + vdso_init(); +#endif +} + /* * This is called when a page has been modified by the kernel. * It just marks the page as not i-cache clean. We do the i-cache diff --git a/arch/powerpc/mm/mem_pieces.c b/arch/powerpc/mm/mem_pieces.c deleted file mode 100644 index 3d639052017e..000000000000 --- a/arch/powerpc/mm/mem_pieces.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 1996 Paul Mackerras - * Changes to accommodate Power Macintoshes. - * Cort Dougan - * Rewrites. - * Grant Erickson - * General rework and split from mm/init.c. - * - * Module name: mem_pieces.c - * - * Description: - * Routines and data structures for manipulating and representing - * phyiscal memory extents (i.e. address/length pairs). - * - */ - -#include -#include -#include -#include -#include - -#include "mem_pieces.h" - -extern struct mem_pieces phys_avail; - -static void mem_pieces_print(struct mem_pieces *); - -/* - * Scan a region for a piece of a given size with the required alignment. - */ -void __init * -mem_pieces_find(unsigned int size, unsigned int align) -{ - int i; - unsigned a, e; - struct mem_pieces *mp = &phys_avail; - - for (i = 0; i < mp->n_regions; ++i) { - a = mp->regions[i].address; - e = a + mp->regions[i].size; - a = (a + align - 1) & -align; - if (a + size <= e) { - mem_pieces_remove(mp, a, size, 1); - return (void *) __va(a); - } - } - panic("Couldn't find %u bytes at %u alignment\n", size, align); - - return NULL; -} - -/* - * Remove some memory from an array of pieces - */ -void __init -mem_pieces_remove(struct mem_pieces *mp, unsigned int start, unsigned int size, - int must_exist) -{ - int i, j; - unsigned int end, rs, re; - struct reg_property *rp; - - end = start + size; - for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) { - if (end > rp->address && start < rp->address + rp->size) - break; - } - if (i >= mp->n_regions) { - if (must_exist) - printk("mem_pieces_remove: [%x,%x) not in any region\n", - start, end); - return; - } - for (; i < mp->n_regions && end > rp->address; ++i, ++rp) { - rs = rp->address; - re = rs + rp->size; - if (must_exist && (start < rs || end > re)) { - printk("mem_pieces_remove: bad overlap [%x,%x) with", - start, end); - mem_pieces_print(mp); - must_exist = 0; - } - if (start > rs) { - rp->size = start - rs; - if (end < re) { - /* need to split this entry */ - if (mp->n_regions >= MEM_PIECES_MAX) - panic("eek... mem_pieces overflow"); - for (j = mp->n_regions; j > i + 1; --j) - mp->regions[j] = mp->regions[j-1]; - ++mp->n_regions; - rp[1].address = end; - rp[1].size = re - end; - } - } else { - if (end < re) { - rp->address = end; - rp->size = re - end; - } else { - /* need to delete this entry */ - for (j = i; j < mp->n_regions - 1; ++j) - mp->regions[j] = mp->regions[j+1]; - --mp->n_regions; - --i; - --rp; - } - } - } -} - -static void __init -mem_pieces_print(struct mem_pieces *mp) -{ - int i; - - for (i = 0; i < mp->n_regions; ++i) - printk(" [%x, %x)", mp->regions[i].address, - mp->regions[i].address + mp->regions[i].size); - printk("\n"); -} - -void __init -mem_pieces_sort(struct mem_pieces *mp) -{ - unsigned long a, s; - int i, j; - - for (i = 1; i < mp->n_regions; ++i) { - a = mp->regions[i].address; - s = mp->regions[i].size; - for (j = i - 1; j >= 0; --j) { - if (a >= mp->regions[j].address) - break; - mp->regions[j+1] = mp->regions[j]; - } - mp->regions[j+1].address = a; - mp->regions[j+1].size = s; - } -} - -void __init -mem_pieces_coalesce(struct mem_pieces *mp) -{ - unsigned long a, s, ns; - int i, j, d; - - d = 0; - for (i = 0; i < mp->n_regions; i = j) { - a = mp->regions[i].address; - s = mp->regions[i].size; - for (j = i + 1; j < mp->n_regions - && mp->regions[j].address - a <= s; ++j) { - ns = mp->regions[j].address + mp->regions[j].size - a; - if (ns > s) - s = ns; - } - mp->regions[d].address = a; - mp->regions[d].size = s; - ++d; - } - mp->n_regions = d; -} diff --git a/arch/powerpc/mm/mem_pieces.h b/arch/powerpc/mm/mem_pieces.h deleted file mode 100644 index e2b700dc7f18..000000000000 --- a/arch/powerpc/mm/mem_pieces.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1996 Paul Mackerras - * Changes to accommodate Power Macintoshes. - * Cort Dougan - * Rewrites. - * Grant Erickson - * General rework and split from mm/init.c. - * - * Module name: mem_pieces.h - * - * Description: - * Routines and data structures for manipulating and representing - * phyiscal memory extents (i.e. address/length pairs). - * - */ - -#ifndef __MEM_PIECES_H__ -#define __MEM_PIECES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Type Definitions */ - -#define MEM_PIECES_MAX 32 - -struct mem_pieces { - int n_regions; - struct reg_property regions[MEM_PIECES_MAX]; -}; - -/* Function Prototypes */ - -extern void *mem_pieces_find(unsigned int size, unsigned int align); -extern void mem_pieces_remove(struct mem_pieces *mp, unsigned int start, - unsigned int size, int must_exist); -extern void mem_pieces_coalesce(struct mem_pieces *mp); -extern void mem_pieces_sort(struct mem_pieces *mp); - -#ifdef __cplusplus -} -#endif - -#endif /* __MEM_PIECES_H__ */ diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 540f3292b229..06fe8af3af55 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -36,6 +36,8 @@ extern unsigned long ioremap_base; extern unsigned long ioremap_bot; extern unsigned int rtas_data, rtas_size; +extern unsigned long __max_low_memory; +extern unsigned long __initial_memory_limit; extern unsigned long total_memory; extern unsigned long total_lowmem; extern int mem_init_done; diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 81a3d7446d37..5792e533916f 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -190,8 +190,7 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) * Don't allow anybody to remap normal RAM that we're using. * mem_init() sets high_memory so only do the check after that. */ - if ( mem_init_done && (p < virt_to_phys(high_memory)) ) - { + if (mem_init_done && (p < virt_to_phys(high_memory))) { printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p, __builtin_return_address(0)); return NULL; diff --git a/arch/powerpc/mm/ppc_mmu.c b/arch/powerpc/mm/ppc_mmu.c index 9a381ed5eb21..cef9e83cc7e9 100644 --- a/arch/powerpc/mm/ppc_mmu.c +++ b/arch/powerpc/mm/ppc_mmu.c @@ -32,9 +32,9 @@ #include #include #include +#include #include "mmu_decl.h" -#include "mem_pieces.h" PTE *Hash, *Hash_end; unsigned long Hash_size, Hash_mask; @@ -215,17 +215,6 @@ void __init MMU_init_hw(void) #define MIN_N_HPTEG 1024 /* min 64kB hash table */ #endif -#ifdef CONFIG_POWER4 - /* The hash table has already been allocated and initialized - in prom.c */ - n_hpteg = Hash_size >> LG_HPTEG_SIZE; - lg_n_hpteg = __ilog2(n_hpteg); - - /* Remove the hash table from the available memory */ - if (Hash) - reserve_phys_mem(__pa(Hash), Hash_size); - -#else /* CONFIG_POWER4 */ /* * Allow 1 HPTE (1/8 HPTEG) for each page of memory. * This is less than the recommended amount, but then @@ -245,10 +234,10 @@ void __init MMU_init_hw(void) * Find some memory for the hash table. */ if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); - Hash = mem_pieces_find(Hash_size, Hash_size); + Hash = __va(lmb_alloc_base(Hash_size, Hash_size, + __initial_memory_limit)); cacheable_memzero(Hash, Hash_size); _SDR1 = __pa(Hash) | SDR1_LOW_BITS; -#endif /* CONFIG_POWER4 */ Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index 4789dc024240..fc44f7ca62d7 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -34,6 +34,17 @@ typedef unsigned long pte_basic_t; #define PTE_FMT "%.8lx" #endif +/* align addr on a size boundary - adjust address up/down if needed */ +#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) +#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1))) + +/* align addr on a size boundary - adjust address up if needed */ +#define _ALIGN(addr,size) _ALIGN_UP(addr,size) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE) + + #undef STRICT_MM_TYPECHECKS #ifdef STRICT_MM_TYPECHECKS @@ -76,13 +87,6 @@ typedef unsigned long pgprot_t; #endif - -/* align addr on a size boundary - adjust address up if needed -- Cort */ -#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) - struct page; extern void clear_pages(void *page, int order); static inline void clear_page(void *page) { clear_pages(page, 0); } From 187a00679ad51dfb3d3e74620217417102784218 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 12:49:05 +1000 Subject: [PATCH 0311/1939] powerpc: Remove 64-bit cpu support from ppc32. These days there is no good reason to run a ppc32 kernel on a 64-bit cpu, rather than a ppc64 kernel, so remove the config option and a bunch of code (and ifdefs) from head.S. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 16 ++-- arch/powerpc/kernel/head.S | 148 ++----------------------------------- 2 files changed, 11 insertions(+), 153 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 34be3247fca4..330376b74c87 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -109,10 +109,6 @@ config 40x config 44x bool "AMCC 44x" -config PPC64BRIDGE - select PPC_FPU - bool "POWER3, POWER4 and PPC970 (G5)" - config 8xx bool "Freescale 8xx" @@ -125,7 +121,7 @@ endchoice config POWER4_ONLY bool "Optimize for POWER4" - depends on PPC64 || PPC64BRIDGE + depends on PPC64 default n ---help--- Cause the compiler to optimize for POWER4/POWER5/PPC970 processors. @@ -134,16 +130,16 @@ config POWER4_ONLY config POWER3 bool - depends on PPC64 || PPC64BRIDGE + depends on PPC64 default y if !POWER4_ONLY config POWER4 - depends on PPC64 || PPC64BRIDGE + depends on PPC64 def_bool y config PPC_FPU - depends on PPC32 - def_bool y + bool + default y if PPC64 config BOOKE bool @@ -317,7 +313,7 @@ config PPC_BPA config PPC_OF bool - depends on PPC_MULTIPLATFORM || PPC_ISERIES + depends on PPC_MULTIPLATFORM # for now default y config XICS diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S index d49bff1a7d51..276793e05fd0 100644 --- a/arch/powerpc/kernel/head.S +++ b/arch/powerpc/kernel/head.S @@ -37,19 +37,6 @@ #include #endif -#ifdef CONFIG_PPC64BRIDGE -#define LOAD_BAT(n, reg, RA, RB) \ - ld RA,(n*32)+0(reg); \ - ld RB,(n*32)+8(reg); \ - mtspr SPRN_IBAT##n##U,RA; \ - mtspr SPRN_IBAT##n##L,RB; \ - ld RA,(n*32)+16(reg); \ - ld RB,(n*32)+24(reg); \ - mtspr SPRN_DBAT##n##U,RA; \ - mtspr SPRN_DBAT##n##L,RB; \ - -#else /* CONFIG_PPC64BRIDGE */ - /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ /* see the comment for clear_bats() -- Cort */ \ @@ -66,7 +53,6 @@ mtspr SPRN_DBAT##n##U,RA; \ mtspr SPRN_DBAT##n##L,RB; \ 1: -#endif /* CONFIG_PPC64BRIDGE */ .text .stabs "arch/ppc/kernel/",N_SO,0,0,0f @@ -150,14 +136,6 @@ __start: */ bl early_init -/* - * On POWER4, we first need to tweak some CPU configuration registers - * like real mode cache inhibit or exception base - */ -#ifdef CONFIG_POWER4 - bl __970_cpu_preinit -#endif /* CONFIG_POWER4 */ - #ifdef CONFIG_APUS /* On APUS the __va/__pa constants need to be set to the correct * values before continuing. @@ -171,7 +149,6 @@ __start: */ bl mmu_off __after_mmu_off: -#ifndef CONFIG_POWER4 bl clear_bats bl flush_tlbs @@ -179,10 +156,6 @@ __after_mmu_off: #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) bl setup_disp_bat #endif -#else /* CONFIG_POWER4 */ - bl reloc_offset - bl initial_mm_power4 -#endif /* CONFIG_POWER4 */ /* * Call setup_cpu for CPU 0 and initialize 6xx Idle @@ -194,10 +167,6 @@ __after_mmu_off: bl reloc_offset bl init_idle_6xx #endif /* CONFIG_6xx */ -#ifdef CONFIG_POWER4 - bl reloc_offset - bl init_idle_power4 -#endif /* CONFIG_POWER4 */ #ifndef CONFIG_APUS @@ -397,13 +366,8 @@ i##n: \ /* Data access exception. */ . = 0x300 -#ifdef CONFIG_PPC64BRIDGE - b DataAccess -DataAccessCont: -#else DataAccess: EXCEPTION_PROLOG -#endif /* CONFIG_PPC64BRIDGE */ mfspr r10,SPRN_DSISR andis. r0,r10,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -415,21 +379,11 @@ DataAccess: mfspr r4,SPRN_DAR EXC_XFER_EE_LITE(0x300, handle_page_fault) -#ifdef CONFIG_PPC64BRIDGE -/* SLB fault on data access. */ - . = 0x380 - b DataSegment -#endif /* CONFIG_PPC64BRIDGE */ /* Instruction access exception. */ . = 0x400 -#ifdef CONFIG_PPC64BRIDGE - b InstructionAccess -InstructionAccessCont: -#else InstructionAccess: EXCEPTION_PROLOG -#endif /* CONFIG_PPC64BRIDGE */ andis. r0,r9,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ li r3,0 /* into the hash table */ @@ -439,12 +393,6 @@ InstructionAccess: mr r5,r9 EXC_XFER_EE_LITE(0x400, handle_page_fault) -#ifdef CONFIG_PPC64BRIDGE -/* SLB fault on instruction access. */ - . = 0x480 - b InstructionSegment -#endif /* CONFIG_PPC64BRIDGE */ - /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) @@ -709,15 +657,9 @@ DataStoreTLBMiss: EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE) EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) -#ifdef CONFIG_POWER4 - EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE) - EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD) -#else /* !CONFIG_POWER4 */ EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) -#endif /* CONFIG_POWER4 */ EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) @@ -754,28 +696,6 @@ AltiVecUnavailable: #endif /* CONFIG_ALTIVEC */ EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) -#ifdef CONFIG_PPC64BRIDGE -DataAccess: - EXCEPTION_PROLOG - b DataAccessCont - -InstructionAccess: - EXCEPTION_PROLOG - b InstructionAccessCont - -DataSegment: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - mfspr r4,SPRN_DAR - stw r4,_DAR(r11) - EXC_XFER_STD(0x380, unknown_exception) - -InstructionSegment: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x480, unknown_exception) -#endif /* CONFIG_PPC64BRIDGE */ - #ifdef CONFIG_ALTIVEC /* Note that the AltiVec support is closely modeled after the FP * support. Changes to one are likely to be applicable to the @@ -1048,13 +968,6 @@ __secondary_start_pmac_0: .globl __secondary_start __secondary_start: -#ifdef CONFIG_PPC64BRIDGE - mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ - SYNC - MTMSRD(r0) - isync -#endif /* Copy some CPU settings from CPU 0 */ bl __restore_cpu_setup @@ -1065,10 +978,6 @@ __secondary_start: lis r3,-KERNELBASE@h bl init_idle_6xx #endif /* CONFIG_6xx */ -#ifdef CONFIG_POWER4 - lis r3,-KERNELBASE@h - bl init_idle_power4 -#endif /* CONFIG_POWER4 */ /* get current_thread_info and current */ lis r1,secondary_ti@ha @@ -1109,12 +1018,12 @@ __secondary_start: * Those generic dummy functions are kept for CPUs not * included in CONFIG_6xx */ -#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) +#if !defined(CONFIG_6xx) _GLOBAL(__save_cpu_setup) blr _GLOBAL(__restore_cpu_setup) blr -#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */ +#endif /* !defined(CONFIG_6xx) */ /* @@ -1132,11 +1041,6 @@ load_up_mmu: tophys(r6,r6) lwz r6,_SDR1@l(r6) mtspr SPRN_SDR1,r6 -#ifdef CONFIG_PPC64BRIDGE - /* clear the ASR so we only use the pseudo-segment registers. */ - li r6,0 - mtasr r6 -#endif /* CONFIG_PPC64BRIDGE */ li r0,16 /* load up segment register values */ mtctr r0 /* for context 0 */ lis r3,0x2000 /* Ku = 1, VSID = 0 */ @@ -1145,7 +1049,7 @@ load_up_mmu: addi r3,r3,0x111 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b -#ifndef CONFIG_POWER4 + /* Load the BAT registers with the values set up by MMU_init. MMU_init takes care of whether we're on a 601 or not. */ mfpvr r3 @@ -1158,7 +1062,7 @@ load_up_mmu: LOAD_BAT(1,r3,r4,r5) LOAD_BAT(2,r3,r4,r5) LOAD_BAT(3,r3,r4,r5) -#endif /* CONFIG_POWER4 */ + blr /* @@ -1183,7 +1087,7 @@ start_here: li r0,0 stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) /* - * Do early bootinfo parsing, platform-specific initialization, + * Do early platform-specific initialization, * and set up the MMU. */ mr r3,r31 @@ -1266,9 +1170,6 @@ _GLOBAL(set_context) li r4,0 isync 3: -#ifdef CONFIG_PPC64BRIDGE - slbie r4 -#endif /* CONFIG_PPC64BRIDGE */ mtsrin r3,r4 addi r3,r3,0x111 /* next VSID */ rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ @@ -1355,7 +1256,6 @@ mmu_off: sync RFI -#ifndef CONFIG_POWER4 /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -1363,7 +1263,6 @@ mmu_off: */ initial_bats: lis r11,KERNELBASE@h -#ifndef CONFIG_PPC64BRIDGE mfspr r9,SPRN_PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpwi 0,r9,1 @@ -1378,7 +1277,6 @@ initial_bats: mtspr SPRN_IBAT1L,r10 isync blr -#endif /* CONFIG_PPC64BRIDGE */ 4: tophys(r8,r11) #ifdef CONFIG_SMP @@ -1392,11 +1290,6 @@ initial_bats: ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ #endif /* CONFIG_APUS */ -#ifdef CONFIG_PPC64BRIDGE - /* clear out the high 32 bits in the BAT */ - clrldi r11,r11,32 - clrldi r8,r8,32 -#endif /* CONFIG_PPC64BRIDGE */ mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ mtspr SPRN_IBAT0L,r8 @@ -1429,37 +1322,6 @@ setup_disp_bat: #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ -#else /* CONFIG_POWER4 */ -/* - * Load up the SDR1 and segment register values now - * since we don't have the BATs. - * Also make sure we are running in 32-bit mode. - */ - -initial_mm_power4: - addis r14,r3,_SDR1@ha /* get the value from _SDR1 */ - lwz r14,_SDR1@l(r14) /* assume hash table below 4GB */ - mtspr SPRN_SDR1,r14 - slbia - lis r4,0x2000 /* set pseudo-segment reg 12 */ - ori r5,r4,0x0ccc - mtsr 12,r5 -#if 0 - ori r5,r4,0x0888 /* set pseudo-segment reg 8 */ - mtsr 8,r5 /* (for access to serial port) */ -#endif -#ifdef CONFIG_BOOTX_TEXT - ori r5,r4,0x0999 /* set pseudo-segment reg 9 */ - mtsr 9,r5 /* (for access to screen) */ -#endif - mfmsr r0 - clrldi r0,r0,1 - sync - mtmsr r0 - isync - blr - -#endif /* CONFIG_POWER4 */ #ifdef CONFIG_8260 /* Jump into the system reset for the rom. From 2e686bc3bf6268e30eb9584e0bcd43b7bec28f3b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 13:22:17 +1000 Subject: [PATCH 0312/1939] powerpc: Merge of_device.c and of_device.h Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/of_device.c | 274 +++++++++++++++++++ include/{asm-ppc => asm-powerpc}/of_device.h | 7 +- include/asm-ppc64/of_device.h | 2 - 3 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/kernel/of_device.c rename include/{asm-ppc => asm-powerpc}/of_device.h (94%) delete mode 100644 include/asm-ppc64/of_device.h diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c new file mode 100644 index 000000000000..766718814515 --- /dev/null +++ b/arch/powerpc/kernel/of_device.c @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * of_match_device - Tell if an of_device structure has a matching + * of_match structure + * @ids: array of of device match structures to search in + * @dev: the of device structure to match against + * + * Used by a driver to check whether an of_device present in the + * system is in its list of supported devices. + */ +const struct of_device_id *of_match_device(const struct of_device_id *matches, + const struct of_device *dev) +{ + if (!dev->node) + return NULL; + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { + int match = 1; + if (matches->name[0]) + match &= dev->node->name + && !strcmp(matches->name, dev->node->name); + if (matches->type[0]) + match &= dev->node->type + && !strcmp(matches->type, dev->node->type); + if (matches->compatible[0]) + match &= device_is_compatible(dev->node, + matches->compatible); + if (match) + return matches; + matches++; + } + return NULL; +} + +static int of_platform_bus_match(struct device *dev, struct device_driver *drv) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * of_drv = to_of_platform_driver(drv); + const struct of_device_id * matches = of_drv->match_table; + + if (!matches) + return 0; + + return of_match_device(matches, of_dev) != NULL; +} + +struct of_device *of_dev_get(struct of_device *dev) +{ + struct device *tmp; + + if (!dev) + return NULL; + tmp = get_device(&dev->dev); + if (tmp) + return to_of_device(tmp); + else + return NULL; +} + +void of_dev_put(struct of_device *dev) +{ + if (dev) + put_device(&dev->dev); +} + + +static int of_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct of_platform_driver *drv; + struct of_device *of_dev; + const struct of_device_id *match; + + drv = to_of_platform_driver(dev->driver); + of_dev = to_of_device(dev); + + if (!drv->probe) + return error; + + of_dev_get(of_dev); + + match = of_match_device(drv->match_table, of_dev); + if (match) + error = drv->probe(of_dev, match); + if (error) + of_dev_put(of_dev); + + return error; +} + +static int of_device_remove(struct device *dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + + if (dev->driver && drv->remove) + drv->remove(of_dev); + return 0; +} + +static int of_device_suspend(struct device *dev, pm_message_t state) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->suspend) + error = drv->suspend(of_dev, state); + return error; +} + +static int of_device_resume(struct device * dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->resume) + error = drv->resume(of_dev); + return error; +} + +struct bus_type of_platform_bus_type = { + .name = "of_platform", + .match = of_platform_bus_match, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; + +static int __init of_bus_driver_init(void) +{ + return bus_register(&of_platform_bus_type); +} + +postcore_initcall(of_bus_driver_init); + +int of_register_driver(struct of_platform_driver *drv) +{ + int count = 0; + + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &of_platform_bus_type; + drv->driver.probe = of_device_probe; + drv->driver.remove = of_device_remove; + + /* register with core */ + count = driver_register(&drv->driver); + return count ? count : 1; +} + +void of_unregister_driver(struct of_platform_driver *drv) +{ + driver_unregister(&drv->driver); +} + + +static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + return sprintf(buf, "%s", ofdev->node->full_name); +} + +static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); + +/** + * of_release_dev - free an of device structure when all users of it are finished. + * @dev: device that's been disconnected + * + * Will be called only by the device core when all users of this of device are + * done. + */ +void of_release_dev(struct device *dev) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + of_node_put(ofdev->node); + kfree(ofdev); +} + +int of_device_register(struct of_device *ofdev) +{ + int rc; + struct of_device **odprop; + + BUG_ON(ofdev->node == NULL); + + odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); + if (!odprop) { + struct property *new_prop; + + new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *), + GFP_KERNEL); + if (new_prop == NULL) + return -ENOMEM; + new_prop->name = "linux,device"; + new_prop->length = sizeof(sizeof(struct of_device *)); + new_prop->value = (unsigned char *)&new_prop[1]; + odprop = (struct of_device **)new_prop->value; + *odprop = NULL; + prom_add_property(ofdev->node, new_prop); + } + *odprop = ofdev; + + rc = device_register(&ofdev->dev); + if (rc) + return rc; + + device_create_file(&ofdev->dev, &dev_attr_devspec); + + return 0; +} + +void of_device_unregister(struct of_device *ofdev) +{ + struct of_device **odprop; + + device_remove_file(&ofdev->dev, &dev_attr_devspec); + + odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); + if (odprop) + *odprop = NULL; + + device_unregister(&ofdev->dev); +} + +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + struct of_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, sizeof(*dev)); + + dev->node = of_node_get(np); + dev->dma_mask = 0xffffffffUL; + dev->dev.dma_mask = &dev->dma_mask; + dev->dev.parent = parent; + dev->dev.bus = &of_platform_bus_type; + dev->dev.release = of_release_dev; + + strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); + + if (of_device_register(dev) != 0) { + kfree(dev); + return NULL; + } + + return dev; +} + +EXPORT_SYMBOL(of_match_device); +EXPORT_SYMBOL(of_platform_bus_type); +EXPORT_SYMBOL(of_register_driver); +EXPORT_SYMBOL(of_unregister_driver); +EXPORT_SYMBOL(of_device_register); +EXPORT_SYMBOL(of_device_unregister); +EXPORT_SYMBOL(of_dev_get); +EXPORT_SYMBOL(of_dev_put); +EXPORT_SYMBOL(of_platform_device_create); +EXPORT_SYMBOL(of_release_dev); diff --git a/include/asm-ppc/of_device.h b/include/asm-powerpc/of_device.h similarity index 94% rename from include/asm-ppc/of_device.h rename to include/asm-powerpc/of_device.h index 575bce418f80..ddb16aae0bd6 100644 --- a/include/asm-ppc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -1,5 +1,5 @@ -#ifndef __OF_DEVICE_H__ -#define __OF_DEVICE_H__ +#ifndef _ASM_POWERPC_OF_DEVICE_H +#define _ASM_POWERPC_OF_DEVICE_H #include #include @@ -61,5 +61,4 @@ extern struct of_device *of_platform_device_create(struct device_node *np, struct device *parent); extern void of_release_dev(struct device *dev); -#endif /* __OF_DEVICE_H__ */ - +#endif /* _ASM_POWERPC_OF_DEVICE_H */ diff --git a/include/asm-ppc64/of_device.h b/include/asm-ppc64/of_device.h deleted file mode 100644 index 7bc136e22590..000000000000 --- a/include/asm-ppc64/of_device.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - From b3491269f5604e4265ee2f27b47a76ce1e3678b6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 13:24:50 +1000 Subject: [PATCH 0313/1939] powerpc: Use the merged of_device.c with ARCH=powerpc Also compile btext.c with -fPIC; this was missed before. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 4842e82dbc2b..06d618e52f8e 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -7,6 +7,7 @@ EXTRA_CFLAGS += -mno-minimal-toc endif ifeq ($(CONFIG_PPC32),y) CFLAGS_prom_init.o += -fPIC +CFLAGS_btext.o += -fPIC endif extra-$(CONFIG_PPC_STD_MMU) := head.o @@ -23,7 +24,7 @@ obj-y := traps.o prom.o semaphore.o obj-$(CONFIG_PPC32) += setup.o process.o obj-$(CONFIG_PPC64) += idle_power4.o ifeq ($(CONFIG_PPC32),y) -obj-$(CONFIG_PPC_OF) += prom_init.o +obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o obj-$(CONFIG_MODULES) += ppc_ksyms.o endif obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o From 8dad3f9257414f151cd821bfe01f54d7f52d2507 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 13:27:05 +1000 Subject: [PATCH 0314/1939] powerpc: Merge traps.c a bit more This reduces the differences between ppc32 and ppc64 in arch/powerpc/kernel/traps.c a bit further. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head.S | 2 +- arch/powerpc/kernel/traps.c | 192 +++++++----------------------------- 2 files changed, 35 insertions(+), 159 deletions(-) diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head.S index 276793e05fd0..d9dbbd426744 100644 --- a/arch/powerpc/kernel/head.S +++ b/arch/powerpc/kernel/head.S @@ -416,7 +416,7 @@ FPUnavailable: EXCEPTION_PROLOG bne load_up_fpu /* if from user, just load it up */ addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x800, KernelFP) + EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 37b961f1e279..a2e4ad3f5a75 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -21,19 +21,17 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include -#ifdef CONFIG_PPC32 -#include -#include -#endif #include #include @@ -56,12 +54,6 @@ #include #endif -#ifdef CONFIG_PPC64 -#define __KPROBES __kprobes -#else -#define __KPROBES -#endif - #ifdef CONFIG_DEBUGGER int (*__debugger)(struct pt_regs *regs); int (*__debugger_ipi)(struct pt_regs *regs); @@ -111,7 +103,7 @@ int die(const char *str, struct pt_regs *regs, long err) console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); -#if defined(CONFIG_PPC32) && defined(CONFIG_PMAC_BACKLIGHT) +#ifdef CONFIG_PMAC_BACKLIGHT if (_machine == _MACH_Pmac) { set_backlight_enable(1); set_backlight_level(BACKLIGHT_MAX); @@ -175,11 +167,7 @@ int die(const char *str, struct pt_regs *regs, long err) #endif panic("Fatal exception"); } -#ifdef CONFIG_PPC32 do_exit(err); -#else - do_exit(SIGSEGV); -#endif return 0; } @@ -199,7 +187,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) info.si_addr = (void __user *) addr; force_sig_info(signr, &info, current); -#ifdef CONFIG_PPC32 /* * Init gets no signals that it doesn't have a handler for. * That's all very well, but if it has caused a synchronous @@ -221,7 +208,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) do_exit(signr); } } -#endif } #ifdef CONFIG_PPC64 @@ -231,7 +217,7 @@ void system_reset_exception(struct pt_regs *regs) if (ppc_md.system_reset_exception) ppc_md.system_reset_exception(regs); - die("System Reset", regs, 0); + die("System Reset", regs, SIGABRT); /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) @@ -241,7 +227,6 @@ void system_reset_exception(struct pt_regs *regs) } #endif -#ifdef CONFIG_PPC32 /* * I/O accesses can cause machine checks on powermacs. * Check if the NIP corresponds to the address of a sync @@ -290,7 +275,6 @@ static inline int check_io_access(struct pt_regs *regs) #endif /* CONFIG_PPC_PMAC */ return 0; } -#endif /* CONFIG_PPC32 */ #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) @@ -326,7 +310,6 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) #endif -#ifdef CONFIG_PPC32 /* * This is "fall-back" implementation for configurations * which don't provide platform-specific machine check info @@ -335,7 +318,6 @@ void __attribute__ ((weak)) platform_machine_check(struct pt_regs *regs) { } -#endif void machine_check_exception(struct pt_regs *regs) { @@ -497,13 +479,7 @@ void machine_check_exception(struct pt_regs *regs) if (debugger_fault_handler(regs)) return; - die("Machine check", regs, -#ifdef CONFIG_PPC32 - SIGBUS -#else - 0 -#endif - ); + die("Machine check", regs, SIGBUS); /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) @@ -542,13 +518,9 @@ void RunModeException(struct pt_regs *regs) } #endif -void __KPROBES single_step_exception(struct pt_regs *regs) +void __kprobes single_step_exception(struct pt_regs *regs) { -#ifdef CONFIG_PPC32 regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ -#else - regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ -#endif if (notify_die(DIE_SSTEP, "single_step", regs, 5, 5, SIGTRAP) == NOTIFY_STOP) @@ -565,15 +537,12 @@ void __KPROBES single_step_exception(struct pt_regs *regs) * pretend we got a single-step exception. This was pointed out * by Kumar Gala. -- paulus */ -static inline void emulate_single_step(struct pt_regs *regs) +static void emulate_single_step(struct pt_regs *regs) { if (single_stepping(regs)) { -#ifdef CONFIG_PPC32 clear_single_step(regs); _exception(SIGTRAP, regs, TRAP_TRACE, 0); -#else single_step_exception(regs); -#endif } } @@ -582,17 +551,7 @@ static void parse_fpe(struct pt_regs *regs) int code = 0; unsigned long fpscr; -#ifdef CONFIG_PPC32 - /* We must make sure the FP state is consistent with - * our MSR_FP in regs - */ - preempt_disable(); - if (regs->msr & MSR_FP) - giveup_fpu(current); - preempt_enable(); -#else flush_fp_to_thread(current); -#endif fpscr = current->thread.fpscr; @@ -737,19 +696,8 @@ static int emulate_instruction(struct pt_regs *regs) } /* Emulating the dcba insn is just a no-op. */ - if ((instword & INST_DCBA_MASK) == INST_DCBA) { -#ifdef CONFIG_PPC64 - static int warned; - - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'dcba' insn\n", - current->pid, current->comm); - warned = 1; - } -#endif /* CONFIG_PPC64 */ + if ((instword & INST_DCBA_MASK) == INST_DCBA) return 0; - } /* Emulate the mcrxr insn. */ if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { @@ -817,7 +765,7 @@ static int check_bug_trap(struct pt_regs *regs) return 0; if (bug->line & BUG_WARNING_TRAP) { /* this is a WARN_ON rather than BUG/BUG_ON */ -#if defined(CONFIG_PPC32) && defined(CONFIG_XMON) +#ifdef CONFIG_XMON xmon_printf(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); @@ -843,12 +791,12 @@ static int check_bug_trap(struct pt_regs *regs) return 0; } -void __KPROBES program_check_exception(struct pt_regs *regs) +void __kprobes program_check_exception(struct pt_regs *regs) { unsigned int reason = get_reason(regs); -#if defined(CONFIG_PPC32) && defined(CONFIG_MATH_EMULATION) extern int do_mathemu(struct pt_regs *regs); +#ifdef CONFIG_MATH_EMULATION /* (reason & REASON_ILLEGAL) would be the obvious thing here, * but there seems to be a hardware bug on the 405GP (RevD) * that means ESR is sometimes set incorrectly - either to @@ -860,58 +808,45 @@ void __KPROBES program_check_exception(struct pt_regs *regs) emulate_single_step(regs); return; } -#endif - -#ifdef CONFIG_PPC64 - if (debugger_fault_handler(regs)) - return; -#endif +#endif /* CONFIG_MATH_EMULATION */ if (reason & REASON_FP) { /* IEEE FP exception */ parse_fpe(regs); - } else if (reason & REASON_TRAP) { + return; + } + if (reason & REASON_TRAP) { /* trap exception */ -#ifdef CONFIG_PPC64 if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP) == NOTIFY_STOP) return; -#endif if (debugger_bpt(regs)) return; if (check_bug_trap(regs)) { regs->nip += 4; return; } - _exception(SIGTRAP, regs, TRAP_BRKPT, -#ifdef CONFIG_PPC32 - 0 -#else - regs->nip -#endif - ); - } else -#ifdef CONFIG_PPC32 - if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) -#endif - { - /* Privileged or illegal instruction; try to emulate it. */ + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); + return; + } + + /* Try to emulate it if we should. */ + if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { switch (emulate_instruction(regs)) { case 0: regs->nip += 4; emulate_single_step(regs); - break; + return; case -EFAULT: _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); - break; - default: - if (reason & REASON_PRIVILEGED) - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - else - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - break; + return; } } + + if (reason & REASON_PRIVILEGED) + _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); + else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } void alignment_exception(struct pt_regs *regs) @@ -929,25 +864,13 @@ void alignment_exception(struct pt_regs *regs) /* Operand address was bad */ if (fixed == -EFAULT) { if (user_mode(regs)) - _exception(SIGSEGV, regs, -#ifdef CONFIG_PPC32 - SEGV_ACCERR, -#else - SEGV_MAPERR, -#endif - regs->dar); + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); else /* Search exception table */ bad_page_fault(regs, regs->dar, SIGSEGV); return; } - _exception(SIGBUS, regs, BUS_ADRALN, -#ifdef CONFIG_PPC32 - regs->dar -#else - regs->nip -#endif - ); + _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); } #ifdef CONFIG_PPC32 @@ -976,18 +899,16 @@ void trace_syscall(struct pt_regs *regs) } #endif /* CONFIG_PPC32 */ -#ifdef CONFIG_PPC64 void kernel_fp_unavailable_exception(struct pt_regs *regs) { printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " "%lx at %lx\n", regs->trap, regs->nip); die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); } -#endif void altivec_unavailable_exception(struct pt_regs *regs) { -#if !defined(CONFIG_ALTIVEC) || defined(CONFIG_PPC64) +#if !defined(CONFIG_ALTIVEC) if (user_mode(regs)) { /* A user program has executed an altivec instruction, but this kernel doesn't support altivec. */ @@ -995,22 +916,9 @@ void altivec_unavailable_exception(struct pt_regs *regs) return; } #endif -#ifdef CONFIG_PPC32 - { - static int kernel_altivec_count; - - /* The kernel has executed an altivec instruction without - first enabling altivec. Whinge but let it do it. */ - if (++kernel_altivec_count < 10) - printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", - current, regs->nip); - regs->msr |= MSR_VEC; - } -#else printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " "%lx at %lx\n", regs->trap, regs->nip); die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); -#endif } #ifdef CONFIG_PPC64 @@ -1024,8 +932,7 @@ void performance_monitor_exception(struct pt_regs *regs) } #endif - -#if defined(CONFIG_PPC32) && defined(CONFIG_8xx) +#ifdef CONFIG_8xx void SoftwareEmulation(struct pt_regs *regs) { extern int do_mathemu(struct pt_regs *); @@ -1054,7 +961,7 @@ void SoftwareEmulation(struct pt_regs *regs) } else emulate_single_step(regs); } -#endif /* defined(CONFIG_PPC32) && defined(CONFIG_8xx) */ +#endif /* CONFIG_8xx */ #ifdef CONFIG_PPC32 #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) @@ -1091,29 +998,14 @@ void TAUException(struct pt_regs *regs) void altivec_assist_exception(struct pt_regs *regs) { int err; -#ifdef CONFIG_PPC64 - siginfo_t info; -#endif -#ifdef CONFIG_PPC32 - preempt_disable(); - if (regs->msr & MSR_VEC) - giveup_altivec(current); - preempt_enable(); -#endif if (!user_mode(regs)) { printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" " at %lx\n", regs->nip); - die("Kernel " -#ifdef CONFIG_PPC64 - "VMX/" -#endif - "Altivec assist exception", regs, SIGILL); + die("Kernel VMX/Altivec assist exception", regs, SIGILL); } -#ifdef CONFIG_PPC64 flush_altivec_to_thread(current); -#endif /* CONFIG_PPC64 */ err = emulate_altivec(regs); if (err == 0) { @@ -1124,15 +1016,7 @@ void altivec_assist_exception(struct pt_regs *regs) if (err == -EFAULT) { /* got an error reading the instruction */ -#ifdef CONFIG_PPC32 _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); -#else - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *) regs->nip; - force_sig_info(SIGSEGV, &info, current); -#endif } else { /* didn't recognize the instruction */ /* XXX quick hack for now: set the non-Java bit in the VSCR */ @@ -1144,7 +1028,6 @@ void altivec_assist_exception(struct pt_regs *regs) } #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_PPC32 #ifdef CONFIG_FSL_BOOKE void CacheLockingException(struct pt_regs *regs, unsigned long address, unsigned long error_code) @@ -1194,9 +1077,7 @@ void SPEFloatingPointException(struct pt_regs *regs) return; } #endif -#endif /* CONFIG_PPC32 */ -#ifdef CONFIG_PPC64 /* * We enter here if we get an unrecoverable exception, that is, one * that happened at a point where the RI (recoverable interrupt) bit @@ -1209,9 +1090,7 @@ void unrecoverable_exception(struct pt_regs *regs) regs->trap, regs->nip); die("Unrecoverable exception", regs, SIGABRT); } -#endif /* CONFIG_PPC64 */ -#ifdef CONFIG_PPC32 #ifdef CONFIG_BOOKE_WDT /* * Default handler for a Watchdog exception, @@ -1230,9 +1109,7 @@ void WatchdogException(struct pt_regs *regs) WatchdogHandler(regs); } #endif -#endif /* CONFIG_PPC32 */ -#ifdef CONFIG_PPC64 /* * We enter here if we discover during exception entry that we are * running in supervisor mode with a userspace value in the stack pointer. @@ -1243,7 +1120,6 @@ void kernel_bad_stack(struct pt_regs *regs) regs->gpr[1], regs->nip); die("Bad kernel stack pointer", regs, SIGABRT); } -#endif void __init trap_init(void) { From c16ff7e44883afc05cbf6fde0e6913bb10c66885 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 13:28:31 +1000 Subject: [PATCH 0315/1939] powerpc: Define a _sdata symbol This is needed by arch/powerpc/mm/mem.c now. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 0587d9c4609d..d0239bf8d4cc 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -107,6 +107,7 @@ SECTIONS #ifdef CONFIG_PPC32 /* Read-write section, merged into data segment: */ . = ALIGN(4096); + _sdata = .; .data : { *(.data) From 05f62a5c049845eab8dfb3aeda55c18a2d4396e3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 Oct 2005 13:29:24 +1000 Subject: [PATCH 0316/1939] powerpc: Fix idle.c compile warning This fixes a compile warning when using arch/ppc/kernel/idle.c in a merged (ARCH=powerpc) kernel. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/idle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index fba29c876b62..0a12fbef7347 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -32,6 +32,7 @@ #include #include #include +#include void default_idle(void) { From ad6e90f6d0c4243cc35e07e2681a3323af533ce4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Oct 2005 11:43:29 +0900 Subject: [PATCH 0317/1939] [PATCH] sil24: ignore non-error exception irqs 01_sil24_ignore-non-error-exception-irqs.patch Do not error-finish commands for non-error exception irqs - just ignore them. This is taken from Edward's driver. Signed-off-by: Tejun Heo sata_sil24.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index d8a2f5f04e82..571302dc48a3 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -489,12 +489,21 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) u32 irq_stat, cmd_err, sstatus, serror; irq_stat = readl(port + PORT_IRQ_STAT); + writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ + + if (!(irq_stat & PORT_IRQ_ERROR)) { + /* ignore non-completion, non-error irqs for now */ + printk(KERN_WARNING DRV_NAME + "ata%u: non-error exception irq (irq_stat %x)\n", + ap->id, irq_stat); + return; + } + cmd_err = readl(port + PORT_CMD_ERR); sstatus = readl(port + PORT_SSTATUS); serror = readl(port + PORT_SERROR); /* Clear IRQ/errors */ - writel(irq_stat, port + PORT_IRQ_STAT); if (cmd_err) writel(cmd_err, port + PORT_CMD_ERR); if (serror) From 46b93e7bce80a08ea07e250d03b0b596cbd32595 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Oct 2005 11:43:34 +0900 Subject: [PATCH 0318/1939] [PATCH] sil24: remove CMDERR clearing 02_sil24_remove-cmderr-clearing.patch CMDERR register doesn't need clearing. This is from Edward's driver. Signed-off-by: Tejun Heo sata_sil24.c | 4 ---- 1 file changed, 4 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 571302dc48a3..032d9c093979 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -502,10 +502,6 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) cmd_err = readl(port + PORT_CMD_ERR); sstatus = readl(port + PORT_SSTATUS); serror = readl(port + PORT_SERROR); - - /* Clear IRQ/errors */ - if (cmd_err) - writel(cmd_err, port + PORT_CMD_ERR); if (serror) writel(serror, port + PORT_SERROR); From 6a575fa969beeddd0859f9e9d26ab16c6a0d8d6a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Oct 2005 11:43:39 +0900 Subject: [PATCH 0319/1939] [PATCH] sil24: implement proper TF register reading & caching 03_sil24_add-tf-reading.patch This patch implements proper TF register reading back and caching and bumps up version to 0.22. This is taken from Edward's driver. Signed-off-by: Tejun Heo sata_sil24.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 50 +++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 032d9c093979..b65194c755f8 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "sata_sil24" -#define DRV_VERSION "0.21" /* Silicon Image's preview driver was 0.10 */ +#define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */ #define NR_PORTS 4 @@ -216,6 +216,7 @@ struct sil24_cmd_block { struct sil24_port_priv { struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ dma_addr_t cmd_block_dma; /* DMA base addr for them */ + struct ata_taskfile tf; /* Cached taskfile registers */ }; /* ap->host_set->private_data */ @@ -322,14 +323,25 @@ static struct ata_port_info sil24_port_info[] = { }, }; +static inline void sil24_update_tf(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + void *port = (void *)ap->ioaddr.cmd_addr; + struct sil24_prb *prb = port; + + ata_tf_from_fis(prb->fis, &pp->tf); +} + static u8 sil24_check_status(struct ata_port *ap) { - return ATA_DRDY; + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.command; } static u8 sil24_check_err(struct ata_port *ap) { - return 0; + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.feature; } static int sil24_scr_map[] = { @@ -485,6 +497,7 @@ static void sil24_eng_timeout(struct ata_port *ap) static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct sil24_port_priv *pp = ap->private_data; void *port = (void *)ap->ioaddr.cmd_addr; u32 irq_stat, cmd_err, sstatus, serror; @@ -509,8 +522,22 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { + /* + * Device is reporting error, tf registers are valid. + */ + sil24_update_tf(ap); + } else { + /* + * Other errors. libata currently doesn't have any + * mechanism to report these errors. Just turn on + * ATA_ERR. + */ + pp->tf.command = ATA_ERR; + } + if (qc) - ata_qc_complete(qc, ATA_ERR); + ata_qc_complete(qc, pp->tf.command); sil24_reset_controller(ap); } @@ -523,8 +550,19 @@ static inline void sil24_host_intr(struct ata_port *ap) slot_stat = readl(port + PORT_SLOT_STAT); if (!(slot_stat & HOST_SSTAT_ATTN)) { + struct sil24_port_priv *pp = ap->private_data; + /* + * !HOST_SSAT_ATTN guarantees successful completion, + * so reading back tf registers is unnecessary for + * most commands. TODO: read tf registers for + * commands which require these values on successful + * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, + * DEVICE RESET and READ PORT MULTIPLIER (any more?). + */ + sil24_update_tf(ap); + if (qc) - ata_qc_complete(qc, 0); + ata_qc_complete(qc, pp->tf.command); } else sil24_error_intr(ap, slot_stat); } @@ -579,6 +617,8 @@ static int sil24_port_start(struct ata_port *ap) return -ENOMEM; memset(pp, 0, sizeof(*pp)); + pp->tf.command = ATA_DRDY; + cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); if (!cb) { kfree(pp); From 0e5dec478cfff2c29e68d1108ff828fa321adc59 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 6 Oct 2005 09:40:20 -0400 Subject: [PATCH 0320/1939] [libata passthru] add (DRIVER_SENSE << 24) to all check-conditions --- drivers/scsi/libata-scsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 75cb685e320b..1b00bc618e15 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -500,7 +500,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - cmd->result = SAM_STAT_CHECK_CONDITION; + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; /* * Read the controller registers. @@ -575,7 +575,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc) memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - cmd->result = SAM_STAT_CHECK_CONDITION; + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; /* * Read the controller registers. @@ -1638,7 +1638,7 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = SAM_STAT_CHECK_CONDITION; + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; cmd->sense_buffer[0] = 0x70; cmd->sense_buffer[2] = ILLEGAL_REQUEST; From 7f726d125d570f38b9e7c8a2decebc39c0a343dc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 7 Oct 2005 01:43:19 +0900 Subject: [PATCH 0321/1939] [PATCH] sil24: implement tf_read callback Hello, guys. This patch implements ->tf_read callback for sil24. It didn't use to be necessary but new ata_gen_fixed_sense now makes use of ->tf_read callback. This patch is taken from Edward Falk's driver. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index b65194c755f8..693330bdc821 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -229,6 +229,7 @@ static u8 sil24_check_status(struct ata_port *ap); static u8 sil24_check_err(struct ata_port *ap); static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void sil24_phy_reset(struct ata_port *ap); static void sil24_qc_prep(struct ata_queued_cmd *qc); static int sil24_qc_issue(struct ata_queued_cmd *qc); @@ -280,6 +281,8 @@ static struct ata_port_operations sil24_ops = { .check_err = sil24_check_err, .dev_select = ata_noop_dev_select, + .tf_read = sil24_tf_read, + .phy_reset = sil24_phy_reset, .qc_prep = sil24_qc_prep, @@ -372,6 +375,12 @@ static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) } } +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct sil24_port_priv *pp = ap->private_data; + *tf = pp->tf; +} + static void sil24_phy_reset(struct ata_port *ap) { __sata_phy_reset(ap); From 845c5834d0aa60eb1588397696e7fabbaab2d3b0 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sun, 9 Oct 2005 08:55:41 -0400 Subject: [PATCH 0322/1939] [libata scsi] add ata_scsi_set_sense helper - add extern ata_scsi_set_sense() to build SCSI fixed sense data and corresponding SCSI status Signed-off-by: Douglas Gilbert Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 28 ++++++++++++++++++++++++++++ drivers/scsi/libata.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 1c3a10fb3c44..bca9a5016b17 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1450,6 +1450,34 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, return 0; } +/** + * ata_scsi_set_sense - Set SCSI sense data and status + * @cmd: SCSI request to be handled + * @sk: SCSI-defined sense key + * @asc: SCSI-defined additional sense code + * @ascq: SCSI-defined additional sense code qualifier + * + * Helper function that builds a valid fixed format, current + * response code and the given sense key (sk), additional sense + * code (asc) and additional sense code qualifier (ascq) with + * a SCSI command status of %SAM_STAT_CHECK_CONDITION and + * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . + * + * LOCKING: + * Not required + */ + +void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; /* fixed format, current */ + cmd->sense_buffer[2] = sk; + cmd->sense_buffer[7] = 18 - 8; /* additional sense length */ + cmd->sense_buffer[12] = asc; + cmd->sense_buffer[13] = ascq; +} + /** * ata_scsi_badcmd - End a SCSI request with an error * @cmd: SCSI request to be handled diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index a4b55dc9c698..4622e643ffd3 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -80,6 +80,8 @@ extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq); +extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, + u8 sk, u8 asc, u8 ascq); extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); From ae00651020413bd7eb5fa3bd0abbd78d7cf1abb2 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sun, 9 Oct 2005 09:09:35 -0400 Subject: [PATCH 0323/1939] [libata scsi] improve scsi error handling with ata_scsi_set_sense() - change "xlat" and "fill" actors in libata-scsi so they are responsible for SCSI status and sense data when they return 1. This allows GOOD status or a specialized error to be set. - yield an error for mode sense requests for saved values [sat-r06] - remove static inlines for ata_bad_scsiop() and ata_bad_cdb() which are no longer used Signed-off-by: Douglas Gilbert Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 184 ++++++++++++++++++++++++------------- drivers/scsi/libata.h | 10 -- 2 files changed, 121 insertions(+), 73 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index bca9a5016b17..c64169ca7ff0 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -49,6 +49,14 @@ static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); +static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + done(cmd); +} + /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined @@ -182,7 +190,6 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; u8 err = 0; - unsigned char *sb = cmd->sense_buffer; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -225,8 +232,6 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) }; int i = 0; - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - /* * Is this an error we can process/parse */ @@ -281,11 +286,9 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) /* Look for best matches first */ if((sense_table[i][0] & err) == sense_table[i][0]) { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); return; } i++; @@ -300,11 +303,9 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { if(stat_table[i][0] & drv_stat) { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); return; } i++; @@ -313,15 +314,12 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ - sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0x11, 0x4); + /* "unrecovered read error" */ } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0xc, 0x2); + /* "write error - auto-reallocation failed" */ } } @@ -430,9 +428,9 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, ; /* ignore IMMED bit, violates sat-r05 */ } if (scsicmd[4] & 0x2) - return 1; /* LOEJ bit set not supported */ + goto invalid_fld; /* LOEJ bit set not supported */ if (((scsicmd[4] >> 4) & 0xf) != 0) - return 1; /* power conditions not supported */ + goto invalid_fld; /* power conditions not supported */ if (scsicmd[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ @@ -464,6 +462,11 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, */ return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; } @@ -623,20 +626,20 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) else if (scsicmd[0] == VERIFY_16) scsi_16_lba_len(scsicmd, &block, &n_block); else - return 1; + goto invalid_fld; if (!n_block) - return 1; + goto nothing_to_do; if (block >= dev_sectors) - return 1; + goto out_of_range; if ((block + n_block) > dev_sectors) - return 1; + goto out_of_range; if (lba48) { if (n_block > (64 * 1024)) - return 1; + goto invalid_fld; } else { if (n_block > 256) - return 1; + goto invalid_fld; } if (lba) { @@ -679,7 +682,7 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) Head: 0-15 Sector: 1-255*/ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) - return 1; + goto out_of_range; tf->command = ATA_CMD_VERIFY; tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ @@ -690,6 +693,20 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; + +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; + return 1; } /** @@ -754,7 +771,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) break; default: DPRINTK("no-byte command\n"); - return 1; + goto invalid_fld; } /* Check and compose ATA command */ @@ -764,13 +781,13 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * However, for ATA R/W commands, sector count 0 means * 256 or 65536 sectors, not 0 sectors as in SCSI. */ - return 1; + goto nothing_to_do; if (lba) { if (lba48) { /* The request -may- be too large for LBA48. */ if ((block >> 48) || (n_block > 65536)) - return 1; + goto out_of_range; tf->hob_nsect = (n_block >> 8) & 0xff; @@ -782,7 +799,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* The request -may- be too large for LBA28. */ if ((block >> 28) || (n_block > 256)) - return 1; + goto out_of_range; tf->device |= (block >> 24) & 0xf; } @@ -801,7 +818,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* The request -may- be too large for CHS addressing. */ if ((block >> 28) || (n_block > 256)) - return 1; + goto out_of_range; /* Convert LBA to CHS */ track = (u32)block / dev->sectors; @@ -817,7 +834,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) Head: 0-15 Sector: 1-255*/ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) - return 1; + goto out_of_range; qc->nsect = n_block; tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ @@ -828,6 +845,20 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; + +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; + return 1; } static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) @@ -859,6 +890,12 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * This function sets up an ata_queued_cmd structure for the * SCSI command, and sends that ata_queued_cmd to the hardware. * + * The xlat_func argument (actor) returns 0 if ready to execute + * ATA command, else 1 to finish translation. If 1 is returned + * then cmd->result (and possibly cmd->sense_buffer) are assumed + * to be set reflecting an error condition or clean (early) + * termination. + * * LOCKING: * spin_lock_irqsave(host_set lock) */ @@ -875,7 +912,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc = ata_scsi_qc_new(ap, dev, cmd, done); if (!qc) - return; + goto err_mem; /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || @@ -883,7 +920,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", ap->id, dev->devno); - goto err_out; + goto err_did; } if (cmd->use_sg) @@ -898,19 +935,28 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc, scsicmd)) - goto err_out; + goto early_finish; /* select device, send command to hardware */ if (ata_qc_issue(qc)) - goto err_out; + goto err_did; VPRINTK("EXIT\n"); return; -err_out: +early_finish: + ata_qc_free(qc); + done(cmd); + DPRINTK("EXIT - early finish (good or error)\n"); + return; + +err_did: ata_qc_free(qc); - ata_bad_cdb(cmd, done); - DPRINTK("EXIT - badcmd\n"); +err_mem: + cmd->result = (DID_ERROR << 16); + done(cmd); + DPRINTK("EXIT - internal\n"); + return; } /** @@ -977,7 +1023,8 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * Mapping the response buffer, calling the command's handler, * and handling the handler's return value. This return value * indicates whether the handler wishes the SCSI command to be - * completed successfully, or not. + * completed successfully (0), or not (in which case cmd->result + * and sense buffer are assumed to be set). * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -996,12 +1043,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, rc = actor(args, rbuf, buflen); ata_scsi_rbuf_put(cmd, rbuf); - if (rc) - ata_bad_cdb(cmd, args->done); - else { + if (rc == 0) cmd->result = SAM_STAT_GOOD; - args->done(cmd); - } + args->done(cmd); } /** @@ -1307,8 +1351,16 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, * in the same manner) */ page_control = scsicmd[2] >> 6; - if ((page_control != 0) && (page_control != 3)) - return 1; + switch (page_control) { + case 0: /* current */ + break; /* supported */ + case 3: /* saved */ + goto saving_not_supp; + case 1: /* changeable */ + case 2: /* defaults */ + default: + goto invalid_fld; + } if (six_byte) output_len = 4; @@ -1339,7 +1391,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, break; default: /* invalid page code */ - return 1; + goto invalid_fld; } if (six_byte) { @@ -1352,6 +1404,16 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, } return 0; + +invalid_fld: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +saving_not_supp: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + /* "Saving parameters not supported" */ + return 1; } /** @@ -1496,13 +1558,7 @@ void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ILLEGAL_REQUEST; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); done(cmd); } @@ -1871,7 +1927,7 @@ void ata_scsi_simulate(u16 *id, case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else if (scsicmd[2] == 0x00) @@ -1881,7 +1937,7 @@ void ata_scsi_simulate(u16 *id, else if (scsicmd[2] == 0x83) ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case MODE_SENSE: @@ -1891,7 +1947,7 @@ void ata_scsi_simulate(u16 *id, case MODE_SELECT: /* unconditionally return */ case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case READ_CAPACITY: @@ -1902,7 +1958,7 @@ void ata_scsi_simulate(u16 *id, if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case REPORT_LUNS: @@ -1914,7 +1970,9 @@ void ata_scsi_simulate(u16 *id, /* all other commands */ default: - ata_bad_scsiop(cmd, done); + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); + /* "Invalid command operation code" */ + done(cmd); break; } } diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 4622e643ffd3..a18f2ac1d4a1 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -86,14 +86,4 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); -static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x20, 0x00); -} - -static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x24, 0x00); -} - #endif /* __LIBATA_H__ */ From 1fcce839a541ffcd50da99a1bfdfea594be0e3d3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 9 Oct 2005 09:31:33 -0400 Subject: [PATCH 0324/1939] [libata sata_sil24] nit pickings This patch removes unused NR_PORTS macro and adds termination entry to sil24_pci_tbl. Signed-off-by: Tejun Heo --- drivers/scsi/sata_sil24.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 693330bdc821..dffa13c84639 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -43,8 +43,6 @@ #define DRV_NAME "sata_sil24" #define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */ -#define NR_PORTS 4 - /* * Port request block (PRB) 32 bytes */ @@ -244,6 +242,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static struct pci_device_id sil24_pci_tbl[] = { { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, + { } /* terminate list */ }; static struct pci_driver sil24_pci_driver = { From 042c21fd2c3aa553907020131caa553a9da24589 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 9 Oct 2005 09:35:46 -0400 Subject: [PATCH 0325/1939] [libata sata_sil24] add support for 3131/3531 This patch adds support for sil_3131 and sil_3531. Both are identical to 3124 except that they have only one port. Bits 30 and 31 of ata_port_info->host_flags is used to encode available port numbers. Version number is bumped to 0.22. Edward Falk supplied all the necessary information and preliminary patch. Signed-off-by: Tejun Heo --- drivers/scsi/sata_sil24.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index dffa13c84639..19857814d69f 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -196,6 +196,7 @@ enum { /* board id */ BID_SIL3124 = 0, BID_SIL3132 = 1, + BID_SIL3131 = 2, IRQ_STAT_4PORTS = 0xf, }; @@ -242,6 +243,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static struct pci_device_id sil24_pci_tbl[] = { { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, + { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, { } /* terminate list */ }; @@ -300,13 +303,20 @@ static struct ata_port_operations sil24_ops = { .host_stop = sil24_host_stop, }; +/* + * Use bits 30-31 of host_flags to encode available port numbers. + * Current maxium is 4. + */ +#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) +#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) + static struct ata_port_info sil24_port_info[] = { /* sil_3124 */ { .sht = &sil24_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA, + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ @@ -317,7 +327,18 @@ static struct ata_port_info sil24_port_info[] = { .sht = &sil24_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA, + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3131/sil_3531 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ @@ -665,6 +686,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_port_info *pinfo = &sil24_port_info[board_id]; struct ata_probe_ent *probe_ent = NULL; struct sil24_host_priv *hpriv = NULL; void *host_base = NULL, *port_base = NULL; @@ -705,12 +727,12 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - probe_ent->sht = sil24_port_info[board_id].sht; - probe_ent->host_flags = sil24_port_info[board_id].host_flags; - probe_ent->pio_mask = sil24_port_info[board_id].pio_mask; - probe_ent->udma_mask = sil24_port_info[board_id].udma_mask; - probe_ent->port_ops = sil24_port_info[board_id].port_ops; - probe_ent->n_ports = (board_id == BID_SIL3124) ? 4 : 2; + probe_ent->sht = pinfo->sht; + probe_ent->host_flags = pinfo->host_flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags); probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; From e710245bb0f980adfb1dfe850e43761a8117c6be Mon Sep 17 00:00:00 2001 From: Andy Currid Date: Fri, 7 Oct 2005 08:53:39 -0700 Subject: [PATCH 0326/1939] [PATCH] Fix sata_nv handling of NVIDIA MCP51/55 Patch to fix sata_nv handling of NVIDIA MCP51/55 Signed-off-by: Andy Currid Signed-off-by: Jeff Garzik --- drivers/scsi/sata_nv.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 749ff92d8c63..9fa2535dd937 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -29,6 +29,8 @@ * NV-specific details such as register offsets, SATA phy location, * hotplug info, etc. * + * 0.09 + * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. * * 0.08 * - Added support for MCP51 and MCP55. @@ -132,9 +134,7 @@ enum nv_host_type GENERIC, NFORCE2, NFORCE3, - CK804, - MCP51, - MCP55 + CK804 }; static struct pci_device_id nv_pci_tbl[] = { @@ -153,13 +153,13 @@ static struct pci_device_id nv_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, + 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, MCP55 }, + 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 }, From 422fa08e538b649a9b80258950d2f8a202f45f19 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 9 Oct 2005 10:49:34 -0400 Subject: [PATCH 0327/1939] [libata passthru] update ATAPI completion for new error handling --- drivers/scsi/libata-scsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 698203bf4f69..617534b7a25e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1933,7 +1933,12 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat); if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); + /* FIXME: not quite right; we don't want the + * translation of taskfile registers into + * a sense descriptors, since that's only + * correct for ATA, not ATAPI + */ + ata_gen_ata_desc_sense(qc); else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); From b5bbeb23732196558222a2827092f5b7be8a7945 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 14:01:07 +1000 Subject: [PATCH 0328/1939] powerpc: Use SPRN_xxx rather than xxx for SPR numbers This changes symbols like HID0, SPRG3, SRR0, SRR1 etc. that refer to special purpose registers to SPRN_HID0, SPRN_SPRG3, etc. Using the SPRN_ symbols clutters the namespace less, and the forthcoming merge of asm/processor.h and asm/reg.h is going to remove the non-SPRN_ versions. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 196 +++++++++++++++++----------------- arch/ppc64/kernel/pmc.c | 4 +- 2 files changed, 100 insertions(+), 100 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index a36ee6ecbaea..7889ff8473b9 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -201,22 +201,22 @@ exception_marker: #define EX_CCR 60 #define EXCEPTION_PROLOG_PSERIES(area, label) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ + mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9; \ clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ - mfspr r11,SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_SRR0; /* save SRR0 */ \ ori r12,r12,(label)@l; /* virt addr of handler */ \ ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SRR0,r12; \ - mfspr r12,SRR1; /* and SRR1 */ \ - mtspr SRR1,r10; \ + mtspr SPRN_SRR0,r12; \ + mfspr r12,SPRN_SRR1; /* and SRR1 */ \ + mtspr SPRN_SRR1,r10; \ rfid; \ b . /* prevent speculative execution */ @@ -225,12 +225,12 @@ exception_marker: * This code runs with relocation on. */ #define EXCEPTION_PROLOG_ISERIES_1(area) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ + mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9 @@ -283,7 +283,7 @@ exception_marker: std r9,_LINK(r1); \ mfctr r10; /* save CTR in stackframe */ \ std r10,_CTR(r1); \ - mfspr r11,XER; /* save XER in stackframe */ \ + mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r11,_XER(r1); \ li r9,(n)+1; \ std r9,_TRAP(r1); /* set trap number */ \ @@ -300,7 +300,7 @@ exception_marker: .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) @@ -308,7 +308,7 @@ label##_pSeries: \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(area); \ EXCEPTION_PROLOG_ISERIES_2; \ @@ -318,7 +318,7 @@ label##_iSeries: \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ lbz r10,PACAPROCENABLED(r13); \ @@ -388,7 +388,7 @@ __start_interrupts: . = 0x200 _machine_check_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) @@ -396,18 +396,18 @@ _machine_check_pSeries: .globl data_access_pSeries data_access_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR srdi r13,r13,60 rlwimi r13,r12,16,0x20 mfcr r12 cmpwi r13,0x2c beq .do_stab_bolted_pSeries mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 END_FTR_SECTION_IFCLR(CPU_FTR_SLB) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) @@ -415,19 +415,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) .globl data_access_slb_pSeries data_access_slb_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 + mfspr r9,SPRN_SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,DAR + mfspr r12,SPRN_SRR1 /* and SRR1 */ + mfspr r3,SPRN_DAR b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x400, instruction_access) @@ -436,19 +436,19 @@ data_access_slb_pSeries: .globl instruction_access_slb_pSeries instruction_access_slb_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 + mfspr r9,SPRN_SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,SRR0 /* SRR0 is faulting address */ + mfspr r12,SPRN_SRR1 /* and SRR1 */ + mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) @@ -466,15 +466,15 @@ system_call_pSeries: RUNLATCH_ON(r9) mr r9,r13 mfmsr r10 - mfspr r13,SPRG3 - mfspr r11,SRR0 + mfspr r13,SPRN_SPRG3 + mfspr r11,SPRN_SRR0 clrrdi r12,r13,32 oris r12,r12,system_call_common@h ori r12,r12,system_call_common@l - mtspr SRR0,r12 + mtspr SPRN_SRR0,r12 ori r10,r10,MSR_IR|MSR_DR|MSR_RI - mfspr r12,SRR1 - mtspr SRR1,r10 + mfspr r12,SPRN_SRR1 + mtspr SPRN_SRR1,r10 rfid b . /* prevent speculative execution */ @@ -504,25 +504,25 @@ system_call_pSeries: .align 7 _GLOBAL(do_stab_bolted_pSeries) mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) /* * Vectors for the FWNMI option. Share common code. */ - .globl system_reset_fwnmi + .globl system_reset_fwnmi system_reset_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) + HMT_MEDIUM + mtspr SPRN_SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) - .globl machine_check_fwnmi + .globl machine_check_fwnmi machine_check_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + HMT_MEDIUM + mtspr SPRN_SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) #ifdef CONFIG_PPC_ISERIES /*** ISeries-LPAR interrupt handlers ***/ @@ -531,18 +531,18 @@ machine_check_fwnmi: .globl data_access_iSeries data_access_iSeries: - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR srdi r13,r13,60 rlwimi r13,r12,16,0x20 mfcr r12 cmpwi r13,0x2c beq .do_stab_bolted_iSeries mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 END_FTR_SECTION_IFCLR(CPU_FTR_SLB) EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_2 @@ -550,25 +550,25 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) .do_stab_bolted_iSeries: mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) EXCEPTION_PROLOG_ISERIES_2 b .do_stab_bolted .globl data_access_slb_iSeries data_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mfspr r3,DAR + mfspr r3,SPRN_DAR b .do_slb_miss STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) .globl instruction_access_slb_iSeries instruction_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) @@ -586,7 +586,7 @@ instruction_access_slb_iSeries: .globl system_call_iSeries system_call_iSeries: mr r9,r13 - mfspr r13,SPRG3 + mfspr r13,SPRN_SPRG3 EXCEPTION_PROLOG_ISERIES_2 b system_call_common @@ -596,7 +596,7 @@ system_call_iSeries: .globl system_reset_iSeries system_reset_iSeries: - mfspr r13,SPRG3 /* Get paca address */ + mfspr r13,SPRN_SPRG3 /* Get paca address */ mfmsr r24 ori r24,r24,MSR_RI mtmsrd r24 /* RI on */ @@ -639,7 +639,7 @@ iSeries_secondary_smp_loop: #endif /* CONFIG_SMP */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ - mfspr r13,SPRG3 /* Put r13 back ???? */ + mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ b 1b /* If SMP not configured, secondaries * loop forever */ @@ -656,8 +656,8 @@ hardware_interrupt_iSeries_masked: mtcrf 0x80,r9 /* Restore regs */ ld r11,PACALPPACA+LPPACASRR0(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 ld r9,PACA_EXGEN+EX_R9(r13) ld r10,PACA_EXGEN+EX_R10(r13) ld r11,PACA_EXGEN+EX_R11(r13) @@ -713,8 +713,8 @@ bad_stack: std r10,GPR1(r1) std r11,_NIP(r1) std r12,_MSR(r1) - mfspr r11,DAR - mfspr r12,DSISR + mfspr r11,SPRN_DAR + mfspr r12,SPRN_DSISR std r11,_DAR(r1) std r12,_DSISR(r1) mflr r10 @@ -766,8 +766,8 @@ fast_exception_return: clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ mtmsrd r10,1 - mtspr SRR1,r12 - mtspr SRR0,r11 + mtspr SPRN_SRR1,r12 + mtspr SPRN_SRR0,r11 REST_4GPRS(10, r1) ld r1,GPR1(r1) rfid @@ -788,9 +788,9 @@ unrecov_fer: .globl data_access_common data_access_common: RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */ - mfspr r10,DAR + mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR + mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) ld r3,PACA_EXGEN+EX_DAR(r13) @@ -821,9 +821,9 @@ hardware_interrupt_entry: .align 7 .globl alignment_common alignment_common: - mfspr r10,DAR + mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR + mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN) ld r3,PACA_EXGEN+EX_DAR(r13) @@ -1064,7 +1064,7 @@ _GLOBAL(do_stab_bolted) /* Hash to the primary group */ ld r10,PACASTABVIRT(r13) - mfspr r11,DAR + mfspr r11,SPRN_DAR srdi r11,r11,28 rldimi r10,r11,7,52 /* r10 = first ste of the group */ @@ -1106,7 +1106,7 @@ _GLOBAL(do_stab_bolted) 2: std r9,8(r10) /* Store the vsid part of the ste */ eieio - mfspr r11,DAR /* Get the new esid */ + mfspr r11,SPRN_DAR /* Get the new esid */ clrrdi r11,r11,28 /* Permits a full 32b of ESID */ ori r11,r11,0x90 /* Turn on valid and kp */ std r11,0(r10) /* Put new entry back into the stab */ @@ -1126,8 +1126,8 @@ _GLOBAL(do_stab_bolted) clrrdi r10,r10,2 mtmsrd r10,1 - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -1173,8 +1173,8 @@ _GLOBAL(do_slb_miss) .machine pop #ifdef CONFIG_PPC_ISERIES - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 #endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) @@ -1260,7 +1260,7 @@ _GLOBAL(pSeries_secondary_smp_init) mr r3,r24 /* not found, copy phys to r3 */ b .kexec_wait /* next kernel might do better */ -2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ +2: mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */ /* From now on, r24 is expected to be logical cpuid */ mr r24,r5 3: HMT_LOW @@ -1531,7 +1531,7 @@ _GLOBAL(pmac_secondary_start) LOADADDR(r4, paca) /* Get base vaddr of paca array */ mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r4 /* for this processor. */ - mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ + mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */ /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) @@ -1566,7 +1566,7 @@ _GLOBAL(__secondary_start) /* Initialize the page table pointer register. */ LOADADDR(r6,_SDR1) ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ + mtspr SPRN_SDR1,r6 /* set the htab location */ #endif /* Initialize the first segment table (or SLB) entry */ ld r3,PACASTABVIRT(r13) /* get addr of segment table */ @@ -1595,7 +1595,7 @@ _GLOBAL(__secondary_start) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ beq 98f /* branch if result is 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ beq 97f @@ -1619,8 +1619,8 @@ _GLOBAL(__secondary_start) #ifdef DO_SOFT_DISABLE ori r4,r4,MSR_EE #endif - mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 rfid b . /* prevent speculative execution */ @@ -1682,7 +1682,7 @@ _STATIC(start_here_multiplatform) #ifdef CONFIG_HMT /* Start up the second thread on cpu 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x34 /* Pulsar */ beq 90f @@ -1742,7 +1742,7 @@ _STATIC(start_here_multiplatform) mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ sub r13,r13,r26 /* convert to physical addr */ - mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ + mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */ /* Do very early kernel initializations, including initial hash table, * stab and slb setup before we turn on relocation. */ @@ -1759,7 +1759,7 @@ _STATIC(start_here_multiplatform) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ beq 98f /* branch if result is 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ beq 97f @@ -1783,12 +1783,12 @@ _STATIC(start_here_multiplatform) LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ sub r6,r6,r26 ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ + mtspr SPRN_SDR1,r6 /* set the htab location */ 98: LOADADDR(r3,.start_here_common) SET_REG_TO_CONST(r4, MSR_KERNEL) - mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 rfid b . /* prevent speculative execution */ #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -1819,7 +1819,7 @@ _STATIC(start_here_common) LOADADDR(r24, paca) /* Get base vaddr of paca array */ mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ - mtspr SPRG3,r13 + mtspr SPRN_SPRG3,r13 /* ptr to current */ LOADADDR(r4,init_task) @@ -1846,7 +1846,7 @@ _STATIC(start_here_common) _GLOBAL(hmt_init) #ifdef CONFIG_HMT LOADADDR(r5, hmt_thread_data) - mfspr r7,PVR + mfspr r7,SPRN_PVR srwi r7,r7,16 cmpwi r7,0x34 /* Pulsar */ beq 90f @@ -1855,10 +1855,10 @@ _GLOBAL(hmt_init) cmpwi r7,0x37 /* SStar */ beq 91f b 101f -90: mfspr r6,PIR +90: mfspr r6,SPRN_PIR andi. r6,r6,0x1f b 92f -91: mfspr r6,PIR +91: mfspr r6,SPRN_PIR andi. r6,r6,0x3ff 92: sldi r4,r24,3 stwx r6,r5,r4 @@ -1869,8 +1869,8 @@ __hmt_secondary_hold: LOADADDR(r5, hmt_thread_data) clrldi r5,r5,4 li r7,0 - mfspr r6,PIR - mfspr r8,PVR + mfspr r6,SPRN_PIR + mfspr r8,SPRN_PVR srwi r8,r8,16 cmpwi r8,0x34 bne 93f @@ -1896,19 +1896,19 @@ __hmt_secondary_hold: _GLOBAL(hmt_start_secondary) LOADADDR(r4,__hmt_secondary_hold) clrldi r4,r4,4 - mtspr NIADORM, r4 - mfspr r4, MSRDORM + mtspr SPRN_NIADORM, r4 + mfspr r4, SPRN_MSRDORM li r5, -65 and r4, r4, r5 - mtspr MSRDORM, r4 + mtspr SPRN_MSRDORM, r4 lis r4,0xffef ori r4,r4,0x7403 - mtspr TSC, r4 + mtspr SPRN_TSC, r4 li r4,0x1f4 - mtspr TST, r4 - mfspr r4, HID0 + mtspr SPRN_TST, r4 + mfspr r4, SPRN_HID0 ori r4, r4, 0x1 - mtspr HID0, r4 + mtspr SPRN_HID0, r4 mfspr r4, SPRN_CTRLF oris r4, r4, 0x40 mtspr SPRN_CTRLT, r4 diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c index 63d9481c3ec2..944d7df7935f 100644 --- a/arch/ppc64/kernel/pmc.c +++ b/arch/ppc64/kernel/pmc.c @@ -70,7 +70,7 @@ void power4_enable_pmcs(void) { unsigned long hid0; - hid0 = mfspr(HID0); + hid0 = mfspr(SPRN_HID0); hid0 |= 1UL << (63 - 20); /* POWER4 requires the following sequence */ @@ -83,6 +83,6 @@ void power4_enable_pmcs(void) "mfspr %0, %1\n" "mfspr %0, %1\n" "mfspr %0, %1\n" - "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): + "isync" : "=&r" (hid0) : "i" (SPRN_HID0), "0" (hid0): "memory"); } From b60fc8bbd2d0ea2a9b1fc7271d521fcf47f27bfd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 14:14:55 +1000 Subject: [PATCH 0329/1939] powerpc: Make some #includes explicit. In preparation for merging processor.h, this adds some explicit but won't be after the merge. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/irq.c | 1 + arch/ppc/kernel/pci.c | 1 + arch/ppc/kernel/smp.c | 1 + arch/ppc64/kernel/rtas.c | 1 + arch/ppc64/kernel/vdso64/sigtramp.S | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 8843f3af230f..772e428aaa59 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -57,6 +57,7 @@ #include #include #include +#include #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index b5cf52f5909e..6600fd485b50 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -21,6 +21,7 @@ #include #include #include +#include #undef DEBUG diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index a8cc96b0d332..801c793fdec8 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -34,6 +34,7 @@ #include #include #include +#include volatile int smp_commenced; int smp_tb_synchronized; diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c index 5e8eb33b8e54..36adab591bd3 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/ppc64/kernel/rtas.c @@ -30,6 +30,7 @@ #include #include #include +#include struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; diff --git a/arch/ppc64/kernel/vdso64/sigtramp.S b/arch/ppc64/kernel/vdso64/sigtramp.S index 8ae8f205e470..31b604ab56de 100644 --- a/arch/ppc64/kernel/vdso64/sigtramp.S +++ b/arch/ppc64/kernel/vdso64/sigtramp.S @@ -15,6 +15,7 @@ #include #include #include +#include /* XXX for __SIGNAL_FRAMESIZE */ .text From 9f04b9e327c495f8ddbf89c08da6cbe626e1b1b3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 14:19:43 +1000 Subject: [PATCH 0330/1939] powerpc: Merged processor.h. This adds register definitions from the ppc64 processor.h to reg.h, and makes a single merged processor.h. I moved __is_processor from the ppc64 system.h to the merged reg.h along with the PVR register constants. Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/processor.h | 189 +++++-- include/asm-powerpc/reg.h | 281 +++++++-- include/asm-ppc64/processor.h | 567 ------------------- include/asm-ppc64/system.h | 7 - 4 files changed, 355 insertions(+), 689 deletions(-) rename include/{asm-ppc => asm-powerpc}/processor.h (51%) delete mode 100644 include/asm-ppc64/processor.h diff --git a/include/asm-ppc/processor.h b/include/asm-powerpc/processor.h similarity index 51% rename from include/asm-ppc/processor.h rename to include/asm-powerpc/processor.h index b05b5d9cae20..9592f533e058 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-powerpc/processor.h @@ -1,21 +1,28 @@ -#ifdef __KERNEL__ -#ifndef __ASM_PPC_PROCESSOR_H -#define __ASM_PPC_PROCESSOR_H +#ifndef _ASM_POWERPC_PROCESSOR_H +#define _ASM_POWERPC_PROCESSOR_H /* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). + * Copyright (C) 2001 PPC 64 Team, 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. */ -#define current_text_addr() ({ __label__ _l; _l: &&_l;}) #include -#include - -#include -#include -#include #include +#ifndef __ASSEMBLY__ +#include +#include +#include +#ifdef CONFIG_PPC64 +#include +#endif + +#ifdef CONFIG_PPC32 +/* 32-bit platform types */ /* We only need to define a new _MACH_xxx for machines which are part of * a configuration which supports more than one type of different machine. * This is currently limited to CONFIG_PPC_MULTIPLATFORM and CHRP/PReP/PMac. @@ -36,20 +43,6 @@ #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ -#define _GLOBAL(n)\ - .stabs __stringify(n:F-1),N_FUN,0,0,n;\ - .globl n;\ -n: - -/* - * this is the minimum allowable io space due to the location - * of the io areas on prep (first one at 0x80000000) but - * as soon as I get around to remapping the io areas with the BATs - * to match the mac we can raise this. -- Cort - */ -#define TASK_SIZE (CONFIG_TASK_SIZE) - -#ifndef __ASSEMBLY__ #ifdef CONFIG_PPC_MULTIPLATFORM extern int _machine; @@ -67,17 +60,49 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin; #else #define _machine 0 #endif /* CONFIG_PPC_MULTIPLATFORM */ +#endif /* CONFIG_PPC32 */ + +#ifdef CONFIG_PPC64 +/* Platforms supported by PPC64 */ +#define PLATFORM_PSERIES 0x0100 +#define PLATFORM_PSERIES_LPAR 0x0101 +#define PLATFORM_ISERIES_LPAR 0x0201 +#define PLATFORM_LPAR 0x0001 +#define PLATFORM_POWERMAC 0x0400 +#define PLATFORM_MAPLE 0x0500 +#define PLATFORM_BPA 0x1000 + +/* Compatibility with drivers coming from PPC32 world */ +#define _machine (systemcfg->platform) +#define _MACH_Pmac PLATFORM_POWERMAC +#endif + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +/* Macros for adjusting thread priority (hardware multi-threading) */ +#define HMT_very_low() asm volatile("or 31,31,31 # very low priority") +#define HMT_low() asm volatile("or 1,1,1 # low priority") +#define HMT_medium_low() asm volatile("or 6,6,6 # medium low priority") +#define HMT_medium() asm volatile("or 2,2,2 # medium priority") +#define HMT_medium_high() asm volatile("or 5,5,5 # medium high priority") +#define HMT_high() asm volatile("or 3,3,3 # high priority") + +#ifdef __KERNEL__ + +extern int have_of; struct task_struct; -void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); +void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); void release_thread(struct task_struct *); /* Prepare to copy thread state - unlazy all lazy status */ extern void prepare_to_copy(struct task_struct *tsk); -/* - * Create a new kernel thread. - */ +/* Create a new kernel thread. */ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* Lazy FPU handling on uni-processor */ @@ -85,10 +110,37 @@ extern struct task_struct *last_task_used_math; extern struct task_struct *last_task_used_altivec; extern struct task_struct *last_task_used_spe; +#ifdef CONFIG_PPC32 +#define TASK_SIZE (CONFIG_TASK_SIZE) + /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3) +#endif + +#ifdef CONFIG_PPC64 +/* 64-bit user address space is 44-bits (16TB user VM) */ +#define TASK_SIZE_USER64 (0x0000100000000000UL) + +/* + * 32-bit user address space is 4GB - 1 page + * (this 1 page is needed so referencing of 0xFFFFFFFF generates EFAULT + */ +#define TASK_SIZE_USER32 (0x0000000100000000UL - (1*PAGE_SIZE)) + +#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ + TASK_SIZE_USER32 : TASK_SIZE_USER64) + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4)) +#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4)) + +#define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)) ? \ + TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 ) +#endif typedef struct { unsigned long seg; @@ -96,18 +148,31 @@ typedef struct { struct thread_struct { unsigned long ksp; /* Kernel stack pointer */ +#ifdef CONFIG_PPC64 + unsigned long ksp_vsid; +#endif struct pt_regs *regs; /* Pointer to saved register state */ mm_segment_t fs; /* for get_fs() validation */ +#ifdef CONFIG_PPC32 void *pgdir; /* root of page-table tree */ - int fpexc_mode; /* floating-point exception mode */ signed long last_syscall; +#endif #if defined(CONFIG_4xx) || defined (CONFIG_BOOKE) unsigned long dbcr0; /* debug control register values */ unsigned long dbcr1; #endif double fpr[32]; /* Complete floating point set */ +#ifdef CONFIG_PPC32 unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ +#endif unsigned long fpscr; /* Floating point status */ + int fpexc_mode; /* floating-point exception mode */ +#ifdef CONFIG_PPC64 + unsigned long start_tb; /* Start purr when proc switched in */ + unsigned long accum_tb; /* Total accumilated purr for process */ + unsigned long vdso_base; /* base of the vDSO library */ +#endif + unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute((aligned(16))); @@ -128,51 +193,58 @@ struct thread_struct { #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) + +#ifdef CONFIG_PPC32 #define INIT_THREAD { \ .ksp = INIT_SP, \ .fs = KERNEL_DS, \ .pgdir = swapper_pg_dir, \ .fpexc_mode = MSR_FE0 | MSR_FE1, \ } +#else +#define INIT_THREAD { \ + .ksp = INIT_SP, \ + .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ + .fs = KERNEL_DS, \ + .fpr = {0}, \ + .fpscr = 0, \ + .fpexc_mode = MSR_FE0|MSR_FE1, \ +} +#endif /* * Return saved PC of a blocked thread. For now, this is the "user" PC */ -#define thread_saved_pc(tsk) \ - ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) +#define thread_saved_pc(tsk) \ + ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) -#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0) +#define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) +#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0) /* Get/set floating-point exception mode */ -#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr)) -#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val)) +#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr)) +#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val)) extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr); extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val); -static inline unsigned int __unpack_fe01(unsigned int msr_bits) +static inline unsigned int __unpack_fe01(unsigned long msr_bits) { return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8); } -static inline unsigned int __pack_fe01(unsigned int fpmode) +static inline unsigned long __pack_fe01(unsigned int fpmode) { return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1); } -/* in process.c - for early bootup debug -- Cort */ -int ll_printk(const char *, ...); -void ll_puts(const char *); - -/* In misc.c */ -void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); - -#define have_of (_machine == _MACH_chrp || _machine == _MACH_Pmac) - +#ifdef CONFIG_PPC64 +#define cpu_relax() do { HMT_low(); HMT_medium(); barrier(); } while (0) +#else #define cpu_relax() barrier() +#endif /* * Prefetch macros. @@ -181,21 +253,28 @@ void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); #define ARCH_HAS_PREFETCHW #define ARCH_HAS_SPINLOCK_PREFETCH -extern inline void prefetch(const void *x) +static inline void prefetch(const void *x) { - __asm__ __volatile__ ("dcbt 0,%0" : : "r" (x)); + if (unlikely(!x)) + return; + + __asm__ __volatile__ ("dcbt 0,%0" : : "r" (x)); } -extern inline void prefetchw(const void *x) +static inline void prefetchw(const void *x) { - __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x)); + if (unlikely(!x)) + return; + + __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x)); } #define spin_lock_prefetch(x) prefetchw(x) -extern int emulate_altivec(struct pt_regs *regs); +#ifdef CONFIG_PPC64 +#define HAVE_ARCH_PICK_MMAP_LAYOUT +#endif -#endif /* !__ASSEMBLY__ */ - -#endif /* __ASM_PPC_PROCESSOR_H */ #endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_POWERPC_PROCESSOR_H */ diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 1402a2dedffb..ff619630dff9 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -6,53 +6,95 @@ * Implementations of the PowerPC Architecture (a.k.a. Green Book) here. */ -#ifndef _ASM_POWERPC_REGS_H -#define _ASM_POWERPC_REGS_H +#ifndef _ASM_POWERPC_REG_H +#define _ASM_POWERPC_REG_H #ifdef __KERNEL__ #include +#include /* Pickup Book E specific registers. */ #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) #include #endif -/* Machine State Register (MSR) Fields */ -#define MSR_SF (1<<63) -#define MSR_ISF (1<<61) -#define MSR_VEC (1<<25) /* Enable AltiVec */ -#define MSR_POW (1<<18) /* Enable Power Management */ -#define MSR_WE (1<<18) /* Wait State Enable */ -#define MSR_TGPR (1<<17) /* TLB Update registers in use */ -#define MSR_CE (1<<17) /* Critical Interrupt Enable */ -#define MSR_ILE (1<<16) /* Interrupt Little Endian */ -#define MSR_EE (1<<15) /* External Interrupt Enable */ -#define MSR_PR (1<<14) /* Problem State / Privilege Level */ -#define MSR_FP (1<<13) /* Floating Point enable */ -#define MSR_ME (1<<12) /* Machine Check Enable */ -#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ -#define MSR_SE (1<<10) /* Single Step */ -#define MSR_BE (1<<9) /* Branch Trace */ -#define MSR_DE (1<<9) /* Debug Exception Enable */ -#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ -#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ -#define MSR_IR (1<<5) /* Instruction Relocate */ -#define MSR_DR (1<<4) /* Data Relocate */ -#define MSR_PE (1<<3) /* Protection Enable */ -#define MSR_PX (1<<2) /* Protection Exclusive Mode */ -#define MSR_RI (1<<1) /* Recoverable Exception */ -#define MSR_LE (1<<0) /* Little Endian */ +#define MSR_SF_LG 63 /* Enable 64 bit mode */ +#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */ +#define MSR_HV_LG 60 /* Hypervisor state */ +#define MSR_VEC_LG 25 /* Enable AltiVec */ +#define MSR_POW_LG 18 /* Enable Power Management */ +#define MSR_WE_LG 18 /* Wait State Enable */ +#define MSR_TGPR_LG 17 /* TLB Update registers in use */ +#define MSR_CE_LG 17 /* Critical Interrupt Enable */ +#define MSR_ILE_LG 16 /* Interrupt Little Endian */ +#define MSR_EE_LG 15 /* External Interrupt Enable */ +#define MSR_PR_LG 14 /* Problem State / Privilege Level */ +#define MSR_FP_LG 13 /* Floating Point enable */ +#define MSR_ME_LG 12 /* Machine Check Enable */ +#define MSR_FE0_LG 11 /* Floating Exception mode 0 */ +#define MSR_SE_LG 10 /* Single Step */ +#define MSR_BE_LG 9 /* Branch Trace */ +#define MSR_DE_LG 9 /* Debug Exception Enable */ +#define MSR_FE1_LG 8 /* Floating Exception mode 1 */ +#define MSR_IP_LG 6 /* Exception prefix 0x000/0xFFF */ +#define MSR_IR_LG 5 /* Instruction Relocate */ +#define MSR_DR_LG 4 /* Data Relocate */ +#define MSR_PE_LG 3 /* Protection Enable */ +#define MSR_PX_LG 2 /* Protection Exclusive Mode */ +#define MSR_PMM_LG 2 /* Performance monitor */ +#define MSR_RI_LG 1 /* Recoverable Exception */ +#define MSR_LE_LG 0 /* Little Endian */ +#ifdef __ASSEMBLY__ +#define __MASK(X) (1<<(X)) +#else +#define __MASK(X) (1UL<<(X)) +#endif + +#define MSR_SF __MASK(MSR_SF_LG) /* Enable 64 bit mode */ +#define MSR_ISF __MASK(MSR_ISF_LG) /* Interrupt 64b mode valid on 630 */ +#define MSR_HV __MASK(MSR_HV_LG) /* Hypervisor state */ +#define MSR_VEC __MASK(MSR_VEC_LG) /* Enable AltiVec */ +#define MSR_POW __MASK(MSR_POW_LG) /* Enable Power Management */ +#define MSR_WE __MASK(MSR_WE_LG) /* Wait State Enable */ +#define MSR_TGPR __MASK(MSR_TGPR_LG) /* TLB Update registers in use */ +#define MSR_CE __MASK(MSR_CE_LG) /* Critical Interrupt Enable */ +#define MSR_ILE __MASK(MSR_ILE_LG) /* Interrupt Little Endian */ +#define MSR_EE __MASK(MSR_EE_LG) /* External Interrupt Enable */ +#define MSR_PR __MASK(MSR_PR_LG) /* Problem State / Privilege Level */ +#define MSR_FP __MASK(MSR_FP_LG) /* Floating Point enable */ +#define MSR_ME __MASK(MSR_ME_LG) /* Machine Check Enable */ +#define MSR_FE0 __MASK(MSR_FE0_LG) /* Floating Exception mode 0 */ +#define MSR_SE __MASK(MSR_SE_LG) /* Single Step */ +#define MSR_BE __MASK(MSR_BE_LG) /* Branch Trace */ +#define MSR_DE __MASK(MSR_DE_LG) /* Debug Exception Enable */ +#define MSR_FE1 __MASK(MSR_FE1_LG) /* Floating Exception mode 1 */ +#define MSR_IP __MASK(MSR_IP_LG) /* Exception prefix 0x000/0xFFF */ +#define MSR_IR __MASK(MSR_IR_LG) /* Instruction Relocate */ +#define MSR_DR __MASK(MSR_DR_LG) /* Data Relocate */ +#define MSR_PE __MASK(MSR_PE_LG) /* Protection Enable */ +#define MSR_PX __MASK(MSR_PX_LG) /* Protection Exclusive Mode */ +#define MSR_PMM __MASK(MSR_PMM_LG) /* Performance monitor */ +#define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */ +#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_USER32 MSR_ | MSR_PR | MSR_EE +#define MSR_USER64 MSR_USER32 | MSR_SF + +#else /* 32-bit */ /* Default MSR for kernel mode. */ #ifdef CONFIG_APUS_FAST_EXCEPT #define MSR_KERNEL (MSR_ME|MSR_IP|MSR_RI|MSR_IR|MSR_DR) -#endif - -#ifndef MSR_KERNEL +#else #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) #endif #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) +#endif /* Floating Point Status and Control Register (FPSCR) Fields */ #define FPSCR_FX 0x80000000 /* FPU exception summary */ @@ -85,6 +127,9 @@ /* Special Purpose Registers (SPRNs)*/ #define SPRN_CTR 0x009 /* Count Register */ +#define SPRN_CTRLF 0x088 +#define SPRN_CTRLT 0x098 +#define CTRL_RUNLATCH 0x1 #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ #define DABR_TRANSLATION (1UL << 2) #define SPRN_DAR 0x013 /* Data Address Register */ @@ -193,6 +238,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_TSCR 0x399 /* Thread switch control on BE */ +#define SPRN_TTR 0x39A /* Thread switch timeout on BE */ +#define TSCR_DEC_ENABLE 0x200000 /* Decrementer Interrupt */ +#define TSCR_EE_ENABLE 0x100000 /* External Interrupt */ +#define TSCR_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 */ @@ -276,22 +331,18 @@ #define L3CR_L3DO 0x00000040 /* L3 data only mode */ #define L3CR_PMEN 0x00000004 /* L3 private memory enable */ #define L3CR_PMSIZ 0x00000001 /* L3 private memory size */ + #define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */ #define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */ #define SPRN_LDSTCR 0x3f8 /* Load/Store control register */ #define SPRN_LDSTDB 0x3f4 /* */ #define SPRN_LR 0x008 /* Link Register */ -#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ -#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ #ifndef SPRN_PIR #define SPRN_PIR 0x3FF /* Processor Identification Register */ #endif -#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ -#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ -#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ -#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ #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_PVR 0x11F /* Processor Version Register */ #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ #define SPRN_SDA 0x3BF /* Sampled Data Address Register */ @@ -333,6 +384,52 @@ #define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ +/* Performance monitor SPRs */ +#ifdef CONFIG_PPC64 +#define SPRN_MMCR0 795 +#define MMCR0_FC 0x80000000UL /* freeze counters */ +#define MMCR0_FCS 0x40000000UL /* freeze in supervisor state */ +#define MMCR0_KERNEL_DISABLE MMCR0_FCS +#define MMCR0_FCP 0x20000000UL /* freeze in problem state */ +#define MMCR0_PROBLEM_DISABLE MMCR0_FCP +#define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */ +#define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */ +#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */ +#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */ +#define MMCR0_TBEE 0x00400000UL /* time base exception enable */ +#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/ +#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/ +#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */ +#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */ +#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */ +#define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */ +#define MMCR0_FCTA 0x00000004UL /* freeze counters in tags active mode */ +#define MMCR0_FCWAIT 0x00000002UL /* freeze counter in WAIT state */ +#define MMCR0_FCHV 0x00000001UL /* freeze conditions in hypervisor mode */ +#define SPRN_MMCR1 798 +#define SPRN_MMCRA 0x312 +#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 SPRN_PMC1 787 +#define SPRN_PMC2 788 +#define SPRN_PMC3 789 +#define SPRN_PMC4 790 +#define SPRN_PMC5 791 +#define SPRN_PMC6 792 +#define SPRN_PMC7 793 +#define SPRN_PMC8 794 +#define SPRN_SIAR 780 +#define SPRN_SDAR 781 + +#else /* 32-bit */ +#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ +#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ +#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ +#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ +#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ +#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ + /* Bit definitions for MMCR0 and PMC1 / PMC2. */ #define MMCR0_PMC1_CYCLES (1 << 7) #define MMCR0_PMC1_ICACHEMISS (5 << 7) @@ -342,14 +439,15 @@ #define MMCR0_PMC2_ITLB 0x7 #define MMCR0_PMC2_LOADMISSTIME 0x5 #define MMCR0_PMXE (1 << 26) - -/* Processor Version Register */ +#endif /* Processor Version Register (PVR) field extraction */ #define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ #define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ +#define __is_processor(pv) (PVR_VER(mfspr(SPRN_PVR)) == (pv)) + /* * IBM has further subdivided the standard PowerPC 16-bit version and * revision subfields of the PVR for the PowerPC 403s into the following: @@ -405,42 +503,105 @@ #define PVR_8245 0x80811014 #define PVR_8260 PVR_8240 -#if 0 -/* Segment Registers */ -#define SR0 0 -#define SR1 1 -#define SR2 2 -#define SR3 3 -#define SR4 4 -#define SR5 5 -#define SR6 6 -#define SR7 7 -#define SR8 8 -#define SR9 9 -#define SR10 10 -#define SR11 11 -#define SR12 12 -#define SR13 13 -#define SR14 14 -#define SR15 15 -#endif +/* 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_970 0x0039 +#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 + +/* + * Number of entries in the SLB. If this ever changes we should handle + * it with a use a cpu feature fixup. + */ +#define SLB_NUM_ENTRIES 64 /* Macros for setting and retrieving special purpose registers */ #ifndef __ASSEMBLY__ -#define mfmsr() ({unsigned int rval; \ +#define mfmsr() ({unsigned long rval; \ asm volatile("mfmsr %0" : "=r" (rval)); rval;}) +#ifdef CONFIG_PPC64 +#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ + : : "r" (v)) +#define mtmsrd(v) __mtmsrd((v), 0) +#else #define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) +#endif -#define mfspr(rn) ({unsigned int rval; \ +#define mfspr(rn) ({unsigned long rval; \ asm volatile("mfspr %0," __stringify(rn) \ : "=r" (rval)); rval;}) #define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) +#define mftb() ({unsigned long rval; \ + asm volatile("mftb %0" : "=r" (rval)); rval;}) +#define mftbl() ({unsigned long rval; \ + asm volatile("mftbl %0" : "=r" (rval)); rval;}) + +#define mttbl(v) asm volatile("mttbl %0":: "r"(v)) +#define mttbu(v) asm volatile("mttbu %0":: "r"(v)) + +#ifdef CONFIG_PPC32 #define mfsrin(v) ({unsigned int rval; \ asm volatile("mfsrin %0,%1" : "=r" (rval) : "r" (v)); \ rval;}) +#endif #define proc_trap() asm volatile("trap") + +#ifdef CONFIG_PPC64 +static inline void ppc64_runlatch_on(void) +{ + unsigned long ctrl; + + if (cpu_has_feature(CPU_FTR_CTRL)) { + ctrl = mfspr(SPRN_CTRLF); + ctrl |= CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); + } +} + +static inline void ppc64_runlatch_off(void) +{ + unsigned long ctrl; + + if (cpu_has_feature(CPU_FTR_CTRL)) { + ctrl = mfspr(SPRN_CTRLF); + ctrl &= ~CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); + } +} + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mttbl(0); + mttbu(upper); + mttbl(lower); +} +#endif + +#define __get_SP() ({unsigned long sp; \ + asm volatile("mr %0,1": "=r" (sp)); sp;}) + +#else /* __ASSEMBLY__ */ + +#define RUNLATCH_ON(REG) \ +BEGIN_FTR_SECTION \ + mfspr (REG),SPRN_CTRLF; \ + ori (REG),(REG),CTRL_RUNLATCH; \ + mtspr SPRN_CTRLT,(REG); \ +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ -#endif /* _ASM_POWERPC_REGS_H */ +#endif /* _ASM_POWERPC_REG_H */ diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h deleted file mode 100644 index 6447fbee7d69..000000000000 --- a/include/asm-ppc64/processor.h +++ /dev/null @@ -1,567 +0,0 @@ -#ifndef __ASM_PPC64_PROCESSOR_H -#define __ASM_PPC64_PROCESSOR_H - -/* - * Copyright (C) 2001 PPC 64 Team, 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 -#ifndef __ASSEMBLY__ -#include -#include -#include -#include -#endif -#include -#include -#include -#include - -/* Machine State Register (MSR) Fields */ -#define MSR_SF_LG 63 /* Enable 64 bit mode */ -#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */ -#define MSR_HV_LG 60 /* Hypervisor state */ -#define MSR_VEC_LG 25 /* Enable AltiVec */ -#define MSR_POW_LG 18 /* Enable Power Management */ -#define MSR_WE_LG 18 /* Wait State Enable */ -#define MSR_TGPR_LG 17 /* TLB Update registers in use */ -#define MSR_CE_LG 17 /* Critical Interrupt Enable */ -#define MSR_ILE_LG 16 /* Interrupt Little Endian */ -#define MSR_EE_LG 15 /* External Interrupt Enable */ -#define MSR_PR_LG 14 /* Problem State / Privilege Level */ -#define MSR_FP_LG 13 /* Floating Point enable */ -#define MSR_ME_LG 12 /* Machine Check Enable */ -#define MSR_FE0_LG 11 /* Floating Exception mode 0 */ -#define MSR_SE_LG 10 /* Single Step */ -#define MSR_BE_LG 9 /* Branch Trace */ -#define MSR_DE_LG 9 /* Debug Exception Enable */ -#define MSR_FE1_LG 8 /* Floating Exception mode 1 */ -#define MSR_IP_LG 6 /* Exception prefix 0x000/0xFFF */ -#define MSR_IR_LG 5 /* Instruction Relocate */ -#define MSR_DR_LG 4 /* Data Relocate */ -#define MSR_PE_LG 3 /* Protection Enable */ -#define MSR_PX_LG 2 /* Protection Exclusive Mode */ -#define MSR_PMM_LG 2 /* Performance monitor */ -#define MSR_RI_LG 1 /* Recoverable Exception */ -#define MSR_LE_LG 0 /* Little Endian */ - -#ifdef __ASSEMBLY__ -#define __MASK(X) (1<<(X)) -#else -#define __MASK(X) (1UL<<(X)) -#endif - -#define MSR_SF __MASK(MSR_SF_LG) /* Enable 64 bit mode */ -#define MSR_ISF __MASK(MSR_ISF_LG) /* Interrupt 64b mode valid on 630 */ -#define MSR_HV __MASK(MSR_HV_LG) /* Hypervisor state */ -#define MSR_VEC __MASK(MSR_VEC_LG) /* Enable AltiVec */ -#define MSR_POW __MASK(MSR_POW_LG) /* Enable Power Management */ -#define MSR_WE __MASK(MSR_WE_LG) /* Wait State Enable */ -#define MSR_TGPR __MASK(MSR_TGPR_LG) /* TLB Update registers in use */ -#define MSR_CE __MASK(MSR_CE_LG) /* Critical Interrupt Enable */ -#define MSR_ILE __MASK(MSR_ILE_LG) /* Interrupt Little Endian */ -#define MSR_EE __MASK(MSR_EE_LG) /* External Interrupt Enable */ -#define MSR_PR __MASK(MSR_PR_LG) /* Problem State / Privilege Level */ -#define MSR_FP __MASK(MSR_FP_LG) /* Floating Point enable */ -#define MSR_ME __MASK(MSR_ME_LG) /* Machine Check Enable */ -#define MSR_FE0 __MASK(MSR_FE0_LG) /* Floating Exception mode 0 */ -#define MSR_SE __MASK(MSR_SE_LG) /* Single Step */ -#define MSR_BE __MASK(MSR_BE_LG) /* Branch Trace */ -#define MSR_DE __MASK(MSR_DE_LG) /* Debug Exception Enable */ -#define MSR_FE1 __MASK(MSR_FE1_LG) /* Floating Exception mode 1 */ -#define MSR_IP __MASK(MSR_IP_LG) /* Exception prefix 0x000/0xFFF */ -#define MSR_IR __MASK(MSR_IR_LG) /* Instruction Relocate */ -#define MSR_DR __MASK(MSR_DR_LG) /* Data Relocate */ -#define MSR_PE __MASK(MSR_PE_LG) /* Protection Enable */ -#define MSR_PX __MASK(MSR_PX_LG) /* Protection Exclusive Mode */ -#define MSR_PMM __MASK(MSR_PMM_LG) /* Performance monitor */ -#define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */ -#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */ - -#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF -#define MSR_KERNEL MSR_ | MSR_SF | MSR_HV - -#define MSR_USER32 MSR_ | MSR_PR | MSR_EE -#define MSR_USER64 MSR_USER32 | MSR_SF - -/* Floating Point Status and Control Register (FPSCR) Fields */ - -#define FPSCR_FX 0x80000000 /* FPU exception summary */ -#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ -#define FPSCR_VX 0x20000000 /* Invalid operation summary */ -#define FPSCR_OX 0x10000000 /* Overflow exception summary */ -#define FPSCR_UX 0x08000000 /* Underflow exception summary */ -#define FPSCR_ZX 0x04000000 /* Zero-divide exception summary */ -#define FPSCR_XX 0x02000000 /* Inexact exception summary */ -#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ -#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ -#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ -#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ -#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ -#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ -#define FPSCR_FR 0x00040000 /* Fraction rounded */ -#define FPSCR_FI 0x00020000 /* Fraction inexact */ -#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ -#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ -#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ -#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ -#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ -#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ -#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ -#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ -#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ -#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ -#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ -#define FPSCR_RN 0x00000003 /* FPU rounding control */ - -/* Special Purpose Registers (SPRNs)*/ - -#define SPRN_CTR 0x009 /* Count Register */ -#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ -#define DABR_TRANSLATION (1UL << 2) -#define SPRN_DAR 0x013 /* Data Address Register */ -#define SPRN_DEC 0x016 /* Decrement 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 */ -#define DSISR_DABRMATCH 0x00400000 /* hit data breakpoint */ -#define DSISR_NOSEGMENT 0x00200000 /* STAB/SLB miss */ -#define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */ -#define SPRN_MSRDORM 0x3F1 /* Hardware Implementation Register 1 */ -#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ -#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ -#define SPRN_NIADORM 0x3F3 /* Hardware Implementation Register 2 */ -#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_TSCR 0x399 /* Thread switch control on BE */ -#define SPRN_TTR 0x39A /* Thread switch timeout on BE */ -#define TSCR_DEC_ENABLE 0x200000 /* Decrementer Interrupt */ -#define TSCR_EE_ENABLE 0x100000 /* External Interrupt */ -#define TSCR_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_L2CR 0x3F9 /* Level 2 Cache Control Regsiter */ -#define SPRN_LR 0x008 /* Link Register */ -#define SPRN_PIR 0x3FF /* Processor Identification Register */ -#define SPRN_PIT 0x3DB /* Programmable Interval Timer */ -#define SPRN_PURR 0x135 /* Processor Utilization of Resources Register */ -#define SPRN_PVR 0x11F /* Processor Version Register */ -#define SPRN_RPA 0x3D6 /* Required Physical Address Register */ -#define SPRN_SDA 0x3BF /* Sampled Data Address Register */ -#define SPRN_SDR1 0x019 /* MMU Hash Base Register */ -#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ -#define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ -#define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ -#define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ -#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ -#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ -#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ -#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */ -#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */ -#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, W/O) */ -#define SPRN_TBWU 0x11D /* Time Base Write Upper Register (super, W/O) */ -#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ -#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ -#define SPRN_XER 0x001 /* Fixed Point Exception Register */ -#define SPRN_VRSAVE 0x100 /* Vector save */ -#define SPRN_CTRLF 0x088 -#define SPRN_CTRLT 0x098 -#define CTRL_RUNLATCH 0x1 - -/* Performance monitor SPRs */ -#define SPRN_SIAR 780 -#define SPRN_SDAR 781 -#define SPRN_MMCRA 786 -#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 SPRN_PMC1 787 -#define SPRN_PMC2 788 -#define SPRN_PMC3 789 -#define SPRN_PMC4 790 -#define SPRN_PMC5 791 -#define SPRN_PMC6 792 -#define SPRN_PMC7 793 -#define SPRN_PMC8 794 -#define SPRN_MMCR0 795 -#define MMCR0_FC 0x80000000UL /* freeze counters. set to 1 on a perfmon exception */ -#define MMCR0_FCS 0x40000000UL /* freeze in supervisor state */ -#define MMCR0_KERNEL_DISABLE MMCR0_FCS -#define MMCR0_FCP 0x20000000UL /* freeze in problem state */ -#define MMCR0_PROBLEM_DISABLE MMCR0_FCP -#define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */ -#define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */ -#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */ -#define MMCR0_FCECE 0x02000000UL /* freeze counters on enabled condition or event */ -/* time base exception enable */ -#define MMCR0_TBEE 0x00400000UL /* time base exception enable */ -#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/ -#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/ -#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */ -#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */ -#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */ -#define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */ -#define MMCR0_FCTA 0x00000004UL /* freeze counters in tags active mode */ -#define MMCR0_FCWAIT 0x00000002UL /* freeze counter in WAIT state */ -#define MMCR0_FCHV 0x00000001UL /* freeze conditions in hypervisor mode */ -#define SPRN_MMCR1 798 - -/* Short-hand versions for a number of the above SPRNs */ - -#define CTR SPRN_CTR /* Counter Register */ -#define DAR SPRN_DAR /* Data Address Register */ -#define DABR SPRN_DABR /* Data Address Breakpoint Register */ -#define DEC SPRN_DEC /* Decrement Register */ -#define DSISR SPRN_DSISR /* Data Storage Interrupt Status Register */ -#define HID0 SPRN_HID0 /* Hardware Implementation Register 0 */ -#define MSRDORM SPRN_MSRDORM /* MSR Dormant Register */ -#define NIADORM SPRN_NIADORM /* NIA Dormant Register */ -#define TSC SPRN_TSC /* Thread switch control */ -#define TST SPRN_TST /* Thread switch timeout */ -#define IABR SPRN_IABR /* Instruction Address Breakpoint Register */ -#define L2CR SPRN_L2CR /* PPC 750 L2 control register */ -#define __LR SPRN_LR -#define PVR SPRN_PVR /* Processor Version */ -#define PIR SPRN_PIR /* Processor ID */ -#define PURR SPRN_PURR /* Processor Utilization of Resource Register */ -#define SDR1 SPRN_SDR1 /* MMU hash base register */ -#define SPR0 SPRN_SPRG0 /* Supervisor Private Registers */ -#define SPR1 SPRN_SPRG1 -#define SPR2 SPRN_SPRG2 -#define SPR3 SPRN_SPRG3 -#define SPRG0 SPRN_SPRG0 -#define SPRG1 SPRN_SPRG1 -#define SPRG2 SPRN_SPRG2 -#define SPRG3 SPRN_SPRG3 -#define SRR0 SPRN_SRR0 /* Save and Restore Register 0 */ -#define SRR1 SPRN_SRR1 /* Save and Restore Register 1 */ -#define TBRL SPRN_TBRL /* Time Base Read Lower Register */ -#define TBRU SPRN_TBRU /* Time Base Read Upper Register */ -#define TBWL SPRN_TBWL /* Time Base Write Lower Register */ -#define TBWU SPRN_TBWU /* Time Base Write Upper Register */ -#define XER SPRN_XER - -/* Processor Version Register (PVR) field extraction */ - -#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ -#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ - -/* Processor Version Numbers */ -#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_POWER5p 0x003B -#define PV_970FX 0x003C -#define PV_630 0x0040 -#define PV_630p 0x0041 -#define PV_970MP 0x0044 -#define PV_BE 0x0070 - -/* Platforms supported by PPC64 */ -#define PLATFORM_PSERIES 0x0100 -#define PLATFORM_PSERIES_LPAR 0x0101 -#define PLATFORM_ISERIES_LPAR 0x0201 -#define PLATFORM_LPAR 0x0001 -#define PLATFORM_POWERMAC 0x0400 -#define PLATFORM_MAPLE 0x0500 -#define PLATFORM_BPA 0x1000 - -/* Compatibility with drivers coming from PPC32 world */ -#define _machine (systemcfg->platform) -#define _MACH_Pmac PLATFORM_POWERMAC - -/* - * List of interrupt controllers. - */ -#define IC_INVALID 0 -#define IC_OPEN_PIC 1 -#define IC_PPC_XIC 2 -#define IC_BPA_IIC 3 -#define IC_ISERIES 4 - -#define XGLUE(a,b) a##b -#define GLUE(a,b) XGLUE(a,b) - -#ifdef __ASSEMBLY__ - -#define _GLOBAL(name) \ - .section ".text"; \ - .align 2 ; \ - .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): - -#define _KPROBE(name) \ - .section ".kprobes.text","a"; \ - .align 2 ; \ - .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): - -#define _STATIC(name) \ - .section ".text"; \ - .align 2 ; \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): - -#else /* __ASSEMBLY__ */ - -/* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). - */ -#define current_text_addr() ({ __label__ _l; _l: &&_l;}) - -/* Macros for setting and retrieving special purpose registers */ - -#define mfmsr() ({unsigned long rval; \ - asm volatile("mfmsr %0" : "=r" (rval)); rval;}) - -#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ - : : "r" (v)) -#define mtmsrd(v) __mtmsrd((v), 0) - -#define mfspr(rn) ({unsigned long rval; \ - asm volatile("mfspr %0," __stringify(rn) \ - : "=r" (rval)); rval;}) -#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) - -#define mftb() ({unsigned long rval; \ - asm volatile("mftb %0" : "=r" (rval)); rval;}) - -#define mttbl(v) asm volatile("mttbl %0":: "r"(v)) -#define mttbu(v) asm volatile("mttbu %0":: "r"(v)) - -#define mfasr() ({unsigned long rval; \ - asm volatile("mfasr %0" : "=r" (rval)); rval;}) - -/* Macros for adjusting thread priority (hardware multi-threading) */ -#define HMT_very_low() asm volatile("or 31,31,31 # very low priority") -#define HMT_low() asm volatile("or 1,1,1 # low priority") -#define HMT_medium_low() asm volatile("or 6,6,6 # medium low priority") -#define HMT_medium() asm volatile("or 2,2,2 # medium priority") -#define HMT_medium_high() asm volatile("or 5,5,5 # medium high priority") -#define HMT_high() asm volatile("or 3,3,3 # high priority") - -static inline void set_tb(unsigned int upper, unsigned int lower) -{ - mttbl(0); - mttbu(upper); - mttbl(lower); -} - -#define __get_SP() ({unsigned long sp; \ - asm volatile("mr %0,1": "=r" (sp)); sp;}) - -#ifdef __KERNEL__ - -extern int have_of; -extern u64 ppc64_interrupt_controller; - -struct task_struct; -void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); -void release_thread(struct task_struct *); - -/* Prepare to copy thread state - unlazy all lazy status */ -extern void prepare_to_copy(struct task_struct *tsk); - -/* Create a new kernel thread. */ -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - -/* Lazy FPU handling on uni-processor */ -extern struct task_struct *last_task_used_math; -extern struct task_struct *last_task_used_altivec; - -/* 64-bit user address space is 44-bits (16TB user VM) */ -#define TASK_SIZE_USER64 (0x0000100000000000UL) - -/* - * 32-bit user address space is 4GB - 1 page - * (this 1 page is needed so referencing of 0xFFFFFFFF generates EFAULT - */ -#define TASK_SIZE_USER32 (0x0000000100000000UL - (1*PAGE_SIZE)) - -#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ - TASK_SIZE_USER32 : TASK_SIZE_USER64) - -/* This decides where the kernel will search for a free chunk of vm - * space during mmap's. - */ -#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4)) -#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4)) - -#define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \ - TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 ) - -typedef struct { - unsigned long seg; -} mm_segment_t; - -struct thread_struct { - unsigned long ksp; /* Kernel stack pointer */ - unsigned long ksp_vsid; - struct pt_regs *regs; /* Pointer to saved register state */ - mm_segment_t fs; /* for get_fs() validation */ - double fpr[32]; /* Complete floating point set */ - unsigned long fpscr; /* Floating point status (plus pad) */ - unsigned long fpexc_mode; /* Floating-point exception mode */ - unsigned long start_tb; /* Start purr when proc switched in */ - unsigned long accum_tb; /* Total accumilated purr for process */ - unsigned long vdso_base; /* base of the vDSO library */ - unsigned long dabr; /* Data address breakpoint register */ -#ifdef CONFIG_ALTIVEC - /* Complete AltiVec register set */ - vector128 vr[32] __attribute((aligned(16))); - /* AltiVec status */ - vector128 vscr __attribute((aligned(16))); - unsigned long vrsave; - int used_vr; /* set if process has used altivec */ -#endif /* CONFIG_ALTIVEC */ -}; - -#define ARCH_MIN_TASKALIGN 16 - -#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) - -#define INIT_THREAD { \ - .ksp = INIT_SP, \ - .regs = (struct pt_regs *)INIT_SP - 1, \ - .fs = KERNEL_DS, \ - .fpr = {0}, \ - .fpscr = 0, \ - .fpexc_mode = MSR_FE0|MSR_FE1, \ -} - -/* - * Return saved PC of a blocked thread. For now, this is the "user" PC - */ -#define thread_saved_pc(tsk) \ - ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) - -unsigned long get_wchan(struct task_struct *p); - -#define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) -#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0) - -/* Get/set floating-point exception mode */ -#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr)) -#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val)) - -extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr); -extern int set_fpexc_mode(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); -} - -static inline unsigned long __pack_fe01(unsigned int fpmode) -{ - return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1); -} - -#define cpu_relax() do { HMT_low(); HMT_medium(); barrier(); } while (0) - -/* - * Prefetch macros. - */ -#define ARCH_HAS_PREFETCH -#define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH - -static inline void prefetch(const void *x) -{ - if (unlikely(!x)) - return; - - __asm__ __volatile__ ("dcbt 0,%0" : : "r" (x)); -} - -static inline void prefetchw(const void *x) -{ - if (unlikely(!x)) - return; - - __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x)); -} - -#define spin_lock_prefetch(x) prefetchw(x) - -#define HAVE_ARCH_PICK_MMAP_LAYOUT - -static inline void ppc64_runlatch_on(void) -{ - unsigned long ctrl; - - if (cpu_has_feature(CPU_FTR_CTRL)) { - ctrl = mfspr(SPRN_CTRLF); - ctrl |= CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); - } -} - -static inline void ppc64_runlatch_off(void) -{ - unsigned long ctrl; - - if (cpu_has_feature(CPU_FTR_CTRL)) { - ctrl = mfspr(SPRN_CTRLF); - ctrl &= ~CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); - } -} - -#endif /* __KERNEL__ */ - -#endif /* __ASSEMBLY__ */ - -#ifdef __KERNEL__ -#define RUNLATCH_ON(REG) \ -BEGIN_FTR_SECTION \ - mfspr (REG),SPRN_CTRLF; \ - ori (REG),(REG),CTRL_RUNLATCH; \ - mtspr SPRN_CTRLT,(REG); \ -END_FTR_SECTION_IFSET(CPU_FTR_CTRL) -#endif - -/* - * Number of entries in the SLB. If this ever changes we should handle - * it with a use a cpu feature fixup. - */ -#define SLB_NUM_ENTRIES 64 - -#endif /* __ASM_PPC64_PROCESSOR_H */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 1fbdc9f0590c..c04d62c592a6 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -144,13 +144,6 @@ struct thread_struct; extern struct task_struct * _switch(struct thread_struct *prev, struct thread_struct *next); -static inline int __is_processor(unsigned long pv) -{ - unsigned long pvr; - asm("mfspr %0, 0x11F" : "=r" (pvr)); - return(PVR_VER(pvr) == pv); -} - /* * Atomic exchange * From a432403a89646614252c3bb6dfbe897c8312ab35 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 20:49:07 +1000 Subject: [PATCH 0331/1939] ppc64: Use the merged lmb routines The only real change here is that lmb_enforce_memory_limit now takes the memory_limit as a parameter instead of as a global variable. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/lmb.c | 299 ------------------------------------- arch/ppc64/kernel/prom.c | 5 +- include/asm-ppc64/lmb.h | 81 ---------- 4 files changed, 4 insertions(+), 383 deletions(-) delete mode 100644 arch/ppc64/kernel/lmb.c delete mode 100644 include/asm-ppc64/lmb.h diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 2fdcc4b63d40..32fd3f1c7935 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := setup.o entry.o irq.o idle.o dma.o \ align.o semaphore.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ - lmb.o cputable.o cpu_setup_power4.o \ + cputable.o cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o prom.o obj-y += vdso32/ vdso64/ diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c deleted file mode 100644 index 5adaca2ddc9d..000000000000 --- a/arch/ppc64/kernel/lmb.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Procedures for interfacing to Open Firmware. - * - * Peter Bergner, IBM Corp. June 2001. - * Copyright (C) 2001 Peter Bergner. - * - * 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 - -struct lmb lmb; - -#undef DEBUG - -void lmb_dump_all(void) -{ -#ifdef DEBUG - unsigned long i; - - udbg_printf("lmb_dump_all:\n"); - udbg_printf(" memory.cnt = 0x%lx\n", - lmb.memory.cnt); - udbg_printf(" memory.size = 0x%lx\n", - lmb.memory.size); - for (i=0; i < lmb.memory.cnt ;i++) { - udbg_printf(" memory.region[0x%x].base = 0x%lx\n", - i, lmb.memory.region[i].base); - udbg_printf(" .size = 0x%lx\n", - lmb.memory.region[i].size); - } - - udbg_printf("\n reserved.cnt = 0x%lx\n", - lmb.reserved.cnt); - udbg_printf(" reserved.size = 0x%lx\n", - lmb.reserved.size); - for (i=0; i < lmb.reserved.cnt ;i++) { - udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", - i, lmb.reserved.region[i].base); - udbg_printf(" .size = 0x%lx\n", - lmb.reserved.region[i].size); - } -#endif /* DEBUG */ -} - -static unsigned long __init -lmb_addrs_overlap(unsigned long base1, unsigned long size1, - unsigned long base2, unsigned long size2) -{ - return ((base1 < (base2+size2)) && (base2 < (base1+size1))); -} - -static long __init -lmb_addrs_adjacent(unsigned long base1, unsigned long size1, - unsigned long base2, unsigned long size2) -{ - if (base2 == base1 + size1) - return 1; - else if (base1 == base2 + size2) - return -1; - - return 0; -} - -static long __init -lmb_regions_adjacent(struct lmb_region *rgn, unsigned long r1, unsigned long r2) -{ - unsigned long base1 = rgn->region[r1].base; - unsigned long size1 = rgn->region[r1].size; - unsigned long base2 = rgn->region[r2].base; - unsigned long size2 = rgn->region[r2].size; - - 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) -{ - 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; - } - rgn->cnt--; -} - -/* This routine called with relocation disabled. */ -void __init -lmb_init(void) -{ - /* Create a dummy zero size LMB which will get coalesced away later. - * This simplifies the lmb_add() code below... - */ - lmb.memory.region[0].base = 0; - lmb.memory.region[0].size = 0; - lmb.memory.cnt = 1; - - /* Ditto. */ - lmb.reserved.region[0].base = 0; - lmb.reserved.region[0].size = 0; - lmb.reserved.cnt = 1; -} - -/* This routine called with relocation disabled. */ -void __init -lmb_analyze(void) -{ - int i; - - lmb.memory.size = 0; - - for (i = 0; i < lmb.memory.cnt; i++) - lmb.memory.size += lmb.memory.region[i].size; -} - -/* This routine called with relocation disabled. */ -static long __init -lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) -{ - unsigned long i, coalesced = 0; - long adjacent; - - /* First try and coalesce this LMB with another. */ - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - - adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); - if ( adjacent > 0 ) { - rgn->region[i].base -= size; - rgn->region[i].size += size; - coalesced++; - break; - } - else if ( adjacent < 0 ) { - rgn->region[i].size += size; - coalesced++; - break; - } - } - - if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { - lmb_coalesce_regions(rgn, i, i+1); - coalesced++; - } - - if ( coalesced ) { - return coalesced; - } else if ( rgn->cnt >= MAX_LMB_REGIONS ) { - return -1; - } - - /* Couldn't coalesce the LMB, so add it to the sorted table. */ - for (i=rgn->cnt-1; i >= 0; i--) { - if (base < rgn->region[i].base) { - rgn->region[i+1].base = rgn->region[i].base; - rgn->region[i+1].size = rgn->region[i].size; - } else { - rgn->region[i+1].base = base; - rgn->region[i+1].size = size; - break; - } - } - rgn->cnt++; - - return 0; -} - -/* This routine called with relocation disabled. */ -long __init -lmb_add(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.memory); - - /* On pSeries LPAR systems, the first LMB is our RMO region. */ - if ( base == 0 ) - lmb.rmo_size = size; - - return lmb_add_region(_rgn, base, size); - -} - -long __init -lmb_reserve(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.reserved); - - return lmb_add_region(_rgn, base, size); -} - -long __init -lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, unsigned long size) -{ - unsigned long i; - - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { - break; - } - } - - return (i < rgn->cnt) ? i : -1; -} - -unsigned long __init -lmb_alloc(unsigned long size, unsigned long align) -{ - return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); -} - -unsigned long __init -lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) -{ - long i, j; - unsigned long base = 0; - - for (i=lmb.memory.cnt-1; i >= 0; i--) { - unsigned long lmbbase = lmb.memory.region[i].base; - unsigned long lmbsize = lmb.memory.region[i].size; - - if ( max_addr == LMB_ALLOC_ANYWHERE ) - base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); - else if ( lmbbase < max_addr ) - base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align); - else - continue; - - while ( (lmbbase <= base) && - ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) { - base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align); - } - - if ( (base != 0) && (lmbbase <= base) ) - break; - } - - if ( i < 0 ) - return 0; - - lmb_add_region(&lmb.reserved, base, size); - - return base; -} - -/* You must call lmb_analyze() before this. */ -unsigned long __init -lmb_phys_mem_size(void) -{ - return lmb.memory.size; -} - -unsigned long __init -lmb_end_of_DRAM(void) -{ - int idx = lmb.memory.cnt - 1; - - 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. - */ -void __init lmb_enforce_memory_limit(void) -{ - extern unsigned long memory_limit; - unsigned long i, limit; - - if (! memory_limit) - return; - - limit = memory_limit; - for (i = 0; i < lmb.memory.cnt; i++) { - if (limit > lmb.memory.region[i].size) { - limit -= lmb.memory.region[i].size; - continue; - } - - lmb.memory.region[i].size = limit; - lmb.memory.cnt = i + 1; - break; - } -} diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index 7035deb6de92..a0866f12647f 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -78,6 +78,7 @@ typedef int interpret_func(struct device_node *, unsigned long *, extern struct rtas_t rtas; extern struct lmb lmb; extern unsigned long klimit; +extern unsigned long memory_limit; static int __initdata dt_root_addr_cells; static int __initdata dt_root_size_cells; @@ -1063,7 +1064,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, { u32 *prop; u64 *prop64; - extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; + extern unsigned long tce_alloc_start, tce_alloc_end; DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); @@ -1237,7 +1238,7 @@ void __init early_init_devtree(void *params) lmb_init(); scan_flat_dt(early_init_dt_scan_root, NULL); scan_flat_dt(early_init_dt_scan_memory, NULL); - lmb_enforce_memory_limit(); + lmb_enforce_memory_limit(memory_limit); lmb_analyze(); systemcfg->physicalMemorySize = lmb_phys_mem_size(); lmb_reserve(0, __pa(klimit)); diff --git a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h deleted file mode 100644 index de91e034bd98..000000000000 --- a/include/asm-ppc64/lmb.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _PPC64_LMB_H -#define _PPC64_LMB_H - -/* - * Definitions for talking to the Open Firmware PROM on - * Power Macintosh computers. - * - * Copyright (C) 2001 Peter Bergner, 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 - -#define MAX_LMB_REGIONS 128 - -#define LMB_ALLOC_ANYWHERE 0 - -struct lmb_property { - unsigned long base; - unsigned long size; -}; - -struct lmb_region { - unsigned long cnt; - unsigned long size; - struct lmb_property region[MAX_LMB_REGIONS+1]; -}; - -struct lmb { - unsigned long debug; - unsigned long rmo_size; - struct lmb_region memory; - struct lmb_region reserved; -}; - -extern struct lmb lmb; - -extern void __init lmb_init(void); -extern void __init lmb_analyze(void); -extern long __init lmb_add(unsigned long, unsigned long); -extern long __init lmb_reserve(unsigned long, unsigned long); -extern unsigned long __init lmb_alloc(unsigned long, unsigned long); -extern unsigned long __init lmb_alloc_base(unsigned long, unsigned long, - unsigned long); -extern unsigned long __init lmb_phys_mem_size(void); -extern unsigned long __init lmb_end_of_DRAM(void); -extern unsigned long __init lmb_abs_to_phys(unsigned long); -extern void __init lmb_enforce_memory_limit(void); - -extern void lmb_dump_all(void); - -extern unsigned long io_hole_start; - -static inline unsigned long -lmb_size_bytes(struct lmb_region *type, unsigned long region_nr) -{ - return type->region[region_nr].size; -} -static inline unsigned long -lmb_size_pages(struct lmb_region *type, unsigned long region_nr) -{ - return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT; -} -static inline unsigned long -lmb_start_pfn(struct lmb_region *type, unsigned long region_nr) -{ - return type->region[region_nr].base >> PAGE_SHIFT; -} -static inline unsigned long -lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) -{ - return lmb_start_pfn(type, region_nr) + - lmb_size_pages(type, region_nr); -} - -#endif /* _PPC64_LMB_H */ From 70d64ceaa1a84d2502405422a4dfd3f87786a347 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 21:52:43 +1000 Subject: [PATCH 0332/1939] powerpc: Rename files to have consistent _32/_64 suffixes This doesn't change any code, just renames things so we consistently have foo_32.c and foo_64.c where we have separate 32- and 64-bit versions. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 2 +- arch/powerpc/kernel/Makefile | 4 +- arch/powerpc/kernel/{head.S => head_32.S} | 0 arch/powerpc/kernel/{setup.c => setup_32.c} | 0 arch/powerpc/lib/Makefile | 6 +- .../powerpc/lib/{checksum.S => checksum_32.S} | 0 .../lib/{checksum64.S => checksum_64.S} | 0 arch/powerpc/lib/{copy32.S => copy_32.S} | 0 .../powerpc/lib/{copypage.S => copypage_64.S} | 0 .../powerpc/lib/{copyuser.S => copyuser_64.S} | 0 arch/powerpc/lib/mem_64.S | 119 ++++++++ arch/powerpc/lib/{memcpy.S => memcpy_64.S} | 0 .../powerpc/lib/{usercopy.c => usercopy_64.c} | 0 arch/powerpc/mm/Makefile | 8 +- arch/powerpc/mm/{hash_32.S => hash_low_32.S} | 0 arch/powerpc/mm/{init.c => init_32.c} | 0 arch/powerpc/mm/{init64.c => init_64.c} | 0 arch/powerpc/mm/mem64.c | 259 ------------------ .../mm/{mmu_context.c => mmu_context_32.c} | 0 .../mm/{mmu_context64.c => mmu_context_64.c} | 0 arch/powerpc/mm/{pgtable.c => pgtable_32.c} | 0 arch/powerpc/mm/{pgtable64.c => pgtable_64.c} | 0 arch/powerpc/mm/{ppc_mmu.c => ppc_mmu_32.c} | 0 arch/powerpc/mm/{tlb.c => tlb_32.c} | 0 24 files changed, 129 insertions(+), 269 deletions(-) rename arch/powerpc/kernel/{head.S => head_32.S} (100%) rename arch/powerpc/kernel/{setup.c => setup_32.c} (100%) rename arch/powerpc/lib/{checksum.S => checksum_32.S} (100%) rename arch/powerpc/lib/{checksum64.S => checksum_64.S} (100%) rename arch/powerpc/lib/{copy32.S => copy_32.S} (100%) rename arch/powerpc/lib/{copypage.S => copypage_64.S} (100%) rename arch/powerpc/lib/{copyuser.S => copyuser_64.S} (100%) create mode 100644 arch/powerpc/lib/mem_64.S rename arch/powerpc/lib/{memcpy.S => memcpy_64.S} (100%) rename arch/powerpc/lib/{usercopy.c => usercopy_64.c} (100%) rename arch/powerpc/mm/{hash_32.S => hash_low_32.S} (100%) rename arch/powerpc/mm/{init.c => init_32.c} (100%) rename arch/powerpc/mm/{init64.c => init_64.c} (100%) delete mode 100644 arch/powerpc/mm/mem64.c rename arch/powerpc/mm/{mmu_context.c => mmu_context_32.c} (100%) rename arch/powerpc/mm/{mmu_context64.c => mmu_context_64.c} (100%) rename arch/powerpc/mm/{pgtable.c => pgtable_32.c} (100%) rename arch/powerpc/mm/{pgtable64.c => pgtable_64.c} (100%) rename arch/powerpc/mm/{ppc_mmu.c => ppc_mmu_32.c} (100%) rename arch/powerpc/mm/{tlb.c => tlb_32.c} (100%) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index eb1224c24e3e..064864065753 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -112,7 +112,7 @@ CFLAGS += $(cpu-as-y) # Default to the common case. KBUILD_DEFCONFIG := common_defconfig -head-y := arch/powerpc/kernel/head.o +head-y := arch/powerpc/kernel/head_32.o head-$(CONFIG_PPC64) := arch/powerpc/kernel/head_64.o head-$(CONFIG_8xx) := arch/powerpc/kernel/head_8xx.o head-$(CONFIG_4xx) := arch/powerpc/kernel/head_4xx.o diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 06d618e52f8e..344cab678c6a 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -extra-$(CONFIG_PPC_STD_MMU) := head.o +extra-$(CONFIG_PPC_STD_MMU) := head_32.o extra-$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o @@ -21,7 +21,7 @@ extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y := traps.o prom.o semaphore.o -obj-$(CONFIG_PPC32) += setup.o process.o +obj-$(CONFIG_PPC32) += setup_32.o process.o obj-$(CONFIG_PPC64) += idle_power4.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o diff --git a/arch/powerpc/kernel/head.S b/arch/powerpc/kernel/head_32.S similarity index 100% rename from arch/powerpc/kernel/head.S rename to arch/powerpc/kernel/head_32.S diff --git a/arch/powerpc/kernel/setup.c b/arch/powerpc/kernel/setup_32.c similarity index 100% rename from arch/powerpc/kernel/setup.c rename to arch/powerpc/kernel/setup_32.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 347f9798e433..a8cedb96de5f 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -3,7 +3,7 @@ # obj-y := strcase.o string.o -obj-$(CONFIG_PPC32) += div64.o copy32.o checksum.o -obj-$(CONFIG_PPC64) += copypage.o copyuser.o memcpy.o usercopy.o \ - sstep.o checksum64.o +obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o +obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o memcpy_64.o \ + usercopy_64.o sstep.o checksum_64.o mem_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/powerpc/lib/checksum.S b/arch/powerpc/lib/checksum_32.S similarity index 100% rename from arch/powerpc/lib/checksum.S rename to arch/powerpc/lib/checksum_32.S diff --git a/arch/powerpc/lib/checksum64.S b/arch/powerpc/lib/checksum_64.S similarity index 100% rename from arch/powerpc/lib/checksum64.S rename to arch/powerpc/lib/checksum_64.S diff --git a/arch/powerpc/lib/copy32.S b/arch/powerpc/lib/copy_32.S similarity index 100% rename from arch/powerpc/lib/copy32.S rename to arch/powerpc/lib/copy_32.S diff --git a/arch/powerpc/lib/copypage.S b/arch/powerpc/lib/copypage_64.S similarity index 100% rename from arch/powerpc/lib/copypage.S rename to arch/powerpc/lib/copypage_64.S diff --git a/arch/powerpc/lib/copyuser.S b/arch/powerpc/lib/copyuser_64.S similarity index 100% rename from arch/powerpc/lib/copyuser.S rename to arch/powerpc/lib/copyuser_64.S diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S new file mode 100644 index 000000000000..68df20283ff5 --- /dev/null +++ b/arch/powerpc/lib/mem_64.S @@ -0,0 +1,119 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * 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 + +_GLOBAL(memset) + neg r0,r3 + rlwimi r4,r4,8,16,23 + andi. r0,r0,7 /* # bytes to be 8-byte aligned */ + rlwimi r4,r4,16,0,15 + cmplw cr1,r5,r0 /* do we get that far? */ + rldimi r4,r4,32,0 + mtcrf 1,r0 + mr r6,r3 + blt cr1,8f + beq+ 3f /* if already 8-byte aligned */ + subf r5,r0,r5 + bf 31,1f + stb r4,0(r6) + addi r6,r6,1 +1: bf 30,2f + sth r4,0(r6) + addi r6,r6,2 +2: bf 29,3f + stw r4,0(r6) + addi r6,r6,4 +3: srdi. r0,r5,6 + clrldi r5,r5,58 + mtctr r0 + beq 5f +4: std r4,0(r6) + std r4,8(r6) + std r4,16(r6) + std r4,24(r6) + std r4,32(r6) + std r4,40(r6) + std r4,48(r6) + std r4,56(r6) + addi r6,r6,64 + bdnz 4b +5: srwi. r0,r5,3 + clrlwi r5,r5,29 + mtcrf 1,r0 + beq 8f + bf 29,6f + std r4,0(r6) + std r4,8(r6) + std r4,16(r6) + std r4,24(r6) + addi r6,r6,32 +6: bf 30,7f + std r4,0(r6) + std r4,8(r6) + addi r6,r6,16 +7: bf 31,8f + std r4,0(r6) + addi r6,r6,8 +8: cmpwi r5,0 + mtcrf 1,r5 + beqlr+ + bf 29,9f + stw r4,0(r6) + addi r6,r6,4 +9: bf 30,10f + sth r4,0(r6) + addi r6,r6,2 +10: bflr 31 + stb r4,0(r6) + blr + +_GLOBAL(memmove) + cmplw 0,r3,r4 + bgt .backwards_memcpy + b .memcpy + +_GLOBAL(backwards_memcpy) + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b diff --git a/arch/powerpc/lib/memcpy.S b/arch/powerpc/lib/memcpy_64.S similarity index 100% rename from arch/powerpc/lib/memcpy.S rename to arch/powerpc/lib/memcpy_64.S diff --git a/arch/powerpc/lib/usercopy.c b/arch/powerpc/lib/usercopy_64.c similarity index 100% rename from arch/powerpc/lib/usercopy.c rename to arch/powerpc/lib/usercopy_64.c diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index afd3be112b79..35497deeb4b2 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -3,10 +3,10 @@ # obj-y := fault.o mem.o lmb.o -obj-$(CONFIG_PPC32) += init.o pgtable.o mmu_context.o \ - tlb.o -obj-$(CONFIG_PPC64) += init64.o pgtable64.o mmu_context64.o -obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu.o hash_32.o +obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o \ + tlb_32.o +obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o +obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o obj-$(CONFIG_40x) += 4xx_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o diff --git a/arch/powerpc/mm/hash_32.S b/arch/powerpc/mm/hash_low_32.S similarity index 100% rename from arch/powerpc/mm/hash_32.S rename to arch/powerpc/mm/hash_low_32.S diff --git a/arch/powerpc/mm/init.c b/arch/powerpc/mm/init_32.c similarity index 100% rename from arch/powerpc/mm/init.c rename to arch/powerpc/mm/init_32.c diff --git a/arch/powerpc/mm/init64.c b/arch/powerpc/mm/init_64.c similarity index 100% rename from arch/powerpc/mm/init64.c rename to arch/powerpc/mm/init_64.c diff --git a/arch/powerpc/mm/mem64.c b/arch/powerpc/mm/mem64.c deleted file mode 100644 index ef765a84433f..000000000000 --- a/arch/powerpc/mm/mem64.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) - * and Cort Dougan (PReP) (cort@cs.nmt.edu) - * Copyright (C) 1996 Paul Mackerras - * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * - * Derived from "arch/i386/mm/init.c" - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * Dave Engebretsen - * Rework for PPC64 port. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This is called by /dev/mem to know if a given address has to - * be mapped non-cacheable or not - */ -int page_is_ram(unsigned long pfn) -{ - int i; - unsigned long paddr = (pfn << PAGE_SHIFT); - - for (i=0; i < lmb.memory.cnt; i++) { - unsigned long base; - - base = lmb.memory.region[i].base; - - if ((paddr >= base) && - (paddr < (base + lmb.memory.region[i].size))) { - return 1; - } - } - - return 0; -} -EXPORT_SYMBOL(page_is_ram); - -pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, - unsigned long size, pgprot_t vma_prot) -{ - if (ppc_md.phys_mem_access_prot) - return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); - - if (!page_is_ram(addr >> PAGE_SHIFT)) - vma_prot = __pgprot(pgprot_val(vma_prot) - | _PAGE_GUARDED | _PAGE_NO_CACHE); - return vma_prot; -} -EXPORT_SYMBOL(phys_mem_access_prot); - -void show_mem(void) -{ - unsigned long total = 0, reserved = 0; - unsigned long shared = 0, cached = 0; - struct page *page; - pg_data_t *pgdat; - unsigned long i; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_spanned_pages; i++) { - page = pgdat_page_nr(pgdat, i); - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; - } - } - printk("%ld pages of RAM\n", total); - printk("%ld reserved pages\n", reserved); - printk("%ld pages shared\n", shared); - printk("%ld pages swap cached\n", cached); -} - -/* - * This is called when a page has been modified by the kernel. - * It just marks the page as not i-cache clean. We do the i-cache - * flush later when the page is given to a user process, if necessary. - */ -void flush_dcache_page(struct page *page) -{ - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &page->flags)) - clear_bit(PG_arch_1, &page->flags); -} -EXPORT_SYMBOL(flush_dcache_page); - -void clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - clear_page(page); - - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - /* - * We shouldnt have to do this, but some versions of glibc - * require it (ld.so assumes zero filled pages are icache clean) - * - Anton - */ - - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &pg->flags)) - clear_bit(PG_arch_1, &pg->flags); -} -EXPORT_SYMBOL(clear_user_page); - -void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *pg) -{ - copy_page(vto, vfrom); - - /* - * We should be able to use the following optimisation, however - * there are two problems. - * Firstly a bug in some versions of binutils meant PLT sections - * were not marked executable. - * Secondly the first word in the GOT section is blrl, used - * to establish the GOT address. Until recently the GOT was - * not marked executable. - * - Anton - */ -#if 0 - if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0)) - return; -#endif - - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &pg->flags)) - clear_bit(PG_arch_1, &pg->flags); -} - -void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, - unsigned long addr, int len) -{ - unsigned long maddr; - - maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK); - flush_icache_range(maddr, maddr + len); -} -EXPORT_SYMBOL(flush_icache_user_range); - -/* - * This is called at the end of handling a user page fault, when the - * fault has been handled by updating a PTE in the linux page tables. - * We use it to preload an HPTE into the hash table corresponding to - * the updated linux PTE. - * - * This must always be called with the mm->page_table_lock held - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea, - pte_t pte) -{ - unsigned long vsid; - void *pgdir; - pte_t *ptep; - int local = 0; - cpumask_t tmp; - unsigned long flags; - - /* handle i-cache coherency */ - if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && - !cpu_has_feature(CPU_FTR_NOEXECUTE)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - if (!PageReserved(page) - && !test_bit(PG_arch_1, &page->flags)) { - __flush_dcache_icache(page_address(page)); - set_bit(PG_arch_1, &page->flags); - } - } - } - - /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ - if (!pte_young(pte)) - return; - - pgdir = vma->vm_mm->pgd; - if (pgdir == NULL) - return; - - ptep = find_linux_pte(pgdir, ea); - if (!ptep) - return; - - vsid = get_vsid(vma->vm_mm->context.id, ea); - - local_irq_save(flags); - tmp = cpumask_of_cpu(smp_processor_id()); - if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) - local = 1; - - __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, - 0x300, local); - local_irq_restore(flags); -} diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context_32.c similarity index 100% rename from arch/powerpc/mm/mmu_context.c rename to arch/powerpc/mm/mmu_context_32.c diff --git a/arch/powerpc/mm/mmu_context64.c b/arch/powerpc/mm/mmu_context_64.c similarity index 100% rename from arch/powerpc/mm/mmu_context64.c rename to arch/powerpc/mm/mmu_context_64.c diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable_32.c similarity index 100% rename from arch/powerpc/mm/pgtable.c rename to arch/powerpc/mm/pgtable_32.c diff --git a/arch/powerpc/mm/pgtable64.c b/arch/powerpc/mm/pgtable_64.c similarity index 100% rename from arch/powerpc/mm/pgtable64.c rename to arch/powerpc/mm/pgtable_64.c diff --git a/arch/powerpc/mm/ppc_mmu.c b/arch/powerpc/mm/ppc_mmu_32.c similarity index 100% rename from arch/powerpc/mm/ppc_mmu.c rename to arch/powerpc/mm/ppc_mmu_32.c diff --git a/arch/powerpc/mm/tlb.c b/arch/powerpc/mm/tlb_32.c similarity index 100% rename from arch/powerpc/mm/tlb.c rename to arch/powerpc/mm/tlb_32.c From ab1f9dac6eea25ee59e4c8e1cf0b7476afbbfe07 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 21:58:35 +1000 Subject: [PATCH 0333/1939] powerpc: Merge arch/ppc64/mm to arch/powerpc/mm This moves the remaining files in arch/ppc64/mm to arch/powerpc/mm, and arranges that we use them when compiling with ARCH=ppc64. Signed-off-by: Paul Mackerras --- arch/powerpc/mm/Makefile | 8 +- .../hash_low.S => powerpc/mm/hash_low_64.S} | 2 +- .../mm/hash_native_64.c} | 0 .../mm/hash_utils_64.c} | 2 +- arch/{ppc64 => powerpc}/mm/hugetlbpage.c | 0 arch/{ppc64 => powerpc}/mm/imalloc.c | 0 arch/powerpc/mm/init_64.c | 36 - arch/powerpc/mm/mem.c | 11 +- arch/{ppc64 => powerpc}/mm/mmap.c | 0 arch/powerpc/mm/mmu_decl.h | 18 +- arch/{ppc64 => powerpc}/mm/numa.c | 0 arch/powerpc/mm/pgtable_64.c | 34 +- arch/{ppc64 => powerpc}/mm/slb.c | 0 arch/{ppc64 => powerpc}/mm/slb_low.S | 0 arch/{ppc64 => powerpc}/mm/stab.c | 0 arch/{ppc64/mm/tlb.c => powerpc/mm/tlb_64.c} | 0 arch/ppc64/Makefile | 2 +- arch/ppc64/mm/Makefile | 11 - arch/ppc64/mm/fault.c | 333 ------- arch/ppc64/mm/init.c | 870 ------------------ 20 files changed, 39 insertions(+), 1288 deletions(-) rename arch/{ppc64/mm/hash_low.S => powerpc/mm/hash_low_64.S} (99%) rename arch/{ppc64/mm/hash_native.c => powerpc/mm/hash_native_64.c} (100%) rename arch/{ppc64/mm/hash_utils.c => powerpc/mm/hash_utils_64.c} (99%) rename arch/{ppc64 => powerpc}/mm/hugetlbpage.c (100%) rename arch/{ppc64 => powerpc}/mm/imalloc.c (100%) rename arch/{ppc64 => powerpc}/mm/mmap.c (100%) rename arch/{ppc64 => powerpc}/mm/numa.c (100%) rename arch/{ppc64 => powerpc}/mm/slb.c (100%) rename arch/{ppc64 => powerpc}/mm/slb_low.S (100%) rename arch/{ppc64 => powerpc}/mm/stab.c (100%) rename arch/{ppc64/mm/tlb.c => powerpc/mm/tlb_64.c} (100%) delete mode 100644 arch/ppc64/mm/Makefile delete mode 100644 arch/ppc64/mm/fault.c delete mode 100644 arch/ppc64/mm/init.c diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 35497deeb4b2..612bc4ec72b1 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -5,8 +5,14 @@ obj-y := fault.o mem.o lmb.o obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o \ tlb_32.o -obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o +hash-$(CONFIG_PPC_MULTIPLATFORM) := hash_native_64.o +obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \ + hash_utils_64.o hash_low_64.o tlb_64.o \ + slb_low.o slb.o stab.o mmap.o imalloc.o \ + $(hash-y) obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o obj-$(CONFIG_40x) += 4xx_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o +obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/ppc64/mm/hash_low.S b/arch/powerpc/mm/hash_low_64.S similarity index 99% rename from arch/ppc64/mm/hash_low.S rename to arch/powerpc/mm/hash_low_64.S index ee5a5d36bfa8..d6ed9102eeea 100644 --- a/arch/ppc64/mm/hash_low.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -10,7 +10,7 @@ * described in the kernel's COPYING file. */ -#include +#include #include #include #include diff --git a/arch/ppc64/mm/hash_native.c b/arch/powerpc/mm/hash_native_64.c similarity index 100% rename from arch/ppc64/mm/hash_native.c rename to arch/powerpc/mm/hash_native_64.c diff --git a/arch/ppc64/mm/hash_utils.c b/arch/powerpc/mm/hash_utils_64.c similarity index 99% rename from arch/ppc64/mm/hash_utils.c rename to arch/powerpc/mm/hash_utils_64.c index 83507438d6a0..35dd93eeaf4b 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -78,7 +78,7 @@ extern unsigned long dart_tablebase; hpte_t *htab_address; unsigned long htab_hash_mask; -extern unsigned long _SDR1; +unsigned long _SDR1; #define KB (1024) #define MB (1024*KB) diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c similarity index 100% rename from arch/ppc64/mm/hugetlbpage.c rename to arch/powerpc/mm/hugetlbpage.c diff --git a/arch/ppc64/mm/imalloc.c b/arch/powerpc/mm/imalloc.c similarity index 100% rename from arch/ppc64/mm/imalloc.c rename to arch/powerpc/mm/imalloc.c diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index c0ce6a7af3c7..b0fc822ec29f 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -73,18 +73,8 @@ #warning TASK_SIZE is smaller than it needs to be. #endif -int mem_init_done; -unsigned long ioremap_bot = IMALLOC_BASE; -static unsigned long phbs_io_bot = PHBS_IO_BASE; - -extern pgd_t swapper_pg_dir[]; -extern struct task_struct *current_set[NR_CPUS]; - unsigned long klimit = (unsigned long)_end; -unsigned long _SDR1=0; -unsigned long _ASR=0; - /* max amount of RAM to use */ unsigned long __max_memory; @@ -193,19 +183,6 @@ static int __init setup_kcore(void) } module_init(setup_kcore); -void __iomem * reserve_phb_iospace(unsigned long size) -{ - void __iomem *virt_addr; - - if (phbs_io_bot >= IMALLOC_BASE) - panic("reserve_phb_iospace(): phb io space overflow\n"); - - virt_addr = (void __iomem *) phbs_io_bot; - phbs_io_bot += size; - - return virt_addr; -} - static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) { memset(addr, 0, kmem_cache_size(cache)); @@ -244,16 +221,3 @@ void pgtable_cache_init(void) name); } } - -pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, - unsigned long size, pgprot_t vma_prot) -{ - if (ppc_md.phys_mem_access_prot) - return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); - - if (!page_is_ram(addr >> PAGE_SHIFT)) - vma_prot = __pgprot(pgprot_val(vma_prot) - | _PAGE_GUARDED | _PAGE_NO_CACHE); - return vma_prot; -} -EXPORT_SYMBOL(phys_mem_access_prot); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 0650de74d0b3..55b5860ed3c9 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -47,6 +47,9 @@ #include #include #include +#ifdef CONFIG_PPC64 +#include +#endif #include "mmu_decl.h" @@ -334,7 +337,7 @@ void flush_dcache_icache_page(struct page *page) void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); __flush_dcache_icache(start); kunmap_atomic(start, KM_PPC_SYNC_ICACHE); -#elif defined(CONFIG_8xx) +#elif defined(CONFIG_8xx) || defined(CONFIG_PPC64) /* On 8xx there is no need to kmap since highmem is not supported */ __flush_dcache_icache(page_address(page)); #else @@ -463,18 +466,18 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, if (pgdir == NULL) return; - ptep = find_linux_pte(pgdir, ea); + ptep = find_linux_pte(pgdir, address); if (!ptep) return; - vsid = get_vsid(vma->vm_mm->context.id, ea); + vsid = get_vsid(vma->vm_mm->context.id, address); local_irq_save(flags); tmp = cpumask_of_cpu(smp_processor_id()); if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) local = 1; - __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, + __hash_page(address, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, 0x300, local); local_irq_restore(flags); #endif diff --git a/arch/ppc64/mm/mmap.c b/arch/powerpc/mm/mmap.c similarity index 100% rename from arch/ppc64/mm/mmap.c rename to arch/powerpc/mm/mmap.c diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 06fe8af3af55..a4d7a327c0e5 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -22,11 +22,11 @@ #include #include +#ifdef CONFIG_PPC32 extern void mapin_ram(void); extern int map_page(unsigned long va, phys_addr_t pa, int flags); extern void setbat(int index, unsigned long virt, unsigned long phys, unsigned int size, int flags); -extern void reserve_phys_mem(unsigned long start, unsigned long size); extern void settlbcam(int index, unsigned long virt, phys_addr_t phys, unsigned int size, int flags, unsigned int pid); extern void invalidate_tlbcam_entry(int index); @@ -36,16 +36,16 @@ extern unsigned long ioremap_base; extern unsigned long ioremap_bot; extern unsigned int rtas_data, rtas_size; -extern unsigned long __max_low_memory; -extern unsigned long __initial_memory_limit; -extern unsigned long total_memory; -extern unsigned long total_lowmem; -extern int mem_init_done; - extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern unsigned int num_tlbcam_entries; +#endif + +extern unsigned long __max_low_memory; +extern unsigned long __initial_memory_limit; +extern unsigned long total_memory; +extern unsigned long total_lowmem; /* ...and now those things that may be slightly different between processor * architectures. -- Dan @@ -66,8 +66,8 @@ extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(void); extern void adjust_total_lowmem(void); -#else -/* anything except 4xx or 8xx */ +#elif defined(CONFIG_PPC32) +/* anything 32-bit except 4xx or 8xx */ extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(void); diff --git a/arch/ppc64/mm/numa.c b/arch/powerpc/mm/numa.c similarity index 100% rename from arch/ppc64/mm/numa.c rename to arch/powerpc/mm/numa.c diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 724f97e5dee5..484d24f9208b 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -67,30 +67,9 @@ #include #include -#if PGTABLE_RANGE > USER_VSID_RANGE -#warning Limited user VSID range means pagetable space is wasted -#endif - -#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE) -#warning TASK_SIZE is smaller than it needs to be. -#endif - -int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; static unsigned long phbs_io_bot = PHBS_IO_BASE; -extern pgd_t swapper_pg_dir[]; -extern struct task_struct *current_set[NR_CPUS]; - -unsigned long klimit = (unsigned long)_end; - -/* max amount of RAM to use */ -unsigned long __max_memory; - -/* info on what we think the IO hole is */ -unsigned long io_hole_start; -unsigned long io_hole_size; - #ifdef CONFIG_PPC_ISERIES void __iomem *ioremap(unsigned long addr, unsigned long size) @@ -355,3 +334,16 @@ int iounmap_explicit(volatile void __iomem *start, unsigned long size) EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); + +void __iomem * reserve_phb_iospace(unsigned long size) +{ + void __iomem *virt_addr; + + if (phbs_io_bot >= IMALLOC_BASE) + panic("reserve_phb_iospace(): phb io space overflow\n"); + + virt_addr = (void __iomem *) phbs_io_bot; + phbs_io_bot += size; + + return virt_addr; +} diff --git a/arch/ppc64/mm/slb.c b/arch/powerpc/mm/slb.c similarity index 100% rename from arch/ppc64/mm/slb.c rename to arch/powerpc/mm/slb.c diff --git a/arch/ppc64/mm/slb_low.S b/arch/powerpc/mm/slb_low.S similarity index 100% rename from arch/ppc64/mm/slb_low.S rename to arch/powerpc/mm/slb_low.S diff --git a/arch/ppc64/mm/stab.c b/arch/powerpc/mm/stab.c similarity index 100% rename from arch/ppc64/mm/stab.c rename to arch/powerpc/mm/stab.c diff --git a/arch/ppc64/mm/tlb.c b/arch/powerpc/mm/tlb_64.c similarity index 100% rename from arch/ppc64/mm/tlb.c rename to arch/powerpc/mm/tlb_64.c diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index fa889204d6ae..4a9928ef3032 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -83,7 +83,7 @@ head-y := arch/ppc64/kernel/head.o libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ -core-y += arch/ppc64/mm/ +core-y += arch/powerpc/mm/ core-y += arch/powerpc/platforms/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile deleted file mode 100644 index 3695d00d347f..000000000000 --- a/arch/ppc64/mm/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the linux ppc-specific parts of the memory manager. -# - -EXTRA_CFLAGS += -mno-minimal-toc - -obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o \ - slb_low.o slb.o stab.o mmap.o -obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PPC_MULTIPLATFORM) += hash_native.o diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c deleted file mode 100644 index be3f25cf3e9f..000000000000 --- a/arch/ppc64/mm/fault.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * arch/ppc/mm/fault.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/i386/mm/fault.c" - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * Modified by Cort Dougan and Paul Mackerras. - * - * Modified for PPC64 by Dave Engebretsen (engebret@ibm.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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Check whether the instruction at regs->nip is a store using - * an update addressing form which will update r1. - */ -static int store_updates_sp(struct pt_regs *regs) -{ - unsigned int inst; - - if (get_user(inst, (unsigned int __user *)regs->nip)) - return 0; - /* check for 1 in the rA field */ - if (((inst >> 16) & 0x1f) != 1) - return 0; - /* check major opcode */ - switch (inst >> 26) { - case 37: /* stwu */ - case 39: /* stbu */ - case 45: /* sthu */ - case 53: /* stfsu */ - case 55: /* stfdu */ - return 1; - case 62: /* std or stdu */ - return (inst & 3) == 1; - case 31: - /* check minor opcode */ - switch ((inst >> 1) & 0x3ff) { - case 181: /* stdux */ - case 183: /* stwux */ - case 247: /* stbux */ - case 439: /* sthux */ - case 695: /* stfsux */ - case 759: /* stfdux */ - return 1; - } - } - return 0; -} - -static void do_dabr(struct pt_regs *regs, unsigned long error_code) -{ - siginfo_t info; - - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return; - - if (debugger_dabr_match(regs)) - return; - - /* Clear the DABR */ - set_dabr(0); - - /* Deliver the signal to userspace */ - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_HWBKPT; - info.si_addr = (void __user *)regs->nip; - force_sig_info(SIGTRAP, &info, current); -} - -/* - * The error_code parameter is - * - DSISR for a non-SLB data access fault, - * - SRR1 & 0x08000000 for a non-SLB instruction access fault - * - 0 any SLB fault. - * The return value is 0 if the fault was handled, or the signal - * number if this is a kernel fault that can't be handled here. - */ -int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long error_code) -{ - struct vm_area_struct * vma; - struct mm_struct *mm = current->mm; - siginfo_t info; - unsigned long code = SEGV_MAPERR; - unsigned long is_write = error_code & DSISR_ISSTORE; - unsigned long trap = TRAP(regs); - unsigned long is_exec = trap == 0x400; - - BUG_ON((trap == 0x380) || (trap == 0x480)); - - if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return 0; - - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } - - /* On a kernel SLB miss we can only check for a valid exception entry */ - if (!user_mode(regs) && (address >= TASK_SIZE)) - return SIGSEGV; - - if (error_code & DSISR_DABRMATCH) { - do_dabr(regs, error_code); - return 0; - } - - if (in_atomic() || mm == NULL) { - if (!user_mode(regs)) - return SIGSEGV; - /* in_atomic() in user mode is really bad, - as is current->mm == NULL. */ - printk(KERN_EMERG "Page fault in user mode with" - "in_atomic() = %d mm = %p\n", in_atomic(), mm); - printk(KERN_EMERG "NIP = %lx MSR = %lx\n", - regs->nip, regs->msr); - die("Weird page fault", regs, SIGSEGV); - } - - /* When running in the kernel we expect faults to occur only to - * addresses in user space. All other faults represent errors in the - * kernel and should generate an OOPS. Unfortunatly, in the case of an - * erroneous fault occuring in a code path which already holds mmap_sem - * we will deadlock attempting to validate the fault against the - * address space. Luckily the kernel only validly references user - * space from well defined areas of code, which are listed in the - * exceptions table. - * - * As the vast majority of faults will be valid we will only perform - * the source reference check when there is a possibilty of a deadlock. - * Attempt to lock the address space, if we cannot we then validate the - * source. If this is invalid we can skip the address space check, - * thus avoiding the deadlock. - */ - if (!down_read_trylock(&mm->mmap_sem)) { - if (!user_mode(regs) && !search_exception_tables(regs->nip)) - goto bad_area_nosemaphore; - - down_read(&mm->mmap_sem); - } - - vma = find_vma(mm, address); - if (!vma) - goto bad_area; - - if (vma->vm_start <= address) { - goto good_area; - } - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - - /* - * N.B. The POWER/Open ABI allows programs to access up to - * 288 bytes below the stack pointer. - * The kernel signal delivery code writes up to about 1.5kB - * below the stack pointer (r1) before decrementing it. - * The exec code can write slightly over 640kB to the stack - * before setting the user r1. Thus we allow the stack to - * expand to 1MB without further checks. - */ - if (address + 0x100000 < vma->vm_end) { - /* get user regs even if this fault is in kernel mode */ - struct pt_regs *uregs = current->thread.regs; - if (uregs == NULL) - goto bad_area; - - /* - * A user-mode access to an address a long way below - * the stack pointer is only valid if the instruction - * is one which would update the stack pointer to the - * address accessed if the instruction completed, - * i.e. either stwu rs,n(r1) or stwux rs,r1,rb - * (or the byte, halfword, float or double forms). - * - * If we don't check this then any write to the area - * between the last mapped region and the stack will - * expand the stack rather than segfaulting. - */ - if (address + 2048 < uregs->gpr[1] - && (!user_mode(regs) || !store_updates_sp(regs))) - goto bad_area; - } - - if (expand_stack(vma, address)) - goto bad_area; - -good_area: - code = SEGV_ACCERR; - - if (is_exec) { - /* protection fault */ - if (error_code & DSISR_PROTFAULT) - goto bad_area; - if (!(vma->vm_flags & VM_EXEC)) - goto bad_area; - /* a write */ - } else if (is_write) { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - /* a read */ - } else { - if (!(vma->vm_flags & VM_READ)) - goto bad_area; - } - - survive: - /* - * If for any reason at all we couldn't handle the fault, - * make sure we exit gracefully rather than endlessly redo - * the fault. - */ - switch (handle_mm_fault(mm, vma, address, is_write)) { - - case VM_FAULT_MINOR: - current->min_flt++; - break; - case VM_FAULT_MAJOR: - current->maj_flt++; - break; - case VM_FAULT_SIGBUS: - goto do_sigbus; - case VM_FAULT_OOM: - goto out_of_memory; - default: - BUG(); - } - - up_read(&mm->mmap_sem); - return 0; - -bad_area: - up_read(&mm->mmap_sem); - -bad_area_nosemaphore: - /* User mode accesses cause a SIGSEGV */ - if (user_mode(regs)) { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = code; - info.si_addr = (void __user *) address; - force_sig_info(SIGSEGV, &info, current); - return 0; - } - - if (trap == 0x400 && (error_code & DSISR_PROTFAULT) - && printk_ratelimit()) - printk(KERN_CRIT "kernel tried to execute NX-protected" - " page (%lx) - exploit attempt? (uid: %d)\n", - address, current->uid); - - return SIGSEGV; - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -out_of_memory: - up_read(&mm->mmap_sem); - if (current->pid == 1) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - printk("VM: killing process %s\n", current->comm); - if (user_mode(regs)) - do_exit(SIGKILL); - return SIGKILL; - -do_sigbus: - up_read(&mm->mmap_sem); - if (user_mode(regs)) { - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)address; - force_sig_info(SIGBUS, &info, current); - return 0; - } - return SIGBUS; -} - -/* - * bad_page_fault is called when we have a bad access from the kernel. - * It is called from do_page_fault above and from some of the procedures - * in traps.c. - */ -void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) -{ - const struct exception_table_entry *entry; - - /* Are we prepared to handle this fault? */ - if ((entry = search_exception_tables(regs->nip)) != NULL) { - regs->nip = entry->fixup; - return; - } - - /* kernel has accessed a bad area */ - die("Kernel access of bad area", regs, sig); -} diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c deleted file mode 100644 index c2157c9c3acb..000000000000 --- a/arch/ppc64/mm/init.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) - * and Cort Dougan (PReP) (cort@cs.nmt.edu) - * Copyright (C) 1996 Paul Mackerras - * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * - * Derived from "arch/i386/mm/init.c" - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * Dave Engebretsen - * Rework for PPC64 port. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#if PGTABLE_RANGE > USER_VSID_RANGE -#warning Limited user VSID range means pagetable space is wasted -#endif - -#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE) -#warning TASK_SIZE is smaller than it needs to be. -#endif - -int mem_init_done; -unsigned long ioremap_bot = IMALLOC_BASE; -static unsigned long phbs_io_bot = PHBS_IO_BASE; - -extern pgd_t swapper_pg_dir[]; -extern struct task_struct *current_set[NR_CPUS]; - -unsigned long klimit = (unsigned long)_end; - -unsigned long _SDR1=0; -unsigned long _ASR=0; - -/* max amount of RAM to use */ -unsigned long __max_memory; - -/* info on what we think the IO hole is */ -unsigned long io_hole_start; -unsigned long io_hole_size; - -void show_mem(void) -{ - unsigned long total = 0, reserved = 0; - unsigned long shared = 0, cached = 0; - struct page *page; - pg_data_t *pgdat; - unsigned long i; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_spanned_pages; i++) { - page = pgdat_page_nr(pgdat, i); - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; - } - } - printk("%ld pages of RAM\n", total); - printk("%ld reserved pages\n", reserved); - printk("%ld pages shared\n", shared); - printk("%ld pages swap cached\n", cached); -} - -#ifdef CONFIG_PPC_ISERIES - -void __iomem *ioremap(unsigned long addr, unsigned long size) -{ - return (void __iomem *)addr; -} - -extern void __iomem *__ioremap(unsigned long addr, unsigned long size, - unsigned long flags) -{ - return (void __iomem *)addr; -} - -void iounmap(volatile void __iomem *addr) -{ - return; -} - -#else - -/* - * map_io_page currently only called by __ioremap - * map_io_page adds an entry to the ioremap page table - * and adds an entry to the HPT, possibly bolting it - */ -static int map_io_page(unsigned long ea, unsigned long pa, int flags) -{ - pgd_t *pgdp; - pud_t *pudp; - pmd_t *pmdp; - pte_t *ptep; - unsigned long vsid; - - if (mem_init_done) { - spin_lock(&init_mm.page_table_lock); - pgdp = pgd_offset_k(ea); - pudp = pud_alloc(&init_mm, pgdp, ea); - if (!pudp) - return -ENOMEM; - pmdp = pmd_alloc(&init_mm, pudp, ea); - if (!pmdp) - return -ENOMEM; - ptep = pte_alloc_kernel(&init_mm, pmdp, ea); - if (!ptep) - return -ENOMEM; - set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); - spin_unlock(&init_mm.page_table_lock); - } else { - unsigned long va, vpn, hash, hpteg; - - /* - * If the mm subsystem is not fully up, we cannot create a - * linux page table entry for this mapping. Simply bolt an - * entry in the hardware page table. - */ - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0xFFFFFFF); - vpn = va >> PAGE_SHIFT; - - hash = hpt_hash(vpn, 0); - - hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); - - /* Panic if a pte grpup is full */ - if (ppc_md.hpte_insert(hpteg, va, pa >> PAGE_SHIFT, - HPTE_V_BOLTED, - _PAGE_NO_CACHE|_PAGE_GUARDED|PP_RWXX) - == -1) { - panic("map_io_page: could not insert mapping"); - } - } - return 0; -} - - -static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, - unsigned long ea, unsigned long size, - unsigned long flags) -{ - unsigned long i; - - if ((flags & _PAGE_PRESENT) == 0) - flags |= pgprot_val(PAGE_KERNEL); - - for (i = 0; i < size; i += PAGE_SIZE) - if (map_io_page(ea+i, pa+i, flags)) - return NULL; - - return (void __iomem *) (ea + (addr & ~PAGE_MASK)); -} - - -void __iomem * -ioremap(unsigned long addr, unsigned long size) -{ - return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED); -} - -void __iomem * __ioremap(unsigned long addr, unsigned long size, - unsigned long flags) -{ - unsigned long pa, ea; - void __iomem *ret; - - /* - * Choose an address to map it to. - * Once the imalloc system is running, we use it. - * Before that, we map using addresses going - * up from ioremap_bot. imalloc will use - * the addresses from ioremap_bot through - * IMALLOC_END - * - */ - pa = addr & PAGE_MASK; - size = PAGE_ALIGN(addr + size) - pa; - - if (size == 0) - return NULL; - - if (mem_init_done) { - struct vm_struct *area; - area = im_get_free_area(size); - if (area == NULL) - return NULL; - ea = (unsigned long)(area->addr); - ret = __ioremap_com(addr, pa, ea, size, flags); - if (!ret) - im_free(area->addr); - } else { - ea = ioremap_bot; - ret = __ioremap_com(addr, pa, ea, size, flags); - if (ret) - ioremap_bot += size; - } - return ret; -} - -#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK)) - -int __ioremap_explicit(unsigned long pa, unsigned long ea, - unsigned long size, unsigned long flags) -{ - struct vm_struct *area; - void __iomem *ret; - - /* For now, require page-aligned values for pa, ea, and size */ - if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) || - !IS_PAGE_ALIGNED(size)) { - printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__); - return 1; - } - - if (!mem_init_done) { - /* Two things to consider in this case: - * 1) No records will be kept (imalloc, etc) that the region - * has been remapped - * 2) It won't be easy to iounmap() the region later (because - * of 1) - */ - ; - } else { - area = im_get_area(ea, size, - IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS); - if (area == NULL) { - /* Expected when PHB-dlpar is in play */ - return 1; - } - if (ea != (unsigned long) area->addr) { - printk(KERN_ERR "unexpected addr return from " - "im_get_area\n"); - return 1; - } - } - - ret = __ioremap_com(pa, pa, ea, size, flags); - if (ret == NULL) { - printk(KERN_ERR "ioremap_explicit() allocation failure !\n"); - return 1; - } - if (ret != (void *) ea) { - printk(KERN_ERR "__ioremap_com() returned unexpected addr\n"); - return 1; - } - - return 0; -} - -/* - * Unmap an IO region and remove it from imalloc'd list. - * Access to IO memory should be serialized by driver. - * This code is modeled after vmalloc code - unmap_vm_area() - * - * XXX what about calls before mem_init_done (ie python_countermeasures()) - */ -void iounmap(volatile void __iomem *token) -{ - void *addr; - - if (!mem_init_done) - return; - - addr = (void *) ((unsigned long __force) token & PAGE_MASK); - - im_free(addr); -} - -static int iounmap_subset_regions(unsigned long addr, unsigned long size) -{ - struct vm_struct *area; - - /* Check whether subsets of this region exist */ - area = im_get_area(addr, size, IM_REGION_SUPERSET); - if (area == NULL) - return 1; - - while (area) { - iounmap((void __iomem *) area->addr); - area = im_get_area(addr, size, - IM_REGION_SUPERSET); - } - - return 0; -} - -int iounmap_explicit(volatile void __iomem *start, unsigned long size) -{ - struct vm_struct *area; - unsigned long addr; - int rc; - - addr = (unsigned long __force) start & PAGE_MASK; - - /* Verify that the region either exists or is a subset of an existing - * region. In the latter case, split the parent region to create - * the exact region - */ - area = im_get_area(addr, size, - IM_REGION_EXISTS | IM_REGION_SUBSET); - if (area == NULL) { - /* Determine whether subset regions exist. If so, unmap */ - rc = iounmap_subset_regions(addr, size); - if (rc) { - printk(KERN_ERR - "%s() cannot unmap nonexistent range 0x%lx\n", - __FUNCTION__, addr); - return 1; - } - } else { - iounmap((void __iomem *) area->addr); - } - /* - * FIXME! This can't be right: - iounmap(area->addr); - * Maybe it should be "iounmap(area);" - */ - return 0; -} - -#endif - -EXPORT_SYMBOL(ioremap); -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); - -void free_initmem(void) -{ - unsigned long addr; - - addr = (unsigned long)__init_begin; - for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { - memset((void *)addr, 0xcc, PAGE_SIZE); - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); - totalram_pages++; - } - printk ("Freeing unused kernel memory: %luk freed\n", - ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10); -} - -#ifdef CONFIG_BLK_DEV_INITRD -void free_initrd_mem(unsigned long start, unsigned long end) -{ - if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - set_page_count(virt_to_page(start), 1); - free_page(start); - totalram_pages++; - } -} -#endif - -static DEFINE_SPINLOCK(mmu_context_lock); -static DEFINE_IDR(mmu_context_idr); - -int init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - int index; - int err; - -again: - if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) - return -ENOMEM; - - spin_lock(&mmu_context_lock); - err = idr_get_new_above(&mmu_context_idr, NULL, 1, &index); - spin_unlock(&mmu_context_lock); - - if (err == -EAGAIN) - goto again; - else if (err) - return err; - - if (index > MAX_CONTEXT) { - idr_remove(&mmu_context_idr, index); - return -ENOMEM; - } - - mm->context.id = index; - - return 0; -} - -void destroy_context(struct mm_struct *mm) -{ - spin_lock(&mmu_context_lock); - idr_remove(&mmu_context_idr, mm->context.id); - spin_unlock(&mmu_context_lock); - - mm->context.id = NO_CONTEXT; -} - -/* - * Do very early mm setup. - */ -void __init mm_init_ppc64(void) -{ -#ifndef CONFIG_PPC_ISERIES - unsigned long i; -#endif - - ppc64_boot_msg(0x100, "MM Init"); - - /* This is the story of the IO hole... please, keep seated, - * unfortunately, we are out of oxygen masks at the moment. - * So we need some rough way to tell where your big IO hole - * is. On pmac, it's between 2G and 4G, on POWER3, it's around - * that area as well, on POWER4 we don't have one, etc... - * We need that as a "hint" when sizing the TCE table on POWER3 - * So far, the simplest way that seem work well enough for us it - * to just assume that the first discontinuity in our physical - * RAM layout is the IO hole. That may not be correct in the future - * (and isn't on iSeries but then we don't care ;) - */ - -#ifndef CONFIG_PPC_ISERIES - for (i = 1; i < lmb.memory.cnt; i++) { - unsigned long base, prevbase, prevsize; - - prevbase = lmb.memory.region[i-1].base; - prevsize = lmb.memory.region[i-1].size; - base = lmb.memory.region[i].base; - if (base > (prevbase + prevsize)) { - io_hole_start = prevbase + prevsize; - io_hole_size = base - (prevbase + prevsize); - break; - } - } -#endif /* CONFIG_PPC_ISERIES */ - if (io_hole_start) - printk("IO Hole assumed to be %lx -> %lx\n", - io_hole_start, io_hole_start + io_hole_size - 1); - - ppc64_boot_msg(0x100, "MM Init Done"); -} - -/* - * This is called by /dev/mem to know if a given address has to - * be mapped non-cacheable or not - */ -int page_is_ram(unsigned long pfn) -{ - int i; - unsigned long paddr = (pfn << PAGE_SHIFT); - - for (i=0; i < lmb.memory.cnt; i++) { - unsigned long base; - - base = lmb.memory.region[i].base; - - if ((paddr >= base) && - (paddr < (base + lmb.memory.region[i].size))) { - return 1; - } - } - - return 0; -} -EXPORT_SYMBOL(page_is_ram); - -/* - * Initialize the bootmem system and give it all the memory we - * have available. - */ -#ifndef CONFIG_NEED_MULTIPLE_NODES -void __init do_init_bootmem(void) -{ - unsigned long i; - unsigned long start, bootmap_pages; - unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; - int boot_mapsize; - - /* - * Find an area to use for the bootmem bitmap. Calculate the size of - * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE. - * Add 1 additional page in case the address isn't page-aligned. - */ - bootmap_pages = bootmem_bootmap_pages(total_pages); - - start = lmb_alloc(bootmap_pages<> PAGE_SHIFT, total_pages); - - max_pfn = max_low_pfn; - - /* Add all physical memory to the bootmem map, mark each area - * present. - */ - for (i=0; i < lmb.memory.cnt; i++) - free_bootmem(lmb.memory.region[i].base, - lmb_size_bytes(&lmb.memory, i)); - - /* reserve the sections we're already using */ - for (i=0; i < lmb.reserved.cnt; i++) - reserve_bootmem(lmb.reserved.region[i].base, - lmb_size_bytes(&lmb.reserved, i)); - - for (i=0; i < lmb.memory.cnt; i++) - memory_present(0, lmb_start_pfn(&lmb.memory, i), - lmb_end_pfn(&lmb.memory, i)); -} - -/* - * paging_init() sets up the page tables - in fact we've already done this. - */ -void __init paging_init(void) -{ - unsigned long zones_size[MAX_NR_ZONES]; - unsigned long zholes_size[MAX_NR_ZONES]; - unsigned long total_ram = lmb_phys_mem_size(); - unsigned long top_of_ram = lmb_end_of_DRAM(); - - printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", - top_of_ram, total_ram); - printk(KERN_INFO "Memory hole size: %ldMB\n", - (top_of_ram - total_ram) >> 20); - /* - * All pages are DMA-able so we put them all in the DMA zone. - */ - memset(zones_size, 0, sizeof(zones_size)); - memset(zholes_size, 0, sizeof(zholes_size)); - - zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; - zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT; - - free_area_init_node(0, NODE_DATA(0), zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); -} -#endif /* ! CONFIG_NEED_MULTIPLE_NODES */ - -static struct kcore_list kcore_vmem; - -static int __init setup_kcore(void) -{ - int i; - - for (i=0; i < lmb.memory.cnt; i++) { - unsigned long base, size; - struct kcore_list *kcore_mem; - - base = lmb.memory.region[i].base; - size = lmb.memory.region[i].size; - - /* GFP_ATOMIC to avoid might_sleep warnings during boot */ - kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC); - if (!kcore_mem) - panic("mem_init: kmalloc failed\n"); - - kclist_add(kcore_mem, __va(base), size); - } - - kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); - - return 0; -} -module_init(setup_kcore); - -void __init mem_init(void) -{ -#ifdef CONFIG_NEED_MULTIPLE_NODES - int nid; -#endif - pg_data_t *pgdat; - unsigned long i; - struct page *page; - unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; - - num_physpages = max_low_pfn; /* RAM is assumed contiguous */ - high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); - -#ifdef CONFIG_NEED_MULTIPLE_NODES - for_each_online_node(nid) { - if (NODE_DATA(nid)->node_spanned_pages != 0) { - printk("freeing bootmem node %x\n", nid); - totalram_pages += - free_all_bootmem_node(NODE_DATA(nid)); - } - } -#else - max_mapnr = num_physpages; - totalram_pages += free_all_bootmem(); -#endif - - for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_spanned_pages; i++) { - page = pgdat_page_nr(pgdat, i); - if (PageReserved(page)) - reservedpages++; - } - } - - codesize = (unsigned long)&_etext - (unsigned long)&_stext; - initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; - datasize = (unsigned long)&_edata - (unsigned long)&__init_end; - bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; - - printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " - "%luk reserved, %luk data, %luk bss, %luk init)\n", - (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), - num_physpages << (PAGE_SHIFT-10), - codesize >> 10, - reservedpages << (PAGE_SHIFT-10), - datasize >> 10, - bsssize >> 10, - initsize >> 10); - - mem_init_done = 1; - - /* Initialize the vDSO */ - vdso_init(); -} - -/* - * This is called when a page has been modified by the kernel. - * It just marks the page as not i-cache clean. We do the i-cache - * flush later when the page is given to a user process, if necessary. - */ -void flush_dcache_page(struct page *page) -{ - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &page->flags)) - clear_bit(PG_arch_1, &page->flags); -} -EXPORT_SYMBOL(flush_dcache_page); - -void clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - clear_page(page); - - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - /* - * We shouldnt have to do this, but some versions of glibc - * require it (ld.so assumes zero filled pages are icache clean) - * - Anton - */ - - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &pg->flags)) - clear_bit(PG_arch_1, &pg->flags); -} -EXPORT_SYMBOL(clear_user_page); - -void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *pg) -{ - copy_page(vto, vfrom); - - /* - * We should be able to use the following optimisation, however - * there are two problems. - * Firstly a bug in some versions of binutils meant PLT sections - * were not marked executable. - * Secondly the first word in the GOT section is blrl, used - * to establish the GOT address. Until recently the GOT was - * not marked executable. - * - Anton - */ -#if 0 - if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0)) - return; -#endif - - if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) - return; - - /* avoid an atomic op if possible */ - if (test_bit(PG_arch_1, &pg->flags)) - clear_bit(PG_arch_1, &pg->flags); -} - -void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, - unsigned long addr, int len) -{ - unsigned long maddr; - - maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK); - flush_icache_range(maddr, maddr + len); -} -EXPORT_SYMBOL(flush_icache_user_range); - -/* - * This is called at the end of handling a user page fault, when the - * fault has been handled by updating a PTE in the linux page tables. - * We use it to preload an HPTE into the hash table corresponding to - * the updated linux PTE. - * - * This must always be called with the mm->page_table_lock held - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea, - pte_t pte) -{ - unsigned long vsid; - void *pgdir; - pte_t *ptep; - int local = 0; - cpumask_t tmp; - unsigned long flags; - - /* handle i-cache coherency */ - if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && - !cpu_has_feature(CPU_FTR_NOEXECUTE)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - if (!PageReserved(page) - && !test_bit(PG_arch_1, &page->flags)) { - __flush_dcache_icache(page_address(page)); - set_bit(PG_arch_1, &page->flags); - } - } - } - - /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ - if (!pte_young(pte)) - return; - - pgdir = vma->vm_mm->pgd; - if (pgdir == NULL) - return; - - ptep = find_linux_pte(pgdir, ea); - if (!ptep) - return; - - vsid = get_vsid(vma->vm_mm->context.id, ea); - - local_irq_save(flags); - tmp = cpumask_of_cpu(smp_processor_id()); - if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) - local = 1; - - __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, - 0x300, local); - local_irq_restore(flags); -} - -void __iomem * reserve_phb_iospace(unsigned long size) -{ - void __iomem *virt_addr; - - if (phbs_io_bot >= IMALLOC_BASE) - panic("reserve_phb_iospace(): phb io space overflow\n"); - - virt_addr = (void __iomem *) phbs_io_bot; - phbs_io_bot += size; - - return virt_addr; -} - -static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) -{ - memset(addr, 0, kmem_cache_size(cache)); -} - -static const int pgtable_cache_size[2] = { - PTE_TABLE_SIZE, PMD_TABLE_SIZE -}; -static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { - "pgd_pte_cache", "pud_pmd_cache", -}; - -kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; - -void pgtable_cache_init(void) -{ - int i; - - BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]); - BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]); - BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]); - BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]); - - for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) { - int size = pgtable_cache_size[i]; - const char *name = pgtable_cache_name[i]; - - pgtable_cache[i] = kmem_cache_create(name, - size, size, - SLAB_HWCACHE_ALIGN - | SLAB_MUST_HWCACHE_ALIGN, - zero_ctor, - NULL); - if (! pgtable_cache[i]) - panic("pgtable_cache_init(): could not create %s!\n", - name); - } -} - -pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, - unsigned long size, pgprot_t vma_prot) -{ - if (ppc_md.phys_mem_access_prot) - return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); - - if (!page_is_ram(addr >> PAGE_SHIFT)) - vma_prot = __pgprot(pgprot_val(vma_prot) - | _PAGE_GUARDED | _PAGE_NO_CACHE); - return vma_prot; -} -EXPORT_SYMBOL(phys_mem_access_prot); From 69a80d3f69d0b2d7fae5a73c6e034d402d434d8a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:03:41 +1000 Subject: [PATCH 0334/1939] powerpc: move pSeries files to arch/powerpc/platforms/pseries Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Makefile | 1 + arch/powerpc/platforms/pseries/Makefile | 4 ++ .../platforms/pseries/hvCall.S} | 0 .../platforms/pseries/iommu.c} | 0 .../platforms/pseries/lpar.c} | 0 .../platforms/pseries/nvram.c} | 0 .../platforms/pseries/pci.c} | 0 .../platforms/pseries/reconfig.c} | 0 .../platforms/pseries/setup.c} | 6 +-- .../platforms/pseries/smp.c} | 48 +------------------ .../platforms/pseries/vio.c} | 0 arch/ppc64/kernel/Makefile | 4 +- 12 files changed, 10 insertions(+), 53 deletions(-) create mode 100644 arch/powerpc/platforms/pseries/Makefile rename arch/{ppc64/kernel/pSeries_hvCall.S => powerpc/platforms/pseries/hvCall.S} (100%) rename arch/{ppc64/kernel/pSeries_iommu.c => powerpc/platforms/pseries/iommu.c} (100%) rename arch/{ppc64/kernel/pSeries_lpar.c => powerpc/platforms/pseries/lpar.c} (100%) rename arch/{ppc64/kernel/pSeries_nvram.c => powerpc/platforms/pseries/nvram.c} (100%) rename arch/{ppc64/kernel/pSeries_pci.c => powerpc/platforms/pseries/pci.c} (100%) rename arch/{ppc64/kernel/pSeries_reconfig.c => powerpc/platforms/pseries/reconfig.c} (100%) rename arch/{ppc64/kernel/pSeries_setup.c => powerpc/platforms/pseries/setup.c} (99%) rename arch/{ppc64/kernel/pSeries_smp.c => powerpc/platforms/pseries/smp.c} (92%) rename arch/{ppc64/kernel/pSeries_vio.c => powerpc/platforms/pseries/vio.c} (100%) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 7637ff3642c3..181ae612b2d3 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -4,4 +4,5 @@ endif obj-$(CONFIG_4xx) += 4xx/ obj-$(CONFIG_83xx) += 83xx/ obj-$(CONFIG_85xx) += 85xx/ +obj-$(CONFIG_PPC_PSERIES) += pseries/ obj-$(CONFIG_PPC_ISERIES) += iseries/ diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile new file mode 100644 index 000000000000..9ebb34180a10 --- /dev/null +++ b/arch/powerpc/platforms/pseries/Makefile @@ -0,0 +1,4 @@ +obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ + setup.o iommu.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_IBMVIO) += vio.o diff --git a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S similarity index 100% rename from arch/ppc64/kernel/pSeries_hvCall.S rename to arch/powerpc/platforms/pseries/hvCall.S diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/powerpc/platforms/pseries/iommu.c similarity index 100% rename from arch/ppc64/kernel/pSeries_iommu.c rename to arch/powerpc/platforms/pseries/iommu.c diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/powerpc/platforms/pseries/lpar.c similarity index 100% rename from arch/ppc64/kernel/pSeries_lpar.c rename to arch/powerpc/platforms/pseries/lpar.c diff --git a/arch/ppc64/kernel/pSeries_nvram.c b/arch/powerpc/platforms/pseries/nvram.c similarity index 100% rename from arch/ppc64/kernel/pSeries_nvram.c rename to arch/powerpc/platforms/pseries/nvram.c diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/powerpc/platforms/pseries/pci.c similarity index 100% rename from arch/ppc64/kernel/pSeries_pci.c rename to arch/powerpc/platforms/pseries/pci.c diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c similarity index 100% rename from arch/ppc64/kernel/pSeries_reconfig.c rename to arch/powerpc/platforms/pseries/reconfig.c diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/powerpc/platforms/pseries/setup.c similarity index 99% rename from arch/ppc64/kernel/pSeries_setup.c rename to arch/powerpc/platforms/pseries/setup.c index 5a9fe96f9f67..eb25ee2eead8 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -64,8 +64,8 @@ #include #include #include - -#include "i8259.h" +#include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -124,7 +124,7 @@ static int pSeries_irq_cascade(struct pt_regs *regs, void *data) if (chrp_int_ack_special) return readb(chrp_int_ack_special); else - return i8259_irq(smp_processor_id()); + return i8259_irq(regs); } static void __init pSeries_init_mpic(void) diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/powerpc/platforms/pseries/smp.c similarity index 92% rename from arch/ppc64/kernel/pSeries_smp.c rename to arch/powerpc/platforms/pseries/smp.c index 5d1ed850f47b..ae1bd270f308 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -1,5 +1,5 @@ /* - * SMP support for pSeries and BPA machines. + * SMP support for pSeries machines. * * Dave Engebretsen, Peter Bergner, and * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com @@ -48,8 +48,6 @@ #include #include -#include "bpa_iic.h" - #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) #else @@ -343,36 +341,6 @@ static void __devinit smp_xics_setup_cpu(int cpu) } #endif /* CONFIG_XICS */ -#ifdef CONFIG_BPA_IIC -static void smp_iic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - iic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - iic_cause_IPI(i, msg); - } - } -} - -static int __init smp_iic_probe(void) -{ - iic_request_IPIs(); - - return cpus_weight(cpu_possible_map); -} - -static void __devinit smp_iic_setup_cpu(int cpu) -{ - if (cpu != boot_cpuid) - iic_setup_cpu(); -} -#endif /* CONFIG_BPA_IIC */ static DEFINE_SPINLOCK(timebase_lock); static unsigned long timebase = 0; @@ -444,15 +412,6 @@ static struct smp_ops_t pSeries_xics_smp_ops = { .cpu_bootable = smp_pSeries_cpu_bootable, }; #endif -#ifdef CONFIG_BPA_IIC -static struct smp_ops_t bpa_iic_smp_ops = { - .message_pass = smp_iic_message_pass, - .probe = smp_iic_probe, - .kick_cpu = smp_pSeries_kick_cpu, - .setup_cpu = smp_iic_setup_cpu, - .cpu_bootable = smp_pSeries_cpu_bootable, -}; -#endif /* This is called very early */ void __init smp_init_pSeries(void) @@ -471,11 +430,6 @@ void __init smp_init_pSeries(void) case IC_PPC_XIC: smp_ops = &pSeries_xics_smp_ops; break; -#endif -#ifdef CONFIG_BPA_IIC - case IC_BPA_IIC: - smp_ops = &bpa_iic_smp_ops; - break; #endif default: panic("Invalid interrupt controller"); diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/powerpc/platforms/pseries/vio.c similarity index 100% rename from arch/ppc64/kernel/pSeries_vio.c rename to arch/powerpc/platforms/pseries/vio.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 32fd3f1c7935..6a0fea272386 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -24,9 +24,7 @@ obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o -obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ - pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ - pSeries_setup.o pSeries_iommu.o udbg_16550.o +obj-$(CONFIG_PPC_PSERIES) += rtasd.o ras.o udbg_16550.o obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ bpa_iic.o spider-pic.o From c17e3325ba603642922219b19623764ba5280ad4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:07:35 +1000 Subject: [PATCH 0335/1939] ppc64: Use SPRN_ prefix for special purpose register names Now that we are using the merged reg.h we have to use the SPRN_xxx names rather than the xxx names. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/entry.S | 30 +++--- arch/ppc64/kernel/head.S | 194 +++++++++++++++++++------------------- 2 files changed, 112 insertions(+), 112 deletions(-) diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index e8c0bbf4d000..ea30af810e0c 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -191,8 +191,8 @@ syscall_exit_trace_cont: ld r1,GPR1(r1) mtlr r4 mtcr r5 - mtspr SRR0,r7 - mtspr SRR1,r8 + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r8 rfid b . /* prevent speculative execution */ @@ -531,7 +531,7 @@ restore: mtctr r3 mtlr r0 ld r3,_XER(r1) - mtspr XER,r3 + mtspr SPRN_XER,r3 REST_8GPRS(5, r1) @@ -543,12 +543,12 @@ restore: mtmsrd r0,1 ld r0,_MSR(r1) - mtspr SRR1,r0 + mtspr SPRN_SRR1,r0 ld r2,_CCR(r1) mtcrf 0xFF,r2 ld r2,_NIP(r1) - mtspr SRR0,r2 + mtspr SPRN_SRR0,r2 ld r0,GPR0(r1) ld r2,GPR2(r1) @@ -643,7 +643,7 @@ _GLOBAL(enter_rtas) std r4,_CCR(r1) mfctr r5 std r5,_CTR(r1) - mfspr r6,XER + mfspr r6,SPRN_XER std r6,_XER(r1) mfdar r7 std r7,_DAR(r1) @@ -697,14 +697,14 @@ _GLOBAL(enter_rtas) ld r5,RTASENTRY(r4) /* get the rtas->entry value */ ld r4,RTASBASE(r4) /* get the rtas->base value */ - mtspr SRR0,r5 - mtspr SRR1,r6 + mtspr SPRN_SRR0,r5 + mtspr SPRN_SRR1,r6 rfid b . /* prevent speculative execution */ _STATIC(rtas_return_loc) /* relocation is off at this point */ - mfspr r4,SPRG3 /* Get PACA */ + mfspr r4,SPRN_SPRG3 /* Get PACA */ SET_REG_TO_CONST(r5, KERNELBASE) sub r4,r4,r5 /* RELOC the PACA base pointer */ @@ -718,8 +718,8 @@ _STATIC(rtas_return_loc) LOADADDR(r3,.rtas_restore_regs) ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ - mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 rfid b . /* prevent speculative execution */ @@ -730,14 +730,14 @@ _STATIC(rtas_restore_regs) REST_8GPRS(14, r1) /* Restore the non-volatiles */ REST_10GPRS(22, r1) /* ditto */ - mfspr r13,SPRG3 + mfspr r13,SPRN_SPRG3 ld r4,_CCR(r1) mtcr r4 ld r5,_CTR(r1) mtctr r5 ld r6,_XER(r1) - mtspr XER,r6 + mtspr SPRN_XER,r6 ld r7,_DAR(r1) mtdar r7 ld r8,_DSISR(r1) @@ -774,7 +774,7 @@ _GLOBAL(enter_prom) std r4,_CCR(r1) mfctr r5 std r5,_CTR(r1) - mfspr r6,XER + mfspr r6,SPRN_XER std r6,_XER(r1) mfdar r7 std r7,_DAR(r1) @@ -827,7 +827,7 @@ _GLOBAL(enter_prom) ld r5,_CTR(r1) mtctr r5 ld r6,_XER(r1) - mtspr XER,r6 + mtspr SPRN_XER,r6 ld r7,_DAR(r1) mtdar r7 ld r8,_DSISR(r1) diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index db0cd3587627..d5e6be200764 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -201,22 +201,22 @@ exception_marker: #define EX_CCR 60 #define EXCEPTION_PROLOG_PSERIES(area, label) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ + mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9; \ clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ - mfspr r11,SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_SRR0; /* save SRR0 */ \ ori r12,r12,(label)@l; /* virt addr of handler */ \ ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SRR0,r12; \ - mfspr r12,SRR1; /* and SRR1 */ \ - mtspr SRR1,r10; \ + mtspr SPRN_SRR0,r12; \ + mfspr r12,SPRN_SRR1; /* and SRR1 */ \ + mtspr SPRN_SRR1,r10; \ rfid; \ b . /* prevent speculative execution */ @@ -225,12 +225,12 @@ exception_marker: * This code runs with relocation on. */ #define EXCEPTION_PROLOG_ISERIES_1(area) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ + mfspr r9,SPRN_SPRG1; \ std r9,area+EX_R13(r13); \ mfcr r9 @@ -283,7 +283,7 @@ exception_marker: std r9,_LINK(r1); \ mfctr r10; /* save CTR in stackframe */ \ std r10,_CTR(r1); \ - mfspr r11,XER; /* save XER in stackframe */ \ + mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r11,_XER(r1); \ li r9,(n)+1; \ std r9,_TRAP(r1); /* set trap number */ \ @@ -300,7 +300,7 @@ exception_marker: .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) @@ -308,7 +308,7 @@ label##_pSeries: \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(area); \ EXCEPTION_PROLOG_ISERIES_2; \ @@ -318,7 +318,7 @@ label##_iSeries: \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ lbz r10,PACAPROCENABLED(r13); \ @@ -388,7 +388,7 @@ __start_interrupts: . = 0x200 _machine_check_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) @@ -396,18 +396,18 @@ _machine_check_pSeries: .globl data_access_pSeries data_access_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR srdi r13,r13,60 rlwimi r13,r12,16,0x20 mfcr r12 cmpwi r13,0x2c beq .do_stab_bolted_pSeries mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 END_FTR_SECTION_IFCLR(CPU_FTR_SLB) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) @@ -415,19 +415,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) .globl data_access_slb_pSeries data_access_slb_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 + mfspr r9,SPRN_SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,DAR + mfspr r12,SPRN_SRR1 /* and SRR1 */ + mfspr r3,SPRN_DAR b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x400, instruction_access) @@ -436,19 +436,19 @@ data_access_slb_pSeries: .globl instruction_access_slb_pSeries instruction_access_slb_pSeries: HMT_MEDIUM - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 + mfspr r9,SPRN_SPRG1 std r9,PACA_EXSLB+EX_R13(r13) mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,SRR0 /* SRR0 is faulting address */ + mfspr r12,SPRN_SRR1 /* and SRR1 */ + mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ b .do_slb_miss /* Rel. branch works in real mode */ STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) @@ -466,15 +466,15 @@ system_call_pSeries: RUNLATCH_ON(r9) mr r9,r13 mfmsr r10 - mfspr r13,SPRG3 - mfspr r11,SRR0 + mfspr r13,SPRN_SPRG3 + mfspr r11,SPRN_SRR0 clrrdi r12,r13,32 oris r12,r12,system_call_common@h ori r12,r12,system_call_common@l - mtspr SRR0,r12 + mtspr SPRN_SRR0,r12 ori r10,r10,MSR_IR|MSR_DR|MSR_RI - mfspr r12,SRR1 - mtspr SRR1,r10 + mfspr r12,SPRN_SRR1 + mtspr SPRN_SRR1,r10 rfid b . /* prevent speculative execution */ @@ -504,25 +504,25 @@ system_call_pSeries: .align 7 _GLOBAL(do_stab_bolted_pSeries) mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) /* * Vectors for the FWNMI option. Share common code. */ - .globl system_reset_fwnmi + .globl system_reset_fwnmi system_reset_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) + HMT_MEDIUM + mtspr SPRN_SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) - .globl machine_check_fwnmi + .globl machine_check_fwnmi machine_check_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + HMT_MEDIUM + mtspr SPRN_SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) #ifdef CONFIG_PPC_ISERIES /*** ISeries-LPAR interrupt handlers ***/ @@ -531,18 +531,18 @@ machine_check_fwnmi: .globl data_access_iSeries data_access_iSeries: - mtspr SPRG1,r13 + mtspr SPRN_SPRG1,r13 BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR srdi r13,r13,60 rlwimi r13,r12,16,0x20 mfcr r12 cmpwi r13,0x2c beq .do_stab_bolted_iSeries mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 END_FTR_SECTION_IFCLR(CPU_FTR_SLB) EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_2 @@ -550,25 +550,25 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) .do_stab_bolted_iSeries: mtcrf 0x80,r12 - mfspr r12,SPRG2 + mfspr r12,SPRN_SPRG2 EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) EXCEPTION_PROLOG_ISERIES_2 b .do_stab_bolted .globl data_access_slb_iSeries data_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mfspr r3,DAR + mfspr r3,SPRN_DAR b .do_slb_miss STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) .globl instruction_access_slb_iSeries instruction_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ + mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) std r3,PACA_EXSLB+EX_R3(r13) ld r12,PACALPPACA+LPPACASRR1(r13) @@ -586,7 +586,7 @@ instruction_access_slb_iSeries: .globl system_call_iSeries system_call_iSeries: mr r9,r13 - mfspr r13,SPRG3 + mfspr r13,SPRN_SPRG3 EXCEPTION_PROLOG_ISERIES_2 b system_call_common @@ -596,7 +596,7 @@ system_call_iSeries: .globl system_reset_iSeries system_reset_iSeries: - mfspr r13,SPRG3 /* Get paca address */ + mfspr r13,SPRN_SPRG3 /* Get paca address */ mfmsr r24 ori r24,r24,MSR_RI mtmsrd r24 /* RI on */ @@ -639,7 +639,7 @@ iSeries_secondary_smp_loop: #endif /* CONFIG_SMP */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ - mfspr r13,SPRG3 /* Put r13 back ???? */ + mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ b 1b /* If SMP not configured, secondaries * loop forever */ @@ -656,8 +656,8 @@ hardware_interrupt_iSeries_masked: mtcrf 0x80,r9 /* Restore regs */ ld r11,PACALPPACA+LPPACASRR0(r13) ld r12,PACALPPACA+LPPACASRR1(r13) - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 ld r9,PACA_EXGEN+EX_R9(r13) ld r10,PACA_EXGEN+EX_R10(r13) ld r11,PACA_EXGEN+EX_R11(r13) @@ -713,8 +713,8 @@ bad_stack: std r10,GPR1(r1) std r11,_NIP(r1) std r12,_MSR(r1) - mfspr r11,DAR - mfspr r12,DSISR + mfspr r11,SPRN_DAR + mfspr r12,SPRN_DSISR std r11,_DAR(r1) std r12,_DSISR(r1) mflr r10 @@ -766,8 +766,8 @@ fast_exception_return: clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ mtmsrd r10,1 - mtspr SRR1,r12 - mtspr SRR0,r11 + mtspr SPRN_SRR1,r12 + mtspr SPRN_SRR0,r11 REST_4GPRS(10, r1) ld r1,GPR1(r1) rfid @@ -788,9 +788,9 @@ unrecov_fer: .globl data_access_common data_access_common: RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */ - mfspr r10,DAR + mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR + mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) ld r3,PACA_EXGEN+EX_DAR(r13) @@ -821,9 +821,9 @@ hardware_interrupt_entry: .align 7 .globl alignment_common alignment_common: - mfspr r10,DAR + mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR + mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN) ld r3,PACA_EXGEN+EX_DAR(r13) @@ -1120,7 +1120,7 @@ _GLOBAL(do_stab_bolted) /* Hash to the primary group */ ld r10,PACASTABVIRT(r13) - mfspr r11,DAR + mfspr r11,SPRN_DAR srdi r11,r11,28 rldimi r10,r11,7,52 /* r10 = first ste of the group */ @@ -1162,7 +1162,7 @@ _GLOBAL(do_stab_bolted) 2: std r9,8(r10) /* Store the vsid part of the ste */ eieio - mfspr r11,DAR /* Get the new esid */ + mfspr r11,SPRN_DAR /* Get the new esid */ clrrdi r11,r11,28 /* Permits a full 32b of ESID */ ori r11,r11,0x90 /* Turn on valid and kp */ std r11,0(r10) /* Put new entry back into the stab */ @@ -1182,8 +1182,8 @@ _GLOBAL(do_stab_bolted) clrrdi r10,r10,2 mtmsrd r10,1 - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -1229,8 +1229,8 @@ _GLOBAL(do_slb_miss) .machine pop #ifdef CONFIG_PPC_ISERIES - mtspr SRR0,r11 - mtspr SRR1,r12 + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 #endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) @@ -1316,7 +1316,7 @@ _GLOBAL(pSeries_secondary_smp_init) mr r3,r24 /* not found, copy phys to r3 */ b .kexec_wait /* next kernel might do better */ -2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ +2: mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */ /* From now on, r24 is expected to be logical cpuid */ mr r24,r5 3: HMT_LOW @@ -1587,7 +1587,7 @@ _GLOBAL(pmac_secondary_start) LOADADDR(r4, paca) /* Get base vaddr of paca array */ mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r4 /* for this processor. */ - mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ + mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */ /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) @@ -1622,7 +1622,7 @@ _GLOBAL(__secondary_start) /* Initialize the page table pointer register. */ LOADADDR(r6,_SDR1) ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ + mtspr SPRN_SDR1,r6 /* set the htab location */ #endif /* Initialize the first segment table (or SLB) entry */ ld r3,PACASTABVIRT(r13) /* get addr of segment table */ @@ -1651,7 +1651,7 @@ _GLOBAL(__secondary_start) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ beq 98f /* branch if result is 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ beq 97f @@ -1675,8 +1675,8 @@ _GLOBAL(__secondary_start) #ifdef DO_SOFT_DISABLE ori r4,r4,MSR_EE #endif - mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 rfid b . /* prevent speculative execution */ @@ -1738,7 +1738,7 @@ _STATIC(start_here_multiplatform) #ifdef CONFIG_HMT /* Start up the second thread on cpu 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x34 /* Pulsar */ beq 90f @@ -1798,7 +1798,7 @@ _STATIC(start_here_multiplatform) mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ sub r13,r13,r26 /* convert to physical addr */ - mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ + mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */ /* Do very early kernel initializations, including initial hash table, * stab and slb setup before we turn on relocation. */ @@ -1815,7 +1815,7 @@ _STATIC(start_here_multiplatform) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ beq 98f /* branch if result is 0 */ - mfspr r3,PVR + mfspr r3,SPRN_PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ beq 97f @@ -1839,12 +1839,12 @@ _STATIC(start_here_multiplatform) LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ sub r6,r6,r26 ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ + mtspr SPRN_SDR1,r6 /* set the htab location */ 98: LOADADDR(r3,.start_here_common) SET_REG_TO_CONST(r4, MSR_KERNEL) - mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 rfid b . /* prevent speculative execution */ #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -1875,7 +1875,7 @@ _STATIC(start_here_common) LOADADDR(r24, paca) /* Get base vaddr of paca array */ mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ - mtspr SPRG3,r13 + mtspr SPRN_SPRG3,r13 /* ptr to current */ LOADADDR(r4,init_task) @@ -1902,7 +1902,7 @@ _STATIC(start_here_common) _GLOBAL(hmt_init) #ifdef CONFIG_HMT LOADADDR(r5, hmt_thread_data) - mfspr r7,PVR + mfspr r7,SPRN_PVR srwi r7,r7,16 cmpwi r7,0x34 /* Pulsar */ beq 90f @@ -1911,10 +1911,10 @@ _GLOBAL(hmt_init) cmpwi r7,0x37 /* SStar */ beq 91f b 101f -90: mfspr r6,PIR +90: mfspr r6,SPRN_PIR andi. r6,r6,0x1f b 92f -91: mfspr r6,PIR +91: mfspr r6,SPRN_PIR andi. r6,r6,0x3ff 92: sldi r4,r24,3 stwx r6,r5,r4 @@ -1925,8 +1925,8 @@ __hmt_secondary_hold: LOADADDR(r5, hmt_thread_data) clrldi r5,r5,4 li r7,0 - mfspr r6,PIR - mfspr r8,PVR + mfspr r6,SPRN_PIR + mfspr r8,SPRN_PVR srwi r8,r8,16 cmpwi r8,0x34 bne 93f @@ -1952,19 +1952,19 @@ __hmt_secondary_hold: _GLOBAL(hmt_start_secondary) LOADADDR(r4,__hmt_secondary_hold) clrldi r4,r4,4 - mtspr NIADORM, r4 - mfspr r4, MSRDORM + mtspr SPRN_NIADORM, r4 + mfspr r4, SPRN_MSRDORM li r5, -65 and r4, r4, r5 - mtspr MSRDORM, r4 + mtspr SPRN_MSRDORM, r4 lis r4,0xffef ori r4,r4,0x7403 - mtspr TSC, r4 + mtspr SPRN_TSC, r4 li r4,0x1f4 - mtspr TST, r4 - mfspr r4, HID0 + mtspr SPRN_TST, r4 + mfspr r4, SPRN_HID0 ori r4, r4, 0x1 - mtspr HID0, r4 + mtspr SPRN_HID0, r4 mfspr r4, SPRN_CTRLF oris r4, r4, 0x40 mtspr SPRN_CTRLT, r4 From f6d57916db2009bd7e220472200cd131fc010d64 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:13:53 +1000 Subject: [PATCH 0336/1939] powerpc: rename powermac files to remove pmac_ prefix Since the files are now in arch/powerpc/platforms/powermac, the pmac_ prefix that they had is redundant. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/Makefile | 13 ++++++------- .../powermac/{pmac_backlight.c => backlight.c} | 0 .../platforms/powermac/{pmac_cache.S => cache.S} | 0 .../powermac/{pmac_cpufreq.c => cpufreq.c} | 0 .../powermac/{pmac_feature.c => feature.c} | 0 .../powermac/{pmac_low_i2c.c => low_i2c.c} | 0 .../platforms/powermac/{pmac_nvram.c => nvram.c} | 0 .../platforms/powermac/{pmac_pci.c => pci.c} | 0 .../platforms/powermac/{pmac_pic.c => pic.c} | 0 .../platforms/powermac/{pmac_pic.h => pic.h} | 0 .../platforms/powermac/{pmac_setup.c => setup.c} | 0 .../platforms/powermac/{pmac_sleep.S => sleep.S} | 0 .../platforms/powermac/{pmac_smp.c => smp.c} | 0 .../platforms/powermac/{pmac_time.c => time.c} | 0 14 files changed, 6 insertions(+), 7 deletions(-) rename arch/powerpc/platforms/powermac/{pmac_backlight.c => backlight.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_cache.S => cache.S} (100%) rename arch/powerpc/platforms/powermac/{pmac_cpufreq.c => cpufreq.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_feature.c => feature.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_low_i2c.c => low_i2c.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_nvram.c => nvram.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_pci.c => pci.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_pic.c => pic.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_pic.h => pic.h} (100%) rename arch/powerpc/platforms/powermac/{pmac_setup.c => setup.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_sleep.S => sleep.S} (100%) rename arch/powerpc/platforms/powermac/{pmac_smp.c => smp.c} (100%) rename arch/powerpc/platforms/powermac/{pmac_time.c => time.c} (100%) diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 37b7341396e4..74712ede16df 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,9 +1,8 @@ -obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ - pmac_feature.o pmac_pci.o pmac_sleep.o \ - pmac_low_i2c.o pmac_cache.o -obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o +obj-$(CONFIG_PPC_PMAC) += pic.o setup.o time.o feature.o pci.o \ + sleep.o low_i2c.o cache.o +obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o +obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o ifeq ($(CONFIG_PPC_PMAC),y) -obj-$(CONFIG_NVRAM) += pmac_nvram.o -obj-$(CONFIG_SMP) += pmac_smp.o +obj-$(CONFIG_NVRAM) += nvram.o +obj-$(CONFIG_SMP) += smp.o endif diff --git a/arch/powerpc/platforms/powermac/pmac_backlight.c b/arch/powerpc/platforms/powermac/backlight.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_backlight.c rename to arch/powerpc/platforms/powermac/backlight.c diff --git a/arch/powerpc/platforms/powermac/pmac_cache.S b/arch/powerpc/platforms/powermac/cache.S similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_cache.S rename to arch/powerpc/platforms/powermac/cache.S diff --git a/arch/powerpc/platforms/powermac/pmac_cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_cpufreq.c rename to arch/powerpc/platforms/powermac/cpufreq.c diff --git a/arch/powerpc/platforms/powermac/pmac_feature.c b/arch/powerpc/platforms/powermac/feature.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_feature.c rename to arch/powerpc/platforms/powermac/feature.c diff --git a/arch/powerpc/platforms/powermac/pmac_low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_low_i2c.c rename to arch/powerpc/platforms/powermac/low_i2c.c diff --git a/arch/powerpc/platforms/powermac/pmac_nvram.c b/arch/powerpc/platforms/powermac/nvram.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_nvram.c rename to arch/powerpc/platforms/powermac/nvram.c diff --git a/arch/powerpc/platforms/powermac/pmac_pci.c b/arch/powerpc/platforms/powermac/pci.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_pci.c rename to arch/powerpc/platforms/powermac/pci.c diff --git a/arch/powerpc/platforms/powermac/pmac_pic.c b/arch/powerpc/platforms/powermac/pic.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_pic.c rename to arch/powerpc/platforms/powermac/pic.c diff --git a/arch/powerpc/platforms/powermac/pmac_pic.h b/arch/powerpc/platforms/powermac/pic.h similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_pic.h rename to arch/powerpc/platforms/powermac/pic.h diff --git a/arch/powerpc/platforms/powermac/pmac_setup.c b/arch/powerpc/platforms/powermac/setup.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_setup.c rename to arch/powerpc/platforms/powermac/setup.c diff --git a/arch/powerpc/platforms/powermac/pmac_sleep.S b/arch/powerpc/platforms/powermac/sleep.S similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_sleep.S rename to arch/powerpc/platforms/powermac/sleep.S diff --git a/arch/powerpc/platforms/powermac/pmac_smp.c b/arch/powerpc/platforms/powermac/smp.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_smp.c rename to arch/powerpc/platforms/powermac/smp.c diff --git a/arch/powerpc/platforms/powermac/pmac_time.c b/arch/powerpc/platforms/powermac/time.c similarity index 100% rename from arch/powerpc/platforms/powermac/pmac_time.c rename to arch/powerpc/platforms/powermac/time.c From ff64208df7eb17c5526197449762ff5e04a95de6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:15:52 +1000 Subject: [PATCH 0337/1939] powerpc: Merge Kconfig.debug This merges in the ppc64 bits into arch/powerpc/Kconfig.debug Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig.debug | 61 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 19df881bf67b..0baf64ec80d0 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -2,9 +2,42 @@ menu "Kernel hacking" source "lib/Kconfig.debug" +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL && PPC64 + help + This option will cause messages to be printed if free stack space + drops below a certain limit. + +config KPROBES + bool "Kprobes" + depends on DEBUG_KERNEL && PPC64 + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL && PPC64 + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config DEBUGGER + bool "Enable debugger hooks" + depends on DEBUG_KERNEL + help + Include in-kernel hooks for kernel debuggers. Unless you are + intending to debug the kernel, say N here. + config KGDB bool "Include kgdb kernel debugger" - depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) + depends on DEBUGGER && (BROKEN || PPC_GEN550 || 4xx) select DEBUG_INFO help Include in-kernel hooks for kgdb, the Linux kernel source level @@ -40,14 +73,36 @@ config KGDB_CONSOLE config XMON bool "Include xmon kernel debugger" - depends on DEBUG_KERNEL + depends on DEBUGGER && !PPC_ISERIES help Include in-kernel hooks for the xmon kernel monitor/debugger. Unless you are intending to debug the kernel, say N here. + Make sure to enable also CONFIG_BOOTX_TEXT on Macs. Otherwise + nothing will appear on the screen (xmon writes directly to the + framebuffer memory). + The cmdline option 'xmon' or 'xmon=early' will drop into xmon + very early during boot. 'xmon=on' will just enable the xmon + debugger hooks. 'xmon=off' will disable the debugger hooks + if CONFIG_XMON_DEFAULT is set. + +config XMON_DEFAULT + bool "Enable xmon by default" + depends on XMON + help + xmon is normally disabled unless booted with 'xmon=on'. + Use 'xmon=off' to disable xmon init during runtime. + +config IRQSTACKS + bool "Use separate kernel stacks when processing interrupts" + depends on PPC64 + help + If you say Y here the kernel will use separate kernel stacks + for handling hard and soft interrupts. This can help avoid + overflowing the process kernel stacks. config BDI_SWITCH bool "Include BDI-2000 user context switcher" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && PPC32 help Include in-kernel support for the Abatron BDI2000 debugger. Unless you are intending to debug the kernel with one of these From b3b8dc6c07cecc1f8d52d03f677206bdf9f794c9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:20:10 +1000 Subject: [PATCH 0338/1939] powerpc: Use reg.h instead of processor.h when we just want reg names Now that the register names and bit definitions are all in reg.h, use that instead of processor.h in assembly code in a few places. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/fpu.S | 2 +- arch/powerpc/kernel/head_32.S | 6 +++--- arch/powerpc/kernel/idle_6xx.S | 2 +- arch/powerpc/kernel/vector.S | 2 +- arch/powerpc/lib/string.S | 5 ----- arch/powerpc/mm/hash_low_32.S | 2 +- 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 04e95e810b21..563d445ff584 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index d9dbbd426744..108e78ef3878 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -23,7 +23,7 @@ */ #include -#include +#include #include #include #include @@ -55,8 +55,8 @@ 1: .text - .stabs "arch/ppc/kernel/",N_SO,0,0,0f - .stabs "head.S",N_SO,0,0,0f + .stabs "arch/powerpc/kernel/",N_SO,0,0,0f + .stabs "head_32.S",N_SO,0,0,0f 0: .globl _stext _stext: diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S index 1a2194cf6828..444fdcc769f1 100644 --- a/arch/powerpc/kernel/idle_6xx.S +++ b/arch/powerpc/kernel/idle_6xx.S @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 12cb90bc209c..66b3d03c5fa5 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -1,6 +1,6 @@ #include #include -#include +#include /* * The routines below are in assembler so we can closely control the diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index 15d40e9ef8b1..b9ca84ed8927 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -13,11 +13,6 @@ #include #include - .text - .stabs "arch/powerpc/lib/",N_SO,0,0,0f - .stabs "string.S",N_SO,0,0,0f -0: - .section __ex_table,"a" #ifdef CONFIG_PPC64 .align 3 diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S index 57278a8dd132..12ccd7155bac 100644 --- a/arch/powerpc/mm/hash_low_32.S +++ b/arch/powerpc/mm/hash_low_32.S @@ -24,7 +24,7 @@ */ #include -#include +#include #include #include #include From daec962e27490be4fae9ab5a51d0c17f6e638715 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:25:26 +1000 Subject: [PATCH 0339/1939] powerpc: Use arch/powerpc/mm and arch/powerpc/lib for 64-bit This also puts a copy of indirect_pci.c in arch/powerpc/sysdev so that we don't need to build in arch/ppc/syslib. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 15 ++-- arch/powerpc/sysdev/Makefile | 4 +- arch/powerpc/sysdev/indirect_pci.c | 134 +++++++++++++++++++++++++++++ arch/ppc/syslib/Makefile | 14 --- 4 files changed, 143 insertions(+), 24 deletions(-) create mode 100644 arch/powerpc/sysdev/indirect_pci.c diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 064864065753..a4c605f469d4 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -124,15 +124,12 @@ head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o endif -core-y += arch/powerpc/kernel/ -core-y += arch/$(OLDARCH)/kernel/ -core-$(CONFIG_PPC32) += arch/powerpc/mm/ -core-$(CONFIG_PPC64) += arch/$(OLDARCH)/mm/ -core-$(CONFIG_PPC32) += arch/powerpc/lib/ -libs-$(CONFIG_PPC64) += arch/$(OLDARCH)/lib/ -core-y += arch/powerpc/sysdev/ -core-y += arch/powerpc/platforms/ -core-$(CONFIG_PPC32) += arch/ppc/syslib/ +core-y += arch/powerpc/kernel/ \ + arch/$(OLDARCH)/kernel/ \ + arch/powerpc/mm/ \ + arch/powerpc/lib/ \ + arch/powerpc/sysdev/ \ + arch/powerpc/platforms/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_APUS) += arch/ppc/amiga/ diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 26bdcd9a2a43..c649f03acf68 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1 +1,3 @@ -obj-$(CONFIG_MPIC) += mpic.o +obj-$(CONFIG_MPIC) += mpic.o +indirectpci-$(CONFIG_PPC_PMAC) = indirect_pci.o +obj-$(CONFIG_PPC32) += $(indirectpci-y) diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c new file mode 100644 index 000000000000..e71488469704 --- /dev/null +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -0,0 +1,134 @@ +/* + * Support for indirect PCI bridges. + * + * Copyright (C) 1998 Gabriel Paubert. + * + * 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 + +#ifdef CONFIG_PPC_INDIRECT_PCI_BE +#define PCI_CFG_OUT out_be32 +#else +#define PCI_CFG_OUT out_le32 +#endif + +static int +indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + u8 cfg_type = 0; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; + + PCI_CFG_OUT(hose->cfg_addr, + (0x80000000 | ((bus->number - hose->bus_offset) << 16) + | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + (offset & 3); + switch (len) { + case 1: + *val = in_8(cfg_data); + break; + case 2: + *val = in_le16(cfg_data); + break; + default: + *val = in_le32(cfg_data); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + u8 cfg_type = 0; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; + + PCI_CFG_OUT(hose->cfg_addr, + (0x80000000 | ((bus->number - hose->bus_offset) << 16) + | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + (offset & 3); + switch (len) { + case 1: + out_8(cfg_data, val); + break; + case 2: + out_le16(cfg_data, val); + break; + default: + out_le32(cfg_data, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops indirect_pci_ops = +{ + indirect_read_config, + indirect_write_config +}; + +void __init +setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr, + void __iomem * cfg_data) +{ + hose->cfg_addr = cfg_addr; + hose->cfg_data = cfg_data; + hose->ops = &indirect_pci_ops; +} + +void __init +setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) +{ + unsigned long base = cfg_addr & PAGE_MASK; + void __iomem *mbase, *addr, *data; + + mbase = ioremap(base, PAGE_SIZE); + addr = mbase + (cfg_addr & ~PAGE_MASK); + if ((cfg_data & PAGE_MASK) != base) + mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); + data = mbase + (cfg_data & ~PAGE_MASK); + setup_indirect_pci_nomap(hose, addr, data); +} diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 1b0a84931afc..b8d08f33f7ee 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -5,7 +5,6 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC -ifneq ($(CONFIG_PPC_MERGE),y) wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o @@ -110,16 +109,3 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o \ ifeq ($(CONFIG_PPC_MPC52xx),y) obj-$(CONFIG_PCI) += mpc52xx_pci.o endif - -else -# Stuff still needed by the merged powerpc sources - -obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o -obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o -obj-$(CONFIG_PPC_PMAC) += indirect_pci.o -obj-$(CONFIG_PPC_CHRP) += indirect_pci.o i8259.o -obj-$(CONFIG_PPC_PREP) += indirect_pci.o i8259.o todc_time.o -obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o ppc_sys.o - -endif From 06d67d54741a5bfefa31945ef195dfa748c29025 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:29:05 +1000 Subject: [PATCH 0340/1939] powerpc: make process.c suitable for both 32-bit and 64-bit Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/init_task.c | 36 +++ arch/powerpc/kernel/process.c | 446 ++++++++++++++++++++++---------- include/asm-powerpc/elf.h | 6 +- 3 files changed, 352 insertions(+), 136 deletions(-) create mode 100644 arch/powerpc/kernel/init_task.c diff --git a/arch/powerpc/kernel/init_task.c b/arch/powerpc/kernel/init_task.c new file mode 100644 index 000000000000..941043ae040f --- /dev/null +++ b/arch/powerpc/kernel/init_task.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial thread structure. + * + * We need to make sure that this is 16384-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index ae316e9ed581..f09908a0beea 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -44,6 +46,11 @@ #include #include #include +#ifdef CONFIG_PPC64 +#include +#include +#include +#endif extern unsigned long _get_SP(void); @@ -53,26 +60,6 @@ struct task_struct *last_task_used_altivec = NULL; struct task_struct *last_task_used_spe = NULL; #endif -static struct fs_struct init_fs = INIT_FS; -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); -EXPORT_SYMBOL(init_mm); - -/* this is 8kB-aligned so we can get to the thread_info struct - at the base of it from the stack pointer with 1 integer instruction. */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = -{ INIT_THREAD_INFO(init_task) }; - -/* initial task structure */ -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); - -/* only used to get secondary processor up */ -struct task_struct *current_set[NR_CPUS] = {&init_task, }; - /* * Make sure the floating-point register state in the * the thread_struct is up to date for task tsk. @@ -237,7 +224,10 @@ int set_dabr(unsigned long dabr) return ret; } +#ifdef CONFIG_PPC64 +DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); static DEFINE_PER_CPU(unsigned long, current_dabr); +#endif struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) @@ -308,10 +298,27 @@ struct task_struct *__switch_to(struct task_struct *prev, set_dabr(new->thread.dabr); __get_cpu_var(current_dabr) = new->thread.dabr; } + + flush_tlb_pending(); #endif new_thread = &new->thread; old_thread = ¤t->thread; + +#ifdef CONFIG_PPC64 + /* + * Collect processor utilization data per process + */ + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { + struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); + long unsigned start_tb, current_tb; + start_tb = old_thread->start_tb; + cu->current_tb = current_tb = mfspr(SPRN_PURR); + old_thread->accum_tb += (current_tb - start_tb); + new_thread->start_tb = current_tb; + } +#endif + local_irq_save(flags); last = _switch(old_thread, new_thread); @@ -320,37 +327,106 @@ struct task_struct *__switch_to(struct task_struct *prev, return last; } +static int instructions_to_print = 16; + +#ifdef CONFIG_PPC64 +#define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \ + (REGION_ID(pc) != VMALLOC_REGION_ID)) +#else +#define BAD_PC(pc) ((pc) < KERNELBASE) +#endif + +static void show_instructions(struct pt_regs *regs) +{ + int i; + unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 * + sizeof(int)); + + printk("Instruction dump:"); + + for (i = 0; i < instructions_to_print; i++) { + int instr; + + if (!(i % 8)) + printk("\n"); + + if (BAD_PC(pc) || __get_user(instr, (unsigned int *)pc)) { + printk("XXXXXXXX "); + } else { + if (regs->nip == pc) + printk("<%08x> ", instr); + else + printk("%08x ", instr); + } + + pc += sizeof(int); + } + + printk("\n"); +} + +static struct regbit { + unsigned long bit; + const char *name; +} msr_bits[] = { + {MSR_EE, "EE"}, + {MSR_PR, "PR"}, + {MSR_FP, "FP"}, + {MSR_ME, "ME"}, + {MSR_IR, "IR"}, + {MSR_DR, "DR"}, + {0, NULL} +}; + +static void printbits(unsigned long val, struct regbit *bits) +{ + const char *sep = ""; + + printk("<"); + for (; bits->bit; ++bits) + if (val & bits->bit) { + printk("%s%s", sep, bits->name); + sep = ","; + } + printk(">"); +} + +#ifdef CONFIG_PPC64 +#define REG "%016lX" +#define REGS_PER_LINE 4 +#define LAST_VOLATILE 13 +#else +#define REG "%08lX" +#define REGS_PER_LINE 8 +#define LAST_VOLATILE 12 +#endif + void show_regs(struct pt_regs * regs) { int i, trap; - printk("NIP: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx %s\n", - regs->nip, regs->link, regs->gpr[1], regs, regs->trap, - print_tainted()); - printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", - regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, - regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, - regs->msr&MSR_IR ? 1 : 0, - regs->msr&MSR_DR ? 1 : 0); + printk("NIP: "REG" LR: "REG" CTR: "REG"\n", + regs->nip, regs->link, regs->ctr); + printk("REGS: %p TRAP: %04lx %s (%s)\n", + regs, regs->trap, print_tainted(), system_utsname.release); + printk("MSR: "REG" ", regs->msr); + printbits(regs->msr, msr_bits); + printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer); trap = TRAP(regs); if (trap == 0x300 || trap == 0x600) - printk("DAR: %08lX, DSISR: %08lX\n", regs->dar, regs->dsisr); - printk("TASK = %p[%d] '%s' THREAD: %p\n", + printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); + printk("TASK = %p[%d] '%s' THREAD: %p", current, current->pid, current->comm, current->thread_info); - printk("Last syscall: %ld ", current->thread.last_syscall); #ifdef CONFIG_SMP printk(" CPU: %d", smp_processor_id()); #endif /* CONFIG_SMP */ for (i = 0; i < 32; i++) { - long r; - if ((i % 8) == 0) + if ((i % REGS_PER_LINE) == 0) printk("\n" KERN_INFO "GPR%02d: ", i); - if (__get_user(r, ®s->gpr[i])) - break; - printk("%08lX ", r); - if (i == 12 && !FULL_REGS(regs)) + printk(REG " ", regs->gpr[i]); + if (i == LAST_VOLATILE && !FULL_REGS(regs)) break; } printk("\n"); @@ -359,16 +435,20 @@ void show_regs(struct pt_regs * regs) * Lookup NIP late so we have the best change of getting the * above info out without failing */ - printk("NIP [%08lx] ", regs->nip); + printk("NIP ["REG"] ", regs->nip); print_symbol("%s\n", regs->nip); - printk("LR [%08lx] ", regs->link); + printk("LR ["REG"] ", regs->link); print_symbol("%s\n", regs->link); #endif show_stack(current, (unsigned long *) regs->gpr[1]); + if (!user_mode(regs)) + show_instructions(regs); } void exit_thread(void) { + kprobe_flush_task(current); + #ifndef CONFIG_SMP if (last_task_used_math == current) last_task_used_math = NULL; @@ -385,6 +465,14 @@ void exit_thread(void) void flush_thread(void) { +#ifdef CONFIG_PPC64 + struct thread_info *t = current_thread_info(); + + if (t->flags & _TIF_ABI_PENDING) + t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); +#endif + kprobe_flush_task(current); + #ifndef CONFIG_SMP if (last_task_used_math == current) last_task_used_math = NULL; @@ -425,15 +513,13 @@ void prepare_to_copy(struct task_struct *tsk) /* * Copy a thread.. */ -int -copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct *p, struct pt_regs *regs) +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct *p, + struct pt_regs *regs) { struct pt_regs *childregs, *kregs; extern void ret_from_fork(void); unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE; - unsigned long childframe; CHECK_FULL_REGS(regs); /* Copy registers */ @@ -443,17 +529,26 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, if ((childregs->msr & MSR_PR) == 0) { /* for kernel thread, set `current' and stackptr in new task */ childregs->gpr[1] = sp + sizeof(struct pt_regs); +#ifdef CONFIG_PPC32 childregs->gpr[2] = (unsigned long) p; +#else + clear_ti_thread_flag(p->thread_info, TIF_32BIT); +#endif p->thread.regs = NULL; /* no user register state */ } else { childregs->gpr[1] = usp; p->thread.regs = childregs; - if (clone_flags & CLONE_SETTLS) - childregs->gpr[2] = childregs->gpr[6]; + if (clone_flags & CLONE_SETTLS) { +#ifdef CONFIG_PPC64 + if (!test_thread_flag(TIF_32BIT)) + childregs->gpr[13] = childregs->gpr[6]; + else +#endif + childregs->gpr[2] = childregs->gpr[6]; + } } childregs->gpr[3] = 0; /* Result from fork() */ sp -= STACK_FRAME_OVERHEAD; - childframe = sp; /* * The way this works is that at some point in the future @@ -467,9 +562,30 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, kregs = (struct pt_regs *) sp; sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; - kregs->nip = (unsigned long)ret_from_fork; +#ifdef CONFIG_PPC64 + if (cpu_has_feature(CPU_FTR_SLB)) { + unsigned long sp_vsid = get_kernel_vsid(sp); + + sp_vsid <<= SLB_VSID_SHIFT; + sp_vsid |= SLB_VSID_KERNEL; + if (cpu_has_feature(CPU_FTR_16M_PAGE)) + sp_vsid |= SLB_VSID_L; + + p->thread.ksp_vsid = sp_vsid; + } + + /* + * The PPC64 ABI makes use of a TOC to contain function + * pointers. The function (ret_from_except) is actually a pointer + * to the TOC entry. The first entry is a pointer to the actual + * function. + */ + kregs->nip = *((unsigned long *)ret_from_fork); +#else + kregs->nip = (unsigned long)ret_from_fork; p->thread.last_syscall = -1; +#endif return 0; } @@ -477,18 +593,61 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, /* * Set up a thread for executing a new program */ -void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) +void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { set_fs(USER_DS); + + /* + * If we exec out of a kernel thread then thread.regs will not be + * set. Do it now. + */ + if (!current->thread.regs) { + unsigned long childregs = (unsigned long)current->thread_info + + THREAD_SIZE; + childregs -= sizeof(struct pt_regs); + current->thread.regs = (struct pt_regs *)childregs; + } + memset(regs->gpr, 0, sizeof(regs->gpr)); regs->ctr = 0; regs->link = 0; regs->xer = 0; regs->ccr = 0; - regs->mq = 0; - regs->nip = nip; regs->gpr[1] = sp; + +#ifdef CONFIG_PPC32 + regs->mq = 0; + regs->nip = start; regs->msr = MSR_USER; +#else + if (test_thread_flag(TIF_32BIT)) { + unsigned long entry, toc, load_addr = regs->gpr[2]; + + /* start is a relocated pointer to the function descriptor for + * the elf _start routine. The first entry in the function + * descriptor is the entry address of _start and the second + * entry is the TOC value we need to use. + */ + __get_user(entry, (unsigned long __user *)start); + __get_user(toc, (unsigned long __user *)start+1); + + /* Check whether the e_entry function descriptor entries + * need to be relocated before we can use them. + */ + if (load_addr != 0) { + entry += load_addr; + toc += load_addr; + } + regs->nip = entry; + regs->gpr[2] = toc; + regs->msr = MSR_USER64; + } else { + regs->nip = start; + regs->gpr[2] = 0; + regs->msr = MSR_USER32; + } +#endif + #ifndef CONFIG_SMP if (last_task_used_math == current) last_task_used_math = NULL; @@ -506,6 +665,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) #ifdef CONFIG_ALTIVEC memset(current->thread.vr, 0, sizeof(current->thread.vr)); memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); + current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */ current->thread.vrsave = 0; current->thread.used_vr = 0; #endif /* CONFIG_ALTIVEC */ @@ -532,22 +692,23 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) #ifdef CONFIG_SPE tsk->thread.fpexc_mode = val & (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); + return 0; #else return -EINVAL; #endif - } else { - /* on a CONFIG_SPE this does not hurt us. The bits that - * __pack_fe01 use do not overlap with bits used for - * PR_FP_EXC_SW_ENABLE. Additionally, the MSR[FE0,FE1] bits - * on CONFIG_SPE implementations are reserved so writing to - * them does not change anything */ - if (val > PR_FP_EXC_PRECISE) - return -EINVAL; - tsk->thread.fpexc_mode = __pack_fe01(val); - if (regs != NULL && (regs->msr & MSR_FP) != 0) - regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) - | tsk->thread.fpexc_mode; } + + /* on a CONFIG_SPE this does not hurt us. The bits that + * __pack_fe01 use do not overlap with bits used for + * PR_FP_EXC_SW_ENABLE. Additionally, the MSR[FE0,FE1] bits + * on CONFIG_SPE implementations are reserved so writing to + * them does not change anything */ + if (val > PR_FP_EXC_PRECISE) + return -EINVAL; + tsk->thread.fpexc_mode = __pack_fe01(val); + if (regs != NULL && (regs->msr & MSR_FP) != 0) + regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) + | tsk->thread.fpexc_mode; return 0; } @@ -566,6 +727,8 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) 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, int __user *parent_tidp, void __user *child_threadptr, int __user *child_tidp, int p6, @@ -574,6 +737,12 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, CHECK_FULL_REGS(regs); if (usp == 0) usp = regs->gpr[1]; /* stack pointer for child */ +#ifdef CONFIG_PPC64 + if (test_thread_flag(TIF_32BIT)) { + parent_tidp = TRUNC_PTR(parent_tidp); + child_tidp = TRUNC_PTR(child_tidp); + } +#endif return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); } @@ -599,7 +768,7 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, struct pt_regs *regs) { int error; - char * filename; + char *filename; filename = getname((char __user *) a0); error = PTR_ERR(filename); @@ -644,20 +813,53 @@ static int validate_sp(unsigned long sp, struct task_struct *p, return 0; } -void dump_stack(void) -{ - show_stack(current, NULL); -} +#ifdef CONFIG_PPC64 +#define MIN_STACK_FRAME 112 /* same as STACK_FRAME_OVERHEAD, in fact */ +#define FRAME_LR_SAVE 2 +#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD + 288) +#define REGS_MARKER 0x7265677368657265ul +#define FRAME_MARKER 12 +#else +#define MIN_STACK_FRAME 16 +#define FRAME_LR_SAVE 1 +#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD) +#define REGS_MARKER 0x72656773ul +#define FRAME_MARKER 2 +#endif -EXPORT_SYMBOL(dump_stack); +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ip, sp; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + sp = p->thread.ksp; + if (!validate_sp(sp, p, MIN_STACK_FRAME)) + return 0; + + do { + sp = *(unsigned long *)sp; + if (!validate_sp(sp, p, MIN_STACK_FRAME)) + return 0; + if (count > 0) { + ip = ((unsigned long *)sp)[FRAME_LR_SAVE]; + if (!in_sched_functions(ip)) + return ip; + } + } while (count++ < 16); + return 0; +} +EXPORT_SYMBOL(get_wchan); + +static int kstack_depth_to_print = 64; void show_stack(struct task_struct *tsk, unsigned long *stack) { - unsigned long sp, stack_top, prev_sp, ret; + unsigned long sp, ip, lr, newsp; int count = 0; - unsigned long next_exc = 0; - struct pt_regs *regs; - extern char ret_from_except, ret_from_except_full, ret_from_syscall; + int firstframe = 1; sp = (unsigned long) stack; if (tsk == NULL) @@ -669,65 +871,45 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) sp = tsk->thread.ksp; } - prev_sp = (unsigned long) (tsk->thread_info + 1); - stack_top = (unsigned long) tsk->thread_info + THREAD_SIZE; - while (count < 16 && sp > prev_sp && sp < stack_top && (sp & 3) == 0) { - if (count == 0) { - printk("Call trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); -#endif - } else { - if (next_exc) { - ret = next_exc; - next_exc = 0; - } else - ret = *(unsigned long *)(sp + 4); - printk(" [%08lx] ", ret); -#ifdef CONFIG_KALLSYMS - print_symbol("%s", ret); - printk("\n"); -#endif - if (ret == (unsigned long) &ret_from_except - || ret == (unsigned long) &ret_from_except_full - || ret == (unsigned long) &ret_from_syscall) { - /* sp + 16 points to an exception frame */ - regs = (struct pt_regs *) (sp + 16); - if (sp + 16 + sizeof(*regs) <= stack_top) - next_exc = regs->nip; - } - } - ++count; - sp = *(unsigned long *)sp; - } -#ifndef CONFIG_KALLSYMS - if (count > 0) - printk("\n"); -#endif -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long ip, sp; - int count = 0; - - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - sp = p->thread.ksp; - if (!validate_sp(sp, p, 16)) - return 0; - + lr = 0; + printk("Call Trace:\n"); do { - sp = *(unsigned long *)sp; - if (!validate_sp(sp, p, 16)) - return 0; - if (count > 0) { - ip = *(unsigned long *)(sp + 4); - if (!in_sched_functions(ip)) - return ip; + if (!validate_sp(sp, tsk, MIN_STACK_FRAME)) + return; + + stack = (unsigned long *) sp; + newsp = stack[0]; + ip = stack[FRAME_LR_SAVE]; + if (!firstframe || ip != lr) { + printk("["REG"] ["REG"] ", sp, ip); + print_symbol("%s", ip); + if (firstframe) + printk(" (unreliable)"); + printk("\n"); } - } while (count++ < 16); - return 0; + firstframe = 0; + + /* + * See if this is an exception frame. + * We look for the "regshere" marker in the current frame. + */ + if (validate_sp(sp, tsk, INT_FRAME_SIZE) + && stack[FRAME_MARKER] == REGS_MARKER) { + struct pt_regs *regs = (struct pt_regs *) + (sp + STACK_FRAME_OVERHEAD); + printk("--- Exception: %lx", regs->trap); + print_symbol(" at %s\n", regs->nip); + lr = regs->link; + print_symbol(" LR = %s\n", lr); + firstframe = 1; + } + + sp = newsp; + } while (count++ < kstack_depth_to_print); } -EXPORT_SYMBOL(get_wchan); + +void dump_stack(void) +{ + show_stack(current, NULL); +} +EXPORT_SYMBOL(dump_stack); diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index f0a6779fbe52..d22b10021b5d 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -214,10 +214,8 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); but it's not easy, and we've already done it here. */ # define ELF_HWCAP (cur_cpu_spec->cpu_user_features) #ifdef __powerpc64__ -# define ELF_PLAT_INIT(_r, load_addr) do { \ - memset(_r->gpr, 0, sizeof(_r->gpr)); \ - _r->ctr = _r->link = _r->xer = _r->ccr = 0; \ - _r->gpr[2] = load_addr; \ +# define ELF_PLAT_INIT(_r, load_addr) do { \ + _r->gpr[2] = load_addr; \ } while (0) #endif /* __powerpc64__ */ From 9994a33865f4d55c44c9731c01e1f891543278de Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:36:14 +1000 Subject: [PATCH 0341/1939] powerpc: Introduce entry_{32,64}.S, misc_{32,64}.S, systbl.S The system call table has been consolidated into systbl.S. We have separate 32-bit and 64-bit versions of entry.S and misc.S since the code is mostly sufficiently different to be not worth merging. There are some common bits that will be extracted in future. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 3 +- arch/powerpc/kernel/Makefile | 6 +- arch/powerpc/kernel/entry_32.S | 1002 ++++++++++++++++++++++++++++++ arch/powerpc/kernel/entry_64.S | 842 ++++++++++++++++++++++++++ arch/powerpc/kernel/misc_32.S | 1039 ++++++++++++++++++++++++++++++++ arch/powerpc/kernel/misc_64.S | 898 +++++++++++++++++++++++++++ arch/powerpc/kernel/systbl.S | 323 ++++++++++ 7 files changed, 4109 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/kernel/entry_32.S create mode 100644 arch/powerpc/kernel/entry_64.S create mode 100644 arch/powerpc/kernel/misc_32.S create mode 100644 arch/powerpc/kernel/misc_64.S create mode 100644 arch/powerpc/kernel/systbl.S diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a4c605f469d4..27649cfc2a5d 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -119,10 +119,9 @@ head-$(CONFIG_4xx) := arch/powerpc/kernel/head_4xx.o head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o -ifeq ($(CONFIG_PPC32),y) head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o +head-$(CONFIG_PPC64) += arch/powerpc/kernel/entry_64.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o -endif core-y += arch/powerpc/kernel/ \ arch/$(OLDARCH)/kernel/ \ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 344cab678c6a..0625470a6235 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -17,12 +17,14 @@ extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o +extra-$(CONFIG_PPC64) += entry_64.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds -obj-y := traps.o prom.o semaphore.o -obj-$(CONFIG_PPC32) += setup_32.o process.o +obj-y += traps.o prom.o semaphore.o +obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += idle_power4.o +obj-$(CONFIG_PPC64) += misc_64.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o obj-$(CONFIG_MODULES) += ppc_ksyms.o diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S new file mode 100644 index 000000000000..094eea6fbd69 --- /dev/null +++ b/arch/powerpc/kernel/entry_32.S @@ -0,0 +1,1002 @@ +/* + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains the system call entry code, context switch + * code, and exception/interrupt return code for PowerPC. + * + * 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 + +#undef SHOW_SYSCALLS +#undef SHOW_SYSCALLS_TASK + +/* + * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE. + */ +#if MSR_KERNEL >= 0x10000 +#define LOAD_MSR_KERNEL(r, x) lis r,(x)@h; ori r,r,(x)@l +#else +#define LOAD_MSR_KERNEL(r, x) li r,(x) +#endif + +#ifdef CONFIG_BOOKE +#include "head_booke.h" +#define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \ + mtspr exc_level##_SPRG,r8; \ + BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \ + lwz r0,GPR10-INT_FRAME_SIZE(r8); \ + stw r0,GPR10(r11); \ + lwz r0,GPR11-INT_FRAME_SIZE(r8); \ + stw r0,GPR11(r11); \ + mfspr r8,exc_level##_SPRG + + .globl mcheck_transfer_to_handler +mcheck_transfer_to_handler: + TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) + b transfer_to_handler_full + + .globl debug_transfer_to_handler +debug_transfer_to_handler: + TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG) + b transfer_to_handler_full + + .globl crit_transfer_to_handler +crit_transfer_to_handler: + TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) + /* fall through */ +#endif + +#ifdef CONFIG_40x + .globl crit_transfer_to_handler +crit_transfer_to_handler: + lwz r0,crit_r10@l(0) + stw r0,GPR10(r11) + lwz r0,crit_r11@l(0) + stw r0,GPR11(r11) + /* fall through */ +#endif + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception, turning + * on address translation. + * Note that we rely on the caller having set cr0.eq iff the exception + * occurred in kernel mode (i.e. MSR:PR = 0). + */ + .globl transfer_to_handler_full +transfer_to_handler_full: + SAVE_NVGPRS(r11) + /* fall through */ + + .globl transfer_to_handler +transfer_to_handler: + stw r2,GPR2(r11) + stw r12,_NIP(r11) + stw r9,_MSR(r11) + andi. r2,r9,MSR_PR + mfctr r12 + mfspr r2,SPRN_XER + stw r12,_CTR(r11) + stw r2,_XER(r11) + mfspr r12,SPRN_SPRG3 + addi r2,r12,-THREAD + tovirt(r2,r2) /* set r2 to current */ + beq 2f /* if from user, fix up THREAD.regs */ + addi r11,r1,STACK_FRAME_OVERHEAD + stw r11,PT_REGS(r12) +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + /* Check to see if the dbcr0 register is set up to debug. Use the + single-step bit to do this. */ + lwz r12,THREAD_DBCR0(r12) + andis. r12,r12,DBCR0_IC@h + beq+ 3f + /* From user and task is ptraced - load up global dbcr0 */ + li r12,-1 /* clear all pending debug events */ + mtspr SPRN_DBSR,r12 + lis r11,global_dbcr0@ha + tophys(r11,r11) + addi r11,r11,global_dbcr0@l + lwz r12,0(r11) + mtspr SPRN_DBCR0,r12 + lwz r12,4(r11) + addi r12,r12,-1 + stw r12,4(r11) +#endif + b 3f +2: /* if from kernel, check interrupted DOZE/NAP mode and + * check for stack overflow + */ +#ifdef CONFIG_6xx + mfspr r11,SPRN_HID0 + mtcr r11 +BEGIN_FTR_SECTION + bt- 8,power_save_6xx_restore /* Check DOZE */ +END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) +BEGIN_FTR_SECTION + bt- 9,power_save_6xx_restore /* Check NAP */ +END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) +#endif /* CONFIG_6xx */ + .globl transfer_to_handler_cont +transfer_to_handler_cont: + lwz r11,THREAD_INFO-THREAD(r12) + cmplw r1,r11 /* if r1 <= current->thread_info */ + ble- stack_ovf /* then the kernel stack overflowed */ +3: + mflr r9 + lwz r11,0(r9) /* virtual address of handler */ + lwz r9,4(r9) /* where to go when done */ + FIX_SRR1(r10,r12) + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r10 + mtlr r9 + SYNC + RFI /* jump to handler, enable MMU */ + +/* + * On kernel stack overflow, load up an initial stack pointer + * and call StackOverflow(regs), which should not return. + */ +stack_ovf: + /* sometimes we use a statically-allocated stack, which is OK. */ + lis r11,_end@h + ori r11,r11,_end@l + cmplw r1,r11 + ble 3b /* r1 <= &_end is OK */ + SAVE_NVGPRS(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + lis r1,init_thread_union@ha + addi r1,r1,init_thread_union@l + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + lis r9,StackOverflow@ha + addi r9,r9,StackOverflow@l + LOAD_MSR_KERNEL(r10,MSR_KERNEL) + FIX_SRR1(r10,r12) + mtspr SPRN_SRR0,r9 + mtspr SPRN_SRR1,r10 + SYNC + RFI + +/* + * Handle a system call. + */ + .stabs "arch/powerpc/kernel/",N_SO,0,0,0f + .stabs "entry_32.S",N_SO,0,0,0f +0: + +_GLOBAL(DoSyscall) + stw r0,THREAD+LAST_SYSCALL(r2) + stw r3,ORIG_GPR3(r1) + li r12,0 + stw r12,RESULT(r1) + lwz r11,_CCR(r1) /* Clear SO bit in CR */ + rlwinm r11,r11,0,4,2 + stw r11,_CCR(r1) +#ifdef SHOW_SYSCALLS + bl do_show_syscall +#endif /* SHOW_SYSCALLS */ + rlwinm r10,r1,0,0,18 /* current_thread_info() */ + lwz r11,TI_LOCAL_FLAGS(r10) + rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR + stw r11,TI_LOCAL_FLAGS(r10) + lwz r11,TI_FLAGS(r10) + andi. r11,r11,_TIF_SYSCALL_T_OR_A + bne- syscall_dotrace +syscall_dotrace_cont: + cmplwi 0,r0,NR_syscalls + lis r10,sys_call_table@h + ori r10,r10,sys_call_table@l + slwi r0,r0,2 + bge- 66f + lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + PPC440EP_ERR42 + blrl /* Call handler */ + .globl ret_from_syscall +ret_from_syscall: +#ifdef SHOW_SYSCALLS + bl do_show_syscall_exit +#endif + mr r6,r3 + li r11,-_LAST_ERRNO + cmplw 0,r3,r11 + rlwinm r12,r1,0,0,18 /* current_thread_info() */ + blt+ 30f + lwz r11,TI_LOCAL_FLAGS(r12) + andi. r11,r11,_TIFL_FORCE_NOERROR + bne 30f + neg r3,r3 + lwz r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + stw r10,_CCR(r1) + + /* disable interrupts so current_thread_info()->flags can't change */ +30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ + SYNC + MTMSRD(r10) + lwz r9,TI_FLAGS(r12) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + bne- syscall_exit_work +syscall_exit_cont: +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + /* If the process has its own DBCR0 value, load it up. The single + step bit tells us that dbcr0 should be loaded. */ + lwz r0,THREAD+THREAD_DBCR0(r2) + andis. r10,r0,DBCR0_IC@h + bnel- load_dbcr0 +#endif + stwcx. r0,0,r1 /* to clear the reservation */ + lwz r4,_LINK(r1) + lwz r5,_CCR(r1) + mtlr r4 + mtcr r5 + lwz r7,_NIP(r1) + lwz r8,_MSR(r1) + FIX_SRR1(r8, r0) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r8 + SYNC + RFI + +66: li r3,-ENOSYS + b ret_from_syscall + + .globl ret_from_fork +ret_from_fork: + REST_NVGPRS(r1) + bl schedule_tail + li r3,0 + b ret_from_syscall + +/* Traced system call support */ +syscall_dotrace: + SAVE_NVGPRS(r1) + li r0,0xc00 + stw r0,TRAP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_syscall_trace_enter + lwz r0,GPR0(r1) /* Restore original registers */ + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) + REST_NVGPRS(r1) + b syscall_dotrace_cont + +syscall_exit_work: + stw r6,RESULT(r1) /* Save result */ + stw r3,GPR3(r1) /* Update return value */ + andi. r0,r9,_TIF_SYSCALL_T_OR_A + beq 5f + ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) /* re-enable interrupts */ + lwz r4,TRAP(r1) + andi. r4,r4,1 + beq 4f + SAVE_NVGPRS(r1) + li r4,0xc00 + stw r4,TRAP(r1) +4: + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_syscall_trace_leave + REST_NVGPRS(r1) +2: + lwz r3,GPR3(r1) + LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ + SYNC + MTMSRD(r10) /* disable interrupts again */ + rlwinm r12,r1,0,0,18 /* current_thread_info() */ + lwz r9,TI_FLAGS(r12) +5: + andi. r0,r9,_TIF_NEED_RESCHED + bne 1f + lwz r5,_MSR(r1) + andi. r5,r5,MSR_PR + beq syscall_exit_cont + andi. r0,r9,_TIF_SIGPENDING + beq syscall_exit_cont + b do_user_signal +1: + ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) /* re-enable interrupts */ + bl schedule + b 2b + +#ifdef SHOW_SYSCALLS +do_show_syscall: +#ifdef SHOW_SYSCALLS_TASK + lis r11,show_syscalls_task@ha + lwz r11,show_syscalls_task@l(r11) + cmp 0,r2,r11 + bnelr +#endif + stw r31,GPR31(r1) + mflr r31 + lis r3,7f@ha + addi r3,r3,7f@l + lwz r4,GPR0(r1) + lwz r5,GPR3(r1) + lwz r6,GPR4(r1) + lwz r7,GPR5(r1) + lwz r8,GPR6(r1) + lwz r9,GPR7(r1) + bl printk + lis r3,77f@ha + addi r3,r3,77f@l + lwz r4,GPR8(r1) + mr r5,r2 + bl printk + lwz r0,GPR0(r1) + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) + mtlr r31 + lwz r31,GPR31(r1) + blr + +do_show_syscall_exit: +#ifdef SHOW_SYSCALLS_TASK + lis r11,show_syscalls_task@ha + lwz r11,show_syscalls_task@l(r11) + cmp 0,r2,r11 + bnelr +#endif + stw r31,GPR31(r1) + mflr r31 + stw r3,RESULT(r1) /* Save result */ + mr r4,r3 + lis r3,79f@ha + addi r3,r3,79f@l + bl printk + lwz r3,RESULT(r1) + mtlr r31 + lwz r31,GPR31(r1) + blr + +7: .string "syscall %d(%x, %x, %x, %x, %x, " +77: .string "%x), current=%p\n" +79: .string " -> %x\n" + .align 2,0 + +#ifdef SHOW_SYSCALLS_TASK + .data + .globl show_syscalls_task +show_syscalls_task: + .long -1 + .text +#endif +#endif /* SHOW_SYSCALLS */ + +/* + * The sigsuspend and rt_sigsuspend system calls can call do_signal + * and thus put the process into the stopped state where we might + * want to examine its user state with ptrace. Therefore we need + * to save all the nonvolatile registers (r13 - r31) before calling + * the C code. + */ + .globl ppc_sigsuspend +ppc_sigsuspend: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ + stw r0,TRAP(r1) /* register set saved */ + b sys_sigsuspend + + .globl ppc_rt_sigsuspend +ppc_rt_sigsuspend: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 + stw r0,TRAP(r1) + b sys_rt_sigsuspend + + .globl ppc_fork +ppc_fork: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ + stw r0,TRAP(r1) /* register set saved */ + b sys_fork + + .globl ppc_vfork +ppc_vfork: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ + stw r0,TRAP(r1) /* register set saved */ + b sys_vfork + + .globl ppc_clone +ppc_clone: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ + stw r0,TRAP(r1) /* register set saved */ + b sys_clone + + .globl ppc_swapcontext +ppc_swapcontext: + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ + stw r0,TRAP(r1) /* register set saved */ + b sys_swapcontext + +/* + * Top-level page fault handling. + * This is in assembler because if do_page_fault tells us that + * it is a bad kernel page fault, we want to save the non-volatile + * registers before calling bad_page_fault. + */ + .globl handle_page_fault +handle_page_fault: + stw r4,_DAR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_page_fault + cmpwi r3,0 + beq+ ret_from_except + SAVE_NVGPRS(r1) + lwz r0,TRAP(r1) + clrrwi r0,r0,1 + stw r0,TRAP(r1) + mr r5,r3 + addi r3,r1,STACK_FRAME_OVERHEAD + lwz r4,_DAR(r1) + bl bad_page_fault + b ret_from_except_full + +/* + * This routine switches between two different tasks. The process + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory + * management hardware is updated to the second process's state. + * Finally, we can return to the second process. + * On entry, r3 points to the THREAD for the current task, r4 + * points to the THREAD for the new task. + * + * This routine is always called with interrupts disabled. + * + * Note: there are two ways to get to the "going out" portion + * of this code; either by coming in via the entry (_switch) + * or via "fork" which must set up an environment equivalent + * to the "_switch" path. If you change this , you'll have to + * change the fork code also. + * + * The code which creates the new task context is in 'copy_thread' + * in arch/ppc/kernel/process.c + */ +_GLOBAL(_switch) + stwu r1,-INT_FRAME_SIZE(r1) + mflr r0 + stw r0,INT_FRAME_SIZE+4(r1) + /* r3-r12 are caller saved -- Cort */ + SAVE_NVGPRS(r1) + stw r0,_NIP(r1) /* Return to switch caller */ + mfmsr r11 + li r0,MSR_FP /* Disable floating-point */ +#ifdef CONFIG_ALTIVEC +BEGIN_FTR_SECTION + oris r0,r0,MSR_VEC@h /* Disable altivec */ + mfspr r12,SPRN_VRSAVE /* save vrsave register value */ + stw r12,THREAD+THREAD_VRSAVE(r2) +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + oris r0,r0,MSR_SPE@h /* Disable SPE */ + mfspr r12,SPRN_SPEFSCR /* save spefscr register value */ + stw r12,THREAD+THREAD_SPEFSCR(r2) +#endif /* CONFIG_SPE */ + and. r0,r0,r11 /* FP or altivec or SPE enabled? */ + beq+ 1f + andc r11,r11,r0 + MTMSRD(r11) + isync +1: stw r11,_MSR(r1) + mfcr r10 + stw r10,_CCR(r1) + stw r1,KSP(r3) /* Set old stack pointer */ + +#ifdef CONFIG_SMP + /* We need a sync somewhere here to make sure that if the + * previous task gets rescheduled on another CPU, it sees all + * stores it has performed on this one. + */ + sync +#endif /* CONFIG_SMP */ + + tophys(r0,r4) + CLR_TOP32(r0) + mtspr SPRN_SPRG3,r0 /* Update current THREAD phys addr */ + lwz r1,KSP(r4) /* Load new stack pointer */ + + /* save the old current 'last' for return value */ + mr r3,r2 + addi r2,r4,-THREAD /* Update current */ + +#ifdef CONFIG_ALTIVEC +BEGIN_FTR_SECTION + lwz r0,THREAD+THREAD_VRSAVE(r2) + mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) +#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + lwz r0,THREAD+THREAD_SPEFSCR(r2) + mtspr SPRN_SPEFSCR,r0 /* restore SPEFSCR reg */ +#endif /* CONFIG_SPE */ + + lwz r0,_CCR(r1) + mtcrf 0xFF,r0 + /* r3-r12 are destroyed -- Cort */ + REST_NVGPRS(r1) + + lwz r4,_NIP(r1) /* Return to _switch caller in new task */ + mtlr r4 + addi r1,r1,INT_FRAME_SIZE + blr + + .globl fast_exception_return +fast_exception_return: +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) + andi. r10,r9,MSR_RI /* check for recoverable interrupt */ + beq 1f /* if not, we've got problems */ +#endif + +2: REST_4GPRS(3, r11) + lwz r10,_CCR(r11) + REST_GPR(1, r11) + mtcr r10 + lwz r10,_LINK(r11) + mtlr r10 + REST_GPR(10, r11) + mtspr SPRN_SRR1,r9 + mtspr SPRN_SRR0,r12 + REST_GPR(9, r11) + REST_GPR(12, r11) + lwz r11,GPR11(r11) + SYNC + RFI + +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) +/* check if the exception happened in a restartable section */ +1: lis r3,exc_exit_restart_end@ha + addi r3,r3,exc_exit_restart_end@l + cmplw r12,r3 + bge 3f + lis r4,exc_exit_restart@ha + addi r4,r4,exc_exit_restart@l + cmplw r12,r4 + blt 3f + lis r3,fee_restarts@ha + tophys(r3,r3) + lwz r5,fee_restarts@l(r3) + addi r5,r5,1 + stw r5,fee_restarts@l(r3) + mr r12,r4 /* restart at exc_exit_restart */ + b 2b + + .comm fee_restarts,4 + +/* aargh, a nonrecoverable interrupt, panic */ +/* aargh, we don't know which trap this is */ +/* but the 601 doesn't implement the RI bit, so assume it's OK */ +3: +BEGIN_FTR_SECTION + b 2b +END_FTR_SECTION_IFSET(CPU_FTR_601) + li r10,-1 + stw r10,TRAP(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + lis r10,MSR_KERNEL@h + ori r10,r10,MSR_KERNEL@l + bl transfer_to_handler_full + .long nonrecoverable_exception + .long ret_from_except +#endif + + .globl sigreturn_exit +sigreturn_exit: + subi r1,r3,STACK_FRAME_OVERHEAD + rlwinm r12,r1,0,0,18 /* current_thread_info() */ + lwz r9,TI_FLAGS(r12) + andi. r0,r9,_TIF_SYSCALL_T_OR_A + bnel- do_syscall_trace_leave + /* fall through */ + + .globl ret_from_except_full +ret_from_except_full: + REST_NVGPRS(r1) + /* fall through */ + + .globl ret_from_except +ret_from_except: + /* Hard-disable interrupts so that current_thread_info()->flags + * can't change between when we test it and when we return + * from the interrupt. */ + LOAD_MSR_KERNEL(r10,MSR_KERNEL) + SYNC /* Some chip revs have problems here... */ + MTMSRD(r10) /* disable interrupts */ + + lwz r3,_MSR(r1) /* Returning to user mode? */ + andi. r0,r3,MSR_PR + beq resume_kernel + +user_exc_return: /* r10 contains MSR_KERNEL here */ + /* Check current_thread_info()->flags */ + rlwinm r9,r1,0,0,18 + lwz r9,TI_FLAGS(r9) + andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) + bne do_work + +restore_user: +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + /* Check whether this process has its own DBCR0 value. The single + step bit tells us that dbcr0 should be loaded. */ + lwz r0,THREAD+THREAD_DBCR0(r2) + andis. r10,r0,DBCR0_IC@h + bnel- load_dbcr0 +#endif + +#ifdef CONFIG_PREEMPT + b restore + +/* N.B. the only way to get here is from the beq following ret_from_except. */ +resume_kernel: + /* check current_thread_info->preempt_count */ + rlwinm r9,r1,0,0,18 + lwz r0,TI_PREEMPT(r9) + cmpwi 0,r0,0 /* if non-zero, just restore regs and return */ + bne restore + lwz r0,TI_FLAGS(r9) + andi. r0,r0,_TIF_NEED_RESCHED + beq+ restore + andi. r0,r3,MSR_EE /* interrupts off? */ + beq restore /* don't schedule if so */ +1: bl preempt_schedule_irq + rlwinm r9,r1,0,0,18 + lwz r3,TI_FLAGS(r9) + andi. r0,r3,_TIF_NEED_RESCHED + bne- 1b +#else +resume_kernel: +#endif /* CONFIG_PREEMPT */ + + /* interrupts are hard-disabled at this point */ +restore: + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + REST_4GPRS(3, r1) + REST_2GPRS(7, r1) + + lwz r10,_XER(r1) + lwz r11,_CTR(r1) + mtspr SPRN_XER,r10 + mtctr r11 + + PPC405_ERR77(0,r1) + stwcx. r0,0,r1 /* to clear the reservation */ + +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) + lwz r9,_MSR(r1) + andi. r10,r9,MSR_RI /* check if this exception occurred */ + beql nonrecoverable /* at a bad place (MSR:RI = 0) */ + + lwz r10,_CCR(r1) + lwz r11,_LINK(r1) + mtcrf 0xFF,r10 + mtlr r11 + + /* + * Once we put values in SRR0 and SRR1, we are in a state + * where exceptions are not recoverable, since taking an + * exception will trash SRR0 and SRR1. Therefore we clear the + * MSR:RI bit to indicate this. If we do take an exception, + * we can't return to the point of the exception but we + * can restart the exception exit path at the label + * exc_exit_restart below. -- paulus + */ + LOAD_MSR_KERNEL(r10,MSR_KERNEL & ~MSR_RI) + SYNC + MTMSRD(r10) /* clear the RI bit */ + .globl exc_exit_restart +exc_exit_restart: + lwz r9,_MSR(r1) + lwz r12,_NIP(r1) + FIX_SRR1(r9,r10) + mtspr SPRN_SRR0,r12 + mtspr SPRN_SRR1,r9 + REST_4GPRS(9, r1) + lwz r1,GPR1(r1) + .globl exc_exit_restart_end +exc_exit_restart_end: + SYNC + RFI + +#else /* !(CONFIG_4xx || CONFIG_BOOKE) */ + /* + * This is a bit different on 4xx/Book-E because it doesn't have + * the RI bit in the MSR. + * The TLB miss handler checks if we have interrupted + * the exception exit path and restarts it if so + * (well maybe one day it will... :). + */ + lwz r11,_LINK(r1) + mtlr r11 + lwz r10,_CCR(r1) + mtcrf 0xff,r10 + REST_2GPRS(9, r1) + .globl exc_exit_restart +exc_exit_restart: + lwz r11,_NIP(r1) + lwz r12,_MSR(r1) +exc_exit_start: + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 + REST_2GPRS(11, r1) + lwz r1,GPR1(r1) + .globl exc_exit_restart_end +exc_exit_restart_end: + PPC405_ERR77_SYNC + rfi + b . /* prevent prefetch past rfi */ + +/* + * Returning from a critical interrupt in user mode doesn't need + * to be any different from a normal exception. For a critical + * interrupt in the kernel, we just return (without checking for + * preemption) since the interrupt may have happened at some crucial + * place (e.g. inside the TLB miss handler), and because we will be + * running with r1 pointing into critical_stack, not the current + * process's kernel stack (and therefore current_thread_info() will + * give the wrong answer). + * We have to restore various SPRs that may have been in use at the + * time of the critical interrupt. + * + */ +#ifdef CONFIG_40x +#define PPC_40x_TURN_OFF_MSR_DR \ + /* avoid any possible TLB misses here by turning off MSR.DR, we \ + * assume the instructions here are mapped by a pinned TLB entry */ \ + li r10,MSR_IR; \ + mtmsr r10; \ + isync; \ + tophys(r1, r1); +#else +#define PPC_40x_TURN_OFF_MSR_DR +#endif + +#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \ + REST_NVGPRS(r1); \ + lwz r3,_MSR(r1); \ + andi. r3,r3,MSR_PR; \ + LOAD_MSR_KERNEL(r10,MSR_KERNEL); \ + bne user_exc_return; \ + lwz r0,GPR0(r1); \ + lwz r2,GPR2(r1); \ + REST_4GPRS(3, r1); \ + REST_2GPRS(7, r1); \ + lwz r10,_XER(r1); \ + lwz r11,_CTR(r1); \ + mtspr SPRN_XER,r10; \ + mtctr r11; \ + PPC405_ERR77(0,r1); \ + stwcx. r0,0,r1; /* to clear the reservation */ \ + lwz r11,_LINK(r1); \ + mtlr r11; \ + lwz r10,_CCR(r1); \ + mtcrf 0xff,r10; \ + PPC_40x_TURN_OFF_MSR_DR; \ + lwz r9,_DEAR(r1); \ + lwz r10,_ESR(r1); \ + mtspr SPRN_DEAR,r9; \ + mtspr SPRN_ESR,r10; \ + lwz r11,_NIP(r1); \ + lwz r12,_MSR(r1); \ + mtspr exc_lvl_srr0,r11; \ + mtspr exc_lvl_srr1,r12; \ + lwz r9,GPR9(r1); \ + lwz r12,GPR12(r1); \ + lwz r10,GPR10(r1); \ + lwz r11,GPR11(r1); \ + lwz r1,GPR1(r1); \ + PPC405_ERR77_SYNC; \ + exc_lvl_rfi; \ + b .; /* prevent prefetch past exc_lvl_rfi */ + + .globl ret_from_crit_exc +ret_from_crit_exc: + RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) + +#ifdef CONFIG_BOOKE + .globl ret_from_debug_exc +ret_from_debug_exc: + RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) + + .globl ret_from_mcheck_exc +ret_from_mcheck_exc: + RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) +#endif /* CONFIG_BOOKE */ + +/* + * Load the DBCR0 value for a task that is being ptraced, + * having first saved away the global DBCR0. Note that r0 + * has the dbcr0 value to set upon entry to this. + */ +load_dbcr0: + mfmsr r10 /* first disable debug exceptions */ + rlwinm r10,r10,0,~MSR_DE + mtmsr r10 + isync + mfspr r10,SPRN_DBCR0 + lis r11,global_dbcr0@ha + addi r11,r11,global_dbcr0@l + stw r10,0(r11) + mtspr SPRN_DBCR0,r0 + lwz r10,4(r11) + addi r10,r10,1 + stw r10,4(r11) + li r11,-1 + mtspr SPRN_DBSR,r11 /* clear all pending debug events */ + blr + + .comm global_dbcr0,8 +#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ + +do_work: /* r10 contains MSR_KERNEL here */ + andi. r0,r9,_TIF_NEED_RESCHED + beq do_user_signal + +do_resched: /* r10 contains MSR_KERNEL here */ + ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) /* hard-enable interrupts */ + bl schedule +recheck: + LOAD_MSR_KERNEL(r10,MSR_KERNEL) + SYNC + MTMSRD(r10) /* disable interrupts */ + rlwinm r9,r1,0,0,18 + lwz r9,TI_FLAGS(r9) + andi. r0,r9,_TIF_NEED_RESCHED + bne- do_resched + andi. r0,r9,_TIF_SIGPENDING + beq restore_user +do_user_signal: /* r10 contains MSR_KERNEL here */ + ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) /* hard-enable interrupts */ + /* save r13-r31 in the exception frame, if not already done */ + lwz r3,TRAP(r1) + andi. r0,r3,1 + beq 2f + SAVE_NVGPRS(r1) + rlwinm r3,r3,0,0,30 + stw r3,TRAP(r1) +2: li r3,0 + addi r4,r1,STACK_FRAME_OVERHEAD + bl do_signal + REST_NVGPRS(r1) + b recheck + +/* + * We come here when we are at the end of handling an exception + * that occurred at a place where taking an exception will lose + * state information, such as the contents of SRR0 and SRR1. + */ +nonrecoverable: + lis r10,exc_exit_restart_end@ha + addi r10,r10,exc_exit_restart_end@l + cmplw r12,r10 + bge 3f + lis r11,exc_exit_restart@ha + addi r11,r11,exc_exit_restart@l + cmplw r12,r11 + blt 3f + lis r10,ee_restarts@ha + lwz r12,ee_restarts@l(r10) + addi r12,r12,1 + stw r12,ee_restarts@l(r10) + mr r12,r11 /* restart at exc_exit_restart */ + blr +3: /* OK, we can't recover, kill this process */ + /* but the 601 doesn't implement the RI bit, so assume it's OK */ +BEGIN_FTR_SECTION + blr +END_FTR_SECTION_IFSET(CPU_FTR_601) + lwz r3,TRAP(r1) + andi. r0,r3,1 + beq 4f + SAVE_NVGPRS(r1) + rlwinm r3,r3,0,0,30 + stw r3,TRAP(r1) +4: addi r3,r1,STACK_FRAME_OVERHEAD + bl nonrecoverable_exception + /* shouldn't return */ + b 4b + + .comm ee_restarts,4 + +/* + * PROM code for specific machines follows. Put it + * here so it's easy to add arch-specific sections later. + * -- Cort + */ +#ifdef CONFIG_PPC_OF +/* + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. + */ +_GLOBAL(enter_rtas) + stwu r1,-INT_FRAME_SIZE(r1) + mflr r0 + stw r0,INT_FRAME_SIZE+4(r1) + lis r4,rtas_data@ha + lwz r4,rtas_data@l(r4) + lis r6,1f@ha /* physical return address for rtas */ + addi r6,r6,1f@l + tophys(r6,r6) + tophys(r7,r1) + lis r8,rtas_entry@ha + lwz r8,rtas_entry@l(r8) + mfmsr r9 + stw r9,8(r1) + LOAD_MSR_KERNEL(r0,MSR_KERNEL) + SYNC /* disable interrupts so SRR0/1 */ + MTMSRD(r0) /* don't get trashed */ + li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) + mtlr r6 + CLR_TOP32(r7) + mtspr SPRN_SPRG2,r7 + mtspr SPRN_SRR0,r8 + mtspr SPRN_SRR1,r9 + RFI +1: tophys(r9,r1) + lwz r8,INT_FRAME_SIZE+4(r9) /* get return address */ + lwz r9,8(r9) /* original msr value */ + FIX_SRR1(r9,r0) + addi r1,r1,INT_FRAME_SIZE + li r0,0 + mtspr SPRN_SPRG2,r0 + mtspr SPRN_SRR0,r8 + mtspr SPRN_SRR1,r9 + RFI /* return to caller */ + + .globl machine_check_in_rtas +machine_check_in_rtas: + twi 31,0,0 + /* XXX load up BATs and panic */ + +#endif /* CONFIG_PPC_OF */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S new file mode 100644 index 000000000000..22796e28881a --- /dev/null +++ b/arch/powerpc/kernel/entry_64.S @@ -0,0 +1,842 @@ +/* + * arch/ppc64/kernel/entry.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains the system call entry code, context switch + * code, and exception/interrupt return code for PowerPC. + * + * 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 + +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + +/* + * System calls. + */ + .section ".toc","aw" +.SYS_CALL_TABLE: + .tc .sys_call_table[TC],.sys_call_table + +/* This value is used to mark exception frames on the stack. */ +exception_marker: + .tc ID_72656773_68657265[TC],0x7265677368657265 + + .section ".text" + .align 7 + +#undef SHOW_SYSCALLS + + .globl system_call_common +system_call_common: + andi. r10,r12,MSR_PR + mr r10,r1 + addi r1,r1,-INT_FRAME_SIZE + beq- 1f + ld r1,PACAKSAVE(r13) +1: std r10,0(r1) + std r11,_NIP(r1) + std r12,_MSR(r1) + std r0,GPR0(r1) + std r10,GPR1(r1) + std r2,GPR2(r1) + std r3,GPR3(r1) + std r4,GPR4(r1) + std r5,GPR5(r1) + std r6,GPR6(r1) + std r7,GPR7(r1) + std r8,GPR8(r1) + li r11,0 + std r11,GPR9(r1) + std r11,GPR10(r1) + std r11,GPR11(r1) + std r11,GPR12(r1) + std r9,GPR13(r1) + crclr so + mfcr r9 + mflr r10 + li r11,0xc01 + std r9,_CCR(r1) + std r10,_LINK(r1) + std r11,_TRAP(r1) + mfxer r9 + mfctr r10 + std r9,_XER(r1) + std r10,_CTR(r1) + std r3,ORIG_GPR3(r1) + ld r2,PACATOC(r13) + addi r9,r1,STACK_FRAME_OVERHEAD + ld r11,exception_marker@toc(r2) + std r11,-16(r9) /* "regshere" marker */ +#ifdef CONFIG_PPC_ISERIES + /* Hack for handling interrupts when soft-enabling on iSeries */ + cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ + andi. r10,r12,MSR_PR /* from kernel */ + crand 4*cr0+eq,4*cr1+eq,4*cr0+eq + beq hardware_interrupt_entry + lbz r10,PACAPROCENABLED(r13) + std r10,SOFTE(r1) +#endif + mfmsr r11 + ori r11,r11,MSR_EE + mtmsrd r11,1 + +#ifdef SHOW_SYSCALLS + bl .do_show_syscall + REST_GPR(0,r1) + REST_4GPRS(3,r1) + REST_2GPRS(7,r1) + addi r9,r1,STACK_FRAME_OVERHEAD +#endif + clrrdi r11,r1,THREAD_SHIFT + li r12,0 + ld r10,TI_FLAGS(r11) + stb r12,TI_SC_NOERR(r11) + andi. r11,r10,_TIF_SYSCALL_T_OR_A + bne- syscall_dotrace +syscall_dotrace_cont: + cmpldi 0,r0,NR_syscalls + bge- syscall_enosys + +system_call: /* label this so stack traces look sane */ +/* + * Need to vector to 32 Bit or default sys_call_table here, + * based on caller's run-mode / personality. + */ + ld r11,.SYS_CALL_TABLE@toc(2) + andi. r10,r10,_TIF_32BIT + beq 15f + addi r11,r11,8 /* use 32-bit syscall entries */ + clrldi r3,r3,32 + clrldi r4,r4,32 + clrldi r5,r5,32 + clrldi r6,r6,32 + clrldi r7,r7,32 + clrldi r8,r8,32 +15: + slwi r0,r0,4 + ldx r10,r11,r0 /* Fetch system call handler [ptr] */ + mtctr r10 + bctrl /* Call handler */ + +syscall_exit: +#ifdef SHOW_SYSCALLS + std r3,GPR3(r1) + bl .do_show_syscall_exit + ld r3,GPR3(r1) +#endif + std r3,RESULT(r1) + ld r5,_CCR(r1) + li r10,-_LAST_ERRNO + cmpld r3,r10 + clrrdi r12,r1,THREAD_SHIFT + bge- syscall_error +syscall_error_cont: + + /* check for syscall tracing or audit */ + ld r9,TI_FLAGS(r12) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + bne- syscall_exit_trace +syscall_exit_trace_cont: + + /* disable interrupts so current_thread_info()->flags can't change, + and so that we don't get interrupted after loading SRR0/1. */ + ld r8,_MSR(r1) + andi. r10,r8,MSR_RI + beq- unrecov_restore + mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 + mtmsrd r10,1 + ld r9,TI_FLAGS(r12) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + bne- syscall_exit_work + ld r7,_NIP(r1) + stdcx. r0,0,r1 /* to clear the reservation */ + andi. r6,r8,MSR_PR + ld r4,_LINK(r1) + beq- 1f /* only restore r13 if */ + ld r13,GPR13(r1) /* returning to usermode */ +1: ld r2,GPR2(r1) + li r12,MSR_RI + andc r10,r10,r12 + mtmsrd r10,1 /* clear MSR.RI */ + ld r1,GPR1(r1) + mtlr r4 + mtcr r5 + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r8 + rfid + b . /* prevent speculative execution */ + +syscall_enosys: + li r3,-ENOSYS + std r3,RESULT(r1) + clrrdi r12,r1,THREAD_SHIFT + ld r5,_CCR(r1) + +syscall_error: + lbz r11,TI_SC_NOERR(r12) + cmpwi 0,r11,0 + bne- syscall_error_cont + neg r3,r3 + oris r5,r5,0x1000 /* Set SO bit in CR */ + std r5,_CCR(r1) + b syscall_error_cont + +/* Traced system call support */ +syscall_dotrace: + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_syscall_trace_enter + ld r0,GPR0(r1) /* Restore original registers */ + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r5,GPR5(r1) + ld r6,GPR6(r1) + ld r7,GPR7(r1) + ld r8,GPR8(r1) + addi r9,r1,STACK_FRAME_OVERHEAD + clrrdi r10,r1,THREAD_SHIFT + ld r10,TI_FLAGS(r10) + b syscall_dotrace_cont + +syscall_exit_trace: + std r3,GPR3(r1) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_syscall_trace_leave + REST_NVGPRS(r1) + ld r3,GPR3(r1) + ld r5,_CCR(r1) + clrrdi r12,r1,THREAD_SHIFT + b syscall_exit_trace_cont + +/* Stuff to do on exit from a system call. */ +syscall_exit_work: + std r3,GPR3(r1) + std r5,_CCR(r1) + b .ret_from_except_lite + +/* Save non-volatile GPRs, if not already saved. */ +_GLOBAL(save_nvgprs) + ld r11,_TRAP(r1) + andi. r0,r11,1 + beqlr- + SAVE_NVGPRS(r1) + clrrdi r0,r11,1 + std r0,_TRAP(r1) + blr + +/* + * The sigsuspend and rt_sigsuspend system calls can call do_signal + * and thus put the process into the stopped state where we might + * want to examine its user state with ptrace. Therefore we need + * to save all the nonvolatile registers (r14 - r31) before calling + * the C code. Similarly, fork, vfork and clone need the full + * register state on the stack so that it can be copied to the child. + */ +_GLOBAL(ppc32_sigsuspend) + bl .save_nvgprs + bl .sys32_sigsuspend + b 70f + +_GLOBAL(ppc64_rt_sigsuspend) + bl .save_nvgprs + bl .sys_rt_sigsuspend + b 70f + +_GLOBAL(ppc32_rt_sigsuspend) + bl .save_nvgprs + bl .sys32_rt_sigsuspend +70: cmpdi 0,r3,0 + /* If it returned an error, we need to return via syscall_exit to set + the SO bit in cr0 and potentially stop for ptrace. */ + bne syscall_exit + /* If sigsuspend() returns zero, we are going into a signal handler. We + may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ +#ifdef CONFIG_AUDIT + ld r3,PACACURRENT(r13) + ld r4,AUDITCONTEXT(r3) + cmpdi 0,r4,0 + beq .ret_from_except /* No audit_context: Leave immediately. */ + li r4, 2 /* AUDITSC_FAILURE */ + li r5,-4 /* It's always -EINTR */ + bl .audit_syscall_exit +#endif + b .ret_from_except + +_GLOBAL(ppc_fork) + bl .save_nvgprs + bl .sys_fork + b syscall_exit + +_GLOBAL(ppc_vfork) + bl .save_nvgprs + bl .sys_vfork + b syscall_exit + +_GLOBAL(ppc_clone) + bl .save_nvgprs + bl .sys_clone + b syscall_exit + +_GLOBAL(ppc32_swapcontext) + bl .save_nvgprs + bl .sys32_swapcontext + b 80f + +_GLOBAL(ppc64_swapcontext) + bl .save_nvgprs + bl .sys_swapcontext + b 80f + +_GLOBAL(ppc32_sigreturn) + bl .sys32_sigreturn + b 80f + +_GLOBAL(ppc32_rt_sigreturn) + bl .sys32_rt_sigreturn + b 80f + +_GLOBAL(ppc64_rt_sigreturn) + bl .sys_rt_sigreturn + +80: cmpdi 0,r3,0 + blt syscall_exit + clrrdi r4,r1,THREAD_SHIFT + ld r4,TI_FLAGS(r4) + andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq+ 81f + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_syscall_trace_leave +81: b .ret_from_except + +_GLOBAL(ret_from_fork) + bl .schedule_tail + REST_NVGPRS(r1) + li r3,0 + b syscall_exit + +/* + * This routine switches between two different tasks. The process + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory + * management hardware is updated to the second process's state. + * Finally, we can return to the second process, via ret_from_except. + * On entry, r3 points to the THREAD for the current task, r4 + * points to the THREAD for the new task. + * + * Note: there are two ways to get to the "going out" portion + * of this code; either by coming in via the entry (_switch) + * or via "fork" which must set up an environment equivalent + * to the "_switch" path. If you change this you'll have to change + * the fork code also. + * + * The code which creates the new task context is in 'copy_thread' + * in arch/ppc64/kernel/process.c + */ + .align 7 +_GLOBAL(_switch) + mflr r0 + std r0,16(r1) + stdu r1,-SWITCH_FRAME_SIZE(r1) + /* r3-r13 are caller saved -- Cort */ + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mflr r20 /* Return to switch caller */ + mfmsr r22 + li r0, MSR_FP +#ifdef CONFIG_ALTIVEC +BEGIN_FTR_SECTION + oris r0,r0,MSR_VEC@h /* Disable altivec */ + mfspr r24,SPRN_VRSAVE /* save vrsave register value */ + std r24,THREAD_VRSAVE(r3) +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) +#endif /* CONFIG_ALTIVEC */ + and. r0,r0,r22 + beq+ 1f + andc r22,r22,r0 + mtmsrd r22 + isync +1: std r20,_NIP(r1) + mfcr r23 + std r23,_CCR(r1) + std r1,KSP(r3) /* Set old stack pointer */ + +#ifdef CONFIG_SMP + /* We need a sync somewhere here to make sure that if the + * previous task gets rescheduled on another CPU, it sees all + * stores it has performed on this one. + */ + sync +#endif /* CONFIG_SMP */ + + addi r6,r4,-THREAD /* Convert THREAD to 'current' */ + std r6,PACACURRENT(r13) /* Set new 'current' */ + + ld r8,KSP(r4) /* new stack pointer */ +BEGIN_FTR_SECTION + clrrdi r6,r8,28 /* get its ESID */ + clrrdi r9,r1,28 /* get current sp ESID */ + clrldi. r0,r6,2 /* is new ESID c00000000? */ + cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ + cror eq,4*cr1+eq,eq + beq 2f /* if yes, don't slbie it */ + + /* Bolt in the new stack SLB entry */ + ld r7,KSP_VSID(r4) /* Get new stack's VSID */ + oris r0,r6,(SLB_ESID_V)@h + ori r0,r0,(SLB_NUM_BOLTED-1)@l + slbie r6 + slbie r6 /* Workaround POWER5 < DD2.1 issue */ + slbmte r7,r0 + isync + +2: +END_FTR_SECTION_IFSET(CPU_FTR_SLB) + clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ + /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE + because we don't need to leave the 288-byte ABI gap at the + top of the kernel stack. */ + addi r7,r7,THREAD_SIZE-SWITCH_FRAME_SIZE + + mr r1,r8 /* start using new stack pointer */ + std r7,PACAKSAVE(r13) + + ld r6,_CCR(r1) + mtcrf 0xFF,r6 + +#ifdef CONFIG_ALTIVEC +BEGIN_FTR_SECTION + ld r0,THREAD_VRSAVE(r4) + mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) +#endif /* CONFIG_ALTIVEC */ + + /* r3-r13 are destroyed -- Cort */ + REST_8GPRS(14, r1) + REST_10GPRS(22, r1) + + /* convert old thread to its task_struct for return value */ + addi r3,r3,-THREAD + ld r7,_NIP(r1) /* Return to _switch caller in new task */ + mtlr r7 + addi r1,r1,SWITCH_FRAME_SIZE + blr + + .align 7 +_GLOBAL(ret_from_except) + ld r11,_TRAP(r1) + andi. r0,r11,1 + bne .ret_from_except_lite + REST_NVGPRS(r1) + +_GLOBAL(ret_from_except_lite) + /* + * Disable interrupts so that current_thread_info()->flags + * can't change between when we test it and when we return + * from the interrupt. + */ + mfmsr r10 /* Get current interrupt state */ + rldicl r9,r10,48,1 /* clear MSR_EE */ + rotldi r9,r9,16 + mtmsrd r9,1 /* Update machine state */ + +#ifdef CONFIG_PREEMPT + clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */ + li r0,_TIF_NEED_RESCHED /* bits to check */ + ld r3,_MSR(r1) + ld r4,TI_FLAGS(r9) + /* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */ + rlwimi r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING + and. r0,r4,r0 /* check NEED_RESCHED and maybe SIGPENDING */ + bne do_work + +#else /* !CONFIG_PREEMPT */ + ld r3,_MSR(r1) /* Returning to user mode? */ + andi. r3,r3,MSR_PR + beq restore /* if not, just restore regs and return */ + + /* Check current_thread_info()->flags */ + clrrdi r9,r1,THREAD_SHIFT + ld r4,TI_FLAGS(r9) + andi. r0,r4,_TIF_USER_WORK_MASK + bne do_work +#endif + +restore: +#ifdef CONFIG_PPC_ISERIES + ld r5,SOFTE(r1) + cmpdi 0,r5,0 + beq 4f + /* Check for pending interrupts (iSeries) */ + ld r3,PACALPPACA+LPPACAANYINT(r13) + cmpdi r3,0 + beq+ 4f /* skip do_IRQ if no interrupts */ + + li r3,0 + stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ + ori r10,r10,MSR_EE + mtmsrd r10 /* hard-enable again */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_IRQ + b .ret_from_except_lite /* loop back and handle more */ + +4: stb r5,PACAPROCENABLED(r13) +#endif + + ld r3,_MSR(r1) + andi. r0,r3,MSR_RI + beq- unrecov_restore + + andi. r0,r3,MSR_PR + + /* + * r13 is our per cpu area, only restore it if we are returning to + * userspace + */ + beq 1f + REST_GPR(13, r1) +1: + ld r3,_CTR(r1) + ld r0,_LINK(r1) + mtctr r3 + mtlr r0 + ld r3,_XER(r1) + mtspr SPRN_XER,r3 + + REST_8GPRS(5, r1) + + stdcx. r0,0,r1 /* to clear the reservation */ + + mfmsr r0 + li r2, MSR_RI + andc r0,r0,r2 + mtmsrd r0,1 + + ld r0,_MSR(r1) + mtspr SPRN_SRR1,r0 + + ld r2,_CCR(r1) + mtcrf 0xFF,r2 + ld r2,_NIP(r1) + mtspr SPRN_SRR0,r2 + + ld r0,GPR0(r1) + ld r2,GPR2(r1) + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r1,GPR1(r1) + + rfid + b . /* prevent speculative execution */ + +/* Note: this must change if we start using the TIF_NOTIFY_RESUME bit */ +do_work: +#ifdef CONFIG_PREEMPT + andi. r0,r3,MSR_PR /* Returning to user mode? */ + bne user_work + /* Check that preempt_count() == 0 and interrupts are enabled */ + lwz r8,TI_PREEMPT(r9) + cmpwi cr1,r8,0 +#ifdef CONFIG_PPC_ISERIES + ld r0,SOFTE(r1) + cmpdi r0,0 +#else + andi. r0,r3,MSR_EE +#endif + crandc eq,cr1*4+eq,eq + bne restore + /* here we are preempting the current task */ +1: +#ifdef CONFIG_PPC_ISERIES + li r0,1 + stb r0,PACAPROCENABLED(r13) +#endif + ori r10,r10,MSR_EE + mtmsrd r10,1 /* reenable interrupts */ + bl .preempt_schedule + mfmsr r10 + clrrdi r9,r1,THREAD_SHIFT + rldicl r10,r10,48,1 /* disable interrupts again */ + rotldi r10,r10,16 + mtmsrd r10,1 + ld r4,TI_FLAGS(r9) + andi. r0,r4,_TIF_NEED_RESCHED + bne 1b + b restore + +user_work: +#endif + /* Enable interrupts */ + ori r10,r10,MSR_EE + mtmsrd r10,1 + + andi. r0,r4,_TIF_NEED_RESCHED + beq 1f + bl .schedule + b .ret_from_except_lite + +1: bl .save_nvgprs + li r3,0 + addi r4,r1,STACK_FRAME_OVERHEAD + bl .do_signal + b .ret_from_except + +unrecov_restore: + addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b unrecov_restore + +#ifdef CONFIG_PPC_RTAS +/* + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. + * + * In addition, we need to be in 32b mode, at least for now. + * + * Note: r3 is an input parameter to rtas, so don't trash it... + */ +_GLOBAL(enter_rtas) + mflr r0 + std r0,16(r1) + stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */ + + /* Because RTAS is running in 32b mode, it clobbers the high order half + * of all registers that it saves. We therefore save those registers + * RTAS might touch to the stack. (r0, r3-r13 are caller saved) + */ + SAVE_GPR(2, r1) /* Save the TOC */ + SAVE_GPR(13, r1) /* Save paca */ + SAVE_8GPRS(14, r1) /* Save the non-volatiles */ + SAVE_10GPRS(22, r1) /* ditto */ + + mfcr r4 + std r4,_CCR(r1) + mfctr r5 + std r5,_CTR(r1) + mfspr r6,SPRN_XER + std r6,_XER(r1) + mfdar r7 + std r7,_DAR(r1) + mfdsisr r8 + std r8,_DSISR(r1) + mfsrr0 r9 + std r9,_SRR0(r1) + mfsrr1 r10 + std r10,_SRR1(r1) + + /* There is no way it is acceptable to get here with interrupts enabled, + * check it with the asm equivalent of WARN_ON + */ + mfmsr r6 + andi. r0,r6,MSR_EE +1: tdnei r0,0 +.section __bug_table,"a" + .llong 1b,__LINE__ + 0x1000000, 1f, 2f +.previous +.section .rodata,"a" +1: .asciz __FILE__ +2: .asciz "enter_rtas" +.previous + + /* Unfortunately, the stack pointer and the MSR are also clobbered, + * so they are saved in the PACA which allows us to restore + * our original state after RTAS returns. + */ + std r1,PACAR1(r13) + std r6,PACASAVEDMSR(r13) + + /* Setup our real return addr */ + SET_REG_TO_LABEL(r4,.rtas_return_loc) + SET_REG_TO_CONST(r9,KERNELBASE) + sub r4,r4,r9 + mtlr r4 + + li r0,0 + ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI + andc r0,r6,r0 + + li r9,1 + rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG) + ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP + andc r6,r0,r9 + ori r6,r6,MSR_RI + sync /* disable interrupts so SRR0/1 */ + mtmsrd r0 /* don't get trashed */ + + SET_REG_TO_LABEL(r4,rtas) + ld r5,RTASENTRY(r4) /* get the rtas->entry value */ + ld r4,RTASBASE(r4) /* get the rtas->base value */ + + mtspr SPRN_SRR0,r5 + mtspr SPRN_SRR1,r6 + rfid + b . /* prevent speculative execution */ + +_STATIC(rtas_return_loc) + /* relocation is off at this point */ + mfspr r4,SPRN_SPRG3 /* Get PACA */ + SET_REG_TO_CONST(r5, KERNELBASE) + sub r4,r4,r5 /* RELOC the PACA base pointer */ + + mfmsr r6 + li r0,MSR_RI + andc r6,r6,r0 + sync + mtmsrd r6 + + ld r1,PACAR1(r4) /* Restore our SP */ + LOADADDR(r3,.rtas_restore_regs) + ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ + + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + rfid + b . /* prevent speculative execution */ + +_STATIC(rtas_restore_regs) + /* relocation is on at this point */ + REST_GPR(2, r1) /* Restore the TOC */ + REST_GPR(13, r1) /* Restore paca */ + REST_8GPRS(14, r1) /* Restore the non-volatiles */ + REST_10GPRS(22, r1) /* ditto */ + + mfspr r13,SPRN_SPRG3 + + ld r4,_CCR(r1) + mtcr r4 + ld r5,_CTR(r1) + mtctr r5 + ld r6,_XER(r1) + mtspr SPRN_XER,r6 + ld r7,_DAR(r1) + mtdar r7 + ld r8,_DSISR(r1) + mtdsisr r8 + ld r9,_SRR0(r1) + mtsrr0 r9 + ld r10,_SRR1(r1) + mtsrr1 r10 + + addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */ + ld r0,16(r1) /* get return address */ + + mtlr r0 + blr /* return to caller */ + +#endif /* CONFIG_PPC_RTAS */ + +#ifdef CONFIG_PPC_MULTIPLATFORM + +_GLOBAL(enter_prom) + mflr r0 + std r0,16(r1) + stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + + /* Because PROM is running in 32b mode, it clobbers the high order half + * of all registers that it saves. We therefore save those registers + * PROM might touch to the stack. (r0, r3-r13 are caller saved) + */ + SAVE_8GPRS(2, r1) + SAVE_GPR(13, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mfcr r4 + std r4,_CCR(r1) + mfctr r5 + std r5,_CTR(r1) + mfspr r6,SPRN_XER + std r6,_XER(r1) + mfdar r7 + std r7,_DAR(r1) + mfdsisr r8 + std r8,_DSISR(r1) + mfsrr0 r9 + std r9,_SRR0(r1) + mfsrr1 r10 + std r10,_SRR1(r1) + mfmsr r11 + std r11,_MSR(r1) + + /* Get the PROM entrypoint */ + ld r0,GPR4(r1) + mtlr r0 + + /* Switch MSR to 32 bits mode + */ + mfmsr r11 + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + andc r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + andc r11,r11,r12 + mtmsrd r11 + isync + + /* Restore arguments & enter PROM here... */ + ld r3,GPR3(r1) + blrl + + /* Just make sure that r1 top 32 bits didn't get + * corrupt by OF + */ + rldicl r1,r1,0,32 + + /* Restore the MSR (back to 64 bits) */ + ld r0,_MSR(r1) + mtmsrd r0 + isync + + /* Restore other registers */ + REST_GPR(2, r1) + REST_GPR(13, r1) + REST_8GPRS(14, r1) + REST_10GPRS(22, r1) + ld r4,_CCR(r1) + mtcr r4 + ld r5,_CTR(r1) + mtctr r5 + ld r6,_XER(r1) + mtspr SPRN_XER,r6 + ld r7,_DAR(r1) + mtdar r7 + ld r8,_DSISR(r1) + mtdsisr r8 + ld r9,_SRR0(r1) + mtsrr0 r9 + ld r10,_SRR1(r1) + mtsrr1 r10 + + addi r1,r1,PROM_FRAME_SIZE + ld r0,16(r1) + mtlr r0 + blr + +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S new file mode 100644 index 000000000000..fa8c20ffec78 --- /dev/null +++ b/arch/powerpc/kernel/misc_32.S @@ -0,0 +1,1039 @@ +/* + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * + * 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 + + .text + + .align 5 +_GLOBAL(__delay) + cmpwi 0,r3,0 + mtctr r3 + beqlr +1: bdnz 1b + blr + +/* + * Returns (address we're running at) - (address we were linked at) + * for use before the text and data are mapped to KERNELBASE. + */ +_GLOBAL(reloc_offset) + mflr r0 + bl 1f +1: mflr r3 + lis r4,1b@ha + addi r4,r4,1b@l + subf r3,r4,r3 + mtlr r0 + blr + +/* + * add_reloc_offset(x) returns x + reloc_offset(). + */ +_GLOBAL(add_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + add r3,r3,r5 + mtlr r0 + blr + +/* + * sub_reloc_offset(x) returns x - reloc_offset(). + */ +_GLOBAL(sub_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + subf r3,r5,r3 + mtlr r0 + blr + +/* + * reloc_got2 runs through the .got2 section adding an offset + * to each entry. + */ +_GLOBAL(reloc_got2) + mflr r11 + lis r7,__got2_start@ha + addi r7,r7,__got2_start@l + lis r8,__got2_end@ha + addi r8,r8,__got2_end@l + subf r8,r7,r8 + srwi. r8,r8,2 + beqlr + mtctr r8 + bl 1f +1: mflr r0 + lis r4,1b@ha + addi r4,r4,1b@l + subf r0,r4,r0 + add r7,r0,r7 +2: lwz r0,0(r7) + add r0,r0,r3 + stw r0,0(r7) + addi r7,r7,4 + bdnz 2b + mtlr r11 + blr + +/* + * identify_cpu, + * called with r3 = data offset and r4 = CPU number + * doesn't change r3 + */ +_GLOBAL(identify_cpu) + addis r8,r3,cpu_specs@ha + addi r8,r8,cpu_specs@l + mfpvr r7 +1: + lwz r5,CPU_SPEC_PVR_MASK(r8) + and r5,r5,r7 + lwz r6,CPU_SPEC_PVR_VALUE(r8) + cmplw 0,r6,r5 + beq 1f + addi r8,r8,CPU_SPEC_ENTRY_SIZE + b 1b +1: + addis r6,r3,cur_cpu_spec@ha + addi r6,r6,cur_cpu_spec@l + sub r8,r8,r3 + stw r8,0(r6) + blr + +/* + * do_cpu_ftr_fixups - goes through the list of CPU feature fixups + * and writes nop's over sections of code that don't apply for this cpu. + * r3 = data offset (not changed) + */ +_GLOBAL(do_cpu_ftr_fixups) + /* Get CPU 0 features */ + addis r6,r3,cur_cpu_spec@ha + addi r6,r6,cur_cpu_spec@l + lwz r4,0(r6) + add r4,r4,r3 + lwz r4,CPU_SPEC_FEATURES(r4) + + /* Get the fixup table */ + addis r6,r3,__start___ftr_fixup@ha + addi r6,r6,__start___ftr_fixup@l + addis r7,r3,__stop___ftr_fixup@ha + addi r7,r7,__stop___ftr_fixup@l + + /* Do the fixup */ +1: cmplw 0,r6,r7 + bgelr + addi r6,r6,16 + lwz r8,-16(r6) /* mask */ + and r8,r8,r4 + lwz r9,-12(r6) /* value */ + cmplw 0,r8,r9 + beq 1b + lwz r8,-8(r6) /* section begin */ + lwz r9,-4(r6) /* section end */ + subf. r9,r8,r9 + beq 1b + /* write nops over the section of code */ + /* todo: if large section, add a branch at the start of it */ + srwi r9,r9,2 + mtctr r9 + add r8,r8,r3 + lis r0,0x60000000@h /* nop */ +3: stw r0,0(r8) + andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l + beq 2f + dcbst 0,r8 /* suboptimal, but simpler */ + sync + icbi 0,r8 +2: addi r8,r8,4 + bdnz 3b + sync /* additional sync needed on g4 */ + isync + b 1b + +/* + * call_setup_cpu - call the setup_cpu function for this cpu + * r3 = data offset, r24 = cpu number + * + * Setup function is called with: + * r3 = data offset + * r4 = ptr to CPU spec (relocated) + */ +_GLOBAL(call_setup_cpu) + addis r4,r3,cur_cpu_spec@ha + addi r4,r4,cur_cpu_spec@l + lwz r4,0(r4) + add r4,r4,r3 + lwz r5,CPU_SPEC_SETUP(r4) + cmpi 0,r5,0 + add r5,r5,r3 + beqlr + mtctr r5 + bctr + +#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx) + +/* This gets called by via-pmu.c to switch the PLL selection + * on 750fx CPU. This function should really be moved to some + * other place (as most of the cpufreq code in via-pmu + */ +_GLOBAL(low_choose_750fx_pll) + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* If switching to PLL1, disable HID0:BTIC */ + cmplwi cr0,r3,0 + beq 1f + mfspr r5,SPRN_HID0 + rlwinm r5,r5,0,27,25 + sync + mtspr SPRN_HID0,r5 + isync + sync + +1: + /* Calc new HID1 value */ + mfspr r4,SPRN_HID1 /* Build a HID1:PS bit from parameter */ + rlwinm r5,r3,16,15,15 /* Clear out HID1:PS from value read */ + rlwinm r4,r4,0,16,14 /* Could have I used rlwimi here ? */ + or r4,r4,r5 + mtspr SPRN_HID1,r4 + + /* Store new HID1 image */ + rlwinm r6,r1,0,0,18 + lwz r6,TI_CPU(r6) + slwi r6,r6,2 + addis r6,r6,nap_save_hid1@ha + stw r4,nap_save_hid1@l(r6) + + /* If switching to PLL0, enable HID0:BTIC */ + cmplwi cr0,r3,0 + bne 1f + mfspr r5,SPRN_HID0 + ori r5,r5,HID0_BTIC + sync + mtspr SPRN_HID0,r5 + isync + sync + +1: + /* Return */ + mtmsr r7 + blr + +_GLOBAL(low_choose_7447a_dfs) + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* Calc new HID1 value */ + mfspr r4,SPRN_HID1 + insrwi r4,r3,1,9 /* insert parameter into bit 9 */ + sync + mtspr SPRN_HID1,r4 + sync + isync + + /* Return */ + mtmsr r7 + blr + +#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */ + +/* + * complement mask on the msr then "or" some values on. + * _nmask_and_or_msr(nmask, value_to_or) + */ +_GLOBAL(_nmask_and_or_msr) + mfmsr r0 /* Get current msr */ + andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ + or r0,r0,r4 /* Or on the bits in r4 (second parm) */ + SYNC /* Some chip revs have problems here... */ + mtmsr r0 /* Update machine state */ + isync + blr /* Done */ + + +/* + * Flush MMU TLB + */ +_GLOBAL(_tlbia) +#if defined(CONFIG_40x) + sync /* Flush to memory before changing mapping */ + tlbia + isync /* Flush shadow TLB */ +#elif defined(CONFIG_44x) + li r3,0 + sync + + /* Load high watermark */ + lis r4,tlb_44x_hwater@ha + lwz r5,tlb_44x_hwater@l(r4) + +1: tlbwe r3,r3,PPC44x_TLB_PAGEID + addi r3,r3,1 + cmpw 0,r3,r5 + ble 1b + + isync +#elif defined(CONFIG_FSL_BOOKE) + /* Invalidate all entries in TLB0 */ + li r3, 0x04 + tlbivax 0,3 + /* Invalidate all entries in TLB1 */ + li r3, 0x0c + tlbivax 0,3 + /* Invalidate all entries in TLB2 */ + li r3, 0x14 + tlbivax 0,3 + /* Invalidate all entries in TLB3 */ + li r3, 0x1c + tlbivax 0,3 + msync +#ifdef CONFIG_SMP + tlbsync +#endif /* CONFIG_SMP */ +#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */ +#if defined(CONFIG_SMP) + rlwinm r8,r1,0,0,18 + lwz r8,TI_CPU(r8) + oris r8,r8,10 + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear DR */ + mtmsr r0 + SYNC_601 + isync + lis r9,mmu_hash_lock@h + ori r9,r9,mmu_hash_lock@l + tophys(r9,r9) +10: lwarx r7,0,r9 + cmpwi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + sync + tlbia + sync + TLBSYNC + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ + mtmsr r10 + SYNC_601 + isync +#else /* CONFIG_SMP */ + sync + tlbia + sync +#endif /* CONFIG_SMP */ +#endif /* ! defined(CONFIG_40x) */ + blr + +/* + * Flush MMU TLB for a particular address + */ +_GLOBAL(_tlbie) +#if defined(CONFIG_40x) + tlbsx. r3, 0, r3 + bne 10f + sync + /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear. + * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate + * the TLB entry. */ + tlbwe r3, r3, TLB_TAG + isync +10: +#elif defined(CONFIG_44x) + mfspr r4,SPRN_MMUCR + mfspr r5,SPRN_PID /* Get PID */ + rlwimi r4,r5,0,24,31 /* Set TID */ + mtspr SPRN_MMUCR,r4 + + tlbsx. r3, 0, r3 + bne 10f + sync + /* There are only 64 TLB entries, so r3 < 64, + * which means bit 22, is clear. Since 22 is + * the V bit in the TLB_PAGEID, loading this + * value will invalidate the TLB entry. + */ + tlbwe r3, r3, PPC44x_TLB_PAGEID + isync +10: +#elif defined(CONFIG_FSL_BOOKE) + rlwinm r4, r3, 0, 0, 19 + ori r5, r4, 0x08 /* TLBSEL = 1 */ + ori r6, r4, 0x10 /* TLBSEL = 2 */ + ori r7, r4, 0x18 /* TLBSEL = 3 */ + tlbivax 0, r4 + tlbivax 0, r5 + tlbivax 0, r6 + tlbivax 0, r7 + msync +#if defined(CONFIG_SMP) + tlbsync +#endif /* CONFIG_SMP */ +#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */ +#if defined(CONFIG_SMP) + rlwinm r8,r1,0,0,18 + lwz r8,TI_CPU(r8) + oris r8,r8,11 + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear DR */ + mtmsr r0 + SYNC_601 + isync + lis r9,mmu_hash_lock@h + ori r9,r9,mmu_hash_lock@l + tophys(r9,r9) +10: lwarx r7,0,r9 + cmpwi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio + tlbie r3 + sync + TLBSYNC + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ + mtmsr r10 + SYNC_601 + isync +#else /* CONFIG_SMP */ + tlbie r3 + sync +#endif /* CONFIG_SMP */ +#endif /* ! CONFIG_40x */ + blr + +/* + * Flush instruction cache. + * This is a no-op on the 601. + */ +_GLOBAL(flush_instruction_cache) +#if defined(CONFIG_8xx) + isync + lis r5, IDC_INVALL@h + mtspr SPRN_IC_CST, r5 +#elif defined(CONFIG_4xx) +#ifdef CONFIG_403GCX + li r3, 512 + mtctr r3 + lis r4, KERNELBASE@h +1: iccci 0, r4 + addi r4, r4, 16 + bdnz 1b +#else + lis r3, KERNELBASE@h + iccci 0,r3 +#endif +#elif CONFIG_FSL_BOOKE +BEGIN_FTR_SECTION + mfspr r3,SPRN_L1CSR0 + ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC + /* msync; isync recommended here */ + mtspr SPRN_L1CSR0,r3 + isync + blr +END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) + mfspr r3,SPRN_L1CSR1 + ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR + mtspr SPRN_L1CSR1,r3 +#else + mfspr r3,SPRN_PVR + rlwinm r3,r3,16,16,31 + cmpwi 0,r3,1 + beqlr /* for 601, do nothing */ + /* 603/604 processor - use invalidate-all bit in HID0 */ + mfspr r3,SPRN_HID0 + ori r3,r3,HID0_ICFI + mtspr SPRN_HID0,r3 +#endif /* CONFIG_8xx/4xx */ + isync + blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * This is a no-op on the 601. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_icache_range) +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) + li r5,L1_CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,L1_CACHE_LINE_SIZE + bdnz 2b + sync /* additional sync needed on g4 */ + isync + blr +/* + * Write any modified data cache blocks out to memory. + * Does not invalidate the corresponding cache lines (especially for + * any corresponding instruction cache). + * + * clean_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(clean_dcache_range) + li r5,L1_CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbst 0,r3 + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + blr + +/* + * Write any modified data cache blocks out to memory and invalidate them. + * Does not invalidate the corresponding instruction cache blocks. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) + li r5,L1_CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbf 0,r3 + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + blr + +/* + * Like above, but invalidate the D-cache. This is used by the 8xx + * to invalidate the cache so the PPC core doesn't get stale data + * from the CPM (no cache snooping here :-). + * + * invalidate_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(invalidate_dcache_range) + li r5,L1_CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbi 0,r3 + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbi's to get to ram */ + blr + +#ifdef CONFIG_NOT_COHERENT_CACHE +/* + * 40x cores have 8K or 16K dcache and 32 byte line size. + * 44x has a 32K dcache and 32 byte line size. + * 8xx has 1, 2, 4, 8K variants. + * For now, cover the worst case of the 44x. + * Must be called with external interrupts disabled. + */ +#define CACHE_NWAYS 64 +#define CACHE_NLINES 16 + +_GLOBAL(flush_dcache_all) + li r4, (2 * CACHE_NWAYS * CACHE_NLINES) + mtctr r4 + lis r5, KERNELBASE@h +1: lwz r3, 0(r5) /* Load one word from every line */ + addi r5, r5, L1_CACHE_LINE_SIZE + bdnz 1b + blr +#endif /* CONFIG_NOT_COHERENT_CACHE */ + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * This is a no-op on the 601 which has a unified cache. + * + * void __flush_dcache_icache(void *page) + */ +_GLOBAL(__flush_dcache_icache) +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) + rlwinm r3,r3,0,0,19 /* Get page base address */ + li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + mtctr r4 + mr r6,r3 +0: dcbst 0,r3 /* Write line to ram */ + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 0b + sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,L1_CACHE_LINE_SIZE + bdnz 1b + sync + isync + blr + +/* + * Flush a particular page from the data cache to RAM, identified + * by its physical address. We turn off the MMU so we can just use + * the physical address (this may be a highmem page without a kernel + * mapping). + * + * void __flush_dcache_icache_phys(unsigned long physaddr) + */ +_GLOBAL(__flush_dcache_icache_phys) +BEGIN_FTR_SECTION + blr /* for 601, do nothing */ +END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) + mfmsr r10 + rlwinm r0,r10,0,28,26 /* clear DR */ + mtmsr r0 + isync + rlwinm r3,r3,0,0,19 /* Get page base address */ + li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + mtctr r4 + mr r6,r3 +0: dcbst 0,r3 /* Write line to ram */ + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 0b + sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,L1_CACHE_LINE_SIZE + bdnz 1b + sync + mtmsr r10 /* restore DR */ + isync + blr + +/* + * Clear pages using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced). This only works on cacheable memory. + * + * void clear_pages(void *page, int order) ; + */ +_GLOBAL(clear_pages) + li r0,4096/L1_CACHE_LINE_SIZE + slw r0,r0,r4 + mtctr r0 +#ifdef CONFIG_8xx + li r4, 0 +1: stw r4, 0(r3) + stw r4, 4(r3) + stw r4, 8(r3) + stw r4, 12(r3) +#else +1: dcbz 0,r3 +#endif + addi r3,r3,L1_CACHE_LINE_SIZE + bdnz 1b + blr + +/* + * Copy a whole page. We use the dcbz instruction on the destination + * to reduce memory traffic (it eliminates the unnecessary reads of + * the destination into cache). This requires that the destination + * is cacheable. + */ +#define COPY_16_BYTES \ + lwz r6,4(r4); \ + lwz r7,8(r4); \ + lwz r8,12(r4); \ + lwzu r9,16(r4); \ + stw r6,4(r3); \ + stw r7,8(r3); \ + stw r8,12(r3); \ + stwu r9,16(r3) + +_GLOBAL(copy_page) + addi r3,r3,-4 + addi r4,r4,-4 + +#ifdef CONFIG_8xx + /* don't use prefetch on 8xx */ + li r0,4096/L1_CACHE_LINE_SIZE + mtctr r0 +1: COPY_16_BYTES + bdnz 1b + blr + +#else /* not 8xx, we can prefetch */ + li r5,4 + +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH + li r11,4 + mtctr r0 +11: dcbt r11,r4 + addi r11,r11,L1_CACHE_LINE_SIZE + bdnz 11b +#else /* MAX_COPY_PREFETCH == 1 */ + dcbt r5,r4 + li r11,L1_CACHE_LINE_SIZE+4 +#endif /* MAX_COPY_PREFETCH */ + li r0,4096/L1_CACHE_LINE_SIZE - MAX_COPY_PREFETCH + crclr 4*cr0+eq +2: + mtctr r0 +1: + dcbt r11,r4 + dcbz r5,r3 + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif + bdnz 1b + beqlr + crnot 4*cr0+eq,4*cr0+eq + li r0,MAX_COPY_PREFETCH + li r11,4 + b 2b +#endif /* CONFIG_8xx */ + +/* + * void atomic_clear_mask(atomic_t mask, atomic_t *addr) + * void atomic_set_mask(atomic_t mask, atomic_t *addr); + */ +_GLOBAL(atomic_clear_mask) +10: lwarx r5,0,r4 + andc r5,r5,r3 + PPC405_ERR77(0,r4) + stwcx. r5,0,r4 + bne- 10b + blr +_GLOBAL(atomic_set_mask) +10: lwarx r5,0,r4 + or r5,r5,r3 + PPC405_ERR77(0,r4) + stwcx. r5,0,r4 + bne- 10b + blr + +/* + * I/O string operations + * + * insb(port, buf, len) + * outsb(port, buf, len) + * insw(port, buf, len) + * outsw(port, buf, len) + * insl(port, buf, len) + * outsl(port, buf, len) + * insw_ns(port, buf, len) + * outsw_ns(port, buf, len) + * insl_ns(port, buf, len) + * outsl_ns(port, buf, len) + * + * The *_ns versions don't do byte-swapping. + */ +_GLOBAL(_insb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbz r5,0(r3) + eieio + stbu r5,1(r4) + bdnz 00b + blr + +_GLOBAL(_outsb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbzu r5,1(r4) + stb r5,0(r3) + eieio + bdnz 00b + blr + +_GLOBAL(_insw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhbrx r5,0,r3 + eieio + sthu r5,2(r4) + bdnz 00b + blr + +_GLOBAL(_outsw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + eieio + sthbrx r5,0,r3 + bdnz 00b + blr + +_GLOBAL(_insl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwbrx r5,0,r3 + eieio + stwu r5,4(r4) + bdnz 00b + blr + +_GLOBAL(_outsl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stwbrx r5,0,r3 + eieio + bdnz 00b + blr + +_GLOBAL(__ide_mm_insw) +_GLOBAL(_insw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhz r5,0(r3) + eieio + sthu r5,2(r4) + bdnz 00b + blr + +_GLOBAL(__ide_mm_outsw) +_GLOBAL(_outsw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + sth r5,0(r3) + eieio + bdnz 00b + blr + +_GLOBAL(__ide_mm_insl) +_GLOBAL(_insl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwz r5,0(r3) + eieio + stwu r5,4(r4) + bdnz 00b + blr + +_GLOBAL(__ide_mm_outsl) +_GLOBAL(_outsl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stw r5,0(r3) + eieio + bdnz 00b + blr + +/* + * Extended precision shifts. + * + * Updated to be valid for shift counts from 0 to 63 inclusive. + * -- Gabriel + * + * R3/R4 has 64 bit value + * R5 has shift count + * result in R3/R4 + * + * ashrdi3: arithmetic right shift (sign propagation) + * lshrdi3: logical right shift + * ashldi3: left shift + */ +_GLOBAL(__ashrdi3) + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr + +_GLOBAL(__ashldi3) + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 + blr + +_GLOBAL(__lshrdi3) + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr + +_GLOBAL(abs) + srawi r4,r3,31 + xor r3,r3,r4 + sub r3,r3,r4 + blr + +_GLOBAL(_get_SP) + mr r3,r1 /* Close enough */ + blr + +/* + * These are used in the alignment trap handler when emulating + * single-precision loads and stores. + * We restore and save the fpscr so the task gets the same result + * and exceptions as if the cpu had performed the load or store. + */ + +#ifdef CONFIG_PPC_FPU +_GLOBAL(cvt_fd) + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfs 0,0(r3) + stfd 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr + +_GLOBAL(cvt_df) + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr +#endif + +/* + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +_GLOBAL(kernel_thread) + stwu r1,-16(r1) + stw r30,8(r1) + stw r31,12(r1) + mr r30,r3 /* function */ + mr r31,r4 /* argument */ + ori r3,r5,CLONE_VM /* flags */ + oris r3,r3,CLONE_UNTRACED>>16 + li r4,0 /* new sp (unused) */ + li r0,__NR_clone + sc + cmpwi 0,r3,0 /* parent or child? */ + bne 1f /* return if parent */ + li r0,0 /* make top-level stack frame */ + stwu r0,-16(r1) + mtlr r30 /* fn addr in lr */ + mr r3,r31 /* load arg and call fn */ + PPC440EP_ERR42 + blrl + li r0,__NR_exit /* exit if function returns */ + li r3,0 + sc +1: lwz r30,8(r1) + lwz r31,12(r1) + addi r1,r1,16 + blr + +_GLOBAL(execve) + li r0,__NR_execve + sc + bnslr + neg r3,r3 + blr + +/* + * This routine is just here to keep GCC happy - sigh... + */ +_GLOBAL(__main) + blr diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S new file mode 100644 index 000000000000..8fe295693c09 --- /dev/null +++ b/arch/powerpc/kernel/misc_64.S @@ -0,0 +1,898 @@ +/* + * arch/powerpc/kernel/misc64.S + * + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * PPC64 updates by Dave Engebretsen (engebret@us.ibm.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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + .text + +/* + * Returns (address we are running at) - (address we were linked at) + * for use before the text and data are mapped to KERNELBASE. + */ + +_GLOBAL(reloc_offset) + mflr r0 + bl 1f +1: mflr r3 + LOADADDR(r4,1b) + subf r3,r4,r3 + mtlr r0 + blr + +/* + * add_reloc_offset(x) returns x + reloc_offset(). + */ +_GLOBAL(add_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + LOADADDR(r4,1b) + subf r5,r4,r5 + add r3,r3,r5 + mtlr r0 + blr + +_GLOBAL(get_msr) + mfmsr r3 + blr + +_GLOBAL(get_dar) + mfdar r3 + blr + +_GLOBAL(get_srr0) + mfsrr0 r3 + blr + +_GLOBAL(get_srr1) + mfsrr1 r3 + blr + +_GLOBAL(get_sp) + mr r3,r1 + blr + +#ifdef CONFIG_IRQSTACKS +_GLOBAL(call_do_softirq) + mflr r0 + std r0,16(r1) + stdu r1,THREAD_SIZE-112(r3) + mr r1,r3 + bl .__do_softirq + ld r1,0(r1) + ld r0,16(r1) + mtlr r0 + blr + +_GLOBAL(call_handle_IRQ_event) + mflr r0 + std r0,16(r1) + stdu r1,THREAD_SIZE-112(r6) + mr r1,r6 + bl .handle_IRQ_event + ld r1,0(r1) + ld r0,16(r1) + mtlr r0 + blr +#endif /* CONFIG_IRQSTACKS */ + + /* + * To be called by C code which needs to do some operations with MMU + * disabled. Note that interrupts have to be disabled by the caller + * prior to calling us. The code called _MUST_ be in the RMO of course + * and part of the linear mapping as we don't attempt to translate the + * stack pointer at all. The function is called with the stack switched + * to this CPU emergency stack + * + * prototype is void *call_with_mmu_off(void *func, void *data); + * + * the called function is expected to be of the form + * + * void *called(void *data); + */ +_GLOBAL(call_with_mmu_off) + mflr r0 /* get link, save it on stackframe */ + std r0,16(r1) + mr r1,r5 /* save old stack ptr */ + ld r1,PACAEMERGSP(r13) /* get emerg. stack */ + subi r1,r1,STACK_FRAME_OVERHEAD + std r0,16(r1) /* save link on emerg. stack */ + std r5,0(r1) /* save old stack ptr in backchain */ + ld r3,0(r3) /* get to real function ptr (assume same TOC) */ + bl 2f /* we need LR to return, continue at label 2 */ + + ld r0,16(r1) /* we return here from the call, get LR and */ + ld r1,0(r1) /* .. old stack ptr */ + mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ + mfmsr r4 + ori r4,r4,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r4 + rfid + +2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ + mr r3,r4 /* get parameter */ + mfmsr r0 + ori r0,r0,MSR_IR|MSR_DR + xori r0,r0,MSR_IR|MSR_DR + mtspr SPRN_SRR1,r0 + rfid + + + .section ".toc","aw" +PPC64_CACHES: + .tc ppc64_caches[TC],ppc64_caches + .section ".text" + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * + * flush_icache_range(unsigned long start, unsigned long stop) + * + * flush all bytes from start through stop-1 inclusive + */ + +_KPROBE(__flush_icache_range) + +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + * and in some cases i-cache and d-cache line sizes differ from + * each other. + */ + ld r10,PPC64_CACHES@toc(r2) + lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +1: dcbst 0,r6 + add r6,r6,r7 + bdnz 1b + sync + +/* Now invalidate the instruction cache */ + + lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 + lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +2: icbi 0,r6 + add r6,r6,r7 + bdnz 2b + isync + blr + .previous .text +/* + * Like above, but only do the D-cache. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + * + * flush all bytes from start to stop-1 inclusive + */ +_GLOBAL(flush_dcache_range) + +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + */ + ld r10,PPC64_CACHES@toc(r2) + lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +0: dcbst 0,r6 + add r6,r6,r7 + bdnz 0b + sync + blr + +/* + * Like above, but works on non-mapped physical addresses. + * Use only for non-LPAR setups ! It also assumes real mode + * is cacheable. Used for flushing out the DART before using + * it as uncacheable memory + * + * flush_dcache_phys_range(unsigned long start, unsigned long stop) + * + * flush all bytes from start to stop-1 inclusive + */ +_GLOBAL(flush_dcache_phys_range) + ld r10,PPC64_CACHES@toc(r2) + lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mfmsr r5 /* Disable MMU Data Relocation */ + ori r0,r5,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsr r0 + sync + isync + mtctr r8 +0: dcbst 0,r6 + add r6,r6,r7 + bdnz 0b + sync + isync + mtmsr r5 /* Re-enable MMU Data Relocation */ + sync + isync + blr + +_GLOBAL(flush_inval_dcache_range) + ld r10,PPC64_CACHES@toc(r2) + lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + sync + isync + mtctr r8 +0: dcbf 0,r6 + add r6,r6,r7 + bdnz 0b + sync + isync + blr + + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + * void __flush_dcache_icache(void *page) + */ +_GLOBAL(__flush_dcache_icache) +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + */ + +/* Flush the dcache */ + ld r7,PPC64_CACHES@toc(r2) + clrrdi r3,r3,PAGE_SHIFT /* Page align */ + lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ + lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ + mr r6,r3 + mtctr r4 +0: dcbst 0,r6 + add r6,r6,r5 + bdnz 0b + sync + +/* Now invalidate the icache */ + + lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ + lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ + mtctr r4 +1: icbi 0,r3 + add r3,r3,r5 + bdnz 1b + isync + blr + +/* + * I/O string operations + * + * insb(port, buf, len) + * outsb(port, buf, len) + * insw(port, buf, len) + * outsw(port, buf, len) + * insl(port, buf, len) + * outsl(port, buf, len) + * insw_ns(port, buf, len) + * outsw_ns(port, buf, len) + * insl_ns(port, buf, len) + * outsl_ns(port, buf, len) + * + * The *_ns versions don't do byte-swapping. + */ +_GLOBAL(_insb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbz r5,0(r3) + eieio + stbu r5,1(r4) + bdnz 00b + twi 0,r5,0 + isync + blr + +_GLOBAL(_outsb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbzu r5,1(r4) + stb r5,0(r3) + bdnz 00b + sync + blr + +_GLOBAL(_insw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhbrx r5,0,r3 + eieio + sthu r5,2(r4) + bdnz 00b + twi 0,r5,0 + isync + blr + +_GLOBAL(_outsw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + sthbrx r5,0,r3 + bdnz 00b + sync + blr + +_GLOBAL(_insl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwbrx r5,0,r3 + eieio + stwu r5,4(r4) + bdnz 00b + twi 0,r5,0 + isync + blr + +_GLOBAL(_outsl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stwbrx r5,0,r3 + bdnz 00b + sync + blr + +/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */ +_GLOBAL(_insw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhz r5,0(r3) + eieio + sthu r5,2(r4) + bdnz 00b + twi 0,r5,0 + isync + blr + +/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */ +_GLOBAL(_outsw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + sth r5,0(r3) + bdnz 00b + sync + blr + +_GLOBAL(_insl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwz r5,0(r3) + eieio + stwu r5,4(r4) + bdnz 00b + twi 0,r5,0 + isync + blr + +_GLOBAL(_outsl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stw r5,0(r3) + bdnz 00b + sync + blr + + +_GLOBAL(cvt_fd) + lfd 0,0(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfs 0,0(r3) + stfd 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,0(r5) + blr + +_GLOBAL(cvt_df) + lfd 0,0(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,0(r5) + blr + +/* + * identify_cpu and calls setup_cpu + * In: r3 = base of the cpu_specs array + * r4 = address of cur_cpu_spec + * r5 = relocation offset + */ +_GLOBAL(identify_cpu) + mfpvr r7 +1: + lwz r8,CPU_SPEC_PVR_MASK(r3) + and r8,r8,r7 + lwz r9,CPU_SPEC_PVR_VALUE(r3) + cmplw 0,r9,r8 + beq 1f + addi r3,r3,CPU_SPEC_ENTRY_SIZE + b 1b +1: + sub r0,r3,r5 + std r0,0(r4) + ld r4,CPU_SPEC_SETUP(r3) + add r4,r4,r5 + ld r4,0(r4) + add r4,r4,r5 + mtctr r4 + /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ + mr r4,r3 + mr r3,r5 + bctr + +/* + * do_cpu_ftr_fixups - goes through the list of CPU feature fixups + * and writes nop's over sections of code that don't apply for this cpu. + * r3 = data offset (not changed) + */ +_GLOBAL(do_cpu_ftr_fixups) + /* Get CPU 0 features */ + LOADADDR(r6,cur_cpu_spec) + sub r6,r6,r3 + ld r4,0(r6) + sub r4,r4,r3 + ld r4,CPU_SPEC_FEATURES(r4) + /* Get the fixup table */ + LOADADDR(r6,__start___ftr_fixup) + sub r6,r6,r3 + LOADADDR(r7,__stop___ftr_fixup) + sub r7,r7,r3 + /* Do the fixup */ +1: cmpld r6,r7 + bgelr + addi r6,r6,32 + ld r8,-32(r6) /* mask */ + and r8,r8,r4 + ld r9,-24(r6) /* value */ + cmpld r8,r9 + beq 1b + ld r8,-16(r6) /* section begin */ + ld r9,-8(r6) /* section end */ + subf. r9,r8,r9 + beq 1b + /* write nops over the section of code */ + /* todo: if large section, add a branch at the start of it */ + srwi r9,r9,2 + mtctr r9 + sub r8,r8,r3 + lis r0,0x60000000@h /* nop */ +3: stw r0,0(r8) + andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l + beq 2f + dcbst 0,r8 /* suboptimal, but simpler */ + sync + icbi 0,r8 +2: addi r8,r8,4 + bdnz 3b + sync /* additional sync needed on g4 */ + isync + b 1b + +#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) +/* + * Do an IO access in real mode + */ +_GLOBAL(real_readb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + lbz r3,0(r3) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr + + /* + * Do an IO access in real mode + */ +_GLOBAL(real_writeb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + mfspr r6,SPRN_HID4 + rldicl r5,r6,32,0 + ori r5,r5,0x100 + rldicl r5,r5,32,0 + sync + mtspr SPRN_HID4,r5 + isync + slbia + isync + stb r3,0(r4) + sync + mtspr SPRN_HID4,r6 + isync + slbia + isync + mtmsrd r7 + sync + isync + blr +#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ + +/* + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +_GLOBAL(kernel_thread) + std r29,-24(r1) + std r30,-16(r1) + stdu r1,-STACK_FRAME_OVERHEAD(r1) + mr r29,r3 + mr r30,r4 + ori r3,r5,CLONE_VM /* flags */ + oris r3,r3,(CLONE_UNTRACED>>16) + li r4,0 /* new sp (unused) */ + li r0,__NR_clone + sc + cmpdi 0,r3,0 /* parent or child? */ + bne 1f /* return if parent */ + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + ld r2,8(r29) + ld r29,0(r29) + mtlr r29 /* fn addr in lr */ + mr r3,r30 /* load arg and call fn */ + blrl + li r0,__NR_exit /* exit after child exits */ + li r3,0 + sc +1: addi r1,r1,STACK_FRAME_OVERHEAD + ld r29,-24(r1) + ld r30,-16(r1) + blr + +/* + * disable_kernel_fp() + * Disable the FPU. + */ +_GLOBAL(disable_kernel_fp) + mfmsr r3 + rldicl r0,r3,(63-MSR_FP_LG),1 + rldicl r3,r0,(MSR_FP_LG+1),0 + mtmsrd r3 /* disable use of fpu now */ + isync + blr + +#ifdef CONFIG_ALTIVEC + +#if 0 /* this has no callers for now */ +/* + * disable_kernel_altivec() + * Disable the VMX. + */ +_GLOBAL(disable_kernel_altivec) + mfmsr r3 + rldicl r0,r3,(63-MSR_VEC_LG),1 + rldicl r3,r0,(MSR_VEC_LG+1),0 + mtmsrd r3 /* disable use of VMX now */ + isync + blr +#endif /* 0 */ + +/* + * giveup_altivec(tsk) + * Disable VMX for the task given as the argument, + * and save the vector registers in its thread_struct. + * Enables the VMX for use in the kernel on return. + */ +_GLOBAL(giveup_altivec) + mfmsr r5 + oris r5,r5,MSR_VEC@h + mtmsrd r5 /* enable use of VMX now */ + isync + cmpdi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + ld r5,PT_REGS(r3) + cmpdi 0,r5,0 + SAVE_32VRS(0,r4,r3) + mfvscr vr0 + li r4,THREAD_VSCR + stvx vr0,r4,r3 + beq 1f + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_VEC@h + andc r4,r4,r3 /* disable FP for previous task */ + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + ld r4,last_task_used_altivec@got(r2) + std r5,0(r4) +#endif /* CONFIG_SMP */ + blr + +#endif /* CONFIG_ALTIVEC */ + +_GLOBAL(__setup_cpu_power3) + blr + +_GLOBAL(execve) + li r0,__NR_execve + sc + bnslr + neg r3,r3 + blr + +/* kexec_wait(phys_cpu) + * + * wait for the flag to change, indicating this kernel is going away but + * the slave code for the next one is at addresses 0 to 100. + * + * This is used by all slaves. + * + * Physical (hardware) cpu id should be in r3. + */ +_GLOBAL(kexec_wait) + bl 1f +1: mflr r5 + addi r5,r5,kexec_flag-1b + +99: HMT_LOW +#ifdef CONFIG_KEXEC /* use no memory without kexec */ + lwz r4,0(r5) + cmpwi 0,r4,0 + bnea 0x60 +#endif + b 99b + +/* this can be in text because we won't change it until we are + * running in real anyways + */ +kexec_flag: + .long 0 + + +#ifdef CONFIG_KEXEC + +/* kexec_smp_wait(void) + * + * call with interrupts off + * note: this is a terminal routine, it does not save lr + * + * get phys id from paca + * set paca id to -1 to say we got here + * switch to real mode + * join other cpus in kexec_wait(phys_id) + */ +_GLOBAL(kexec_smp_wait) + lhz r3,PACAHWCPUID(r13) + li r4,-1 + sth r4,PACAHWCPUID(r13) /* let others know we left */ + bl real_mode + b .kexec_wait + +/* + * switch to real mode (turn mmu off) + * we use the early kernel trick that the hardware ignores bits + * 0 and 1 (big endian) of the effective address in real mode + * + * don't overwrite r3 here, it is live for kexec_wait above. + */ +real_mode: /* assume normal blr return */ +1: li r9,MSR_RI + li r10,MSR_DR|MSR_IR + mflr r11 /* return address to SRR0 */ + mfmsr r12 + andc r9,r12,r9 + andc r10,r12,r10 + + mtmsrd r9,1 + mtspr SPRN_SRR1,r10 + mtspr SPRN_SRR0,r11 + rfid + + +/* + * kexec_sequence(newstack, start, image, control, clear_all()) + * + * does the grungy work with stack switching and real mode switches + * also does simple calls to other code + */ + +_GLOBAL(kexec_sequence) + mflr r0 + std r0,16(r1) + + /* switch stacks to newstack -- &kexec_stack.stack */ + stdu r1,THREAD_SIZE-112(r3) + mr r1,r3 + + li r0,0 + std r0,16(r1) + + /* save regs for local vars on new stack. + * yes, we won't go back, but ... + */ + std r31,-8(r1) + std r30,-16(r1) + std r29,-24(r1) + std r28,-32(r1) + std r27,-40(r1) + std r26,-48(r1) + std r25,-56(r1) + + stdu r1,-112-64(r1) + + /* save args into preserved regs */ + mr r31,r3 /* newstack (both) */ + mr r30,r4 /* start (real) */ + mr r29,r5 /* image (virt) */ + mr r28,r6 /* control, unused */ + mr r27,r7 /* clear_all() fn desc */ + mr r26,r8 /* spare */ + lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ + + /* disable interrupts, we are overwriting kernel data next */ + mfmsr r3 + rlwinm r3,r3,0,17,15 + mtmsrd r3,1 + + /* copy dest pages, flush whole dest image */ + mr r3,r29 + bl .kexec_copy_flush /* (image) */ + + /* turn off mmu */ + bl real_mode + + /* clear out hardware hash page table and tlb */ + ld r5,0(r27) /* deref function descriptor */ + mtctr r5 + bctrl /* ppc_md.hash_clear_all(void); */ + +/* + * kexec image calling is: + * the first 0x100 bytes of the entry point are copied to 0 + * + * all slaves branch to slave = 0x60 (absolute) + * slave(phys_cpu_id); + * + * master goes to start = entry point + * start(phys_cpu_id, start, 0); + * + * + * a wrapper is needed to call existing kernels, here is an approximate + * description of one method: + * + * v2: (2.6.10) + * start will be near the boot_block (maybe 0x100 bytes before it?) + * it will have a 0x60, which will b to boot_block, where it will wait + * and 0 will store phys into struct boot-block and load r3 from there, + * copy kernel 0-0x100 and tell slaves to back down to 0x60 again + * + * v1: (2.6.9) + * boot block will have all cpus scanning device tree to see if they + * are the boot cpu ????? + * other device tree differences (prop sizes, va vs pa, etc)... + */ + + /* copy 0x100 bytes starting at start to 0 */ + li r3,0 + mr r4,r30 + li r5,0x100 + li r6,0 + bl .copy_and_flush /* (dest, src, copy limit, start offset) */ +1: /* assume normal blr return */ + + /* release other cpus to the new kernel secondary start at 0x60 */ + mflr r5 + li r6,1 + stw r6,kexec_flag-1b(5) + mr r3,r25 # my phys cpu + mr r4,r30 # start, aka phys mem offset + mtlr 4 + li r5,0 + blr /* image->start(physid, image->start, 0); */ +#endif /* CONFIG_KEXEC */ diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S new file mode 100644 index 000000000000..82d1fedb441c --- /dev/null +++ b/arch/powerpc/kernel/systbl.S @@ -0,0 +1,323 @@ +/* + * This file contains the table of syscall-handling functions. + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * PPC64 updates by Dave Engebretsen (engebret@us.ibm.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. + */ + +#include +#include + +#ifdef CONFIG_PPC64 +#define SYSCALL(func) .llong .sys_##func,.sys_##func +#define SYSCALL32(func) .llong .sys_##func,.sys32_##func +#define COMPAT_SYS(func) .llong .sys_##func,.compat_sys_##func +#define PPC_SYS(func) .llong .ppc_##func,.ppc_##func +#define OLDSYS(func) .llong .sys_ni_syscall,.sys_ni_syscall +#define SYS32ONLY(func) .llong .sys_ni_syscall,.sys32_##func +#define SYSX(f, f3264, f32) .llong .f,.f3264 +#else +#define SYSCALL(func) .long sys_##func +#define SYSCALL32(func) .long sys_##func +#define COMPAT_SYS(func) .long sys_##func +#define PPC_SYS(func) .long ppc_##func +#define OLDSYS(func) .long sys_##func +#define SYS32ONLY(func) .long sys_##func +#define SYSX(f, f3264, f32) .long f32 +#endif + +#ifdef CONFIG_PPC64 +#define sys_sigpending sys_ni_syscall +#define sys_old_getrlimit sys_ni_syscall +#else +#define ppc_rtas sys_ni_syscall +#endif + +_GLOBAL(sys_call_table) +SYSCALL(restart_syscall) +SYSCALL(exit) +PPC_SYS(fork) +SYSCALL(read) +SYSCALL(write) +COMPAT_SYS(open) +SYSCALL(close) +SYSCALL32(waitpid) +SYSCALL32(creat) +SYSCALL(link) +SYSCALL(unlink) +SYSCALL32(execve) +SYSCALL(chdir) +SYSX(sys64_time,compat_sys_time,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) +SYSCALL32(ptrace) +SYSCALL(alarm) +OLDSYS(fstat) +SYSCALL32(pause) +COMPAT_SYS(utime) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +SYSCALL32(access) +SYSCALL32(nice) +SYSCALL(ni_syscall) +SYSCALL(sync) +SYSCALL32(kill) +SYSCALL(rename) +SYSCALL32(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) +SYSCALL32(setpgid) +SYSCALL(ni_syscall) +SYS32ONLY(olduname) +SYSCALL32(umask) +SYSCALL(chroot) +SYSCALL(ustat) +SYSCALL(dup2) +SYSCALL(getppid) +SYSCALL(getpgrp) +SYSCALL(setsid) +SYS32ONLY(sigaction) +SYSCALL(sgetmask) +SYSCALL32(ssetmask) +SYSCALL(setreuid) +SYSCALL(setregid) +SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) +COMPAT_SYS(sigpending) +SYSCALL32(sethostname) +COMPAT_SYS(setrlimit) +COMPAT_SYS(old_getrlimit) +COMPAT_SYS(getrusage) +SYSCALL32(gettimeofday) +SYSCALL32(settimeofday) +SYSCALL32(getgroups) +SYSCALL32(setgroups) +SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select) +SYSCALL(symlink) +OLDSYS(lstat) +SYSCALL32(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) +SYSCALL32(getpriority) +SYSCALL32(setpriority) +SYSCALL(ni_syscall) +COMPAT_SYS(statfs) +COMPAT_SYS(fstatfs) +SYSCALL(ni_syscall) +COMPAT_SYS(socketcall) +SYSCALL32(syslog) +COMPAT_SYS(setitimer) +COMPAT_SYS(getitimer) +COMPAT_SYS(newstat) +COMPAT_SYS(newlstat) +COMPAT_SYS(newfstat) +SYSX(sys_ni_syscall,sys32_uname,sys_uname) +SYSCALL(ni_syscall) +SYSCALL(vhangup) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +COMPAT_SYS(wait4) +SYSCALL(swapoff) +SYSCALL32(sysinfo) +SYSCALL32(ipc) +SYSCALL(fsync) +SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) +PPC_SYS(clone) +SYSCALL32(setdomainname) +SYSX(ppc64_newuname,ppc64_newuname,sys_newuname) +SYSCALL(ni_syscall) +SYSCALL32(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) +SYSCALL32(getpgid) +SYSCALL(fchdir) +SYSCALL(bdflush) +SYSCALL32(sysfs) +SYSX(ppc64_personality,ppc64_personality,sys_personality) +SYSCALL(ni_syscall) +SYSCALL(setfsuid) +SYSCALL(setfsgid) +SYSCALL(llseek) +SYSCALL32(getdents) +SYSX(sys_select,ppc32_select,ppc_select) +SYSCALL(flock) +SYSCALL(msync) +COMPAT_SYS(readv) +COMPAT_SYS(writev) +SYSCALL32(getsid) +SYSCALL(fdatasync) +SYSCALL32(sysctl) +SYSCALL(mlock) +SYSCALL(munlock) +SYSCALL(mlockall) +SYSCALL(munlockall) +SYSCALL32(sched_setparam) +SYSCALL32(sched_getparam) +SYSCALL32(sched_setscheduler) +SYSCALL32(sched_getscheduler) +SYSCALL(sched_yield) +SYSCALL32(sched_get_priority_max) +SYSCALL32(sched_get_priority_min) +SYSCALL32(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) +SYSCALL32(prctl) +SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) +SYSCALL32(rt_sigaction) +SYSCALL32(rt_sigprocmask) +SYSCALL32(rt_sigpending) +COMPAT_SYS(rt_sigtimedwait) +SYSCALL32(rt_sigqueueinfo) +SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) +SYSCALL32(pread64) +SYSCALL32(pwrite64) +SYSCALL(chown) +SYSCALL(getcwd) +SYSCALL(capget) +SYSCALL(capset) +SYSCALL32(sigaltstack) +SYSX(sys_sendfile64,sys32_sendfile,sys_sendfile) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +PPC_SYS(vfork) +COMPAT_SYS(getrlimit) +SYSCALL32(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) +SYSCALL32(pciconfig_read) +SYSCALL32(pciconfig_write) +SYSCALL32(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,ppc32_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) +SYSCALL32(tgkill) +SYSCALL32(utimes) +COMPAT_SYS(statfs64) +COMPAT_SYS(fstatfs64) +SYSX(sys_ni_syscall, ppc32_fadvise64_64, sys_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) +SYSCALL32(add_key) +SYSCALL32(request_key) +COMPAT_SYS(keyctl) +COMPAT_SYS(waitid) +SYSCALL32(ioprio_set) +SYSCALL32(ioprio_get) +SYSCALL(inotify_init) +SYSCALL(inotify_add_watch) +SYSCALL(inotify_rm_watch) From b42b661745c8d78cd3483752fb22cc7420c67f74 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:37:16 +1000 Subject: [PATCH 0342/1939] powerpc: Make prom_init.c suitable for both 32-bit and 64-bit Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e01cda1454c9..75b487f107c3 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1968,9 +1968,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, extern char _stext[]; unsigned long hdr; u32 getprop_rval; + unsigned long offset = reloc_offset(); #ifdef CONFIG_PPC32 - unsigned long offset = reloc_offset(); reloc_got2(offset); #endif From 8641778049e75c1da66e66441a6d8b7a2069f607 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:37:57 +1000 Subject: [PATCH 0343/1939] powerpc: Reduce the 32/64-bit differences in traps.c Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 58 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index a2e4ad3f5a75..6a881e3ea01d 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -31,29 +31,33 @@ #include #include #include -#include +#include #include #include #include #include +#include +#include +#include #ifdef CONFIG_PPC32 #include -#include +#include +#endif #ifdef CONFIG_PMAC_BACKLIGHT #include #endif -#include -#endif #ifdef CONFIG_PPC64 +#include #include -#include -#include #include -#include #include #endif +#ifdef CONFIG_PPC64 /* XXX */ +#define _IO_BASE pci_io_base +#endif + #ifdef CONFIG_DEBUGGER int (*__debugger)(struct pt_regs *regs); int (*__debugger_ipi)(struct pt_regs *regs); @@ -277,7 +281,6 @@ static inline int check_io_access(struct pt_regs *regs) } #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - /* On 4xx, the reason for the machine check or program exception is in the ESR. */ #define get_reason(regs) ((regs)->dsisr) @@ -296,7 +299,6 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC) #else - /* On non-4xx, the reason for the machine check or program exception is in the MSR. */ #define get_reason(regs) ((regs)->msr) @@ -475,7 +477,7 @@ void machine_check_exception(struct pt_regs *regs) * additional info, e.g. bus error registers. */ platform_machine_check(regs); -#endif /* CONFIG_PPC32 */ +#endif /* CONFIG_PPC64 */ if (debugger_fault_handler(regs)) return; @@ -486,12 +488,10 @@ void machine_check_exception(struct pt_regs *regs) panic("Unrecoverable Machine check"); } -#ifdef CONFIG_PPC32 void SMIException(struct pt_regs *regs) { die("System Management Interrupt", regs, SIGABRT); } -#endif void unknown_exception(struct pt_regs *regs) { @@ -511,12 +511,10 @@ void instruction_breakpoint_exception(struct pt_regs *regs) _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); } -#ifdef CONFIG_PPC32 void RunModeException(struct pt_regs *regs) { _exception(SIGTRAP, regs, 0, 0); } -#endif void __kprobes single_step_exception(struct pt_regs *regs) { @@ -542,7 +540,6 @@ static void emulate_single_step(struct pt_regs *regs) if (single_stepping(regs)) { clear_single_step(regs); _exception(SIGTRAP, regs, TRAP_TRACE, 0); - single_step_exception(regs); } } @@ -587,6 +584,7 @@ static void parse_fpe(struct pt_regs *regs) * There are a couple of ways to do this, either "decode" the instruction * or directly match lots of bits. In this case, matching lots of * bits is faster and easier. + * */ #define INST_MFSPR_PVR 0x7c1f42a6 #define INST_MFSPR_PVR_MASK 0xfc1fffff @@ -597,8 +595,6 @@ static void parse_fpe(struct pt_regs *regs) #define INST_MCRXR 0x7c000400 #define INST_MCRXR_MASK 0x7c0007fe -#ifdef CONFIG_PPC32 - #define INST_STRING 0x7c00042a #define INST_STRING_MASK 0x7c0007fe #define INST_STRING_GEN_MASK 0x7c00067e @@ -674,7 +670,6 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) return 0; } -#endif /* CONFIG_PPC32 */ static int emulate_instruction(struct pt_regs *regs) { @@ -701,28 +696,17 @@ static int emulate_instruction(struct pt_regs *regs) /* Emulate the mcrxr insn. */ if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { - unsigned int shift = (instword >> 21) & 0x1c; + int shift = (instword >> 21) & 0x1c; unsigned long msk = 0xf0000000UL >> shift; -#ifdef CONFIG_PPC64 - static int warned; - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'mcrxr' insn\n", - current->pid, current->comm); - warned = 1; - } -#endif regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); regs->xer &= ~0xf0000000UL; return 0; } -#ifdef CONFIG_PPC32 /* Emulate load/store string insn. */ if ((instword & INST_STRING_GEN_MASK) == INST_STRING) return emulate_string_inst(regs, instword); -#endif return -EINVAL; } @@ -769,22 +753,18 @@ static int check_bug_trap(struct pt_regs *regs) xmon_printf(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); -#endif +#endif /* CONFIG_XMON */ printk(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); -#ifdef CONFIG_PPC32 dump_stack(); -#else - show_stack(current, (void *)regs->gpr[1]); -#endif return 1; } -#if defined(CONFIG_PPC32) && defined(CONFIG_XMON) +#ifdef CONFIG_XMON xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n", bug->function, bug->file, bug->line); xmon(regs); -#endif +#endif /* CONFIG_XMON */ printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", bug->function, bug->file, bug->line); @@ -873,7 +853,6 @@ void alignment_exception(struct pt_regs *regs) _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); } -#ifdef CONFIG_PPC32 void StackOverflow(struct pt_regs *regs) { printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", @@ -897,7 +876,6 @@ void trace_syscall(struct pt_regs *regs) current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); } -#endif /* CONFIG_PPC32 */ void kernel_fp_unavailable_exception(struct pt_regs *regs) { @@ -963,7 +941,6 @@ void SoftwareEmulation(struct pt_regs *regs) } #endif /* CONFIG_8xx */ -#ifdef CONFIG_PPC32 #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) void DebugException(struct pt_regs *regs, unsigned long debug_status) @@ -992,7 +969,6 @@ void TAUException(struct pt_regs *regs) regs->nip, regs->msr, regs->trap, print_tainted()); } #endif /* CONFIG_INT_TAU */ -#endif /* CONFIG_PPC32*/ #ifdef CONFIG_ALTIVEC void altivec_assist_exception(struct pt_regs *regs) From 4a2885630bc0735e573bced7001dae9750cb80d5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:38:46 +1000 Subject: [PATCH 0344/1939] powerpc: Reduce the 32/64-bit diffs in vmlinux.lds.S Also adds the definition of the _sdata symbol to the ppc64 vmlinux.lds.S. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vmlinux.lds.S | 74 ++++--------------------------- arch/ppc64/kernel/vmlinux.lds.S | 1 + 2 files changed, 10 insertions(+), 65 deletions(-) diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index d0239bf8d4cc..d4dfcfbce272 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -1,6 +1,8 @@ #include #ifdef CONFIG_PPC64 #include +#else +#define PAGE_SIZE 4096 #endif #include @@ -16,9 +18,7 @@ SECTIONS /* Sections to be discarded. */ /DISCARD/ : { *(.exitcall.exit) -#ifdef CONFIG_PPC32 *(.exit.data) -#endif } @@ -49,16 +49,10 @@ SECTIONS .plt : { *(.plt) } #endif .text : { -#ifdef CONFIG_PPC64 *(.text .text.*) -#else - *(.text) -#endif SCHED_TEXT LOCK_TEXT -#ifdef CONFIG_PPC64 KPROBES_TEXT -#endif *(.fixup) #ifdef CONFIG_PPC32 *(.got1) @@ -106,7 +100,7 @@ SECTIONS #ifdef CONFIG_PPC32 /* Read-write section, merged into data segment: */ - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _sdata = .; .data : { @@ -119,10 +113,10 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __nosave_end = .; . = ALIGN(32); @@ -133,12 +127,10 @@ SECTIONS . = ALIGN(8192); .data.init_task : { *(.data.init_task) } +#endif - . = ALIGN(4096); -#else /* will be freed after init */ . = ALIGN(PAGE_SIZE); -#endif __init_begin = .; .init.text : { _sinittext = .; @@ -151,9 +143,6 @@ SECTIONS .exit.text : { *(.exit.text) } #endif .init.data : { -#ifdef CONFIG_PPC64 - *(.init.data) -#else *(.init.data); __vtop_table_begin = .; *(.vtop_fixup); @@ -161,31 +150,17 @@ SECTIONS __ptov_table_begin = .; *(.ptov_fixup); __ptov_table_end = .; -#endif } . = ALIGN(16); -#ifdef CONFIG_PPC32 - __setup_start = .; -#endif .init.setup : { -#ifdef CONFIG_PPC64 __setup_start = .; -#endif *(.init.setup) -#ifdef CONFIG_PPC64 __setup_end = .; -#endif } -#ifdef CONFIG_PPC32 - __setup_end = .; - __initcall_start = .; -#endif .initcall.init : { -#ifdef CONFIG_PPC64 __initcall_start = .; -#endif *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) @@ -193,27 +168,14 @@ SECTIONS *(.initcall5.init) *(.initcall6.init) *(.initcall7.init) -#ifdef CONFIG_PPC64 __initcall_end = .; -#endif } -#ifdef CONFIG_PPC32 - __initcall_end = .; - __con_initcall_start = .; -#endif .con_initcall.init : { -#ifdef CONFIG_PPC64 __con_initcall_start = .; -#endif *(.con_initcall.init) -#ifdef CONFIG_PPC64 __con_initcall_end = .; -#endif } -#ifdef CONFIG_PPC32 - __con_initcall_end = .; -#endif SECURITY_INIT @@ -232,31 +194,23 @@ SECTIONS #ifdef CONFIG_PPC32 . = ALIGN(32); - __per_cpu_start = .; #endif .data.percpu : { -#ifdef CONFIG_PPC64 __per_cpu_start = .; -#endif *(.data.percpu) -#ifdef CONFIG_PPC64 __per_cpu_end = .; -#endif } -#ifdef CONFIG_PPC32 - __per_cpu_end = .; -#endif -#ifdef CONFIG_PPC64 . = ALIGN(PAGE_SIZE); +#ifdef CONFIG_PPC64 . = ALIGN(16384); __init_end = .; /* freed after init ends here */ - /* Read/write sections */ . = ALIGN(PAGE_SIZE); . = ALIGN(16384); + _sdata = .; /* The initial task and kernel stack */ .data.init_task : { *(.data.init_task) @@ -288,10 +242,8 @@ SECTIONS _edata = .; } - . = ALIGN(PAGE_SIZE); #else - . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) @@ -307,23 +259,15 @@ SECTIONS __bss_start = .; #endif + .bss : { -#ifdef CONFIG_PPC64 __bss_start = .; -#else *(.sbss) *(.scommon) *(.dynbss) -#endif *(.bss) -#ifdef CONFIG_PPC32 *(COMMON) -#else __bss_stop = .; -#endif } -#ifdef CONFIG_PPC32 - __bss_stop = .; -#endif #ifdef CONFIG_PPC64 . = ALIGN(PAGE_SIZE); diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S index f34d514432ac..022f220e772f 100644 --- a/arch/ppc64/kernel/vmlinux.lds.S +++ b/arch/ppc64/kernel/vmlinux.lds.S @@ -106,6 +106,7 @@ SECTIONS /* Read/write sections */ . = ALIGN(PAGE_SIZE); . = ALIGN(16384); + _sdata = .; /* The initial task and kernel stack */ .data.init_task : { *(.data.init_task) From 5a408329ed19cf2a80e831d28cbd93d2e36155a6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:41:25 +1000 Subject: [PATCH 0345/1939] powerpc: Fix bug caused by negation of 64-bit reloc_offset value Although both ppc32 and ppc64 have a reloc_offset function, the ppc64 one produced the opposite sign to the ppc32 one. This standardizes on the ppc32 sign and fixes the merged 64-bit code to account for that. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 20 ++++++++++---------- arch/powerpc/kernel/prom_init.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 7889ff8473b9..3fcac3c37b9b 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1385,7 +1385,7 @@ _STATIC(__boot_from_prom) addi r2,r2,0x4000 /* Relocate the TOC from a virt addr to a real addr */ - sub r2,r2,r3 + add r2,r2,r3 /* Restore parameters */ mr r3,r31 @@ -1424,7 +1424,7 @@ _STATIC(__after_prom_start) li r3,0 /* target addr */ // XXX FIXME: Use phys returned by OF (r30) - sub r4,r27,r26 /* source addr */ + add r4,r27,r26 /* source addr */ /* current address of _start */ /* i.e. where we are running */ /* the source addr */ @@ -1444,7 +1444,7 @@ _STATIC(__after_prom_start) bctr 4: LOADADDR(r5,klimit) - sub r5,r5,r26 + add r5,r5,r26 ld r5,0(r5) /* get the value of klimit */ sub r5,r5,r27 bl .copy_and_flush /* copy the rest */ @@ -1703,7 +1703,7 @@ _STATIC(start_here_multiplatform) /* kernel but are still running in real mode. */ LOADADDR(r3,init_thread_union) - sub r3,r3,r26 + add r3,r3,r26 /* set up a stack pointer (physical address) */ addi r1,r3,THREAD_SIZE @@ -1714,12 +1714,12 @@ _STATIC(start_here_multiplatform) LOADADDR(r2,__toc_start) addi r2,r2,0x4000 addi r2,r2,0x4000 - sub r2,r2,r26 + add r2,r2,r26 LOADADDR(r3,cpu_specs) - sub r3,r3,r26 + add r3,r3,r26 LOADADDR(r4,cur_cpu_spec) - sub r4,r4,r26 + add r4,r4,r26 mr r5,r26 bl .identify_cpu @@ -1735,13 +1735,13 @@ _STATIC(start_here_multiplatform) * code */ LOADADDR(r27, boot_cpuid) - sub r27,r27,r26 + add r27,r27,r26 lwz r27,0(r27) LOADADDR(r24, paca) /* Get base vaddr of paca array */ mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ - sub r13,r13,r26 /* convert to physical addr */ + add r13,r13,r26 /* convert to physical addr */ mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */ /* Do very early kernel initializations, including initial hash table, @@ -1781,7 +1781,7 @@ _STATIC(start_here_multiplatform) andi. r3,r3,PLATFORM_LPAR bne 98f /* branch if result is !0 */ LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ - sub r6,r6,r26 + add r6,r6,r26 ld r6,0(r6) /* get the value of _SDR1 */ mtspr SPRN_SDR1,r6 /* set the htab location */ 98: diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 75b487f107c3..75dc7f3714bd 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2019,7 +2019,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * On pSeries and BPA, copy the CPU hold code */ if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) - copy_and_flush(0, KERNELBASE - offset, 0x100, 0); + copy_and_flush(0, KERNELBASE + offset, 0x100, 0); #endif /* From bc6f8a4b199156897f6eb5b70bf5c1a4773f4e2b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:45:07 +1000 Subject: [PATCH 0346/1939] powerpc: move lparmap.c to arch/powerpc/kernel Since lparmap.s gets included in arch/powerpc/kernel/head_64.S, this avoids depending on a file in another directory. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 5 +++-- arch/powerpc/{platforms/iseries => kernel}/lparmap.c | 0 arch/ppc64/kernel/Makefile | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) rename arch/powerpc/{platforms/iseries => kernel}/lparmap.c (100%) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 0625470a6235..bc063edd6de0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_BOOTX_TEXT) += btext.o ifeq ($(CONFIG_PPC_ISERIES),y) -arch/powerpc/kernel/head_64.o: arch/powerpc/platforms/iseries/lparmap.s -AFLAGS_head_64.o += -Iarch/powerpc/platforms/iseries +$(obj)/head_64.o: $(obj)/lparmap.s +AFLAGS_head_64.o += -I$(obj) +endif endif diff --git a/arch/powerpc/platforms/iseries/lparmap.c b/arch/powerpc/kernel/lparmap.c similarity index 100% rename from arch/powerpc/platforms/iseries/lparmap.c rename to arch/powerpc/kernel/lparmap.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 6a0fea272386..79366e4a9e5c 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -70,7 +70,7 @@ CFLAGS_ioctl32.o += -Ifs/ ifneq ($(CONFIG_PPC_MERGE),y) ifeq ($(CONFIG_PPC_ISERIES),y) -arch/ppc64/kernel/head.o: arch/powerpc/platforms/iseries/lparmap.s -AFLAGS_head.o += -Iarch/powerpc/platforms/iseries +arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s +AFLAGS_head.o += -Iarch/powerpc/kernel endif endif From 40ef8cbc6d360e564573eb19582249c35d8ba330 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:50:37 +1000 Subject: [PATCH 0347/1939] powerpc: Get 64-bit configs to compile with ARCH=powerpc This is a bunch of mostly small fixes that are needed to get ARCH=powerpc to compile for 64-bit. This adds setup_64.c from arch/ppc64/kernel/setup.c and locks.c from arch/ppc64/lib/locks.c. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 15 +- arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/btext.c | 3 +- arch/powerpc/kernel/head_64.S | 1 + arch/powerpc/kernel/ppc_ksyms.c | 103 +-- arch/powerpc/kernel/prom.c | 6 +- arch/powerpc/kernel/setup_64.c | 1324 +++++++++++++++++++++++++++++ arch/powerpc/lib/Makefile | 4 + arch/powerpc/lib/locks.c | 95 +++ arch/ppc64/Kconfig | 3 + arch/ppc64/kernel/Makefile | 64 +- arch/ppc64/kernel/asm-offsets.c | 1 + arch/ppc64/kernel/bpa_iommu.c | 2 +- arch/ppc64/kernel/bpa_setup.c | 1 + arch/ppc64/kernel/maple_setup.c | 1 + arch/ppc64/kernel/pmac_setup.c | 1 + include/asm-powerpc/hardirq.h | 3 + include/asm-powerpc/hw_irq.h | 1 - include/asm-powerpc/ppc_asm.h | 92 +- include/asm-powerpc/prom.h | 3 + include/asm-powerpc/system.h | 3 + include/asm-ppc64/pci-bridge.h | 10 + 22 files changed, 1632 insertions(+), 105 deletions(-) create mode 100644 arch/powerpc/kernel/setup_64.c create mode 100644 arch/powerpc/lib/locks.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index bc063edd6de0..47a8eb6e7e39 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,6 +10,12 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif +obj-y := semaphore.o traps.o +obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o +obj-$(CONFIG_POWER4) += idle_power4.o + +ifeq ($(CONFIG_PPC_MERGE),y) + extra-$(CONFIG_PPC_STD_MMU) := head_32.o extra-$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_4xx.o @@ -21,15 +27,12 @@ extra-$(CONFIG_PPC64) += entry_64.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds -obj-y += traps.o prom.o semaphore.o +obj-y += process.o init_task.o \ + prom.o systbl.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o -obj-$(CONFIG_PPC64) += idle_power4.o -obj-$(CONFIG_PPC64) += misc_64.o -ifeq ($(CONFIG_PPC32),y) +obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o obj-$(CONFIG_MODULES) += ppc_ksyms.o -endif -obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_BOOTX_TEXT) += btext.o ifeq ($(CONFIG_PPC_ISERIES),y) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 3a247c033e8b..ddf0c81e1958 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -111,6 +111,7 @@ int main(void) DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); + DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); /* paca */ DEFINE(PACA_SIZE, sizeof(struct paca_struct)); diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 44f5d98e27c0..bdfba92b2b38 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -50,7 +50,7 @@ static unsigned char vga_font[cmapsz]; int boot_text_mapped; int force_printk_to_btext = 0; - +#ifdef CONFIG_PPC32 /* Calc BAT values for mapping the display and store them * in disp_BAT. Those values are then used from head.S to map * the display during identify_machine() and MMU_Init() @@ -93,6 +93,7 @@ btext_prepare_BAT(void) } logicalDisplayBase = (void *) (vaddr + lowbits); } +#endif /* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3fcac3c37b9b..a4ceb9ae20fc 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -746,6 +746,7 @@ bad_stack: * any task or sent any task a signal, you should use * ret_from_except or ret_from_except_lite instead of this. */ + .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) ld r11,_NIP(r1) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 91a562e3257b..010554e5fe48 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -51,6 +51,7 @@ #include #endif +#ifdef CONFIG_PPC32 extern void transfer_to_handler(void); extern void do_IRQ(struct pt_regs *regs); extern void machine_check_exception(struct pt_regs *regs); @@ -61,14 +62,12 @@ extern int do_signal(sigset_t *, struct pt_regs *); extern int pmac_newworld; extern int sys_sigreturn(struct pt_regs *regs); -long long __ashrdi3(long long, int); -long long __ashldi3(long long, int); -long long __lshrdi3(long long, int); - -extern unsigned long mm_ptov (unsigned long paddr); - EXPORT_SYMBOL(clear_pages); -EXPORT_SYMBOL(clear_user_page); +EXPORT_SYMBOL(ISA_DMA_THRESHOLD); +EXPORT_SYMBOL(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_WRITE); +EXPORT_SYMBOL(__div64_32); + EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); @@ -77,12 +76,8 @@ EXPORT_SYMBOL(alignment_exception); EXPORT_SYMBOL(program_check_exception); EXPORT_SYMBOL(single_step_exception); EXPORT_SYMBOL(sys_sigreturn); -EXPORT_SYMBOL(ppc_n_lost_interrupts); -EXPORT_SYMBOL(ppc_lost_interrupts); +#endif -EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL(DMA_MODE_READ); -EXPORT_SYMBOL(DMA_MODE_WRITE); #if defined(CONFIG_PPC_PREP) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); @@ -110,7 +105,6 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strcasecmp); -EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); @@ -132,21 +126,21 @@ EXPORT_SYMBOL(_insw_ns); EXPORT_SYMBOL(_outsw_ns); EXPORT_SYMBOL(_insl_ns); EXPORT_SYMBOL(_outsl_ns); -EXPORT_SYMBOL(iopa); -EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(ioremap); #ifdef CONFIG_44x EXPORT_SYMBOL(ioremap64); #endif EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +#ifdef CONFIG_PPC32 EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */ +#endif -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#if defined(CONFIG_PPC32) && (defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)) EXPORT_SYMBOL(ppc_ide_md); #endif -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) && defined(CONFIG_PPC32) EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); EXPORT_SYMBOL(pci_dram_offset); @@ -168,31 +162,31 @@ EXPORT_SYMBOL(flush_dcache_all); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(giveup_fpu); -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(__flush_icache_range); -#else -EXPORT_SYMBOL(flush_icache_range); -#endif -EXPORT_SYMBOL(flush_dcache_range); -EXPORT_SYMBOL(flush_icache_user_range); -EXPORT_SYMBOL(flush_dcache_page); -EXPORT_SYMBOL(flush_tlb_kernel_range); -EXPORT_SYMBOL(flush_tlb_page); -EXPORT_SYMBOL(_tlbie); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(giveup_altivec); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE EXPORT_SYMBOL(giveup_spe); #endif /* CONFIG_SPE */ + +#ifdef CONFIG_PPC64 +EXPORT_SYMBOL(__flush_icache_range); +#else +EXPORT_SYMBOL(flush_instruction_cache); +EXPORT_SYMBOL(flush_icache_range); +EXPORT_SYMBOL(flush_tlb_kernel_range); +EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(_tlbie); +#endif +EXPORT_SYMBOL(flush_dcache_range); + #ifdef CONFIG_SMP EXPORT_SYMBOL(smp_call_function); +#ifdef CONFIG_PPC32 EXPORT_SYMBOL(smp_hw_index); #endif - -EXPORT_SYMBOL(ppc_md); +#endif #ifdef CONFIG_ADB EXPORT_SYMBOL(adb_request); @@ -205,25 +199,27 @@ EXPORT_SYMBOL(adb_try_handler_change); EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_PPC_MULTIPLATFORM +#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_PPC32) EXPORT_SYMBOL(_machine); #endif #ifdef CONFIG_PPC_PMAC EXPORT_SYMBOL(sys_ctrler); -EXPORT_SYMBOL(pmac_newworld); #endif #ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); #endif EXPORT_SYMBOL(to_tm); -EXPORT_SYMBOL(pm_power_off); - +#ifdef CONFIG_PPC32 +long long __ashrdi3(long long, int); +long long __ashldi3(long long, int); +long long __lshrdi3(long long, int); EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__lshrdi3); +#endif + EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(cacheable_memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memscan); @@ -234,17 +230,14 @@ EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(screen_info); #endif +#ifdef CONFIG_PPC32 +EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); EXPORT_SYMBOL(tb_ticks_per_jiffy); -EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); - -#ifdef CONFIG_PPC_ISERIES -EXPORT_SYMBOL(local_irq_disable); -EXPORT_SYMBOL(local_irq_enable); -EXPORT_SYMBOL(local_get_flags); +EXPORT_SYMBOL(cacheable_memcpy); #endif #ifdef CONFIG_XMON @@ -255,22 +248,6 @@ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); -#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) -extern void (*debugger)(struct pt_regs *regs); -extern int (*debugger_bpt)(struct pt_regs *regs); -extern int (*debugger_sstep)(struct pt_regs *regs); -extern int (*debugger_iabr_match)(struct pt_regs *regs); -extern int (*debugger_dabr_match)(struct pt_regs *regs); -extern void (*debugger_fault_handler)(struct pt_regs *regs); - -EXPORT_SYMBOL(debugger); -EXPORT_SYMBOL(debugger_bpt); -EXPORT_SYMBOL(debugger_sstep); -EXPORT_SYMBOL(debugger_iabr_match); -EXPORT_SYMBOL(debugger_dabr_match); -EXPORT_SYMBOL(debugger_fault_handler); -#endif - #ifdef CONFIG_8xx EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); @@ -280,22 +257,24 @@ EXPORT_SYMBOL(cpm_free_handler); EXPORT_SYMBOL(__res); #endif +#ifdef CONFIG_PPC32 EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); -EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */ EXPORT_SYMBOL(disarm_decr); -#ifdef CONFIG_PPC_STD_MMU +#endif + +#ifdef CONFIG_PPC_STD_MMU_32 extern long mol_trampoline; EXPORT_SYMBOL(mol_trampoline); /* For MOL */ EXPORT_SYMBOL(flush_hash_pages); /* For MOL */ +EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */ #ifdef CONFIG_SMP extern int mmu_hash_lock; EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ #endif /* CONFIG_SMP */ extern long *intercept_table; EXPORT_SYMBOL(intercept_table); -#endif /* CONFIG_PPC_STD_MMU */ -EXPORT_SYMBOL(cur_cpu_spec); +#endif /* CONFIG_PPC_STD_MMU_32 */ #ifdef CONFIG_PPC_PMAC extern unsigned long agp_special_page; EXPORT_SYMBOL(agp_special_page); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index dc3d24ea3bff..ce0dff1caa80 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -47,6 +47,10 @@ #include #include #include +#include +#ifdef CONFIG_PPC64 +#include +#endif #ifdef DEBUG #define DBG(fmt...) printk(KERN_ERR fmt) @@ -1072,7 +1076,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } else { /* Check if it's the boot-cpu, set it's hw index in paca now */ if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { - u32 *prop = get_flat_dt_prop(node, "reg", NULL); + prop = get_flat_dt_prop(node, "reg", NULL); set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); boot_cpuid_phys = get_hard_smp_processor_id(0); } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c new file mode 100644 index 000000000000..212b00823f82 --- /dev/null +++ b/arch/powerpc/kernel/setup_64.c @@ -0,0 +1,1324 @@ +/* + * + * Common boot and setup code. + * + * Copyright (C) 2001 PPC64 Team, 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. + */ + +#undef DEBUG + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * Here are some early debugging facilities. You can enable one + * but your kernel will not boot on anything else if you do so + */ + +/* This one is for use on LPAR machines that support an HVC console + * on vterm 0 + */ +extern void udbg_init_debug_lpar(void); +/* This one is for use on Apple G5 machines + */ +extern void udbg_init_pmac_realmode(void); +/* That's RTAS panel debug */ +extern void call_rtas_display_status_delay(unsigned char c); +/* Here's maple real mode debug */ +extern void udbg_init_maple_realmode(void); + +#define EARLY_DEBUG_INIT() do {} while(0) + +#if 0 +#define EARLY_DEBUG_INIT() udbg_init_debug_lpar() +#define EARLY_DEBUG_INIT() udbg_init_maple_realmode() +#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() +#define EARLY_DEBUG_INIT() \ + do { udbg_putc = call_rtas_display_status_delay; } while(0) +#endif + +/* extern void *stab; */ +extern unsigned long klimit; + +extern void mm_init_ppc64(void); +extern void stab_initialize(unsigned long stab); +extern void htab_initialize(void); +extern void early_init_devtree(void *flat_dt); +extern void unflatten_device_tree(void); + +extern void smp_release_cpus(void); + +int have_of = 1; +int boot_cpuid = 0; +int boot_cpuid_phys = 0; +dev_t boot_dev; +u64 ppc64_pft_size; + +struct ppc64_caches ppc64_caches; +EXPORT_SYMBOL_GPL(ppc64_caches); + +/* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; + +/* The main machine-dep calls structure + */ +struct machdep_calls ppc_md; +EXPORT_SYMBOL(ppc_md); + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned long SYSRQ_KEY; +#endif /* CONFIG_MAGIC_SYSRQ */ + + +static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); +static struct notifier_block ppc64_panic_block = { + .notifier_call = ppc64_panic_event, + .priority = INT_MIN /* may not return; must be done last */ +}; + +/* + * Perhaps we can put the pmac screen_info[] here + * on pmac as well so we don't need the ifdef's. + * Until we get multiple-console support in here + * that is. -- Cort + * Maybe tie it to serial consoles, since this is really what + * these processors use on existing boards. -- Dan + */ +struct screen_info screen_info = { + .orig_x = 0, + .orig_y = 25, + .orig_video_cols = 80, + .orig_video_lines = 25, + .orig_video_isVGA = 1, + .orig_video_points = 16 +}; + +#ifdef CONFIG_SMP + +static int smt_enabled_cmdline; + +/* Look for ibm,smt-enabled OF option */ +static void check_smt_enabled(void) +{ + struct device_node *dn; + char *smt_option; + + /* Allow the command line to overrule the OF option */ + if (smt_enabled_cmdline) + return; + + dn = of_find_node_by_path("/options"); + + if (dn) { + smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = 1; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + } +} + +/* Look for smt-enabled= cmdline option */ +static int __init early_smt_enabled(char *p) +{ + smt_enabled_cmdline = 1; + + if (!p) + return 0; + + if (!strcmp(p, "on") || !strcmp(p, "1")) + smt_enabled_at_boot = 1; + else if (!strcmp(p, "off") || !strcmp(p, "0")) + smt_enabled_at_boot = 0; + + return 0; +} +early_param("smt-enabled", early_smt_enabled); + +/** + * setup_cpu_maps - initialize the following cpu maps: + * cpu_possible_map + * cpu_present_map + * cpu_sibling_map + * + * Having the possible map set up early allows us to restrict allocations + * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. + * + * We do not initialize the online map here; cpus set their own bits in + * cpu_online_map as they come up. + * + * This function is valid only for Open Firmware systems. finish_device_tree + * must be called before using this. + * + * While we're here, we may as well set the "physical" cpu ids in the paca. + */ +static void __init setup_cpu_maps(void) +{ + struct device_node *dn = NULL; + int cpu = 0; + int swap_cpuid = 0; + + check_smt_enabled(); + + while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { + u32 *intserv; + int j, len = sizeof(u32), nthreads; + + intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", + &len); + if (!intserv) + intserv = (u32 *)get_property(dn, "reg", NULL); + + nthreads = len / sizeof(u32); + + for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { + cpu_set(cpu, cpu_present_map); + set_hard_smp_processor_id(cpu, intserv[j]); + + if (intserv[j] == boot_cpuid_phys) + swap_cpuid = cpu; + cpu_set(cpu, cpu_possible_map); + cpu++; + } + } + + /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that + * boot cpu is logical 0. + */ + if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { + u32 tmp; + tmp = get_hard_smp_processor_id(0); + set_hard_smp_processor_id(0, boot_cpuid_phys); + set_hard_smp_processor_id(swap_cpuid, tmp); + } + + /* + * On pSeries LPAR, we need to know how many cpus + * could possibly be added to this partition. + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && + (dn = of_find_node_by_path("/rtas"))) { + int num_addr_cell, num_size_cell, maxcpus; + unsigned int *ireg; + + num_addr_cell = prom_n_addr_cells(dn); + num_size_cell = prom_n_size_cells(dn); + + ireg = (unsigned int *) + get_property(dn, "ibm,lrdr-capacity", NULL); + + if (!ireg) + goto out; + + maxcpus = ireg[num_addr_cell + num_size_cell]; + + /* Double maxcpus for processors which have SMT capability */ + if (cpu_has_feature(CPU_FTR_SMT)) + maxcpus *= 2; + + if (maxcpus > NR_CPUS) { + printk(KERN_WARNING + "Partition configured for %d cpus, " + "operating system maximum is %d.\n", + maxcpus, NR_CPUS); + maxcpus = NR_CPUS; + } else + printk(KERN_INFO "Partition configured for %d cpus.\n", + maxcpus); + + for (cpu = 0; cpu < maxcpus; cpu++) + cpu_set(cpu, cpu_possible_map); + out: + of_node_put(dn); + } + + /* + * Do the sibling map; assume only two threads per processor. + */ + for_each_cpu(cpu) { + cpu_set(cpu, cpu_sibling_map[cpu]); + if (cpu_has_feature(CPU_FTR_SMT)) + cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); + } + + systemcfg->processorCount = num_present_cpus(); +} +#endif /* CONFIG_SMP */ + +extern struct machdep_calls pSeries_md; +extern struct machdep_calls pmac_md; +extern struct machdep_calls maple_md; +extern struct machdep_calls bpa_md; +extern struct machdep_calls iseries_md; + +/* Ultimately, stuff them in an elf section like initcalls... */ +static struct machdep_calls __initdata *machines[] = { +#ifdef CONFIG_PPC_PSERIES + &pSeries_md, +#endif /* CONFIG_PPC_PSERIES */ +#ifdef CONFIG_PPC_PMAC + &pmac_md, +#endif /* CONFIG_PPC_PMAC */ +#ifdef CONFIG_PPC_MAPLE + &maple_md, +#endif /* CONFIG_PPC_MAPLE */ +#ifdef CONFIG_PPC_BPA + &bpa_md, +#endif +#ifdef CONFIG_PPC_ISERIES + &iseries_md, +#endif + NULL +}; + +/* + * Early initialization entry point. This is called by head.S + * with MMU translation disabled. We rely on the "feature" of + * the CPU that ignores the top 2 bits of the address in real + * mode so we can access kernel globals normally provided we + * only toy with things in the RMO region. From here, we do + * some early parsing of the device-tree to setup out LMB + * data structures, and allocate & initialize the hash table + * and segment tables so we can start running with translation + * enabled. + * + * It is this function which will call the probe() callback of + * the various platform types and copy the matching one to the + * global ppc_md structure. Your platform can eventually do + * some very early initializations from the probe() routine, but + * this is not recommended, be very careful as, for example, the + * device-tree is not accessible via normal means at this point. + */ + +void __init early_setup(unsigned long dt_ptr) +{ + struct paca_struct *lpaca = get_paca(); + static struct machdep_calls **mach; + + /* + * Enable early debugging if any specified (see top of + * this file) + */ + EARLY_DEBUG_INIT(); + + DBG(" -> early_setup()\n"); + + /* + * Fill the default DBG level (do we want to keep + * that old mecanism around forever ?) + */ + ppcdbg_initialize(); + + /* + * Do early initializations using the flattened device + * tree, like retreiving the physical memory map or + * calculating/retreiving the hash table size + */ + early_init_devtree(__va(dt_ptr)); + + /* + * Iterate all ppc_md structures until we find the proper + * one for the current machine type + */ + DBG("Probing machine type for platform %x...\n", + systemcfg->platform); + + for (mach = machines; *mach; mach++) { + if ((*mach)->probe(systemcfg->platform)) + break; + } + /* What can we do if we didn't find ? */ + if (*mach == NULL) { + DBG("No suitable machine found !\n"); + for (;;); + } + ppc_md = **mach; + + DBG("Found, Initializing memory management...\n"); + + /* + * Initialize stab / SLB management + */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + stab_initialize(lpaca->stab_real); + + /* + * Initialize the MMU Hash table and create the linear mapping + * of memory + */ + htab_initialize(); + + DBG(" <- early_setup()\n"); +} + + +/* + * Initialize some remaining members of the ppc64_caches and systemcfg structures + * (at least until we get rid of them completely). This is mostly some + * cache informations about the CPU that will be used by cache flush + * routines and/or provided to userland + */ +static void __init initialize_cache_info(void) +{ + struct device_node *np; + unsigned long num_cpus = 0; + + DBG(" -> initialize_cache_info()\n"); + + for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { + num_cpus += 1; + + /* We're assuming *all* of the CPUs have the same + * d-cache and i-cache sizes... -Peter + */ + + if ( num_cpus == 1 ) { + u32 *sizep, *lsizep; + u32 size, lsize; + const char *dc, *ic; + + /* Then read cache informations */ + if (systemcfg->platform == PLATFORM_POWERMAC) { + dc = "d-cache-block-size"; + ic = "i-cache-block-size"; + } else { + dc = "d-cache-line-size"; + ic = "i-cache-line-size"; + } + + size = 0; + lsize = cur_cpu_spec->dcache_bsize; + sizep = (u32 *)get_property(np, "d-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *) get_property(np, dc, NULL); + if (lsizep != NULL) + lsize = *lsizep; + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find dcache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->dcache_size = ppc64_caches.dsize = size; + systemcfg->dcache_line_size = + ppc64_caches.dline_size = lsize; + ppc64_caches.log_dline_size = __ilog2(lsize); + ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; + + size = 0; + lsize = cur_cpu_spec->icache_bsize; + sizep = (u32 *)get_property(np, "i-cache-size", NULL); + if (sizep != NULL) + size = *sizep; + lsizep = (u32 *)get_property(np, ic, NULL); + if (lsizep != NULL) + lsize = *lsizep; + if (sizep == 0 || lsizep == 0) + DBG("Argh, can't find icache properties ! " + "sizep: %p, lsizep: %p\n", sizep, lsizep); + + systemcfg->icache_size = ppc64_caches.isize = size; + systemcfg->icache_line_size = + ppc64_caches.iline_size = lsize; + ppc64_caches.log_iline_size = __ilog2(lsize); + ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; + } + } + + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + systemcfg->version.major = SYSTEMCFG_MAJOR; + systemcfg->version.minor = SYSTEMCFG_MINOR; + systemcfg->processor = mfspr(SPRN_PVR); + + DBG(" <- initialize_cache_info()\n"); +} + +static void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + u64 *prop; + + DBG(" -> check_for_initrd()\n"); + + if (of_chosen) { + prop = (u64 *)get_property(of_chosen, + "linux,initrd-start", NULL); + if (prop != NULL) { + initrd_start = (unsigned long)__va(*prop); + prop = (u64 *)get_property(of_chosen, + "linux,initrd-end", NULL); + if (prop != NULL) { + initrd_end = (unsigned long)__va(*prop); + initrd_below_start_ok = 1; + } else + initrd_start = 0; + } + } + + /* If we were passed an initrd, set the ROOT_DEV properly if the values + * look sensible. If not, clear initrd reference. + */ + if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + initrd_end > initrd_start) + ROOT_DEV = Root_RAM0; + else + initrd_start = initrd_end = 0; + + if (initrd_start) + printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); + + DBG(" <- check_for_initrd()\n"); +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* + * Do some initial setup of the system. The parameters are those which + * were passed in from the bootloader. + */ +void __init setup_system(void) +{ + DBG(" -> setup_system()\n"); + + /* + * Unflatten the device-tree passed by prom_init or kexec + */ + unflatten_device_tree(); + + /* + * Fill the ppc64_caches & systemcfg structures with informations + * retreived from the device-tree. Need to be called before + * finish_device_tree() since the later requires some of the + * informations filled up here to properly parse the interrupt + * tree. + * It also sets up the cache line sizes which allows to call + * routines like flush_icache_range (used by the hash init + * later on). + */ + initialize_cache_info(); + +#ifdef CONFIG_PPC_RTAS + /* + * Initialize RTAS if available + */ + rtas_initialize(); +#endif /* CONFIG_PPC_RTAS */ + printk("%s:%d rtas.dev=%p (@ %p)\n", __FILE__, __LINE__, rtas.dev, + &rtas.dev); + + /* + * Check if we have an initrd provided via the device-tree + */ + check_for_initrd(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + /* + * Do some platform specific early initializations, that includes + * setting up the hash table pointers. It also sets up some interrupt-mapping + * related options that will be used by finish_device_tree() + */ + ppc_md.init_early(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + /* + * "Finish" the device-tree, that is do the actual parsing of + * some of the properties like the interrupt map + */ + finish_device_tree(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + /* + * Initialize xmon + */ +#ifdef CONFIG_XMON_DEFAULT + xmon_init(1); +#endif + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + /* + * Register early console + */ + register_early_udbg_console(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + + parse_early_param(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + +#ifdef CONFIG_SMP + /* + * iSeries has already initialized the cpu maps at this point. + */ + setup_cpu_maps(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + /* Release secondary cpus out of their spinloops at 0x60 now that + * we can map physical -> logical CPU ids + */ + smp_release_cpus(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); +#endif + + printk("Starting Linux PPC64 %s\n", system_utsname.version); + + printk("-----------------------------------------------------\n"); + printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); + printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); + printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); + printk("systemcfg = 0x%p\n", systemcfg); + printk("systemcfg->platform = 0x%x\n", systemcfg->platform); + printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); + printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); + printk("ppc64_caches.dcache_line_size = 0x%x\n", + ppc64_caches.dline_size); + printk("ppc64_caches.icache_line_size = 0x%x\n", + ppc64_caches.iline_size); + printk("htab_address = 0x%p\n", htab_address); + printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); + printk("-----------------------------------------------------\n"); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + mm_init_ppc64(); + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + DBG(" <- setup_system()\n"); +} + +/* also used by kexec */ +void machine_shutdown(void) +{ + if (ppc_md.nvram_sync) + ppc_md.nvram_sync(); +} + +void machine_restart(char *cmd) +{ + machine_shutdown(); + ppc_md.restart(cmd); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} + +void machine_power_off(void) +{ + machine_shutdown(); + ppc_md.power_off(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} +/* Used by the G5 thermal driver */ +EXPORT_SYMBOL_GPL(machine_power_off); + +void machine_halt(void) +{ + machine_shutdown(); + ppc_md.halt(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} + +static int ppc64_panic_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + ppc_md.panic((char *)ptr); /* May not return */ + return NOTIFY_DONE; +} + + +#ifdef CONFIG_SMP +DEFINE_PER_CPU(unsigned int, pvr); +#endif + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long cpu_id = (unsigned long)v - 1; + unsigned int pvr; + unsigned short maj; + unsigned short min; + + if (cpu_id == NR_CPUS) { + seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); + + if (ppc_md.get_cpuinfo != NULL) + ppc_md.get_cpuinfo(m); + + return 0; + } + + /* We only show online cpus: disable preempt (overzealous, I + * knew) to prevent cpu going down. */ + preempt_disable(); + if (!cpu_online(cpu_id)) { + preempt_enable(); + return 0; + } + +#ifdef CONFIG_SMP + pvr = per_cpu(pvr, cpu_id); +#else + pvr = mfspr(SPRN_PVR); +#endif + maj = (pvr >> 8) & 0xFF; + min = pvr & 0xFF; + + seq_printf(m, "processor\t: %lu\n", cpu_id); + seq_printf(m, "cpu\t\t: "); + + if (cur_cpu_spec->pvr_mask) + seq_printf(m, "%s", cur_cpu_spec->cpu_name); + else + seq_printf(m, "unknown (%08x)", pvr); + +#ifdef CONFIG_ALTIVEC + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + seq_printf(m, ", altivec supported"); +#endif /* CONFIG_ALTIVEC */ + + seq_printf(m, "\n"); + + /* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ + seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, + ppc_proc_freq % 1000000); + + seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); + + preempt_enable(); + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} +static void c_stop(struct seq_file *m, void *v) +{ +} +struct seq_operations cpuinfo_op = { + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +/* + * These three variables are used to save values passed to us by prom_init() + * via the device tree. The TCE variables are needed because with a memory_limit + * in force we may need to explicitly map the TCE are at the top of RAM. + */ +unsigned long memory_limit; +unsigned long tce_alloc_start; +unsigned long tce_alloc_end; + +#ifdef CONFIG_PPC_ISERIES +/* + * 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) + return 0; + + memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); + + return 0; +} +early_param("mem", early_parsemem); +#endif /* CONFIG_PPC_ISERIES */ + +#ifdef CONFIG_PPC_MULTIPLATFORM +static int __init set_preferred_console(void) +{ + struct device_node *prom_stdout = NULL; + char *name; + u32 *spd; + int offset = 0; + + DBG(" -> set_preferred_console()\n"); + + /* The user has requested a console so this is already set up. */ + if (strstr(saved_command_line, "console=")) { + DBG(" console was specified !\n"); + return -EBUSY; + } + + if (!of_chosen) { + DBG(" of_chosen is NULL !\n"); + return -ENODEV; + } + /* We are getting a weird phandle from OF ... */ + /* ... So use the full path instead */ + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) { + DBG(" no linux,stdout-path !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_path(name); + if (!prom_stdout) { + DBG(" can't find stdout package %s !\n", name); + return -ENODEV; + } + DBG("stdout is %s\n", prom_stdout->full_name); + + name = (char *)get_property(prom_stdout, "name", NULL); + if (!name) { + DBG(" stdout package has no name !\n"); + goto not_found; + } + spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); + + if (0) + ; +#ifdef CONFIG_SERIAL_8250_CONSOLE + else if (strcmp(name, "serial") == 0) { + int i; + u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); + if (i > 8) { + switch (reg[1]) { + case 0x3f8: + offset = 0; + break; + case 0x2f8: + offset = 1; + break; + case 0x898: + offset = 2; + break; + case 0x890: + offset = 3; + break; + default: + /* We dont recognise the serial port */ + goto not_found; + } + } + } +#endif /* CONFIG_SERIAL_8250_CONSOLE */ +#ifdef CONFIG_PPC_PSERIES + else if (strcmp(name, "vty") == 0) { + u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); + char *compat = (char *)get_property(prom_stdout, "compatible", NULL); + + if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { + /* Host Virtual Serial Interface */ + int offset; + switch (reg[0]) { + case 0x30000000: + offset = 0; + break; + case 0x30000001: + offset = 1; + break; + default: + goto not_found; + } + of_node_put(prom_stdout); + DBG("Found hvsi console at offset %d\n", offset); + return add_preferred_console("hvsi", offset, NULL); + } else { + /* pSeries LPAR virtual console */ + of_node_put(prom_stdout); + DBG("Found hvc console\n"); + return add_preferred_console("hvc", 0, NULL); + } + } +#endif /* CONFIG_PPC_PSERIES */ +#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE + else if (strcmp(name, "ch-a") == 0) + offset = 0; + else if (strcmp(name, "ch-b") == 0) + offset = 1; +#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ + else + goto not_found; + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); + + if (spd) { + static char __initdata opt[16]; + sprintf(opt, "%d", *spd); + return add_preferred_console("ttyS", offset, opt); + } else + return add_preferred_console("ttyS", offset, NULL); + + not_found: + DBG("No preferred console found !\n"); + of_node_put(prom_stdout); + return -ENODEV; +} +console_initcall(set_preferred_console); +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +#ifdef CONFIG_IRQSTACKS +static void __init irqstack_early_init(void) +{ + unsigned int i; + + /* + * interrupt stacks must be under 256MB, we cannot afford to take + * SLB misses on them. + */ + for_each_cpu(i) { + softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, + THREAD_SIZE, 0x10000000)); + hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, + THREAD_SIZE, 0x10000000)); + } +} +#else +#define irqstack_early_init() +#endif + +/* + * Stack space used when we detect a bad kernel stack pointer, and + * early in SMP boots before relocation is enabled. + */ +static void __init emergency_stack_init(void) +{ + unsigned long limit; + unsigned int i; + + /* + * Emergency stacks must be under 256MB, we cannot afford to take + * SLB misses on them. The ABI also requires them to be 128-byte + * aligned. + * + * Since we use these as temporary stacks during secondary CPU + * bringup, we need to get at them in real mode. This means they + * must also be within the RMO region. + */ + limit = min(0x10000000UL, lmb.rmo_size); + + for_each_cpu(i) + paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, + limit)) + PAGE_SIZE; +} + +/* + * Called from setup_arch to initialize the bitmap of available + * syscalls in the systemcfg page + */ +void __init setup_syscall_map(void) +{ + unsigned int i, count64 = 0, count32 = 0; + extern unsigned long *sys_call_table; + extern unsigned long sys_ni_syscall; + + + for (i = 0; i < __NR_syscalls; i++) { + if (sys_call_table[i*2] != sys_ni_syscall) { + count64++; + systemcfg->syscall_map_64[i >> 5] |= + 0x80000000UL >> (i & 0x1f); + } + if (sys_call_table[i*2+1] != sys_ni_syscall) { + count32++; + systemcfg->syscall_map_32[i >> 5] |= + 0x80000000UL >> (i & 0x1f); + } + } + printk(KERN_INFO "Syscall map setup, %d 32-bit and %d 64-bit syscalls\n", + count32, count64); +} + +/* + * Called into from start_kernel, after lock_kernel has been called. + * Initializes bootmem, which is unsed to manage page allocation until + * mem_init is called. + */ +void __init setup_arch(char **cmdline_p) +{ + extern void do_init_bootmem(void); + + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + ppc64_boot_msg(0x12, "Setup Arch"); + + *cmdline_p = cmd_line; + + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) + * for a possibly more accurate value. + */ + dcache_bsize = ppc64_caches.dline_size; + icache_bsize = ppc64_caches.iline_size; + + /* reboot on panic */ + panic_timeout = 180; + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + + if (ppc_md.panic) + notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); + + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = klimit; + + irqstack_early_init(); + emergency_stack_init(); + + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + stabs_alloc(); + + /* set up the bootmem stuff with available memory */ + do_init_bootmem(); + sparse_init(); + + printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); + /* initialize the syscall map in systemcfg */ + setup_syscall_map(); + + ppc_md.setup_arch(); + + /* Use the default idle loop if the platform hasn't provided one. */ + if (NULL == ppc_md.idle_loop) { + ppc_md.idle_loop = default_idle; + printk(KERN_INFO "Using default idle loop\n"); + } + + paging_init(); + ppc64_boot_msg(0x15, "Setup Done"); +} + + +/* ToDo: do something useful if ppc_md is not yet setup. */ +#define PPC64_LINUX_FUNCTION 0x0f000000 +#define PPC64_IPL_MESSAGE 0xc0000000 +#define PPC64_TERM_MESSAGE 0xb0000000 + +static void ppc64_do_msg(unsigned int src, const char *msg) +{ + if (ppc_md.progress) { + char buf[128]; + + sprintf(buf, "%08X\n", src); + ppc_md.progress(buf, 0); + snprintf(buf, 128, "%s", msg); + ppc_md.progress(buf, 0); + } +} + +/* Print a boot progress message. */ +void ppc64_boot_msg(unsigned int src, const char *msg) +{ + ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); + printk("[boot]%04x %s\n", src, msg); +} + +/* Print a termination message (print only -- does not stop the kernel) */ +void ppc64_terminate_msg(unsigned int src, const char *msg) +{ + ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); + printk("[terminate]%04x %s\n", src, msg); +} + +/* This should only be called on processor 0 during calibrate decr */ +void __init setup_default_decr(void) +{ + struct paca_struct *lpaca = get_paca(); + + lpaca->default_decr = tb_ticks_per_jiffy; + lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; +} + +#ifndef CONFIG_PPC_ISERIES +/* + * This function can be used by platforms to "find" legacy serial ports. + * It works for "serial" nodes under an "isa" node, and will try to + * respect the "ibm,aix-loc" property if any. It works with up to 8 + * ports. + */ + +#define MAX_LEGACY_SERIAL_PORTS 8 +static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; +static unsigned int old_serial_count; + +void __init generic_find_legacy_serial_ports(u64 *physport, + unsigned int *default_speed) +{ + struct device_node *np; + u32 *sizeprop; + + struct isa_reg_property { + u32 space; + u32 address; + u32 size; + }; + struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; + }; + + DBG(" -> generic_find_legacy_serial_port()\n"); + + *physport = 0; + if (default_speed) + *default_speed = 0; + + np = of_find_node_by_path("/"); + if (!np) + return; + + /* First fill our array */ + for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { + struct device_node *isa, *pci; + struct isa_reg_property *reg; + unsigned long phys_size, addr_size, io_base; + u32 *rangesp; + u32 *interrupts, *clk, *spd; + char *typep; + int index, rlen, rentsize; + + /* Ok, first check if it's under an "isa" parent */ + isa = of_get_parent(np); + if (!isa || strcmp(isa->name, "isa")) { + DBG("%s: no isa parent found\n", np->full_name); + continue; + } + + /* Now look for an "ibm,aix-loc" property that gives us ordering + * if any... + */ + typep = (char *)get_property(np, "ibm,aix-loc", NULL); + + /* Get the ISA port number */ + reg = (struct isa_reg_property *)get_property(np, "reg", NULL); + if (reg == NULL) + goto next_port; + /* We assume the interrupt number isn't translated ... */ + interrupts = (u32 *)get_property(np, "interrupts", NULL); + /* get clock freq. if present */ + clk = (u32 *)get_property(np, "clock-frequency", NULL); + /* get default speed if present */ + spd = (u32 *)get_property(np, "current-speed", NULL); + /* Default to locate at end of array */ + index = old_serial_count; /* end of the array by default */ + + /* If we have a location index, then use it */ + if (typep && *typep == 'S') { + index = simple_strtol(typep+1, NULL, 0) - 1; + /* if index is out of range, use end of array instead */ + if (index >= MAX_LEGACY_SERIAL_PORTS) + index = old_serial_count; + /* if our index is still out of range, that mean that + * array is full, we could scan for a free slot but that + * make little sense to bother, just skip the port + */ + if (index >= MAX_LEGACY_SERIAL_PORTS) + goto next_port; + if (index >= old_serial_count) + old_serial_count = index + 1; + /* Check if there is a port who already claimed our slot */ + if (serial_ports[index].iobase != 0) { + /* if we still have some room, move it, else override */ + if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { + DBG("Moved legacy port %d -> %d\n", index, + old_serial_count); + serial_ports[old_serial_count++] = + serial_ports[index]; + } else { + DBG("Replacing legacy port %d\n", index); + } + } + } + if (index >= MAX_LEGACY_SERIAL_PORTS) + goto next_port; + if (index >= old_serial_count) + old_serial_count = index + 1; + + /* Now fill the entry */ + memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); + serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; + serial_ports[index].iobase = reg->address; + serial_ports[index].irq = interrupts ? interrupts[0] : 0; + serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; + + DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", + index, + serial_ports[index].iobase, + serial_ports[index].irq, + serial_ports[index].uartclk); + + /* Get phys address of IO reg for port 1 */ + if (index != 0) + goto next_port; + + pci = of_get_parent(isa); + if (!pci) { + DBG("%s: no pci parent found\n", np->full_name); + goto next_port; + } + + rangesp = (u32 *)get_property(pci, "ranges", &rlen); + if (rangesp == NULL) { + of_node_put(pci); + goto next_port; + } + rlen /= 4; + + /* we need the #size-cells of the PCI bridge node itself */ + phys_size = 1; + sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); + if (sizeprop != NULL) + phys_size = *sizeprop; + /* we need the parent #addr-cells */ + addr_size = prom_n_addr_cells(pci); + rentsize = 3 + addr_size + phys_size; + io_base = 0; + for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { + if (((rangesp[0] >> 24) & 0x3) != 1) + continue; /* not IO space */ + io_base = rangesp[3]; + if (addr_size == 2) + io_base = (io_base << 32) | rangesp[4]; + } + if (io_base != 0) { + *physport = io_base + reg->address; + if (default_speed && spd) + *default_speed = *spd; + } + of_node_put(pci); + next_port: + of_node_put(isa); + } + + DBG(" <- generic_find_legacy_serial_port()\n"); +} + +static struct platform_device serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_ports, + }, +}; + +static int __init serial_dev_init(void) +{ + return platform_device_register(&serial_device); +} +arch_initcall(serial_dev_init); + +#endif /* CONFIG_PPC_ISERIES */ + +int check_legacy_ioport(unsigned long base_port) +{ + if (ppc_md.check_legacy_ioport == NULL) + return 0; + return ppc_md.check_legacy_ioport(base_port); +} +EXPORT_SYMBOL(check_legacy_ioport); + +#ifdef CONFIG_XMON +static int __init early_xmon(char *p) +{ + /* ensure xmon is enabled */ + if (p) { + if (strncmp(p, "on", 2) == 0) + xmon_init(1); + if (strncmp(p, "off", 3) == 0) + xmon_init(0); + if (strncmp(p, "early", 5) != 0) + return 0; + } + xmon_init(1); + debugger(NULL); + + return 0; +} +early_param("xmon", early_xmon); +#endif + +void cpu_die(void) +{ + if (ppc_md.cpu_die) + ppc_md.cpu_die(); +} diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index a8cedb96de5f..30367a0237dd 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,3 +7,7 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o memcpy_64.o \ usercopy_64.o sstep.o checksum_64.o mem_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o +ifeq ($(CONFIG_PPC64),y) +obj-$(CONFIG_SMP) += locks.o +endif + diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c new file mode 100644 index 000000000000..4b8c5ad5e7dc --- /dev/null +++ b/arch/powerpc/lib/locks.c @@ -0,0 +1,95 @@ +/* + * Spin and read/write lock operations. + * + * Copyright (C) 2001-2004 Paul Mackerras , IBM + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2002 Dave Engebretsen , IBM + * Rework to support virtual processors + * + * 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 + +/* waiting for a spinlock... */ +#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +#include +#include + +void __spin_yield(raw_spinlock_t *lock) +{ + unsigned int lock_value, holder_cpu, yield_count; + struct paca_struct *holder_paca; + + lock_value = lock->slock; + if (lock_value == 0) + return; + holder_cpu = lock_value & 0xffff; + BUG_ON(holder_cpu >= NR_CPUS); + holder_paca = &paca[holder_cpu]; + yield_count = holder_paca->lppaca.yield_count; + if ((yield_count & 1) == 0) + return; /* virtual cpu is currently running */ + rmb(); + if (lock->slock != lock_value) + return; /* something has changed */ +#ifdef CONFIG_PPC_ISERIES + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#else + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); +#endif +} + +/* + * Waiting for a read lock or a write lock on a rwlock... + * This turns out to be the same for read and write locks, since + * we only know the holder if it is write-locked. + */ +void __rw_yield(raw_rwlock_t *rw) +{ + int lock_value; + unsigned int holder_cpu, yield_count; + struct paca_struct *holder_paca; + + lock_value = rw->lock; + if (lock_value >= 0) + return; /* no write lock at present */ + holder_cpu = lock_value & 0xffff; + BUG_ON(holder_cpu >= NR_CPUS); + holder_paca = &paca[holder_cpu]; + yield_count = holder_paca->lppaca.yield_count; + if ((yield_count & 1) == 0) + return; /* virtual cpu is currently running */ + rmb(); + if (rw->lock != lock_value) + return; /* something has changed */ +#ifdef CONFIG_PPC_ISERIES + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#else + plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), + yield_count); +#endif +} +#endif + +void __raw_spin_unlock_wait(raw_spinlock_t *lock) +{ + while (lock->slock) { + HMT_low(); + if (SHARED_PROCESSOR) + __spin_yield(lock); + } + HMT_medium(); +} + +EXPORT_SYMBOL(__raw_spin_unlock_wait); diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 246212115a48..e656e02d9dd1 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -186,6 +186,9 @@ config BOOTX_TEXT Say Y here to see progress messages from the boot firmware in text mode. Requires an Open Firmware compatible video card. +config POWER4 + def_bool y + config POWER4_ONLY bool "Optimize for POWER4" default n diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 79366e4a9e5c..5c598892f891 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -2,14 +2,14 @@ # Makefile for the linux ppc64 kernel. # -EXTRA_CFLAGS += -mno-minimal-toc ifneq ($(CONFIG_PPC_MERGE),y) + +EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds -endif obj-y := setup.o entry.o irq.o idle.o dma.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ - align.o semaphore.o bitops.o pacaData.o \ + align.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o init_task.o \ cputable.o cpu_setup_power4.o \ @@ -43,7 +43,6 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_HVCS) += hvcserver.o -vio-obj-$(CONFIG_PPC_PSERIES) += pSeries_vio.o obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y) obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_MPIC) += mpic.o @@ -59,8 +58,6 @@ obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o -obj-$(CONFIG_PPC_PSERIES) += pSeries_smp.o -obj-$(CONFIG_PPC_BPA) += pSeries_smp.o obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o endif @@ -68,9 +65,62 @@ obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ -ifneq ($(CONFIG_PPC_MERGE),y) ifeq ($(CONFIG_PPC_ISERIES),y) arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s AFLAGS_head.o += -Iarch/powerpc/kernel endif + +else + +# Things still needed from here by the merged ppc code + +obj-y := irq.o idle.o dma.o \ + time.o signal.o syscalls.o ptrace.o \ + align.o bitops.o pacaData.o \ + udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ + ptrace32.o signal32.o rtc.o \ + cputable.o cpu_setup_power4.o \ + iommu.o sysfs.o vdso.o pmc.o firmware.o +obj-y += vdso32/ vdso64/ + +pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o + +obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) + +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o + +obj-$(CONFIG_PPC_PSERIES) += rtasd.o ras.o udbg_16550.o + +obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ + bpa_iic.o spider-pic.o + +obj-$(CONFIG_KEXEC) += machine_kexec.o +obj-$(CONFIG_EEH) += eeh.o +obj-$(CONFIG_PROC_FS) += proc_ppc64.o +obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o +obj-$(CONFIG_RTAS_PROC) += rtas-proc.o +obj-$(CONFIG_SCANLOG) += scanlog.o +obj-$(CONFIG_LPARCFG) += lparcfg.o +obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o +obj-$(CONFIG_HVCS) += hvcserver.o + +obj-$(CONFIG_IBMVIO) += vio.o +obj-$(CONFIG_XICS) += xics.o + +obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ + udbg_16550.o + +obj-$(CONFIG_U3_DART) += u3_iommu.o + +ifdef CONFIG_SMP +obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o +endif + +obj-$(CONFIG_KPROBES) += kprobes.o + +CFLAGS_ioctl32.o += -Ifs/ + endif diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 1ff4fa05a973..1378fbbe1e57 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -77,6 +77,7 @@ int main(void) DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); + DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); /* paca */ DEFINE(PACA_SIZE, sizeof(struct paca_struct)); diff --git a/arch/ppc64/kernel/bpa_iommu.c b/arch/ppc64/kernel/bpa_iommu.c index 0cc463f24539..45ebe5486c40 100644 --- a/arch/ppc64/kernel/bpa_iommu.c +++ b/arch/ppc64/kernel/bpa_iommu.c @@ -99,7 +99,7 @@ get_iost_entry(unsigned long iopt_base, unsigned long io_address, unsigned page_ break; default: /* not a known compile time constant */ - BUILD_BUG_ON(1); + BUG_ON(1); break; } diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c index 9f915f4222b1..017cf23e91fa 100644 --- a/arch/ppc64/kernel/bpa_setup.c +++ b/arch/ppc64/kernel/bpa_setup.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "bpa_iic.h" #include "bpa_iommu.h" diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index 2a7fae01eee1..22987675f544 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c @@ -60,6 +60,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 497c3cd95bc3..be4c1693d149 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "pmac.h" diff --git a/include/asm-powerpc/hardirq.h b/include/asm-powerpc/hardirq.h index 2c0a31b1008d..3b3e3b49ec12 100644 --- a/include/asm-powerpc/hardirq.h +++ b/include/asm-powerpc/hardirq.h @@ -1,6 +1,9 @@ #ifndef _ASM_POWERPC_HARDIRQ_H #define _ASM_POWERPC_HARDIRQ_H +#include +#include + /* The __last_jiffy_stamp field is needed to ensure that no decrementer * interrupt is lost on SMP machines. Since on most CPUs it is in the same * cache line as local_irq_count, it is cheap to access and is also used on UP diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h index 605a65e42063..c37b31b96337 100644 --- a/include/asm-powerpc/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h @@ -10,7 +10,6 @@ #include #include #include -#include extern void timer_interrupt(struct pt_regs *); extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 6cd52c130332..e4350e406d2a 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -1,10 +1,12 @@ /* * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. */ - #ifndef _ASM_POWERPC_PPC_ASM_H #define _ASM_POWERPC_PPC_ASM_H +#include +#include + #ifdef __ASSEMBLY__ /* @@ -87,6 +89,66 @@ #define RFDI .long 0x4c00004e /* rfdi instruction */ #define RFMCI .long 0x4c00004c /* rfmci instruction */ +#ifdef CONFIG_PPC64 + +#define XGLUE(a,b) a##b +#define GLUE(a,b) XGLUE(a,b) + +#define _GLOBAL(name) \ + .section ".text"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _KPROBE(name) \ + .section ".kprobes.text","a"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _STATIC(name) \ + .section ".text"; \ + .align 2 ; \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#else /* 32-bit */ + +#define _GLOBAL(n) \ + .text; \ + .stabs __stringify(n:F-1),N_FUN,0,0,n;\ + .globl n; \ +n: + +#define _KPROBE(n) \ + .section ".kprobes.text","a"; \ + .globl n; \ +n: + +#endif + /* * LOADADDR( rn, name ) * loads the address of 'name' into 'rn' @@ -251,31 +313,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) .previous #endif -/* - * On 64-bit cpus, we use the rfid instruction instead of rfi, but - * we then have to make sure we preserve the top 32 bits except for - * the 64-bit mode bit, which we clear. - */ -#if defined(CONFIG_PPC64BRIDGE) -#define FIX_SRR1(ra, rb) \ - mr rb,ra; \ - mfmsr ra; \ - clrldi ra,ra,1; /* turn off 64-bit mode */ \ - rldimi ra,rb,0,32 -#define RFI .long 0x4c000024 /* rfid instruction */ -#define MTMSRD(r) .long (0x7c000164 + ((r) << 21)) /* mtmsrd */ -#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ -#elif defined(CONFIG_PPC64) -/* Insert the high 32 bits of the MSR into what will be the new - MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF - bits. */ - -#define FIX_SRR1(ra, rb) \ - mr rb,ra; \ - mfmsr ra; \ - rldimi ra,rb,0,32 - -#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ +#ifdef CONFIG_PPC64 +#define RFI rfid +#define MTMSRD(r) mtmsrd r #else #define FIX_SRR1(ra, rb) diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 194b56ee1693..efc40980cb48 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -196,6 +196,7 @@ extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); extern void prom_add_property(struct device_node* np, struct property* prop); +#ifdef CONFIG_PPC32 /* * PCI <-> OF matching functions * (XXX should these be here?) @@ -207,6 +208,8 @@ extern int pci_device_from_OF_node(struct device_node *node, extern struct device_node* pci_busdev_to_OF_node(struct pci_bus *, int); extern struct device_node* pci_device_to_OF_node(struct pci_dev *); extern void pci_create_OF_bus_map(void); +#endif + extern struct resource *request_OF_resource(struct device_node* node, int index, const char* name_postfix); extern int release_OF_resource(struct device_node* node, int index); diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 66866f7301a9..6463453b61a3 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -9,6 +9,7 @@ #include #include +#include /* * Memory barrier. @@ -127,6 +128,7 @@ extern void flush_fp_to_thread(struct task_struct *); extern void enable_kernel_altivec(void); extern void giveup_altivec(struct task_struct *); extern void load_up_altivec(struct task_struct *); +extern int emulate_altivec(struct pt_regs *); extern void giveup_spe(struct task_struct *); extern void load_up_spe(struct task_struct *); extern int fix_alignment(struct pt_regs *); @@ -176,6 +178,7 @@ extern struct task_struct *_switch(struct thread_struct *prev, struct thread_struct *next); extern unsigned int rtas_data; +extern int mem_init_done; /* set on boot once kmalloc can be called */ /* * Atomic exchange diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 8ca5fce626bb..c342c9eb07a4 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -106,6 +106,16 @@ static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev) return fetch_dev_dn(dev); } +static inline int pci_device_from_OF_node(struct device_node *np, + u8 *bus, u8 *devfn) +{ + if (!PCI_DN(np)) + return -ENODEV; + *bus = PCI_DN(np)->busno; + *devfn = PCI_DN(np)->devfn; + return 0; +} + static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus) { if (bus->self) From 76f9f87fa51c9fb62c17986e2066ed467ac2da05 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:52:26 +1000 Subject: [PATCH 0348/1939] powerpc: Get iseries to compile with ARCH=powerpc This moves the Device_List member from struct device_node to struct pci_dn, which cleans up the device_node and makes the code a little simpler. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/hvcall.S | 1 + arch/powerpc/platforms/iseries/iommu.c | 7 +++---- arch/powerpc/platforms/iseries/pci.c | 15 ++++++--------- include/asm-ppc64/pci-bridge.h | 2 ++ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S index 9901c0ec1415..07ae6ad5f49f 100644 --- a/arch/powerpc/platforms/iseries/hvcall.S +++ b/arch/powerpc/platforms/iseries/hvcall.S @@ -10,6 +10,7 @@ #include #include +#include /* XXX for STACK_FRAME_OVERHEAD */ .text diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 9ac735d5b817..e40c50b7cefc 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -89,11 +89,10 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) */ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) { - struct device_node *dp; - - list_for_each_entry(dp, &iSeries_Global_Device_List, Device_List) { - struct iommu_table *it = PCI_DN(dp)->iommu_table; + struct pci_dn *pdn; + list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { + struct iommu_table *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 70185dec940b..46879d7de925 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -220,7 +220,7 @@ static struct device_node *build_device_node(HvBusNumber Bus, return NULL; } node->data = pdn; - list_add_tail(&node->Device_List, &iSeries_Global_Device_List); + list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List); #if 0 pdn->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); #endif @@ -549,15 +549,12 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio); */ static struct device_node *find_Device_Node(int bus, int devfn) { - struct list_head *pos; + struct pci_dn *pdn; - list_for_each(pos, &iSeries_Global_Device_List) { - struct device_node *node = - list_entry(pos, struct device_node, Device_List); - - if ((bus == ISERIES_BUS(node)) && - (devfn == PCI_DN(node)->devfn)) - return node; + list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { + if ((bus == pdn->DsaAddr.Dsa.busNumber) && + (devfn == pdn->devfn)) + return pdn->node; } return NULL; } diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index c342c9eb07a4..56863df18232 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -3,6 +3,7 @@ #define _ASM_PCI_BRIDGE_H #include +#include #include @@ -74,6 +75,7 @@ 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; union HvDsaMap DsaAddr; /* Direct Select Address */ /* busNumber, subBusNumber, */ /* deviceId, barNumber */ From 1b92313d5ba993bb6e38a6205ccc64a7595cd0a6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:54:57 +1000 Subject: [PATCH 0349/1939] powerpc: Merge asm/irq.h Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/irq.h | 160 ++++++++++++++++++------- include/asm-ppc64/irq.h | 120 ------------------- 2 files changed, 118 insertions(+), 162 deletions(-) rename include/{asm-ppc => asm-powerpc}/irq.h (84%) delete mode 100644 include/asm-ppc64/irq.h diff --git a/include/asm-ppc/irq.h b/include/asm-powerpc/irq.h similarity index 84% rename from include/asm-ppc/irq.h rename to include/asm-powerpc/irq.h index 137ea0cf34d3..980393a16be2 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-powerpc/irq.h @@ -1,11 +1,23 @@ #ifdef __KERNEL__ -#ifndef _ASM_IRQ_H -#define _ASM_IRQ_H +#ifndef _ASM_POWERPC_IRQ_H +#define _ASM_POWERPC_IRQ_H + +/* + * 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 /* ppc_md */ +#include + +#include #include +/* this number is used when no interrupt has been assigned */ +#define NO_IRQ (-1) + /* * These constants are used for passing information about interrupt * signal polarity and level/edge sensing to the low-level PIC chip @@ -30,6 +42,44 @@ #define for_each_irq(i) \ for ((i) = 0; (i) < NR_IRQS; ++(i)) +#ifdef CONFIG_PPC64 + +/* + * Maximum number of interrupt sources that we can handle. + */ +#define NR_IRQS 512 + +/* Interrupt numbers are virtual in case they are sparsely + * distributed by the hardware. + */ +extern unsigned int virt_irq_to_real_map[NR_IRQS]; + +/* Create a mapping for a real_irq if it doesn't already exist. + * Return the virtual irq as a convenience. + */ +int virt_irq_create_mapping(unsigned int real_irq); +void virt_irq_init(void); + +static inline unsigned int virt_irq_to_real(unsigned int virt_irq) +{ + return virt_irq_to_real_map[virt_irq]; +} + +extern unsigned int real_irq_to_virt_slowpath(unsigned int real_irq); + +/* + * List of interrupt controllers. + */ +#define IC_INVALID 0 +#define IC_OPEN_PIC 1 +#define IC_PPC_XIC 2 +#define IC_BPA_IIC 3 +#define IC_ISERIES 4 + +extern u64 ppc64_interrupt_controller; + +#else /* 32-bit */ + #if defined(CONFIG_40x) #include @@ -72,11 +122,6 @@ #define NR_UIC_IRQS UIC_WIDTH #define NR_IRQS ((NR_UIC_IRQS * NR_UICS) + NR_BOARD_IRQS) #endif -static __inline__ int -irq_canonicalize(int irq) -{ - return (irq); -} #elif defined(CONFIG_44x) #include @@ -84,12 +129,6 @@ irq_canonicalize(int irq) #define NR_UIC_IRQS 32 #define NR_IRQS ((NR_UIC_IRQS * NR_UICS) + NR_BOARD_IRQS) -static __inline__ int -irq_canonicalize(int irq) -{ - return (irq); -} - #elif defined(CONFIG_8xx) /* Now include the board configuration specific associations. @@ -176,20 +215,9 @@ irq_canonicalize(int irq) */ #define mk_int_int_mask(IL) (1 << (7 - (IL/2))) -/* always the same on 8xx -- Cort */ -static __inline__ int irq_canonicalize(int irq) -{ - return irq; -} - #elif defined(CONFIG_83xx) #include -static __inline__ int irq_canonicalize(int irq) -{ - return irq; -} - #define NR_IRQS (NR_IPIC_INTS) #elif defined(CONFIG_85xx) @@ -313,17 +341,13 @@ static __inline__ int irq_canonicalize(int irq) #define SIU_INT_PC1 ((uint)0x3e+CPM_IRQ_OFFSET) #define SIU_INT_PC0 ((uint)0x3f+CPM_IRQ_OFFSET) -static __inline__ int irq_canonicalize(int irq) -{ - return irq; -} - #else /* CONFIG_40x + CONFIG_8xx */ /* * this is the # irq's for all ppc arch's (pmac/chrp/prep) * so it is the max of them all */ #define NR_IRQS 256 +#define __DO_IRQ_CANON 1 #ifndef CONFIG_8260 @@ -400,18 +424,6 @@ static __inline__ int irq_canonicalize(int irq) #endif /* CONFIG_8260 */ -/* - * This gets called from serial.c, which is now used on - * powermacs as well as prep/chrp boxes. - * Prep and chrp both have cascaded 8259 PICs. - */ -static __inline__ int irq_canonicalize(int irq) -{ - if (ppc_md.irq_canonicalize) - return ppc_md.irq_canonicalize(irq); - return irq; -} - #endif #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) @@ -420,5 +432,69 @@ extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; extern atomic_t ppc_n_lost_interrupts; +#endif + +/* + * Because many systems have two overlapping names spaces for + * interrupts (ISA and XICS for example), and the ISA interrupts + * have historically not been easy to renumber, we allow ISA + * interrupts to take values 0 - 15, and shift up the remaining + * interrupts by 0x10. + */ +#define NUM_ISA_INTERRUPTS 0x10 +extern int __irq_offset_value; + +static inline int irq_offset_up(int irq) +{ + return(irq + __irq_offset_value); +} + +static inline int irq_offset_down(int irq) +{ + return(irq - __irq_offset_value); +} + +static inline int irq_offset_value(void) +{ + return __irq_offset_value; +} + +#ifdef __DO_IRQ_CANON +extern int ppc_do_canonicalize_irqs; +#else +#define ppc_do_canonicalize_irqs 0 +#endif + +static __inline__ int irq_canonicalize(int irq) +{ + if (ppc_do_canonicalize_irqs && irq == 2) + irq = 9; + return irq; +} + +extern int distribute_irqs; + +struct irqaction; +struct pt_regs; + +#ifdef CONFIG_IRQSTACKS +/* + * Per-cpu stacks for handling hard and soft interrupts. + */ +extern struct thread_info *hardirq_ctx[NR_CPUS]; +extern struct thread_info *softirq_ctx[NR_CPUS]; + +extern void irq_ctx_init(void); +extern void call_do_softirq(struct thread_info *tp); +extern int call_handle_IRQ_event(int irq, struct pt_regs *regs, + struct irqaction *action, struct thread_info *tp); + +#define __ARCH_HAS_DO_SOFTIRQ + +#else +#define irq_ctx_init() + +#endif /* CONFIG_IRQSTACKS */ + #endif /* _ASM_IRQ_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc64/irq.h b/include/asm-ppc64/irq.h deleted file mode 100644 index 99782afb4cde..000000000000 --- a/include/asm-ppc64/irq.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _ASM_IRQ_H -#define _ASM_IRQ_H - -/* - * 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 - -/* - * Maximum number of interrupt sources that we can handle. - */ -#define NR_IRQS 512 - -/* this number is used when no interrupt has been assigned */ -#define NO_IRQ (-1) - -/* - * These constants are used for passing information about interrupt - * signal polarity and level/edge sensing to the low-level PIC chip - * drivers. - */ -#define IRQ_SENSE_MASK 0x1 -#define IRQ_SENSE_LEVEL 0x1 /* interrupt on active level */ -#define IRQ_SENSE_EDGE 0x0 /* interrupt triggered by edge */ - -#define IRQ_POLARITY_MASK 0x2 -#define IRQ_POLARITY_POSITIVE 0x2 /* high level or low->high edge */ -#define IRQ_POLARITY_NEGATIVE 0x0 /* low level or high->low edge */ - -/* - * IRQ line status macro IRQ_PER_CPU is used - */ -#define ARCH_HAS_IRQ_PER_CPU - -#define get_irq_desc(irq) (&irq_desc[(irq)]) - -/* Define a way to iterate across irqs. */ -#define for_each_irq(i) \ - for ((i) = 0; (i) < NR_IRQS; ++(i)) - -/* Interrupt numbers are virtual in case they are sparsely - * distributed by the hardware. - */ -extern unsigned int virt_irq_to_real_map[NR_IRQS]; - -/* Create a mapping for a real_irq if it doesn't already exist. - * Return the virtual irq as a convenience. - */ -int virt_irq_create_mapping(unsigned int real_irq); -void virt_irq_init(void); - -static inline unsigned int virt_irq_to_real(unsigned int virt_irq) -{ - return virt_irq_to_real_map[virt_irq]; -} - -extern unsigned int real_irq_to_virt_slowpath(unsigned int real_irq); - -/* - * Because many systems have two overlapping names spaces for - * interrupts (ISA and XICS for example), and the ISA interrupts - * have historically not been easy to renumber, we allow ISA - * interrupts to take values 0 - 15, and shift up the remaining - * interrupts by 0x10. - */ -#define NUM_ISA_INTERRUPTS 0x10 -extern int __irq_offset_value; - -static inline int irq_offset_up(int irq) -{ - return(irq + __irq_offset_value); -} - -static inline int irq_offset_down(int irq) -{ - return(irq - __irq_offset_value); -} - -static inline int irq_offset_value(void) -{ - return __irq_offset_value; -} - -static __inline__ int irq_canonicalize(int irq) -{ - return irq; -} - -extern int distribute_irqs; - -struct irqaction; -struct pt_regs; - -#ifdef CONFIG_IRQSTACKS -/* - * Per-cpu stacks for handling hard and soft interrupts. - */ -extern struct thread_info *hardirq_ctx[NR_CPUS]; -extern struct thread_info *softirq_ctx[NR_CPUS]; - -extern void irq_ctx_init(void); -extern void call_do_softirq(struct thread_info *tp); -extern int call_handle_IRQ_event(int irq, struct pt_regs *regs, - struct irqaction *action, struct thread_info *tp); - -#define __ARCH_HAS_DO_SOFTIRQ - -#else -#define irq_ctx_init() - -#endif /* CONFIG_IRQSTACKS */ - -#endif /* _ASM_IRQ_H */ -#endif /* __KERNEL__ */ From eef289f79c03ba5ca197e2ac1e33906175f01c39 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:56:11 +1000 Subject: [PATCH 0350/1939] powerpc: Merge asm/unistd.h Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/unistd.h | 91 ++-- include/asm-ppc64/unistd.h | 487 ---------------------- 2 files changed, 54 insertions(+), 524 deletions(-) rename include/{asm-ppc => asm-powerpc}/unistd.h (90%) delete mode 100644 include/asm-ppc64/unistd.h diff --git a/include/asm-ppc/unistd.h b/include/asm-powerpc/unistd.h similarity index 90% rename from include/asm-ppc/unistd.h rename to include/asm-powerpc/unistd.h index 3173ab3d2eb9..c2d039e338a8 100644 --- a/include/asm-ppc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -3,7 +3,13 @@ /* * This file contains the system call numbers. + * + * 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. */ + #define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 @@ -196,19 +202,23 @@ #define __NR_vfork 189 #define __NR_ugetrlimit 190 /* SuS compliant getrlimit */ #define __NR_readahead 191 +#ifndef __powerpc64__ /* these are 32-bit only */ #define __NR_mmap2 192 #define __NR_truncate64 193 #define __NR_ftruncate64 194 #define __NR_stat64 195 #define __NR_lstat64 196 #define __NR_fstat64 197 +#endif #define __NR_pciconfig_read 198 #define __NR_pciconfig_write 199 #define __NR_pciconfig_iobase 200 #define __NR_multiplexer 201 #define __NR_getdents64 202 #define __NR_pivot_root 203 +#ifndef __powerpc64__ #define __NR_fcntl64 204 +#endif #define __NR_madvise 205 #define __NR_mincore 206 #define __NR_gettid 207 @@ -230,7 +240,9 @@ #define __NR_sched_getaffinity 223 /* 224 currently unused */ #define __NR_tuxcall 225 +#ifndef __powerpc64__ #define __NR_sendfile64 226 +#endif #define __NR_io_setup 227 #define __NR_io_destroy 228 #define __NR_io_getevents 229 @@ -258,14 +270,16 @@ #define __NR_utimes 251 #define __NR_statfs64 252 #define __NR_fstatfs64 253 +#ifndef __powerpc64__ #define __NR_fadvise64_64 254 +#endif #define __NR_rtas 255 #define __NR_sys_debug_setcontext 256 /* Number 257 is reserved for vserver */ /* 258 currently unused */ -/* Number 259 is reserved for new sys_mbind */ -/* Number 260 is reserved for new sys_get_mempolicy */ -/* Number 261 is reserved for new sys_set_mempolicy */ +#define __NR_mbind 259 +#define __NR_get_mempolicy 260 +#define __NR_set_mempolicy 261 #define __NR_mq_open 262 #define __NR_mq_unlink 263 #define __NR_mq_timedsend 264 @@ -285,7 +299,12 @@ #define __NR_syscalls 278 -#define __NR(n) #n +#ifdef __KERNEL__ +#define __NR__exit __NR_exit +#define NR_syscalls __NR_syscalls +#endif + +#ifndef __ASSEMBLY__ /* On powerpc a system call basically clobbers the same registers like a * function call, with the exception of LR (which is needed for the @@ -389,7 +408,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ { \ __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \ } - #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ { \ @@ -398,12 +416,13 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #ifdef __KERNEL__ -#define __NR__exit __NR_exit -#define NR_syscalls __NR_syscalls +#include +#include +#include +#include #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR -#define __ARCH_WANT_OLD_STAT #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM #define __ARCH_WANT_SYS_GETHOSTNAME @@ -423,23 +442,17 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION - -/* - * Forking from kernel space will result in the child getting a new, - * empty kernel stack area. Thus the child cannot access automatic - * variables set in the parent unless they are in registers, and the - * procedure where the fork was done cannot return to its caller in - * the child. - */ - -#ifdef __KERNEL_SYSCALLS__ - -#include -#include +#ifdef CONFIG_PPC32 +#define __ARCH_WANT_OLD_STAT +#endif +#ifdef CONFIG_PPC64 +#define __ARCH_WANT_COMPAT_SYS_TIME +#endif /* * System call prototypes. */ +#ifdef __KERNEL_SYSCALLS__ extern pid_t setsid(void); extern int write(int fd, const char *buf, off_t count); extern int read(int fd, char *buf, off_t count); @@ -449,10 +462,13 @@ extern int execve(const char *file, char **argv, char **envp); extern int open(const char *file, int flag, int mode); extern int close(int fd); extern pid_t waitpid(pid_t pid, int *wait_stat, int options); +#endif /* __KERNEL_SYSCALLS__ */ -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset); +/* + * Functions that implement syscalls. + */ +unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot, + unsigned long flags, unsigned long fd, off_t offset); unsigned long sys_mmap2(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); @@ -461,22 +477,19 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs *regs); int sys_clone(unsigned long clone_flags, unsigned long usp, - int __user *parent_tidp, void __user *child_threadptr, - int __user *child_tidp, int p6, - struct pt_regs *regs); -int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, + int __user *parent_tidp, void __user *child_threadptr, + int __user *child_tidp, int p6, struct pt_regs *regs); +int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, struct pt_regs *regs); -int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, +int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, struct pt_regs *regs); int sys_pipe(int __user *fildes); int sys_ptrace(long request, long pid, long addr, long data); struct sigaction; -long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ +long sys_rt_sigaction(int sig, const struct sigaction __user *act, + struct sigaction __user *oact, size_t sigsetsize); /* * "Conditional" syscalls @@ -484,10 +497,14 @@ long sys_rt_sigaction(int sig, * What we want is __attribute__((weak,alias("sys_ni_syscall"))), * but it doesn't work on all toolchains, so we just do it by hand */ -#ifndef cond_syscall +#ifdef CONFIG_PPC32 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#else +#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall") #endif -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ #endif /* _ASM_PPC_UNISTD_H_ */ diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h deleted file mode 100644 index 977bc980c1af..000000000000 --- a/include/asm-ppc64/unistd.h +++ /dev/null @@ -1,487 +0,0 @@ -#ifndef _ASM_PPC_UNISTD_H_ -#define _ASM_PPC_UNISTD_H_ - -/* - * This file contains the system call numbers. - * - * 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. - */ - -#define __NR_restart_syscall 0 -#define __NR_exit 1 -#define __NR_fork 2 -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 -#define __NR_waitpid 7 -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_lchown 16 -#define __NR_break 17 -#define __NR_oldstat 18 -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 -#define __NR_umount 22 -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 -#define __NR_oldfstat 28 -#define __NR_pause 29 -#define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 -#define __NR_access 33 -#define __NR_nice 34 -#define __NR_ftime 35 -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 -#define __NR_prof 44 -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 -#define __NR_signal 48 -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount2 52 -#define __NR_lock 53 -#define __NR_ioctl 54 -#define __NR_fcntl 55 -#define __NR_mpx 56 -#define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 -#define __NR_sigaction 67 -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 -#define __NR_sigsuspend 72 -#define __NR_sigpending 73 -#define __NR_sethostname 74 -#define __NR_setrlimit 75 -#define __NR_getrlimit 76 -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 -#define __NR_select 82 -#define __NR_symlink 83 -#define __NR_oldlstat 84 -#define __NR_readlink 85 -#define __NR_uselib 86 -#define __NR_swapon 87 -#define __NR_reboot 88 -#define __NR_readdir 89 -#define __NR_mmap 90 -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 -#define __NR_profil 98 -#define __NR_statfs 99 -#define __NR_fstatfs 100 -#define __NR_ioperm 101 -#define __NR_socketcall 102 -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_stat 106 -#define __NR_lstat 107 -#define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl 110 -#define __NR_vhangup 111 -#define __NR_idle 112 -#define __NR_vm86 113 -#define __NR_wait4 114 -#define __NR_swapoff 115 -#define __NR_sysinfo 116 -#define __NR_ipc 117 -#define __NR_fsync 118 -#define __NR_sigreturn 119 -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_uname 122 -#define __NR_modify_ldt 123 -#define __NR_adjtimex 124 -#define __NR_mprotect 125 -#define __NR_sigprocmask 126 -#define __NR_create_module 127 -#define __NR_init_module 128 -#define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 -#define __NR_sysfs 135 -#define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR__llseek 140 -#define __NR_getdents 141 -#define __NR__newselect 142 -#define __NR_flock 143 -#define __NR_msync 144 -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR__sysctl 149 -#define __NR_mlock 150 -#define __NR_munlock 151 -#define __NR_mlockall 152 -#define __NR_munlockall 153 -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 -#define __NR_query_module 166 -#define __NR_poll 167 -#define __NR_nfsservctl 168 -#define __NR_setresgid 169 -#define __NR_getresgid 170 -#define __NR_prctl 171 -#define __NR_rt_sigreturn 172 -#define __NR_rt_sigaction 173 -#define __NR_rt_sigprocmask 174 -#define __NR_rt_sigpending 175 -#define __NR_rt_sigtimedwait 176 -#define __NR_rt_sigqueueinfo 177 -#define __NR_rt_sigsuspend 178 -#define __NR_pread64 179 -#define __NR_pwrite64 180 -#define __NR_chown 181 -#define __NR_getcwd 182 -#define __NR_capget 183 -#define __NR_capset 184 -#define __NR_sigaltstack 185 -#define __NR_sendfile 186 -#define __NR_getpmsg 187 /* some people actually want streams */ -#define __NR_putpmsg 188 /* some people actually want streams */ -#define __NR_vfork 189 -#define __NR_ugetrlimit 190 /* SuS compliant getrlimit */ -#define __NR_readahead 191 -/* #define __NR_mmap2 192 32bit only */ -/* #define __NR_truncate64 193 32bit only */ -/* #define __NR_ftruncate64 194 32bit only */ -/* #define __NR_stat64 195 32bit only */ -/* #define __NR_lstat64 196 32bit only */ -/* #define __NR_fstat64 197 32bit only */ -#define __NR_pciconfig_read 198 -#define __NR_pciconfig_write 199 -#define __NR_pciconfig_iobase 200 -#define __NR_multiplexer 201 -#define __NR_getdents64 202 -#define __NR_pivot_root 203 -/* #define __NR_fcntl64 204 32bit only */ -#define __NR_madvise 205 -#define __NR_mincore 206 -#define __NR_gettid 207 -#define __NR_tkill 208 -#define __NR_setxattr 209 -#define __NR_lsetxattr 210 -#define __NR_fsetxattr 211 -#define __NR_getxattr 212 -#define __NR_lgetxattr 213 -#define __NR_fgetxattr 214 -#define __NR_listxattr 215 -#define __NR_llistxattr 216 -#define __NR_flistxattr 217 -#define __NR_removexattr 218 -#define __NR_lremovexattr 219 -#define __NR_fremovexattr 220 -#define __NR_futex 221 -#define __NR_sched_setaffinity 222 -#define __NR_sched_getaffinity 223 -/* 224 currently unused */ -#define __NR_tuxcall 225 -/* #define __NR_sendfile64 226 32bit only */ -#define __NR_io_setup 227 -#define __NR_io_destroy 228 -#define __NR_io_getevents 229 -#define __NR_io_submit 230 -#define __NR_io_cancel 231 -#define __NR_set_tid_address 232 -#define __NR_fadvise64 233 -#define __NR_exit_group 234 -#define __NR_lookup_dcookie 235 -#define __NR_epoll_create 236 -#define __NR_epoll_ctl 237 -#define __NR_epoll_wait 238 -#define __NR_remap_file_pages 239 -#define __NR_timer_create 240 -#define __NR_timer_settime 241 -#define __NR_timer_gettime 242 -#define __NR_timer_getoverrun 243 -#define __NR_timer_delete 244 -#define __NR_clock_settime 245 -#define __NR_clock_gettime 246 -#define __NR_clock_getres 247 -#define __NR_clock_nanosleep 248 -#define __NR_swapcontext 249 -#define __NR_tgkill 250 -#define __NR_utimes 251 -#define __NR_statfs64 252 -#define __NR_fstatfs64 253 -/* #define __NR_fadvise64_64 254 32bit only */ -#define __NR_rtas 255 -/* Number 256 is reserved for sys_debug_setcontext */ -/* Number 257 is reserved for vserver */ -/* 258 currently unused */ -#define __NR_mbind 259 -#define __NR_get_mempolicy 260 -#define __NR_set_mempolicy 261 -#define __NR_mq_open 262 -#define __NR_mq_unlink 263 -#define __NR_mq_timedsend 264 -#define __NR_mq_timedreceive 265 -#define __NR_mq_notify 266 -#define __NR_mq_getsetattr 267 -#define __NR_kexec_load 268 -#define __NR_add_key 269 -#define __NR_request_key 270 -#define __NR_keyctl 271 -#define __NR_waitid 272 -#define __NR_ioprio_set 273 -#define __NR_ioprio_get 274 -#define __NR_inotify_init 275 -#define __NR_inotify_add_watch 276 -#define __NR_inotify_rm_watch 277 - -#define __NR_syscalls 278 -#ifdef __KERNEL__ -#define NR_syscalls __NR_syscalls -#endif - -#ifndef __ASSEMBLY__ - -/* On powerpc a system call basically clobbers the same registers like a - * function call, with the exception of LR (which is needed for the - * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal - * an error return status). - */ - -#define __syscall_nr(nr, type, name, args...) \ - unsigned long __sc_ret, __sc_err; \ - { \ - register unsigned long __sc_0 __asm__ ("r0"); \ - register unsigned long __sc_3 __asm__ ("r3"); \ - register unsigned long __sc_4 __asm__ ("r4"); \ - register unsigned long __sc_5 __asm__ ("r5"); \ - register unsigned long __sc_6 __asm__ ("r6"); \ - register unsigned long __sc_7 __asm__ ("r7"); \ - register unsigned long __sc_8 __asm__ ("r8"); \ - \ - __sc_loadargs_##nr(name, args); \ - __asm__ __volatile__ \ - ("sc \n\t" \ - "mfcr %0 " \ - : "=&r" (__sc_0), \ - "=&r" (__sc_3), "=&r" (__sc_4), \ - "=&r" (__sc_5), "=&r" (__sc_6), \ - "=&r" (__sc_7), "=&r" (__sc_8) \ - : __sc_asm_input_##nr \ - : "cr0", "ctr", "memory", \ - "r9", "r10","r11", "r12"); \ - __sc_ret = __sc_3; \ - __sc_err = __sc_0; \ - } \ - if (__sc_err & 0x10000000) \ - { \ - errno = __sc_ret; \ - __sc_ret = -1; \ - } \ - return (type) __sc_ret - -#define __sc_loadargs_0(name, dummy...) \ - __sc_0 = __NR_##name -#define __sc_loadargs_1(name, arg1) \ - __sc_loadargs_0(name); \ - __sc_3 = (unsigned long) (arg1) -#define __sc_loadargs_2(name, arg1, arg2) \ - __sc_loadargs_1(name, arg1); \ - __sc_4 = (unsigned long) (arg2) -#define __sc_loadargs_3(name, arg1, arg2, arg3) \ - __sc_loadargs_2(name, arg1, arg2); \ - __sc_5 = (unsigned long) (arg3) -#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \ - __sc_loadargs_3(name, arg1, arg2, arg3); \ - __sc_6 = (unsigned long) (arg4) -#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \ - __sc_loadargs_4(name, arg1, arg2, arg3, arg4); \ - __sc_7 = (unsigned long) (arg5) -#define __sc_loadargs_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ - __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5); \ - __sc_8 = (unsigned long) (arg6) - -#define __sc_asm_input_0 "0" (__sc_0) -#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3) -#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4) -#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5) -#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6) -#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7) -#define __sc_asm_input_6 __sc_asm_input_5, "6" (__sc_8) - -#define _syscall0(type,name) \ -type name(void) \ -{ \ - __syscall_nr(0, type, name); \ -} - -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) \ -{ \ - __syscall_nr(1, type, name, arg1); \ -} - -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1, type2 arg2) \ -{ \ - __syscall_nr(2, type, name, arg1, arg2); \ -} - -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1, type2 arg2, type3 arg3) \ -{ \ - __syscall_nr(3, type, name, arg1, arg2, arg3); \ -} - -#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ -{ \ - __syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \ -} - -#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ -{ \ - __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \ -} -#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ -{ \ - __syscall_nr(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ -} - -#ifdef __KERNEL_SYSCALLS__ - -/* - * Forking from kernel space will result in the child getting a new, - * empty kernel stack area. Thus the child cannot access automatic - * variables set in the parent unless they are in registers, and the - * procedure where the fork was done cannot return to its caller in - * the child. - */ - -/* - * System call prototypes. - */ -static inline _syscall3(int, execve, __const__ char *, file, char **, argv, - char **,envp) - -#endif /* __KERNEL_SYSCALLS__ */ - -#ifdef __KERNEL__ - -#include -#include -#include - -#define __ARCH_WANT_IPC_PARSE_VERSION -#define __ARCH_WANT_OLD_READDIR -#define __ARCH_WANT_STAT64 -#define __ARCH_WANT_SYS_ALARM -#define __ARCH_WANT_SYS_GETHOSTNAME -#define __ARCH_WANT_SYS_PAUSE -#define __ARCH_WANT_SYS_SGETMASK -#define __ARCH_WANT_SYS_SIGNAL -#define __ARCH_WANT_SYS_TIME -#define __ARCH_WANT_COMPAT_SYS_TIME -#define __ARCH_WANT_SYS_UTIME -#define __ARCH_WANT_SYS_WAITPID -#define __ARCH_WANT_SYS_SOCKETCALL -#define __ARCH_WANT_SYS_FADVISE64 -#define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK -#define __ARCH_WANT_SYS_NICE -#define __ARCH_WANT_SYS_OLD_GETRLIMIT -#define __ARCH_WANT_SYS_OLDUMOUNT -#define __ARCH_WANT_SYS_SIGPENDING -#define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION - -unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot, - unsigned long flags, unsigned long fd, off_t offset); -struct pt_regs; -int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs); -int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs); -int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs); -int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs); -int sys_pipe(int __user *fildes); -int sys_ptrace(long request, long pid, long addr, long data); -struct sigaction; -long sys_rt_sigaction(int sig, const struct sigaction __user *act, - struct sigaction __user *oact, size_t sigsetsize); - -/* - * "Conditional" syscalls - * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand - */ -#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall") - -#endif /* __KERNEL__ */ - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_PPC_UNISTD_H_ */ From c5200c90db3823a6e2f529acf202c4aed04966ae Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:57:03 +1000 Subject: [PATCH 0351/1939] powerpc: Fix off-by-one error in prom_init.c This was preventing us from recognizing that we did actually instantiate RTAS successfully on pSeries. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 75dc7f3714bd..911a803f27da 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -268,7 +268,7 @@ static int __init call_prom_ret(const char *service, int nargs, int nret, if (rets != NULL) for (i = 1; i < nret; ++i) - rets[i] = args.args[nargs+i]; + rets[i-1] = args.args[nargs+i]; return (nret > 0) ? args.args[nargs] : 0; } From e574d238ab907963ae6f97cb6bf12bb8fd48c376 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:58:10 +1000 Subject: [PATCH 0352/1939] powerpc: Fix compilation for 32-bit configs Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 21 +++------------------ arch/ppc/kernel/Makefile | 6 ++---- include/asm-ppc/pci-bridge.h | 5 +++++ 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 27d7f828212b..bfa155c00ea5 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -70,6 +70,8 @@ unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; +int have_of = 1; + #ifdef CONFIG_PPC_MULTIPLATFORM int _machine = 0; @@ -89,6 +91,7 @@ unsigned long vgacon_remap_base; #endif struct machdep_calls ppc_md; +EXPORT_SYMBOL(ppc_md); /* * These are used in binfmt_elf.c to put aux entries on the stack @@ -455,24 +458,6 @@ console_initcall(set_preferred_console); #endif /* CONFIG_SERIAL_CORE_CONSOLE */ #endif /* CONFIG_PPC_MULTIPLATFORM */ -struct bi_record *find_bootinfo(void) -{ - struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) { - /* - * This 0x10000 offset is a terrible hack but it will go away when - * we have the bootloader handle all the relocation and - * prom calls -- Cort - */ - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) - return NULL; - } - return rec; -} - /* * Find out what kind of machine we're on and save any data we need * from the early boot process (devtree is copied on pmac by prom_init()). diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index da2dc08c4c1b..74b30978619f 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -42,13 +42,11 @@ vector-y += ../../powerpc/kernel/vector.o fpu-y += ../../powerpc/kernel/fpu.o else -obj-y := entry.o irq.o idle.o time.o misc.o \ +obj-y := irq.o idle.o time.o \ signal.o ptrace.o align.o \ - syscalls.o setup.o \ - cputable.o perfmon.o + syscalls.o cputable.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o -obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_PCI) += pci.o diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index ffa423456c2b..e58c78f90a5a 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -79,6 +79,11 @@ struct pci_controller { struct resource mem_space; }; +static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) +{ + return bus->sysdata; +} + /* These are used for config access before all the PCI probing has been done. */ int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, From 3c3f42d63a11f2e22dbff6bb4d170f92dbd39316 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 10 Oct 2005 22:58:41 +1000 Subject: [PATCH 0353/1939] powerpc: Start merging 64-bit support into powermac files Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pci.c | 194 +++++++++++------------- arch/powerpc/platforms/powermac/pic.c | 32 ++-- arch/powerpc/platforms/powermac/pmac.h | 25 ++- arch/powerpc/platforms/powermac/setup.c | 20 +-- 4 files changed, 128 insertions(+), 143 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 40bcd3e55afb..afb147e6b89f 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1,8 +1,5 @@ /* * Support for PCI bridges found on Power Macintoshes. - * At present the "bandit" and "chaos" bridges are supported. - * Fortunately you access configuration space in the same - * way with either bridge. * * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) @@ -26,6 +23,10 @@ #include #include #include +#ifdef CONFIG_PPC64 +#include +#include +#endif #undef DEBUG @@ -160,9 +161,13 @@ static unsigned long macrisc_cfg_access(struct pci_controller* hose, static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose; unsigned long addr; + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -187,9 +192,13 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose; unsigned long addr; + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -221,7 +230,7 @@ static struct pci_ops macrisc_pci_ops = }; /* - * Verifiy that a specific (bus, dev_fn) exists on chaos + * Verify that a specific (bus, dev_fn) exists on chaos */ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) @@ -274,7 +283,6 @@ static struct pci_ops chaos_pci_ops = }; #ifdef CONFIG_POWER4 - /* * These versions of U3 HyperTransport config space access ops do not * implement self-view of the HT host yet @@ -342,11 +350,11 @@ static unsigned long u3_ht_cfg_access(struct pci_controller* hose, static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose; unsigned long addr; - struct device_node *np = pci_busdev_to_OF_node(bus, devfn); - if (np == NULL) + hose = pci_bus_to_host(bus); + if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); @@ -357,19 +365,19 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, case 0: break; case 1: - switch (len) { - case 1: - *val = 0xff; break; - case 2: - *val = 0xffff; break; - default: - *val = 0xfffffffful; break; - } - return PCIBIOS_SUCCESSFUL; + switch (len) { + case 1: + *val = 0xff; break; + case 2: + *val = 0xffff; break; + default: + *val = 0xfffffffful; break; + } + return PCIBIOS_SUCCESSFUL; default: return PCIBIOS_DEVICE_NOT_FOUND; - } - + } + /* * Note: the caller has already checked that offset is * suitably aligned and that len is 1, 2 or 4. @@ -391,11 +399,11 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose; unsigned long addr; - struct device_node *np = pci_busdev_to_OF_node(bus, devfn); - if (np == NULL) + hose = pci_bus_to_host(bus); + if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); @@ -437,15 +445,13 @@ static struct pci_ops u3_ht_pci_ops = u3_ht_read_config, u3_ht_write_config }; - #endif /* CONFIG_POWER4 */ /* * For a bandit bridge, turn on cache coherency if necessary. * N.B. we could clean this up using the hose ops directly. */ -static void __init -init_bandit(struct pci_controller *bp) +static void __init init_bandit(struct pci_controller *bp) { unsigned int vendev, magic; int rev; @@ -485,8 +491,7 @@ init_bandit(struct pci_controller *bp) /* * Tweak the PCI-PCI bridge chip on the blue & white G3s. */ -static void __init -init_p2pbridge(void) +static void __init init_p2pbridge(void) { struct device_node *p2pbridge; struct pci_controller* hose; @@ -526,8 +531,7 @@ init_p2pbridge(void) * EHCI part of it so it behaves like a pair of OHCI's. This fixup * code re-enables it ;) */ -static void __init -fixup_nec_usb2(void) +static void __init fixup_nec_usb2(void) { struct device_node *nec; @@ -567,77 +571,6 @@ fixup_nec_usb2(void) } } -void __init -pmac_find_bridges(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); - return; - } - for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) - continue; - if (strcmp(np->name, "bandit") == 0 - || strcmp(np->name, "chaos") == 0 - || strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Probe HT last as it relies on the agp resources to be already - * setup - */ - if (ht && add_bridge(ht) != 0) - of_node_put(ht); - - init_p2pbridge(); - fixup_nec_usb2(); - - /* We are still having some issues with the Xserve G4, enabling - * some offset between bus number and domains for now when we - * assign all busses should help for now - */ - if (pci_assign_all_busses) - pcibios_assign_bus_offset = 0x10; - -#ifdef CONFIG_POWER4 - /* There is something wrong with DMA on U3/HT. I haven't figured out - * the details yet, but if I set the cache line size to 128 bytes like - * it should, I'm getting memory corruption caused by devices like - * sungem (even without the MWI bit set, but maybe sungem doesn't - * care). Right now, it appears that setting up a 64 bytes line size - * works properly, 64 bytes beeing the max transfer size of HT, I - * suppose this is related the way HT/PCI are hooked together. I still - * need to dive into more specs though to be really sure of what's - * going on. --BenH. - * - * Ok, apparently, it's just that HT can't do more than 64 bytes - * transactions. MWI seem to be meaningless there as well, it may - * be worth nop'ing out pci_set_mwi too though I haven't done that - * yet. - * - * Note that it's a bit different for whatever is in the AGP slot. - * For now, I don't care, but this can become a real issue, we - * should probably hook pci_set_mwi anyway to make sure it sets - * the real cache line size in there. - */ - if (machine_is_compatible("MacRISC4")) - pci_cache_line_size = 16; /* 64 bytes */ - - pmac_check_ht_link(); -#endif /* CONFIG_POWER4 */ -} - #define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ | (((o) & ~3) << 24)) @@ -703,7 +636,6 @@ setup_chaos(struct pci_controller* hose, struct reg_property* addr) } #ifdef CONFIG_POWER4 - static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need @@ -715,7 +647,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; has_uninorth = 1; hose->ops = ¯isc_pci_ops; @@ -748,7 +680,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) */ hose->io_base_phys = 0xf4000000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); - isa_io_base = (unsigned long) hose->io_base_virt; + isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; hose->io_resource.name = np->full_name; hose->io_resource.start = 0; hose->io_resource.end = 0x003fffff; @@ -794,13 +726,13 @@ static void __init setup_u3_ht(struct pci_controller* hose) } /* No, it's not the case, we need a hole */ if (cur == 2) { - /* not enough resources to make a hole, we drop part of the range */ + /* not enough resources for a hole, we drop part of the range */ printk(KERN_WARNING "Running out of resources for /ht host !\n"); hose->mem_resources[cur].end = res->start - 1; continue; } cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); hose->mem_resources[cur].name = np->full_name; hose->mem_resources[cur].flags = IORESOURCE_MEM; @@ -981,7 +913,7 @@ static int __init add_bridge(struct device_node *dev) if (device_is_compatible(dev, "uni-north")) { primary = setup_uninorth(hose, addr); disp_name = "UniNorth"; - } else if (strcmp(dev->name, "pci") == 0) { + } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ setup_grackle(hose); disp_name = "Grackle (MPC106)"; @@ -993,7 +925,7 @@ static int __init add_bridge(struct device_node *dev) disp_name = "Chaos"; primary = 0; } - printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", + printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", disp_name, addr->address, hose->first_busno, hose->last_busno); DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", hose, hose->cfg_addr, hose->cfg_data); @@ -1036,6 +968,50 @@ pmac_pcibios_fixup(void) pcibios_fixup_OF_interrupts(); } +void __init pmac_find_bridges(void) +{ + struct device_node *np, *root; + struct device_node *ht = NULL; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + return; + } + for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { + if (np->name == NULL) + continue; + if (strcmp(np->name, "bandit") == 0 + || strcmp(np->name, "chaos") == 0 + || strcmp(np->name, "pci") == 0) { + if (add_bridge(np) == 0) + of_node_get(np); + } + if (strcmp(np->name, "ht") == 0) { + of_node_get(np); + ht = np; + } + } + of_node_put(root); + + /* Probe HT last as it relies on the agp resources to be already + * setup + */ + if (ht && add_bridge(ht) != 0) + of_node_put(ht); + + init_p2pbridge(); + fixup_nec_usb2(); + + /* We are still having some issues with the Xserve G4, enabling + * some offset between bus number and domains for now when we + * assign all busses should help for now + */ + if (pci_assign_all_busses) + pcibios_assign_bus_offset = 0x10; + +} + int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) { diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 7ddd5264cc6e..682fe8b6e025 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -32,12 +33,11 @@ #include #include #include -#include #include #include #include -#include "pmac_pic.h" +#include "pmac.h" /* * XXX this should be in xmon.h, but putting it there means xmon.h @@ -46,6 +46,7 @@ */ extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); +#ifdef CONFIG_PPC32 struct pmac_irq_hw { unsigned int event; unsigned int enable; @@ -71,6 +72,9 @@ static u32 level_mask[4]; static DEFINE_SPINLOCK(pmac_pic_lock); +/* XXX here for now, should move to arch/powerpc/kernel/irq.c */ +int ppc_do_canonicalize_irqs; +EXPORT_SYMBOL(ppc_do_canonicalize_irqs); #define GATWICK_IRQ_POOL_SIZE 10 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; @@ -377,11 +381,6 @@ static int __init enable_second_ohare(void) return irqctrler->intrs[0].line; } -static int pmac_u3_cascade(struct pt_regs *regs, void *data) -{ - return mpic_get_one_irq((struct mpic *)data, regs); -} - #ifdef CONFIG_XMON static struct irqaction xmon_action = { .handler = xmon_irq, @@ -397,15 +396,23 @@ static struct irqaction gatwick_cascade_action = { .mask = CPU_MASK_NONE, .name = "cascade", }; +#endif /* CONFIG_PPC32 */ + +static int pmac_u3_cascade(struct pt_regs *regs, void *data) +{ + return mpic_get_one_irq((struct mpic *)data, regs); +} void __init pmac_pic_init(void) { - int i; struct device_node *irqctrler = NULL; struct device_node *irqctrler2 = NULL; struct device_node *np; +#ifdef CONFIG_PPC32 + int i; unsigned long addr; int irq_cascade = -1; +#endif struct mpic *mpic1, *mpic2; /* We first try to detect Apple's new Core99 chipset, since mac-io @@ -455,7 +462,7 @@ void __init pmac_pic_init(void) mpic_setup_cascade(irqctrler2->intrs[0].line, pmac_u3_cascade, mpic2); } -#ifdef CONFIG_XMON +#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) { struct device_node* pswitch; int nmi_irq; @@ -463,7 +470,7 @@ void __init pmac_pic_init(void) pswitch = find_devices("programmer-switch"); if (pswitch && pswitch->n_intrs) { nmi_irq = pswitch->intrs[0].line; - openpic_init_nmi_irq(nmi_irq); + mpic_irq_set_priority(nmi_irq, 9); setup_irq(nmi_irq, &xmon_action); } } @@ -472,6 +479,7 @@ void __init pmac_pic_init(void) } irqctrler = NULL; +#ifdef CONFIG_PPC32 /* Get the level/edge settings, assume if it's not * a Grand Central nor an OHare, then it's an Heathrow * (or Paddington). @@ -570,6 +578,7 @@ void __init pmac_pic_init(void) #ifdef CONFIG_XMON setup_irq(20, &xmon_action); #endif /* CONFIG_XMON */ +#endif /* CONFIG_PPC32 */ } #ifdef CONFIG_PM @@ -659,9 +668,10 @@ static struct sysdev_driver driver_pmacpic = { static int __init init_pmacpic_sysfs(void) { +#ifdef CONFIG_PPC32 if (max_irqs == 0) return -ENODEV; - +#endif printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); sysdev_class_register(&pmacpic_sysclass); sysdev_register(&device_pmacpic); diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 40e1c5030f74..81f52512b046 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -3,19 +3,31 @@ #include #include +#include /* * Declaration for the various functions exported by the * pmac_* files. Mostly for use by pmac_setup */ -extern void pmac_get_boot_time(struct rtc_time *tm); -extern void pmac_get_rtc_time(struct rtc_time *tm); -extern int pmac_set_rtc_time(struct rtc_time *tm); +extern long pmac_time_init(void); +extern unsigned long pmac_get_rtc_time(void); +extern int pmac_set_rtc_time(unsigned long nowtime); extern void pmac_read_rtc_time(void); extern void pmac_calibrate_decr(void); - extern void pmac_pcibios_fixup(void); +extern void pmac_find_bridges(void); +extern unsigned long pmac_ide_get_base(int index); +extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, + unsigned long data_port, unsigned long ctrl_port, int *irq); + +extern void pmac_nvram_update(void); +extern unsigned char pmac_nvram_read_byte(int addr); +extern void pmac_nvram_write_byte(int addr, unsigned char val); +extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +extern void pmac_pcibios_after_init(void); +extern int of_show_percpuinfo(struct seq_file *m, int i); + extern void pmac_pci_init(void); extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); @@ -28,4 +40,9 @@ extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, extern void pmac_nvram_init(void); +extern struct hw_interrupt_type pmac_pic; + +void pmac_pic_init(void); +int pmac_get_irq(struct pt_regs *regs); + #endif /* __PMAC_H__ */ diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 1b12bf9956cb..9416fcaa6daa 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -73,28 +73,10 @@ #include #include -#include "pmac_pic.h" +#include "pmac.h" #undef SHOW_GATWICK_IRQS -extern long pmac_time_init(void); -extern unsigned long pmac_get_rtc_time(void); -extern int pmac_set_rtc_time(unsigned long nowtime); -extern void pmac_read_rtc_time(void); -extern void pmac_calibrate_decr(void); -extern void pmac_pcibios_fixup(void); -extern void pmac_find_bridges(void); -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); - -extern void pmac_nvram_update(void); -extern unsigned char pmac_nvram_read_byte(int addr); -extern void pmac_nvram_write_byte(int addr, unsigned char val); -extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); -extern void pmac_pcibios_after_init(void); -extern int of_show_percpuinfo(struct seq_file *m, int i); - unsigned char drive_info; int ppc_override_l2cr = 0; From edea3ab58f8edd5f72d31f891ab4f34382e97e3a Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Mon, 10 Oct 2005 17:53:58 -0400 Subject: [PATCH 0354/1939] libata: add new driver pdc_adma for PDC ADMA ATA cards --- drivers/scsi/Kconfig | 14 +- drivers/scsi/Makefile | 1 + drivers/scsi/pdc_adma.c | 737 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 749 insertions(+), 3 deletions(-) create mode 100644 drivers/scsi/pdc_adma.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index be96cb78e3b5..e2845b442776 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -489,11 +489,11 @@ config SCSI_SATA_NV If unsure, say N. -config SCSI_SATA_PROMISE - tristate "Promise SATA TX2/TX4 support" +config SCSI_PDC_ADMA + tristate "Pacific Digital ADMA support" depends on SCSI_SATA && PCI help - This option enables support for Promise Serial ATA TX2/TX4. + This option enables support for Pacific Digital ADMA controllers If unsure, say N. @@ -505,6 +505,14 @@ config SCSI_SATA_QSTOR If unsure, say N. +config SCSI_SATA_PROMISE + tristate "Promise SATA TX2/TX4 support" + depends on SCSI_SATA && PCI + help + This option enables support for Promise Serial ATA TX2/TX4. + + If unsure, say N. + config SCSI_SATA_SX4 tristate "Promise SATA SX4 support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e2e3d8671930..2d4439826c08 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -138,6 +138,7 @@ obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o +obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c new file mode 100644 index 000000000000..ce006a5b4533 --- /dev/null +++ b/drivers/scsi/pdc_adma.c @@ -0,0 +1,737 @@ +/* + * pdc_adma.c - Pacific Digital Corporation ADMA + * + * Maintained by: Mark Lord + * + * Copyright 2005 Mark Lord + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + * Supports ATA disks in single-packet ADMA mode. + * Uses PIO for everything else. + * + * TODO: Use ADMA transfers for ATAPI devices, when possible. + * This requires careful attention to a number of quirks of the chip. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include +#include + +#define DRV_NAME "pdc_adma" +#define DRV_VERSION "0.01" + +/* macro to calculate base address for ATA regs */ +#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) + +/* macro to calculate base address for ADMA regs */ +#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) + +enum { + ADMA_PORTS = 2, + ADMA_CPB_BYTES = 40, + ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16, + ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES, + + ADMA_DMA_BOUNDARY = 0xffffffff, + + /* global register offsets */ + ADMA_MODE_LOCK = 0x00c7, + + /* per-channel register offsets */ + ADMA_CONTROL = 0x0000, /* ADMA control */ + ADMA_STATUS = 0x0002, /* ADMA status */ + ADMA_CPB_COUNT = 0x0004, /* CPB count */ + ADMA_CPB_CURRENT = 0x000c, /* current CPB address */ + ADMA_CPB_NEXT = 0x000c, /* next CPB address */ + ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */ + ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */ + ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */ + + /* ADMA_CONTROL register bits */ + aNIEN = (1 << 8), /* irq mask: 1==masked */ + aGO = (1 << 7), /* packet trigger ("Go!") */ + aRSTADM = (1 << 5), /* ADMA logic reset */ + aAUTEN = (1 << 3), /* packet trigger ("Go!") */ + aRSTA = (1 << 2), /* ATA hard reset */ + aPIOMD4 = 0x0003, /* PIO mode 4 */ + + /* ADMA_STATUS register bits */ + aPSD = (1 << 6), + aUIRQ = (1 << 4), + aPERR = (1 << 0), + + /* CPB bits */ + cDONE = (1 << 0), + cVLD = (1 << 0), + cDAT = (1 << 2), + cIEN = (1 << 3), + + /* PRD bits */ + pORD = (1 << 4), + pDIRO = (1 << 5), + pEND = (1 << 7), + + /* ATA register flags */ + rIGN = (1 << 5), + rEND = (1 << 7), + + /* ATA register addresses */ + ADMA_REGS_CONTROL = 0x0e, + ADMA_REGS_SECTOR_COUNT = 0x12, + ADMA_REGS_LBA_LOW = 0x13, + ADMA_REGS_LBA_MID = 0x14, + ADMA_REGS_LBA_HIGH = 0x15, + ADMA_REGS_DEVICE = 0x16, + ADMA_REGS_COMMAND = 0x17, + + /* PCI device IDs */ + board_1841_idx = 0, /* ADMA 2-port controller */ +}; + +typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t; + +struct adma_port_priv { + u8 *pkt; + dma_addr_t pkt_dma; + adma_state_t state; +}; + +static int adma_ata_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); +static irqreturn_t adma_intr (int irq, void *dev_instance, + struct pt_regs *regs); +static int adma_port_start(struct ata_port *ap); +static void adma_host_stop(struct ata_host_set *host_set); +static void adma_port_stop(struct ata_port *ap); +static void adma_phy_reset(struct ata_port *ap); +static void adma_qc_prep(struct ata_queued_cmd *qc); +static int adma_qc_issue(struct ata_queued_cmd *qc); +static int adma_check_atapi_dma(struct ata_queued_cmd *qc); +static void adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 adma_bmdma_status(struct ata_port *ap); +static void adma_irq_clear(struct ata_port *ap); +static void adma_eng_timeout(struct ata_port *ap); + +static Scsi_Host_Template adma_ata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ENABLE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ADMA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations adma_ata_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = adma_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + .phy_reset = adma_phy_reset, + .qc_prep = adma_qc_prep, + .qc_issue = adma_qc_issue, + .eng_timeout = adma_eng_timeout, + .irq_handler = adma_intr, + .irq_clear = adma_irq_clear, + .port_start = adma_port_start, + .port_stop = adma_port_stop, + .host_stop = adma_host_stop, + .bmdma_stop = adma_bmdma_stop, + .bmdma_status = adma_bmdma_status, +}; + +static struct ata_port_info adma_port_info[] = { + /* board_1841_idx */ + { + .sht = &adma_ata_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + .pio_mask = 0x10, /* pio4 */ + .udma_mask = 0x1f, /* udma0-4 */ + .port_ops = &adma_ata_ops, + }, +}; + +static struct pci_device_id adma_ata_pci_tbl[] = { + { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_1841_idx }, + + { } /* terminate list */ +}; + +static struct pci_driver adma_ata_pci_driver = { + .name = DRV_NAME, + .id_table = adma_ata_pci_tbl, + .probe = adma_ata_init_one, + .remove = ata_pci_remove_one, +}; + +static int adma_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return 1; /* ATAPI DMA not yet supported */ +} + +static void adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + /* nothing */ +} + +static u8 adma_bmdma_status(struct ata_port *ap) +{ + return 0; +} + +static void adma_irq_clear(struct ata_port *ap) +{ + /* nothing */ +} + +static void adma_reset_engine(void __iomem *chan) +{ + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4, chan + ADMA_CONTROL); + udelay(2); +} + +static void adma_reinit_engine(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + void __iomem *mmio_base = ap->host_set->mmio_base; + void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr); + ata_check_status(ap); + + /* reset the ADMA engine */ + adma_reset_engine(chan); + + /* set in-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_IN); + + /* set CPB pointer */ + writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT); + + /* set out-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_OUT); + + /* set CPB count */ + writew(1, chan + ADMA_CPB_COUNT); + + /* read/discard ADMA status */ + readb(chan + ADMA_STATUS); +} + +static inline void adma_enter_reg_mode(struct ata_port *ap) +{ + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + writew(aPIOMD4, chan + ADMA_CONTROL); + readb(chan + ADMA_STATUS); /* flush */ +} + +static void adma_phy_reset(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + pp->state = adma_state_idle; + adma_reinit_engine(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} + +static void adma_eng_timeout(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + if (pp->state != adma_state_idle) /* healthy paranoia */ + pp->state = adma_state_mmio; + adma_reinit_engine(ap); + ata_eng_timeout(ap); +} + +static int adma_fill_sg(struct ata_queued_cmd *qc) +{ + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct adma_port_priv *pp = ap->private_data; + u8 *buf = pp->pkt; + int nelem, i = (2 + buf[3]) * 8; + u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); + + for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) { + u32 addr; + u32 len; + + addr = (u32)sg_dma_address(sg); + *(__le32 *)(buf + i) = cpu_to_le32(addr); + i += 4; + + len = sg_dma_len(sg) >> 3; + *(__le32 *)(buf + i) = cpu_to_le32(len); + i += 4; + + if ((nelem + 1) == qc->n_elem) + pFLAGS |= pEND; + buf[i++] = pFLAGS; + buf[i++] = qc->dev->dma_mode & 0xf; + buf[i++] = 0; /* pPKLW */ + buf[i++] = 0; /* reserved */ + + *(__le32 *)(buf + i) + = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4); + i += 4; + + VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", nelem, + (unsigned long)addr, len); + } + return i; +} + +static void adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + u8 *buf = pp->pkt; + u32 pkt_dma = (u32)pp->pkt_dma; + int i = 0; + + VPRINTK("ENTER\n"); + + adma_enter_reg_mode(qc->ap); + if (qc->tf.protocol != ATA_PROT_DMA) { + ata_qc_prep(qc); + return; + } + + buf[i++] = 0; /* Response flags */ + buf[i++] = 0; /* reserved */ + buf[i++] = cVLD | cDAT | cIEN; + i++; /* cLEN, gets filled in below */ + + *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */ + i += 4; /* cNCPB */ + i += 4; /* cPRD, gets filled in below */ + + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + + /* ATA registers; must be a multiple of 4 */ + buf[i++] = qc->tf.device; + buf[i++] = ADMA_REGS_DEVICE; + if ((qc->tf.flags & ATA_TFLAG_LBA48)) { + buf[i++] = qc->tf.hob_nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.hob_lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.hob_lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.hob_lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + } + buf[i++] = qc->tf.nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + buf[i++] = 0; + buf[i++] = ADMA_REGS_CONTROL; + buf[i++] = rIGN; + buf[i++] = 0; + buf[i++] = qc->tf.command; + buf[i++] = ADMA_REGS_COMMAND | rEND; + + buf[3] = (i >> 3) - 2; /* cLEN */ + *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */ + + i = adma_fill_sg(qc); + wmb(); /* flush PRDs and pkt to memory */ +#if 0 + /* dump out CPB + PRDs for debug */ + { + int j, len = 0; + static char obuf[2048]; + for (j = 0; j < i; ++j) { + len += sprintf(obuf+len, "%02x ", buf[j]); + if ((j & 7) == 7) { + printk("%s\n", obuf); + len = 0; + } + } + if (len) + printk("%s\n", obuf); + } +#endif +} + +static inline void adma_packet_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + VPRINTK("ENTER, ap %p\n", ap); + + /* fire up the ADMA engine */ + writew(aPIOMD4 | aGO | aAUTEN, chan + ADMA_CONTROL); +} + +static int adma_qc_issue(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pp->state = adma_state_pkt; + adma_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + pp->state = adma_state_mmio; + return ata_qc_issue_prot(qc); +} + +static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + u8 __iomem *mmio_base = host_set->mmio_base; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap = host_set->ports[port_no]; + struct adma_port_priv *pp; + struct ata_queued_cmd *qc; + void __iomem *chan = ADMA_REGS(mmio_base, port_no); + u8 drv_stat, status = readb(chan + ADMA_STATUS); + + if (status == 0) + continue; + handled = 1; + adma_enter_reg_mode(ap); + if ((ap->flags & ATA_FLAG_PORT_DISABLED)) + continue; + pp = ap->private_data; + if (!pp || pp->state != adma_state_pkt) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + drv_stat = 0; + if ((status & (aPERR | aPSD | aUIRQ))) + drv_stat = ATA_ERR; + else if (pp->pkt[0] != cDONE) + drv_stat = ATA_ERR; + ata_qc_complete(qc, drv_stat); + } + return handled; +} + +static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + + 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)))) { + struct ata_queued_cmd *qc; + struct adma_port_priv *pp = ap->private_data; + if (!pp || pp->state != adma_state_mmio) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + + /* check main status, clearing INTRQ */ + u8 status = ata_chk_status(ap); + if ((status & ATA_BUSY)) + continue; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* complete taskfile transaction */ + pp->state = adma_state_idle; + ata_qc_complete(qc, status); + handled = 1; + } + } + } + return handled; +} + +static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int handled = 0; + + VPRINTK("ENTER\n"); + + spin_lock(&host_set->lock); + handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set); + spin_unlock(&host_set->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(handled); +} + +static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = + port->data_addr = base + 0x000; + port->error_addr = + port->feature_addr = base + 0x004; + port->nsect_addr = base + 0x008; + port->lbal_addr = base + 0x00c; + port->lbam_addr = base + 0x010; + port->lbah_addr = base + 0x014; + port->device_addr = base + 0x018; + port->status_addr = + port->command_addr = base + 0x01c; + port->altstatus_addr = + port->ctl_addr = base + 0x038; +} + +static int adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + adma_enter_reg_mode(ap); + rc = -ENOMEM; + pp = kcalloc(1, sizeof(*pp), GFP_KERNEL); + if (!pp) + goto err_out; + pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); + if (!pp->pkt) + goto err_out_kfree; + /* paranoia? */ + if ((pp->pkt_dma & 7) != 0) { + printk("bad alignment for pp->pkt_dma: %08x\n", + (u32)pp->pkt_dma); + goto err_out_kfree2; + } + memset(pp->pkt, 0, ADMA_PKT_BYTES); + ap->private_data = pp; + adma_reinit_engine(ap); + return 0; + +err_out_kfree2: + kfree(pp); +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp = ap->private_data; + + adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no)); + if (pp != NULL) { + ap->private_data = NULL; + if (pp->pkt != NULL) + dma_free_coherent(dev, ADMA_PKT_BYTES, + pp->pkt, pp->pkt_dma); + kfree(pp); + } + ata_port_stop(ap); +} + +static void adma_host_stop(struct ata_host_set *host_set) +{ + unsigned int port_no; + + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no)); + + ata_pci_host_stop(host_set); +} + +static void adma_host_init(unsigned int chip_id, + struct ata_probe_ent *probe_ent) +{ + unsigned int port_no; + void __iomem *mmio_base = probe_ent->mmio_base; + + /* enable/lock aGO operation */ + writeb(7, mmio_base + ADMA_MODE_LOCK); + + /* reset the ADMA logic */ + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(mmio_base, port_no)); +} + +static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) +{ + int rc; + + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + return rc; + } + return 0; +} + +static int adma_ata_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + void __iomem *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc, port_no; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { + rc = -ENODEV; + goto err_out_regions; + } + + mmio_base = pci_iomap(pdev, 4, 0); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + rc = adma_set_dma_masks(pdev, mmio_base); + if (rc) + goto err_out_iounmap; + + probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_iounmap; + } + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = adma_port_info[board_idx].sht; + probe_ent->host_flags = adma_port_info[board_idx].host_flags; + probe_ent->pio_mask = adma_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = adma_port_info[board_idx].udma_mask; + probe_ent->port_ops = adma_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + probe_ent->n_ports = ADMA_PORTS; + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { + adma_ata_setup_port(&probe_ent->port[port_no], + ADMA_ATA_REGS((unsigned long)mmio_base, port_no)); + } + + pci_set_master(pdev); + + /* initialize adapter */ + adma_host_init(board_idx, probe_ent); + + rc = ata_device_add(probe_ent); + kfree(probe_ent); + if (rc != ADMA_PORTS) + goto err_out_iounmap; + return 0; + +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init adma_ata_init(void) +{ + return pci_module_init(&adma_ata_pci_driver); +} + +static void __exit adma_ata_exit(void) +{ + pci_unregister_driver(&adma_ata_pci_driver); +} + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(adma_ata_init); +module_exit(adma_ata_exit); From 20f629549b30a1154c8b5e830cb10a0c0faa875f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:25:40 +1000 Subject: [PATCH 0355/1939] powerpc: Make building the boot image work for both 32-bit and 64-bit At the moment we don't have a merged arch/powerpc/boot, so we build the boot images in arch/ppc/boot and arch/ppc64/boot. Unfortunately the makefile targets are different in those two directories, so this makes a change to accommodate both for the moment. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 27649cfc2a5d..8d1e7bd14c55 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -140,6 +140,7 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ defaultimage-$(CONFIG_PPC32) := uImage zImage defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux +defaultimage-$(CONFIG_PPC_PSERIES) := zImage KBUILD_IMAGE := $(defaultimage-y) all: $(KBUILD_IMAGE) @@ -154,8 +155,14 @@ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm boot := arch/$(OLDARCH)/boot +# urk +ifeq ($(CONFIG_PPC64),y) $(BOOT_TARGETS): vmlinux - $(Q)$(MAKE) ARCH=$(OLDARCH) $(build)=$(boot) $@ + $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@) +else +$(BOOT_TARGETS): vmlinux + $(Q)$(MAKE) ARCH=ppc $(build)=$(boot) $@ +endif uImage: vmlinux $(Q)$(MAKE) ARCH=$(OLDARCH) $(build)=$(boot)/images $(boot)/images/$@ From 508c40227caee4cef0e963e61a3a5172a108b455 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:26:48 +1000 Subject: [PATCH 0356/1939] powerpc: Merged asm/backlight.h Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/backlight.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) rename include/{asm-ppc => asm-powerpc}/backlight.h (82%) diff --git a/include/asm-ppc/backlight.h b/include/asm-powerpc/backlight.h similarity index 82% rename from include/asm-ppc/backlight.h rename to include/asm-powerpc/backlight.h index 3a1c3dede2a0..1ba1f27a0b63 100644 --- a/include/asm-ppc/backlight.h +++ b/include/asm-powerpc/backlight.h @@ -1,12 +1,13 @@ /* * Routines for handling backlight control on PowerBooks * - * For now, implementation resides in arch/ppc/kernel/pmac_support.c + * For now, implementation resides in + * arch/powerpc/platforms/powermac/pmac_support.c * */ +#ifndef __ASM_POWERPC_BACKLIGHT_H +#define __ASM_POWERPC_BACKLIGHT_H #ifdef __KERNEL__ -#ifndef __ASM_PPC_BACKLIGHT_H -#define __ASM_PPC_BACKLIGHT_H /* Abstract values */ #define BACKLIGHT_OFF 0 @@ -26,5 +27,5 @@ extern int get_backlight_enable(void); extern int set_backlight_level(int level); extern int get_backlight_level(void); -#endif #endif /* __KERNEL__ */ +#endif From 3b341c1c410078bdc4128e08d4dfeef491697198 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:28:16 +1000 Subject: [PATCH 0357/1939] powerpc: Merged asm/i8259.h Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/i8259.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename include/{asm-ppc => asm-powerpc}/i8259.h (62%) diff --git a/include/asm-ppc/i8259.h b/include/asm-powerpc/i8259.h similarity index 62% rename from include/asm-ppc/i8259.h rename to include/asm-powerpc/i8259.h index 091b71295de4..9521ad47740f 100644 --- a/include/asm-ppc/i8259.h +++ b/include/asm-powerpc/i8259.h @@ -1,5 +1,5 @@ -#ifndef _PPC_KERNEL_i8259_H -#define _PPC_KERNEL_i8259_H +#ifndef _ASM_POWERPC_I8259_H +#define _ASM_POWERPC_I8259_H #include @@ -8,4 +8,4 @@ extern struct hw_interrupt_type i8259_pic; extern void i8259_init(long intack_addr); extern int i8259_irq(struct pt_regs *regs); -#endif /* _PPC_KERNEL_i8259_H */ +#endif /* _ASM_POWERPC_I8259_H */ From 8d66912c3d12df45a59d4e2a66b5ae622e3524b7 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:33:08 +1000 Subject: [PATCH 0358/1939] powerpc: Remove 83xx from arch/powerpc/platforms/Makefile for now Since we don't have an 83xx directory or a 83xx/Makefile, having 83xx in causes make clean to fail. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 181ae612b2d3..da744d5e52fd 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -2,7 +2,6 @@ ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_PPC_PMAC) += powermac/ endif obj-$(CONFIG_4xx) += 4xx/ -obj-$(CONFIG_83xx) += 83xx/ obj-$(CONFIG_85xx) += 85xx/ obj-$(CONFIG_PPC_PSERIES) += pseries/ obj-$(CONFIG_PPC_ISERIES) += iseries/ From 60a3d741780a883f4ce10c0fab99e8542ec65e04 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:46:10 +1000 Subject: [PATCH 0359/1939] powerpc: Merged asm/xmon.h Xmon itself isn't merged yet, though. Signed-off-by: Paul Mackerras --- include/asm-powerpc/xmon.h | 12 ++++++++++++ include/asm-ppc/xmon.h | 17 ----------------- 2 files changed, 12 insertions(+), 17 deletions(-) create mode 100644 include/asm-powerpc/xmon.h delete mode 100644 include/asm-ppc/xmon.h diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h new file mode 100644 index 000000000000..ca5f33277e0c --- /dev/null +++ b/include/asm-powerpc/xmon.h @@ -0,0 +1,12 @@ +#ifndef __PPC_XMON_H +#define __PPC_XMON_H +#ifdef __KERNEL__ + +struct pt_regs; + +extern void xmon(struct pt_regs *excp); +extern void xmon_printf(const char *fmt, ...); +extern void xmon_init(int); + +#endif +#endif diff --git a/include/asm-ppc/xmon.h b/include/asm-ppc/xmon.h deleted file mode 100644 index 042b83e6680d..000000000000 --- a/include/asm-ppc/xmon.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __PPC_XMON_H -#define __PPC_XMON_H -#ifdef __KERNEL__ - -struct pt_regs; - -extern void xmon(struct pt_regs *excp); -extern void xmon_printf(const char *fmt, ...); -extern void xmon_map_scc(void); -extern int xmon_bpt(struct pt_regs *regs); -extern int xmon_sstep(struct pt_regs *regs); -extern int xmon_iabr_match(struct pt_regs *regs); -extern int xmon_dabr_match(struct pt_regs *regs); -extern void (*xmon_fault_handler)(struct pt_regs *regs); - -#endif -#endif From abc244dd855a8013db8c850c21811c12a22b608a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 09:47:23 +1000 Subject: [PATCH 0360/1939] powerpc: Remove xmon.h include from arch/powerpc/platforms/powermac/pic.c ... since it isn't needed. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 682fe8b6e025..58017d18db70 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include From 68399bb5080c1d96f2110b0a040b39d3ccd7a18a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 11 Oct 2005 01:44:14 -0400 Subject: [PATCH 0361/1939] [libata pdc_adma] license update, minor cleanup from me: change from OSL+GPL to GPL (with approval) from Mark: Gets rid of an unneeded control bit, slightly increasing throughput. --- drivers/scsi/pdc_adma.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index ce006a5b4533..53b8db4be1a9 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -5,21 +5,24 @@ * * Copyright 2005 Mark Lord * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. + * 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.* * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. * * Supports ATA disks in single-packet ADMA mode. * Uses PIO for everything else. @@ -76,7 +79,6 @@ enum { aNIEN = (1 << 8), /* irq mask: 1==masked */ aGO = (1 << 7), /* packet trigger ("Go!") */ aRSTADM = (1 << 5), /* ADMA logic reset */ - aAUTEN = (1 << 3), /* packet trigger ("Go!") */ aRSTA = (1 << 2), /* ATA hard reset */ aPIOMD4 = 0x0003, /* PIO mode 4 */ @@ -415,7 +417,7 @@ static inline void adma_packet_start(struct ata_queued_cmd *qc) VPRINTK("ENTER, ap %p\n", ap); /* fire up the ADMA engine */ - writew(aPIOMD4 | aGO | aAUTEN, chan + ADMA_CONTROL); + writew(aPIOMD4 | aGO, chan + ADMA_CONTROL); } static int adma_qc_issue(struct ata_queued_cmd *qc) From cc5aa206d2c853929ce67d8f5ebb57cd1c7fd413 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 17:35:20 +1000 Subject: [PATCH 0362/1939] powerpc: Remove debug messages from setup_64.c A bunch of printks were left in arch/powerpc/kernel/setup_64.c from when I was chasing a bug. This removes them. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_64.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 212b00823f82..4fcf67575cbb 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -567,14 +567,11 @@ void __init setup_system(void) */ rtas_initialize(); #endif /* CONFIG_PPC_RTAS */ - printk("%s:%d rtas.dev=%p (@ %p)\n", __FILE__, __LINE__, rtas.dev, - &rtas.dev); /* * Check if we have an initrd provided via the device-tree */ check_for_initrd(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* * Do some platform specific early initializations, that includes @@ -582,14 +579,12 @@ void __init setup_system(void) * related options that will be used by finish_device_tree() */ ppc_md.init_early(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* * "Finish" the device-tree, that is do the actual parsing of * some of the properties like the interrupt map */ finish_device_tree(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* * Initialize xmon @@ -597,31 +592,26 @@ void __init setup_system(void) #ifdef CONFIG_XMON_DEFAULT xmon_init(1); #endif - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* * Register early console */ register_early_udbg_console(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* Save unparsed command line copy for /proc/cmdline */ strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); parse_early_param(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); #ifdef CONFIG_SMP /* * iSeries has already initialized the cpu maps at this point. */ setup_cpu_maps(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* Release secondary cpus out of their spinloops at 0x60 now that * we can map physical -> logical CPU ids */ smp_release_cpus(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); #endif printk("Starting Linux PPC64 %s\n", system_utsname.version); @@ -641,10 +631,8 @@ void __init setup_system(void) printk("htab_address = 0x%p\n", htab_address); printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); printk("-----------------------------------------------------\n"); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); mm_init_ppc64(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); DBG(" <- setup_system()\n"); } @@ -1016,7 +1004,6 @@ void __init setup_arch(char **cmdline_p) { extern void do_init_bootmem(void); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); ppc64_boot_msg(0x12, "Setup Arch"); *cmdline_p = cmd_line; @@ -1031,7 +1018,6 @@ void __init setup_arch(char **cmdline_p) /* reboot on panic */ panic_timeout = 180; - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); if (ppc_md.panic) notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); @@ -1044,14 +1030,12 @@ void __init setup_arch(char **cmdline_p) irqstack_early_init(); emergency_stack_init(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); stabs_alloc(); /* set up the bootmem stuff with available memory */ do_init_bootmem(); sparse_init(); - printk("%s:%d rtas.dev=%p\n", __FILE__, __LINE__, rtas.dev); /* initialize the syscall map in systemcfg */ setup_syscall_map(); From 35d81a4bfe28a6ea81c9f67c9ce40543124ded0b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 22:03:09 +1000 Subject: [PATCH 0363/1939] ppc: Adapt to asm-powerpc/irq.h irq_canonicalize changes Now instead of having a ppc_md function, we just have a variable which says whether to do the i8259 irq canonicalization or not, and set that variable on the platforms that need that. It looks to me that radstone_ppc7d was trying to use irq canonicalization for something else in a broken kind of way - it will need to be fixed properly. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/setup.c | 5 +++++ arch/ppc/platforms/chestnut.c | 1 - arch/ppc/platforms/chrp_setup.c | 10 +--------- arch/ppc/platforms/gemini_setup.c | 1 - arch/ppc/platforms/lopec.c | 11 +---------- arch/ppc/platforms/pmac_setup.c | 1 - arch/ppc/platforms/pplus.c | 10 +--------- arch/ppc/platforms/prep_setup.c | 15 +-------------- arch/ppc/platforms/radstone_ppc7d.c | 1 + arch/ppc/platforms/sandpoint.c | 11 +---------- arch/ppc/syslib/m8xx_setup.c | 1 - 11 files changed, 11 insertions(+), 56 deletions(-) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 62022eacf63e..fae6335193ef 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -87,6 +87,11 @@ extern void chrp_init(unsigned long r3, unsigned long r4, dev_t boot_dev; #endif /* CONFIG_PPC_MULTIPLATFORM */ +#ifdef __DO_IRQ_CANON +int ppc_do_canonicalize_irqs; +EXPORT_SYMBOL(ppc_do_canonicalize_irqs); +#endif + #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY = 0x54; #endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c index 7786818bd9d0..b3d3bdb3936b 100644 --- a/arch/ppc/platforms/chestnut.c +++ b/arch/ppc/platforms/chestnut.c @@ -542,7 +542,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = chestnut_setup_arch; ppc_md.show_cpuinfo = chestnut_show_cpuinfo; - ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = mv64360_init_irq; ppc_md.get_irq = mv64360_get_irq; ppc_md.init = NULL; diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index 47b154c27617..a0cf1b6fdbfe 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -337,14 +337,6 @@ chrp_halt(void) chrp_power_off(); } -u_int -chrp_irq_canonicalize(u_int irq) -{ - if (irq == 2) - return 9; - return irq; -} - /* * Finds the open-pic node and sets OpenPIC_Addr based on its reg property. * Then checks if it has an interrupt-ranges property. If it does then @@ -500,6 +492,7 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; isa_io_base = CHRP_ISA_IO_BASE; /* default value */ + ppc_do_canonicalize_irqs = 1; if (root) machine = get_property(root, "model", NULL); @@ -518,7 +511,6 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.show_percpuinfo = of_show_percpuinfo; ppc_md.show_cpuinfo = chrp_show_cpuinfo; - ppc_md.irq_canonicalize = chrp_irq_canonicalize; ppc_md.init_IRQ = chrp_init_IRQ; if (_chrp_type == _CHRP_Pegasos) ppc_md.get_irq = i8259_irq; diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c index e391e52383c7..a8ed5c0a2980 100644 --- a/arch/ppc/platforms/gemini_setup.c +++ b/arch/ppc/platforms/gemini_setup.c @@ -556,7 +556,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = gemini_setup_arch; ppc_md.show_cpuinfo = gemini_show_cpuinfo; - ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = gemini_init_IRQ; ppc_md.get_irq = openpic_get_irq; ppc_md.init = NULL; diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c index a5569525e0af..800c56a07a97 100644 --- a/arch/ppc/platforms/lopec.c +++ b/arch/ppc/platforms/lopec.c @@ -144,15 +144,6 @@ lopec_show_cpuinfo(struct seq_file *m) return 0; } -static u32 -lopec_irq_canonicalize(u32 irq) -{ - if (irq == 2) - return 9; - else - return irq; -} - static void lopec_restart(char *cmd) { @@ -379,10 +370,10 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ISA_DMA_THRESHOLD = 0x00ffffff; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; + ppc_do_canonicalize_irqs = 1; ppc_md.setup_arch = lopec_setup_arch; ppc_md.show_cpuinfo = lopec_show_cpuinfo; - ppc_md.irq_canonicalize = lopec_irq_canonicalize; ppc_md.init_IRQ = lopec_init_IRQ; ppc_md.get_irq = openpic_get_irq; diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index e6a12182bfbb..8e7b79b110e7 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -662,7 +662,6 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = pmac_setup_arch; ppc_md.show_cpuinfo = pmac_show_cpuinfo; ppc_md.show_percpuinfo = pmac_show_percpuinfo; - ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = pmac_pic_init; ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c index 65705c911795..93e9c7b889f7 100644 --- a/arch/ppc/platforms/pplus.c +++ b/arch/ppc/platforms/pplus.c @@ -647,14 +647,6 @@ static void pplus_power_off(void) pplus_halt(); } -static unsigned int pplus_irq_canonicalize(u_int irq) -{ - if (irq == 2) - return 9; - else - return irq; -} - static void __init pplus_init_IRQ(void) { int i; @@ -873,10 +865,10 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ISA_DMA_THRESHOLD = 0x00ffffff; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; + ppc_do_canonicalize_irqs = 1; ppc_md.setup_arch = pplus_setup_arch; ppc_md.show_cpuinfo = pplus_show_cpuinfo; - ppc_md.irq_canonicalize = pplus_irq_canonicalize; ppc_md.init_IRQ = pplus_init_IRQ; /* this gets changed later on if we have an OpenPIC -- Cort */ ppc_md.get_irq = i8259_irq; diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 8bc734fe6682..490ff175c902 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -942,19 +942,6 @@ prep_calibrate_decr(void) todc_calibrate_decr(); } -static unsigned int -prep_irq_canonicalize(u_int irq) -{ - if (irq == 2) - { - return 9; - } - else - { - return irq; - } -} - static void __init prep_init_IRQ(void) { @@ -1110,6 +1097,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ISA_DMA_THRESHOLD = 0x00ffffff; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; + ppc_do_canonicalize_irqs = 1; /* figure out what kind of prep workstation we are */ if (have_residual_data) { @@ -1136,7 +1124,6 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = prep_setup_arch; ppc_md.show_percpuinfo = prep_show_percpuinfo; ppc_md.show_cpuinfo = NULL; /* set in prep_setup_arch() */ - ppc_md.irq_canonicalize = prep_irq_canonicalize; ppc_md.init_IRQ = prep_init_IRQ; /* this gets changed later on if we have an OpenPIC -- Cort */ ppc_md.get_irq = i8259_irq; diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 06ec30f7e2f4..3cf74aa5fed0 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -1426,6 +1426,7 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = ppc7d_setup_arch; ppc_md.init = ppc7d_init2; ppc_md.show_cpuinfo = ppc7d_show_cpuinfo; + /* XXX this is broken... */ ppc_md.irq_canonicalize = ppc7d_irq_canonicalize; ppc_md.init_IRQ = ppc7d_init_irq; ppc_md.get_irq = ppc7d_get_irq; diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c index 21e31346b12b..84c96cb9ac2b 100644 --- a/arch/ppc/platforms/sandpoint.c +++ b/arch/ppc/platforms/sandpoint.c @@ -509,15 +509,6 @@ sandpoint_init_IRQ(void) i8259_init(0xfef00000); } -static u32 -sandpoint_irq_canonicalize(u32 irq) -{ - if (irq == 2) - return 9; - else - return irq; -} - static unsigned long __init sandpoint_find_end_of_memory(void) { @@ -728,10 +719,10 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ISA_DMA_THRESHOLD = 0x00ffffff; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; + ppc_do_canonicalize_irqs = 1; ppc_md.setup_arch = sandpoint_setup_arch; ppc_md.show_cpuinfo = sandpoint_show_cpuinfo; - ppc_md.irq_canonicalize = sandpoint_irq_canonicalize; ppc_md.init_IRQ = sandpoint_init_IRQ; ppc_md.get_irq = openpic_get_irq; diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index 4c888da89b3c..c88e2d4dceb7 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -406,7 +406,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = m8xx_setup_arch; ppc_md.show_percpuinfo = m8xx_show_percpuinfo; - ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = m8xx_init_IRQ; ppc_md.get_irq = m8xx_get_irq; ppc_md.init = NULL; From fd582ec88eb8d2d907876603e4ecebe6eab330d9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 22:08:12 +1000 Subject: [PATCH 0364/1939] ppc: Various minor compile fixes This fixes up a variety of minor problems in compiling with ARCH=ppc arising from using the merged versions of various header files. A lot of the changes are just adding #include to files that use ppc_md or smp_ops_t. This also arranges for us to use semaphore.c, vecemu.c, vector.S and fpu.S from arch/powerpc/kernel when compiling with ARCH=ppc. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 12 ++++++++++-- arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/platforms/4xx/Makefile | 1 + arch/powerpc/platforms/85xx/Makefile | 1 + arch/ppc/Makefile | 5 +++-- arch/ppc/kernel/Makefile | 7 +------ arch/ppc/kernel/asm-offsets.c | 1 + arch/ppc/kernel/head.S | 2 +- arch/ppc/kernel/pci.c | 4 ++++ arch/ppc/kernel/process.c | 6 ++++-- arch/ppc/kernel/setup.c | 7 ++++++- arch/ppc/kernel/traps.c | 16 ++++++++++++++++ arch/ppc/platforms/chrp_smp.c | 1 + arch/ppc/platforms/ev64360.c | 1 + arch/ppc/platforms/gemini_setup.c | 1 + arch/ppc/platforms/katana.c | 1 + arch/ppc/platforms/lite5200.c | 1 + arch/ppc/platforms/pal4_setup.c | 1 + arch/ppc/platforms/pmac_pic.c | 1 + arch/ppc/syslib/gt64260_pic.c | 1 + arch/ppc/syslib/mpc52xx_pci.c | 1 + arch/ppc/syslib/mpc83xx_devices.c | 1 + arch/ppc/syslib/mv64360_pic.c | 1 + arch/ppc/syslib/mv64x60_dbg.c | 1 + arch/ppc/syslib/open_pic.c | 1 + arch/ppc/syslib/open_pic2.c | 1 + arch/ppc/syslib/ppc403_pic.c | 1 + arch/ppc/syslib/ppc4xx_pic.c | 1 + arch/ppc/syslib/ppc83xx_setup.c | 1 + arch/ppc/syslib/ppc85xx_setup.c | 1 + arch/ppc/syslib/pq2_devices.c | 1 + arch/ppc/syslib/xilinx_pic.c | 1 + arch/ppc/xmon/start.c | 3 ++- include/asm-powerpc/reg.h | 4 ++++ include/asm-ppc/system.h | 3 +++ 35 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 arch/powerpc/platforms/4xx/Makefile create mode 100644 arch/powerpc/platforms/85xx/Makefile diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 47a8eb6e7e39..e1db51e6f23a 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o traps.o +obj-y := semaphore.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o @@ -28,7 +28,7 @@ extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y += process.o init_task.o \ - prom.o systbl.o + prom.o systbl.o traps.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o @@ -39,4 +39,12 @@ ifeq ($(CONFIG_PPC_ISERIES),y) $(obj)/head_64.o: $(obj)/lparmap.s AFLAGS_head_64.o += -I$(obj) endif + +else +# stuff used from here for ARCH=ppc or ARCH=ppc64 +obj-$(CONFIG_PPC64) += traps.o + +fpux-$(CONFIG_PPC32) += fpu.o +extra-$(CONFIG_PPC_FPU) += $(fpux-y) + endif diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ddf0c81e1958..b0d6a7cd85e9 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -252,6 +252,7 @@ int main(void) DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); DEFINE(pbe_next, offsetof(struct pbe, next)); + DEFINE(TASK_SIZE, TASK_SIZE); DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); #else /* CONFIG_PPC64 */ /* systemcfg offsets for use by vdso */ diff --git a/arch/powerpc/platforms/4xx/Makefile b/arch/powerpc/platforms/4xx/Makefile new file mode 100644 index 000000000000..79ff6b1e887c --- /dev/null +++ b/arch/powerpc/platforms/4xx/Makefile @@ -0,0 +1 @@ +# empty makefile so make clean works \ No newline at end of file diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile new file mode 100644 index 000000000000..6407197ffd89 --- /dev/null +++ b/arch/powerpc/platforms/85xx/Makefile @@ -0,0 +1 @@ +# empty makefile so make clean works diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 90c750227ed9..aedc9ae13b2a 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -57,9 +57,10 @@ head-$(CONFIG_FSL_BOOKE) := arch/ppc/kernel/head_fsl_booke.o head-$(CONFIG_6xx) += arch/ppc/kernel/idle_6xx.o head-$(CONFIG_POWER4) += arch/ppc/kernel/idle_power4.o -head-$(CONFIG_PPC_FPU) += arch/ppc/kernel/fpu.o +head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o -core-y += arch/ppc/kernel/ arch/ppc/platforms/ \ +core-y += arch/ppc/kernel/ arch/powerpc/kernel/ \ + arch/ppc/platforms/ \ arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/ core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 74b30978619f..59b6b62d1120 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -10,12 +10,11 @@ extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_POWER4) += idle_power4.o -extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ - semaphore.o syscalls.o setup.o \ + syscalls.o setup.o \ cputable.o ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o @@ -26,7 +25,6 @@ obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o obj-$(CONFIG_TAU) += temp.o -obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o ifndef CONFIG_E200 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o endif @@ -37,9 +35,6 @@ obj-$(CONFIG_8xx) += softemu8xx.o endif # These are here while we do the architecture merge -vecemu-y += ../../powerpc/kernel/vecemu.o -vector-y += ../../powerpc/kernel/vector.o -fpu-y += ../../powerpc/kernel/fpu.o else obj-y := irq.o idle.o time.o \ diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index d9ad1d776d0e..7972db1f6570 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -141,6 +141,7 @@ main(void) DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); DEFINE(pbe_next, offsetof(struct pbe, next)); + DEFINE(TASK_SIZE, TASK_SIZE); DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); return 0; } diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 2c3a1d34e3c7..5b43987a943b 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -467,7 +467,7 @@ FPUnavailable: EXCEPTION_PROLOG bne load_up_fpu /* if from user, just load it up */ addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x800, KernelFP) + EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) /* Decrementer */ EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 6600fd485b50..163276be7cc5 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1034,6 +1034,10 @@ static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *att } static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); +#else /* CONFIG_PPC_OF */ +void pcibios_make_OF_bus_map(void) +{ +} #endif /* CONFIG_PPC_OF */ /* Add sysfs properties */ diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 82de66e4db6d..0870e5553453 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -557,14 +557,16 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); } -int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, +int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, struct pt_regs *regs) { CHECK_FULL_REGS(regs); return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); } -int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, +int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6, struct pt_regs *regs) { CHECK_FULL_REGS(regs); diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index fae6335193ef..6bcb85d2b7fd 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -87,6 +87,9 @@ extern void chrp_init(unsigned long r3, unsigned long r4, dev_t boot_dev; #endif /* CONFIG_PPC_MULTIPLATFORM */ +int have_of; +EXPORT_SYMBOL(have_of); + #ifdef __DO_IRQ_CANON int ppc_do_canonicalize_irqs; EXPORT_SYMBOL(ppc_do_canonicalize_irqs); @@ -420,6 +423,8 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, } #endif + have_of = 1; + /* prom_init has already been called from __start */ if (boot_infos) relocate_nodes(); @@ -735,7 +740,7 @@ void __init setup_arch(char **cmdline_p) #endif #ifdef CONFIG_XMON - xmon_map_scc(); + xmon_init(1); if (strstr(cmd_line, "xmon")) xmon(NULL); #endif /* CONFIG_XMON */ diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 26606aa33de6..3145e9773db9 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -44,6 +44,11 @@ #include #ifdef CONFIG_XMON +extern int xmon_bpt(struct pt_regs *regs); +extern int xmon_sstep(struct pt_regs *regs); +extern int xmon_iabr_match(struct pt_regs *regs); +extern int xmon_dabr_match(struct pt_regs *regs); + void (*debugger)(struct pt_regs *regs) = xmon; int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; @@ -814,6 +819,17 @@ void TAUException(struct pt_regs *regs) } #endif /* CONFIG_INT_TAU */ +/* + * FP unavailable trap from kernel - print a message, but let + * the task use FP in the kernel until it returns to user mode. + */ +void kernel_fp_unavailable_exception(struct pt_regs *regs) +{ + regs->msr |= MSR_FP; + printk(KERN_ERR "floating point used in kernel (task=%p, pc=%lx)\n", + current, regs->nip); +} + void altivec_unavailable_exception(struct pt_regs *regs) { static int kernel_altivec_count; diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c index dc62e3209443..97e539557ecb 100644 --- a/arch/ppc/platforms/chrp_smp.c +++ b/arch/ppc/platforms/chrp_smp.c @@ -31,6 +31,7 @@ #include #include #include +#include extern unsigned long smp_chrp_cpu_nr; diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c index 9811a8a52c25..53388a1c334f 100644 --- a/arch/ppc/platforms/ev64360.c +++ b/arch/ppc/platforms/ev64360.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #define BOARD_VENDOR "Marvell" diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c index a8ed5c0a2980..a2a09dc4b5e2 100644 --- a/arch/ppc/platforms/gemini_setup.c +++ b/arch/ppc/platforms/gemini_setup.c @@ -36,6 +36,7 @@ #include #include #include +#include void gemini_find_bridges(void); static int gemini_get_clock_speed(void); diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index 2b53afae0e9c..3eb611e23f69 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -42,6 +42,7 @@ #include #include #include +#include static struct mv64x60_handle bh; static katana_id_t katana_id; diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c index b604cf8b3cae..d44cc991179f 100644 --- a/arch/ppc/platforms/lite5200.c +++ b/arch/ppc/platforms/lite5200.c @@ -35,6 +35,7 @@ #include #include #include +#include #include diff --git a/arch/ppc/platforms/pal4_setup.c b/arch/ppc/platforms/pal4_setup.c index 12446b93e38c..f93a3f871932 100644 --- a/arch/ppc/platforms/pal4_setup.c +++ b/arch/ppc/platforms/pal4_setup.c @@ -28,6 +28,7 @@ #include #include #include +#include #include diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c index 3349cfb624a0..9f2d95ea8564 100644 --- a/arch/ppc/platforms/pmac_pic.c +++ b/arch/ppc/platforms/pmac_pic.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "pmac_pic.h" diff --git a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c index 44aa87385451..f97b3a9abd1e 100644 --- a/arch/ppc/syslib/gt64260_pic.c +++ b/arch/ppc/syslib/gt64260_pic.c @@ -45,6 +45,7 @@ #include #include #include +#include #define CPU_INTR_STR "gt64260 cpu interface error" #define PCI0_INTR_STR "gt64260 pci 0 error" diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c index 59cf3e8bd1a0..02edff8befd0 100644 --- a/arch/ppc/syslib/mpc52xx_pci.c +++ b/arch/ppc/syslib/mpc52xx_pci.c @@ -21,6 +21,7 @@ #include "mpc52xx_pci.h" #include +#include static int diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c index 95b3b8a7f0ba..dbf8acac507f 100644 --- a/arch/ppc/syslib/mpc83xx_devices.c +++ b/arch/ppc/syslib/mpc83xx_devices.c @@ -21,6 +21,7 @@ #include #include #include +#include /* We use offsets for IORESOURCE_MEM since we do not know at compile time * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c index 8356da4678a2..58b0aa813e85 100644 --- a/arch/ppc/syslib/mv64360_pic.c +++ b/arch/ppc/syslib/mv64360_pic.c @@ -48,6 +48,7 @@ #include #include #include +#include #ifdef CONFIG_IRQ_ALL_CPUS #error "The mv64360 does not support distribution of IRQs on all CPUs" diff --git a/arch/ppc/syslib/mv64x60_dbg.c b/arch/ppc/syslib/mv64x60_dbg.c index 2927c7adf5e5..fa5b2e45e0ca 100644 --- a/arch/ppc/syslib/mv64x60_dbg.c +++ b/arch/ppc/syslib/mv64x60_dbg.c @@ -24,6 +24,7 @@ #include #include #include +#include #if defined(CONFIG_SERIAL_TEXT_DEBUG) diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 53da58523e39..df0f76dc0ce3 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "open_pic_defs.h" diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index 9a7e8748e2b2..ef365cc04bd9 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "open_pic_defs.h" diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c index ce4d1deb86e9..c46043c47225 100644 --- a/arch/ppc/syslib/ppc403_pic.c +++ b/arch/ppc/syslib/ppc403_pic.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Function Prototypes */ diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index 40086212b9c3..0b435633a0d1 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -25,6 +25,7 @@ #include #include #include +#include /* See comment in include/arch-ppc/ppc4xx_pic.h * for more info about these two variables diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c index 890484e576e7..4da168a6ad03 100644 --- a/arch/ppc/syslib/ppc83xx_setup.c +++ b/arch/ppc/syslib/ppc83xx_setup.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #if defined(CONFIG_PCI) diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index 832b8bf99ae7..de2f90576577 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -29,6 +29,7 @@ #include #include #include +#include #include diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c index 1d3869768f96..6f88ba93412b 100644 --- a/arch/ppc/syslib/pq2_devices.c +++ b/arch/ppc/syslib/pq2_devices.c @@ -18,6 +18,7 @@ #include #include #include +#include struct platform_device ppc_sys_platform_devices[] = { [MPC82xx_CPM_FCC1] = { diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c index 2cbcad278cef..47f04c71fe9c 100644 --- a/arch/ppc/syslib/xilinx_pic.c +++ b/arch/ppc/syslib/xilinx_pic.c @@ -17,6 +17,7 @@ #include #include #include +#include /* No one else should require these constants, so define them locally here. */ #define ISR 0 /* Interrupt Status Register */ diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 507d4eeffe07..98612d420346 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -478,8 +478,9 @@ void *xmon_stdout; void *xmon_stderr; void -xmon_init(void) +xmon_init(int arg) { + xmon_map_scc(); } int diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index ff619630dff9..06a1f0f2db21 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -74,7 +74,9 @@ #define MSR_DR __MASK(MSR_DR_LG) /* Data Relocate */ #define MSR_PE __MASK(MSR_PE_LG) /* Protection Enable */ #define MSR_PX __MASK(MSR_PX_LG) /* Protection Exclusive Mode */ +#ifndef MSR_PMM #define MSR_PMM __MASK(MSR_PMM_LG) /* Performance monitor */ +#endif #define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */ #define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */ @@ -87,11 +89,13 @@ #else /* 32-bit */ /* Default MSR for kernel mode. */ +#ifndef MSR_KERNEL /* reg_booke.h also defines this */ #ifdef CONFIG_APUS_FAST_EXCEPT #define MSR_KERNEL (MSR_ME|MSR_IP|MSR_RI|MSR_IR|MSR_DR) #else #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) #endif +#endif #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) #endif diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 6a49b138c218..af93ff04c53f 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -77,6 +77,7 @@ extern void enable_kernel_fp(void); extern void enable_kernel_altivec(void); extern void giveup_altivec(struct task_struct *); extern void load_up_altivec(struct task_struct *); +extern int emulate_altivec(struct pt_regs *); extern void giveup_spe(struct task_struct *); extern void load_up_spe(struct task_struct *); extern int fix_alignment(struct pt_regs *); @@ -89,6 +90,8 @@ extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); extern void bad_page_fault(struct pt_regs *, unsigned long, int); extern int die(const char *, struct pt_regs *, long); extern void _exception(int, struct pt_regs *, int, unsigned long); +void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); + #ifdef CONFIG_BOOKE_WDT extern u32 booke_wdt_enabled; extern u32 booke_wdt_period; From 3abec857a0f7491b397a97337cc057b84a1d637a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 22:09:48 +1000 Subject: [PATCH 0365/1939] ppc64: Use merged versions of init_task.c and process.c. These two files are now built in arch/powerpc/kernel instead of arch/ppc64/kernel. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/ppc64/kernel/Makefile | 4 +- arch/ppc64/kernel/init_task.c | 36 -- arch/ppc64/kernel/process.c | 713 ---------------------------------- include/asm-ppc64/system.h | 4 + 5 files changed, 7 insertions(+), 752 deletions(-) delete mode 100644 arch/ppc64/kernel/init_task.c delete mode 100644 arch/ppc64/kernel/process.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index e1db51e6f23a..931795380978 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -42,7 +42,7 @@ endif else # stuff used from here for ARCH=ppc or ARCH=ppc64 -obj-$(CONFIG_PPC64) += traps.o +obj-$(CONFIG_PPC64) += traps.o process.o init_task.o fpux-$(CONFIG_PPC32) += fpu.o extra-$(CONFIG_PPC_FPU) += $(fpux-y) diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 5c598892f891..5569ea7e6830 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -8,10 +8,10 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds obj-y := setup.o entry.o irq.o idle.o dma.o \ - time.o process.o signal.o syscalls.o misc.o ptrace.o \ + time.o signal.o syscalls.o misc.o ptrace.o \ align.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ - ptrace32.o signal32.o rtc.o init_task.o \ + ptrace32.o signal32.o rtc.o \ cputable.o cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o prom.o obj-y += vdso32/ vdso64/ diff --git a/arch/ppc64/kernel/init_task.c b/arch/ppc64/kernel/init_task.c deleted file mode 100644 index 941043ae040f..000000000000 --- a/arch/ppc64/kernel/init_task.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static struct fs_struct init_fs = INIT_FS; -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); - -EXPORT_SYMBOL(init_mm); - -/* - * Initial thread structure. - * - * We need to make sure that this is 16384-byte aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c deleted file mode 100644 index 887005358eb1..000000000000 --- a/arch/ppc64/kernel/process.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * linux/arch/ppc64/kernel/process.c - * - * Derived from "arch/i386/kernel/process.c" - * Copyright (C) 1995 Linus Torvalds - * - * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and - * Paul Mackerras (paulus@cs.anu.edu.au) - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * 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 -#include -#include -#include - -#ifndef CONFIG_SMP -struct task_struct *last_task_used_math = NULL; -struct task_struct *last_task_used_altivec = NULL; -#endif - -/* - * Make sure the floating-point register state in the - * the thread_struct is up to date for task tsk. - */ -void flush_fp_to_thread(struct task_struct *tsk) -{ - if (tsk->thread.regs) { - /* - * We need to disable preemption here because if we didn't, - * another process could get scheduled after the regs->msr - * test but before we have finished saving the FP registers - * to the thread_struct. That process could take over the - * FPU, and then when we get scheduled again we would store - * bogus values for the remaining FP registers. - */ - preempt_disable(); - if (tsk->thread.regs->msr & MSR_FP) { -#ifdef CONFIG_SMP - /* - * This should only ever be called for current or - * for a stopped child process. Since we save away - * the FP register state on context switch on SMP, - * there is something wrong if a stopped child appears - * to still have its FP state in the CPU registers. - */ - BUG_ON(tsk != current); -#endif - giveup_fpu(current); - } - preempt_enable(); - } -} - -void enable_kernel_fp(void) -{ - WARN_ON(preemptible()); - -#ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); - else - giveup_fpu(NULL); /* just enables FP for kernel */ -#else - giveup_fpu(last_task_used_math); -#endif /* CONFIG_SMP */ -} -EXPORT_SYMBOL(enable_kernel_fp); - -int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) -{ - if (!tsk->thread.regs) - return 0; - flush_fp_to_thread(current); - - memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); - - return 1; -} - -#ifdef CONFIG_ALTIVEC - -void enable_kernel_altivec(void) -{ - WARN_ON(preemptible()); - -#ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); - else - giveup_altivec(NULL); /* just enables FP for kernel */ -#else - giveup_altivec(last_task_used_altivec); -#endif /* CONFIG_SMP */ -} -EXPORT_SYMBOL(enable_kernel_altivec); - -/* - * Make sure the VMX/Altivec register state in the - * the thread_struct is up to date for task tsk. - */ -void flush_altivec_to_thread(struct task_struct *tsk) -{ - if (tsk->thread.regs) { - preempt_disable(); - if (tsk->thread.regs->msr & MSR_VEC) { -#ifdef CONFIG_SMP - BUG_ON(tsk != current); -#endif - giveup_altivec(current); - } - preempt_enable(); - } -} - -int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) -{ - flush_altivec_to_thread(current); - memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); - return 1; -} - -#endif /* CONFIG_ALTIVEC */ - -static void set_dabr_spr(unsigned long val) -{ - mtspr(SPRN_DABR, val); -} - -int set_dabr(unsigned long dabr) -{ - int ret = 0; - - if (firmware_has_feature(FW_FEATURE_XDABR)) { - /* We want to catch accesses from kernel and userspace */ - unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; - ret = plpar_set_xdabr(dabr, flags); - } else if (firmware_has_feature(FW_FEATURE_DABR)) { - ret = plpar_set_dabr(dabr); - } else { - set_dabr_spr(dabr); - } - - return ret; -} - -DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); -static DEFINE_PER_CPU(unsigned long, current_dabr); - -struct task_struct *__switch_to(struct task_struct *prev, - struct task_struct *new) -{ - struct thread_struct *new_thread, *old_thread; - unsigned long flags; - struct task_struct *last; - -#ifdef CONFIG_SMP - /* avoid complexity of lazy save/restore of fpu - * by just saving it every time we switch out if - * this task used the fpu during the last quantum. - * - * If it tries to use the fpu again, it'll trap and - * reload its fp regs. So we don't have to do a restore - * every switch, just a save. - * -- Cort - */ - if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) - giveup_fpu(prev); -#ifdef CONFIG_ALTIVEC - if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) - giveup_altivec(prev); -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ - -#if defined(CONFIG_ALTIVEC) && !defined(CONFIG_SMP) - /* Avoid the trap. On smp this this never happens since - * we don't set last_task_used_altivec -- Cort - */ - if (new->thread.regs && last_task_used_altivec == new) - new->thread.regs->msr |= MSR_VEC; -#endif /* CONFIG_ALTIVEC */ - - if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { - set_dabr(new->thread.dabr); - __get_cpu_var(current_dabr) = new->thread.dabr; - } - - flush_tlb_pending(); - - new_thread = &new->thread; - old_thread = ¤t->thread; - - /* Collect purr utilization data per process and per processor - * wise purr is nothing but processor time base - */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); - long unsigned start_tb, current_tb; - start_tb = old_thread->start_tb; - cu->current_tb = current_tb = mfspr(SPRN_PURR); - old_thread->accum_tb += (current_tb - start_tb); - new_thread->start_tb = current_tb; - } - - local_irq_save(flags); - last = _switch(old_thread, new_thread); - - local_irq_restore(flags); - - return last; -} - -static int instructions_to_print = 16; - -static void show_instructions(struct pt_regs *regs) -{ - int i; - unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 * - sizeof(int)); - - printk("Instruction dump:"); - - for (i = 0; i < instructions_to_print; i++) { - int instr; - - if (!(i % 8)) - printk("\n"); - - if (((REGION_ID(pc) != KERNEL_REGION_ID) && - (REGION_ID(pc) != VMALLOC_REGION_ID)) || - __get_user(instr, (unsigned int *)pc)) { - printk("XXXXXXXX "); - } else { - if (regs->nip == pc) - printk("<%08x> ", instr); - else - printk("%08x ", instr); - } - - pc += sizeof(int); - } - - printk("\n"); -} - -void show_regs(struct pt_regs * regs) -{ - int i; - unsigned long trap; - - printk("NIP: %016lX XER: %08X LR: %016lX CTR: %016lX\n", - regs->nip, (unsigned int)regs->xer, regs->link, regs->ctr); - printk("REGS: %p TRAP: %04lx %s (%s)\n", - regs, regs->trap, print_tainted(), system_utsname.release); - printk("MSR: %016lx EE: %01x PR: %01x FP: %01x ME: %01x " - "IR/DR: %01x%01x CR: %08X\n", - regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, - regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, - regs->msr&MSR_IR ? 1 : 0, - regs->msr&MSR_DR ? 1 : 0, - (unsigned int)regs->ccr); - trap = TRAP(regs); - printk("DAR: %016lx DSISR: %016lx\n", regs->dar, regs->dsisr); - printk("TASK: %p[%d] '%s' THREAD: %p", - current, current->pid, current->comm, current->thread_info); - -#ifdef CONFIG_SMP - printk(" CPU: %d", smp_processor_id()); -#endif /* CONFIG_SMP */ - - for (i = 0; i < 32; i++) { - if ((i % 4) == 0) { - printk("\n" KERN_INFO "GPR%02d: ", i); - } - - printk("%016lX ", regs->gpr[i]); - if (i == 13 && !FULL_REGS(regs)) - break; - } - printk("\n"); - /* - * Lookup NIP late so we have the best change of getting the - * above info out without failing - */ - printk("NIP [%016lx] ", regs->nip); - print_symbol("%s\n", regs->nip); - printk("LR [%016lx] ", regs->link); - print_symbol("%s\n", regs->link); - show_stack(current, (unsigned long *)regs->gpr[1]); - if (!user_mode(regs)) - show_instructions(regs); -} - -void exit_thread(void) -{ - kprobe_flush_task(current); - -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = NULL; -#ifdef CONFIG_ALTIVEC - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ -} - -void flush_thread(void) -{ - struct thread_info *t = current_thread_info(); - - kprobe_flush_task(current); - if (t->flags & _TIF_ABI_PENDING) - t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); - -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = NULL; -#ifdef CONFIG_ALTIVEC - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ - - if (current->thread.dabr) { - current->thread.dabr = 0; - set_dabr(0); - } -} - -void -release_thread(struct task_struct *t) -{ -} - - -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - flush_fp_to_thread(current); - flush_altivec_to_thread(current); -} - -/* - * Copy a thread.. - */ -int -copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, struct task_struct *p, struct pt_regs *regs) -{ - struct pt_regs *childregs, *kregs; - extern void ret_from_fork(void); - unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE; - - /* Copy registers */ - sp -= sizeof(struct pt_regs); - childregs = (struct pt_regs *) sp; - *childregs = *regs; - if ((childregs->msr & MSR_PR) == 0) { - /* for kernel thread, set stackptr in new task */ - childregs->gpr[1] = sp + sizeof(struct pt_regs); - p->thread.regs = NULL; /* no user register state */ - clear_ti_thread_flag(p->thread_info, TIF_32BIT); - } else { - childregs->gpr[1] = usp; - p->thread.regs = childregs; - if (clone_flags & CLONE_SETTLS) { - if (test_thread_flag(TIF_32BIT)) - childregs->gpr[2] = childregs->gpr[6]; - else - childregs->gpr[13] = childregs->gpr[6]; - } - } - childregs->gpr[3] = 0; /* Result from fork() */ - sp -= STACK_FRAME_OVERHEAD; - - /* - * The way this works is that at some point in the future - * some task will call _switch to switch to the new task. - * That will pop off the stack frame created below and start - * the new task running at ret_from_fork. The new task will - * do some house keeping and then return from the fork or clone - * system call, using the stack frame created above. - */ - sp -= sizeof(struct pt_regs); - kregs = (struct pt_regs *) sp; - sp -= STACK_FRAME_OVERHEAD; - p->thread.ksp = sp; - if (cpu_has_feature(CPU_FTR_SLB)) { - unsigned long sp_vsid = get_kernel_vsid(sp); - - sp_vsid <<= SLB_VSID_SHIFT; - sp_vsid |= SLB_VSID_KERNEL; - if (cpu_has_feature(CPU_FTR_16M_PAGE)) - sp_vsid |= SLB_VSID_L; - - p->thread.ksp_vsid = sp_vsid; - } - - /* - * The PPC64 ABI makes use of a TOC to contain function - * pointers. The function (ret_from_except) is actually a pointer - * to the TOC entry. The first entry is a pointer to the actual - * function. - */ - kregs->nip = *((unsigned long *)ret_from_fork); - - return 0; -} - -/* - * Set up a thread for executing a new program - */ -void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp) -{ - unsigned long entry, toc, load_addr = regs->gpr[2]; - - /* fdptr is a relocated pointer to the function descriptor for - * the elf _start routine. The first entry in the function - * descriptor is the entry address of _start and the second - * entry is the TOC value we need to use. - */ - set_fs(USER_DS); - __get_user(entry, (unsigned long __user *)fdptr); - __get_user(toc, (unsigned long __user *)fdptr+1); - - /* Check whether the e_entry function descriptor entries - * need to be relocated before we can use them. - */ - if (load_addr != 0) { - entry += load_addr; - toc += load_addr; - } - - /* - * If we exec out of a kernel thread then thread.regs will not be - * set. Do it now. - */ - if (!current->thread.regs) { - unsigned long childregs = (unsigned long)current->thread_info + - THREAD_SIZE; - childregs -= sizeof(struct pt_regs); - current->thread.regs = (struct pt_regs *)childregs; - } - - regs->nip = entry; - regs->gpr[1] = sp; - regs->gpr[2] = toc; - regs->msr = MSR_USER64; -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); - current->thread.fpscr = 0; -#ifdef CONFIG_ALTIVEC -#ifndef CONFIG_SMP - if (last_task_used_altivec == current) - last_task_used_altivec = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.vr, 0, sizeof(current->thread.vr)); - current->thread.vscr.u[0] = 0; - current->thread.vscr.u[1] = 0; - current->thread.vscr.u[2] = 0; - current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */ - current->thread.vrsave = 0; - current->thread.used_vr = 0; -#endif /* CONFIG_ALTIVEC */ -} -EXPORT_SYMBOL(start_thread); - -int set_fpexc_mode(struct task_struct *tsk, unsigned int val) -{ - struct pt_regs *regs = tsk->thread.regs; - - if (val > PR_FP_EXC_PRECISE) - return -EINVAL; - tsk->thread.fpexc_mode = __pack_fe01(val); - if (regs != NULL && (regs->msr & MSR_FP) != 0) - regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) - | tsk->thread.fpexc_mode; - return 0; -} - -int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) -{ - unsigned int val; - - val = __unpack_fe01(tsk->thread.fpexc_mode); - return put_user(val, (unsigned int __user *) adr); -} - -int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - unsigned long parent_tidptr = 0; - unsigned long child_tidptr = 0; - - if (p2 == 0) - p2 = regs->gpr[1]; /* stack pointer for child */ - - if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | - CLONE_CHILD_CLEARTID)) { - parent_tidptr = p3; - child_tidptr = p5; - if (test_thread_flag(TIF_32BIT)) { - parent_tidptr &= 0xffffffff; - child_tidptr &= 0xffffffff; - } - } - - return do_fork(clone_flags, p2, regs, 0, - (int __user *)parent_tidptr, (int __user *)child_tidptr); -} - -int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); -} - -int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0, - NULL, NULL); -} - -int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) -{ - int error; - char * filename; - - filename = getname((char __user *) a0); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - error = do_execve(filename, (char __user * __user *) a1, - (char __user * __user *) a2, regs); - - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } - putname(filename); - -out: - return error; -} - -static int kstack_depth_to_print = 64; - -static int validate_sp(unsigned long sp, struct task_struct *p, - unsigned long nbytes) -{ - unsigned long stack_page = (unsigned long)p->thread_info; - - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - -#ifdef CONFIG_IRQSTACKS - stack_page = (unsigned long) hardirq_ctx[task_cpu(p)]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - - stack_page = (unsigned long) softirq_ctx[task_cpu(p)]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; -#endif - - return 0; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long ip, sp; - int count = 0; - - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - sp = p->thread.ksp; - if (!validate_sp(sp, p, 112)) - return 0; - - do { - sp = *(unsigned long *)sp; - if (!validate_sp(sp, p, 112)) - return 0; - if (count > 0) { - ip = *(unsigned long *)(sp + 16); - if (!in_sched_functions(ip)) - return ip; - } - } while (count++ < 16); - return 0; -} -EXPORT_SYMBOL(get_wchan); - -void show_stack(struct task_struct *p, unsigned long *_sp) -{ - unsigned long ip, newsp, lr; - int count = 0; - unsigned long sp = (unsigned long)_sp; - int firstframe = 1; - - if (sp == 0) { - if (p) { - sp = p->thread.ksp; - } else { - sp = __get_SP(); - p = current; - } - } - - lr = 0; - printk("Call Trace:\n"); - do { - if (!validate_sp(sp, p, 112)) - return; - - _sp = (unsigned long *) sp; - newsp = _sp[0]; - ip = _sp[2]; - if (!firstframe || ip != lr) { - printk("[%016lx] [%016lx] ", sp, ip); - print_symbol("%s", ip); - if (firstframe) - printk(" (unreliable)"); - printk("\n"); - } - firstframe = 0; - - /* - * See if this is an exception frame. - * We look for the "regshere" marker in the current frame. - */ - if (validate_sp(sp, p, sizeof(struct pt_regs) + 400) - && _sp[12] == 0x7265677368657265ul) { - struct pt_regs *regs = (struct pt_regs *) - (sp + STACK_FRAME_OVERHEAD); - printk("--- Exception: %lx", regs->trap); - print_symbol(" at %s\n", regs->nip); - lr = regs->link; - print_symbol(" LR = %s\n", lr); - firstframe = 1; - } - - sp = newsp; - } while (count++ < kstack_depth_to_print); -} - -void dump_stack(void) -{ - show_stack(current, (unsigned long *)__get_SP()); -} -EXPORT_SYMBOL(dump_stack); diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index c04d62c592a6..d1e00933354c 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -131,6 +131,10 @@ static inline void flush_altivec_to_thread(struct task_struct *t) } #endif +static inline void flush_spe_to_thread(struct task_struct *t) +{ +} + extern int mem_init_done; /* set on boot once kmalloc can be called */ /* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */ From f696012330a67a60a9822ed48d1e9ecba73b4f18 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 11 Oct 2005 22:10:49 +1000 Subject: [PATCH 0366/1939] ppc64: compile fix - define execve in misc.S This used to be inline in include/asm-ppc64/unistd.h, but isn't inline in the merged include/asm-powerpc/unistd.h, so we need a definition here. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/misc.S | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index d069bbd7f81f..f9f2131d2fb5 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -740,6 +740,13 @@ _GLOBAL(giveup_altivec) _GLOBAL(__setup_cpu_power3) blr +_GLOBAL(execve) + li r0,__NR_execve + sc + bnslr + neg r3,r3 + blr + /* kexec_wait(phys_cpu) * * wait for the flag to change, indicating this kernel is going away but From 29b8990513b077dc388b0756acd31465e5c21441 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 11 Oct 2005 14:54:42 +0100 Subject: [PATCH 0367/1939] NTFS: In attrib.c::ntfs_attr_set() call balance_dirty_pages_ratelimited() and cond_resched() in the main loop as we could be dirtying a lot of pages and this ensures we play nice with the VM and the system as a whole. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 4 ++++ fs/ntfs/attrib.c | 4 ++++ fs/ntfs/malloc.h | 3 +-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 9f4674a026f2..3b8ff2318085 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -57,6 +57,10 @@ ToDo/Notes: uncompressed and unencrypted files are supported. Also, there is only very limited support for highly fragmented files (the ones whose $DATA attribute is split into multiple attribute extents). + - In attrib.c::ntfs_attr_set() call balance_dirty_pages_ratelimited() + and cond_resched() in the main loop as we could be dirtying a lot of + pages and this ensures we play nice with the VM and the system as a + whole. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index bc25e88ad468..338e47144fc9 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -21,7 +21,9 @@ */ #include +#include #include +#include #include "attrib.h" #include "debug.h" @@ -2590,6 +2592,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) /* Finally unlock and release the page. */ unlock_page(page); page_cache_release(page); + balance_dirty_pages_ratelimited(mapping); + cond_resched(); } /* If there is a last partial page, need to do it the slow way. */ if (end_ofs) { diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 590887b943f5..e38e402e4103 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h @@ -39,8 +39,7 @@ * If there was insufficient memory to complete the request, return NULL. * Depending on @gfp_mask the allocation may be guaranteed to succeed. */ -static inline void *__ntfs_malloc(unsigned long size, - gfp_t gfp_mask) +static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask) { if (likely(size <= PAGE_SIZE)) { BUG_ON(!size); From 29f5f3c141c58b0a4c0765c77da612271875bcce Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 11 Oct 2005 14:59:40 +0100 Subject: [PATCH 0368/1939] NTFS: Remove address space operations ->prepare_write and ->commit_write in preparation for the big rewrite of write(2) support in ntfs. Signed-off-by: Anton Altaparmakov --- fs/ntfs/aops.c | 827 ------------------------------------------------- 1 file changed, 827 deletions(-) diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 5e80c07c6a4d..8f23c60030c0 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -1542,830 +1542,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) return err; } -/** - * ntfs_prepare_nonresident_write - - * - */ -static int ntfs_prepare_nonresident_write(struct page *page, - unsigned from, unsigned to) -{ - VCN vcn; - LCN lcn; - s64 initialized_size; - loff_t i_size; - sector_t block, ablock, iblock; - struct inode *vi; - ntfs_inode *ni; - ntfs_volume *vol; - runlist_element *rl; - struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; - unsigned long flags; - unsigned int vcn_ofs, block_start, block_end, blocksize; - int err; - BOOL is_retry; - unsigned char blocksize_bits; - - vi = page->mapping->host; - ni = NTFS_I(vi); - vol = ni->vol; - - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " - "0x%lx, from = %u, to = %u.", ni->mft_no, ni->type, - page->index, from, to); - - BUG_ON(!NInoNonResident(ni)); - - blocksize_bits = vi->i_blkbits; - blocksize = 1 << blocksize_bits; - - /* - * create_empty_buffers() will create uptodate/dirty buffers if the - * page is uptodate/dirty. - */ - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - bh = head = page_buffers(page); - if (unlikely(!bh)) - return -ENOMEM; - - /* The first block in the page. */ - block = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); - - read_lock_irqsave(&ni->size_lock, flags); - /* - * The first out of bounds block for the allocated size. No need to - * round up as allocated_size is in multiples of cluster size and the - * minimum cluster size is 512 bytes, which is equal to the smallest - * blocksize. - */ - ablock = ni->allocated_size >> blocksize_bits; - i_size = i_size_read(vi); - initialized_size = ni->initialized_size; - read_unlock_irqrestore(&ni->size_lock, flags); - - /* The last (fully or partially) initialized block. */ - iblock = initialized_size >> blocksize_bits; - - /* Loop through all the buffers in the page. */ - block_start = 0; - rl = NULL; - err = 0; - do { - block_end = block_start + blocksize; - /* - * If buffer @bh is outside the write, just mark it uptodate - * if the page is uptodate and continue with the next buffer. - */ - if (block_end <= from || block_start >= to) { - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - } - continue; - } - /* - * @bh is at least partially being written to. - * Make sure it is not marked as new. - */ - //if (buffer_new(bh)) - // clear_buffer_new(bh); - - if (block >= ablock) { - // TODO: block is above allocated_size, need to - // allocate it. Best done in one go to accommodate not - // only block but all above blocks up to and including: - // ((page->index << PAGE_CACHE_SHIFT) + to + blocksize - // - 1) >> blobksize_bits. Obviously will need to round - // up to next cluster boundary, too. This should be - // done with a helper function, so it can be reused. - ntfs_error(vol->sb, "Writing beyond allocated size " - "is not supported yet. Sorry."); - err = -EOPNOTSUPP; - goto err_out; - // Need to update ablock. - // Need to set_buffer_new() on all block bhs that are - // newly allocated. - } - /* - * Now we have enough allocated size to fulfill the whole - * request, i.e. block < ablock is true. - */ - if (unlikely((block >= iblock) && - (initialized_size < i_size))) { - /* - * If this page is fully outside initialized size, zero - * out all pages between the current initialized size - * and the current page. Just use ntfs_readpage() to do - * the zeroing transparently. - */ - if (block > iblock) { - // TODO: - // For each page do: - // - read_cache_page() - // Again for each page do: - // - wait_on_page_locked() - // - Check (PageUptodate(page) && - // !PageError(page)) - // Update initialized size in the attribute and - // in the inode. - // Again, for each page do: - // __set_page_dirty_buffers(); - // page_cache_release() - // We don't need to wait on the writes. - // Update iblock. - } - /* - * The current page straddles initialized size. Zero - * all non-uptodate buffers and set them uptodate (and - * dirty?). Note, there aren't any non-uptodate buffers - * if the page is uptodate. - * FIXME: For an uptodate page, the buffers may need to - * be written out because they were not initialized on - * disk before. - */ - if (!PageUptodate(page)) { - // TODO: - // Zero any non-uptodate buffers up to i_size. - // Set them uptodate and dirty. - } - // TODO: - // Update initialized size in the attribute and in the - // inode (up to i_size). - // Update iblock. - // FIXME: This is inefficient. Try to batch the two - // size changes to happen in one go. - ntfs_error(vol->sb, "Writing beyond initialized size " - "is not supported yet. Sorry."); - err = -EOPNOTSUPP; - goto err_out; - // Do NOT set_buffer_new() BUT DO clear buffer range - // outside write request range. - // set_buffer_uptodate() on complete buffers as well as - // set_buffer_dirty(). - } - - /* Need to map unmapped buffers. */ - if (!buffer_mapped(bh)) { - /* Unmapped buffer. Need to map it. */ - bh->b_bdev = vol->sb->s_bdev; - - /* Convert block into corresponding vcn and offset. */ - vcn = (VCN)block << blocksize_bits >> - vol->cluster_size_bits; - vcn_ofs = ((VCN)block << blocksize_bits) & - vol->cluster_size_mask; - - is_retry = FALSE; - if (!rl) { -lock_retry_remap: - down_read(&ni->runlist.lock); - rl = ni->runlist.rl; - } - if (likely(rl != NULL)) { - /* Seek to element containing target vcn. */ - while (rl->length && rl[1].vcn <= vcn) - rl++; - lcn = ntfs_rl_vcn_to_lcn(rl, vcn); - } else - lcn = LCN_RL_NOT_MAPPED; - if (unlikely(lcn < 0)) { - /* - * We extended the attribute allocation above. - * If we hit an ENOENT here it means that the - * allocation was insufficient which is a bug. - */ - BUG_ON(lcn == LCN_ENOENT); - - /* It is a hole, need to instantiate it. */ - if (lcn == LCN_HOLE) { - // TODO: Instantiate the hole. - // clear_buffer_new(bh); - // unmap_underlying_metadata(bh->b_bdev, - // bh->b_blocknr); - // For non-uptodate buffers, need to - // zero out the region outside the - // request in this bh or all bhs, - // depending on what we implemented - // above. - // Need to flush_dcache_page(). - // Or could use set_buffer_new() - // instead? - ntfs_error(vol->sb, "Writing into " - "sparse regions is " - "not supported yet. " - "Sorry."); - err = -EOPNOTSUPP; - if (!rl) - up_read(&ni->runlist.lock); - goto err_out; - } else if (!is_retry && - lcn == LCN_RL_NOT_MAPPED) { - is_retry = TRUE; - /* - * Attempt to map runlist, dropping - * lock for the duration. - */ - up_read(&ni->runlist.lock); - err = ntfs_map_runlist(ni, vcn); - if (likely(!err)) - goto lock_retry_remap; - rl = NULL; - } else if (!rl) - up_read(&ni->runlist.lock); - /* - * Failed to map the buffer, even after - * retrying. - */ - if (!err) - err = -EIO; - bh->b_blocknr = -1; - ntfs_error(vol->sb, "Failed to write to inode " - "0x%lx, attribute type 0x%x, " - "vcn 0x%llx, offset 0x%x " - "because its location on disk " - "could not be determined%s " - "(error code %i).", - ni->mft_no, ni->type, - (unsigned long long)vcn, - vcn_ofs, is_retry ? " even " - "after retrying" : "", err); - goto err_out; - } - /* We now have a successful remap, i.e. lcn >= 0. */ - - /* Setup buffer head to correct block. */ - bh->b_blocknr = ((lcn << vol->cluster_size_bits) - + vcn_ofs) >> blocksize_bits; - set_buffer_mapped(bh); - - // FIXME: Something analogous to this is needed for - // each newly allocated block, i.e. BH_New. - // FIXME: Might need to take this out of the - // if (!buffer_mapped(bh)) {}, depending on how we - // implement things during the allocated_size and - // initialized_size extension code above. - if (buffer_new(bh)) { - clear_buffer_new(bh); - unmap_underlying_metadata(bh->b_bdev, - bh->b_blocknr); - if (PageUptodate(page)) { - set_buffer_uptodate(bh); - continue; - } - /* - * Page is _not_ uptodate, zero surrounding - * region. NOTE: This is how we decide if to - * zero or not! - */ - if (block_end > to || block_start < from) { - void *kaddr; - - kaddr = kmap_atomic(page, KM_USER0); - if (block_end > to) - memset(kaddr + to, 0, - block_end - to); - if (block_start < from) - memset(kaddr + block_start, 0, - from - - block_start); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - } - continue; - } - } - /* @bh is mapped, set it uptodate if the page is uptodate. */ - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - continue; - } - /* - * The page is not uptodate. The buffer is mapped. If it is not - * uptodate, and it is only partially being written to, we need - * to read the buffer in before the write, i.e. right now. - */ - if (!buffer_uptodate(bh) && - (block_start < from || block_end > to)) { - ll_rw_block(READ, 1, &bh); - *wait_bh++ = bh; - } - } while (block++, block_start = block_end, - (bh = bh->b_this_page) != head); - - /* Release the lock if we took it. */ - if (rl) { - up_read(&ni->runlist.lock); - rl = NULL; - } - - /* If we issued read requests, let them complete. */ - while (wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) - return -EIO; - } - - ntfs_debug("Done."); - return 0; -err_out: - /* - * Zero out any newly allocated blocks to avoid exposing stale data. - * If BH_New is set, we know that the block was newly allocated in the - * above loop. - * FIXME: What about initialized_size increments? Have we done all the - * required zeroing above? If not this error handling is broken, and - * in particular the if (block_end <= from) check is completely bogus. - */ - bh = head; - block_start = 0; - is_retry = FALSE; - do { - block_end = block_start + blocksize; - if (block_end <= from) - continue; - if (block_start >= to) - break; - if (buffer_new(bh)) { - void *kaddr; - - clear_buffer_new(bh); - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + block_start, 0, bh->b_size); - kunmap_atomic(kaddr, KM_USER0); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - is_retry = TRUE; - } - } while (block_start = block_end, (bh = bh->b_this_page) != head); - if (is_retry) - flush_dcache_page(page); - if (rl) - up_read(&ni->runlist.lock); - return err; -} - -/** - * ntfs_prepare_write - prepare a page for receiving data - * - * This is called from generic_file_write() with i_sem held on the inode - * (@page->mapping->host). The @page is locked but not kmap()ped. The source - * data has not yet been copied into the @page. - * - * Need to extend the attribute/fill in holes if necessary, create blocks and - * make partially overwritten blocks uptodate, - * - * i_size is not to be modified yet. - * - * Return 0 on success or -errno on error. - * - * Should be using block_prepare_write() [support for sparse files] or - * cont_prepare_write() [no support for sparse files]. Cannot do that due to - * ntfs specifics but can look at them for implementation guidance. - * - * Note: In the range, @from is inclusive and @to is exclusive, i.e. @from is - * the first byte in the page that will be written to and @to is the first byte - * after the last byte that will be written to. - */ -static int ntfs_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) -{ - s64 new_size; - loff_t i_size; - struct inode *vi = page->mapping->host; - ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi); - ntfs_volume *vol = ni->vol; - ntfs_attr_search_ctx *ctx = NULL; - MFT_RECORD *m = NULL; - ATTR_RECORD *a; - u8 *kaddr; - u32 attr_len; - int err; - - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " - "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, - page->index, from, to); - BUG_ON(!PageLocked(page)); - BUG_ON(from > PAGE_CACHE_SIZE); - BUG_ON(to > PAGE_CACHE_SIZE); - BUG_ON(from > to); - BUG_ON(NInoMstProtected(ni)); - /* - * If a previous ntfs_truncate() failed, repeat it and abort if it - * fails again. - */ - if (unlikely(NInoTruncateFailed(ni))) { - down_write(&vi->i_alloc_sem); - err = ntfs_truncate(vi); - up_write(&vi->i_alloc_sem); - if (err || NInoTruncateFailed(ni)) { - if (!err) - err = -EIO; - goto err_out; - } - } - /* If the attribute is not resident, deal with it elsewhere. */ - if (NInoNonResident(ni)) { - /* - * Only unnamed $DATA attributes can be compressed, encrypted, - * and/or sparse. - */ - if (ni->type == AT_DATA && !ni->name_len) { - /* If file is encrypted, deny access, just like NT4. */ - if (NInoEncrypted(ni)) { - ntfs_debug("Denying write access to encrypted " - "file."); - return -EACCES; - } - /* Compressed data streams are handled in compress.c. */ - if (NInoCompressed(ni)) { - // TODO: Implement and replace this check with - // return ntfs_write_compressed_block(page); - ntfs_error(vi->i_sb, "Writing to compressed " - "files is not supported yet. " - "Sorry."); - return -EOPNOTSUPP; - } - // TODO: Implement and remove this check. - if (NInoSparse(ni)) { - ntfs_error(vi->i_sb, "Writing to sparse files " - "is not supported yet. Sorry."); - return -EOPNOTSUPP; - } - } - /* Normal data stream. */ - return ntfs_prepare_nonresident_write(page, from, to); - } - /* - * Attribute is resident, implying it is not compressed, encrypted, or - * sparse. - */ - BUG_ON(page_has_buffers(page)); - new_size = ((s64)page->index << PAGE_CACHE_SHIFT) + to; - /* If we do not need to resize the attribute allocation we are done. */ - if (new_size <= i_size_read(vi)) - goto done; - /* Map, pin, and lock the (base) mft record. */ - if (!NInoAttr(ni)) - base_ni = ni; - else - base_ni = ni->ext.base_ntfs_ino; - m = map_mft_record(base_ni); - if (IS_ERR(m)) { - err = PTR_ERR(m); - m = NULL; - ctx = NULL; - goto err_out; - } - ctx = ntfs_attr_get_search_ctx(base_ni, m); - if (unlikely(!ctx)) { - err = -ENOMEM; - goto err_out; - } - err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, - CASE_SENSITIVE, 0, NULL, 0, ctx); - if (unlikely(err)) { - if (err == -ENOENT) - err = -EIO; - goto err_out; - } - m = ctx->mrec; - a = ctx->attr; - /* The total length of the attribute value. */ - attr_len = le32_to_cpu(a->data.resident.value_length); - /* Fix an eventual previous failure of ntfs_commit_write(). */ - i_size = i_size_read(vi); - if (unlikely(attr_len > i_size)) { - attr_len = i_size; - a->data.resident.value_length = cpu_to_le32(attr_len); - } - /* If we do not need to resize the attribute allocation we are done. */ - if (new_size <= attr_len) - goto done_unm; - /* Check if new size is allowed in $AttrDef. */ - err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); - if (unlikely(err)) { - if (err == -ERANGE) { - ntfs_error(vol->sb, "Write would cause the inode " - "0x%lx to exceed the maximum size for " - "its attribute type (0x%x). Aborting " - "write.", vi->i_ino, - le32_to_cpu(ni->type)); - } else { - ntfs_error(vol->sb, "Inode 0x%lx has unknown " - "attribute type 0x%x. Aborting " - "write.", vi->i_ino, - le32_to_cpu(ni->type)); - err = -EIO; - } - goto err_out2; - } - /* - * Extend the attribute record to be able to store the new attribute - * size. - */ - if (new_size >= vol->mft_record_size || ntfs_attr_record_resize(m, a, - le16_to_cpu(a->data.resident.value_offset) + - new_size)) { - /* Not enough space in the mft record. */ - ntfs_error(vol->sb, "Not enough space in the mft record for " - "the resized attribute value. This is not " - "supported yet. Aborting write."); - err = -EOPNOTSUPP; - goto err_out2; - } - /* - * We have enough space in the mft record to fit the write. This - * implies the attribute is smaller than the mft record and hence the - * attribute must be in a single page and hence page->index must be 0. - */ - BUG_ON(page->index); - /* - * If the beginning of the write is past the old size, enlarge the - * attribute value up to the beginning of the write and fill it with - * zeroes. - */ - if (from > attr_len) { - memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + - attr_len, 0, from - attr_len); - a->data.resident.value_length = cpu_to_le32(from); - /* Zero the corresponding area in the page as well. */ - if (PageUptodate(page)) { - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + attr_len, 0, from - attr_len); - kunmap_atomic(kaddr, KM_USER0); - flush_dcache_page(page); - } - } - flush_dcache_mft_record_page(ctx->ntfs_ino); - mark_mft_record_dirty(ctx->ntfs_ino); -done_unm: - ntfs_attr_put_search_ctx(ctx); - unmap_mft_record(base_ni); - /* - * Because resident attributes are handled by memcpy() to/from the - * corresponding MFT record, and because this form of i/o is byte - * aligned rather than block aligned, there is no need to bring the - * page uptodate here as in the non-resident case where we need to - * bring the buffers straddled by the write uptodate before - * generic_file_write() does the copying from userspace. - * - * We thus defer the uptodate bringing of the page region outside the - * region written to to ntfs_commit_write(), which makes the code - * simpler and saves one atomic kmap which is good. - */ -done: - ntfs_debug("Done."); - return 0; -err_out: - if (err == -ENOMEM) - ntfs_warning(vi->i_sb, "Error allocating memory required to " - "prepare the write."); - else { - ntfs_error(vi->i_sb, "Resident attribute prepare write failed " - "with error %i.", err); - NVolSetErrors(vol); - make_bad_inode(vi); - } -err_out2: - if (ctx) - ntfs_attr_put_search_ctx(ctx); - if (m) - unmap_mft_record(base_ni); - return err; -} - -/** - * ntfs_commit_nonresident_write - - * - */ -static int ntfs_commit_nonresident_write(struct page *page, - unsigned from, unsigned to) -{ - s64 pos = ((s64)page->index << PAGE_CACHE_SHIFT) + to; - struct inode *vi = page->mapping->host; - struct buffer_head *bh, *head; - unsigned int block_start, block_end, blocksize; - BOOL partial; - - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " - "0x%lx, from = %u, to = %u.", vi->i_ino, - NTFS_I(vi)->type, page->index, from, to); - blocksize = 1 << vi->i_blkbits; - - // FIXME: We need a whole slew of special cases in here for compressed - // files for example... - // For now, we know ntfs_prepare_write() would have failed so we can't - // get here in any of the cases which we have to special case, so we - // are just a ripped off, unrolled generic_commit_write(). - - bh = head = page_buffers(page); - block_start = 0; - partial = FALSE; - do { - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (!buffer_uptodate(bh)) - partial = TRUE; - } else { - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - } - } while (block_start = block_end, (bh = bh->b_this_page) != head); - /* - * If this is a partial write which happened to make all buffers - * uptodate then we can optimize away a bogus ->readpage() for the next - * read(). Here we 'discover' whether the page went uptodate as a - * result of this (potentially partial) write. - */ - if (!partial) - SetPageUptodate(page); - /* - * Not convinced about this at all. See disparity comment above. For - * now we know ntfs_prepare_write() would have failed in the write - * exceeds i_size case, so this will never trigger which is fine. - */ - if (pos > i_size_read(vi)) { - ntfs_error(vi->i_sb, "Writing beyond the existing file size is " - "not supported yet. Sorry."); - return -EOPNOTSUPP; - // vi->i_size = pos; - // mark_inode_dirty(vi); - } - ntfs_debug("Done."); - return 0; -} - -/** - * ntfs_commit_write - commit the received data - * - * This is called from generic_file_write() with i_sem held on the inode - * (@page->mapping->host). The @page is locked but not kmap()ped. The source - * data has already been copied into the @page. ntfs_prepare_write() has been - * called before the data copied and it returned success so we can take the - * results of various BUG checks and some error handling for granted. - * - * Need to mark modified blocks dirty so they get written out later when - * ntfs_writepage() is invoked by the VM. - * - * Return 0 on success or -errno on error. - * - * Should be using generic_commit_write(). This marks buffers uptodate and - * dirty, sets the page uptodate if all buffers in the page are uptodate, and - * updates i_size if the end of io is beyond i_size. In that case, it also - * marks the inode dirty. - * - * Cannot use generic_commit_write() due to ntfs specialities but can look at - * it for implementation guidance. - * - * If things have gone as outlined in ntfs_prepare_write(), then we do not - * need to do any page content modifications here at all, except in the write - * to resident attribute case, where we need to do the uptodate bringing here - * which we combine with the copying into the mft record which means we save - * one atomic kmap. - */ -static int ntfs_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) -{ - struct inode *vi = page->mapping->host; - ntfs_inode *base_ni, *ni = NTFS_I(vi); - char *kaddr, *kattr; - ntfs_attr_search_ctx *ctx; - MFT_RECORD *m; - ATTR_RECORD *a; - u32 attr_len; - int err; - - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " - "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, - page->index, from, to); - /* If the attribute is not resident, deal with it elsewhere. */ - if (NInoNonResident(ni)) { - /* Only unnamed $DATA attributes can be compressed/encrypted. */ - if (ni->type == AT_DATA && !ni->name_len) { - /* Encrypted files need separate handling. */ - if (NInoEncrypted(ni)) { - // We never get here at present! - BUG(); - } - /* Compressed data streams are handled in compress.c. */ - if (NInoCompressed(ni)) { - // TODO: Implement this! - // return ntfs_write_compressed_block(page); - // We never get here at present! - BUG(); - } - } - /* Normal data stream. */ - return ntfs_commit_nonresident_write(page, from, to); - } - /* - * Attribute is resident, implying it is not compressed, encrypted, or - * sparse. - */ - if (!NInoAttr(ni)) - base_ni = ni; - else - base_ni = ni->ext.base_ntfs_ino; - /* Map, pin, and lock the mft record. */ - m = map_mft_record(base_ni); - if (IS_ERR(m)) { - err = PTR_ERR(m); - m = NULL; - ctx = NULL; - goto err_out; - } - ctx = ntfs_attr_get_search_ctx(base_ni, m); - if (unlikely(!ctx)) { - err = -ENOMEM; - goto err_out; - } - err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, - CASE_SENSITIVE, 0, NULL, 0, ctx); - if (unlikely(err)) { - if (err == -ENOENT) - err = -EIO; - goto err_out; - } - a = ctx->attr; - /* The total length of the attribute value. */ - attr_len = le32_to_cpu(a->data.resident.value_length); - BUG_ON(from > attr_len); - kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); - kaddr = kmap_atomic(page, KM_USER0); - /* Copy the received data from the page to the mft record. */ - memcpy(kattr + from, kaddr + from, to - from); - /* Update the attribute length if necessary. */ - if (to > attr_len) { - attr_len = to; - a->data.resident.value_length = cpu_to_le32(attr_len); - } - /* - * If the page is not uptodate, bring the out of bounds area(s) - * uptodate by copying data from the mft record to the page. - */ - if (!PageUptodate(page)) { - if (from > 0) - memcpy(kaddr, kattr, from); - if (to < attr_len) - memcpy(kaddr + to, kattr + to, attr_len - to); - /* Zero the region outside the end of the attribute value. */ - if (attr_len < PAGE_CACHE_SIZE) - memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - /* - * The probability of not having done any of the above is - * extremely small, so we just flush unconditionally. - */ - flush_dcache_page(page); - SetPageUptodate(page); - } - kunmap_atomic(kaddr, KM_USER0); - /* Update i_size if necessary. */ - if (i_size_read(vi) < attr_len) { - unsigned long flags; - - write_lock_irqsave(&ni->size_lock, flags); - ni->allocated_size = ni->initialized_size = attr_len; - i_size_write(vi, attr_len); - write_unlock_irqrestore(&ni->size_lock, flags); - } - /* Mark the mft record dirty, so it gets written back. */ - flush_dcache_mft_record_page(ctx->ntfs_ino); - mark_mft_record_dirty(ctx->ntfs_ino); - ntfs_attr_put_search_ctx(ctx); - unmap_mft_record(base_ni); - ntfs_debug("Done."); - return 0; -err_out: - if (err == -ENOMEM) { - ntfs_warning(vi->i_sb, "Error allocating memory required to " - "commit the write."); - if (PageUptodate(page)) { - ntfs_warning(vi->i_sb, "Page is uptodate, setting " - "dirty so the write will be retried " - "later on by the VM."); - /* - * Put the page on mapping->dirty_pages, but leave its - * buffers' dirty state as-is. - */ - __set_page_dirty_nobuffers(page); - err = 0; - } else - ntfs_error(vi->i_sb, "Page is not uptodate. Written " - "data has been lost."); - } else { - ntfs_error(vi->i_sb, "Resident attribute commit write failed " - "with error %i.", err); - NVolSetErrors(ni->vol); - make_bad_inode(vi); - } - if (ctx) - ntfs_attr_put_search_ctx(ctx); - if (m) - unmap_mft_record(base_ni); - return err; -} - #endif /* NTFS_RW */ /** @@ -2377,9 +1553,6 @@ struct address_space_operations ntfs_aops = { disk request queue. */ #ifdef NTFS_RW .writepage = ntfs_writepage, /* Write dirty page to disk. */ - .prepare_write = ntfs_prepare_write, /* Prepare page and buffers - ready to receive data. */ - .commit_write = ntfs_commit_write, /* Commit received data. */ #endif /* NTFS_RW */ }; From b6a47fd8ff08a9d5cd279cdb8d97a619983575fa Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Tue, 11 Oct 2005 09:06:59 -0500 Subject: [PATCH 0369/1939] JFS: Corrupted block map should not cause trap Replace assert statements with better error handling. Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_dmap.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 51c02bf07878..68000a50ceb6 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -74,7 +74,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks); static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval); -static void dbBackSplit(dmtree_t * tp, int leafno); +static int dbBackSplit(dmtree_t * tp, int leafno); static int dbJoin(dmtree_t * tp, int leafno, int newval); static void dbAdjTree(dmtree_t * tp, int leafno, int newval); static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, @@ -2466,7 +2466,9 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) * that it is at the front of a binary buddy system. */ if (oldval == NOFREE) { - dbBackSplit((dmtree_t *) dcp, leafno); + rc = dbBackSplit((dmtree_t *) dcp, leafno); + if (rc) + return rc; oldval = dcp->stree[ti]; } dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval); @@ -2626,7 +2628,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ -static void dbBackSplit(dmtree_t * tp, int leafno) +static int dbBackSplit(dmtree_t * tp, int leafno) { int budsz, bud, w, bsz, size; int cursz; @@ -2661,7 +2663,10 @@ static void dbBackSplit(dmtree_t * tp, int leafno) */ for (w = leafno, bsz = budsz;; bsz <<= 1, w = (w < bud) ? w : bud) { - assert(bsz < le32_to_cpu(tp->dmt_nleafs)); + if (bsz >= le32_to_cpu(tp->dmt_nleafs)) { + jfs_err("JFS: block map error in dbBackSplit"); + return -EIO; + } /* determine the buddy. */ @@ -2680,7 +2685,11 @@ static void dbBackSplit(dmtree_t * tp, int leafno) } } - assert(leaf[leafno] == size); + if (leaf[leafno] != size) { + jfs_err("JFS: wrong leaf value in dbBackSplit"); + return -EIO; + } + return 0; } From 98b270362bb9ea6629732e7f5b65b8a6ce4743c7 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 11 Oct 2005 15:40:40 +0100 Subject: [PATCH 0370/1939] NTFS: The big ntfs write(2) rewrite has arrived. We now implement our own file operations ->write(), ->aio_write(), and ->writev() for regular files. This replaces the old use of generic_file_write(), et al and the address space operations ->prepare_write and ->commit_write. This means that both sparse and non-sparse (unencrypted and uncompressed) files can now be extended using the normal write(2) code path. There are two limitations at present and these are that we never create sparse files and that we only have limited support for highly fragmented files, i.e. ones whose data attribute is split across multiple extents. When such a case is encountered, EOPNOTSUPP is returned. Signed-off-by: Anton Altaparmakov --- Documentation/filesystems/ntfs.txt | 42 +- fs/ntfs/ChangeLog | 38 +- fs/ntfs/Makefile | 2 +- fs/ntfs/file.c | 2247 +++++++++++++++++++++++++++- 4 files changed, 2280 insertions(+), 49 deletions(-) diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index a5fbc8e897fa..614de3124901 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt @@ -50,9 +50,14 @@ userspace utilities, etc. Features ======== -- This is a complete rewrite of the NTFS driver that used to be in the kernel. - This new driver implements NTFS read support and is functionally equivalent - to the old ntfs driver. +- This is a complete rewrite of the NTFS driver that used to be in the 2.4 and + earlier kernels. This new driver implements NTFS read support and is + functionally equivalent to the old ntfs driver and it also implements limited + write support. The biggest limitation at present is that files/directories + cannot be created or deleted. See below for the list of write features that + are so far supported. Another limitation is that writing to compressed files + is not implemented at all. Also, neither read nor write access to encrypted + files is so far implemented. - The new driver has full support for sparse files on NTFS 3.x volumes which the old driver isn't happy with. - The new driver supports execution of binaries due to mmap() now being @@ -78,7 +83,20 @@ Features - The new driver supports fsync(2), fdatasync(2), and msync(2). - The new driver supports readv(2) and writev(2). - The new driver supports access time updates (including mtime and ctime). - +- The new driver supports truncate(2) and open(2) with O_TRUNC. But at present + only very limited support for highly fragmented files, i.e. ones which have + their data attribute split across multiple extents, is included. Another + limitation is that at present truncate(2) will never create sparse files, + since to mark a file sparse we need to modify the directory entry for the + file and we do not implement directory modifications yet. +- The new driver supports write(2) which can both overwrite existing data and + extend the file size so that you can write beyond the existing data. Also, + writing into sparse regions is supported and the holes are filled in with + clusters. But at present only limited support for highly fragmented files, + i.e. ones which have their data attribute split across multiple extents, is + included. Another limitation is that write(2) will never create sparse + files, since to mark a file sparse we need to modify the directory entry for + the file and we do not implement directory modifications yet. Supported mount options ======================= @@ -439,6 +457,22 @@ ChangeLog Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.25: + - Write support is now extended with write(2) being able to both + overwrite existing file data and to extend files. Also, if a write + to a sparse region occurs, write(2) will fill in the hole. Note, + mmap(2) based writes still do not support writing into holes or + writing beyond the initialized size. + - Write support has a new feature and that is that truncate(2) and + open(2) with O_TRUNC are now implemented thus files can be both made + smaller and larger. + - Note: Both write(2) and truncate(2)/open(2) with O_TRUNC still have + limitations in that they + - only provide limited support for highly fragmented files. + - only work on regular, i.e. uncompressed and unencrypted files. + - never create sparse files although this will change once directory + operations are implemented. + - Lots of bug fixes and enhancements across the board. 2.1.24: - Support journals ($LogFile) which have been modified by chkdsk. This means users can boot into Windows after we marked the volume dirty. diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 3b8ff2318085..03015c7b236c 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -1,16 +1,15 @@ ToDo/Notes: - Find and fix bugs. - - In between ntfs_prepare/commit_write, need exclusion between - simultaneous file extensions. This is given to us by holding i_sem - on the inode. The only places in the kernel when a file is resized - are prepare/commit write and ntfs_truncate() for both of which i_sem - is held. Just have to be careful in read-/writepage and other helpers + - The only places in the kernel where a file is resized are + ntfs_file_write*() and ntfs_truncate() for both of which i_sem is + held. Just have to be careful in read-/writepage and other helpers not running under i_sem that we play nice... Also need to be careful - with initialized_size extention in ntfs_prepare_write and writepage. - UPDATE: The only things that need to be checked are - prepare/commit_write as well as the compressed write and the other - attribute resize/write cases like index attributes, etc. For now - none of these are implemented so are safe. + with initialized_size extension in ntfs_file_write*() and writepage. + UPDATE: The only things that need to be checked are the compressed + write and the other attribute resize/write cases like index + attributes, etc. For now none of these are implemented so are safe. + - Implement filling in of holes in aops.c::ntfs_writepage() and its + helpers. - Implement mft.c::sync_mft_mirror_umount(). We currently will just leave the volume dirty on umount if the final iput(vol->mft_ino) causes a write of any mirrored mft records due to the mft mirror @@ -20,7 +19,7 @@ ToDo/Notes: - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. -2.1.25-WIP +2.1.25 - (Almost) fully implement write(2) and truncate(2). - Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and {__,}ntfs_cluster_free() to also take an optional attribute search @@ -49,7 +48,12 @@ ToDo/Notes: extend the allocation of an attributes. Optionally, the data size, but not the initialized size can be extended, too. - Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports - uncompressed and unencrypted files. + uncompressed and unencrypted files and it never creates sparse files + at least for the moment (making a file sparse requires us to modify + its directory entries and we do not support directory operations at + the moment). Also, support for highly fragmented files, i.e. ones + whose data attribute is split across multiple extents, is severly + limited. When such a case is encountered, EOPNOTSUPP is returned. - Enable ATTR_SIZE attribute changes in ntfs_setattr(). This completes the initial implementation of file truncation. Now both open(2)ing a file with the O_TRUNC flag and the {,f}truncate(2) system calls @@ -61,6 +65,16 @@ ToDo/Notes: and cond_resched() in the main loop as we could be dirtying a lot of pages and this ensures we play nice with the VM and the system as a whole. + - Implement file operations ->write, ->aio_write, ->writev for regular + files. This replaces the old use of generic_file_write(), et al and + the address space operations ->prepare_write and ->commit_write. + This means that both sparse and non-sparse (unencrypted and + uncompressed) files can now be extended using the normal write(2) + code path. There are two limitations at present and these are that + we never create sparse files and that we only have limited support + for highly fragmented files, i.e. ones whose data attribute is split + across multiple extents. When such a case is encountered, + EOPNOTSUPP is returned. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index a3ce2c0e7dd9..d0d45d1c853a 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25-WIP\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index be9fd1dd423d..cf2a0e2330df 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -19,11 +19,24 @@ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "attrib.h" +#include "bitmap.h" #include "inode.h" #include "debug.h" +#include "lcnalloc.h" +#include "malloc.h" +#include "mft.h" #include "ntfs.h" /** @@ -55,6 +68,2176 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) #ifdef NTFS_RW +/** + * ntfs_attr_extend_initialized - extend the initialized size of an attribute + * @ni: ntfs inode of the attribute to extend + * @new_init_size: requested new initialized size in bytes + * @cached_page: store any allocated but unused page here + * @lru_pvec: lru-buffering pagevec of the caller + * + * Extend the initialized size of an attribute described by the ntfs inode @ni + * to @new_init_size bytes. This involves zeroing any non-sparse space between + * the old initialized size and @new_init_size both in the page cache and on + * disk (if relevant complete pages are zeroed in the page cache then these may + * simply be marked dirty for later writeout). There is one caveat and that is + * that if any uptodate page cache pages between the old initialized size and + * the smaller of @new_init_size and the file size (vfs inode->i_size) are in + * memory, these need to be marked dirty without being zeroed since they could + * be non-zero due to mmap() based writes. + * + * As a side-effect, the file size (vfs inode->i_size) may be incremented as, + * in the resident attribute case, it is tied to the initialized size and, in + * the non-resident attribute case, it may not fall below the initialized size. + * + * Note that if the attribute is resident, we do not need to touch the page + * cache at all. This is because if the page cache page is not uptodate we + * bring it uptodate later, when doing the write to the mft record since we + * then already have the page mapped. And if the page is uptodate, the + * non-initialized region will already have been zeroed when the page was + * brought uptodate and the region may in fact already have been overwritten + * with new data via mmap() based writes, so we cannot just zero it. And since + * POSIX specifies that the behaviour of resizing a file whilst it is mmap()ped + * is unspecified, we choose not to do zeroing and thus we do not need to touch + * the page at all. For a more detailed explanation see ntfs_truncate() which + * is in fs/ntfs/inode.c. + * + * @cached_page and @lru_pvec are just optimisations for dealing with multiple + * pages. + * + * Return 0 on success and -errno on error. In the case that an error is + * encountered it is possible that the initialized size will already have been + * incremented some way towards @new_init_size but it is guaranteed that if + * this is the case, the necessary zeroing will also have happened and that all + * metadata is self-consistent. + * + * Locking: This function locks the mft record of the base ntfs inode and + * maintains the lock throughout execution of the function. This is required + * so that the initialized size of the attribute can be modified safely. + */ +static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size, + struct page **cached_page, struct pagevec *lru_pvec) +{ + s64 old_init_size; + loff_t old_i_size; + pgoff_t index, end_index; + unsigned long flags; + struct inode *vi = VFS_I(ni); + ntfs_inode *base_ni; + MFT_RECORD *m = NULL; + ATTR_RECORD *a; + ntfs_attr_search_ctx *ctx = NULL; + struct address_space *mapping; + struct page *page = NULL; + u8 *kattr; + int err; + u32 attr_len; + + read_lock_irqsave(&ni->size_lock, flags); + old_init_size = ni->initialized_size; + old_i_size = i_size_read(vi); + BUG_ON(new_init_size > ni->allocated_size); + read_unlock_irqrestore(&ni->size_lock, flags); + ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " + "old_initialized_size 0x%llx, " + "new_initialized_size 0x%llx, i_size 0x%llx.", + vi->i_ino, (unsigned)le32_to_cpu(ni->type), + (unsigned long long)old_init_size, + (unsigned long long)new_init_size, old_i_size); + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + /* Use goto to reduce indentation and we need the label below anyway. */ + if (NInoNonResident(ni)) + goto do_non_resident_extend; + BUG_ON(old_init_size != old_i_size); + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + goto err_out; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + m = ctx->mrec; + a = ctx->attr; + BUG_ON(a->non_resident); + /* The total length of the attribute value. */ + attr_len = le32_to_cpu(a->data.resident.value_length); + BUG_ON(old_i_size != (loff_t)attr_len); + /* + * Do the zeroing in the mft record and update the attribute size in + * the mft record. + */ + kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); + memset(kattr + attr_len, 0, new_init_size - attr_len); + a->data.resident.value_length = cpu_to_le32((u32)new_init_size); + /* Finally, update the sizes in the vfs and ntfs inodes. */ + write_lock_irqsave(&ni->size_lock, flags); + i_size_write(vi, new_init_size); + ni->initialized_size = new_init_size; + write_unlock_irqrestore(&ni->size_lock, flags); + goto done; +do_non_resident_extend: + /* + * If the new initialized size @new_init_size exceeds the current file + * size (vfs inode->i_size), we need to extend the file size to the + * new initialized size. + */ + if (new_init_size > old_i_size) { + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + goto err_out; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + m = ctx->mrec; + a = ctx->attr; + BUG_ON(!a->non_resident); + BUG_ON(old_i_size != (loff_t) + sle64_to_cpu(a->data.non_resident.data_size)); + a->data.non_resident.data_size = cpu_to_sle64(new_init_size); + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + /* Update the file size in the vfs inode. */ + i_size_write(vi, new_init_size); + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + unmap_mft_record(base_ni); + m = NULL; + } + mapping = vi->i_mapping; + index = old_init_size >> PAGE_CACHE_SHIFT; + end_index = (new_init_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + do { + /* + * 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); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto init_err_out; + } + wait_on_page_locked(page); + if (unlikely(!PageUptodate(page) || PageError(page))) { + page_cache_release(page); + err = -EIO; + goto init_err_out; + } + /* + * Update the initialized size in the ntfs inode. This is + * enough to make ntfs_writepage() work. + */ + write_lock_irqsave(&ni->size_lock, flags); + ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT; + if (ni->initialized_size > new_init_size) + ni->initialized_size = new_init_size; + write_unlock_irqrestore(&ni->size_lock, flags); + /* Set the page dirty so it gets written out. */ + set_page_dirty(page); + page_cache_release(page); + /* + * Play nice with the vm and the rest of the system. This is + * very much needed as we can potentially be modifying the + * initialised size from a very small value to a really huge + * value, e.g. + * f = open(somefile, O_TRUNC); + * truncate(f, 10GiB); + * seek(f, 10GiB); + * write(f, 1); + * And this would mean we would be marking dirty hundreds of + * thousands of pages or as in the above example more than + * two and a half million pages! + * + * TODO: For sparse pages could optimize this workload by using + * the FsMisc / MiscFs page bit as a "PageIsSparse" bit. This + * would be set in readpage for sparse pages and here we would + * not need to mark dirty any pages which have this bit set. + * The only caveat is that we have to clear the bit everywhere + * where we allocate any clusters that lie in the page or that + * contain the page. + * + * TODO: An even greater optimization would be for us to only + * call readpage() on pages which are not in sparse regions as + * determined from the runlist. This would greatly reduce the + * number of pages we read and make dirty in the case of sparse + * files. + */ + balance_dirty_pages_ratelimited(mapping); + cond_resched(); + } while (++index < end_index); + read_lock_irqsave(&ni->size_lock, flags); + BUG_ON(ni->initialized_size != new_init_size); + read_unlock_irqrestore(&ni->size_lock, flags); + /* Now bring in sync the initialized_size in the mft record. */ + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + goto init_err_out; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto init_err_out; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto init_err_out; + } + m = ctx->mrec; + a = ctx->attr; + BUG_ON(!a->non_resident); + a->data.non_resident.initialized_size = cpu_to_sle64(new_init_size); +done: + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + ntfs_debug("Done, initialized_size 0x%llx, i_size 0x%llx.", + (unsigned long long)new_init_size, i_size_read(vi)); + return 0; +init_err_out: + write_lock_irqsave(&ni->size_lock, flags); + ni->initialized_size = old_init_size; + write_unlock_irqrestore(&ni->size_lock, flags); +err_out: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + ntfs_debug("Failed. Returning error code %i.", err); + return err; +} + +/** + * ntfs_fault_in_pages_readable - + * + * Fault a number of userspace pages into pagetables. + * + * Unlike include/linux/pagemap.h::fault_in_pages_readable(), this one copes + * with more than two userspace pages as well as handling the single page case + * elegantly. + * + * If you find this difficult to understand, then think of the while loop being + * the following code, except that we do without the integer variable ret: + * + * do { + * ret = __get_user(c, uaddr); + * uaddr += PAGE_SIZE; + * } while (!ret && uaddr < end); + * + * Note, the final __get_user() may well run out-of-bounds of the user buffer, + * but _not_ out-of-bounds of the page the user buffer belongs to, and since + * this is only a read and not a write, and since it is still in the same page, + * it should not matter and this makes the code much simpler. + */ +static inline void ntfs_fault_in_pages_readable(const char __user *uaddr, + int bytes) +{ + const char __user *end; + volatile char c; + + /* Set @end to the first byte outside the last page we care about. */ + end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes); + + while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end)) + ; +} + +/** + * ntfs_fault_in_pages_readable_iovec - + * + * Same as ntfs_fault_in_pages_readable() but operates on an array of iovecs. + */ +static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov, + size_t iov_ofs, int bytes) +{ + do { + const char __user *buf; + unsigned len; + + buf = iov->iov_base + iov_ofs; + len = iov->iov_len - iov_ofs; + if (len > bytes) + len = bytes; + ntfs_fault_in_pages_readable(buf, len); + bytes -= len; + iov++; + iov_ofs = 0; + } while (bytes); +} + +/** + * __ntfs_grab_cache_pages - obtain a number of locked pages + * @mapping: address space mapping from which to obtain page cache pages + * @index: starting index in @mapping at which to begin obtaining pages + * @nr_pages: number of page cache pages to obtain + * @pages: array of pages in which to return the obtained page cache pages + * @cached_page: allocated but as yet unused page + * @lru_pvec: lru-buffering pagevec of caller + * + * Obtain @nr_pages locked page cache pages from the mapping @maping and + * starting at index @index. + * + * If a page is newly created, increment its refcount and add it to the + * caller's lru-buffering pagevec @lru_pvec. + * + * This is the same as mm/filemap.c::__grab_cache_page(), except that @nr_pages + * are obtained at once instead of just one page and that 0 is returned on + * success and -errno on error. + * + * Note, the page locks are obtained in ascending page index order. + */ +static inline int __ntfs_grab_cache_pages(struct address_space *mapping, + pgoff_t index, const unsigned nr_pages, struct page **pages, + struct page **cached_page, struct pagevec *lru_pvec) +{ + int err, nr; + + BUG_ON(!nr_pages); + err = nr = 0; + do { + pages[nr] = find_lock_page(mapping, index); + if (!pages[nr]) { + if (!*cached_page) { + *cached_page = page_cache_alloc(mapping); + if (unlikely(!*cached_page)) { + err = -ENOMEM; + goto err_out; + } + } + err = add_to_page_cache(*cached_page, mapping, index, + GFP_KERNEL); + if (unlikely(err)) { + if (err == -EEXIST) + continue; + goto err_out; + } + pages[nr] = *cached_page; + page_cache_get(*cached_page); + if (unlikely(!pagevec_add(lru_pvec, *cached_page))) + __pagevec_lru_add(lru_pvec); + *cached_page = NULL; + } + index++; + nr++; + } while (nr < nr_pages); +out: + return err; +err_out: + while (nr > 0) { + unlock_page(pages[--nr]); + page_cache_release(pages[nr]); + } + goto out; +} + +static inline int ntfs_submit_bh_for_read(struct buffer_head *bh) +{ + lock_buffer(bh); + get_bh(bh); + bh->b_end_io = end_buffer_read_sync; + return submit_bh(READ, bh); +} + +/** + * ntfs_prepare_pages_for_non_resident_write - prepare pages for receiving data + * @pages: array of destination pages + * @nr_pages: number of pages in @pages + * @pos: byte position in file at which the write begins + * @bytes: number of bytes to be written + * + * This is called for non-resident attributes from ntfs_file_buffered_write() + * with i_sem held on the inode (@pages[0]->mapping->host). There are + * @nr_pages pages in @pages which are locked but not kmap()ped. The source + * data has not yet been copied into the @pages. + * + * Need to fill any holes with actual clusters, allocate buffers if necessary, + * ensure all the buffers are mapped, and bring uptodate any buffers that are + * only partially being written to. + * + * If @nr_pages is greater than one, we are guaranteed that the cluster size is + * greater than PAGE_CACHE_SIZE, that all pages in @pages are entirely inside + * the same cluster and that they are the entirety of that cluster, and that + * the cluster is sparse, i.e. we need to allocate a cluster to fill the hole. + * + * i_size is not to be modified yet. + * + * Return 0 on success or -errno on error. + */ +static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, + unsigned nr_pages, s64 pos, size_t bytes) +{ + VCN vcn, highest_vcn = 0, cpos, cend, bh_cpos, bh_cend; + LCN lcn; + s64 bh_pos, vcn_len, end, initialized_size; + sector_t lcn_block; + struct page *page; + struct inode *vi; + ntfs_inode *ni, *base_ni = NULL; + ntfs_volume *vol; + runlist_element *rl, *rl2; + struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; + ntfs_attr_search_ctx *ctx = NULL; + MFT_RECORD *m = NULL; + ATTR_RECORD *a = NULL; + unsigned long flags; + u32 attr_rec_len = 0; + unsigned blocksize, u; + int err, mp_size; + BOOL rl_write_locked, was_hole, is_retry; + unsigned char blocksize_bits; + struct { + u8 runlist_merged:1; + u8 mft_attr_mapped:1; + u8 mp_rebuilt:1; + u8 attr_switched:1; + } status = { 0, 0, 0, 0 }; + + BUG_ON(!nr_pages); + BUG_ON(!pages); + BUG_ON(!*pages); + vi = pages[0]->mapping->host; + ni = NTFS_I(vi); + vol = ni->vol; + ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " + "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%x.", + vi->i_ino, ni->type, pages[0]->index, nr_pages, + (long long)pos, bytes); + blocksize_bits = vi->i_blkbits; + blocksize = 1 << blocksize_bits; + u = 0; + do { + struct page *page = pages[u]; + /* + * create_empty_buffers() will create uptodate/dirty buffers if + * the page is uptodate/dirty. + */ + if (!page_has_buffers(page)) { + create_empty_buffers(page, blocksize, 0); + if (unlikely(!page_has_buffers(page))) + return -ENOMEM; + } + } while (++u < nr_pages); + rl_write_locked = FALSE; + rl = NULL; + err = 0; + vcn = lcn = -1; + vcn_len = 0; + lcn_block = -1; + was_hole = FALSE; + cpos = pos >> vol->cluster_size_bits; + end = pos + bytes; + cend = (end + vol->cluster_size - 1) >> vol->cluster_size_bits; + /* + * Loop over each page and for each page over each buffer. Use goto to + * reduce indentation. + */ + u = 0; +do_next_page: + page = pages[u]; + bh_pos = (s64)page->index << PAGE_CACHE_SHIFT; + bh = head = page_buffers(page); + do { + VCN cdelta; + s64 bh_end; + unsigned bh_cofs; + + /* Clear buffer_new on all buffers to reinitialise state. */ + if (buffer_new(bh)) + clear_buffer_new(bh); + bh_end = bh_pos + blocksize; + bh_cpos = bh_pos >> vol->cluster_size_bits; + bh_cofs = bh_pos & vol->cluster_size_mask; + if (buffer_mapped(bh)) { + /* + * The buffer is already mapped. If it is uptodate, + * ignore it. + */ + if (buffer_uptodate(bh)) + continue; + /* + * The buffer is not uptodate. If the page is uptodate + * set the buffer uptodate and otherwise ignore it. + */ + if (PageUptodate(page)) { + set_buffer_uptodate(bh); + continue; + } + /* + * Neither the page nor the buffer are uptodate. If + * the buffer is only partially being written to, we + * need to read it in before the write, i.e. now. + */ + if ((bh_pos < pos && bh_end > pos) || + (bh_pos < end && bh_end > end)) { + /* + * If the buffer is fully or partially within + * the initialized size, do an actual read. + * Otherwise, simply zero the buffer. + */ + read_lock_irqsave(&ni->size_lock, flags); + initialized_size = ni->initialized_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (bh_pos < initialized_size) { + ntfs_submit_bh_for_read(bh); + *wait_bh++ = bh; + } else { + u8 *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh), 0, + blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + } + continue; + } + /* Unmapped buffer. Need to map it. */ + bh->b_bdev = vol->sb->s_bdev; + /* + * If the current buffer is in the same clusters as the map + * cache, there is no need to check the runlist again. The + * map cache is made up of @vcn, which is the first cached file + * cluster, @vcn_len which is the number of cached file + * clusters, @lcn is the device cluster corresponding to @vcn, + * and @lcn_block is the block number corresponding to @lcn. + */ + cdelta = bh_cpos - vcn; + if (likely(!cdelta || (cdelta > 0 && cdelta < vcn_len))) { +map_buffer_cached: + BUG_ON(lcn < 0); + bh->b_blocknr = lcn_block + + (cdelta << (vol->cluster_size_bits - + blocksize_bits)) + + (bh_cofs >> blocksize_bits); + set_buffer_mapped(bh); + /* + * If the page is uptodate so is the buffer. If the + * buffer is fully outside the write, we ignore it if + * it was already allocated and we mark it dirty so it + * gets written out if we allocated it. On the other + * hand, if we allocated the buffer but we are not + * marking it dirty we set buffer_new so we can do + * error recovery. + */ + if (PageUptodate(page)) { + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + if (unlikely(was_hole)) { + /* We allocated the buffer. */ + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + if (bh_end <= pos || bh_pos >= end) + mark_buffer_dirty(bh); + else + set_buffer_new(bh); + } + continue; + } + /* Page is _not_ uptodate. */ + if (likely(!was_hole)) { + /* + * Buffer was already allocated. If it is not + * uptodate and is only partially being written + * to, we need to read it in before the write, + * i.e. now. + */ + if (!buffer_uptodate(bh) && ((bh_pos < pos && + bh_end > pos) || + (bh_end > end && + bh_end > end))) { + /* + * If the buffer is fully or partially + * within the initialized size, do an + * actual read. Otherwise, simply zero + * the buffer. + */ + read_lock_irqsave(&ni->size_lock, + flags); + initialized_size = ni->initialized_size; + read_unlock_irqrestore(&ni->size_lock, + flags); + if (bh_pos < initialized_size) { + ntfs_submit_bh_for_read(bh); + *wait_bh++ = bh; + } else { + u8 *kaddr = kmap_atomic(page, + KM_USER0); + memset(kaddr + bh_offset(bh), + 0, blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + } + continue; + } + /* We allocated the buffer. */ + unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); + /* + * If the buffer is fully outside the write, zero it, + * set it uptodate, and mark it dirty so it gets + * written out. If it is partially being written to, + * zero region surrounding the write but leave it to + * commit write to do anything else. Finally, if the + * buffer is fully being overwritten, do nothing. + */ + if (bh_end <= pos || bh_pos >= end) { + if (!buffer_uptodate(bh)) { + u8 *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh), 0, + blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + mark_buffer_dirty(bh); + continue; + } + set_buffer_new(bh); + if (!buffer_uptodate(bh) && + (bh_pos < pos || bh_end > end)) { + u8 *kaddr; + unsigned pofs; + + kaddr = kmap_atomic(page, KM_USER0); + if (bh_pos < pos) { + pofs = bh_pos & ~PAGE_CACHE_MASK; + memset(kaddr + pofs, 0, pos - bh_pos); + } + if (bh_end > end) { + pofs = end & ~PAGE_CACHE_MASK; + memset(kaddr + pofs, 0, bh_end - end); + } + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + } + continue; + } + /* + * Slow path: this is the first buffer in the cluster. If it + * is outside allocated size and is not uptodate, zero it and + * set it uptodate. + */ + read_lock_irqsave(&ni->size_lock, flags); + initialized_size = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (bh_pos > initialized_size) { + if (PageUptodate(page)) { + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + } else if (!buffer_uptodate(bh)) { + u8 *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh), 0, blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + continue; + } + is_retry = FALSE; + if (!rl) { + down_read(&ni->runlist.lock); +retry_remap: + rl = ni->runlist.rl; + } + if (likely(rl != NULL)) { + /* Seek to element containing target cluster. */ + while (rl->length && rl[1].vcn <= bh_cpos) + rl++; + lcn = ntfs_rl_vcn_to_lcn(rl, bh_cpos); + if (likely(lcn >= 0)) { + /* + * Successful remap, setup the map cache and + * use that to deal with the buffer. + */ + was_hole = FALSE; + vcn = bh_cpos; + vcn_len = rl[1].vcn - vcn; + lcn_block = lcn << (vol->cluster_size_bits - + blocksize_bits); + /* + * If the number of remaining clusters in the + * @pages is smaller or equal to the number of + * cached clusters, unlock the runlist as the + * map cache will be used from now on. + */ + if (likely(vcn + vcn_len >= cend)) { + if (rl_write_locked) { + up_write(&ni->runlist.lock); + rl_write_locked = FALSE; + } else + up_read(&ni->runlist.lock); + rl = NULL; + } + goto map_buffer_cached; + } + } else + lcn = LCN_RL_NOT_MAPPED; + /* + * If it is not a hole and not out of bounds, the runlist is + * probably unmapped so try to map it now. + */ + if (unlikely(lcn != LCN_HOLE && lcn != LCN_ENOENT)) { + if (likely(!is_retry && lcn == LCN_RL_NOT_MAPPED)) { + /* Attempt to map runlist. */ + if (!rl_write_locked) { + /* + * We need the runlist locked for + * writing, so if it is locked for + * reading relock it now and retry in + * case it changed whilst we dropped + * the lock. + */ + up_read(&ni->runlist.lock); + down_write(&ni->runlist.lock); + rl_write_locked = TRUE; + goto retry_remap; + } + err = ntfs_map_runlist_nolock(ni, bh_cpos, + NULL); + if (likely(!err)) { + is_retry = TRUE; + goto retry_remap; + } + /* + * If @vcn is out of bounds, pretend @lcn is + * LCN_ENOENT. As long as the buffer is out + * of bounds this will work fine. + */ + if (err == -ENOENT) { + lcn = LCN_ENOENT; + err = 0; + goto rl_not_mapped_enoent; + } + } else + err = -EIO; + /* Failed to map the buffer, even after retrying. */ + bh->b_blocknr = -1; + ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " + "attribute type 0x%x, vcn 0x%llx, " + "vcn offset 0x%x, because its " + "location on disk could not be " + "determined%s (error code %i).", + ni->mft_no, ni->type, + (unsigned long long)bh_cpos, + (unsigned)bh_pos & + vol->cluster_size_mask, + is_retry ? " even after retrying" : "", + err); + break; + } +rl_not_mapped_enoent: + /* + * The buffer is in a hole or out of bounds. We need to fill + * the hole, unless the buffer is in a cluster which is not + * touched by the write, in which case we just leave the buffer + * unmapped. This can only happen when the cluster size is + * less than the page cache size. + */ + if (unlikely(vol->cluster_size < PAGE_CACHE_SIZE)) { + bh_cend = (bh_end + vol->cluster_size - 1) >> + vol->cluster_size_bits; + if ((bh_cend <= cpos || bh_cpos >= cend)) { + bh->b_blocknr = -1; + /* + * If the buffer is uptodate we skip it. If it + * is not but the page is uptodate, we can set + * the buffer uptodate. If the page is not + * uptodate, we can clear the buffer and set it + * uptodate. Whether this is worthwhile is + * debatable and this could be removed. + */ + if (PageUptodate(page)) { + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + } else if (!buffer_uptodate(bh)) { + u8 *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh), 0, + blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + continue; + } + } + /* + * Out of bounds buffer is invalid if it was not really out of + * bounds. + */ + BUG_ON(lcn != LCN_HOLE); + /* + * We need the runlist locked for writing, so if it is locked + * for reading relock it now and retry in case it changed + * whilst we dropped the lock. + */ + BUG_ON(!rl); + if (!rl_write_locked) { + up_read(&ni->runlist.lock); + down_write(&ni->runlist.lock); + rl_write_locked = TRUE; + goto retry_remap; + } + /* Find the previous last allocated cluster. */ + BUG_ON(rl->lcn != LCN_HOLE); + lcn = -1; + rl2 = rl; + while (--rl2 >= ni->runlist.rl) { + if (rl2->lcn >= 0) { + lcn = rl2->lcn + rl2->length; + break; + } + } + rl2 = ntfs_cluster_alloc(vol, bh_cpos, 1, lcn, DATA_ZONE, + FALSE); + if (IS_ERR(rl2)) { + err = PTR_ERR(rl2); + ntfs_debug("Failed to allocate cluster, error code %i.", + err); + break; + } + lcn = rl2->lcn; + rl = ntfs_runlists_merge(ni->runlist.rl, rl2); + if (IS_ERR(rl)) { + err = PTR_ERR(rl); + if (err != -ENOMEM) + err = -EIO; + if (ntfs_cluster_free_from_rl(vol, rl2)) { + ntfs_error(vol->sb, "Failed to release " + "allocated cluster in error " + "code path. Run chkdsk to " + "recover the lost cluster."); + NVolSetErrors(vol); + } + ntfs_free(rl2); + break; + } + ni->runlist.rl = rl; + status.runlist_merged = 1; + ntfs_debug("Allocated cluster, lcn 0x%llx.", lcn); + /* Map and lock the mft record and get the attribute record. */ + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + break; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + unmap_mft_record(base_ni); + break; + } + status.mft_attr_mapped = 1; + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, bh_cpos, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + break; + } + m = ctx->mrec; + a = ctx->attr; + /* + * Find the runlist element with which the attribute extent + * starts. Note, we cannot use the _attr_ version because we + * have mapped the mft record. That is ok because we know the + * runlist fragment must be mapped already to have ever gotten + * here, so we can just use the _rl_ version. + */ + vcn = sle64_to_cpu(a->data.non_resident.lowest_vcn); + rl2 = ntfs_rl_find_vcn_nolock(rl, vcn); + BUG_ON(!rl2); + BUG_ON(!rl2->length); + BUG_ON(rl2->lcn < LCN_HOLE); + highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); + /* + * If @highest_vcn is zero, calculate the real highest_vcn + * (which can really be zero). + */ + if (!highest_vcn) + highest_vcn = (sle64_to_cpu( + a->data.non_resident.allocated_size) >> + vol->cluster_size_bits) - 1; + /* + * Determine the size of the mapping pairs array for the new + * extent, i.e. the old extent with the hole filled. + */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, vcn, + highest_vcn); + if (unlikely(mp_size <= 0)) { + if (!(err = mp_size)) + err = -EIO; + ntfs_debug("Failed to get size for mapping pairs " + "array, error code %i.", err); + break; + } + /* + * Resize the attribute record to fit the new mapping pairs + * array. + */ + attr_rec_len = le32_to_cpu(a->length); + err = ntfs_attr_record_resize(m, a, mp_size + le16_to_cpu( + a->data.non_resident.mapping_pairs_offset)); + if (unlikely(err)) { + BUG_ON(err != -ENOSPC); + // TODO: Deal with this by using the current attribute + // and fill it with as much of the mapping pairs + // array as possible. Then loop over each attribute + // extent rewriting the mapping pairs arrays as we go + // along and if when we reach the end we have not + // enough space, try to resize the last attribute + // extent and if even that fails, add a new attribute + // extent. + // We could also try to resize at each step in the hope + // that we will not need to rewrite every single extent. + // Note, we may need to decompress some extents to fill + // the runlist as we are walking the extents... + ntfs_error(vol->sb, "Not enough space in the mft " + "record for the extended attribute " + "record. This case is not " + "implemented yet."); + err = -EOPNOTSUPP; + break ; + } + status.mp_rebuilt = 1; + /* + * Generate the mapping pairs array directly into the attribute + * record. + */ + err = ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( + a->data.non_resident.mapping_pairs_offset), + mp_size, rl2, vcn, highest_vcn, NULL); + if (unlikely(err)) { + ntfs_error(vol->sb, "Cannot fill hole in inode 0x%lx, " + "attribute type 0x%x, because building " + "the mapping pairs failed with error " + "code %i.", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + err = -EIO; + break; + } + /* Update the highest_vcn but only if it was not set. */ + if (unlikely(!a->data.non_resident.highest_vcn)) + a->data.non_resident.highest_vcn = + cpu_to_sle64(highest_vcn); + /* + * If the attribute is sparse/compressed, update the compressed + * size in the ntfs_inode structure and the attribute record. + */ + if (likely(NInoSparse(ni) || NInoCompressed(ni))) { + /* + * If we are not in the first attribute extent, switch + * to it, but first ensure the changes will make it to + * disk later. + */ + if (a->data.non_resident.lowest_vcn) { + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + ntfs_attr_reinit_search_ctx(ctx); + err = ntfs_attr_lookup(ni->type, ni->name, + ni->name_len, CASE_SENSITIVE, + 0, NULL, 0, ctx); + if (unlikely(err)) { + status.attr_switched = 1; + break; + } + /* @m is not used any more so do not set it. */ + a = ctx->attr; + } + write_lock_irqsave(&ni->size_lock, flags); + ni->itype.compressed.size += vol->cluster_size; + a->data.non_resident.compressed_size = + cpu_to_sle64(ni->itype.compressed.size); + write_unlock_irqrestore(&ni->size_lock, flags); + } + /* Ensure the changes make it to disk. */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + /* Successfully filled the hole. */ + status.runlist_merged = 0; + status.mft_attr_mapped = 0; + status.mp_rebuilt = 0; + /* Setup the map cache and use that to deal with the buffer. */ + was_hole = TRUE; + vcn = bh_cpos; + vcn_len = 1; + lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits); + cdelta = 0; + /* + * If the number of remaining clusters in the @pages is smaller + * or equal to the number of cached clusters, unlock the + * runlist as the map cache will be used from now on. + */ + if (likely(vcn + vcn_len >= cend)) { + up_write(&ni->runlist.lock); + rl_write_locked = FALSE; + rl = NULL; + } + goto map_buffer_cached; + } while (bh_pos += blocksize, (bh = bh->b_this_page) != head); + /* If there are no errors, do the next page. */ + if (likely(!err && ++u < nr_pages)) + goto do_next_page; + /* If there are no errors, release the runlist lock if we took it. */ + if (likely(!err)) { + if (unlikely(rl_write_locked)) { + up_write(&ni->runlist.lock); + rl_write_locked = FALSE; + } else if (unlikely(rl)) + up_read(&ni->runlist.lock); + rl = NULL; + } + /* If we issued read requests, let them complete. */ + read_lock_irqsave(&ni->size_lock, flags); + initialized_size = ni->initialized_size; + read_unlock_irqrestore(&ni->size_lock, flags); + while (wait_bh > wait) { + bh = *--wait_bh; + wait_on_buffer(bh); + if (likely(buffer_uptodate(bh))) { + page = bh->b_page; + bh_pos = ((s64)page->index << PAGE_CACHE_SHIFT) + + bh_offset(bh); + /* + * If the buffer overflows the initialized size, need + * to zero the overflowing region. + */ + if (unlikely(bh_pos + blocksize > initialized_size)) { + u8 *kaddr; + int ofs = 0; + + if (likely(bh_pos < initialized_size)) + ofs = initialized_size - bh_pos; + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh) + ofs, 0, + blocksize - ofs); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + } + } else /* if (unlikely(!buffer_uptodate(bh))) */ + err = -EIO; + } + if (likely(!err)) { + /* Clear buffer_new on all buffers. */ + u = 0; + do { + bh = head = page_buffers(pages[u]); + do { + if (buffer_new(bh)) + clear_buffer_new(bh); + } while ((bh = bh->b_this_page) != head); + } while (++u < nr_pages); + ntfs_debug("Done."); + return err; + } + if (status.attr_switched) { + /* Get back to the attribute extent we modified. */ + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, bh_cpos, NULL, 0, ctx)) { + ntfs_error(vol->sb, "Failed to find required " + "attribute extent of attribute in " + "error code path. Run chkdsk to " + "recover."); + write_lock_irqsave(&ni->size_lock, flags); + ni->itype.compressed.size += vol->cluster_size; + write_unlock_irqrestore(&ni->size_lock, flags); + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + /* + * The only thing that is now wrong is the compressed + * size of the base attribute extent which chkdsk + * should be able to fix. + */ + NVolSetErrors(vol); + } else { + m = ctx->mrec; + a = ctx->attr; + status.attr_switched = 0; + } + } + /* + * If the runlist has been modified, need to restore it by punching a + * hole into it and we then need to deallocate the on-disk cluster as + * well. Note, we only modify the runlist if we are able to generate a + * new mapping pairs array, i.e. only when the mapped attribute extent + * is not switched. + */ + if (status.runlist_merged && !status.attr_switched) { + BUG_ON(!rl_write_locked); + /* Make the file cluster we allocated sparse in the runlist. */ + if (ntfs_rl_punch_nolock(vol, &ni->runlist, bh_cpos, 1)) { + ntfs_error(vol->sb, "Failed to punch hole into " + "attribute runlist in error code " + "path. Run chkdsk to recover the " + "lost cluster."); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } else /* if (success) */ { + status.runlist_merged = 0; + /* + * Deallocate the on-disk cluster we allocated but only + * if we succeeded in punching its vcn out of the + * runlist. + */ + down_write(&vol->lcnbmp_lock); + if (ntfs_bitmap_clear_bit(vol->lcnbmp_ino, lcn)) { + ntfs_error(vol->sb, "Failed to release " + "allocated cluster in error " + "code path. Run chkdsk to " + "recover the lost cluster."); + NVolSetErrors(vol); + } + up_write(&vol->lcnbmp_lock); + } + } + /* + * Resize the attribute record to its old size and rebuild the mapping + * pairs array. Note, we only can do this if the runlist has been + * restored to its old state which also implies that the mapped + * attribute extent is not switched. + */ + if (status.mp_rebuilt && !status.runlist_merged) { + if (ntfs_attr_record_resize(m, a, attr_rec_len)) { + ntfs_error(vol->sb, "Failed to restore attribute " + "record in error code path. Run " + "chkdsk to recover."); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } else /* if (success) */ { + if (ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->data.non_resident. + mapping_pairs_offset), attr_rec_len - + le16_to_cpu(a->data.non_resident. + mapping_pairs_offset), ni->runlist.rl, + vcn, highest_vcn, NULL)) { + ntfs_error(vol->sb, "Failed to restore " + "mapping pairs array in error " + "code path. Run chkdsk to " + "recover."); + make_bad_inode(vi); + make_bad_inode(VFS_I(base_ni)); + NVolSetErrors(vol); + } + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + } + } + /* Release the mft record and the attribute. */ + if (status.mft_attr_mapped) { + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + } + /* Release the runlist lock. */ + if (rl_write_locked) + up_write(&ni->runlist.lock); + else if (rl) + up_read(&ni->runlist.lock); + /* + * Zero out any newly allocated blocks to avoid exposing stale data. + * If BH_New is set, we know that the block was newly allocated above + * and that it has not been fully zeroed and marked dirty yet. + */ + nr_pages = u; + u = 0; + end = bh_cpos << vol->cluster_size_bits; + do { + page = pages[u]; + bh = head = page_buffers(page); + do { + if (u == nr_pages && + ((s64)page->index << PAGE_CACHE_SHIFT) + + bh_offset(bh) >= end) + break; + if (!buffer_new(bh)) + continue; + clear_buffer_new(bh); + if (!buffer_uptodate(bh)) { + if (PageUptodate(page)) + set_buffer_uptodate(bh); + else { + u8 *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + bh_offset(bh), 0, + blocksize); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); + set_buffer_uptodate(bh); + } + } + mark_buffer_dirty(bh); + } while ((bh = bh->b_this_page) != head); + } while (++u <= nr_pages); + ntfs_error(vol->sb, "Failed. Returning error code %i.", err); + return err; +} + +/* + * Copy as much as we can into the pages and return the number of bytes which + * were sucessfully copied. If a fault is encountered then clear the pages + * out to (ofs + bytes) and return the number of bytes which were copied. + */ +static inline size_t ntfs_copy_from_user(struct page **pages, + unsigned nr_pages, unsigned ofs, const char __user *buf, + size_t bytes) +{ + struct page **last_page = pages + nr_pages; + char *kaddr; + size_t total = 0; + unsigned len; + int left; + + do { + len = PAGE_CACHE_SIZE - ofs; + if (len > bytes) + len = bytes; + kaddr = kmap_atomic(*pages, KM_USER0); + left = __copy_from_user_inatomic(kaddr + ofs, buf, len); + kunmap_atomic(kaddr, KM_USER0); + if (unlikely(left)) { + /* Do it the slow way. */ + kaddr = kmap(*pages); + left = __copy_from_user(kaddr + ofs, buf, len); + kunmap(*pages); + if (unlikely(left)) + goto err_out; + } + total += len; + bytes -= len; + if (!bytes) + break; + buf += len; + ofs = 0; + } while (++pages < last_page); +out: + return total; +err_out: + total += len - left; + /* Zero the rest of the target like __copy_from_user(). */ + while (++pages < last_page) { + bytes -= len; + if (!bytes) + break; + len = PAGE_CACHE_SIZE; + if (len > bytes) + len = bytes; + kaddr = kmap_atomic(*pages, KM_USER0); + memset(kaddr, 0, len); + kunmap_atomic(kaddr, KM_USER0); + } + goto out; +} + +static size_t __ntfs_copy_from_user_iovec(char *vaddr, + const struct iovec *iov, size_t iov_ofs, size_t bytes) +{ + size_t total = 0; + + while (1) { + const char __user *buf = iov->iov_base + iov_ofs; + unsigned len; + size_t left; + + len = iov->iov_len - iov_ofs; + if (len > bytes) + len = bytes; + left = __copy_from_user_inatomic(vaddr, buf, len); + total += len; + bytes -= len; + vaddr += len; + if (unlikely(left)) { + /* + * Zero the rest of the target like __copy_from_user(). + */ + memset(vaddr, 0, bytes); + total -= left; + break; + } + if (!bytes) + break; + iov++; + iov_ofs = 0; + } + return total; +} + +static inline void ntfs_set_next_iovec(const struct iovec **iovp, + size_t *iov_ofsp, size_t bytes) +{ + const struct iovec *iov = *iovp; + size_t iov_ofs = *iov_ofsp; + + while (bytes) { + unsigned len; + + len = iov->iov_len - iov_ofs; + if (len > bytes) + len = bytes; + bytes -= len; + iov_ofs += len; + if (iov->iov_len == iov_ofs) { + iov++; + iov_ofs = 0; + } + } + *iovp = iov; + *iov_ofsp = iov_ofs; +} + +/* + * This has the same side-effects and return value as ntfs_copy_from_user(). + * The difference is that on a fault we need to memset the remainder of the + * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s + * single-segment behaviour. + * + * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and + * when not atomic. This is ok because __ntfs_copy_from_user_iovec() calls + * __copy_from_user_inatomic() and it is ok to call this when non-atomic. In + * fact, the only difference between __copy_from_user_inatomic() and + * __copy_from_user() is that the latter calls might_sleep(). And on many + * architectures __copy_from_user_inatomic() is just defined to + * __copy_from_user() so it makes no difference at all on those architectures. + */ +static inline size_t ntfs_copy_from_user_iovec(struct page **pages, + unsigned nr_pages, unsigned ofs, const struct iovec **iov, + size_t *iov_ofs, size_t bytes) +{ + struct page **last_page = pages + nr_pages; + char *kaddr; + size_t copied, len, total = 0; + + do { + len = PAGE_CACHE_SIZE - ofs; + if (len > bytes) + len = bytes; + kaddr = kmap_atomic(*pages, KM_USER0); + copied = __ntfs_copy_from_user_iovec(kaddr + ofs, + *iov, *iov_ofs, len); + kunmap_atomic(kaddr, KM_USER0); + if (unlikely(copied != len)) { + /* Do it the slow way. */ + kaddr = kmap(*pages); + copied = __ntfs_copy_from_user_iovec(kaddr + ofs, + *iov, *iov_ofs, len); + kunmap(*pages); + if (unlikely(copied != len)) + goto err_out; + } + total += len; + bytes -= len; + if (!bytes) + break; + ntfs_set_next_iovec(iov, iov_ofs, len); + ofs = 0; + } while (++pages < last_page); +out: + return total; +err_out: + total += copied; + /* Zero the rest of the target like __copy_from_user(). */ + while (++pages < last_page) { + bytes -= len; + if (!bytes) + break; + len = PAGE_CACHE_SIZE; + if (len > bytes) + len = bytes; + kaddr = kmap_atomic(*pages, KM_USER0); + memset(kaddr, 0, len); + kunmap_atomic(kaddr, KM_USER0); + } + goto out; +} + +static inline void ntfs_flush_dcache_pages(struct page **pages, + unsigned nr_pages) +{ + BUG_ON(!nr_pages); + do { + /* + * Warning: Do not do the decrement at the same time as the + * call because flush_dcache_page() is a NULL macro on i386 + * and hence the decrement never happens. + */ + flush_dcache_page(pages[nr_pages]); + } while (--nr_pages > 0); +} + +/** + * ntfs_commit_pages_after_non_resident_write - commit the received data + * @pages: array of destination pages + * @nr_pages: number of pages in @pages + * @pos: byte position in file at which the write begins + * @bytes: number of bytes to be written + * + * See description of ntfs_commit_pages_after_write(), below. + */ +static inline int ntfs_commit_pages_after_non_resident_write( + struct page **pages, const unsigned nr_pages, + s64 pos, size_t bytes) +{ + s64 end, initialized_size; + struct inode *vi; + ntfs_inode *ni, *base_ni; + struct buffer_head *bh, *head; + ntfs_attr_search_ctx *ctx; + MFT_RECORD *m; + ATTR_RECORD *a; + unsigned long flags; + unsigned blocksize, u; + int err; + + vi = pages[0]->mapping->host; + ni = NTFS_I(vi); + blocksize = 1 << vi->i_blkbits; + end = pos + bytes; + u = 0; + do { + s64 bh_pos; + struct page *page; + BOOL partial; + + page = pages[u]; + bh_pos = (s64)page->index << PAGE_CACHE_SHIFT; + bh = head = page_buffers(page); + partial = FALSE; + do { + s64 bh_end; + + bh_end = bh_pos + blocksize; + if (bh_end <= pos || bh_pos >= end) { + if (!buffer_uptodate(bh)) + partial = TRUE; + } else { + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + } + } while (bh_pos += blocksize, (bh = bh->b_this_page) != head); + /* + * If all buffers are now uptodate but the page is not, set the + * page uptodate. + */ + if (!partial && !PageUptodate(page)) + SetPageUptodate(page); + } while (++u < nr_pages); + /* + * Finally, if we do not need to update initialized_size or i_size we + * are finished. + */ + read_lock_irqsave(&ni->size_lock, flags); + initialized_size = ni->initialized_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (end <= initialized_size) { + ntfs_debug("Done."); + return 0; + } + /* + * Update initialized_size/i_size as appropriate, both in the inode and + * the mft record. + */ + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + /* Map, pin, and lock the mft record. */ + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + ctx = NULL; + goto err_out; + } + BUG_ON(!NInoNonResident(ni)); + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + a = ctx->attr; + BUG_ON(!a->non_resident); + write_lock_irqsave(&ni->size_lock, flags); + BUG_ON(end > ni->allocated_size); + ni->initialized_size = end; + a->data.non_resident.initialized_size = cpu_to_sle64(end); + if (end > i_size_read(vi)) { + i_size_write(vi, end); + a->data.non_resident.data_size = + a->data.non_resident.initialized_size; + } + write_unlock_irqrestore(&ni->size_lock, flags); + /* Mark the mft record dirty, so it gets written back. */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + ntfs_debug("Done."); + return 0; +err_out: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error " + "code %i).", err); + if (err != -ENOMEM) { + NVolSetErrors(ni->vol); + make_bad_inode(VFS_I(base_ni)); + make_bad_inode(vi); + } + return err; +} + +/** + * ntfs_commit_pages_after_write - commit the received data + * @pages: array of destination pages + * @nr_pages: number of pages in @pages + * @pos: byte position in file at which the write begins + * @bytes: number of bytes to be written + * + * This is called from ntfs_file_buffered_write() with i_sem held on the inode + * (@pages[0]->mapping->host). There are @nr_pages pages in @pages which are + * locked but not kmap()ped. The source data has already been copied into the + * @page. ntfs_prepare_pages_for_non_resident_write() has been called before + * the data was copied (for non-resident attributes only) and it returned + * success. + * + * Need to set uptodate and mark dirty all buffers within the boundary of the + * write. If all buffers in a page are uptodate we set the page uptodate, too. + * + * Setting the buffers dirty ensures that they get written out later when + * ntfs_writepage() is invoked by the VM. + * + * Finally, we need to update i_size and initialized_size as appropriate both + * in the inode and the mft record. + * + * This is modelled after fs/buffer.c::generic_commit_write(), which marks + * buffers uptodate and dirty, sets the page uptodate if all buffers in the + * page are uptodate, and updates i_size if the end of io is beyond i_size. In + * that case, it also marks the inode dirty. + * + * If things have gone as outlined in + * ntfs_prepare_pages_for_non_resident_write(), we do not need to do any page + * content modifications here for non-resident attributes. For resident + * attributes we need to do the uptodate bringing here which we combine with + * the copying into the mft record which means we save one atomic kmap. + * + * Return 0 on success or -errno on error. + */ +static int ntfs_commit_pages_after_write(struct page **pages, + const unsigned nr_pages, s64 pos, size_t bytes) +{ + s64 end, initialized_size; + loff_t i_size; + struct inode *vi; + ntfs_inode *ni, *base_ni; + struct page *page; + ntfs_attr_search_ctx *ctx; + MFT_RECORD *m; + ATTR_RECORD *a; + char *kattr, *kaddr; + unsigned long flags; + u32 attr_len; + int err; + + BUG_ON(!nr_pages); + BUG_ON(!pages); + page = pages[0]; + BUG_ON(!page); + vi = page->mapping->host; + ni = NTFS_I(vi); + ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " + "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%x.", + vi->i_ino, ni->type, page->index, nr_pages, + (long long)pos, bytes); + if (NInoNonResident(ni)) + return ntfs_commit_pages_after_non_resident_write(pages, + nr_pages, pos, bytes); + BUG_ON(nr_pages > 1); + /* + * Attribute is resident, implying it is not compressed, encrypted, or + * sparse. + */ + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + BUG_ON(NInoNonResident(ni)); + /* Map, pin, and lock the mft record. */ + m = map_mft_record(base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + m = NULL; + ctx = NULL; + goto err_out; + } + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; + } + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; + } + a = ctx->attr; + BUG_ON(a->non_resident); + /* The total length of the attribute value. */ + attr_len = le32_to_cpu(a->data.resident.value_length); + i_size = i_size_read(vi); + BUG_ON(attr_len != i_size); + BUG_ON(pos > attr_len); + end = pos + bytes; + BUG_ON(end > le32_to_cpu(a->length) - + le16_to_cpu(a->data.resident.value_offset)); + kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); + kaddr = kmap_atomic(page, KM_USER0); + /* Copy the received data from the page to the mft record. */ + memcpy(kattr + pos, kaddr + pos, bytes); + /* Update the attribute length if necessary. */ + if (end > attr_len) { + attr_len = end; + a->data.resident.value_length = cpu_to_le32(attr_len); + } + /* + * If the page is not uptodate, bring the out of bounds area(s) + * uptodate by copying data from the mft record to the page. + */ + if (!PageUptodate(page)) { + if (pos > 0) + memcpy(kaddr, kattr, pos); + if (end < attr_len) + memcpy(kaddr + end, kattr + end, attr_len - end); + /* Zero the region outside the end of the attribute value. */ + memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); + flush_dcache_page(page); + SetPageUptodate(page); + } + kunmap_atomic(kaddr, KM_USER0); + /* Update initialized_size/i_size if necessary. */ + read_lock_irqsave(&ni->size_lock, flags); + initialized_size = ni->initialized_size; + BUG_ON(end > ni->allocated_size); + read_unlock_irqrestore(&ni->size_lock, flags); + BUG_ON(initialized_size != i_size); + if (end > initialized_size) { + unsigned long flags; + + write_lock_irqsave(&ni->size_lock, flags); + ni->initialized_size = end; + i_size_write(vi, end); + write_unlock_irqrestore(&ni->size_lock, flags); + } + /* Mark the mft record dirty, so it gets written back. */ + flush_dcache_mft_record_page(ctx->ntfs_ino); + mark_mft_record_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + ntfs_debug("Done."); + return 0; +err_out: + if (err == -ENOMEM) { + ntfs_warning(vi->i_sb, "Error allocating memory required to " + "commit the write."); + if (PageUptodate(page)) { + ntfs_warning(vi->i_sb, "Page is uptodate, setting " + "dirty so the write will be retried " + "later on by the VM."); + /* + * Put the page on mapping->dirty_pages, but leave its + * buffers' dirty state as-is. + */ + __set_page_dirty_nobuffers(page); + err = 0; + } else + ntfs_error(vi->i_sb, "Page is not uptodate. Written " + "data has been lost."); + } else { + ntfs_error(vi->i_sb, "Resident attribute commit write failed " + "with error %i.", err); + NVolSetErrors(ni->vol); + make_bad_inode(VFS_I(base_ni)); + make_bad_inode(vi); + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(base_ni); + return err; +} + +/** + * ntfs_file_buffered_write - + * + * Locking: The vfs is holding ->i_sem on the inode. + */ +static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, + const struct iovec *iov, unsigned long nr_segs, + loff_t pos, loff_t *ppos, size_t count) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *vi = mapping->host; + ntfs_inode *ni = NTFS_I(vi); + ntfs_volume *vol = ni->vol; + struct page *pages[NTFS_MAX_PAGES_PER_CLUSTER]; + struct page *cached_page = NULL; + char __user *buf = NULL; + s64 end, ll; + VCN last_vcn; + LCN lcn; + unsigned long flags; + size_t bytes, iov_ofs; + ssize_t status, written; + unsigned nr_pages; + int err; + struct pagevec lru_pvec; + + ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " + "pos 0x%llx, count 0x%lx.", + vi->i_ino, (unsigned)le32_to_cpu(ni->type), + (unsigned long long)pos, (unsigned long)count); + if (unlikely(!count)) + return 0; + BUG_ON(NInoMstProtected(ni)); + /* + * If the attribute is not an index root and it is encrypted or + * compressed, we cannot write to it yet. Note we need to check for + * AT_INDEX_ALLOCATION since this is the type of both directory and + * index inodes. + */ + if (ni->type != AT_INDEX_ALLOCATION) { + /* If file is encrypted, deny access, just like NT4. */ + if (NInoEncrypted(ni)) { + ntfs_debug("Denying write access to encrypted file."); + return -EACCES; + } + if (NInoCompressed(ni)) { + ntfs_error(vi->i_sb, "Writing to compressed files is " + "not implemented yet. Sorry."); + return -EOPNOTSUPP; + } + } + /* + * If a previous ntfs_truncate() failed, repeat it and abort if it + * fails again. + */ + if (unlikely(NInoTruncateFailed(ni))) { + down_write(&vi->i_alloc_sem); + err = ntfs_truncate(vi); + up_write(&vi->i_alloc_sem); + if (err || NInoTruncateFailed(ni)) { + if (!err) + err = -EIO; + ntfs_error(vol->sb, "Cannot perform write to inode " + "0x%lx, attribute type 0x%x, because " + "ntfs_truncate() failed (error code " + "%i).", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + return err; + } + } + /* The first byte after the write. */ + end = pos + count; + /* + * If the write goes beyond the allocated size, extend the allocation + * to cover the whole of the write, rounded up to the nearest cluster. + */ + read_lock_irqsave(&ni->size_lock, flags); + ll = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (end > ll) { + /* Extend the allocation without changing the data size. */ + ll = ntfs_attr_extend_allocation(ni, end, -1, pos); + if (likely(ll >= 0)) { + BUG_ON(pos >= ll); + /* If the extension was partial truncate the write. */ + if (end > ll) { + ntfs_debug("Truncating write to inode 0x%lx, " + "attribute type 0x%x, because " + "the allocation was only " + "partially extended.", + vi->i_ino, (unsigned) + le32_to_cpu(ni->type)); + end = ll; + count = ll - pos; + } + } else { + err = ll; + read_lock_irqsave(&ni->size_lock, flags); + ll = ni->allocated_size; + read_unlock_irqrestore(&ni->size_lock, flags); + /* Perform a partial write if possible or fail. */ + if (pos < ll) { + ntfs_debug("Truncating write to inode 0x%lx, " + "attribute type 0x%x, because " + "extending the allocation " + "failed (error code %i).", + vi->i_ino, (unsigned) + le32_to_cpu(ni->type), err); + end = ll; + count = ll - pos; + } else { + ntfs_error(vol->sb, "Cannot perform write to " + "inode 0x%lx, attribute type " + "0x%x, because extending the " + "allocation failed (error " + "code %i).", vi->i_ino, + (unsigned) + le32_to_cpu(ni->type), err); + return err; + } + } + } + pagevec_init(&lru_pvec, 0); + written = 0; + /* + * If the write starts beyond the initialized size, extend it up to the + * beginning of the write and initialize all non-sparse space between + * the old initialized size and the new one. This automatically also + * increments the vfs inode->i_size to keep it above or equal to the + * initialized_size. + */ + read_lock_irqsave(&ni->size_lock, flags); + ll = ni->initialized_size; + read_unlock_irqrestore(&ni->size_lock, flags); + if (pos > ll) { + err = ntfs_attr_extend_initialized(ni, pos, &cached_page, + &lru_pvec); + if (err < 0) { + ntfs_error(vol->sb, "Cannot perform write to inode " + "0x%lx, attribute type 0x%x, because " + "extending the initialized size " + "failed (error code %i).", vi->i_ino, + (unsigned)le32_to_cpu(ni->type), err); + status = err; + goto err_out; + } + } + /* + * Determine the number of pages per cluster for non-resident + * attributes. + */ + nr_pages = 1; + if (vol->cluster_size > PAGE_CACHE_SIZE && NInoNonResident(ni)) + nr_pages = vol->cluster_size >> PAGE_CACHE_SHIFT; + /* Finally, perform the actual write. */ + last_vcn = -1; + if (likely(nr_segs == 1)) + buf = iov->iov_base; + else + iov_ofs = 0; /* Offset in the current iovec. */ + do { + VCN vcn; + pgoff_t idx, start_idx; + unsigned ofs, do_pages, u; + size_t copied; + + start_idx = idx = pos >> PAGE_CACHE_SHIFT; + ofs = pos & ~PAGE_CACHE_MASK; + bytes = PAGE_CACHE_SIZE - ofs; + do_pages = 1; + if (nr_pages > 1) { + vcn = pos >> vol->cluster_size_bits; + if (vcn != last_vcn) { + last_vcn = vcn; + /* + * Get the lcn of the vcn the write is in. If + * it is a hole, need to lock down all pages in + * the cluster. + */ + down_read(&ni->runlist.lock); + lcn = ntfs_attr_vcn_to_lcn_nolock(ni, pos >> + vol->cluster_size_bits, FALSE); + up_read(&ni->runlist.lock); + if (unlikely(lcn < LCN_HOLE)) { + status = -EIO; + if (lcn == LCN_ENOMEM) + status = -ENOMEM; + else + ntfs_error(vol->sb, "Cannot " + "perform write to " + "inode 0x%lx, " + "attribute type 0x%x, " + "because the attribute " + "is corrupt.", + vi->i_ino, (unsigned) + le32_to_cpu(ni->type)); + break; + } + if (lcn == LCN_HOLE) { + start_idx = (pos & ~(s64) + vol->cluster_size_mask) + >> PAGE_CACHE_SHIFT; + bytes = vol->cluster_size - (pos & + vol->cluster_size_mask); + do_pages = nr_pages; + } + } + } + if (bytes > count) + bytes = count; + /* + * Bring in the user page(s) that we will copy from _first_. + * Otherwise there is a nasty deadlock on copying from the same + * page(s) as we are writing to, without it/them being marked + * up-to-date. Note, at present there is nothing to stop the + * pages being swapped out between us bringing them into memory + * and doing the actual copying. + */ + if (likely(nr_segs == 1)) + ntfs_fault_in_pages_readable(buf, bytes); + else + ntfs_fault_in_pages_readable_iovec(iov, iov_ofs, bytes); + /* Get and lock @do_pages starting at index @start_idx. */ + status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages, + pages, &cached_page, &lru_pvec); + if (unlikely(status)) + break; + /* + * For non-resident attributes, we need to fill any holes with + * actual clusters and ensure all bufferes are mapped. We also + * need to bring uptodate any buffers that are only partially + * being written to. + */ + if (NInoNonResident(ni)) { + status = ntfs_prepare_pages_for_non_resident_write( + pages, do_pages, pos, bytes); + if (unlikely(status)) { + loff_t i_size; + + do { + unlock_page(pages[--do_pages]); + page_cache_release(pages[do_pages]); + } while (do_pages); + /* + * The write preparation may have instantiated + * allocated space outside i_size. Trim this + * off again. We can ignore any errors in this + * case as we will just be waisting a bit of + * allocated space, which is not a disaster. + */ + i_size = i_size_read(vi); + if (pos + bytes > i_size) + vmtruncate(vi, i_size); + break; + } + } + u = (pos >> PAGE_CACHE_SHIFT) - pages[0]->index; + if (likely(nr_segs == 1)) { + copied = ntfs_copy_from_user(pages + u, do_pages - u, + ofs, buf, bytes); + buf += copied; + } else + copied = ntfs_copy_from_user_iovec(pages + u, + do_pages - u, ofs, &iov, &iov_ofs, + bytes); + ntfs_flush_dcache_pages(pages + u, do_pages - u); + status = ntfs_commit_pages_after_write(pages, do_pages, pos, + bytes); + if (likely(!status)) { + written += copied; + count -= copied; + pos += copied; + if (unlikely(copied != bytes)) + status = -EFAULT; + } + do { + unlock_page(pages[--do_pages]); + mark_page_accessed(pages[do_pages]); + page_cache_release(pages[do_pages]); + } while (do_pages); + if (unlikely(status)) + break; + balance_dirty_pages_ratelimited(mapping); + cond_resched(); + } while (count); +err_out: + *ppos = pos; + if (cached_page) + page_cache_release(cached_page); + /* For now, when the user asks for O_SYNC, we actually give O_DSYNC. */ + if (likely(!status)) { + if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(vi))) { + if (!mapping->a_ops->writepage || !is_sync_kiocb(iocb)) + status = generic_osync_inode(vi, mapping, + OSYNC_METADATA|OSYNC_DATA); + } + } + pagevec_lru_add(&lru_pvec); + ntfs_debug("Done. Returning %s (written 0x%lx, status %li).", + written ? "written" : "status", (unsigned long)written, + (long)status); + return written ? written : status; +} + +/** + * ntfs_file_aio_write_nolock - + */ +static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, + const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + loff_t pos; + unsigned long seg; + size_t count; /* after file limit checks */ + ssize_t written, err; + + count = 0; + for (seg = 0; seg < nr_segs; seg++) { + const struct iovec *iv = &iov[seg]; + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + count += iv->iov_len; + if (unlikely((ssize_t)(count|iv->iov_len) < 0)) + return -EINVAL; + if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) + continue; + if (!seg) + return -EFAULT; + nr_segs = seg; + count -= iv->iov_len; /* This segment is no good */ + break; + } + pos = *ppos; + vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); + /* We can write back this queue in page reclaim. */ + current->backing_dev_info = mapping->backing_dev_info; + written = 0; + err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); + if (err) + goto out; + if (!count) + goto out; + err = remove_suid(file->f_dentry); + if (err) + goto out; + inode_update_time(inode, 1); + written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos, + count); +out: + current->backing_dev_info = NULL; + return written ? written : err; +} + +/** + * ntfs_file_aio_write - + */ +static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf, + size_t count, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + struct iovec local_iov = { .iov_base = (void __user *)buf, + .iov_len = count }; + + BUG_ON(iocb->ki_pos != pos); + + down(&inode->i_sem); + ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); + up(&inode->i_sem); + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + int err = sync_page_range(inode, mapping, pos, ret); + if (err < 0) + ret = err; + } + return ret; +} + +/** + * ntfs_file_writev - + * + * Basically the same as generic_file_writev() except that it ends up calling + * ntfs_file_aio_write_nolock() instead of __generic_file_aio_write_nolock(). + */ +static ssize_t ntfs_file_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + struct kiocb kiocb; + ssize_t ret; + + down(&inode->i_sem); + init_sync_kiocb(&kiocb, file); + ret = ntfs_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + up(&inode->i_sem); + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + int err = sync_page_range(inode, mapping, *ppos - ret, ret); + if (err < 0) + ret = err; + } + return ret; +} + +/** + * ntfs_file_write - simple wrapper for ntfs_file_writev() + */ +static ssize_t ntfs_file_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct iovec local_iov = { .iov_base = (void __user *)buf, + .iov_len = count }; + + return ntfs_file_writev(file, &local_iov, 1, ppos); +} + /** * ntfs_file_fsync - sync a file to disk * @filp: file to be synced @@ -113,39 +2296,39 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, #endif /* NTFS_RW */ struct file_operations ntfs_file_ops = { - .llseek = generic_file_llseek, /* Seek inside file. */ - .read = generic_file_read, /* Read from file. */ - .aio_read = generic_file_aio_read, /* Async read from file. */ - .readv = generic_file_readv, /* Read from file. */ + .llseek = generic_file_llseek, /* Seek inside file. */ + .read = generic_file_read, /* Read from file. */ + .aio_read = generic_file_aio_read, /* Async read from file. */ + .readv = generic_file_readv, /* Read from file. */ #ifdef NTFS_RW - .write = generic_file_write, /* Write to file. */ - .aio_write = generic_file_aio_write, /* Async write to file. */ - .writev = generic_file_writev, /* Write to file. */ - /*.release = ,*/ /* Last file is closed. See - fs/ext2/file.c:: - ext2_release_file() for - how to use this to discard - preallocated space for - write opened files. */ - .fsync = ntfs_file_fsync, /* Sync a file to disk. */ - /*.aio_fsync = ,*/ /* Sync all outstanding async - i/o operations on a - kiocb. */ + .write = ntfs_file_write, /* Write to file. */ + .aio_write = ntfs_file_aio_write, /* Async write to file. */ + .writev = ntfs_file_writev, /* Write to file. */ + /*.release = ,*/ /* Last file is closed. See + fs/ext2/file.c:: + ext2_release_file() for + how to use this to discard + preallocated space for + write opened files. */ + .fsync = ntfs_file_fsync, /* Sync a file to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a + kiocb. */ #endif /* NTFS_RW */ - /*.ioctl = ,*/ /* Perform function on the - mounted filesystem. */ - .mmap = generic_file_mmap, /* Mmap file. */ - .open = ntfs_file_open, /* Open file. */ - .sendfile = generic_file_sendfile, /* Zero-copy data send with - the data source being on - the ntfs partition. We - do not need to care about - the data destination. */ - /*.sendpage = ,*/ /* Zero-copy data send with - the data destination being - on the ntfs partition. We - do not need to care about - the data source. */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ + .mmap = generic_file_mmap, /* Mmap file. */ + .open = ntfs_file_open, /* Open file. */ + .sendfile = generic_file_sendfile, /* Zero-copy data send with + the data source being on + the ntfs partition. We do + not need to care about the + data destination. */ + /*.sendpage = ,*/ /* Zero-copy data send with + the data destination being + on the ntfs partition. We + do not need to care about + the data source. */ }; struct inode_operations ntfs_file_inode_ops = { From f255f0dd1b4ef7af0e48f5603d1f27ee4bad5848 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 10 Oct 2005 17:10:54 +1000 Subject: [PATCH 0371/1939] powerpc: pci_dn's should point to their device_node's Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 46879d7de925..f79c5982446b 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -220,6 +220,7 @@ static struct device_node *build_device_node(HvBusNumber Bus, return NULL; } node->data = pdn; + pdn->node = node; list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List); #if 0 pdn->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); From 3a5f8c5f788d68e325d9fe3c26f4df5a5aee838a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 11 Oct 2005 19:40:20 +1000 Subject: [PATCH 0372/1939] powerpc: make iSeries boot again On ARCH=ppc64 we were getting htab_hash_mask recalculated to the correct value for our particular machine by accident. In the merge tree, that code was commented out, so htab_hash_mask was being corrupted. We now set ppc64_pft_size instead which gets htab_has_mask calculated correctly for us later. We should put an ibm,pft-size property in the device tree at some point. Also set -mno-minimal-toc in some makefiles. Allow iSeries to configure PROC_DEVICETREE. Signed-off-by: Stephen Rothwell --- arch/powerpc/Kconfig | 2 +- arch/powerpc/mm/Makefile | 4 ++++ arch/powerpc/platforms/iseries/Makefile | 2 ++ arch/powerpc/platforms/iseries/setup.c | 6 +----- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 330376b74c87..cd55c9b0f7ea 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -570,7 +570,7 @@ config SCHED_SMT config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" - depends on PPC_OF && PROC_FS + depends on (PPC_OF || PPC_ISERIES) && PROC_FS help This option adds a device-tree directory under /proc which contains an image of the device tree that the kernel copies from Open diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 612bc4ec72b1..14b2ffb6c2d8 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -2,6 +2,10 @@ # Makefile for the linux ppc-specific parts of the memory manager. # +ifeq ($(CONFIG_PPC64),y) +EXTRA_CFLAGS += -mno-minimal-toc +endif + obj-y := fault.o mem.o lmb.o obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o \ tlb_32.o diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 18bf40077561..127b465308be 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,3 +1,5 @@ +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 obj-$(CONFIG_PCI) += pci.o irq.o vpdinfo.o diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index c3e532b766ef..b6cf050a8c27 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -430,7 +430,6 @@ static void __init build_iSeries_Memory_Map(void) u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; u32 nextPhysChunk; u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; - u32 num_ptegs; u32 totalChunks,moreChunks; u32 currChunk, thisChunk, absChunk; u32 currDword; @@ -493,10 +492,7 @@ static void __init build_iSeries_Memory_Map(void) printk("HPT absolute addr = %016lx, size = %dK\n", chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); - /* Fill in the hashed page table hash mask */ - num_ptegs = hptSizePages * - (PAGE_SIZE / (sizeof(hpte_t) * HPTES_PER_GROUP)); - htab_hash_mask = num_ptegs - 1; + ppc64_pft_size = __ilog2(hptSizePages * PAGE_SIZE); /* * The actual hashed page table is in the hypervisor, From 3eac8c69d1ac1266327f4e29deb23716a12c6d30 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 12 Oct 2005 16:58:53 +1000 Subject: [PATCH 0373/1939] powerpc: Move default hash table size calculation to hash_utils_64.c We weren't computing the size of the hash table correctly on iSeries because the relevant code in prom.c was #ifdef CONFIG_PPC_PSERIES. This moves the code to hash_utils_64.c, makes it unconditional, and cleans it up a bit. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 20 -------------------- arch/powerpc/mm/hash_utils_64.c | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index ce0dff1caa80..c8d288457b4c 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1323,26 +1323,6 @@ void __init early_init_devtree(void *params) */ scan_flat_dt(early_init_dt_scan_cpus, NULL); -#ifdef CONFIG_PPC_PSERIES - /* If hash size wasn't obtained above, we calculate it now based on - * the total RAM size - */ - if (ppc64_pft_size == 0) { - unsigned long rnd_mem_size, pteg_count; - - /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); - if (rnd_mem_size < systemcfg->physicalMemorySize) - rnd_mem_size <<= 1; - - /* # pages / 2 */ - pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); - - ppc64_pft_size = __ilog2(pteg_count << 7); - } - - DBG("Hash pftSize: %x\n", (int)ppc64_pft_size); -#endif DBG(" <- early_init_devtree()\n"); } diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 35dd93eeaf4b..6e9e05cce02c 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -155,6 +155,27 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end, } } +static unsigned long get_hashtable_size(void) +{ + unsigned long rnd_mem_size, pteg_count; + + /* If hash size wasn't obtained in prom.c, we calculate it now based on + * the total RAM size + */ + if (ppc64_pft_size) + return 1UL << ppc64_pft_size; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); + if (rnd_mem_size < systemcfg->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); + + return pteg_count << 7; +} + void __init htab_initialize(void) { unsigned long table, htab_size_bytes; @@ -170,7 +191,7 @@ void __init htab_initialize(void) * Calculate the required size of the htab. We want the number of * PTEGs to equal one half the number of real pages. */ - htab_size_bytes = 1UL << ppc64_pft_size; + htab_size_bytes = get_hashtable_size(); pteg_count = htab_size_bytes >> 7; /* For debug, make the HTAB 1/8 as big as it normally would be. */ From 5629d41d5ce255802cd3c350fbadfe5f3aa5f279 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 12 Oct 2005 17:01:50 +1000 Subject: [PATCH 0374/1939] powerpc: Bring in some changes made to arch/ppc and include/asm-ppc64 Recent commits upstream have changed files which are currently duplicated in arch/powerpc and include/asm-powerpc. This updates them with the corresponding changes. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/cpufreq.c | 7 +++++++ arch/powerpc/platforms/powermac/feature.c | 4 ++++ arch/powerpc/platforms/powermac/time.c | 2 +- include/asm-powerpc/iommu.h | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq.c index 6d32d99402be..bcd9224f3f90 100644 --- a/arch/powerpc/platforms/powermac/cpufreq.c +++ b/arch/powerpc/platforms/powermac/cpufreq.c @@ -695,6 +695,13 @@ static int __init pmac_cpufreq_setup(void) set_speed_proc = pmu_set_cpu_speed; is_pmu_based = 1; } + /* Else check for TiPb 550 */ + else if (machine_is_compatible("PowerBook3,3") && cur_freq == 550000) { + hi_freq = cur_freq; + low_freq = 500000; + set_speed_proc = pmu_set_cpu_speed; + is_pmu_based = 1; + } /* Else check for TiPb 400 & 500 */ else if (machine_is_compatible("PowerBook3,2")) { /* We only know about the 400 MHz and the 500Mhz model diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 2cba670c71b7..243a24fd025a 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2382,6 +2382,10 @@ static struct pmac_mb_def pmac_mb_defs[] = { PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, }, + { "PowerBook6,7", "iBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, { "PowerBook6,8", "PowerBook G4 12\"", PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index ff6adff36cb8..edb9fcc64790 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -195,7 +195,7 @@ via_calibrate_decr(void) ; dend = get_dec(); - tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100)); + tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index d096faf4191e..f80ec8daf122 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -88,7 +88,7 @@ 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 int __nocast flag); + dma_addr_t *dma_handle, gfp_t flag); 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, From 7e130edf712ac054aecf643f9d3d0142a9679e6a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 12 Oct 2005 17:03:36 +1000 Subject: [PATCH 0375/1939] ppc64: Remove duplicate versions of some headers This removes three headers from include/asm-ppc64 that are now in include/asm-powerpc and are sufficiently similar that they can be used with ARCH=ppc64. Signed-off-by: Paul Mackerras --- include/asm-ppc64/iommu.h | 112 ------------ include/asm-ppc64/pSeries_reconfig.h | 25 --- include/asm-ppc64/rtas.h | 249 --------------------------- 3 files changed, 386 deletions(-) delete mode 100644 include/asm-ppc64/iommu.h delete mode 100644 include/asm-ppc64/pSeries_reconfig.h delete mode 100644 include/asm-ppc64/rtas.h diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h deleted file mode 100644 index f80ec8daf122..000000000000 --- a/include/asm-ppc64/iommu.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * Rewrite, cleanup: - * Copyright (C) 2004 Olof Johansson , 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 - */ - -#ifndef _ASM_IOMMU_H -#define _ASM_IOMMU_H - -#include -#include -#include -#include - -/* - * IOMAP_MAX_ORDER defines the largest contiguous block - * of dma space we can get. IOMAP_MAX_ORDER = 13 - * allows up to 2**12 pages (4096 * 4096) = 16 MB - */ -#define IOMAP_MAX_ORDER 13 - -struct iommu_table { - unsigned long it_busno; /* Bus number this table belongs to */ - unsigned long it_size; /* Size of iommu table in entries */ - unsigned long it_offset; /* Offset into global table */ - unsigned long it_base; /* mapped address of tce table */ - unsigned long it_index; /* which iommu table this is */ - unsigned long it_type; /* type: PCI or Virtual Bus */ - unsigned long it_blocksize; /* Entries in each block (cacheline) */ - unsigned long it_hint; /* Hint for next alloc */ - unsigned long it_largehint; /* Hint for large allocs */ - unsigned long it_halfpoint; /* Breaking point for small/large allocs */ - spinlock_t it_lock; /* Protects it_map */ - unsigned long *it_map; /* A simple allocation bitmap for now */ -}; - -struct scatterlist; -struct device_node; - -#ifdef CONFIG_PPC_MULTIPLATFORM - -/* Walks all buses and creates iommu tables */ -extern void iommu_setup_pSeries(void); -extern void iommu_setup_u3(void); - -/* Frees table for an individual device node */ -extern void iommu_free_table(struct device_node *dn); - -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -#ifdef CONFIG_PPC_PSERIES - -/* Creates table for an individual device node */ -extern void iommu_devnode_init_pSeries(struct device_node *dn); - -#endif /* CONFIG_PPC_PSERIES */ - -#ifdef CONFIG_PPC_ISERIES - -/* Creates table for an individual device node */ -extern void iommu_devnode_init_iSeries(struct device_node *dn); - -#endif /* CONFIG_PPC_ISERIES */ - -/* 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 int iommu_map_sg(struct device *dev, struct iommu_table *tbl, - struct scatterlist *sglist, int nelems, - enum dma_data_direction direction); -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, gfp_t flag); -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, - size_t size, enum dma_data_direction direction); -extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction); - -extern void iommu_init_early_pSeries(void); -extern void iommu_init_early_iSeries(void); -extern void iommu_init_early_u3(void); - -#ifdef CONFIG_PCI -extern void pci_iommu_init(void); -extern void pci_direct_iommu_init(void); -#else -static inline void pci_iommu_init(void) { } -#endif - -extern void alloc_u3_dart_table(void); - -#endif /* _ASM_IOMMU_H */ diff --git a/include/asm-ppc64/pSeries_reconfig.h b/include/asm-ppc64/pSeries_reconfig.h deleted file mode 100644 index c0db1ea7f7d1..000000000000 --- a/include/asm-ppc64/pSeries_reconfig.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _PPC64_PSERIES_RECONFIG_H -#define _PPC64_PSERIES_RECONFIG_H - -#include - -/* - * Use this API if your code needs to know about OF device nodes being - * added or removed on pSeries systems. - */ - -#define PSERIES_RECONFIG_ADD 0x0001 -#define PSERIES_RECONFIG_REMOVE 0x0002 - -#ifdef CONFIG_PPC_PSERIES -extern int pSeries_reconfig_notifier_register(struct notifier_block *); -extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); -#else /* !CONFIG_PPC_PSERIES */ -static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) -{ - return 0; -} -static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } -#endif /* CONFIG_PPC_PSERIES */ - -#endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h deleted file mode 100644 index e7d1b5222802..000000000000 --- a/include/asm-ppc64/rtas.h +++ /dev/null @@ -1,249 +0,0 @@ -#ifndef _PPC64_RTAS_H -#define _PPC64_RTAS_H - -#include -#include - -/* - * Definitions for talking to the RTAS on CHRP machines. - * - * Copyright (C) 2001 Peter Bergner - * Copyright (C) 2001 PPC 64 Team, 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. - */ - -#define RTAS_UNKNOWN_SERVICE (-1) -#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */ - -/* Buffer size for ppc_rtas system call. */ -#define RTAS_RMOBUF_MAX (64 * 1024) - -/* RTAS return status codes */ -#define RTAS_BUSY -2 /* RTAS Busy */ -#define RTAS_EXTENDED_DELAY_MIN 9900 -#define RTAS_EXTENDED_DELAY_MAX 9905 - -/* - * In general to call RTAS use rtas_token("string") to lookup - * an RTAS token for the given string (e.g. "event-scan"). - * To actually perform the call use - * ret = rtas_call(token, n_in, n_out, ...) - * Where n_in is the number of input parameters and - * n_out is the number of output parameters - * - * If the "string" is invalid on this system, RTAS_UNKNOWN_SERVICE - * will be returned as a token. rtas_call() does look for this - * token and error out gracefully so rtas_call(rtas_token("str"), ...) - * may be safely used for one-shot calls to RTAS. - * - */ - -typedef u32 rtas_arg_t; - -struct rtas_args { - u32 token; - u32 nargs; - u32 nret; - rtas_arg_t args[16]; - rtas_arg_t *rets; /* Pointer to return values in args[]. */ -}; - -extern struct rtas_args rtas_stop_self_args; - -struct rtas_t { - unsigned long entry; /* physical address pointer */ - unsigned long base; /* physical address pointer */ - unsigned long size; - spinlock_t lock; - struct rtas_args args; - struct device_node *dev; /* virtual address pointer */ -}; - -/* RTAS event classes */ -#define RTAS_INTERNAL_ERROR 0x80000000 /* set bit 0 */ -#define RTAS_EPOW_WARNING 0x40000000 /* set bit 1 */ -#define RTAS_POWERMGM_EVENTS 0x20000000 /* set bit 2 */ -#define RTAS_HOTPLUG_EVENTS 0x10000000 /* set bit 3 */ -#define RTAS_EVENT_SCAN_ALL_EVENTS 0xf0000000 - -/* RTAS event severity */ -#define RTAS_SEVERITY_FATAL 0x5 -#define RTAS_SEVERITY_ERROR 0x4 -#define RTAS_SEVERITY_ERROR_SYNC 0x3 -#define RTAS_SEVERITY_WARNING 0x2 -#define RTAS_SEVERITY_EVENT 0x1 -#define RTAS_SEVERITY_NO_ERROR 0x0 - -/* RTAS event disposition */ -#define RTAS_DISP_FULLY_RECOVERED 0x0 -#define RTAS_DISP_LIMITED_RECOVERY 0x1 -#define RTAS_DISP_NOT_RECOVERED 0x2 - -/* RTAS event initiator */ -#define RTAS_INITIATOR_UNKNOWN 0x0 -#define RTAS_INITIATOR_CPU 0x1 -#define RTAS_INITIATOR_PCI 0x2 -#define RTAS_INITIATOR_ISA 0x3 -#define RTAS_INITIATOR_MEMORY 0x4 -#define RTAS_INITIATOR_POWERMGM 0x5 - -/* RTAS event target */ -#define RTAS_TARGET_UNKNOWN 0x0 -#define RTAS_TARGET_CPU 0x1 -#define RTAS_TARGET_PCI 0x2 -#define RTAS_TARGET_ISA 0x3 -#define RTAS_TARGET_MEMORY 0x4 -#define RTAS_TARGET_POWERMGM 0x5 - -/* RTAS event type */ -#define RTAS_TYPE_RETRY 0x01 -#define RTAS_TYPE_TCE_ERR 0x02 -#define RTAS_TYPE_INTERN_DEV_FAIL 0x03 -#define RTAS_TYPE_TIMEOUT 0x04 -#define RTAS_TYPE_DATA_PARITY 0x05 -#define RTAS_TYPE_ADDR_PARITY 0x06 -#define RTAS_TYPE_CACHE_PARITY 0x07 -#define RTAS_TYPE_ADDR_INVALID 0x08 -#define RTAS_TYPE_ECC_UNCORR 0x09 -#define RTAS_TYPE_ECC_CORR 0x0a -#define RTAS_TYPE_EPOW 0x40 -#define RTAS_TYPE_PLATFORM 0xE0 -#define RTAS_TYPE_IO 0xE1 -#define RTAS_TYPE_INFO 0xE2 -#define RTAS_TYPE_DEALLOC 0xE3 -#define RTAS_TYPE_DUMP 0xE4 -/* I don't add PowerMGM events right now, this is a different topic */ -#define RTAS_TYPE_PMGM_POWER_SW_ON 0x60 -#define RTAS_TYPE_PMGM_POWER_SW_OFF 0x61 -#define RTAS_TYPE_PMGM_LID_OPEN 0x62 -#define RTAS_TYPE_PMGM_LID_CLOSE 0x63 -#define RTAS_TYPE_PMGM_SLEEP_BTN 0x64 -#define RTAS_TYPE_PMGM_WAKE_BTN 0x65 -#define RTAS_TYPE_PMGM_BATTERY_WARN 0x66 -#define RTAS_TYPE_PMGM_BATTERY_CRIT 0x67 -#define RTAS_TYPE_PMGM_SWITCH_TO_BAT 0x68 -#define RTAS_TYPE_PMGM_SWITCH_TO_AC 0x69 -#define RTAS_TYPE_PMGM_KBD_OR_MOUSE 0x6a -#define RTAS_TYPE_PMGM_ENCLOS_OPEN 0x6b -#define RTAS_TYPE_PMGM_ENCLOS_CLOSED 0x6c -#define RTAS_TYPE_PMGM_RING_INDICATE 0x6d -#define RTAS_TYPE_PMGM_LAN_ATTENTION 0x6e -#define RTAS_TYPE_PMGM_TIME_ALARM 0x6f -#define RTAS_TYPE_PMGM_CONFIG_CHANGE 0x70 -#define RTAS_TYPE_PMGM_SERVICE_PROC 0x71 - -struct rtas_error_log { - unsigned long version:8; /* Architectural version */ - unsigned long severity:3; /* Severity level of error */ - unsigned long disposition:2; /* Degree of recovery */ - unsigned long extended:1; /* extended log present? */ - unsigned long /* reserved */ :2; /* Reserved for future use */ - unsigned long initiator:4; /* Initiator of event */ - unsigned long target:4; /* Target of failed operation */ - unsigned long type:8; /* General event or error*/ - unsigned long extended_log_length:32; /* length in bytes */ - unsigned char buffer[1]; -}; - -struct flash_block { - char *data; - unsigned long length; -}; - -/* This struct is very similar but not identical to - * that needed by the rtas flash update. - * All we need to do for rtas is rewrite num_blocks - * into a version/length and translate the pointers - * to absolute. - */ -#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block)) -struct flash_block_list { - unsigned long num_blocks; - struct flash_block_list *next; - struct flash_block blocks[FLASH_BLOCKS_PER_NODE]; -}; -struct flash_block_list_header { /* just the header of flash_block_list */ - unsigned long num_blocks; - struct flash_block_list *next; -}; -extern struct flash_block_list_header rtas_firmware_flash_list; - -extern struct rtas_t rtas; - -extern void enter_rtas(unsigned long); -extern int rtas_token(const char *service); -extern int rtas_call(int token, int, int, int *, ...); -extern void call_rtas_display_status(unsigned char); -extern void rtas_restart(char *cmd); -extern void rtas_power_off(void); -extern void rtas_halt(void); -extern void rtas_os_term(char *str); -extern int rtas_get_sensor(int sensor, int index, int *state); -extern int rtas_get_power_level(int powerdomain, int *level); -extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); -extern int rtas_set_indicator(int indicator, int index, int new_value); -extern void rtas_progress(char *s, unsigned short hex); -extern void rtas_initialize(void); - -struct rtc_time; -extern void rtas_get_boot_time(struct rtc_time *rtc_time); -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 void pSeries_log_error(char *buf, unsigned int err_type, int fatal); - -/* Error types logged. */ -#define ERR_FLAG_ALREADY_LOGGED 0x0 -#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ -#define ERR_TYPE_RTAS_LOG 0x2 /* from rtas event-scan */ -#define ERR_TYPE_KERNEL_PANIC 0x4 /* from panic() */ - -/* All the types and not flags */ -#define ERR_TYPE_MASK (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC) - -#define RTAS_DEBUG KERN_DEBUG "RTAS: " - -#define RTAS_ERROR_LOG_MAX 2048 - -/* - * Return the firmware-specified size of the error log buffer - * for all rtas calls that require an error buffer argument. - * This includes 'check-exception' and 'rtas-last-error'. - */ -extern int rtas_get_error_log_max(void); - -/* Event Scan Parameters */ -#define EVENT_SCAN_ALL_EVENTS 0xf0000000 -#define SURVEILLANCE_TOKEN 9000 -#define LOG_NUMBER 64 /* must be a power of two */ -#define LOG_NUMBER_MASK (LOG_NUMBER-1) - -/* Some RTAS ops require a data buffer and that buffer must be < 4G. - * Rather than having a memory allocator, just use this buffer - * (get the lock first), make the RTAS call. Copy the data instead - * of holding the buffer for long. - */ - -#define RTAS_DATA_BUF_SIZE 4096 -extern spinlock_t rtas_data_buf_lock; -extern char rtas_data_buf[RTAS_DATA_BUF_SIZE]; - -extern void rtas_stop_self(void); - -/* RMO buffer reserved for user-space RTAS use */ -extern unsigned long rtas_rmo_buf; - -#define GLOBAL_INTERRUPT_QUEUE 9005 - -#endif /* _PPC64_RTAS_H */ From 4920960f577edcb0a5ef03823a53911cca5875e1 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 12 Oct 2005 15:55:09 +1000 Subject: [PATCH 0376/1939] powerpc: consolidate cputable.c Also simplify arch/ppc64/kernel/Makefile Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 2 +- arch/{ppc => powerpc}/kernel/cputable.c | 413 +++++++++++++++++------- arch/ppc/kernel/Makefile | 4 +- arch/ppc64/kernel/Makefile | 101 ++---- arch/ppc64/kernel/cputable.c | 260 --------------- include/asm-powerpc/cputable.h | 3 - 6 files changed, 337 insertions(+), 446 deletions(-) rename arch/{ppc => powerpc}/kernel/cputable.c (69%) delete mode 100644 arch/ppc64/kernel/cputable.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 931795380978..f03f6d4ffaa6 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o +obj-y := semaphore.o cputable.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o diff --git a/arch/ppc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c similarity index 69% rename from arch/ppc/kernel/cputable.c rename to arch/powerpc/kernel/cputable.c index 207d4dd059d9..214f3b088edf 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1,8 +1,9 @@ /* - * arch/ppc/kernel/cputable.c - * * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) * + * Modifications for ppc64: + * Copyright (C) 2003 Dave Engebretsen + * * 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 @@ -20,7 +21,22 @@ #include struct cpu_spec* cur_cpu_spec = NULL; +#ifdef CONFIG_PPC64 +EXPORT_SYMBOL(cur_cpu_spec); +#endif +/* NOTE: + * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's + * the responsibility of the appropriate CPU save/restore functions to + * eventually copy these settings over. Those save/restore aren't yet + * part of the cputable though. That has to be fixed for both ppc32 + * and ppc64 + */ +#ifdef CONFIG_PPC64 +extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); +#else extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); @@ -29,35 +45,264 @@ extern void __setup_cpu_750fx(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_7400(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); +#endif /* CONFIG_PPC32 */ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); -#define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \ - !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \ - !defined(CONFIG_BOOKE)) - /* This table only contains "desktop" CPUs, it need to be filled with embedded * ones as well... */ -#define COMMON_PPC (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ - PPC_FEATURE_HAS_MMU) +#define COMMON_USER (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ + PPC_FEATURE_HAS_MMU) +#define COMMON_USER_PPC64 (COMMON_USER | PPC_FEATURE_64) + /* We only set the spe features if the kernel was compiled with * spe support */ #ifdef CONFIG_SPE -#define PPC_FEATURE_SPE_COMP PPC_FEATURE_HAS_SPE +#define PPC_FEATURE_SPE_COMP PPC_FEATURE_HAS_SPE #else -#define PPC_FEATURE_SPE_COMP 0 +#define PPC_FEATURE_SPE_COMP 0 #endif struct cpu_spec cpu_specs[] = { +#ifdef CONFIG_PPC64 + { /* Power3 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00400000, + .cpu_name = "POWER3 (630)", + .cpu_features = CPU_FTRS_POWER3, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power3", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* Power3+ */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00410000, + .cpu_name = "POWER3 (630+)", + .cpu_features = CPU_FTRS_POWER3, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power3", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* Northstar */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00330000, + .cpu_name = "RS64-II (northstar)", + .cpu_features = CPU_FTRS_RS64, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* Pulsar */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00340000, + .cpu_name = "RS64-III (pulsar)", + .cpu_features = CPU_FTRS_RS64, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* I-star */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00360000, + .cpu_name = "RS64-III (icestar)", + .cpu_features = CPU_FTRS_RS64, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* S-star */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00370000, + .cpu_name = "RS64-IV (sstar)", + .cpu_features = CPU_FTRS_RS64, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* Power4 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00350000, + .cpu_name = "POWER4 (gp)", + .cpu_features = CPU_FTRS_POWER4, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power4", + .oprofile_model = &op_model_rs64, +#endif + }, + { /* Power4+ */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00380000, + .cpu_name = "POWER4+ (gq)", + .cpu_features = CPU_FTRS_POWER4, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power4", + .oprofile_model = &op_model_power4, +#endif + }, + { /* PPC970 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00390000, + .cpu_name = "PPC970", + .cpu_features = CPU_FTRS_PPC970, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif + }, +#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_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 8, + .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif + }, +#endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */ +#ifdef CONFIG_PPC64 + { /* PPC970MP */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00440000, + .cpu_name = "PPC970MP", + .cpu_features = CPU_FTRS_PPC970, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif + }, + { /* Power5 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003a0000, + .cpu_name = "POWER5 (gr)", + .cpu_features = CPU_FTRS_POWER5, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power5", + .oprofile_model = &op_model_power4, +#endif + }, + { /* Power5 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003b0000, + .cpu_name = "POWER5 (gs)", + .cpu_features = CPU_FTRS_POWER5, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power5", + .oprofile_model = &op_model_power4, +#endif + }, + { /* BE DD1.x */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00700000, + .cpu_name = "Cell Broadband Engine", + .cpu_features = CPU_FTRS_CELL, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_be, + }, + { /* default match */ + .pvr_mask = 0x00000000, + .pvr_value = 0x00000000, + .cpu_name = "POWER4 (compatible)", + .cpu_features = CPU_FTRS_COMPATIBLE, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .cpu_setup = __setup_cpu_power4, + } +#endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC32 #if CLASSIC_PPC - { /* 601 */ + { /* 601 */ .pvr_mask = 0xffff0000, .pvr_value = 0x00010000, .cpu_name = "601", .cpu_features = CPU_FTRS_PPC601, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_601_INSTR | + .cpu_user_features = COMMON_USER | PPC_FEATURE_601_INSTR | PPC_FEATURE_UNIFIED_CACHE, .icache_bsize = 32, .dcache_bsize = 32, @@ -67,7 +312,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00030000, .cpu_name = "603", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -77,7 +322,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00060000, .cpu_name = "603e", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -87,7 +332,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00070000, .cpu_name = "603ev", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -97,7 +342,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00040000, .cpu_name = "604", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 2, @@ -108,7 +353,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00090000, .cpu_name = "604e", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -119,7 +364,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00090000, .cpu_name = "604r", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -130,7 +375,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000a0000, .cpu_name = "604ev", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -141,7 +386,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00084202, .cpu_name = "740/750", .cpu_features = CPU_FTRS_740_NOTAU, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -152,7 +397,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00080100, .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -163,7 +408,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00082200, .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -174,7 +419,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00082210, .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -185,7 +430,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00083214, .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -196,7 +441,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00083000, .cpu_name = "745/755", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -207,7 +452,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000100, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX1, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -218,7 +463,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000200, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX2, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -229,7 +474,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000000, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -240,7 +485,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70020000, .cpu_name = "750GX", .cpu_features = CPU_FTRS_750GX, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -251,7 +496,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00080000, .cpu_name = "740/750", .cpu_features = CPU_FTRS_740, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -262,7 +507,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000c1101, .cpu_name = "7400 (1.1)", .cpu_features = CPU_FTRS_7400_NOTAU, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -273,7 +518,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000c0000, .cpu_name = "7400", .cpu_features = CPU_FTRS_7400, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -284,7 +529,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x800c0000, .cpu_name = "7410", .cpu_features = CPU_FTRS_7400, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -295,7 +540,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000200, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_20, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -306,7 +551,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000201, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_21, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -317,7 +562,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000000, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_23, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -328,7 +573,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010100, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455_1, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -339,7 +584,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010200, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455_20, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -350,7 +595,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010000, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -361,7 +606,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020100, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447_10, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -372,7 +617,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020101, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447_10, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -383,7 +628,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020000, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -394,7 +639,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80030000, .cpu_name = "7447A", .cpu_features = CPU_FTRS_7447A, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -405,7 +650,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80040000, .cpu_name = "7448", .cpu_features = CPU_FTRS_7447A, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -416,7 +661,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00810000, .cpu_name = "82xx", .cpu_features = CPU_FTRS_82XX, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -426,7 +671,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00820000, .cpu_name = "G2_LE", .cpu_features = CPU_FTRS_G2_LE, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -436,7 +681,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00830000, .cpu_name = "e300", .cpu_features = CPU_FTRS_E300, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603 @@ -446,66 +691,11 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00000000, .cpu_name = "(generic PPC)", .cpu_features = CPU_FTRS_CLASSIC32, - .cpu_user_features = COMMON_PPC, + .cpu_user_features = COMMON_USER, .icache_bsize = 32, .dcache_bsize = 32, }, #endif /* CLASSIC_PPC */ -#ifdef CONFIG_PPC64BRIDGE - { /* Power3 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00400000, - .cpu_name = "Power3 (630)", - .cpu_features = CPU_FTRS_POWER3_32, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - }, - { /* Power3+ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00410000, - .cpu_name = "Power3 (630+)", - .cpu_features = CPU_FTRS_POWER3_32, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - }, - { /* I-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00360000, - .cpu_name = "I-star", - .cpu_features = CPU_FTRS_POWER3_32, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - }, - { /* S-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00370000, - .cpu_name = "S-star", - .cpu_features = CPU_FTRS_POWER3_32, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - }, -#endif /* CONFIG_PPC64BRIDGE */ -#ifdef CONFIG_POWER4 - { /* PPC970FX */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003c0000, - .cpu_name = "PPC970FX", - .cpu_features = CPU_FTRS_970_32, - .cpu_user_features = COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970 - }, -#endif /* CONFIG_POWER4 */ #ifdef CONFIG_8xx { /* 8xx */ .pvr_mask = 0xffff0000, @@ -664,7 +854,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x40000850, .cpu_name = "440EP Rev. A", .cpu_features = CPU_FTRS_44X, - .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */ + .cpu_user_features = COMMON_USER, /* 440EP has an FPU */ .icache_bsize = 32, .dcache_bsize = 32, }, @@ -673,11 +863,11 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x400008d3, .cpu_name = "440EP Rev. B", .cpu_features = CPU_FTRS_44X, - .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */ + .cpu_user_features = COMMON_USER, /* 440EP has an FPU */ .icache_bsize = 32, .dcache_bsize = 32, }, - { /* 440GP Rev. B */ + { /* 440GP Rev. B */ .pvr_mask = 0xf0000fff, .pvr_value = 0x40000440, .cpu_name = "440GP Rev. B", @@ -686,7 +876,7 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, }, - { /* 440GP Rev. C */ + { /* 440GP Rev. C */ .pvr_mask = 0xf0000fff, .pvr_value = 0x40000481, .cpu_name = "440GP Rev. C", @@ -742,7 +932,7 @@ struct cpu_spec cpu_specs[] = { }, #endif /* CONFIG_44x */ #ifdef CONFIG_FSL_BOOKE - { /* e200z5 */ + { /* e200z5 */ .pvr_mask = 0xfff00000, .pvr_value = 0x81000000, .cpu_name = "e200z5", @@ -753,7 +943,7 @@ struct cpu_spec cpu_specs[] = { PPC_FEATURE_UNIFIED_CACHE, .dcache_bsize = 32, }, - { /* e200z6 */ + { /* e200z6 */ .pvr_mask = 0xfff00000, .pvr_value = 0x81100000, .cpu_name = "e200z6", @@ -765,7 +955,7 @@ struct cpu_spec cpu_specs[] = { PPC_FEATURE_UNIFIED_CACHE, .dcache_bsize = 32, }, - { /* e500 */ + { /* e500 */ .pvr_mask = 0xffff0000, .pvr_value = 0x80200000, .cpu_name = "e500", @@ -778,7 +968,7 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, }, - { /* e500v2 */ + { /* e500v2 */ .pvr_mask = 0xffff0000, .pvr_value = 0x80210000, .cpu_name = "e500v2", @@ -803,4 +993,5 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, } #endif /* !CLASSIC_PPC */ +#endif /* CONFIG_PPC32 */ }; diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 59b6b62d1120..0cba463adf9a 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -15,7 +15,7 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ syscalls.o setup.o \ - cputable.o ppc_htab.o perfmon.o + ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o @@ -39,7 +39,7 @@ endif else obj-y := irq.o idle.o time.o \ signal.o ptrace.o align.o \ - syscalls.o cputable.o perfmon.o + syscalls.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 5569ea7e6830..834aef034b77 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -7,13 +7,17 @@ ifneq ($(CONFIG_PPC_MERGE),y) EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds -obj-y := setup.o entry.o irq.o idle.o dma.o \ - time.o signal.o syscalls.o misc.o ptrace.o \ +obj-y := setup.o entry.o misc.o prom.o + +endif + +obj-y += irq.o idle.o dma.o \ + time.o signal.o syscalls.o ptrace.o \ align.o bitops.o pacaData.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o \ - cputable.o cpu_setup_power4.o \ - iommu.o sysfs.o vdso.o pmc.o firmware.o prom.o + cpu_setup_power4.o \ + iommu.o sysfs.o vdso.o pmc.o firmware.o obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o @@ -22,72 +26,10 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o - -obj-$(CONFIG_PPC_PSERIES) += rtasd.o ras.o udbg_16550.o - -obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ - bpa_iic.o spider-pic.o - -obj-$(CONFIG_KEXEC) += machine_kexec.o -obj-$(CONFIG_EEH) += eeh.o -obj-$(CONFIG_PROC_FS) += proc_ppc64.o -obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o -obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o -obj-$(CONFIG_RTAS_PROC) += rtas-proc.o -obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_LPARCFG) += lparcfg.o -obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o -obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_HVCS) += hvcserver.o - -obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y) -obj-$(CONFIG_XICS) += xics.o -obj-$(CONFIG_MPIC) += mpic.o - -obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ - pmac_time.o pmac_nvram.o pmac_low_i2c.o \ - udbg_scc.o - -obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ - udbg_16550.o - -obj-$(CONFIG_U3_DART) += u3_iommu.o - -ifdef CONFIG_SMP -obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o -obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o -endif - -obj-$(CONFIG_KPROBES) += kprobes.o - -CFLAGS_ioctl32.o += -Ifs/ - -ifeq ($(CONFIG_PPC_ISERIES),y) -arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s -AFLAGS_head.o += -Iarch/powerpc/kernel -endif - -else - -# Things still needed from here by the merged ppc code - -obj-y := irq.o idle.o dma.o \ - time.o signal.o syscalls.o ptrace.o \ - align.o bitops.o pacaData.o \ - udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ - ptrace32.o signal32.o rtc.o \ - cputable.o cpu_setup_power4.o \ - iommu.o sysfs.o vdso.o pmc.o firmware.o -obj-y += vdso32/ vdso64/ - -pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o - -obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) - obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o +ifneq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o +endif obj-$(CONFIG_PPC_PSERIES) += rtasd.o ras.o udbg_16550.o @@ -100,15 +42,28 @@ obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o +ifneq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_MODULES) += ppc_ksyms.o +endif obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o +ifneq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_BOOTX_TEXT) += btext.o +endif obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o +ifneq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_MPIC) += mpic.o + +obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ + pmac_time.o pmac_nvram.o pmac_low_i2c.o \ + udbg_scc.o +endif obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ udbg_16550.o @@ -116,6 +71,9 @@ obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP +ifneq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o +endif obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o endif @@ -123,4 +81,9 @@ obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ +ifneq ($(CONFIG_PPC_MERGE),y) +ifeq ($(CONFIG_PPC_ISERIES),y) +arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s +AFLAGS_head.o += -Iarch/powerpc/kernel +endif endif diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c deleted file mode 100644 index 5134c53d536d..000000000000 --- a/arch/ppc64/kernel/cputable.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * arch/ppc64/kernel/cputable.c - * - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * Modifications for ppc64: - * Copyright (C) 2003 Dave Engebretsen - * - * 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 - -struct cpu_spec* cur_cpu_spec = NULL; -EXPORT_SYMBOL(cur_cpu_spec); - -/* NOTE: - * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's - * the responsibility of the appropriate CPU save/restore functions to - * eventually copy these settings over. Those save/restore aren't yet - * part of the cputable though. That has to be fixed for both ppc32 - * and ppc64 - */ -extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); - -struct cpu_spec cpu_specs[] = { - { /* Power3 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00400000, - .cpu_name = "POWER3 (630)", - .cpu_features = CPU_FTRS_POWER3, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power3+ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00410000, - .cpu_name = "POWER3 (630+)", - .cpu_features = CPU_FTRS_POWER3, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Northstar */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00330000, - .cpu_name = "RS64-II (northstar)", - .cpu_features = CPU_FTRS_RS64, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Pulsar */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00340000, - .cpu_name = "RS64-III (pulsar)", - .cpu_features = CPU_FTRS_RS64, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* I-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00360000, - .cpu_name = "RS64-III (icestar)", - .cpu_features = CPU_FTRS_RS64, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* S-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00370000, - .cpu_name = "RS64-IV (sstar)", - .cpu_features = CPU_FTRS_RS64, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power4 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00350000, - .cpu_name = "POWER4 (gp)", - .cpu_features = CPU_FTRS_POWER4, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power4+ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00380000, - .cpu_name = "POWER4+ (gq)", - .cpu_features = CPU_FTRS_POWER4, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00390000, - .cpu_name = "PPC970", - .cpu_features = CPU_FTRS_PPC970, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970FX */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003c0000, - .cpu_name = "PPC970FX", - .cpu_features = CPU_FTRS_PPC970, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970MP */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00440000, - .cpu_name = "PPC970MP", - .cpu_features = CPU_FTRS_PPC970, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* Power5 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003a0000, - .cpu_name = "POWER5 (gr)", - .cpu_features = CPU_FTRS_POWER5, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif - }, - { /* Power5 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003b0000, - .cpu_name = "POWER5 (gs)", - .cpu_features = CPU_FTRS_POWER5, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif - }, - { /* BE DD1.x */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00700000, - .cpu_name = "Cell Broadband Engine", - .cpu_features = CPU_FTRS_CELL, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .cpu_setup = __setup_cpu_be, - }, - { /* default match */ - .pvr_mask = 0x00000000, - .pvr_value = 0x00000000, - .cpu_name = "POWER4 (compatible)", - .cpu_features = CPU_FTRS_COMPATIBLE, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, - } -}; diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index a4a50d08d384..373642aff7d8 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -119,9 +119,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #ifndef __ASSEMBLY__ -#define COMMON_USER_PPC64 (PPC_FEATURE_32 | PPC_FEATURE_64 | \ - PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_MMU) - #define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \ CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \ CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL) From 7062018687da3d5d4966f58d6f0a58528b1e331b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 12 Oct 2005 17:44:55 +1000 Subject: [PATCH 0377/1939] powerpc: create 32 bit LOADADDR macro and use it in misc_32.S Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/misc_32.S | 6 ++---- include/asm-powerpc/ppc_asm.h | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index fa8c20ffec78..27274108116f 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -43,8 +43,7 @@ _GLOBAL(reloc_offset) mflr r0 bl 1f 1: mflr r3 - lis r4,1b@ha - addi r4,r4,1b@l + LOADADDR(r4,1b) subf r3,r4,r3 mtlr r0 blr @@ -56,8 +55,7 @@ _GLOBAL(add_reloc_offset) mflr r0 bl 1f 1: mflr r5 - lis r4,1b@ha - addi r4,r4,1b@l + LOADADDR(r4,1b) subf r5,r4,r5 add r3,r3,r5 mtlr r0 diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index e4350e406d2a..6aae414a161b 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -193,6 +193,10 @@ GLUE(.,name): #define CMPI cmpdi #else /* 32-bit */ +#define LOADADDR(rn,name) \ + lis rn,name@ha \ + addi rn,rn,name@l + #define LOADBASE(rn,name) \ lis rn,name@ha From 0f17d0742f27b7a69b0e2dfb21190f06ea3a9087 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 12 Oct 2005 23:23:44 +1000 Subject: [PATCH 0378/1939] powerpc: make 64 bit binaries work Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/process.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f09908a0beea..92bc75f61ca6 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -620,7 +620,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = start; regs->msr = MSR_USER; #else - if (test_thread_flag(TIF_32BIT)) { + { unsigned long entry, toc, load_addr = regs->gpr[2]; /* start is a relocated pointer to the function descriptor for @@ -641,10 +641,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = entry; regs->gpr[2] = toc; regs->msr = MSR_USER64; - } else { - regs->nip = start; - regs->gpr[2] = 0; - regs->msr = MSR_USER32; } #endif From d4bf9a7858a0766cafb21dcb66ff9a5d92c1cd09 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 13 Oct 2005 13:40:54 +1000 Subject: [PATCH 0379/1939] ppc64: merge binfmt_elf32.c and use start_thread for both 32 and 64 bit bineries. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 1 + arch/{ppc64 => powerpc}/kernel/binfmt_elf32.c | 3 -- arch/powerpc/kernel/process.c | 6 ++- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/sys_ppc32.c | 46 ------------------- 5 files changed, 7 insertions(+), 51 deletions(-) rename arch/{ppc64 => powerpc}/kernel/binfmt_elf32.c (94%) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f03f6d4ffaa6..adac749a1a8a 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -11,6 +11,7 @@ CFLAGS_btext.o += -fPIC endif obj-y := semaphore.o cputable.o +obj-$(CONFIG_PPC64) += binfmt_elf32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o diff --git a/arch/ppc64/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c similarity index 94% rename from arch/ppc64/kernel/binfmt_elf32.c rename to arch/powerpc/kernel/binfmt_elf32.c index fadc699a0497..8ad6b0f33651 100644 --- a/arch/ppc64/kernel/binfmt_elf32.c +++ b/arch/powerpc/kernel/binfmt_elf32.c @@ -70,9 +70,6 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) value->tv_sec = jiffies / HZ; } -extern void start_thread32(struct pt_regs *, unsigned long, unsigned long); -#undef start_thread -#define start_thread start_thread32 #define init_elf_binfmt init_elf32_binfmt #include "../../../fs/binfmt_elf.c" diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 92bc75f61ca6..193c8c1bf132 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -620,7 +620,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = start; regs->msr = MSR_USER; #else - { + if (!test_thread_flag(TIF_32BIT)) { unsigned long entry, toc, load_addr = regs->gpr[2]; /* start is a relocated pointer to the function descriptor for @@ -641,6 +641,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = entry; regs->gpr[2] = toc; regs->msr = MSR_USER64; + } else { + regs->nip = start; + regs->gpr[2] = 0; + regs->msr = MSR_USER32; } #endif diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 834aef034b77..a724f6fc04da 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -14,7 +14,7 @@ endif obj-y += irq.o idle.o dma.o \ time.o signal.o syscalls.o ptrace.o \ align.o bitops.o pacaData.o \ - udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ + udbg.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o \ cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 1cacf61f9c91..b53f565ee443 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -609,52 +609,6 @@ long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2, return error; } -/* Set up a thread for executing a new program. */ -void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp) -{ - set_fs(USER_DS); - - /* - * If we exec out of a kernel thread then thread.regs will not be - * set. Do it now. - */ - if (!current->thread.regs) { - unsigned long childregs = (unsigned long)current->thread_info + - THREAD_SIZE; - childregs -= sizeof(struct pt_regs); - current->thread.regs = (struct pt_regs *)childregs; - } - - /* - * ELF_PLAT_INIT already clears all registers but it also sets r2. - * So just clear r2 here. - */ - regs->gpr[2] = 0; - - regs->nip = nip; - regs->gpr[1] = sp; - regs->msr = MSR_USER32; -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = 0; -#endif /* CONFIG_SMP */ - current->thread.fpscr = 0; - memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); -#ifdef CONFIG_ALTIVEC -#ifndef CONFIG_SMP - if (last_task_used_altivec == current) - last_task_used_altivec = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.vr, 0, sizeof(current->thread.vr)); - current->thread.vscr.u[0] = 0; - current->thread.vscr.u[1] = 0; - current->thread.vscr.u[2] = 0; - current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */ - current->thread.vrsave = 0; - current->thread.used_vr = 0; -#endif /* CONFIG_ALTIVEC */ -} - /* Note: it is necessary to treat option as an unsigned int, * with the corresponding cast to a signed int to insure that the * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) From ae2752050d21f5aef811c362d3a47dce4694068d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 13 Oct 2005 14:12:25 +1000 Subject: [PATCH 0380/1939] ppc64: fix arch/ppc64/kernel/Makefile Signed-off-by: Stephen Rothwell --- arch/ppc64/kernel/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index a724f6fc04da..615484b09f90 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -8,6 +8,7 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds obj-y := setup.o entry.o misc.o prom.o +obj-$(CONFIG_PPC_OF) += of_device.o endif @@ -20,8 +21,6 @@ obj-y += irq.o idle.o dma.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o obj-y += vdso32/ vdso64/ -obj-$(CONFIG_PPC_OF) += of_device.o - pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) From eec5ef909888cd9d25a61f904cd8f0db50ea0455 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 13 Oct 2005 15:16:25 +1000 Subject: [PATCH 0381/1939] ppc64: use powerpc of_device.c Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 3 +- arch/ppc64/kernel/Makefile | 1 - arch/ppc64/kernel/of_device.c | 274 ---------------------------------- 3 files changed, 2 insertions(+), 276 deletions(-) delete mode 100644 arch/ppc64/kernel/of_device.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index adac749a1a8a..bce253969e4c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -14,6 +14,7 @@ obj-y := semaphore.o cputable.o obj-$(CONFIG_PPC64) += binfmt_elf32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o +obj-$(CONFIG_PPC_OF) += of_device.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -32,7 +33,7 @@ obj-y += process.o init_task.o \ prom.o systbl.o traps.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o -obj-$(CONFIG_PPC_OF) += prom_init.o of_device.o +obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 615484b09f90..1a8f3532885a 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -8,7 +8,6 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds obj-y := setup.o entry.o misc.o prom.o -obj-$(CONFIG_PPC_OF) += of_device.o endif diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c deleted file mode 100644 index 9f200f0f2ad5..000000000000 --- a/arch/ppc64/kernel/of_device.c +++ /dev/null @@ -1,274 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * of_match_device - Tell if an of_device structure has a matching - * of_match structure - * @ids: array of of device match structures to search in - * @dev: the of device structure to match against - * - * Used by a driver to check whether an of_device present in the - * system is in its list of supported devices. - */ -const struct of_device_id *of_match_device(const struct of_device_id *matches, - const struct of_device *dev) -{ - if (!dev->node) - return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= dev->node->name - && !strcmp(matches->name, dev->node->name); - if (matches->type[0]) - match &= dev->node->type - && !strcmp(matches->type, dev->node->type); - if (matches->compatible[0]) - match &= device_is_compatible(dev->node, - matches->compatible); - if (match) - return matches; - matches++; - } - return NULL; -} - -static int of_platform_bus_match(struct device *dev, struct device_driver *drv) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_device_id * matches = of_drv->match_table; - - if (!matches) - return 0; - - return of_match_device(matches, of_dev) != NULL; -} - -struct of_device *of_dev_get(struct of_device *dev) -{ - struct device *tmp; - - if (!dev) - return NULL; - tmp = get_device(&dev->dev); - if (tmp) - return to_of_device(tmp); - else - return NULL; -} - -void of_dev_put(struct of_device *dev) -{ - if (dev) - put_device(&dev->dev); -} - - -static int of_device_probe(struct device *dev) -{ - int error = -ENODEV; - struct of_platform_driver *drv; - struct of_device *of_dev; - const struct of_device_id *match; - - drv = to_of_platform_driver(dev->driver); - of_dev = to_of_device(dev); - - if (!drv->probe) - return error; - - of_dev_get(of_dev); - - match = of_match_device(drv->match_table, of_dev); - if (match) - error = drv->probe(of_dev, match); - if (error) - of_dev_put(of_dev); - - return error; -} - -static int of_device_remove(struct device *dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - - if (dev->driver && drv->remove) - drv->remove(of_dev); - return 0; -} - -static int of_device_suspend(struct device *dev, pm_message_t state) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->suspend) - error = drv->suspend(of_dev, state); - return error; -} - -static int of_device_resume(struct device * dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->resume) - error = drv->resume(of_dev); - return error; -} - -struct bus_type of_platform_bus_type = { - .name = "of_platform", - .match = of_platform_bus_match, - .suspend = of_device_suspend, - .resume = of_device_resume, -}; - -static int __init of_bus_driver_init(void) -{ - return bus_register(&of_platform_bus_type); -} - -postcore_initcall(of_bus_driver_init); - -int of_register_driver(struct of_platform_driver *drv) -{ - int count = 0; - - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &of_platform_bus_type; - drv->driver.probe = of_device_probe; - drv->driver.remove = of_device_remove; - - /* register with core */ - count = driver_register(&drv->driver); - return count ? count : 1; -} - -void of_unregister_driver(struct of_platform_driver *drv) -{ - driver_unregister(&drv->driver); -} - - -static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - return sprintf(buf, "%s", ofdev->node->full_name); -} - -static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); - -/** - * of_release_dev - free an of device structure when all users of it are finished. - * @dev: device that's been disconnected - * - * Will be called only by the device core when all users of this of device are - * done. - */ -void of_release_dev(struct device *dev) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - kfree(ofdev); -} - -int of_device_register(struct of_device *ofdev) -{ - int rc; - struct of_device **odprop; - - BUG_ON(ofdev->node == NULL); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (!odprop) { - struct property *new_prop; - - new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *), - GFP_KERNEL); - if (new_prop == NULL) - return -ENOMEM; - new_prop->name = "linux,device"; - new_prop->length = sizeof(sizeof(struct of_device *)); - new_prop->value = (unsigned char *)&new_prop[1]; - odprop = (struct of_device **)new_prop->value; - *odprop = NULL; - prom_add_property(ofdev->node, new_prop); - } - *odprop = ofdev; - - rc = device_register(&ofdev->dev); - if (rc) - return rc; - - device_create_file(&ofdev->dev, &dev_attr_devspec); - - return 0; -} - -void of_device_unregister(struct of_device *ofdev) -{ - struct of_device **odprop; - - device_remove_file(&ofdev->dev, &dev_attr_devspec); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (odprop) - *odprop = NULL; - - device_unregister(&ofdev->dev); -} - -struct of_device* of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, sizeof(*dev)); - - dev->node = np; - dev->dma_mask = 0xffffffffUL; - dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = parent; - dev->dev.bus = &of_platform_bus_type; - dev->dev.release = of_release_dev; - - strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); - - if (of_device_register(dev) != 0) { - kfree(dev); - return NULL; - } - - return dev; -} - - -EXPORT_SYMBOL(of_match_device); -EXPORT_SYMBOL(of_platform_bus_type); -EXPORT_SYMBOL(of_register_driver); -EXPORT_SYMBOL(of_unregister_driver); -EXPORT_SYMBOL(of_device_register); -EXPORT_SYMBOL(of_device_unregister); -EXPORT_SYMBOL(of_dev_get); -EXPORT_SYMBOL(of_dev_put); -EXPORT_SYMBOL(of_platform_device_create); -EXPORT_SYMBOL(of_release_dev); From e8a30302abc42a0c537b9326883523da9963deb6 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 13 Oct 2005 15:52:04 +1000 Subject: [PATCH 0382/1939] powerpc: merge ptrace.c Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 2 +- arch/{ppc => powerpc}/kernel/ptrace.c | 168 +++++++++--- arch/ppc/kernel/Makefile | 4 +- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/ptrace.c | 363 -------------------------- 5 files changed, 141 insertions(+), 398 deletions(-) rename arch/{ppc => powerpc}/kernel/ptrace.c (79%) delete mode 100644 arch/ppc64/kernel/ptrace.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index bce253969e4c..ae97295f270d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o cputable.o +obj-y := semaphore.o cputable.o ptrace.o obj-$(CONFIG_PPC64) += binfmt_elf32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o diff --git a/arch/ppc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c similarity index 79% rename from arch/ppc/kernel/ptrace.c rename to arch/powerpc/kernel/ptrace.c index e7aee4108dea..336b8bf542d7 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1,6 +1,4 @@ /* - * arch/ppc/kernel/ptrace.c - * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * @@ -17,6 +15,7 @@ * this archive for more details. */ +#include #include #include #include @@ -29,13 +28,19 @@ #include #include #include +#ifdef CONFIG_PPC32 #include +#endif #include #include #include #include +#ifdef CONFIG_PPC64 +#include +#endif +#ifdef CONFIG_PPC32 /* * Set of msr bits that gdb can change on behalf of a process. */ @@ -44,12 +49,14 @@ #else #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) #endif +#endif /* CONFIG_PPC32 */ /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ +#ifdef CONFIG_PPC32 /* * Get contents of register REGNO in task TASK. */ @@ -228,6 +235,7 @@ clear_single_step(struct task_struct *task) #endif } } +#endif /* CONFIG_PPC32 */ /* * Called by kernel/ptrace.c when detaching.. @@ -296,25 +304,28 @@ int sys_ptrace(long request, long pid, long addr, long data) } /* read the word at location addr in the USER area. */ - /* XXX this will need fixing for 64-bit */ case PTRACE_PEEKUSR: { unsigned long index, tmp; ret = -EIO; /* convert to index and check */ +#ifdef CONFIG_PPC32 index = (unsigned long) addr >> 2; - if ((addr & 3) || index > PT_FPSCR - || child->thread.regs == NULL) + if ((addr & 3) || (index > PT_FPSCR) + || (child->thread.regs == NULL)) +#else + index = (unsigned long) addr >> 3; + if ((addr & 7) || (index > PT_FPSCR)) +#endif break; +#ifdef CONFIG_PPC32 CHECK_FULL_REGS(child->thread.regs); +#endif if (index < PT_FPR0) { tmp = get_reg(child, (int) index); } else { - preempt_disable(); - if (child->thread.regs->msr & MSR_FP) - giveup_fpu(child); - preempt_enable(); + flush_fp_to_thread(child); tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; } ret = put_user(tmp,(unsigned long __user *) data); @@ -325,7 +336,8 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + if (access_process_vm(child, addr, &data, sizeof(data), 1) + == sizeof(data)) break; ret = -EIO; break; @@ -336,21 +348,25 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; /* convert to index and check */ +#ifdef CONFIG_PPC32 index = (unsigned long) addr >> 2; - if ((addr & 3) || index > PT_FPSCR - || child->thread.regs == NULL) + if ((addr & 3) || (index > PT_FPSCR) + || (child->thread.regs == NULL)) +#else + index = (unsigned long) addr >> 3; + if ((addr & 7) || (index > PT_FPSCR)) +#endif break; +#ifdef CONFIG_PPC32 CHECK_FULL_REGS(child->thread.regs); +#endif if (index == PT_ORIG_R3) break; if (index < PT_FPR0) { ret = put_reg(child, index, data); } else { - preempt_disable(); - if (child->thread.regs->msr & MSR_FP) - giveup_fpu(child); - preempt_enable(); + flush_fp_to_thread(child); ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ret = 0; } @@ -362,11 +378,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if (!valid_signal(data)) break; - if (request == PTRACE_SYSCALL) { + if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } else { + else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); @@ -404,28 +419,102 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } +#ifdef CONFIG_PPC64 + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, + (unsigned long __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; +#endif + case PTRACE_DETACH: 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]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } +#endif /* CONFIG_PPC64 */ + #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: /* Get the child altivec register state. */ - preempt_disable(); - if (child->thread.regs->msr & MSR_VEC) - giveup_altivec(child); - preempt_enable(); + flush_altivec_to_thread(child); ret = get_vrregs((unsigned long __user *)data, child); break; case PTRACE_SETVRREGS: /* Set the child altivec register state. */ - /* this is to clear the MSR_VEC bit to force a reload - * of register state from memory */ - preempt_disable(); - if (child->thread.regs->msr & MSR_VEC) - giveup_altivec(child); - preempt_enable(); + flush_altivec_to_thread(child); ret = set_vrregs(child, (unsigned long __user *)data); break; #endif @@ -478,12 +567,21 @@ static void do_syscall_trace(void) void do_syscall_trace_enter(struct pt_regs *regs) { +#ifdef CONFIG_PPC64 + secure_computing(regs->gpr[0]); +#endif + if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) do_syscall_trace(); if (unlikely(current->audit_context)) - audit_syscall_entry(current, AUDIT_ARCH_PPC, + audit_syscall_entry(current, +#ifdef CONFIG_PPC32 + AUDIT_ARCH_PPC, +#else + test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, +#endif regs->gpr[0], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); @@ -491,17 +589,25 @@ void do_syscall_trace_enter(struct pt_regs *regs) void do_syscall_trace_leave(struct pt_regs *regs) { +#ifdef CONFIG_PPC32 secure_computing(regs->gpr[0]); +#endif if (unlikely(current->audit_context)) audit_syscall_exit(current, (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, regs->result); - if ((test_thread_flag(TIF_SYSCALL_TRACE)) + if ((test_thread_flag(TIF_SYSCALL_TRACE) +#ifdef CONFIG_PPC64 + || test_thread_flag(TIF_SINGLESTEP) +#endif + ) && (current->ptrace & PT_PTRACED)) do_syscall_trace(); } +#ifdef CONFIG_PPC32 EXPORT_SYMBOL(do_syscall_trace_enter); EXPORT_SYMBOL(do_syscall_trace_leave); +#endif diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0cba463adf9a..7d16b1f7cd31 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -13,7 +13,7 @@ extra-$(CONFIG_POWER4) += idle_power4.o extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ - process.o signal.o ptrace.o align.o \ + process.o signal.o align.o \ syscalls.o setup.o \ ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o @@ -38,7 +38,7 @@ endif else obj-y := irq.o idle.o time.o \ - signal.o ptrace.o align.o \ + signal.o align.o \ syscalls.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 1a8f3532885a..b1203b79edf0 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := setup.o entry.o misc.o prom.o endif obj-y += irq.o idle.o dma.o \ - time.o signal.o syscalls.o ptrace.o \ + time.o signal.o syscalls.o \ align.o bitops.o pacaData.o \ udbg.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o rtc.o \ diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c deleted file mode 100644 index b1c044ca5756..000000000000 --- a/arch/ppc64/kernel/ptrace.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * linux/arch/ppc64/kernel/ptrace.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/m68k/kernel/ptrace.c" - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file README.legal in the main directory of - * this archive for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure single step bits etc are not set. - */ -void ptrace_disable(struct task_struct *child) -{ - /* make sure the single step bit is not set. */ - clear_single_step(child); -} - -int sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - int ret = -EPERM; - - lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long __user *) data); - break; - } - - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long index; - unsigned long tmp; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 3; - if ((addr & 7) || (index > PT_FPSCR)) - break; - - if (index < PT_FPR0) { - tmp = get_reg(child, (int)index); - } else { - flush_fp_to_thread(child); - tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; - } - ret = put_user(tmp,(unsigned long __user *) data); - break; - } - - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) - == sizeof(data)) - break; - ret = -EIO; - break; - - /* write the word at location addr in the USER area */ - case PTRACE_POKEUSR: { - unsigned long index; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 3; - if ((addr & 7) || (index > PT_FPSCR)) - break; - - if (index == PT_ORIG_R3) - break; - if (index < PT_FPR0) { - ret = put_reg(child, index, data); - } else { - flush_fp_to_thread(child); - ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; - ret = 0; - } - break; - } - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - ret = 0; - break; - } - - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_single_step(child); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - - case PTRACE_GET_DEBUGREG: { - ret = -EINVAL; - /* We only support one DABR and no IABRS at the moment */ - if (addr > 0) - break; - ret = put_user(child->thread.dabr, - (unsigned long __user *)data); - break; - } - - case PTRACE_SET_DEBUGREG: - ret = ptrace_set_debugreg(child, addr, data); - break; - - case PTRACE_DETACH: - ret = ptrace_detach(child, data); - break; - - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - -#ifdef CONFIG_ALTIVEC - case PTRACE_GETVRREGS: - /* Get the child altivec register state. */ - flush_altivec_to_thread(child); - ret = get_vrregs((unsigned long __user *)data, child); - break; - - case PTRACE_SETVRREGS: - /* Set the child altivec register state. */ - flush_altivec_to_thread(child); - ret = set_vrregs(child, (unsigned long __user *)data); - break; -#endif - - default: - ret = ptrace_request(child, request, addr, data); - break; - } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - return ret; -} - -static void do_syscall_trace(void) -{ - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - -void do_syscall_trace_enter(struct pt_regs *regs) -{ - secure_computing(regs->gpr[0]); - - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); - - if (unlikely(current->audit_context)) - audit_syscall_entry(current, - test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, - regs->gpr[0], - regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); - -} - -void do_syscall_trace_leave(struct pt_regs *regs) -{ - if (unlikely(current->audit_context)) - audit_syscall_exit(current, - (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, - regs->result); - - if ((test_thread_flag(TIF_SYSCALL_TRACE) - || test_thread_flag(TIF_SINGLESTEP)) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); -} From 190554db7bcd41935827f71d4f6f787673da208a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 13 Oct 2005 16:14:15 +1000 Subject: [PATCH 0383/1939] powerpc: fix uname -m It will now give ppc64 on 64bit platforms and ppc on 32bit platforms. Signed-off-by: Stephen Rothwell --- arch/powerpc/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 8d1e7bd14c55..a5f2eb5f89ce 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -51,6 +51,8 @@ OLDARCH := ppc SZ := 32 endif +UTS_MACHINE := $(OLDARCH) + ifeq ($(HAS_BIARCH),y) override AS += -a$(SZ) override LD += -m elf$(SZ)ppc From 426c1a11a677e39a8c8ed744a521d0f4cb2e417e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 14 Oct 2005 14:51:42 +1000 Subject: [PATCH 0384/1939] powerpc: move iSeries/iSeries_pci.h to platforms/iseries The only real user of this file outside platforms/iseries was drivers/net/iseries_veth.c but all it wanted was ISERIES_HV_ADDR() so we move that to abs_addr.h (and lowercase it). Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/iommu.c | 6 ++++-- arch/powerpc/platforms/iseries/mf.c | 9 +++++---- arch/powerpc/platforms/iseries/pci.c | 7 ++++--- .../powerpc/platforms/iseries/pci.h | 19 ++++--------------- arch/powerpc/platforms/iseries/vpdinfo.c | 8 +++++--- arch/ppc64/kernel/pci_iommu.c | 13 ++++--------- drivers/net/iseries_veth.c | 11 ++++++----- include/asm-powerpc/iommu.h | 1 + include/asm-powerpc/prom.h | 1 + include/asm-ppc64/abs_addr.h | 7 +++++++ include/asm-ppc64/pci-bridge.h | 1 + include/asm-ppc64/prom.h | 1 + 12 files changed, 43 insertions(+), 41 deletions(-) rename include/asm-ppc64/iSeries/iSeries_pci.h => arch/powerpc/platforms/iseries/pci.h (80%) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index e40c50b7cefc..e6f4a4ab57b8 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -30,8 +30,10 @@ #include #include #include +#include #include -#include + +#include "pci.h" extern struct list_head iSeries_Global_Device_List; @@ -127,7 +129,7 @@ static void iommu_table_getparms(struct device_node *dn, parms->itc_slotno = PCI_DN(dn)->LogicalSlot; parms->itc_virtbus = 0; - HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms)); + HvCallXm_getTceTableParms(iseries_hv_addr(parms)); if (parms->itc_size == 0) panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 82f5abab9afa..3f25f7fc79fc 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1064,10 +1065,10 @@ static void mf_getSrcHistory(char *buffer, int size) ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); ev->event.data.vsp_cmd.result_code = 0xFF; ev->event.data.vsp_cmd.reserved = 0; - ev->event.data.vsp_cmd.sub_data.page[0] = ISERIES_HV_ADDR(pages[0]); - ev->event.data.vsp_cmd.sub_data.page[1] = ISERIES_HV_ADDR(pages[1]); - ev->event.data.vsp_cmd.sub_data.page[2] = ISERIES_HV_ADDR(pages[2]); - ev->event.data.vsp_cmd.sub_data.page[3] = ISERIES_HV_ADDR(pages[3]); + ev->event.data.vsp_cmd.sub_data.page[0] = iseries_hv_addr(pages[0]); + ev->event.data.vsp_cmd.sub_data.page[1] = iseries_hv_addr(pages[1]); + ev->event.data.vsp_cmd.sub_data.page[2] = iseries_hv_addr(pages[2]); + ev->event.data.vsp_cmd.sub_data.page[3] = iseries_hv_addr(pages[3]); mb(); if (signal_event(ev) != 0) return; diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index f79c5982446b..fe34d1175818 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -34,15 +34,16 @@ #include #include #include +#include #include #include -#include #include #include #include "irq.h" +#include "pci.h" extern unsigned long io_page_mask; @@ -368,7 +369,7 @@ static void scan_PHB_slots(struct pci_controller *Phb) */ for (IdSel = 1; IdSel < MaxAgents; ++IdSel) { HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, - ISERIES_HV_ADDR(DevInfo), + iseries_hv_addr(DevInfo), sizeof(struct HvCallPci_DeviceInfo)); if (HvRc == 0) { if (DevInfo->deviceType == HvCallPci_NodeDevice) @@ -409,7 +410,7 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, "PCI:Connect EADs: 0x%02X.%02X.%02X\n", bus, SubBus, AgentId); HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, - ISERIES_HV_ADDR(BridgeInfo), + iseries_hv_addr(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo)); if (HvRc == 0) { printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n", diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/arch/powerpc/platforms/iseries/pci.h similarity index 80% rename from include/asm-ppc64/iSeries/iSeries_pci.h rename to arch/powerpc/platforms/iseries/pci.h index a4d88b49fd9f..e7d92504cb05 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/arch/powerpc/platforms/iseries/pci.h @@ -1,8 +1,8 @@ -#ifndef _ISERIES_64_PCI_H -#define _ISERIES_64_PCI_H +#ifndef _PLATFORMS_ISERIES_PCI_H +#define _PLATFORMS_ISERIES_PCI_H /* - * File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001. + * Created by Allan Trautman on Tue Feb 20, 2001. * * Define some useful macros for the iSeries pci routines. * Copyright (C) 2001 Allan H Trautman, IBM Corporation @@ -30,8 +30,6 @@ * End Change Activity */ -#include -#include #include struct pci_dev; /* For Forward Reference */ @@ -42,9 +40,6 @@ struct pci_dev; /* For Forward Reference */ #define ISERIES_BUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.busNumber #define ISERIES_SUBBUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.subBusNumber -#define ISERIES_DEVNODE(PciDev) ((struct device_node *)PciDev->sysdata) - -#define EADsMaxAgents 7 /* * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. @@ -59,12 +54,6 @@ struct pci_dev; /* For Forward Reference */ #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) -/* - * Converts Virtual Address to Real Address for Hypervisor calls - */ -#define ISERIES_HV_ADDR(virtaddr) \ - (0x8000000000000000 | virt_to_abs(virtaddr)) - extern void iSeries_Device_Information(struct pci_dev*, int); -#endif /* _ISERIES_64_PCI_H */ +#endif /* _PLATFORMS_ISERIES_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c index d8a6796924e2..6bd8da4f17fe 100644 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -27,12 +27,14 @@ #include #include #include + #include #include - +#include #include #include -#include + +#include "pci.h" /* * Size of Bus VPD data @@ -212,7 +214,7 @@ static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, printk("PCI: Bus VPD Buffer allocation failure.\n"); return; } - BusVpdLen = HvCallPci_getBusVpd(bus, ISERIES_HV_ADDR(BusVpdPtr), + BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr), BUS_VPDSIZE); if (BusVpdLen == 0) { printk("PCI: Bus VPD Buffer zero length.\n"); diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index 2114dc9c59b5..bdf15dbbf4f0 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -1,8 +1,8 @@ /* * arch/ppc64/kernel/pci_iommu.c * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup, new allocation schemes: + * + * Rewrite, cleanup, new allocation schemes: * Copyright (C) 2004 Olof Johansson, IBM Corporation * * Dynamic DMA mapping support, platform-independent parts. @@ -11,19 +11,18 @@ * 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 @@ -39,10 +38,6 @@ #include #include -#ifdef CONFIG_PPC_ISERIES -#include -#endif /* CONFIG_PPC_ISERIES */ - /* * We can use ->sysdata directly and avoid the extra work in * pci_device_to_OF_node since ->sysdata will have been initialised diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 3d56cf5a4e23..db3bc2f6f0fa 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -70,8 +70,9 @@ #include #include #include + +#include #include -#include #include #include @@ -1397,13 +1398,13 @@ static inline void veth_build_dma_list(struct dma_chunk *list, * it just at the granularity of iSeries real->absolute * mapping? Indeed, given the way the allocator works, can we * count on them being absolutely contiguous? */ - list[0].addr = ISERIES_HV_ADDR(p); + list[0].addr = iseries_hv_addr(p); list[0].size = min(length, PAGE_SIZE - ((unsigned long)p & ~PAGE_MASK)); done = list[0].size; while (done < length) { - list[i].addr = ISERIES_HV_ADDR(p + done); + list[i].addr = iseries_hv_addr(p + done); list[i].size = min(length-done, PAGE_SIZE); done += list[i].size; i++; @@ -1496,8 +1497,8 @@ static void veth_receive(struct veth_lpar_connection *cnx, cnx->dst_inst, HvLpDma_AddressType_RealAddress, HvLpDma_AddressType_TceIndex, - ISERIES_HV_ADDR(&local_list), - ISERIES_HV_ADDR(&remote_list), + iseries_hv_addr(&local_list), + iseries_hv_addr(&remote_list), length); if (rc != HvLpDma_Rc_Good) { dev_kfree_skb_irq(skb); diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index f80ec8daf122..9d91bdd667ae 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -21,6 +21,7 @@ #ifndef _ASM_IOMMU_H #define _ASM_IOMMU_H +#include #include #include #include diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index efc40980cb48..8a21791c7cae 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -15,6 +15,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #include #include diff --git a/include/asm-ppc64/abs_addr.h b/include/asm-ppc64/abs_addr.h index 84c24d4cdb71..dc3fc3fefef2 100644 --- a/include/asm-ppc64/abs_addr.h +++ b/include/asm-ppc64/abs_addr.h @@ -63,4 +63,11 @@ static inline unsigned long phys_to_abs(unsigned long pa) #define virt_to_abs(va) phys_to_abs(__pa(va)) #define abs_to_virt(aa) __va(aa) +/* + * Converts Virtual Address to Real Address for + * Legacy iSeries Hypervisor calls + */ +#define iseries_hv_addr(virtaddr) \ + (0x8000000000000000 | virt_to_abs(virtaddr)) + #endif /* _ABS_ADDR_H */ diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 56863df18232..01bffca61f89 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -2,6 +2,7 @@ #ifndef _ASM_PCI_BRIDGE_H #define _ASM_PCI_BRIDGE_H +#include #include #include diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h index cf0284e081ea..e8d0d2ab4c0f 100644 --- a/include/asm-ppc64/prom.h +++ b/include/asm-ppc64/prom.h @@ -14,6 +14,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #include From bffa8fc3835b0d3c4a59af8aceeea3aba823b032 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 14 Oct 2005 15:06:10 +1000 Subject: [PATCH 0385/1939] powerpc: remove ISERIES_[SUB]BUS macros This allows us to simplify a couple of things. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/iommu.c | 11 +++++------ arch/powerpc/platforms/iseries/pci.h | 9 --------- arch/powerpc/platforms/iseries/vpdinfo.c | 7 +++++-- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index e6f4a4ab57b8..533d9b467402 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -31,10 +31,9 @@ #include #include #include +#include #include -#include "pci.h" - extern struct list_head iSeries_Global_Device_List; @@ -114,7 +113,7 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) * 2. TCE table per Bus. * 3. TCE Table per IOA. */ -static void iommu_table_getparms(struct device_node *dn, +static void iommu_table_getparms(struct pci_dn *pdn, struct iommu_table* tbl) { struct iommu_table_cb *parms; @@ -125,8 +124,8 @@ static void iommu_table_getparms(struct device_node *dn, memset(parms, 0, sizeof(*parms)); - parms->itc_busno = ISERIES_BUS(dn); - parms->itc_slotno = PCI_DN(dn)->LogicalSlot; + parms->itc_busno = pdn->DsaAddr.Dsa.busNumber; + parms->itc_slotno = pdn->LogicalSlot; parms->itc_virtbus = 0; HvCallXm_getTceTableParms(iseries_hv_addr(parms)); @@ -153,7 +152,7 @@ void iommu_devnode_init_iSeries(struct device_node *dn) tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - iommu_table_getparms(dn, tbl); + iommu_table_getparms(pdn, tbl); /* Look for existing tce table */ pdn->iommu_table = iommu_table_find(tbl); diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h index e7d92504cb05..94b4bfdceadf 100644 --- a/arch/powerpc/platforms/iseries/pci.h +++ b/arch/powerpc/platforms/iseries/pci.h @@ -30,17 +30,8 @@ * End Change Activity */ -#include - struct pci_dev; /* For Forward Reference */ -/* - * Gets iSeries Bus, SubBus, DevFn using device_node structure - */ - -#define ISERIES_BUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.busNumber -#define ISERIES_SUBBUS(DevPtr) PCI_DN(DevPtr)->DsaAddr.Dsa.subBusNumber - /* * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c index 6bd8da4f17fe..dcdac995565c 100644 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -243,6 +244,7 @@ static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) { struct device_node *DevNode = PciDev->sysdata; + struct pci_dn *pdn; u16 bus; u8 frame; char card[4]; @@ -255,8 +257,9 @@ void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) return; } - bus = ISERIES_BUS(DevNode); - subbus = ISERIES_SUBBUS(DevNode); + pdn = PCI_DN(DevNode); + bus = pdn->DsaAddr.Dsa.busNumber; + subbus = pdn->DsaAddr.Dsa.subBusNumber; agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); iSeries_Get_Location_Code(bus, agent, &frame, card); From 20f48ccfa015d8b8391bbf07fc27618453f44969 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 14 Oct 2005 16:49:58 +1000 Subject: [PATCH 0386/1939] powerpc: eliminate DsaAddr from pci_dn Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/iommu.c | 2 +- arch/powerpc/platforms/iseries/pci.c | 20 +- arch/powerpc/platforms/iseries/pci.h | 13 ++ arch/powerpc/platforms/iseries/vpdinfo.c | 4 +- include/asm-ppc64/iSeries/HvCallPci.h | 243 ----------------------- include/asm-ppc64/pci-bridge.h | 3 - 6 files changed, 23 insertions(+), 262 deletions(-) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 533d9b467402..1db26d8be640 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -124,7 +124,7 @@ static void iommu_table_getparms(struct pci_dn *pdn, memset(parms, 0, sizeof(*parms)); - parms->itc_busno = pdn->DsaAddr.Dsa.busNumber; + parms->itc_busno = pdn->busno; parms->itc_slotno = pdn->LogicalSlot; parms->itc_virtbus = 0; diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index fe34d1175818..d14e9d9d7797 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -223,13 +223,8 @@ static struct device_node *build_device_node(HvBusNumber Bus, node->data = pdn; pdn->node = node; list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List); -#if 0 - pdn->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); -#endif - pdn->DsaAddr.DsaAddr = 0; - pdn->DsaAddr.Dsa.busNumber = Bus; - pdn->DsaAddr.Dsa.subBusNumber = SubBus; - pdn->DsaAddr.Dsa.deviceId = 0x10; + pdn->busno = Bus; + pdn->bussubno = SubBus; pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); return node; } @@ -554,8 +549,7 @@ static struct device_node *find_Device_Node(int bus, int devfn) struct pci_dn *pdn; list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { - if ((bus == pdn->DsaAddr.Dsa.busNumber) && - (devfn == pdn->devfn)) + if ((bus == pdn->busno) && (devfn == pdn->devfn)) return pdn->node; } return NULL; @@ -612,7 +606,7 @@ static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, } fn = hv_cfg_read_func[(size - 1) & 3]; - HvCall3Ret16(fn, &ret, PCI_DN(node)->DsaAddr.DsaAddr, offset, 0); + HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0); if (ret.rc != 0) { *val = ~0; @@ -640,7 +634,7 @@ static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_BAD_REGISTER_NUMBER; fn = hv_cfg_write_func[(size - 1) & 3]; - ret = HvCall4(fn, PCI_DN(node)->DsaAddr.DsaAddr, offset, val, 0); + ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0); if (ret != 0) return PCIBIOS_DEVICE_NOT_FOUND; @@ -671,7 +665,7 @@ static int CheckReturnCode(char *TextHdr, struct device_node *DevNode, ++Pci_Error_Count; (*retry)++; printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", - TextHdr, pdn->DsaAddr.Dsa.busNumber, pdn->devfn, + TextHdr, pdn->busno, pdn->devfn, *retry, (int)ret); /* * Bump the retry and check for retry count exceeded. @@ -712,7 +706,7 @@ static inline struct device_node *xlate_iomm_address( if (DevNode != NULL) { int barnum = iobar_table[TableIndex]; - *dsaptr = PCI_DN(DevNode)->DsaAddr.DsaAddr | (barnum << 24); + *dsaptr = iseries_ds_addr(DevNode) | (barnum << 24); *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; } else panic("PCI: Invalid PCI IoAddress detected!\n"); diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h index 94b4bfdceadf..33a8489fde54 100644 --- a/arch/powerpc/platforms/iseries/pci.h +++ b/arch/powerpc/platforms/iseries/pci.h @@ -30,6 +30,8 @@ * End Change Activity */ +#include + struct pci_dev; /* For Forward Reference */ /* @@ -45,6 +47,17 @@ struct pci_dev; /* For Forward Reference */ #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) +/* + * Generate a Direct Select Address for the Hypervisor + */ +static inline u64 iseries_ds_addr(struct device_node *node) +{ + struct pci_dn *pdn = PCI_DN(node); + + return ((u64)pdn->busno << 48) + ((u64)pdn->bussubno << 40) + + ((u64)0x10 << 32); +} + extern void iSeries_Device_Information(struct pci_dev*, int); #endif /* _PLATFORMS_ISERIES_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c index dcdac995565c..a03984e19c13 100644 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -258,8 +258,8 @@ void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) } pdn = PCI_DN(DevNode); - bus = pdn->DsaAddr.Dsa.busNumber; - subbus = pdn->DsaAddr.Dsa.subBusNumber; + bus = pdn->busno; + subbus = pdn->bussubno; agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); iSeries_Get_Location_Code(bus, agent, &frame, card); diff --git a/include/asm-ppc64/iSeries/HvCallPci.h b/include/asm-ppc64/iSeries/HvCallPci.h index c8d675c40f5e..17b4840b64b2 100644 --- a/include/asm-ppc64/iSeries/HvCallPci.h +++ b/include/asm-ppc64/iSeries/HvCallPci.h @@ -126,25 +126,6 @@ enum HvCallPci_VpdType { #define HvCallPciUnmaskInterrupts HvCallPci + 49 #define HvCallPciGetBusUnitInfo HvCallPci + 50 -static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u8 *value) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - HvCall3Ret16(HvCallPciConfigLoad8, &retVal, *(u64 *)&dsa, offset, 0); - - *value = retVal.value; - - return retVal.rc; -} - static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, u8 deviceId, u32 offset, u16 *value) { @@ -164,25 +145,6 @@ static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, return retVal.rc; } -static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u32 *value) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); - - *value = retVal.value; - - return retVal.rc; -} - static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, u8 deviceId, u32 offset, u8 value) { @@ -197,186 +159,6 @@ static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); } -static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u16 value) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - return HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0); -} - -static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u32 value) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - return HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0); -} - -static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u8 *valueParm) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - HvCall3Ret16(HvCallPciBarLoad8, &retVal, *(u64 *)&dsa, offsetParm, 0); - - *valueParm = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_barLoad16(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u16 *valueParm) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - HvCall3Ret16(HvCallPciBarLoad16, &retVal, *(u64 *)&dsa, offsetParm, 0); - - *valueParm = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_barLoad32(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u32 *valueParm) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - HvCall3Ret16(HvCallPciBarLoad32, &retVal, *(u64 *)&dsa, offsetParm, 0); - - *valueParm = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_barLoad64(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u64 *valueParm) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - HvCall3Ret16(HvCallPciBarLoad64, &retVal, *(u64 *)&dsa, offsetParm, 0); - - *valueParm = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u8 valueParm) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - return HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm, - valueParm, 0); -} - -static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u16 valueParm) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - return HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm, - valueParm, 0); -} - -static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u32 valueParm) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - return HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm, - valueParm, 0); -} - -static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, - u64 valueParm) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - return HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm, - valueParm, 0); -} - static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm) { @@ -437,20 +219,6 @@ static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); } -static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 onNotOff) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff); -} - static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, u8 deviceNumberParm, u64 parms, u32 sizeofParms) { @@ -519,15 +287,4 @@ static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, return xRc & 0xFFFF; } -static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, - u16 sizeParm) -{ - u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, - sizeParm, HvCallPci_BusAdapterVpd); - if (xRc == -1) - return -1; - else - return xRc & 0xFFFF; -} - #endif /* _HVCALLPCI_H */ diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 01bffca61f89..0474bdbf556c 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -77,9 +77,6 @@ struct pci_dn { struct device_node *node; /* back-pointer to the device_node */ #ifdef CONFIG_PPC_ISERIES struct list_head Device_List; - union HvDsaMap DsaAddr; /* Direct Select Address */ - /* busNumber, subBusNumber, */ - /* deviceId, barNumber */ int Irq; /* Assigned IRQ */ int Flags; /* Possible flags(disable/bist)*/ u8 LogicalSlot; /* Hv Slot Index for Tces */ From 0e29bb1a4ef69120a614391a649510010031dd8a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 14 Oct 2005 17:09:16 +1000 Subject: [PATCH 0387/1939] powerpc: move iSeries/HvCallHpt.h to platforms/iseries/call_hpt.h Signed-off-by: Stephen Rothwell --- .../powerpc/platforms/iseries/call_hpt.h | 7 +++---- arch/powerpc/platforms/iseries/htab.c | 3 ++- arch/powerpc/platforms/iseries/setup.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename include/asm-ppc64/iSeries/HvCallHpt.h => arch/powerpc/platforms/iseries/call_hpt.h (96%) diff --git a/include/asm-ppc64/iSeries/HvCallHpt.h b/arch/powerpc/platforms/iseries/call_hpt.h similarity index 96% rename from include/asm-ppc64/iSeries/HvCallHpt.h rename to arch/powerpc/platforms/iseries/call_hpt.h index 43a1969230b8..321f3bb7a8f5 100644 --- a/include/asm-ppc64/iSeries/HvCallHpt.h +++ b/arch/powerpc/platforms/iseries/call_hpt.h @@ -1,5 +1,4 @@ /* - * HvCallHpt.h * Copyright (C) 2001 Mike Corrigan IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -16,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _HVCALLHPT_H -#define _HVCALLHPT_H +#ifndef _PLATFORMS_ISERIES_CALL_HPT_H +#define _PLATFORMS_ISERIES_CALL_HPT_H /* * This file contains the "hypervisor call" interface which is used to @@ -99,4 +98,4 @@ static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, hpte_t *hpte) HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); } -#endif /* _HVCALLHPT_H */ +#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */ diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index 431b22767d06..c00b8e9e2b3c 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c @@ -14,10 +14,11 @@ #include #include #include -#include #include #include +#include "call_hpt.h" + static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = { [0 ... 63] = SPIN_LOCK_UNLOCKED}; diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index b6cf050a8c27..93852c2ee5de 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -60,6 +59,7 @@ #include "processor_vpd.h" #include "main_store.h" #include "call_sm.h" +#include "call_hpt.h" extern void hvlog(char *fmt, ...); From c6d2ea92d162c81d4d593b4b5e0f5ceb1b940c72 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 14 Oct 2005 17:16:17 +1000 Subject: [PATCH 0388/1939] powerpc: move iSeries/HvCallPci.h to platforms/iseries/call_pci.h Signed-off-by: Stephen Rothwell --- .../powerpc/platforms/iseries/call_pci.h | 6 +++--- arch/powerpc/platforms/iseries/irq.c | 2 +- arch/powerpc/platforms/iseries/pci.c | 2 +- arch/powerpc/platforms/iseries/vpdinfo.c | 2 +- include/asm-ppc64/pci-bridge.h | 2 -- 5 files changed, 6 insertions(+), 8 deletions(-) rename include/asm-ppc64/iSeries/HvCallPci.h => arch/powerpc/platforms/iseries/call_pci.h (98%) diff --git a/include/asm-ppc64/iSeries/HvCallPci.h b/arch/powerpc/platforms/iseries/call_pci.h similarity index 98% rename from include/asm-ppc64/iSeries/HvCallPci.h rename to arch/powerpc/platforms/iseries/call_pci.h index 17b4840b64b2..a86e065b9577 100644 --- a/include/asm-ppc64/iSeries/HvCallPci.h +++ b/arch/powerpc/platforms/iseries/call_pci.h @@ -22,8 +22,8 @@ * Created, Jan 9, 2001 */ -#ifndef _HVCALLPCI_H -#define _HVCALLPCI_H +#ifndef _PLATFORMS_ISERIES_CALL_PCI_H +#define _PLATFORMS_ISERIES_CALL_PCI_H #include #include @@ -287,4 +287,4 @@ static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, return xRc & 0xFFFF; } -#endif /* _HVCALLPCI_H */ +#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 31fb5fa67fa3..937ac99b9d33 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -38,10 +38,10 @@ #include #include #include -#include #include #include "irq.h" +#include "call_pci.h" /* This maps virtual irq numbers to real irqs */ unsigned int virt_irq_to_real_map[NR_IRQS]; diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index d14e9d9d7797..959e59fd9c11 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -44,6 +43,7 @@ #include "irq.h" #include "pci.h" +#include "call_pci.h" extern unsigned long io_page_mask; diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c index a03984e19c13..9c318849dee7 100644 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ b/arch/powerpc/platforms/iseries/vpdinfo.c @@ -32,10 +32,10 @@ #include #include #include -#include #include #include "pci.h" +#include "call_pci.h" /* * Size of Bus VPD data diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 0474bdbf556c..1136cb6433bf 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -6,8 +6,6 @@ #include #include -#include - /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License From f566a576bca09de85bf477fc0ab2c8c96405b77b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Oct 2005 17:15:29 -0700 Subject: [PATCH 0389/1939] [SCSI] NCR5380: fix undefined preprocessor identifier Fix 12 undefined preprocessor identifier warnings (4 each in 3 driver builds): drivers/scsi/NCR5380.c:2744:16: warning: undefined preprocessor identifier 'NDEBUG_ABORT' drivers/scsi/NCR5380.c:2744:16: warning: "NDEBUG_ABORT" is not defined Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley --- drivers/scsi/NCR5380.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index d40ba0bd68a3..23392ae7df8b 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -91,7 +91,7 @@ #ifndef NDEBUG #define NDEBUG 0 #endif -#ifndef NDEBUG +#ifndef NDEBUG_ABORT #define NDEBUG_ABORT 0 #endif From 7a9366e46c167930f8bd9e378a3656861c5a41b6 Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Wed, 5 Oct 2005 12:58:38 -0400 Subject: [PATCH 0390/1939] [SCSI] Fix aacraid regression Juan was kind enough to linger on site, and work on a production machine, to try the parameter to make the system stable. He discovered that reducing the maximum transfer size issued to the adapter to 128KB stabilized his system. This is related to an earlier change for the 2.6.13 tree resulting from Martin Drab's testing where the transfer size was reduced from 4G to 256KB; we needed to go still further in scaling back the request size. Here is the patch that tames this regression. Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aacraid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 4a99d2f000f4..d54b1cc88d0d 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -19,7 +19,7 @@ #define AAC_MAX_LUN (8) #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff) -#define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)512) +#define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256) /* * These macros convert from physical channels to virtual channels From d16794f6ac8d9b50f62e02a6e6175ae1a30d0ccd Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 5 Oct 2005 13:50:08 -0400 Subject: [PATCH 0391/1939] [SCSI] FW: [PATCH] for Deadlock in transport_fc Cannot call fc_rport_terminate() under the host lock, so drop the lock. Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2cab556b6e82..771e97ef136e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -819,12 +819,15 @@ show_fc_private_host_tgtid_bind_type(struct class_device *cdev, char *buf) return snprintf(buf, FC_BINDTYPE_MAX_NAMELEN, "%s\n", name); } +#define get_list_head_entry(pos, head, member) \ + pos = list_entry((head)->next, typeof(*pos), member) + static ssize_t store_fc_private_host_tgtid_bind_type(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *shost = transport_class_to_shost(cdev); - struct fc_rport *rport, *next_rport; + struct fc_rport *rport; enum fc_tgtid_binding_type val; unsigned long flags; @@ -834,9 +837,13 @@ store_fc_private_host_tgtid_bind_type(struct class_device *cdev, /* if changing bind type, purge all unused consistent bindings */ if (val != fc_host_tgtid_bind_type(shost)) { spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry_safe(rport, next_rport, - &fc_host_rport_bindings(shost), peers) + while (!list_empty(&fc_host_rport_bindings(shost))) { + get_list_head_entry(rport, + &fc_host_rport_bindings(shost), peers); + spin_unlock_irqrestore(shost->host_lock, flags); fc_rport_terminate(rport); + spin_lock_irqsave(shost->host_lock, flags); + } spin_unlock_irqrestore(shost->host_lock, flags); } From 7c72ce81870ded9365f4bc5caa98ef1591dd18dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 14 Oct 2005 11:23:27 -0400 Subject: [PATCH 0392/1939] [SCSI] Fix leak of Scsi_Cmnds When a request is deferred in scsi_init_io because the sg table could not be allocated, the associated scsi_cmnd is not released and the request is not marked with REQ_DONTPREP. When the command is retried, if scsi_prep_fn decides to kill it then the scsi_cmnd will never be released. This patch (as573) changes scsi_init_io so that it calls scsi_put_command before deferring a request. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index dc9c772bc874..0074f28c37b2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -97,7 +97,6 @@ int scsi_insert_special_req(struct scsi_request *sreq, int at_head) } static void scsi_run_queue(struct request_queue *q); -static void scsi_release_buffers(struct scsi_cmnd *cmd); /* * Function: scsi_unprep_request() @@ -1040,8 +1039,10 @@ static int scsi_init_io(struct scsi_cmnd *cmd) * if sg table allocation fails, requeue request later. */ sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC); - if (unlikely(!sgpnt)) + if (unlikely(!sgpnt)) { + scsi_unprep_request(req); return BLKPREP_DEFER; + } cmd->request_buffer = (char *) sgpnt; cmd->request_bufflen = req->nr_sectors << 9; @@ -1245,8 +1246,8 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) */ ret = scsi_init_io(cmd); switch(ret) { + /* For BLKPREP_KILL/DEFER the cmd was released */ case BLKPREP_KILL: - /* BLKPREP_KILL return also releases the command */ goto kill; case BLKPREP_DEFER: goto defer; From cf764855620aa1aa5b134687ca18b841ac9be4c7 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 17 Oct 2005 11:46:53 +1000 Subject: [PATCH 0393/1939] powerpc: fix 32bit LOADADDR macro I forgot a semicolon. Signed-off-by: Stephen Rothwell --- include/asm-powerpc/ppc_asm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 6aae414a161b..96367e04fa58 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -194,7 +194,7 @@ GLUE(.,name): #else /* 32-bit */ #define LOADADDR(rn,name) \ - lis rn,name@ha \ + lis rn,name@ha; \ addi rn,rn,name@l #define LOADBASE(rn,name) \ From 7dffb72028bfd909ac51a1546d182de2df4d2426 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 17 Oct 2005 11:50:32 +1000 Subject: [PATCH 0394/1939] ppc32: use L1_CACHE_SHIFT/L1_CACHE_BYTES instead of L1_CACHE_LINE_SIZE and LG_L1_CACHE_LINE_SIZE Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/head_32.S | 2 +- arch/powerpc/kernel/misc_32.S | 58 ++++++++++++------------- arch/powerpc/lib/copy_32.S | 24 +++++----- arch/powerpc/platforms/powermac/sleep.S | 4 +- arch/ppc/kernel/cpu_setup_6xx.S | 4 +- arch/ppc/kernel/cpu_setup_power4.S | 4 +- arch/ppc/kernel/head.S | 2 +- arch/ppc/kernel/l2cr.S | 2 +- arch/ppc/kernel/misc.S | 58 ++++++++++++------------- arch/ppc/lib/string.S | 24 +++++----- arch/ppc/platforms/katana.c | 2 +- arch/ppc/platforms/pmac_sleep.S | 4 +- arch/ppc/syslib/mv64x60.c | 2 +- include/asm-ppc/cache.h | 13 +++--- 14 files changed, 100 insertions(+), 103 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 108e78ef3878..d9b063f567e0 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -837,7 +837,7 @@ relocate_kernel: copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,L1_CACHE_LINE_SIZE/4 +4: li r0,L1_CACHE_BYTES/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 27274108116f..0b0e908b5065 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -496,21 +496,21 @@ _GLOBAL(flush_icache_range) BEGIN_FTR_SECTION blr /* for 601, do nothing */ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 mr r6,r3 1: dcbst 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ mtctr r4 2: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 2b sync /* additional sync needed on g4 */ isync @@ -523,16 +523,16 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) * clean_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(clean_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbst 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ blr @@ -544,16 +544,16 @@ _GLOBAL(clean_dcache_range) * flush_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(flush_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbf 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ blr @@ -566,16 +566,16 @@ _GLOBAL(flush_dcache_range) * invalidate_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(invalidate_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbi 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbi's to get to ram */ blr @@ -596,7 +596,7 @@ _GLOBAL(flush_dcache_all) mtctr r4 lis r5, KERNELBASE@h 1: lwz r3, 0(r5) /* Load one word from every line */ - addi r5, r5, L1_CACHE_LINE_SIZE + addi r5, r5, L1_CACHE_BYTES bdnz 1b blr #endif /* CONFIG_NOT_COHERENT_CACHE */ @@ -614,16 +614,16 @@ BEGIN_FTR_SECTION blr /* for 601, do nothing */ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 0b sync mtctr r4 1: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 1b sync isync @@ -646,16 +646,16 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) mtmsr r0 isync rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 0b sync mtctr r4 1: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 1b sync mtmsr r10 /* restore DR */ @@ -670,7 +670,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) * void clear_pages(void *page, int order) ; */ _GLOBAL(clear_pages) - li r0,4096/L1_CACHE_LINE_SIZE + li r0,4096/L1_CACHE_BYTES slw r0,r0,r4 mtctr r0 #ifdef CONFIG_8xx @@ -682,7 +682,7 @@ _GLOBAL(clear_pages) #else 1: dcbz 0,r3 #endif - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b blr @@ -708,7 +708,7 @@ _GLOBAL(copy_page) #ifdef CONFIG_8xx /* don't use prefetch on 8xx */ - li r0,4096/L1_CACHE_LINE_SIZE + li r0,4096/L1_CACHE_BYTES mtctr r0 1: COPY_16_BYTES bdnz 1b @@ -722,13 +722,13 @@ _GLOBAL(copy_page) li r11,4 mtctr r0 11: dcbt r11,r4 - addi r11,r11,L1_CACHE_LINE_SIZE + addi r11,r11,L1_CACHE_BYTES bdnz 11b #else /* MAX_COPY_PREFETCH == 1 */ dcbt r5,r4 - li r11,L1_CACHE_LINE_SIZE+4 + li r11,L1_CACHE_BYTES+4 #endif /* MAX_COPY_PREFETCH */ - li r0,4096/L1_CACHE_LINE_SIZE - MAX_COPY_PREFETCH + li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH crclr 4*cr0+eq 2: mtctr r0 @@ -736,12 +736,12 @@ _GLOBAL(copy_page) dcbt r11,r4 dcbz r5,r3 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES COPY_16_BYTES COPY_16_BYTES diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S index 420a912198a2..bee51414812e 100644 --- a/arch/powerpc/lib/copy_32.S +++ b/arch/powerpc/lib/copy_32.S @@ -66,9 +66,9 @@ .stabs "copy32.S",N_SO,0,0,0f 0: -CACHELINE_BYTES = L1_CACHE_LINE_SIZE -LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE -CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1) +CACHELINE_BYTES = L1_CACHE_BYTES +LG_CACHELINE_BYTES = L1_CACHE_SHIFT +CACHELINE_MASK = (L1_CACHE_BYTES-1) /* * Use dcbz on the complete cache lines in the destination @@ -205,12 +205,12 @@ _GLOBAL(cacheable_memcpy) dcbz r11,r6 #endif COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES COPY_16_BYTES COPY_16_BYTES @@ -399,12 +399,12 @@ _GLOBAL(__copy_tofrom_user) .text /* the main body of the cacheline loop */ COPY_16_BYTES_WITHEX(0) -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES_WITHEX(1) -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES_WITHEX(2) COPY_16_BYTES_WITHEX(3) -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES_WITHEX(4) COPY_16_BYTES_WITHEX(5) COPY_16_BYTES_WITHEX(6) @@ -458,12 +458,12 @@ _GLOBAL(__copy_tofrom_user) * 104f (if in read part) or 105f (if in write part), after updating r5 */ COPY_16_BYTES_EXCODE(0) -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES_EXCODE(1) -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES_EXCODE(2) COPY_16_BYTES_EXCODE(3) -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES_EXCODE(4) COPY_16_BYTES_EXCODE(5) COPY_16_BYTES_EXCODE(6) diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S index 88419c77ac43..22b113d19b24 100644 --- a/arch/powerpc/platforms/powermac/sleep.S +++ b/arch/powerpc/platforms/powermac/sleep.S @@ -387,10 +387,10 @@ turn_on_mmu: #endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */ .section .data - .balign L1_CACHE_LINE_SIZE + .balign L1_CACHE_BYTES sleep_storage: .long 0 - .balign L1_CACHE_LINE_SIZE, 0 + .balign L1_CACHE_BYTES, 0 #endif /* CONFIG_6xx */ .section .text diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index a5333c07fc3c..55ed7716636f 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -290,10 +290,10 @@ _GLOBAL(__init_fpu_registers) #define CS_SIZE 32 .data - .balign L1_CACHE_LINE_SIZE + .balign L1_CACHE_BYTES cpu_state_storage: .space CS_SIZE - .balign L1_CACHE_LINE_SIZE,0 + .balign L1_CACHE_BYTES,0 .text /* Called in normal context to backup CPU 0 state. This diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S index 0abb5f25b2ca..d7bfd60e21fc 100644 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ b/arch/ppc/kernel/cpu_setup_power4.S @@ -86,10 +86,10 @@ _GLOBAL(__setup_cpu_ppc970) #define CS_SIZE 32 .data - .balign L1_CACHE_LINE_SIZE + .balign L1_CACHE_BYTES cpu_state_storage: .space CS_SIZE - .balign L1_CACHE_LINE_SIZE,0 + .balign L1_CACHE_BYTES,0 .text /* Called in normal context to backup CPU 0 state. This diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 5b43987a943b..c5a890dca9cf 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -916,7 +916,7 @@ relocate_kernel: copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,L1_CACHE_LINE_SIZE/4 +4: li r0,L1_CACHE_BYTES/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 diff --git a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S index 861115249b35..d7f4e982b539 100644 --- a/arch/ppc/kernel/l2cr.S +++ b/arch/ppc/kernel/l2cr.S @@ -203,7 +203,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) * L1 icache */ b 20f - .balign L1_CACHE_LINE_SIZE + .balign L1_CACHE_BYTES 22: sync mtspr SPRN_L2CR,r3 diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 2b9a16274b0b..2350f3e09f95 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -498,21 +498,21 @@ _GLOBAL(flush_icache_range) BEGIN_FTR_SECTION blr /* for 601, do nothing */ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 mr r6,r3 1: dcbst 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ mtctr r4 2: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 2b sync /* additional sync needed on g4 */ isync @@ -525,16 +525,16 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) * clean_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(clean_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbst 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ blr @@ -546,16 +546,16 @@ _GLOBAL(clean_dcache_range) * flush_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(flush_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbf 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbst's to get to ram */ blr @@ -568,16 +568,16 @@ _GLOBAL(flush_dcache_range) * invalidate_dcache_range(unsigned long start, unsigned long stop) */ _GLOBAL(invalidate_dcache_range) - li r5,L1_CACHE_LINE_SIZE-1 + li r5,L1_CACHE_BYTES-1 andc r3,r3,r5 subf r4,r3,r4 add r4,r4,r5 - srwi. r4,r4,LG_L1_CACHE_LINE_SIZE + srwi. r4,r4,L1_CACHE_SHIFT beqlr mtctr r4 1: dcbi 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b sync /* wait for dcbi's to get to ram */ blr @@ -598,7 +598,7 @@ _GLOBAL(flush_dcache_all) mtctr r4 lis r5, KERNELBASE@h 1: lwz r3, 0(r5) /* Load one word from every line */ - addi r5, r5, L1_CACHE_LINE_SIZE + addi r5, r5, L1_CACHE_BYTES bdnz 1b blr #endif /* CONFIG_NOT_COHERENT_CACHE */ @@ -616,16 +616,16 @@ BEGIN_FTR_SECTION blr /* for 601, do nothing */ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 0b sync mtctr r4 1: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 1b sync isync @@ -648,16 +648,16 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) mtmsr r0 isync rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ + li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 0b sync mtctr r4 1: icbi 0,r6 - addi r6,r6,L1_CACHE_LINE_SIZE + addi r6,r6,L1_CACHE_BYTES bdnz 1b sync mtmsr r10 /* restore DR */ @@ -672,7 +672,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) * void clear_pages(void *page, int order) ; */ _GLOBAL(clear_pages) - li r0,4096/L1_CACHE_LINE_SIZE + li r0,4096/L1_CACHE_BYTES slw r0,r0,r4 mtctr r0 #ifdef CONFIG_8xx @@ -684,7 +684,7 @@ _GLOBAL(clear_pages) #else 1: dcbz 0,r3 #endif - addi r3,r3,L1_CACHE_LINE_SIZE + addi r3,r3,L1_CACHE_BYTES bdnz 1b blr @@ -710,7 +710,7 @@ _GLOBAL(copy_page) #ifdef CONFIG_8xx /* don't use prefetch on 8xx */ - li r0,4096/L1_CACHE_LINE_SIZE + li r0,4096/L1_CACHE_BYTES mtctr r0 1: COPY_16_BYTES bdnz 1b @@ -724,13 +724,13 @@ _GLOBAL(copy_page) li r11,4 mtctr r0 11: dcbt r11,r4 - addi r11,r11,L1_CACHE_LINE_SIZE + addi r11,r11,L1_CACHE_BYTES bdnz 11b #else /* MAX_COPY_PREFETCH == 1 */ dcbt r5,r4 - li r11,L1_CACHE_LINE_SIZE+4 + li r11,L1_CACHE_BYTES+4 #endif /* MAX_COPY_PREFETCH */ - li r0,4096/L1_CACHE_LINE_SIZE - MAX_COPY_PREFETCH + li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH crclr 4*cr0+eq 2: mtctr r0 @@ -738,12 +738,12 @@ _GLOBAL(copy_page) dcbt r11,r4 dcbz r5,r3 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES COPY_16_BYTES COPY_16_BYTES diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 36c9b97fd92a..2e258c49e8be 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -65,9 +65,9 @@ .stabs "arch/ppc/lib/",N_SO,0,0,0f .stabs "string.S",N_SO,0,0,0f -CACHELINE_BYTES = L1_CACHE_LINE_SIZE -LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE -CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1) +CACHELINE_BYTES = L1_CACHE_BYTES +LG_CACHELINE_BYTES = L1_CACHE_SHIFT +CACHELINE_MASK = (L1_CACHE_BYTES-1) _GLOBAL(strcpy) addi r5,r3,-1 @@ -265,12 +265,12 @@ _GLOBAL(cacheable_memcpy) dcbz r11,r6 #endif COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES COPY_16_BYTES -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES COPY_16_BYTES COPY_16_BYTES @@ -485,12 +485,12 @@ _GLOBAL(__copy_tofrom_user) .text /* the main body of the cacheline loop */ COPY_16_BYTES_WITHEX(0) -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES_WITHEX(1) -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES_WITHEX(2) COPY_16_BYTES_WITHEX(3) -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES_WITHEX(4) COPY_16_BYTES_WITHEX(5) COPY_16_BYTES_WITHEX(6) @@ -544,12 +544,12 @@ _GLOBAL(__copy_tofrom_user) * 104f (if in read part) or 105f (if in write part), after updating r5 */ COPY_16_BYTES_EXCODE(0) -#if L1_CACHE_LINE_SIZE >= 32 +#if L1_CACHE_BYTES >= 32 COPY_16_BYTES_EXCODE(1) -#if L1_CACHE_LINE_SIZE >= 64 +#if L1_CACHE_BYTES >= 64 COPY_16_BYTES_EXCODE(2) COPY_16_BYTES_EXCODE(3) -#if L1_CACHE_LINE_SIZE >= 128 +#if L1_CACHE_BYTES >= 128 COPY_16_BYTES_EXCODE(4) COPY_16_BYTES_EXCODE(5) COPY_16_BYTES_EXCODE(6) diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index 3eb611e23f69..a301c5ac58dd 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -521,7 +521,7 @@ katana_fixup_resources(struct pci_dev *dev) { u16 v16; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_LINE_SIZE>>2); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES>>2); pci_read_config_word(dev, PCI_COMMAND, &v16); v16 |= PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK; diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S index 88419c77ac43..22b113d19b24 100644 --- a/arch/ppc/platforms/pmac_sleep.S +++ b/arch/ppc/platforms/pmac_sleep.S @@ -387,10 +387,10 @@ turn_on_mmu: #endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */ .section .data - .balign L1_CACHE_LINE_SIZE + .balign L1_CACHE_BYTES sleep_storage: .long 0 - .balign L1_CACHE_LINE_SIZE, 0 + .balign L1_CACHE_BYTES, 0 #endif /* CONFIG_6xx */ .section .text diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index 4849850a59ed..a781c50d2f4c 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c @@ -1304,7 +1304,7 @@ mv64x60_config_pci_params(struct pci_controller *hose, early_write_config_word(hose, 0, devfn, PCI_COMMAND, u16_val); /* Set latency timer, cache line size, clear BIST */ - u16_val = (pi->latency_timer << 8) | (L1_CACHE_LINE_SIZE >> 2); + u16_val = (pi->latency_timer << 8) | (L1_CACHE_BYTES >> 2); early_write_config_word(hose, 0, devfn, PCI_CACHE_LINE_SIZE, u16_val); mv64x60_pci_exclude_bridge = save_exclude; diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h index 38f2f1be4a87..7a157d0f4b5f 100644 --- a/include/asm-ppc/cache.h +++ b/include/asm-ppc/cache.h @@ -9,21 +9,18 @@ /* bytes per L1 cache line */ #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) -#define L1_CACHE_LINE_SIZE 16 -#define LG_L1_CACHE_LINE_SIZE 4 +#define L1_CACHE_SHIFT 4 #define MAX_COPY_PREFETCH 1 #elif defined(CONFIG_PPC64BRIDGE) -#define L1_CACHE_LINE_SIZE 128 -#define LG_L1_CACHE_LINE_SIZE 7 +#define L1_CACHE_SHIFT 7 #define MAX_COPY_PREFETCH 1 #else -#define L1_CACHE_LINE_SIZE 32 -#define LG_L1_CACHE_LINE_SIZE 5 +#define L1_CACHE_SHIFT 5 #define MAX_COPY_PREFETCH 4 #endif -#define L1_CACHE_BYTES L1_CACHE_LINE_SIZE -#define L1_CACHE_SHIFT LG_L1_CACHE_LINE_SIZE +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + #define SMP_CACHE_BYTES L1_CACHE_BYTES #define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ From 30cd4a4e9c25e154ba087848a839bd0c6d024092 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 19:20:46 +1000 Subject: [PATCH 0395/1939] powerpc: Initialize btext subsystem later, after prom_init We were initializing the btext stuff from prom_init(), thus breaking the rule that all communication between prom_init() and the rest of the kernel has to be via the flattened device tree. This removes the btext initialization calls from prom_init() and initializes it instead after the device tree is unflattened. It would be nice to do it earlier, but that needs some more infrastructure to find the properties we need in the flattened device tree. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_32.S | 28 ---------------- arch/powerpc/kernel/prom_init.c | 59 --------------------------------- arch/powerpc/kernel/setup_32.c | 16 +++------ arch/powerpc/mm/init_32.c | 7 ---- 4 files changed, 4 insertions(+), 106 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index d9b063f567e0..7ef9a3e3002b 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -153,9 +153,6 @@ __after_mmu_off: bl flush_tlbs bl initial_bats -#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) - bl setup_disp_bat -#endif /* * Call setup_cpu for CPU 0 and initialize 6xx Idle @@ -1297,31 +1294,6 @@ initial_bats: isync blr -#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) -setup_disp_bat: - /* - * setup the display bat prepared for us in prom.c - */ - mflr r8 - bl reloc_offset - mtlr r8 - addis r8,r3,disp_BAT@ha - addi r8,r8,disp_BAT@l - lwz r11,0(r8) - lwz r8,4(r8) - mfspr r9,SPRN_PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpwi 0,r9,1 - beq 1f - mtspr SPRN_DBAT3L,r8 - mtspr SPRN_DBAT3U,r11 - blr -1: mtspr SPRN_IBAT3L,r8 - mtspr SPRN_IBAT3U,r11 - blr - -#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ - #ifdef CONFIG_8260 /* Jump into the system reset for the rom. diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 911a803f27da..d9130c839039 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1404,62 +1404,6 @@ static int __init prom_find_machine_type(void) #endif } -static int __init setup_disp(phandle dp) -{ -#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - u32 addrs[8][5]; - int i, naddrs; - char name[32]; - char *getprop = "getprop"; - - prom_printf("Initializing screen: "); - - memset(name, 0, sizeof(name)); - call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_print(name); - prom_print("\n"); - call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); - call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); - call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - call_prom(getprop, 4, 1, dp, "linebytes", - &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - call_prom(getprop, 4, 1, dp, "address", &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses", - addrs, sizeof(addrs)); - naddrs /= 20; - for (i = 0; i < naddrs; ++i) { - if (addrs[i][4] >= (1 << 20)) { - address = addrs[i][2]; - /* use the BE aperture if possible */ - if (addrs[i][4] >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_print("Failed to get address\n"); - return 0; - } - } - /* kludge for valkyrie */ - if (strcmp(name, "valkyrie") == 0) - address += 0x1000; - - prom_printf("\n\n\n\naddress = %x\n", address); - btext_setup_display(width, height, depth, pitch, address); -#endif /* CONFIG_BOOTX_TEXT && CONFIG_PPC32 */ - return 1; -} - static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) { return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); @@ -1479,7 +1423,6 @@ static void __init prom_check_displays(void) phandle node; ihandle ih; int i; - int got_display = 0; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, @@ -1546,8 +1489,6 @@ static void __init prom_check_displays(void) clut[2]) != 0) break; #endif /* CONFIG_LOGO_LINUX_CLUT224 */ - if (!got_display) - got_display = setup_disp(node); } } diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index bfa155c00ea5..e68f848f24bf 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -294,8 +294,6 @@ unsigned long __init early_init(unsigned long dt_ptr) { unsigned long offset = reloc_offset(); - reloc_got2(offset); - /* * Identify the CPU type and fix up code sections * that depend on which cpu we have. @@ -303,12 +301,6 @@ unsigned long __init early_init(unsigned long dt_ptr) identify_cpu(offset, 0); do_cpu_ftr_fixups(offset); -#ifdef CONFIG_BOOTX_TEXT - btext_prepare_BAT(); -#endif - - reloc_got2(-offset); - return KERNELBASE + offset; } @@ -578,13 +570,13 @@ void __init setup_arch(char **cmdline_p) /* so udelay does something sensible, assume <= 1000 bogomips */ loops_per_jiffy = 500000000 / HZ; -#ifdef CONFIG_BOOTX_TEXT - map_boot_text(); -#endif - unflatten_device_tree(); finish_device_tree(); +#ifdef CONFIG_BOOTX_TEXT + init_boot_display(); +#endif + #ifdef CONFIG_PPC_MULTIPLATFORM /* This could be called "early setup arch", it must be done * now because xmon need it diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index bf13c14e66b3..caeb02ee72c5 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -188,13 +188,6 @@ void __init MMU_init(void) if (ppc_md.progress) ppc_md.progress("MMU:exit", 0x211); - -#ifdef CONFIG_BOOTX_TEXT - /* By default, we are no longer mapped */ - boot_text_mapped = 0; - /* Must be done last, or ppc_md.progress will die. */ - map_boot_text(); -#endif } /* This is only called until mem_init is done. */ From 30286ef6e044bc3d9019c3d8b900572e3fa05e65 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 20:10:13 +1000 Subject: [PATCH 0396/1939] powerpc: Merge syscalls.c and sys_ppc32.c. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 6 +- arch/{ppc64 => powerpc}/kernel/sys_ppc32.c | 48 ---- arch/{ppc64 => powerpc}/kernel/syscalls.c | 180 ++++++++++---- arch/powerpc/kernel/systbl.S | 6 +- arch/ppc/kernel/Makefile | 3 +- arch/ppc/kernel/syscalls.c | 268 --------------------- arch/ppc64/kernel/Makefile | 4 +- arch/ppc64/kernel/misc.S | 8 +- 8 files changed, 147 insertions(+), 376 deletions(-) rename arch/{ppc64 => powerpc}/kernel/sys_ppc32.c (95%) rename arch/{ppc64 => powerpc}/kernel/syscalls.c (56%) delete mode 100644 arch/ppc/kernel/syscalls.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ae97295f270d..1ca740bc5b47 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -11,7 +11,7 @@ CFLAGS_btext.o += -fPIC endif obj-y := semaphore.o cputable.o ptrace.o -obj-$(CONFIG_PPC64) += binfmt_elf32.o +obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o @@ -30,7 +30,7 @@ extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y += process.o init_task.o \ - prom.o systbl.o traps.o + prom.o systbl.o traps.o syscalls.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o @@ -44,7 +44,7 @@ endif else # stuff used from here for ARCH=ppc or ARCH=ppc64 -obj-$(CONFIG_PPC64) += traps.o process.o init_task.o +obj-$(CONFIG_PPC64) += traps.o process.o init_task.o syscalls.o fpux-$(CONFIG_PPC32) += fpu.o extra-$(CONFIG_PPC_FPU) += $(fpux-y) diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c similarity index 95% rename from arch/ppc64/kernel/sys_ppc32.c rename to arch/powerpc/kernel/sys_ppc32.c index b53f565ee443..9babe055356e 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -985,54 +985,6 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) } #endif -asmlinkage int sys32_uname(struct old_utsname __user * name) -{ - int err = 0; - - down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) - err = -EFAULT; - up_read(&uts_sem); - if (!err && personality(current->personality) == PER_LINUX32) { - /* change "ppc64" to "ppc" */ - if (__put_user(0, name->machine + 3) - || __put_user(0, name->machine + 4)) - err = -EFAULT; - } - return err; -} - -asmlinkage int sys32_olduname(struct oldold_utsname __user * name) -{ - int error; - - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - if (personality(current->personality) == PER_LINUX32) { - /* change "ppc64" to "ppc" */ - error |= __put_user(0, name->machine + 3); - error |= __put_user(0, name->machine + 4); - } - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - unsigned long sys32_mmap2(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) diff --git a/arch/ppc64/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c similarity index 56% rename from arch/ppc64/kernel/syscalls.c rename to arch/powerpc/kernel/syscalls.c index 05f16633bd2c..3e3a4f67de96 100644 --- a/arch/ppc64/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -1,7 +1,6 @@ /* - * linux/arch/ppc64/kernel/sys_ppc.c + * Implementation of various system calls for Linux/PowerPC * - * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Derived from "arch/i386/kernel/sys_i386.c" @@ -52,9 +51,8 @@ extern unsigned long wall_jiffies; * * This is really horribly ugly. */ -asmlinkage int -sys_ipc (uint call, int first, unsigned long second, long third, - void __user *ptr, long fifth) +int sys_ipc(uint call, int first, unsigned long second, long third, + void __user *ptr, long fifth) { int version, ret; @@ -88,7 +86,7 @@ sys_ipc (uint call, int first, unsigned long second, long third, } case MSGSND: ret = sys_msgsnd(first, (struct msgbuf __user *)ptr, - (size_t)second, third); + (size_t)second, third); break; case MSGRCV: switch (version) { @@ -113,41 +111,29 @@ sys_ipc (uint call, int first, unsigned long second, long third, } break; case MSGGET: - ret = sys_msgget ((key_t)first, (int)second); + ret = sys_msgget((key_t)first, (int)second); break; case MSGCTL: ret = sys_msgctl(first, (int)second, (struct msqid_ds __user *)ptr); break; - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = do_shmat(first, (char __user *) ptr, - (int)second, &raddr); - if (ret) - break; - ret = put_user (raddr, (ulong __user *) third); + case SHMAT: { + ulong raddr; + ret = do_shmat(first, (char __user *)ptr, (int)second, &raddr); + if (ret) break; - } - case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; - if (!segment_eq(get_fs(), get_ds())) - break; - ret = do_shmat(first, (char __user *)ptr, - (int)second, (ulong *)third); - break; - } + ret = put_user(raddr, (ulong __user *) third); break; - case SHMDT: - ret = sys_shmdt ((char __user *)ptr); + } + case SHMDT: + ret = sys_shmdt((char __user *)ptr); break; case SHMGET: - ret = sys_shmget (first, (size_t)second, third); + ret = sys_shmget(first, (size_t)second, third); break; case SHMCTL: ret = sys_shmctl(first, (int)second, - (struct shmid_ds __user *)ptr); + (struct shmid_ds __user *)ptr); break; } @@ -158,43 +144,89 @@ sys_ipc (uint call, int first, unsigned long second, long third, * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage int sys_pipe(int __user *fildes) +int sys_pipe(int __user *fildes) { int fd[2]; int error; - + error = do_pipe(fd); if (!error) { if (copy_to_user(fildes, fd, 2*sizeof(int))) error = -EFAULT; } - return error; } -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +static inline unsigned long do_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off, int shift) { struct file * file = NULL; - unsigned long ret = -EBADF; + int ret = -EINVAL; + if (shift) { + if (off & ((1 << shift) - 1)) + goto out; + off >>= shift; + } + + ret = -EBADF; if (!(flags & MAP_ANONYMOUS)) { if (!(file = fget(fd))) goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, offset); + ret = do_mmap_pgoff(file, addr, len, prot, flags, off); up_write(¤t->mm->mmap_sem); if (file) fput(file); - out: return ret; } +unsigned long sys_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff, PAGE_SHIFT-12); +} + +unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + return do_mmap2(addr, len, prot, flags, fd, offset, PAGE_SHIFT); +} + +#ifdef CONFIG_PPC32 +/* + * Due to some executables calling the wrong select we sometimes + * get wrong args. This determines how the args are being passed + * (a single ptr to them all args passed) then calls + * sys_select() with the appropriate args. -- Cort + */ +int +ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) +{ + if ( (unsigned long)n >= 4096 ) + { + unsigned long __user *buffer = (unsigned long __user *)n; + if (!access_ok(VERIFY_READ, buffer, 5*sizeof(unsigned long)) + || __get_user(n, buffer) + || __get_user(inp, ((fd_set __user * __user *)(buffer+1))) + || __get_user(outp, ((fd_set __user * __user *)(buffer+2))) + || __get_user(exp, ((fd_set __user * __user *)(buffer+3))) + || __get_user(tvp, ((struct timeval __user * __user *)(buffer+4)))) + return -EFAULT; + } + return sys_select(n, inp, outp, exp, tvp); +} +#endif + +#ifdef CONFIG_PPC64 long ppc64_personality(unsigned long personality) { long ret; @@ -207,8 +239,25 @@ long ppc64_personality(unsigned long personality) ret = PER_LINUX; return ret; } +#endif -long ppc64_newuname(struct new_utsname __user * name) +#ifdef CONFIG_PPC64 +#define OVERRIDE_MACHINE (personality(current->personality) == PER_LINUX32) +#else +#define OVERRIDE_MACHINE 0 +#endif + +static inline int override_machine(char *mach) +{ + if (OVERRIDE_MACHINE) { + /* change ppc64 to ppc */ + if (__put_user(0, mach+3) || __put_user(0, mach+4)) + return -EFAULT; + } + return 0; +} + +long ppc_newuname(struct new_utsname __user * name) { int err = 0; @@ -216,16 +265,54 @@ long ppc64_newuname(struct new_utsname __user * name) if (copy_to_user(name, &system_utsname, sizeof(*name))) err = -EFAULT; up_read(&uts_sem); - if (!err && personality(current->personality) == PER_LINUX32) { - /* change ppc64 to ppc */ - if (__put_user(0, name->machine + 3) - || __put_user(0, name->machine + 4)) - err = -EFAULT; - } + if (!err) + err = override_machine(name->machine); return err; } -asmlinkage time_t sys64_time(time_t __user * tloc) +int sys_uname(struct old_utsname __user *name) +{ + int err = 0; + + down_read(&uts_sem); + if (copy_to_user(name, &system_utsname, sizeof(*name))) + err = -EFAULT; + up_read(&uts_sem); + if (!err) + err = override_machine(name->machine); + return err; +} + +int sys_olduname(struct oldold_utsname __user *name) +{ + int error; + + if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) + return -EFAULT; + + down_read(&uts_sem); + error = __copy_to_user(&name->sysname, &system_utsname.sysname, + __OLD_UTS_LEN); + error |= __put_user(0, name->sysname + __OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename, &system_utsname.nodename, + __OLD_UTS_LEN); + error |= __put_user(0, name->nodename + __OLD_UTS_LEN); + error |= __copy_to_user(&name->release, &system_utsname.release, + __OLD_UTS_LEN); + error |= __put_user(0, name->release + __OLD_UTS_LEN); + error |= __copy_to_user(&name->version, &system_utsname.version, + __OLD_UTS_LEN); + error |= __put_user(0, name->version + __OLD_UTS_LEN); + error |= __copy_to_user(&name->machine, &system_utsname.machine, + __OLD_UTS_LEN); + error |= override_machine(name->machine); + up_read(&uts_sem); + + return error? -EFAULT: 0; +} + +#ifdef CONFIG_PPC64 +time_t sys64_time(time_t __user * tloc) { time_t secs; time_t usecs; @@ -247,6 +334,7 @@ asmlinkage time_t sys64_time(time_t __user * tloc) return secs; } +#endif void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 82d1fedb441c..b364141ec01c 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -102,7 +102,7 @@ COMPAT_SYS(fcntl) SYSCALL(ni_syscall) SYSCALL32(setpgid) SYSCALL(ni_syscall) -SYS32ONLY(olduname) +SYSX(sys_ni_syscall,sys_olduname, sys_olduname) SYSCALL32(umask) SYSCALL(chroot) SYSCALL(ustat) @@ -152,7 +152,7 @@ COMPAT_SYS(getitimer) COMPAT_SYS(newstat) COMPAT_SYS(newlstat) COMPAT_SYS(newfstat) -SYSX(sys_ni_syscall,sys32_uname,sys_uname) +SYSX(sys_ni_syscall,sys_uname,sys_uname) SYSCALL(ni_syscall) SYSCALL(vhangup) SYSCALL(ni_syscall) @@ -165,7 +165,7 @@ SYSCALL(fsync) SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) PPC_SYS(clone) SYSCALL32(setdomainname) -SYSX(ppc64_newuname,ppc64_newuname,sys_newuname) +PPC_SYS(newuname) SYSCALL(ni_syscall) SYSCALL32(adjtimex) SYSCALL(mprotect) diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 7d16b1f7cd31..87d3be4af820 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -38,8 +38,7 @@ endif else obj-y := irq.o idle.o time.o \ - signal.o align.o \ - syscalls.o perfmon.o + signal.o align.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c deleted file mode 100644 index 127f040de9de..000000000000 --- a/arch/ppc/kernel/syscalls.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * arch/ppc/kernel/sys_ppc.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/i386/kernel/sys_i386.c" - * Adapted from the i386 version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au). - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/PPC - * platform. - * - * 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 - - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ -int -sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - ret = -ENOSYS; - switch (call) { - case SEMOP: - ret = sys_semtimedop (first, (struct sembuf __user *)ptr, - second, NULL); - break; - case SEMTIMEDOP: - ret = sys_semtimedop (first, (struct sembuf __user *)ptr, - second, (const struct timespec __user *) fifth); - break; - case SEMGET: - ret = sys_semget (first, second, third); - break; - case SEMCTL: { - union semun fourth; - - if (!ptr) - break; - if ((ret = access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT) - || (ret = get_user(fourth.__pad, (void __user *__user *)ptr))) - break; - ret = sys_semctl (first, second, third, fourth); - break; - } - case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third); - break; - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - - if (!ptr) - break; - if ((ret = access_ok(VERIFY_READ, ptr, sizeof(tmp)) ? 0 : -EFAULT) - || (ret = copy_from_user(&tmp, - (struct ipc_kludge __user *) ptr, - sizeof (tmp)) ? -EFAULT : 0)) - break; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, - third); - break; - } - default: - ret = sys_msgrcv (first, (struct msgbuf __user *) ptr, - second, fifth, third); - break; - } - break; - case MSGGET: - ret = sys_msgget ((key_t) first, second); - break; - case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds __user *) ptr); - break; - case SHMAT: { - ulong raddr; - - if ((ret = access_ok(VERIFY_WRITE, (ulong __user *) third, - sizeof(ulong)) ? 0 : -EFAULT)) - break; - ret = do_shmat (first, (char __user *) ptr, second, &raddr); - if (ret) - break; - ret = put_user (raddr, (ulong __user *) third); - break; - } - case SHMDT: - ret = sys_shmdt ((char __user *)ptr); - break; - case SHMGET: - ret = sys_shmget (first, second, third); - break; - case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds __user *) ptr); - break; - } - - return ret; -} - -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -int sys_pipe(int __user *fildes) -{ - int fd[2]; - int error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) - error = -EFAULT; - } - return error; -} - -static inline unsigned long -do_mmap2(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - struct file * file = NULL; - int ret = -EBADF; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fget(fd))) - goto out; - } - - down_write(¤t->mm->mmap_sem); - ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); -out: - return ret; -} - -unsigned long sys_mmap2(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) -{ - int err = -EINVAL; - - if (offset & ~PAGE_MASK) - goto out; - - err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -out: - return err; -} - -/* - * Due to some executables calling the wrong select we sometimes - * get wrong args. This determines how the args are being passed - * (a single ptr to them all args passed) then calls - * sys_select() with the appropriate args. -- Cort - */ -int -ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) -{ - if ( (unsigned long)n >= 4096 ) - { - unsigned long __user *buffer = (unsigned long __user *)n; - if (!access_ok(VERIFY_READ, buffer, 5*sizeof(unsigned long)) - || __get_user(n, buffer) - || __get_user(inp, ((fd_set __user * __user *)(buffer+1))) - || __get_user(outp, ((fd_set __user * __user *)(buffer+2))) - || __get_user(exp, ((fd_set __user * __user *)(buffer+3))) - || __get_user(tvp, ((struct timeval __user * __user *)(buffer+4)))) - return -EFAULT; - } - return sys_select(n, inp, outp, exp, tvp); -} - -int sys_uname(struct old_utsname __user * name) -{ - int err = -EFAULT; - - down_read(&uts_sem); - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) - err = 0; - up_read(&uts_sem); - return err; -} - -int sys_olduname(struct oldold_utsname __user * name) -{ - int error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error = __put_user(0,name->machine+__OLD_UTS_LEN); - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - return error; -} - -/* - * We put the arguments in a different order so we only use 6 - * registers for arguments, rather than 7 as sys_fadvise64_64 needs - * (because `offset' goes in r5/r6). - */ -long ppc_fadvise64_64(int fd, int advice, loff_t offset, loff_t len) -{ - return sys_fadvise64_64(fd, offset, len, advice); -} diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index b1203b79edf0..0be7c7ecefdf 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -12,9 +12,9 @@ obj-y := setup.o entry.o misc.o prom.o endif obj-y += irq.o idle.o dma.o \ - time.o signal.o syscalls.o \ + time.o signal.o \ align.o bitops.o pacaData.o \ - udbg.o sys_ppc32.o ioctl32.o \ + udbg.o ioctl32.o \ ptrace32.o signal32.o rtc.o \ cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index f9f2131d2fb5..eb407c429bb0 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -980,7 +980,7 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall /* old mpx syscall */ .llong .sys32_setpgid .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys32_olduname + .llong .sys_olduname .llong .sys32_umask /* 60 */ .llong .sys_chroot .llong .sys_ustat @@ -1030,7 +1030,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_newstat .llong .compat_sys_newlstat .llong .compat_sys_newfstat - .llong .sys32_uname + .llong .sys_uname .llong .sys_ni_syscall /* 110 old iopl syscall */ .llong .sys_vhangup .llong .sys_ni_syscall /* old idle syscall */ @@ -1043,7 +1043,7 @@ _GLOBAL(sys_call_table32) .llong .ppc32_sigreturn .llong .ppc_clone /* 120 */ .llong .sys32_setdomainname - .llong .ppc64_newuname + .llong .ppc_newuname .llong .sys_ni_syscall /* old modify_ldt syscall */ .llong .sys32_adjtimex .llong .sys_mprotect /* 125 */ @@ -1324,7 +1324,7 @@ _GLOBAL(sys_call_table) .llong .sys_ni_syscall .llong .ppc_clone /* 120 */ .llong .sys_setdomainname - .llong .ppc64_newuname + .llong .ppc_newuname .llong .sys_ni_syscall /* old modify_ldt syscall */ .llong .sys_adjtimex .llong .sys_mprotect /* 125 */ From 3e63b9ec51eb1d9f441e5015427b23d70e5991b3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 20:11:03 +1000 Subject: [PATCH 0397/1939] ppc: Use the merged of_device.c from arch/powerpc/kernel Signed-off-by: Paul Mackerras --- arch/ppc/syslib/Makefile | 2 +- arch/ppc/syslib/of_device.c | 276 ------------------------------------ 2 files changed, 1 insertion(+), 277 deletions(-) delete mode 100644 arch/ppc/syslib/of_device.c diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index b8d08f33f7ee..f6a2f1938bfa 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif -obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o +obj-$(CONFIG_PPC_OF) += prom_init.o prom.o obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o obj-$(CONFIG_POWER4) += open_pic2.o obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c deleted file mode 100644 index 93c7231ea709..000000000000 --- a/arch/ppc/syslib/of_device.c +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * of_match_device - Tell if an of_device structure has a matching - * of_match structure - * @ids: array of of device match structures to search in - * @dev: the of device structure to match against - * - * Used by a driver to check whether an of_device present in the - * system is in its list of supported devices. - */ -const struct of_device_id * of_match_device(const struct of_device_id *matches, - const struct of_device *dev) -{ - if (!dev->node) - return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= dev->node->name - && !strcmp(matches->name, dev->node->name); - if (matches->type[0]) - match &= dev->node->type - && !strcmp(matches->type, dev->node->type); - if (matches->compatible[0]) - match &= device_is_compatible(dev->node, - matches->compatible); - if (match) - return matches; - matches++; - } - return NULL; -} - -static int of_platform_bus_match(struct device *dev, struct device_driver *drv) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_device_id * matches = of_drv->match_table; - - if (!matches) - return 0; - - return of_match_device(matches, of_dev) != NULL; -} - -struct of_device *of_dev_get(struct of_device *dev) -{ - struct device *tmp; - - if (!dev) - return NULL; - tmp = get_device(&dev->dev); - if (tmp) - return to_of_device(tmp); - else - return NULL; -} - -void of_dev_put(struct of_device *dev) -{ - if (dev) - put_device(&dev->dev); -} - - -static int of_device_probe(struct device *dev) -{ - int error = -ENODEV; - struct of_platform_driver *drv; - struct of_device *of_dev; - const struct of_device_id *match; - - drv = to_of_platform_driver(dev->driver); - of_dev = to_of_device(dev); - - if (!drv->probe) - return error; - - of_dev_get(of_dev); - - match = of_match_device(drv->match_table, of_dev); - if (match) - error = drv->probe(of_dev, match); - if (error) - of_dev_put(of_dev); - - return error; -} - -static int of_device_remove(struct device *dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - - if (dev->driver && drv->remove) - drv->remove(of_dev); - return 0; -} - -static int of_device_suspend(struct device *dev, pm_message_t state) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->suspend) - error = drv->suspend(of_dev, state); - return error; -} - -static int of_device_resume(struct device * dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->resume) - error = drv->resume(of_dev); - return error; -} - -struct bus_type of_platform_bus_type = { - .name = "of_platform", - .match = of_platform_bus_match, - .suspend = of_device_suspend, - .resume = of_device_resume, -}; - -static int __init of_bus_driver_init(void) -{ - return bus_register(&of_platform_bus_type); -} - -postcore_initcall(of_bus_driver_init); - -int of_register_driver(struct of_platform_driver *drv) -{ - int count = 0; - - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &of_platform_bus_type; - drv->driver.probe = of_device_probe; - drv->driver.remove = of_device_remove; - - /* register with core */ - count = driver_register(&drv->driver); - return count ? count : 1; -} - -void of_unregister_driver(struct of_platform_driver *drv) -{ - driver_unregister(&drv->driver); -} - - -static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - return sprintf(buf, "%s", ofdev->node->full_name); -} - -static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); - -/** - * of_release_dev - free an of device structure when all users of it are finished. - * @dev: device that's been disconnected - * - * Will be called only by the device core when all users of this of device are - * done. - */ -void of_release_dev(struct device *dev) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - of_node_put(ofdev->node); - kfree(ofdev); -} - -int of_device_register(struct of_device *ofdev) -{ - int rc; - struct of_device **odprop; - - BUG_ON(ofdev->node == NULL); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (!odprop) { - struct property *new_prop; - - new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *), - GFP_KERNEL); - if (new_prop == NULL) - return -ENOMEM; - new_prop->name = "linux,device"; - new_prop->length = sizeof(sizeof(struct of_device *)); - new_prop->value = (unsigned char *)&new_prop[1]; - odprop = (struct of_device **)new_prop->value; - *odprop = NULL; - prom_add_property(ofdev->node, new_prop); - } - *odprop = ofdev; - - rc = device_register(&ofdev->dev); - if (rc) - return rc; - - device_create_file(&ofdev->dev, &dev_attr_devspec); - - return 0; -} - -void of_device_unregister(struct of_device *ofdev) -{ - struct of_device **odprop; - - device_remove_file(&ofdev->dev, &dev_attr_devspec); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (odprop) - *odprop = NULL; - - device_unregister(&ofdev->dev); -} - -struct of_device* of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - u32 *reg; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, sizeof(*dev)); - - dev->node = of_node_get(np); - dev->dma_mask = 0xffffffffUL; - dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = parent; - dev->dev.bus = &of_platform_bus_type; - dev->dev.release = of_release_dev; - - reg = (u32 *)get_property(np, "reg", NULL); - strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); - - if (of_device_register(dev) != 0) { - kfree(dev); - return NULL; - } - - return dev; -} - -EXPORT_SYMBOL(of_match_device); -EXPORT_SYMBOL(of_platform_bus_type); -EXPORT_SYMBOL(of_register_driver); -EXPORT_SYMBOL(of_unregister_driver); -EXPORT_SYMBOL(of_device_register); -EXPORT_SYMBOL(of_device_unregister); -EXPORT_SYMBOL(of_dev_get); -EXPORT_SYMBOL(of_dev_put); -EXPORT_SYMBOL(of_platform_device_create); -EXPORT_SYMBOL(of_release_dev); From 7ac59c624992281ff315911dea2a98ca3f3ff06e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 20:12:39 +1000 Subject: [PATCH 0398/1939] ppc: Fix various compile errors resulting from ptrace.c merge This introduces flush_{fp,altivec,spe}_to_thread and fixes a branch-too-far error in linking. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/entry.S | 3 +- arch/ppc/kernel/process.c | 136 +++++++++++++++++++++++++++----------- include/asm-ppc/system.h | 18 +++++ 3 files changed, 118 insertions(+), 39 deletions(-) diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 03d4886869f3..68fc61221776 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -633,7 +633,8 @@ sigreturn_exit: rlwinm r12,r1,0,0,18 /* current_thread_info() */ lwz r9,TI_FLAGS(r12) andi. r0,r9,_TIF_SYSCALL_T_OR_A - bnel- do_syscall_trace_leave + beq+ ret_from_except_full + bl do_syscall_trace_leave /* fall through */ .globl ret_from_except_full diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 0870e5553453..6d60c40598e7 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -152,18 +152,66 @@ int check_stack(struct task_struct *tsk) } #endif /* defined(CHECK_STACK) */ -#ifdef CONFIG_ALTIVEC -int -dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) +/* + * Make sure the floating-point register state in the + * the thread_struct is up to date for task tsk. + */ +void flush_fp_to_thread(struct task_struct *tsk) { - if (regs->msr & MSR_VEC) - giveup_altivec(current); - memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); + if (tsk->thread.regs) { + /* + * We need to disable preemption here because if we didn't, + * another process could get scheduled after the regs->msr + * test but before we have finished saving the FP registers + * to the thread_struct. That process could take over the + * FPU, and then when we get scheduled again we would store + * bogus values for the remaining FP registers. + */ + preempt_disable(); + if (tsk->thread.regs->msr & MSR_FP) { +#ifdef CONFIG_SMP + /* + * This should only ever be called for current or + * for a stopped child process. Since we save away + * the FP register state on context switch on SMP, + * there is something wrong if a stopped child appears + * to still have its FP state in the CPU registers. + */ + BUG_ON(tsk != current); +#endif + giveup_fpu(current); + } + preempt_enable(); + } +} + +void enable_kernel_fp(void) +{ + WARN_ON(preemptible()); + +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) + giveup_fpu(current); + else + giveup_fpu(NULL); /* just enables FP for kernel */ +#else + giveup_fpu(last_task_used_math); +#endif /* CONFIG_SMP */ +} +EXPORT_SYMBOL(enable_kernel_fp); + +int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + preempt_disable(); + if (tsk->thread.regs && (tsk->thread.regs->msr & MSR_FP)) + giveup_fpu(tsk); + preempt_enable(); + memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); return 1; } -void -enable_kernel_altivec(void) +#ifdef CONFIG_ALTIVEC +void enable_kernel_altivec(void) { WARN_ON(preemptible()); @@ -177,19 +225,35 @@ enable_kernel_altivec(void) #endif /* __SMP __ */ } EXPORT_SYMBOL(enable_kernel_altivec); + +/* + * Make sure the VMX/Altivec register state in the + * the thread_struct is up to date for task tsk. + */ +void flush_altivec_to_thread(struct task_struct *tsk) +{ + if (tsk->thread.regs) { + preempt_disable(); + if (tsk->thread.regs->msr & MSR_VEC) { +#ifdef CONFIG_SMP + BUG_ON(tsk != current); +#endif + giveup_altivec(current); + } + preempt_enable(); + } +} + +int dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) +{ + if (regs->msr & MSR_VEC) + giveup_altivec(current); + memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); + return 1; +} #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE -int -dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) -{ - if (regs->msr & MSR_SPE) - giveup_spe(current); - /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ - memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); - return 1; -} - void enable_kernel_spe(void) { @@ -205,34 +269,30 @@ enable_kernel_spe(void) #endif /* __SMP __ */ } EXPORT_SYMBOL(enable_kernel_spe); -#endif /* CONFIG_SPE */ -void -enable_kernel_fp(void) +void flush_spe_to_thread(struct task_struct *tsk) { - WARN_ON(preemptible()); - + if (tsk->thread.regs) { + preempt_disable(); + if (tsk->thread.regs->msr & MSR_SPE) { #ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); - else - giveup_fpu(NULL); /* just enables FP for kernel */ -#else - giveup_fpu(last_task_used_math); -#endif /* CONFIG_SMP */ + BUG_ON(tsk != current); +#endif + giveup_spe(current); + } + preempt_enable(); + } } -EXPORT_SYMBOL(enable_kernel_fp); -int -dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) { - preempt_disable(); - if (tsk->thread.regs && (tsk->thread.regs->msr & MSR_FP)) - giveup_fpu(tsk); - preempt_enable(); - memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); + if (regs->msr & MSR_SPE) + giveup_spe(current); + /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ + memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); return 1; } +#endif /* CONFIG_SPE */ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index af93ff04c53f..1f310783757e 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -74,6 +74,7 @@ extern void read_rtc_time(void); extern void pmac_find_display(void); extern void giveup_fpu(struct task_struct *); extern void enable_kernel_fp(void); +extern void flush_fp_to_thread(struct task_struct *); extern void enable_kernel_altivec(void); extern void giveup_altivec(struct task_struct *); extern void load_up_altivec(struct task_struct *); @@ -83,6 +84,23 @@ extern void load_up_spe(struct task_struct *); extern int fix_alignment(struct pt_regs *); extern void cvt_fd(float *from, double *to, unsigned long *fpscr); extern void cvt_df(double *from, float *to, unsigned long *fpscr); + +#ifdef CONFIG_ALTIVEC +extern void flush_altivec_to_thread(struct task_struct *); +#else +static inline void flush_altivec_to_thread(struct task_struct *t) +{ +} +#endif + +#ifdef CONFIG_SPE +extern void flush_spe_to_thread(struct task_struct *); +#else +static inline void flush_spe_to_thread(struct task_struct *t) +{ +} +#endif + extern int call_rtas(const char *, int, int, unsigned long *, ...); extern void cacheable_memzero(void *p, unsigned int nb); extern void *cacheable_memcpy(void *, const void *, unsigned int); From dd184343b45e94fd3b0d4d0865070924bc6195ab Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 20:13:47 +1000 Subject: [PATCH 0399/1939] powerpc: Clear the BSS at the start of early_init with ARCH=ppc Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index e68f848f24bf..b95f7cf693e6 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -294,6 +294,10 @@ unsigned long __init early_init(unsigned long dt_ptr) { unsigned long offset = reloc_offset(); + /* First zero the BSS -- use memset_io, some platforms don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); + /* * Identify the CPU type and fix up code sections * that depend on which cpu we have. From 5f2967553394d01f4bafd03398777a42e8344d28 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Oct 2005 20:14:59 +1000 Subject: [PATCH 0400/1939] powerpc: Make CONFIG_PROC_DEVICETREE independent of CONFIG_PPC_OF ... since all platforms will have a device tree. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index cd55c9b0f7ea..e70f7049cc6f 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -569,12 +569,12 @@ config SCHED_SMT overhead in some places. If unsure say N here. config PROC_DEVICETREE - bool "Support for Open Firmware device tree in /proc" - depends on (PPC_OF || PPC_ISERIES) && PROC_FS + bool "Support for device tree in /proc" + depends on PROC_FS help This option adds a device-tree directory under /proc which contains an image of the device tree that the kernel copies from Open - Firmware. If unsure, say Y here. + Firmware or other boot firmware. If unsure, say Y here. source "arch/powerpc/platforms/prep/Kconfig" From ea703ce20699dd85ad7954e34b71a2c7c47b6132 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 11 Oct 2005 23:54:00 -0500 Subject: [PATCH 0401/1939] [PATCH] powerpc: replace use of _GLOBAL with .globl The _GLOBAL() macro is for text symbols only. Changed to using .globl for .data symbols. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_44x.S | 18 +++++++++++------- arch/powerpc/kernel/head_4xx.S | 16 +++++++++++----- arch/powerpc/kernel/head_fsl_booke.S | 17 +++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index b1b9dc08abca..8b49679fad54 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -743,14 +743,18 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 /* * To support >32-bit physical addresses, we use an 8KB pgdir. */ -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 8192 /* Reserved 4k for the critical exception stack & 4k for the machine @@ -759,13 +763,15 @@ _GLOBAL(swapper_pg_dir) .align 12 exception_stack_bottom: .space BOOKE_EXCEPTION_STACK_SIZE -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* * This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* @@ -774,5 +780,3 @@ _GLOBAL(cmd_line) */ abatron_pteptrs: .space 8 - - diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S index 5772ce97e24e..10c261c67021 100644 --- a/arch/powerpc/kernel/head_4xx.S +++ b/arch/powerpc/kernel/head_4xx.S @@ -988,10 +988,14 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 4096 @@ -1001,12 +1005,14 @@ _GLOBAL(swapper_pg_dir) exception_stack_bottom: .space 4096 critical_stack_top: -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* Room for two PTE pointers, usually the kernel and current user pointers diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 53949811efda..5063c603fad4 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -1028,10 +1028,14 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 4096 /* Reserved 4k for the critical exception stack & 4k for the machine @@ -1040,13 +1044,15 @@ _GLOBAL(swapper_pg_dir) .align 12 exception_stack_bottom: .space BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* * This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* @@ -1055,4 +1061,3 @@ _GLOBAL(cmd_line) */ abatron_pteptrs: .space 8 - From 61f684ec074f40e2e13e750513df42c0c046689b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Oct 2005 14:28:58 +1000 Subject: [PATCH 0402/1939] [PATCH] powerpc: Fix use of LOADBASE in merge tree The merge-tree version of LOADBASE actually loads the whole given address from the toc for ppc64. The matching OFF macro adjust for this, using an offset of 0 for ppc64, but we weren't using that in power4_idle. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/idle_power4.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index 5596fad6c87c..1494e2f177f7 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -39,13 +39,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) * can be cleared by CPU init after the fixups are done */ LOADBASE(r3,cur_cpu_spec) - ld r4,cur_cpu_spec@l(r3) + ld r4,OFF(cur_cpu_spec)(r3) ld r4,CPU_SPEC_FEATURES(r4) andi. r0,r4,CPU_FTR_CAN_NAP beqlr /* Now check if user or arch enabled NAP mode */ LOADBASE(r3,powersave_nap) - lwz r4,powersave_nap@l(r3) + lwz r4,OFF(powersave_nap)(r3) cmpwi 0,r4,0 beqlr From 55d363397f1bdfa4fe861f0e2fadb058c79dafea Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Oct 2005 15:46:22 +1000 Subject: [PATCH 0403/1939] [PATCH] powerpc: Another maple merge tree fix With ARCH=powerpc, a spurious ifdef in prom_init prevented the seconday hold loop being correctly copied down on Maple. With this patch, Maple boots with ARCH=powerpc Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index d9130c839039..9b1baaa9eda0 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1955,13 +1955,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, prom_send_capabilities(); #endif -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_BPA) /* * On pSeries and BPA, copy the CPU hold code */ - if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) + if (RELOC(of_platform) != PLATFORM_POWERMAC) copy_and_flush(0, KERNELBASE + offset, 0x100, 0); -#endif /* * Do early parsing of command line From f4fd20bf31376f29e4edde6596e3972198877309 Mon Sep 17 00:00:00 2001 From: Karl Magnus Kolstoe Date: Mon, 17 Oct 2005 10:05:42 +0200 Subject: [PATCH 0404/1939] [SCSI] 2.6.13.3; add Pioneer DRM-624x to drivers/scsi/scsi_devinfo.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch below should make the Pioneer DRM-624X automatically be set up with all 6 "drives". (6 slot SCSI CD changer) Signed-off-by: Karl Magnus Kolstø Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 64fc9e21f35b..e69477d1889b 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -185,6 +185,7 @@ static struct { {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */ From 16192896ea8e03d18d4228023500607b00df49e6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Oct 2005 15:40:52 +0200 Subject: [PATCH 0405/1939] [SCSI] mptsas: fix phy identifiers This patch from Eric fixes handling of the phy identifiers in mptsas. I've split it up from his bigger patch as it should go into 2.6.14 still. Signed-off-by: Eric Moore Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 429820e48c69..7de19a84dc74 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -257,8 +257,8 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); printk("Target ID=0x%X\n", pg0->TargetID); printk("Bus=0x%X\n", pg0->Bus); - printk("PhyNum=0x%X\n", pg0->PhyNum); - printk("AccessStatus=0x%X\n", le16_to_cpu(pg0->AccessStatus)); + printk("Parent Phy Num=0x%X\n", pg0->PhyNum); + printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)); printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)); printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags)); printk("Physical Port=0x%X\n", pg0->PhysicalPort); @@ -270,7 +270,7 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) printk("---- SAS EXPANDER PAGE 1 ------------\n"); printk("Physical Port=0x%X\n", pg1->PhysicalPort); - printk("PHY Identifier=0x%X\n", pg1->Phy); + printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier); printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate); printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate); printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate); @@ -604,7 +604,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, mptsas_print_expander_pg1(buffer); /* save config data */ - phy_info->phy_id = buffer->Phy; + phy_info->phy_id = buffer->PhyIdentifier; phy_info->port_id = buffer->PhysicalPort; phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; @@ -825,6 +825,8 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; handle = port_info->phy_info[i].identify.handle; if (port_info->phy_info[i].attached.handle) { @@ -881,6 +883,8 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].identify.handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; } if (port_info->phy_info[i].attached.handle) { From 0c33aeedb2cf99d877ad9adc7c3df07870f60293 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 26 Sep 2005 11:47:53 -0700 Subject: [PATCH 0406/1939] [IB] Add checks to multicast attach and detach Add checks so that we only allow multicast attach/detach with a valid multicast GID and the correct QP type. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/core/verbs.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 5081d903e561..72d3ef786db5 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -523,16 +523,22 @@ EXPORT_SYMBOL(ib_dealloc_fmr); int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) { - return qp->device->attach_mcast ? - qp->device->attach_mcast(qp, gid, lid) : - -ENOSYS; + if (!qp->device->attach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + + return qp->device->attach_mcast(qp, gid, lid); } EXPORT_SYMBOL(ib_attach_mcast); int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) { - return qp->device->detach_mcast ? - qp->device->detach_mcast(qp, gid, lid) : - -ENOSYS; + if (!qp->device->detach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + + return qp->device->detach_mcast(qp, gid, lid); } EXPORT_SYMBOL(ib_detach_mcast); From 33033b797225553e48ca68d8d8dc5e64ec22e02b Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 26 Sep 2005 12:30:02 -0700 Subject: [PATCH 0407/1939] [IB] mthca: Report correct atomic capability Return correct atomic capability flag from mthca query function. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_dev.h | 1 + drivers/infiniband/hw/mthca/mthca_main.c | 1 + drivers/infiniband/hw/mthca/mthca_provider.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 7bff5a8425f4..67a2f324a274 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -148,6 +148,7 @@ struct mthca_limits { int reserved_mcgs; int num_pds; int reserved_pds; + u32 flags; u8 port_width_cap; }; diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 23a3f56c7899..576e7fcd053c 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -172,6 +172,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.reserved_uars = dev_lim->reserved_uars; mdev->limits.reserved_pds = dev_lim->reserved_pds; mdev->limits.port_width_cap = dev_lim->max_port_width; + mdev->limits.flags = dev_lim->flags; /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. May be doable since hardware supports it for SRQ. diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 3f5319a46577..141509dced7e 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -99,6 +99,8 @@ static int mthca_query_device(struct ib_device *ibdev, props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; props->max_qp_init_rd_atom = 1 << mdev->qp_table.rdb_shift; props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; + props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; err = 0; out: From 6b73597e7062118c0549c2702bfb7d273518c906 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 26 Sep 2005 13:53:25 -0700 Subject: [PATCH 0408/1939] [IB] uverbs: ABI-breaking fixes for userspace verbs Introduce new userspace verbs ABI version 3. This eliminates some unneeded commands, and adds support for user-created completion channels. This cleans up problems with file leaks on error paths, and also makes sure that file descriptors are always installed into the correct process. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 18 +- drivers/infiniband/core/uverbs_cmd.c | 188 ++++++++--------- drivers/infiniband/core/uverbs_main.c | 290 +++++++++++++------------- include/rdma/ib_user_verbs.h | 58 ++---- 4 files changed, 258 insertions(+), 296 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index cc124344dd2c..475153e510a9 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -53,14 +53,14 @@ struct ib_uverbs_device { struct cdev dev; struct class_device class_dev; struct ib_device *ib_dev; - int num_comp; + int num_comp_vectors; }; struct ib_uverbs_event_file { struct kref ref; + struct file *file; struct ib_uverbs_file *uverbs_file; spinlock_t lock; - int fd; int is_async; wait_queue_head_t poll_wait; struct fasync_struct *async_queue; @@ -73,8 +73,7 @@ struct ib_uverbs_file { struct ib_uverbs_device *device; struct ib_ucontext *ucontext; struct ib_event_handler event_handler; - struct ib_uverbs_event_file async_file; - struct ib_uverbs_event_file comp_file[1]; + struct ib_uverbs_event_file *async_file; }; struct ib_uverbs_event { @@ -110,10 +109,17 @@ extern struct idr ib_uverbs_cq_idr; extern struct idr ib_uverbs_qp_idr; extern struct idr ib_uverbs_srq_idr; +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd); +void ib_uverbs_release_event_file(struct kref *ref); +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); + void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event); int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, void *addr, size_t size, int write); @@ -125,16 +131,14 @@ void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem); const char __user *buf, int in_len, \ int out_len) -IB_UVERBS_DECLARE_CMD(query_params); IB_UVERBS_DECLARE_CMD(get_context); IB_UVERBS_DECLARE_CMD(query_device); IB_UVERBS_DECLARE_CMD(query_port); -IB_UVERBS_DECLARE_CMD(query_gid); -IB_UVERBS_DECLARE_CMD(query_pkey); IB_UVERBS_DECLARE_CMD(alloc_pd); IB_UVERBS_DECLARE_CMD(dealloc_pd); IB_UVERBS_DECLARE_CMD(reg_mr); IB_UVERBS_DECLARE_CMD(dereg_mr); +IB_UVERBS_DECLARE_CMD(create_comp_channel); IB_UVERBS_DECLARE_CMD(create_cq); IB_UVERBS_DECLARE_CMD(destroy_cq); IB_UVERBS_DECLARE_CMD(create_qp); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 562445165d2b..79b60c3dc8d0 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -33,6 +33,8 @@ * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $ */ +#include + #include #include "uverbs.h" @@ -45,29 +47,6 @@ (udata)->outlen = (olen); \ } while (0) -ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_params cmd; - struct ib_uverbs_query_params_resp resp; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - resp.num_cq_events = file->device->num_comp; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -77,7 +56,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, struct ib_udata udata; struct ib_device *ibdev = file->device->ib_dev; struct ib_ucontext *ucontext; - int i; + struct file *filp; int ret; if (out_len < sizeof resp) @@ -110,26 +89,42 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, INIT_LIST_HEAD(&ucontext->srq_list); INIT_LIST_HEAD(&ucontext->ah_list); - resp.async_fd = file->async_file.fd; - for (i = 0; i < file->device->num_comp; ++i) - if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab + - i * sizeof (__u32), - &file->comp_file[i].fd, sizeof (__u32))) { - ret = -EFAULT; - goto err_free; - } + resp.num_comp_vectors = file->device->num_comp_vectors; + + filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); + if (IS_ERR(filp)) { + ret = PTR_ERR(filp); + goto err_free; + } if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_free; + goto err_file; } - file->ucontext = ucontext; + file->async_file = filp->private_data; + + INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, + ib_uverbs_event_handler); + ret = ib_register_event_handler(&file->event_handler); + if (ret) + goto err_file; + + kref_get(&file->async_file->ref); + kref_get(&file->ref); + file->ucontext = ucontext; + + fd_install(resp.async_fd, filp); + up(&file->mutex); return in_len; +err_file: + put_unused_fd(resp.async_fd); + fput(filp); + err_free: ibdev->dealloc_ucontext(ucontext); @@ -255,62 +250,6 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, return in_len; } -ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_gid cmd; - struct ib_uverbs_query_gid_resp resp; - int ret; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index, - (union ib_gid *) resp.gid); - if (ret) - return ret; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, - &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - -ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_pkey cmd; - struct ib_uverbs_query_pkey_resp resp; - int ret; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index, - &resp.pkey); - if (ret) - return ret; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, - &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -595,6 +534,35 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, return ret ? ret : in_len; } +ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_comp_channel cmd; + struct ib_uverbs_create_comp_channel_resp resp; + struct file *filp; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); + if (IS_ERR(filp)) + return PTR_ERR(filp); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + put_unused_fd(resp.fd); + fput(filp); + return -EFAULT; + } + + fd_install(resp.fd, filp); + return in_len; +} + ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -603,6 +571,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, struct ib_uverbs_create_cq_resp resp; struct ib_udata udata; struct ib_ucq_object *uobj; + struct ib_uverbs_event_file *ev_file = NULL; struct ib_cq *cq; int ret; @@ -616,9 +585,12 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - if (cmd.event_handler >= file->device->num_comp) + if (cmd.comp_vector >= file->device->num_comp_vectors) return -EINVAL; + if (cmd.comp_channel >= 0) + ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; @@ -641,7 +613,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, cq->uobject = &uobj->uobject; cq->comp_handler = ib_uverbs_comp_handler; cq->event_handler = ib_uverbs_cq_event_handler; - cq->cq_context = file; + cq->cq_context = ev_file; atomic_set(&cq->usecnt, 0); retry: @@ -700,6 +672,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, struct ib_uverbs_destroy_cq_resp resp; struct ib_cq *cq; struct ib_ucq_object *uobj; + struct ib_uverbs_event_file *ev_file; struct ib_uverbs_event *evt, *tmp; u64 user_handle; int ret = -EINVAL; @@ -716,7 +689,8 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, goto out; user_handle = cq->uobject->user_handle; - uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + ev_file = cq->cq_context; ret = ib_destroy_cq(cq); if (ret) @@ -728,19 +702,23 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->comp_file[0].lock); - list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->comp_file[0].lock); + if (ev_file) { + spin_lock_irq(&ev_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&ev_file->lock); - spin_lock_irq(&file->async_file.lock); + kref_put(&ev_file->ref, ib_uverbs_release_event_file); + } + + spin_lock_irq(&file->async_file->lock); list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { list_del(&evt->list); kfree(evt); } - spin_unlock_irq(&file->async_file.lock); + spin_unlock_irq(&file->async_file->lock); resp.comp_events_reported = uobj->comp_events_reported; resp.async_events_reported = uobj->async_events_reported; @@ -1005,12 +983,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file.lock); + spin_lock_irq(&file->async_file->lock); list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { list_del(&evt->list); kfree(evt); } - spin_unlock_irq(&file->async_file.lock); + spin_unlock_irq(&file->async_file->lock); resp.events_reported = uobj->events_reported; @@ -1243,12 +1221,12 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file.lock); + spin_lock_irq(&file->async_file->lock); list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { list_del(&evt->list); kfree(evt); } - spin_unlock_irq(&file->async_file.lock); + spin_unlock_irq(&file->async_file->lock); resp.events_reported = uobj->events_reported; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 12511808de21..e7058fbc607d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -77,26 +77,24 @@ static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) = { - [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params, - [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, - [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, - [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, - [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid, - [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey, - [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, - [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, - [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, - [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, - [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, - [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, - [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, - [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, - [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, - [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, - [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, - [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, - [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, - [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, + [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, + [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, + [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, + [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, + [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, + [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, + [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, + [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, + [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, + [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, + [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, + [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, + [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, + [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, + [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, + [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, }; static struct vfsmount *uverbs_event_mnt; @@ -188,25 +186,19 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, spin_lock_irq(&file->lock); - while (list_empty(&file->event_list) && file->fd >= 0) { + while (list_empty(&file->event_list)) { spin_unlock_irq(&file->lock); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(file->poll_wait, - !list_empty(&file->event_list) || - file->fd < 0)) + !list_empty(&file->event_list))) return -ERESTARTSYS; spin_lock_irq(&file->lock); } - if (file->fd < 0) { - spin_unlock_irq(&file->lock); - return -ENODEV; - } - event = list_entry(file->event_list.next, struct ib_uverbs_event, list); if (file->is_async) @@ -248,26 +240,19 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, poll_wait(filp, &file->poll_wait, wait); spin_lock_irq(&file->lock); - if (file->fd < 0) - pollflags = POLLERR; - else if (!list_empty(&file->event_list)) + if (!list_empty(&file->event_list)) pollflags = POLLIN | POLLRDNORM; spin_unlock_irq(&file->lock); return pollflags; } -static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) +void ib_uverbs_release_event_file(struct kref *ref) { - struct ib_uverbs_event *entry, *tmp; + struct ib_uverbs_event_file *file = + container_of(ref, struct ib_uverbs_event_file, ref); - spin_lock_irq(&file->lock); - if (file->fd != -1) { - file->fd = -1; - list_for_each_entry_safe(entry, tmp, &file->event_list, list) - kfree(entry); - } - spin_unlock_irq(&file->lock); + kfree(file); } static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) @@ -280,21 +265,30 @@ static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) static int ib_uverbs_event_close(struct inode *inode, struct file *filp) { struct ib_uverbs_event_file *file = filp->private_data; + struct ib_uverbs_event *entry, *tmp; + + spin_lock_irq(&file->lock); + file->file = NULL; + list_for_each_entry_safe(entry, tmp, &file->event_list, list) { + if (entry->counter) + list_del(&entry->obj_list); + kfree(entry); + } + spin_unlock_irq(&file->lock); - ib_uverbs_event_release(file); ib_uverbs_event_fasync(-1, filp, 0); - kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + + if (file->is_async) { + ib_unregister_event_handler(&file->uverbs_file->event_handler); + kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + } + kref_put(&file->ref, ib_uverbs_release_event_file); return 0; } static struct file_operations uverbs_event_fops = { - /* - * No .owner field since we artificially create event files, - * so there is no increment to the module reference count in - * the open path. All event files come from a uverbs command - * file, which already takes a module reference, so this is OK. - */ + .owner = THIS_MODULE, .read = ib_uverbs_event_read, .poll = ib_uverbs_event_poll, .release = ib_uverbs_event_close, @@ -303,10 +297,19 @@ static struct file_operations uverbs_event_fops = { void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) { - struct ib_uverbs_file *file = cq_context; - struct ib_ucq_object *uobj; - struct ib_uverbs_event *entry; - unsigned long flags; + struct ib_uverbs_event_file *file = cq_context; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *entry; + unsigned long flags; + + if (!file) + return; + + spin_lock_irqsave(&file->lock, flags); + if (!file->file) { + spin_unlock_irqrestore(&file->lock, flags); + return; + } entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) @@ -317,13 +320,12 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) entry->desc.comp.cq_handle = cq->uobject->user_handle; entry->counter = &uobj->comp_events_reported; - spin_lock_irqsave(&file->comp_file[0].lock, flags); - list_add_tail(&entry->list, &file->comp_file[0].event_list); + list_add_tail(&entry->list, &file->event_list); list_add_tail(&entry->obj_list, &uobj->comp_list); - spin_unlock_irqrestore(&file->comp_file[0].lock, flags); + spin_unlock_irqrestore(&file->lock, flags); - wake_up_interruptible(&file->comp_file[0].poll_wait); - kill_fasync(&file->comp_file[0].async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&file->poll_wait); + kill_fasync(&file->async_queue, SIGIO, POLL_IN); } static void ib_uverbs_async_handler(struct ib_uverbs_file *file, @@ -334,6 +336,12 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, struct ib_uverbs_event *entry; unsigned long flags; + spin_lock_irqsave(&file->async_file->lock, flags); + if (!file->async_file->file) { + spin_unlock_irqrestore(&file->async_file->lock, flags); + return; + } + entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) return; @@ -342,24 +350,24 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, entry->desc.async.event_type = event; entry->counter = counter; - spin_lock_irqsave(&file->async_file.lock, flags); - list_add_tail(&entry->list, &file->async_file.event_list); + list_add_tail(&entry->list, &file->async_file->event_list); if (obj_list) list_add_tail(&entry->obj_list, obj_list); - spin_unlock_irqrestore(&file->async_file.lock, flags); + spin_unlock_irqrestore(&file->async_file->lock, flags); - wake_up_interruptible(&file->async_file.poll_wait); - kill_fasync(&file->async_file.async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&file->async_file->poll_wait); + kill_fasync(&file->async_file->async_queue, SIGIO, POLL_IN); } void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) { + struct ib_uverbs_event_file *ev_file = context_ptr; struct ib_ucq_object *uobj; uobj = container_of(event->element.cq->uobject, struct ib_ucq_object, uobject); - ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + ib_uverbs_async_handler(ev_file->uverbs_file, uobj->uobject.user_handle, event->event, &uobj->async_list, &uobj->async_events_reported); @@ -389,8 +397,8 @@ void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) &uobj->events_reported); } -static void ib_uverbs_event_handler(struct ib_event_handler *handler, - struct ib_event *event) +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event) { struct ib_uverbs_file *file = container_of(handler, struct ib_uverbs_file, event_handler); @@ -399,38 +407,90 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, NULL, NULL); } -static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, - struct ib_uverbs_file *uverbs_file) +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd) { + struct ib_uverbs_event_file *ev_file; struct file *filp; + int ret; - spin_lock_init(&file->lock); - INIT_LIST_HEAD(&file->event_list); - init_waitqueue_head(&file->poll_wait); - file->uverbs_file = uverbs_file; - file->async_queue = NULL; + ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); + if (!ev_file) + return ERR_PTR(-ENOMEM); - file->fd = get_unused_fd(); - if (file->fd < 0) - return file->fd; + kref_init(&ev_file->ref); + spin_lock_init(&ev_file->lock); + INIT_LIST_HEAD(&ev_file->event_list); + init_waitqueue_head(&ev_file->poll_wait); + ev_file->uverbs_file = uverbs_file; + ev_file->async_queue = NULL; + ev_file->is_async = is_async; + + *fd = get_unused_fd(); + if (*fd < 0) { + ret = *fd; + goto err; + } filp = get_empty_filp(); if (!filp) { - put_unused_fd(file->fd); - return -ENFILE; + ret = -ENFILE; + goto err_fd; } - filp->f_op = &uverbs_event_fops; + ev_file->file = filp; + + /* + * fops_get() can't fail here, because we're coming from a + * system call on a uverbs file, which will already have a + * module reference. + */ + filp->f_op = fops_get(&uverbs_event_fops); filp->f_vfsmnt = mntget(uverbs_event_mnt); filp->f_dentry = dget(uverbs_event_mnt->mnt_root); filp->f_mapping = filp->f_dentry->d_inode->i_mapping; filp->f_flags = O_RDONLY; filp->f_mode = FMODE_READ; - filp->private_data = file; + filp->private_data = ev_file; - fd_install(file->fd, filp); + return filp; - return 0; +err_fd: + put_unused_fd(*fd); + +err: + kfree(ev_file); + return ERR_PTR(ret); +} + +/* + * Look up a completion event file by FD. If lookup is successful, + * takes a ref to the event file struct that it returns; if + * unsuccessful, returns NULL. + */ +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd) +{ + struct ib_uverbs_event_file *ev_file = NULL; + struct file *filp; + + filp = fget(fd); + if (!filp) + return NULL; + + if (filp->f_op != &uverbs_event_fops) + goto out; + + ev_file = filp->private_data; + if (ev_file->is_async) { + ev_file = NULL; + goto out; + } + + kref_get(&ev_file->ref); + +out: + fput(filp); + return ev_file; } static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, @@ -453,8 +513,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, !uverbs_cmd_table[hdr.command]) return -EINVAL; - if (!file->ucontext && - hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS && + if (!file->ucontext && hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) return -EINVAL; @@ -477,82 +536,33 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) struct ib_uverbs_device *dev = container_of(inode->i_cdev, struct ib_uverbs_device, dev); struct ib_uverbs_file *file; - int i = 0; - int ret; if (!try_module_get(dev->ib_dev->owner)) return -ENODEV; - file = kmalloc(sizeof *file + - (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), - GFP_KERNEL); + file = kmalloc(sizeof *file, GFP_KERNEL); if (!file) { - ret = -ENOMEM; - goto err; + module_put(dev->ib_dev->owner); + return -ENOMEM; } - file->device = dev; + file->device = dev; + file->ucontext = NULL; kref_init(&file->ref); init_MUTEX(&file->mutex); - file->ucontext = NULL; - - kref_get(&file->ref); - ret = ib_uverbs_event_init(&file->async_file, file); - if (ret) - goto err_kref; - - file->async_file.is_async = 1; - - for (i = 0; i < dev->num_comp; ++i) { - kref_get(&file->ref); - ret = ib_uverbs_event_init(&file->comp_file[i], file); - if (ret) - goto err_async; - file->comp_file[i].is_async = 0; - } - - filp->private_data = file; - INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev, - ib_uverbs_event_handler); - if (ib_register_event_handler(&file->event_handler)) - goto err_async; - return 0; - -err_async: - while (i--) - ib_uverbs_event_release(&file->comp_file[i]); - - ib_uverbs_event_release(&file->async_file); - -err_kref: - /* - * One extra kref_put() because we took a reference before the - * event file creation that failed and got us here. - */ - kref_put(&file->ref, ib_uverbs_release_file); - kref_put(&file->ref, ib_uverbs_release_file); - -err: - module_put(dev->ib_dev->owner); - return ret; } static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; - int i; - ib_unregister_event_handler(&file->event_handler); - ib_uverbs_event_release(&file->async_file); ib_dealloc_ucontext(file->ucontext); - for (i = 0; i < file->device->num_comp; ++i) - ib_uverbs_event_release(&file->comp_file[i]); - + kref_put(&file->async_file->ref, ib_uverbs_release_event_file); kref_put(&file->ref, ib_uverbs_release_file); return 0; @@ -631,8 +641,8 @@ static void ib_uverbs_add_one(struct ib_device *device) set_bit(uverbs_dev->devnum, dev_map); spin_unlock(&map_lock); - uverbs_dev->ib_dev = device; - uverbs_dev->num_comp = 1; + uverbs_dev->ib_dev = device; + uverbs_dev->num_comp_vectors = 1; if (device->mmap) cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index fd85725391a4..0532b78200ca 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h @@ -42,15 +42,12 @@ * Increment this value if any changes that break userspace ABI * compatibility are made. */ -#define IB_USER_VERBS_ABI_VERSION 2 +#define IB_USER_VERBS_ABI_VERSION 3 enum { - IB_USER_VERBS_CMD_QUERY_PARAMS, IB_USER_VERBS_CMD_GET_CONTEXT, IB_USER_VERBS_CMD_QUERY_DEVICE, IB_USER_VERBS_CMD_QUERY_PORT, - IB_USER_VERBS_CMD_QUERY_GID, - IB_USER_VERBS_CMD_QUERY_PKEY, IB_USER_VERBS_CMD_ALLOC_PD, IB_USER_VERBS_CMD_DEALLOC_PD, IB_USER_VERBS_CMD_CREATE_AH, @@ -65,6 +62,7 @@ enum { IB_USER_VERBS_CMD_ALLOC_MW, IB_USER_VERBS_CMD_BIND_MW, IB_USER_VERBS_CMD_DEALLOC_MW, + IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL, IB_USER_VERBS_CMD_CREATE_CQ, IB_USER_VERBS_CMD_RESIZE_CQ, IB_USER_VERBS_CMD_DESTROY_CQ, @@ -118,27 +116,14 @@ struct ib_uverbs_cmd_hdr { __u16 out_words; }; -/* - * No driver_data for "query params" command, since this is intended - * to be a core function with no possible device dependence. - */ -struct ib_uverbs_query_params { - __u64 response; -}; - -struct ib_uverbs_query_params_resp { - __u32 num_cq_events; -}; - struct ib_uverbs_get_context { __u64 response; - __u64 cq_fd_tab; __u64 driver_data[0]; }; struct ib_uverbs_get_context_resp { __u32 async_fd; - __u32 reserved; + __u32 num_comp_vectors; }; struct ib_uverbs_query_device { @@ -220,31 +205,6 @@ struct ib_uverbs_query_port_resp { __u8 reserved[3]; }; -struct ib_uverbs_query_gid { - __u64 response; - __u8 port_num; - __u8 index; - __u8 reserved[6]; - __u64 driver_data[0]; -}; - -struct ib_uverbs_query_gid_resp { - __u8 gid[16]; -}; - -struct ib_uverbs_query_pkey { - __u64 response; - __u8 port_num; - __u8 index; - __u8 reserved[6]; - __u64 driver_data[0]; -}; - -struct ib_uverbs_query_pkey_resp { - __u16 pkey; - __u16 reserved; -}; - struct ib_uverbs_alloc_pd { __u64 response; __u64 driver_data[0]; @@ -278,11 +238,21 @@ struct ib_uverbs_dereg_mr { __u32 mr_handle; }; +struct ib_uverbs_create_comp_channel { + __u64 response; +}; + +struct ib_uverbs_create_comp_channel_resp { + __u32 fd; +}; + struct ib_uverbs_create_cq { __u64 response; __u64 user_handle; __u32 cqe; - __u32 event_handler; + __u32 comp_vector; + __s32 comp_channel; + __u32 reserved; __u64 driver_data[0]; }; From eb9d3cd5ce2828fbb99ed7270089ea152c8f64b3 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 27 Sep 2005 15:07:25 -0700 Subject: [PATCH 0409/1939] [IB] uverbs: Fix up resource creation error paths By waiting to add resources to our lists until after the last operation that can fail, we don't have to remove them from their lists in the error path. Also, we should hold the idr mutex until we know whether resource creation has succeed or failed, to avoid someone finding a resource in our table before we're ready. Loosely based on work by Robert Walsh . Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_cmd.c | 111 ++++++++++++--------------- 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 79b60c3dc8d0..a0ceb1cbed52 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -288,24 +289,20 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, pd->uobject = uobj; atomic_set(&pd->usecnt, 0); + down(&ib_uverbs_idr_mutex); + retry: if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) { ret = -ENOMEM; - goto err_pd; + goto err_up; } - down(&ib_uverbs_idr_mutex); ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id); - up(&ib_uverbs_idr_mutex); if (ret == -EAGAIN) goto retry; if (ret) - goto err_pd; - - down(&file->mutex); - list_add_tail(&uobj->list, &file->ucontext->pd_list); - up(&file->mutex); + goto err_up; memset(&resp, 0, sizeof resp); resp.pd_handle = uobj->id; @@ -313,21 +310,22 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->pd_list); + up(&file->mutex); + + up(&ib_uverbs_idr_mutex); + return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->list); - up(&file->mutex); - - down(&ib_uverbs_idr_mutex); +err_idr: idr_remove(&ib_uverbs_pd_idr, uobj->id); - up(&ib_uverbs_idr_mutex); -err_pd: +err_up: + up(&ib_uverbs_idr_mutex); ib_dealloc_pd(pd); err: @@ -463,24 +461,22 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, resp.mr_handle = obj->uobject.id; - down(&file->mutex); - list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&obj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_mr_idr, obj->uobject.id); err_unreg: ib_dereg_mr(mr); @@ -616,24 +612,20 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, cq->cq_context = ev_file; atomic_set(&cq->usecnt, 0); + down(&ib_uverbs_idr_mutex); + retry: if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) { ret = -ENOMEM; - goto err_cq; + goto err_up; } - down(&ib_uverbs_idr_mutex); ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); - up(&ib_uverbs_idr_mutex); if (ret == -EAGAIN) goto retry; if (ret) - goto err_cq; - - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); - up(&file->mutex); + goto err_up; memset(&resp, 0, sizeof resp); resp.cq_handle = uobj->uobject.id; @@ -642,21 +634,22 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); + up(&file->mutex); + + up(&ib_uverbs_idr_mutex); + return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); - up(&file->mutex); - - down(&ib_uverbs_idr_mutex); +err_idr: idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); - up(&ib_uverbs_idr_mutex); -err_cq: +err_up: + up(&ib_uverbs_idr_mutex); ib_destroy_cq(cq); err: @@ -837,24 +830,22 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, resp.qp_handle = uobj->uobject.id; - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_qp_idr, uobj->uobject.id); err_destroy: ib_destroy_qp(qp); @@ -1126,24 +1117,22 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, resp.srq_handle = uobj->uobject.id; - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id); err_destroy: ib_destroy_srq(srq); From 274c0891637c44ac71f3ac40be91b43c2318883a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 29 Sep 2005 14:17:48 -0700 Subject: [PATCH 0410/1939] [IB] uverbs: Add device-specific ABI version attribute Add abi_version attribute to uverbs class devices to allow for ABI versioning of device-specific interfaces. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 11 +++++++++++ drivers/infiniband/hw/mthca/mthca_provider.c | 1 + drivers/infiniband/hw/mthca/mthca_user.h | 6 ++++++ include/rdma/ib_verbs.h | 2 ++ 4 files changed, 20 insertions(+) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index e7058fbc607d..c84cc28b60ee 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -598,6 +598,15 @@ static ssize_t show_ibdev(struct class_device *class_dev, char *buf) } static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); +static ssize_t show_dev_abi_version(struct class_device *class_dev, char *buf) +{ + struct ib_uverbs_device *dev = + container_of(class_dev, struct ib_uverbs_device, class_dev); + + return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); +} +static CLASS_DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); + static void ib_uverbs_release_class_dev(struct class_device *class_dev) { struct ib_uverbs_device *dev = @@ -662,6 +671,8 @@ static void ib_uverbs_add_one(struct ib_device *device) if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) goto err_class; + if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_abi_version)) + goto err_class; ib_set_client_data(device, &uverbs_client, uverbs_dev); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 141509dced7e..939b09dcfe09 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1060,6 +1060,7 @@ int mthca_register_device(struct mthca_dev *dev) strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; + dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION; dev->ib_dev.node_type = IB_NODE_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; dev->ib_dev.dma_device = &dev->pdev->dev; diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h index 41613ec8a04e..bb015c6494c4 100644 --- a/drivers/infiniband/hw/mthca/mthca_user.h +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -37,6 +37,12 @@ #include +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define MTHCA_UVERBS_ABI_VERSION 1 + /* * Make sure that all structs defined in this file remain laid out so * that they pack the same way on 32-bit and 64-bit architectures (to diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e6f4c9e55df7..d13f25a78192 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -951,6 +951,8 @@ struct ib_device { IB_DEV_UNREGISTERED } reg_state; + int uverbs_abi_ver; + u8 node_type; u8 phys_port_cnt; }; From 9825051e8c81cbd4400333e7cdc04be77a0bab75 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 1 Oct 2005 13:09:44 -0700 Subject: [PATCH 0411/1939] [IB] mthca: Fill in more fields in query_port method Add code to fill in the bad_pkey_cntr, max_mtu, active_mtu and subnet_timeout fields in mthca_query_port(). Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_provider.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 939b09dcfe09..4e87ad115712 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -152,9 +152,13 @@ static int mthca_query_port(struct ib_device *ibdev, props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; props->max_msg_sz = 0x80000000; props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); props->active_width = out_mad->data[31] & 0xf; props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; out: kfree(in_mad); From f575394f1de9b4afa4b474f1882c7e2d3b8e51d7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 3 Oct 2005 09:18:02 -0700 Subject: [PATCH 0412/1939] [IB] uverbs: reject invalid memory registration permission flags Reject userspace memory registrations with invalid permission flags: "local write" is required if "remote write" or "remote atomic" is also requested. Pointed out by Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_cmd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a0ceb1cbed52..2e959acf2ff1 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -396,6 +396,14 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) return -EINVAL; + /* + * Local write permission is required if remote write or + * remote atomic permission is also requested. + */ + if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) && + !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) + return -EINVAL; + obj = kmalloc(sizeof *obj, GFP_KERNEL); if (!obj) return -ENOMEM; From 116c0074ecfd6f061570856bec52b691d54dbd3c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 3 Oct 2005 09:32:33 -0700 Subject: [PATCH 0413/1939] [IB] Check port number in ib_query_port()/ib_modify_port() Check port number before passing query_port or modify_port operations on to device driver. Signed-off-by: Roland Dreier --- drivers/infiniband/core/device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index d3cf84e01587..5a6e44976405 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -514,6 +514,12 @@ int ib_query_port(struct ib_device *device, u8 port_num, struct ib_port_attr *port_attr) { + if (device->node_type == IB_NODE_SWITCH) { + if (port_num) + return -EINVAL; + } else if (port_num < 1 || port_num > device->phys_port_cnt) + return -EINVAL; + return device->query_port(device, port_num, port_attr); } EXPORT_SYMBOL(ib_query_port); @@ -583,6 +589,12 @@ int ib_modify_port(struct ib_device *device, u8 port_num, int port_modify_mask, struct ib_port_modify *port_modify) { + if (device->node_type == IB_NODE_SWITCH) { + if (port_num) + return -EINVAL; + } else if (port_num < 1 || port_num > device->phys_port_cnt) + return -EINVAL; + return device->modify_port(device, port_num, port_modify_mask, port_modify); } From 90f104da22bbf2e2b8a2136c12fb4e013fccf504 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 6 Oct 2005 13:15:56 -0700 Subject: [PATCH 0414/1939] [IB] mthca: SRQ limit reached events Our hardware supports generating an event when the number of receives posted to a shared receive queue (SRQ) falls below a user-specified limit. Implement mthca_modify_srq() to arm the limit, and add code to handle dispatching SRQ events when they occur. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_dev.h | 2 ++ drivers/infiniband/hw/mthca/mthca_eq.c | 21 +++++++++++++--- drivers/infiniband/hw/mthca/mthca_provider.c | 1 + drivers/infiniband/hw/mthca/mthca_srq.c | 25 +++++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 67a2f324a274..6e18c128af42 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -448,6 +448,8 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, struct ib_srq_attr *attr, struct mthca_srq *srq); void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask); void mthca_srq_event(struct mthca_dev *dev, u32 srqn, enum ib_event_type event_type); void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr); diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index c81fa8e975ef..f2afdc6c7e60 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -83,7 +83,8 @@ enum { MTHCA_EVENT_TYPE_PATH_MIG = 0x01, MTHCA_EVENT_TYPE_COMM_EST = 0x02, MTHCA_EVENT_TYPE_SQ_DRAINED = 0x03, - MTHCA_EVENT_TYPE_SRQ_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_LIMIT = 0x14, MTHCA_EVENT_TYPE_CQ_ERROR = 0x04, MTHCA_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, MTHCA_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, @@ -110,8 +111,9 @@ enum { (1ULL << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR) | \ (1ULL << MTHCA_EVENT_TYPE_PORT_CHANGE) | \ (1ULL << MTHCA_EVENT_TYPE_ECC_DETECT)) -#define MTHCA_SRQ_EVENT_MASK (1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ - (1ULL << MTHCA_EVENT_TYPE_SRQ_LAST_WQE) +#define MTHCA_SRQ_EVENT_MASK ((1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_LIMIT)) #define MTHCA_CMD_EVENT_MASK (1ULL << MTHCA_EVENT_TYPE_CMD) #define MTHCA_EQ_DB_INC_CI (1 << 24) @@ -141,6 +143,9 @@ struct mthca_eqe { struct { __be32 qpn; } __attribute__((packed)) qp; + struct { + __be32 srqn; + } __attribute__((packed)) srq; struct { __be32 cqn; u32 reserved1; @@ -305,6 +310,16 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) IB_EVENT_SQ_DRAINED); break; + case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_LAST_WQE_REACHED); + break; + + case MTHCA_EVENT_TYPE_SRQ_LIMIT: + mthca_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, + IB_EVENT_SRQ_LIMIT_REACHED); + break; + case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR: mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, IB_EVENT_QP_FATAL); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 4e87ad115712..53b29a0841bf 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1084,6 +1084,7 @@ int mthca_register_device(struct mthca_dev *dev) if (dev->mthca_flags & MTHCA_FLAG_SRQ) { dev->ib_dev.create_srq = mthca_create_srq; + dev->ib_dev.modify_srq = mthca_modify_srq; dev->ib_dev.destroy_srq = mthca_destroy_srq; if (mthca_is_memfree(dev)) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 18998d48c53e..13d2290261d9 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -332,6 +332,29 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) mthca_free_mailbox(dev, mailbox); } +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + int ret; + u8 status; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & IB_SRQ_MAX_WR) + return -EINVAL; + + if (attr_mask & IB_SRQ_LIMIT) { + ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); + if (ret) + return ret; + if (status) + return -EINVAL; + } + + return 0; +} + void mthca_srq_event(struct mthca_dev *dev, u32 srqn, enum ib_event_type event_type) { @@ -354,7 +377,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, event.device = &dev->ib_dev; event.event = event_type; - event.element.srq = &srq->ibsrq; + event.element.srq = &srq->ibsrq; srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context); out: From e23d6d2b090658007732770720a44375cba23200 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 6 Oct 2005 13:25:16 -0700 Subject: [PATCH 0415/1939] [IB] mthca: detect SRQ overflow The hardware relies on us keeping one extra work request that never gets used in SRQs. Add checks to the SRQ work request posting functions so that they fail when someone is about to use up that extra work request, rather than when someone uses the very last work request. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_srq.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 13d2290261d9..e464321a7aa7 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -438,6 +438,14 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + prev_wqe = srq->last; srq->last = wqe; @@ -529,6 +537,13 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); + if (next_ind < 0) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + ((struct mthca_next_seg *) wqe)->nda_op = cpu_to_be32((next_ind << srq->wqe_shift) | 1); ((struct mthca_next_seg *) wqe)->ee_nds = 0; From 4ab6fb7e5b3d34b65a1c3473d80d9d1a462d3a49 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 6 Oct 2005 13:28:16 -0700 Subject: [PATCH 0416/1939] [IB] Fix leak on MAD initialization failure There is a bug in ib_mad_init_device(): if ib_agent_port_open() fails for a given port, then the current code doesn't call ib_mad_port_close() for that port. Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad.c | 45 ++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index a14ca87fda18..af302e830561 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2683,40 +2683,47 @@ static int ib_mad_port_close(struct ib_device *device, int port_num) static void ib_mad_init_device(struct ib_device *device) { - int num_ports, cur_port, i; + int start, end, i; if (device->node_type == IB_NODE_SWITCH) { - num_ports = 1; - cur_port = 0; + start = 0; + end = 0; } else { - num_ports = device->phys_port_cnt; - cur_port = 1; + start = 1; + end = device->phys_port_cnt; } - for (i = 0; i < num_ports; i++, cur_port++) { - if (ib_mad_port_open(device, cur_port)) { + + for (i = start; i <= end; i++) { + if (ib_mad_port_open(device, i)) { printk(KERN_ERR PFX "Couldn't open %s port %d\n", - device->name, cur_port); - goto error_device_open; + device->name, i); + goto error; } - if (ib_agent_port_open(device, cur_port)) { + if (ib_agent_port_open(device, i)) { printk(KERN_ERR PFX "Couldn't open %s port %d " "for agents\n", - device->name, cur_port); - goto error_device_open; + device->name, i); + goto error_agent; } } return; -error_device_open: - while (i > 0) { - cur_port--; - if (ib_agent_port_close(device, cur_port)) +error_agent: + if (ib_mad_port_close(device, i)) + printk(KERN_ERR PFX "Couldn't close %s port %d\n", + device->name, i); + +error: + i--; + + while (i >= start) { + if (ib_agent_port_close(device, i)) printk(KERN_ERR PFX "Couldn't close %s port %d " "for agents\n", - device->name, cur_port); - if (ib_mad_port_close(device, cur_port)) + device->name, i); + if (ib_mad_port_close(device, i)) printk(KERN_ERR PFX "Couldn't close %s port %d\n", - device->name, cur_port); + device->name, i); i--; } } From efaae8f71f3088cc73c9e5ceabbd314aa82ac768 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 10 Oct 2005 13:48:07 -0700 Subject: [PATCH 0417/1939] [IB] mthca: Better limit checking and reporting Check the sizes of CQs, QPs and SRQs when creating objects, and fail instead of creating too-big queues. Also return real limits instead of just plausible-sounding values from mthca_query_device(). Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cmd.c | 6 ++++-- drivers/infiniband/hw/mthca/mthca_dev.h | 6 ++++++ drivers/infiniband/hw/mthca/mthca_main.c | 9 +++++++++ drivers/infiniband/hw/mthca/mthca_mcg.c | 4 ---- drivers/infiniband/hw/mthca/mthca_provider.c | 18 +++++++++++++++--- drivers/infiniband/hw/mthca/mthca_qp.c | 6 ++++-- drivers/infiniband/hw/mthca/mthca_srq.c | 3 ++- 7 files changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f6a8ac026557..1bd7dc8f778c 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -933,9 +933,9 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, goto out; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); - dev_lim->max_srq_sz = 1 << field; + dev_lim->max_srq_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); - dev_lim->max_qp_sz = 1 << field; + dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); dev_lim->reserved_qps = 1 << (field & 0xf); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); @@ -1045,6 +1045,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, dev_lim->max_pds, dev_lim->reserved_pds, dev_lim->reserved_uars); mthca_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", dev_lim->max_pds, dev_lim->reserved_mgms); + mthca_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_lim->max_cq_sz, dev_lim->max_qp_sz, dev_lim->max_srq_sz); mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 6e18c128af42..f106bac0f925 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -83,6 +83,8 @@ enum { /* Arbel FW gives us these, but we need them for Tavor */ MTHCA_MPT_ENTRY_SIZE = 0x40, MTHCA_MTT_SEG_SIZE = 0x40, + + MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) }; enum { @@ -128,12 +130,16 @@ struct mthca_limits { int num_uars; int max_sg; int num_qps; + int max_wqes; + int max_qp_init_rdma; int reserved_qps; int num_srqs; + int max_srq_wqes; int reserved_srqs; int num_eecs; int reserved_eecs; int num_cqs; + int max_cqes; int reserved_cqs; int num_eqs; int reserved_eqs; diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 576e7fcd053c..7c35abec81ea 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -162,9 +162,18 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.pkey_table_len = dev_lim->max_pkeys; mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; mdev->limits.max_sg = dev_lim->max_sg; + mdev->limits.max_wqes = dev_lim->max_qp_sz; + mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; mdev->limits.reserved_qps = dev_lim->reserved_qps; + mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; mdev->limits.reserved_srqs = dev_lim->reserved_srqs; mdev->limits.reserved_eecs = dev_lim->reserved_eecs; + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; mdev->limits.reserved_cqs = dev_lim->reserved_cqs; mdev->limits.reserved_eqs = dev_lim->reserved_eqs; mdev->limits.reserved_mtts = dev_lim->reserved_mtts; diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index a2707605f4c8..9a0612a9d304 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -37,10 +37,6 @@ #include "mthca_dev.h" #include "mthca_cmd.h" -enum { - MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) -}; - struct mthca_mgm { __be32 next_gid_index; u32 reserved[3]; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 53b29a0841bf..46864d18827d 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -90,17 +90,26 @@ static int mthca_query_device(struct ib_device *ibdev, props->max_mr_size = ~0ull; props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; - props->max_qp_wr = 0xffff; + props->max_qp_wr = mdev->limits.max_wqes; props->max_sge = mdev->limits.max_sg; props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; - props->max_cqe = 0xffff; + props->max_cqe = mdev->limits.max_cqes; props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; - props->max_qp_init_rd_atom = 1 << mdev->qp_table.rdb_shift; + props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; + props->max_srq_wr = mdev->limits.max_srq_wqes; + props->max_srq_sge = mdev->limits.max_sg; props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? IB_ATOMIC_HCA : IB_ATOMIC_NONE; + props->max_pkeys = mdev->limits.pkey_table_len; + props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; + props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; err = 0; out: @@ -640,6 +649,9 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, int nent; int err; + if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) + return ERR_PTR(-EINVAL); + if (context) { if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) return ERR_PTR(-EFAULT); diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 5fa00669f9b8..2ee0a2b0fd4b 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1112,8 +1112,10 @@ static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, struct mthca_qp *qp) { /* Sanity check QP size before proceeding */ - if (cap->max_send_wr > 65536 || cap->max_recv_wr > 65536 || - cap->max_send_sge > 64 || cap->max_recv_sge > 64) + if (cap->max_send_wr > dev->limits.max_wqes || + cap->max_recv_wr > dev->limits.max_wqes || + cap->max_send_sge > dev->limits.max_sg || + cap->max_recv_sge > dev->limits.max_sg) return -EINVAL; if (mthca_is_memfree(dev)) { diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index e464321a7aa7..64f70aa1b3c0 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -186,7 +186,8 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, int err; /* Sanity check SRQ size before proceeding */ - if (attr->max_wr > 16 << 20 || attr->max_sge > 64) + if (attr->max_wr > dev->limits.max_srq_wqes || + attr->max_sge > dev->limits.max_sg) return -EINVAL; srq->max = attr->max_wr; From 5b6810e048435de508ef66aebd6b78db13d651b8 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 11 Oct 2005 11:08:24 -0700 Subject: [PATCH 0418/1939] [IPoIB] Rename ipoib_create_qp() -> ipoib_init_qp() and fix error cleanup ipoib_create_qp() no longer creates IPoIB's QP, so it shouldn't destroy the QP on failure -- that unwinding happens elsewhere, so the current code can cause a double free. While we're at it, the function's name should match what it actually does, so rename it to ipoib_init_qp(). Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 2 +- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 4 ++-- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 4ea1c1ca85bc..6b14bd1c60a0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -277,7 +277,7 @@ int ipoib_mcast_attach(struct net_device *dev, u16 mlid, int ipoib_mcast_detach(struct net_device *dev, u16 mlid, union ib_gid *mgid); -int ipoib_qp_create(struct net_device *dev); +int ipoib_init_qp(struct net_device *dev); int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca); void ipoib_transport_dev_cleanup(struct net_device *dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index f7440096b5ed..02d0e0006578 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -387,9 +387,9 @@ int ipoib_ib_dev_open(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; - ret = ipoib_qp_create(dev); + ret = ipoib_init_qp(dev); if (ret) { - ipoib_warn(priv, "ipoib_qp_create returned %d\n", ret); + ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret); return -1; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 79f59d0563ed..b5902a7ec240 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -92,7 +92,7 @@ int ipoib_mcast_detach(struct net_device *dev, u16 mlid, union ib_gid *mgid) return ret; } -int ipoib_qp_create(struct net_device *dev) +int ipoib_init_qp(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; @@ -149,10 +149,11 @@ int ipoib_qp_create(struct net_device *dev) return 0; out_fail: - ib_destroy_qp(priv->qp); - priv->qp = NULL; + qp_attr.qp_state = IB_QPS_RESET; + if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) + ipoib_warn(priv, "Failed to modify QP to RESET state\n"); - return -EINVAL; + return ret; } int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) From 305a7e87055dde2466a855c24ef51a606915d149 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 11 Oct 2005 15:39:38 -0700 Subject: [PATCH 0419/1939] [IB] uverbs: unlock correctly in error paths A couple of functions were missing spin_unlock calls in error paths. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index c84cc28b60ee..3a887006b253 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -312,8 +312,10 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) } entry = kmalloc(sizeof *entry, GFP_ATOMIC); - if (!entry) + if (!entry) { + spin_unlock_irqrestore(&file->lock, flags); return; + } uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); @@ -343,8 +345,10 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, } entry = kmalloc(sizeof *entry, GFP_ATOMIC); - if (!entry) + if (!entry) { + spin_unlock_irqrestore(&file->async_file->lock, flags); return; + } entry->desc.async.element = element; entry->desc.async.event_type = event; From 56c202d6e4f542468fe79b8a735cf128898b87fb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 13 Oct 2005 10:45:02 -0700 Subject: [PATCH 0420/1939] [IB] fail SA queries if device initialization failed If the SA query module's initialization fails for a device, then that device won't have a struct ib_sa_device associated. We should fail SA queries in that case, rather than blindly dereferencing the NULL pointer we get back from ib_get_client_data(). Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 262618210c1c..a2c4234ca8a3 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -583,10 +583,16 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, { struct ib_sa_path_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; @@ -685,10 +691,16 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, { struct ib_sa_service_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + if (method != IB_MGMT_METHOD_GET && method != IB_MGMT_METHOD_SET && method != IB_SA_METHOD_DELETE) @@ -768,10 +780,16 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, { struct ib_sa_mcmember_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; From 883a99c7024c5763d6d4f22d9239c133893e8d74 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 14 Oct 2005 14:00:58 -0700 Subject: [PATCH 0421/1939] [IB] uverbs: Add a mask of device methods allowed for userspace Give each device a uverbs_cmd_mask, so that a low-level driver can control which methods may be called on behalf of userspace. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 3 ++- drivers/infiniband/hw/mthca/mthca_provider.c | 20 ++++++++++++++++++++ include/rdma/ib_verbs.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 3a887006b253..6a5e5084db7a 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -514,7 +514,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[hdr.command]) + !uverbs_cmd_table[hdr.command] || + !(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) return -EINVAL; if (!file->ucontext && diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 46864d18827d..9e911a1ea415 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -37,6 +37,7 @@ */ #include +#include #include #include "mthca_dev.h" @@ -1077,6 +1078,25 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION; + dev->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); dev->ib_dev.node_type = IB_NODE_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; dev->ib_dev.dma_device = &dev->pdev->dev; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index d13f25a78192..a5a963cb5676 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -951,6 +951,7 @@ struct ib_device { IB_DEV_UNREGISTERED } reg_state; + u64 uverbs_cmd_mask; int uverbs_abi_ver; u8 node_type; From 91ecd4ae178bed83da4f6a94ced7992e4d7711eb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 14 Oct 2005 15:21:44 -0700 Subject: [PATCH 0422/1939] [IB] uverbs: Add ABI structures for more commands Add kernel/user ABI structures for marshalling poll CQ, request CQ notification, post send, post receive, post SRQ receive, create AH and destroy AH commands. These commands allow us to support userspace verbs for devices that can't perform these operations directly from userspace (eg the PathScale HCA). Signed-off-by: Roland Dreier --- include/rdma/ib_user_verbs.h | 164 ++++++++++++++++++++++++++++++++++- 1 file changed, 162 insertions(+), 2 deletions(-) diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 0532b78200ca..072f3a2edace 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -88,8 +89,11 @@ enum { * Make sure that all structs defined in this file remain laid out so * that they pack the same way on 32-bit and 64-bit architectures (to * avoid incompatibility between 32-bit userspace and 64-bit kernels). - * In particular do not use pointer types -- pass pointers in __u64 - * instead. + * Specifically: + * - Do not use pointer types -- pass pointers in __u64 instead. + * - Make sure that any structure larger than 4 bytes is padded to a + * multiple of 8 bytes. Otherwise the structure size will be + * different between 32-bit and 64-bit architectures. */ struct ib_uverbs_async_event_desc { @@ -261,6 +265,41 @@ struct ib_uverbs_create_cq_resp { __u32 cqe; }; +struct ib_uverbs_poll_cq { + __u64 response; + __u32 cq_handle; + __u32 ne; +}; + +struct ib_uverbs_wc { + __u64 wr_id; + __u32 status; + __u32 opcode; + __u32 vendor_err; + __u32 byte_len; + __u32 imm_data; + __u32 qp_num; + __u32 src_qp; + __u32 wc_flags; + __u16 pkey_index; + __u16 slid; + __u8 sl; + __u8 dlid_path_bits; + __u8 port_num; + __u8 reserved; +}; + +struct ib_uverbs_poll_cq_resp { + __u32 count; + __u32 reserved; + struct ib_uverbs_wc wc[0]; +}; + +struct ib_uverbs_req_notify_cq { + __u32 cq_handle; + __u32 solicited_only; +}; + struct ib_uverbs_destroy_cq { __u64 response; __u32 cq_handle; @@ -358,6 +397,127 @@ struct ib_uverbs_destroy_qp_resp { __u32 events_reported; }; +/* + * The ib_uverbs_sge structure isn't used anywhere, since we assume + * the ib_sge structure is packed the same way on 32-bit and 64-bit + * architectures in both kernel and user space. It's just here to + * document the ABI. + */ +struct ib_uverbs_sge { + __u64 addr; + __u32 length; + __u32 lkey; +}; + +struct ib_uverbs_send_wr { + __u64 wr_id; + __u32 num_sge; + __u32 opcode; + __u32 send_flags; + __u32 imm_data; + union { + struct { + __u64 remote_addr; + __u32 rkey; + __u32 reserved; + } rdma; + struct { + __u64 remote_addr; + __u64 compare_add; + __u64 swap; + __u32 rkey; + __u32 reserved; + } atomic; + struct { + __u32 ah; + __u32 remote_qpn; + __u32 remote_qkey; + __u32 reserved; + } ud; + } wr; +}; + +struct ib_uverbs_post_send { + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_send_wr send_wr[0]; +}; + +struct ib_uverbs_post_send_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_recv_wr { + __u64 wr_id; + __u32 num_sge; + __u32 reserved; +}; + +struct ib_uverbs_post_recv { + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_recv_wr recv_wr[0]; +}; + +struct ib_uverbs_post_recv_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_post_srq_recv { + __u64 response; + __u32 srq_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_recv_wr recv[0]; +}; + +struct ib_uverbs_post_srq_recv_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_global_route { + __u8 dgid[16]; + __u32 flow_label; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 reserved; +}; + +struct ib_uverbs_ah_attr { + struct ib_uverbs_global_route grh; + __u16 dlid; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; + __u8 reserved; +}; + +struct ib_uverbs_create_ah { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 reserved; + struct ib_uverbs_ah_attr attr; +}; + +struct ib_uverbs_create_ah_resp { + __u32 ah_handle; +}; + +struct ib_uverbs_destroy_ah { + __u32 ah_handle; +}; + struct ib_uverbs_attach_mcast { __u8 gid[16]; __u32 qp_handle; From 67cdb40ca444c09853ab4d8a41cf547ac26a4de4 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 14 Oct 2005 15:26:04 -0700 Subject: [PATCH 0423/1939] [IB] uverbs: Implement more commands Add kernel support for userspace calling poll CQ, request CQ notification, post send, post receive, post SRQ receive, create AH and destroy AH commands. These commands allow us to support userspace verbs for devices that can't perform these operations directly from userspace (eg the PathScale HCA). Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 8 + drivers/infiniband/core/uverbs_cmd.c | 549 ++++++++++++++++++++++++++ drivers/infiniband/core/uverbs_main.c | 16 +- 3 files changed, 572 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 475153e510a9..63c8085c0c98 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -3,6 +3,7 @@ * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -140,10 +141,17 @@ IB_UVERBS_DECLARE_CMD(reg_mr); IB_UVERBS_DECLARE_CMD(dereg_mr); IB_UVERBS_DECLARE_CMD(create_comp_channel); IB_UVERBS_DECLARE_CMD(create_cq); +IB_UVERBS_DECLARE_CMD(poll_cq); +IB_UVERBS_DECLARE_CMD(req_notify_cq); IB_UVERBS_DECLARE_CMD(destroy_cq); IB_UVERBS_DECLARE_CMD(create_qp); IB_UVERBS_DECLARE_CMD(modify_qp); IB_UVERBS_DECLARE_CMD(destroy_qp); +IB_UVERBS_DECLARE_CMD(post_send); +IB_UVERBS_DECLARE_CMD(post_recv); +IB_UVERBS_DECLARE_CMD(post_srq_recv); +IB_UVERBS_DECLARE_CMD(create_ah); +IB_UVERBS_DECLARE_CMD(destroy_ah); IB_UVERBS_DECLARE_CMD(attach_mcast); IB_UVERBS_DECLARE_CMD(detach_mcast); IB_UVERBS_DECLARE_CMD(create_srq); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 2e959acf2ff1..14583bb6e2c0 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -665,6 +665,93 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, return ret; } +ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_poll_cq cmd; + struct ib_uverbs_poll_cq_resp *resp; + struct ib_cq *cq; + struct ib_wc *wc; + int ret = 0; + int i; + int rsize; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); + if (!wc) + return -ENOMEM; + + rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); + resp = kmalloc(rsize, GFP_KERNEL); + if (!resp) { + ret = -ENOMEM; + goto out_wc; + } + + down(&ib_uverbs_idr_mutex); + cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); + if (!cq || cq->uobject->context != file->ucontext) { + ret = -EINVAL; + goto out; + } + + resp->count = ib_poll_cq(cq, cmd.ne, wc); + + for (i = 0; i < resp->count; i++) { + resp->wc[i].wr_id = wc[i].wr_id; + resp->wc[i].status = wc[i].status; + resp->wc[i].opcode = wc[i].opcode; + resp->wc[i].vendor_err = wc[i].vendor_err; + resp->wc[i].byte_len = wc[i].byte_len; + resp->wc[i].imm_data = wc[i].imm_data; + resp->wc[i].qp_num = wc[i].qp_num; + resp->wc[i].src_qp = wc[i].src_qp; + resp->wc[i].wc_flags = wc[i].wc_flags; + resp->wc[i].pkey_index = wc[i].pkey_index; + resp->wc[i].slid = wc[i].slid; + resp->wc[i].sl = wc[i].sl; + resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; + resp->wc[i].port_num = wc[i].port_num; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + kfree(resp); + +out_wc: + kfree(wc); + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_req_notify_cq cmd; + struct ib_cq *cq; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); + if (cq && cq->uobject->context == file->ucontext) { + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); + ret = in_len; + } + up(&ib_uverbs_idr_mutex); + + return ret; +} + ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -1003,6 +1090,468 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, return ret ? ret : in_len; } +ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_send cmd; + struct ib_uverbs_post_send_resp resp; + struct ib_uverbs_send_wr *user_wr; + struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; + struct ib_qp *qp; + int i, sg_ind; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count + + cmd.sge_count * sizeof (struct ib_uverbs_sge)) + return -EINVAL; + + if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr)) + return -EINVAL; + + user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); + if (!user_wr) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + sg_ind = 0; + last = NULL; + for (i = 0; i < cmd.wr_count; ++i) { + if (copy_from_user(user_wr, + buf + sizeof cmd + i * cmd.wqe_size, + cmd.wqe_size)) { + ret = -EFAULT; + goto out; + } + + if (user_wr->num_sge + sg_ind > cmd.sge_count) { + ret = -EINVAL; + goto out; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto out; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + next->opcode = user_wr->opcode; + next->send_flags = user_wr->send_flags; + next->imm_data = user_wr->imm_data; + + if (qp->qp_type == IB_QPT_UD) { + next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, + user_wr->wr.ud.ah); + if (!next->wr.ud.ah) { + ret = -EINVAL; + goto out; + } + next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; + next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; + } else { + switch (next->opcode) { + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + case IB_WR_RDMA_READ: + next->wr.rdma.remote_addr = + user_wr->wr.rdma.remote_addr; + next->wr.rdma.rkey = + user_wr->wr.rdma.rkey; + break; + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + next->wr.atomic.remote_addr = + user_wr->wr.atomic.remote_addr; + next->wr.atomic.compare_add = + user_wr->wr.atomic.compare_add; + next->wr.atomic.swap = user_wr->wr.atomic.swap; + next->wr.atomic.rkey = user_wr->wr.atomic.rkey; + break; + default: + break; + } + } + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + sizeof cmd + + cmd.wr_count * cmd.wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto out; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + resp.bad_wr = 0; + ret = qp->device->post_send(qp, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + kfree(user_wr); + + return ret ? ret : in_len; +} + +static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, + int in_len, + u32 wr_count, + u32 sge_count, + u32 wqe_size) +{ + struct ib_uverbs_recv_wr *user_wr; + struct ib_recv_wr *wr = NULL, *last, *next; + int sg_ind; + int i; + int ret; + + if (in_len < wqe_size * wr_count + + sge_count * sizeof (struct ib_uverbs_sge)) + return ERR_PTR(-EINVAL); + + if (wqe_size < sizeof (struct ib_uverbs_recv_wr)) + return ERR_PTR(-EINVAL); + + user_wr = kmalloc(wqe_size, GFP_KERNEL); + if (!user_wr) + return ERR_PTR(-ENOMEM); + + sg_ind = 0; + last = NULL; + for (i = 0; i < wr_count; ++i) { + if (copy_from_user(user_wr, buf + i * wqe_size, + wqe_size)) { + ret = -EFAULT; + goto err; + } + + if (user_wr->num_sge + sg_ind > sge_count) { + ret = -EINVAL; + goto err; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto err; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + wr_count * wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto err; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + kfree(user_wr); + return wr; + +err: + kfree(user_wr); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ERR_PTR(ret); +} + +ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_recv cmd; + struct ib_uverbs_post_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_qp *qp; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + resp.bad_wr = 0; + ret = qp->device->post_recv(qp, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_srq_recv cmd; + struct ib_uverbs_post_srq_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_srq *srq; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + down(&ib_uverbs_idr_mutex); + + srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); + if (!srq || srq->uobject->context != file->ucontext) + goto out; + + resp.bad_wr = 0; + ret = srq->device->post_srq_recv(srq, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_ah cmd; + struct ib_uverbs_create_ah_resp resp; + struct ib_uobject *uobj; + struct ib_pd *pd; + struct ib_ah *ah; + struct ib_ah_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + if (!pd || pd->uobject->context != file->ucontext) { + ret = -EINVAL; + goto err_up; + } + + uobj->user_handle = cmd.user_handle; + uobj->context = file->ucontext; + + attr.dlid = cmd.attr.dlid; + attr.sl = cmd.attr.sl; + attr.src_path_bits = cmd.attr.src_path_bits; + attr.static_rate = cmd.attr.static_rate; + attr.port_num = cmd.attr.port_num; + attr.grh.flow_label = cmd.attr.grh.flow_label; + attr.grh.sgid_index = cmd.attr.grh.sgid_index; + attr.grh.hop_limit = cmd.attr.grh.hop_limit; + attr.grh.traffic_class = cmd.attr.grh.traffic_class; + memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); + + ah = ib_create_ah(pd, &attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + goto err_up; + } + + ah->uobject = uobj; + +retry: + if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_destroy; + } + + ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_destroy; + + resp.ah_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_idr; + } + + down(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->ah_list); + up(&file->mutex); + + up(&ib_uverbs_idr_mutex); + + return in_len; + +err_idr: + idr_remove(&ib_uverbs_ah_idr, uobj->id); + +err_destroy: + ib_destroy_ah(ah); + +err_up: + up(&ib_uverbs_idr_mutex); + + kfree(uobj); + return ret; +} + +ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, int out_len) +{ + struct ib_uverbs_destroy_ah cmd; + struct ib_ah *ah; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle); + if (!ah || ah->uobject->context != file->ucontext) + goto out; + + uobj = ah->uobject; + + ret = ib_destroy_ah(ah); + if (ret) + goto out; + + idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle); + + down(&file->mutex); + list_del(&uobj->list); + up(&file->mutex); + + kfree(uobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 6a5e5084db7a..ef2312a9ea76 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -3,6 +3,7 @@ * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -86,10 +87,17 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, + [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, + [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, + [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, + [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, + [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, @@ -111,7 +119,13 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) down(&ib_uverbs_idr_mutex); - /* XXX Free AHs */ + list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { + struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); + idr_remove(&ib_uverbs_ah_idr, uobj->id); + ib_destroy_ah(ah); + list_del(&uobj->list); + kfree(uobj); + } list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); From 595e726a1f28420c5fc7970b1a87cbce77a1cd45 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Mon, 17 Oct 2005 15:33:47 -0700 Subject: [PATCH 0424/1939] [IB] merge ucm.h into ucm.c Eliminate ucm.h. Replace ucm_dbg with direct call to printk KERN_ERR. Signed-off-by: Sean Hefty --- drivers/infiniband/core/ucm.c | 62 +++++++++++++++++--------- drivers/infiniband/core/ucm.h | 83 ----------------------------------- 2 files changed, 41 insertions(+), 104 deletions(-) delete mode 100644 drivers/infiniband/core/ucm.h diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index d0f0b0a2edd3..b7470f0fe83b 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -41,19 +41,52 @@ #include #include #include +#include #include -#include "ucm.h" +#include +#include MODULE_AUTHOR("Libor Michalek"); MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); MODULE_LICENSE("Dual BSD/GPL"); -static int ucm_debug_level; +struct ib_ucm_file { + struct semaphore mutex; + struct file *filp; -module_param_named(debug_level, ucm_debug_level, int, 0644); -MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + struct list_head ctxs; /* list of active connections */ + struct list_head events; /* list of pending events */ + wait_queue_head_t poll_wait; +}; + +struct ib_ucm_context { + int id; + wait_queue_head_t wait; + atomic_t ref; + int events_reported; + + struct ib_ucm_file *file; + struct ib_cm_id *cm_id; + __u64 uid; + + struct list_head events; /* list of pending events. */ + struct list_head file_list; /* member in file ctx list */ +}; + +struct ib_ucm_event { + struct ib_ucm_context *ctx; + struct list_head file_list; /* member in file event list */ + struct list_head ctx_list; /* member in ctx event list */ + + struct ib_cm_id *cm_id; + struct ib_ucm_event_resp resp; + void *data; + void *info; + int data_len; + int info_len; +}; enum { IB_UCM_MAJOR = 231, @@ -62,17 +95,10 @@ enum { #define IB_UCM_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_MINOR) -#define PFX "UCM: " - -#define ucm_dbg(format, arg...) \ - do { \ - if (ucm_debug_level > 0) \ - printk(KERN_DEBUG PFX format, ## arg); \ - } while (0) - static struct semaphore ctx_id_mutex; static struct idr ctx_id_table; + static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) { struct ib_ucm_context *ctx; @@ -152,7 +178,6 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) goto error; list_add_tail(&ctx->file_list, &file->ctxs); - ucm_dbg("Allocated CM ID <%d>\n", ctx->id); return ctx; error: @@ -1184,9 +1209,6 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, if (copy_from_user(&hdr, buf, sizeof(hdr))) return -EFAULT; - ucm_dbg("Write. cmd <%d> in <%d> out <%d> len <%Zu>\n", - hdr.cmd, hdr.in, hdr.out, len); - if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucm_cmd_table)) return -EINVAL; @@ -1232,8 +1254,6 @@ static int ib_ucm_open(struct inode *inode, struct file *filp) filp->private_data = file; file->filp = filp; - ucm_dbg("Created struct\n"); - return 0; } @@ -1281,7 +1301,7 @@ static int __init ib_ucm_init(void) result = register_chrdev_region(IB_UCM_DEV, 1, "infiniband_cm"); if (result) { - ucm_dbg("Error <%d> registering dev\n", result); + printk(KERN_ERR "ucm: Error <%d> registering dev\n", result); goto err_chr; } @@ -1289,14 +1309,14 @@ static int __init ib_ucm_init(void) result = cdev_add(&ib_ucm_cdev, IB_UCM_DEV, 1); if (result) { - ucm_dbg("Error <%d> adding cdev\n", result); + printk(KERN_ERR "ucm: Error <%d> adding cdev\n", result); goto err_cdev; } ib_ucm_class = class_create(THIS_MODULE, "infiniband_cm"); if (IS_ERR(ib_ucm_class)) { result = PTR_ERR(ib_ucm_class); - ucm_dbg("Error <%d> creating class\n", result); + printk(KERN_ERR "Error <%d> creating class\n", result); goto err_class; } diff --git a/drivers/infiniband/core/ucm.h b/drivers/infiniband/core/ucm.h deleted file mode 100644 index f46f37bc1201..000000000000 --- a/drivers/infiniband/core/ucm.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Intel Corporation. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * $Id: ucm.h 2208 2005-04-22 23:24:31Z libor $ - */ - -#ifndef UCM_H -#define UCM_H - -#include -#include -#include -#include - -#include -#include - -struct ib_ucm_file { - struct semaphore mutex; - struct file *filp; - - struct list_head ctxs; /* list of active connections */ - struct list_head events; /* list of pending events */ - wait_queue_head_t poll_wait; -}; - -struct ib_ucm_context { - int id; - wait_queue_head_t wait; - atomic_t ref; - int events_reported; - - struct ib_ucm_file *file; - struct ib_cm_id *cm_id; - __u64 uid; - - struct list_head events; /* list of pending events. */ - struct list_head file_list; /* member in file ctx list */ -}; - -struct ib_ucm_event { - struct ib_ucm_context *ctx; - struct list_head file_list; /* member in file event list */ - struct list_head ctx_list; /* member in ctx event list */ - - struct ib_cm_id *cm_id; - struct ib_ucm_event_resp resp; - void *data; - void *info; - int data_len; - int info_len; -}; - -#endif /* UCM_H */ From 07d357d0cbf89d9980b1769d5444a3c70f000e00 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Mon, 17 Oct 2005 15:37:43 -0700 Subject: [PATCH 0425/1939] [IB] CM: bind IDs to a specific device Bind communication identifiers to a device to support device removal. Export per HCA CM devices to userspace. Signed-off-by: Sean Hefty --- drivers/infiniband/core/cm.c | 41 +++++-- drivers/infiniband/core/ucm.c | 220 +++++++++++++++++++++++++--------- include/rdma/ib_cm.h | 10 +- include/rdma/ib_user_cm.h | 10 +- 4 files changed, 203 insertions(+), 78 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 54db6d4831f1..6f747debca90 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -366,9 +366,15 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) cur_cm_id_priv = rb_entry(parent, struct cm_id_private, service_node); if ((cur_cm_id_priv->id.service_mask & service_id) == - (service_mask & cur_cm_id_priv->id.service_id)) - return cm_id_priv; - if (service_id < cur_cm_id_priv->id.service_id) + (service_mask & cur_cm_id_priv->id.service_id) && + (cm_id_priv->id.device == cur_cm_id_priv->id.device)) + return cur_cm_id_priv; + + if (cm_id_priv->id.device < cur_cm_id_priv->id.device) + link = &(*link)->rb_left; + else if (cm_id_priv->id.device > cur_cm_id_priv->id.device) + link = &(*link)->rb_right; + else if (service_id < cur_cm_id_priv->id.service_id) link = &(*link)->rb_left; else link = &(*link)->rb_right; @@ -378,7 +384,8 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) return NULL; } -static struct cm_id_private * cm_find_listen(__be64 service_id) +static struct cm_id_private * cm_find_listen(struct ib_device *device, + __be64 service_id) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; @@ -386,9 +393,15 @@ static struct cm_id_private * cm_find_listen(__be64 service_id) while (node) { cm_id_priv = rb_entry(node, struct cm_id_private, service_node); if ((cm_id_priv->id.service_mask & service_id) == - (cm_id_priv->id.service_mask & cm_id_priv->id.service_id)) + cm_id_priv->id.service_id && + (cm_id_priv->id.device == device)) return cm_id_priv; - if (service_id < cm_id_priv->id.service_id) + + if (device < cm_id_priv->id.device) + node = node->rb_left; + else if (device > cm_id_priv->id.device) + node = node->rb_right; + else if (service_id < cm_id_priv->id.service_id) node = node->rb_left; else node = node->rb_right; @@ -523,7 +536,8 @@ static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv, ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m); } -struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, +struct ib_cm_id *ib_create_cm_id(struct ib_device *device, + ib_cm_handler cm_handler, void *context) { struct cm_id_private *cm_id_priv; @@ -535,6 +549,7 @@ struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, memset(cm_id_priv, 0, sizeof *cm_id_priv); cm_id_priv->id.state = IB_CM_IDLE; + cm_id_priv->id.device = device; cm_id_priv->id.cm_handler = cm_handler; cm_id_priv->id.context = context; cm_id_priv->id.remote_cm_qpn = 1; @@ -1047,7 +1062,6 @@ static void cm_format_req_event(struct cm_work *work, req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; param = &work->cm_event.param.req_rcvd; param->listen_id = listen_id; - param->device = cm_id_priv->av.port->mad_agent->device; param->port = cm_id_priv->av.port->port_num; param->primary_path = &work->path[0]; if (req_msg->alt_local_lid) @@ -1226,7 +1240,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, } /* Find matching listen request. */ - listen_cm_id_priv = cm_find_listen(req_msg->service_id); + listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, + req_msg->service_id); if (!listen_cm_id_priv) { spin_unlock_irqrestore(&cm.lock, flags); cm_issue_rej(work->port, work->mad_recv_wc, @@ -1254,7 +1269,7 @@ static int cm_req_handler(struct cm_work *work) req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; - cm_id = ib_create_cm_id(NULL, NULL); + cm_id = ib_create_cm_id(work->port->cm_dev->device, NULL, NULL); if (IS_ERR(cm_id)) return PTR_ERR(cm_id); @@ -2629,7 +2644,6 @@ static void cm_format_sidr_req_event(struct cm_work *work, param = &work->cm_event.param.sidr_req_rcvd; param->pkey = __be16_to_cpu(sidr_req_msg->pkey); param->listen_id = listen_id; - param->device = work->port->mad_agent->device; param->port = work->port->port_num; work->cm_event.private_data = &sidr_req_msg->private_data; } @@ -2642,7 +2656,7 @@ static int cm_sidr_req_handler(struct cm_work *work) struct ib_wc *wc; unsigned long flags; - cm_id = ib_create_cm_id(NULL, NULL); + cm_id = ib_create_cm_id(work->port->cm_dev->device, NULL, NULL); if (IS_ERR(cm_id)) return PTR_ERR(cm_id); cm_id_priv = container_of(cm_id, struct cm_id_private, id); @@ -2666,7 +2680,8 @@ static int cm_sidr_req_handler(struct cm_work *work) spin_unlock_irqrestore(&cm.lock, flags); goto out; /* Duplicate message. */ } - cur_cm_id_priv = cm_find_listen(sidr_req_msg->service_id); + cur_cm_id_priv = cm_find_listen(cm_id->device, + sidr_req_msg->service_id); if (!cur_cm_id_priv) { rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); spin_unlock_irqrestore(&cm.lock, flags); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index b7470f0fe83b..d208ea29e07a 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -52,12 +52,20 @@ MODULE_AUTHOR("Libor Michalek"); MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); MODULE_LICENSE("Dual BSD/GPL"); +struct ib_ucm_device { + int devnum; + struct cdev dev; + struct class_device class_dev; + struct ib_device *ib_dev; +}; + struct ib_ucm_file { struct semaphore mutex; struct file *filp; + struct ib_ucm_device *device; - struct list_head ctxs; /* list of active connections */ - struct list_head events; /* list of pending events */ + struct list_head ctxs; + struct list_head events; wait_queue_head_t poll_wait; }; @@ -90,14 +98,24 @@ struct ib_ucm_event { enum { IB_UCM_MAJOR = 231, - IB_UCM_MINOR = 255 + IB_UCM_BASE_MINOR = 224, + IB_UCM_MAX_DEVICES = 32 }; -#define IB_UCM_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_MINOR) +#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) -static struct semaphore ctx_id_mutex; -static struct idr ctx_id_table; +static void ib_ucm_add_one(struct ib_device *device); +static void ib_ucm_remove_one(struct ib_device *device); +static struct ib_client ucm_client = { + .name = "ucm", + .add = ib_ucm_add_one, + .remove = ib_ucm_remove_one +}; + +DECLARE_MUTEX(ctx_id_mutex); +DEFINE_IDR(ctx_id_table); +static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES); static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) { @@ -184,10 +202,7 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) kfree(ctx); return NULL; } -/* - * Event portion of the API, handle CM events - * and allow event polling. - */ + static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, struct ib_sa_path_rec *kpath) { @@ -234,6 +249,7 @@ static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, ureq->retry_count = kreq->retry_count; ureq->rnr_retry_count = kreq->rnr_retry_count; ureq->srq = kreq->srq; + ureq->port = kreq->port; ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path); ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path); @@ -320,6 +336,8 @@ static int ib_ucm_event_process(struct ib_cm_event *evt, case IB_CM_SIDR_REQ_RECEIVED: uvt->resp.u.sidr_req_resp.pkey = evt->param.sidr_req_rcvd.pkey; + uvt->resp.u.sidr_req_resp.port = + evt->param.sidr_req_rcvd.port; uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; break; case IB_CM_SIDR_REP_RECEIVED: @@ -412,9 +430,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - /* - * wait - */ + down(&file->mutex); while (list_empty(&file->events)) { @@ -496,7 +512,6 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, return result; } - static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, const char __user *inbuf, int in_len, int out_len) @@ -519,29 +534,27 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, return -ENOMEM; ctx->uid = cmd.uid; - ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx); + ctx->cm_id = ib_create_cm_id(file->device->ib_dev, + ib_ucm_event_handler, ctx); if (IS_ERR(ctx->cm_id)) { result = PTR_ERR(ctx->cm_id); - goto err; + goto err1; } resp.id = ctx->id; if (copy_to_user((void __user *)(unsigned long)cmd.response, &resp, sizeof(resp))) { result = -EFAULT; - goto err; + goto err2; } - return 0; -err: +err2: + ib_destroy_cm_id(ctx->cm_id); +err1: down(&ctx_id_mutex); idr_remove(&ctx_id_table, ctx->id); up(&ctx_id_mutex); - - if (!IS_ERR(ctx->cm_id)) - ib_destroy_cm_id(ctx->cm_id); - kfree(ctx); return result; } @@ -1253,6 +1266,7 @@ static int ib_ucm_open(struct inode *inode, struct file *filp) filp->private_data = file; file->filp = filp; + file->device = container_of(inode->i_cdev, struct ib_ucm_device, dev); return 0; } @@ -1283,7 +1297,17 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) return 0; } -static struct file_operations ib_ucm_fops = { +static void ib_ucm_release_class_dev(struct class_device *class_dev) +{ + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + cdev_del(&dev->dev); + clear_bit(dev->devnum, dev_map); + kfree(dev); +} + +static struct file_operations ucm_fops = { .owner = THIS_MODULE, .open = ib_ucm_open, .release = ib_ucm_close, @@ -1291,55 +1315,141 @@ static struct file_operations ib_ucm_fops = { .poll = ib_ucm_poll, }; +static struct class ucm_class = { + .name = "infiniband_cm", + .release = ib_ucm_release_class_dev +}; -static struct class *ib_ucm_class; -static struct cdev ib_ucm_cdev; +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + return print_dev_t(buf, dev->dev.dev); +} +static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); + +static ssize_t show_ibdev(struct class_device *class_dev, char *buf) +{ + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + return sprintf(buf, "%s\n", dev->ib_dev->name); +} +static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); + +static void ib_ucm_add_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev; + + if (!device->alloc_ucontext) + return; + + ucm_dev = kmalloc(sizeof *ucm_dev, GFP_KERNEL); + if (!ucm_dev) + return; + + memset(ucm_dev, 0, sizeof *ucm_dev); + ucm_dev->ib_dev = device; + + ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); + if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES) + goto err; + + set_bit(ucm_dev->devnum, dev_map); + + cdev_init(&ucm_dev->dev, &ucm_fops); + ucm_dev->dev.owner = THIS_MODULE; + kobject_set_name(&ucm_dev->dev.kobj, "ucm%d", ucm_dev->devnum); + if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) + goto err; + + ucm_dev->class_dev.class = &ucm_class; + ucm_dev->class_dev.dev = device->dma_device; + snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d", + ucm_dev->devnum); + if (class_device_register(&ucm_dev->class_dev)) + goto err_cdev; + + if (class_device_create_file(&ucm_dev->class_dev, + &class_device_attr_dev)) + goto err_class; + if (class_device_create_file(&ucm_dev->class_dev, + &class_device_attr_ibdev)) + goto err_class; + + ib_set_client_data(device, &ucm_client, ucm_dev); + return; + +err_class: + class_device_unregister(&ucm_dev->class_dev); +err_cdev: + cdev_del(&ucm_dev->dev); + clear_bit(ucm_dev->devnum, dev_map); +err: + kfree(ucm_dev); + return; +} + +static void ib_ucm_remove_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev = ib_get_client_data(device, &ucm_client); + + if (!ucm_dev) + return; + + class_device_unregister(&ucm_dev->class_dev); +} + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static int __init ib_ucm_init(void) { - int result; + int ret; - result = register_chrdev_region(IB_UCM_DEV, 1, "infiniband_cm"); - if (result) { - printk(KERN_ERR "ucm: Error <%d> registering dev\n", result); - goto err_chr; + ret = register_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES, + "infiniband_cm"); + if (ret) { + printk(KERN_ERR "ucm: couldn't register device number\n"); + goto err; } - cdev_init(&ib_ucm_cdev, &ib_ucm_fops); - - result = cdev_add(&ib_ucm_cdev, IB_UCM_DEV, 1); - if (result) { - printk(KERN_ERR "ucm: Error <%d> adding cdev\n", result); - goto err_cdev; + ret = class_register(&ucm_class); + if (ret) { + printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n"); + goto err_chrdev; } - ib_ucm_class = class_create(THIS_MODULE, "infiniband_cm"); - if (IS_ERR(ib_ucm_class)) { - result = PTR_ERR(ib_ucm_class); - printk(KERN_ERR "Error <%d> creating class\n", result); + ret = class_create_file(&ucm_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); goto err_class; } - class_device_create(ib_ucm_class, IB_UCM_DEV, NULL, "ucm"); - - idr_init(&ctx_id_table); - init_MUTEX(&ctx_id_mutex); - + ret = ib_register_client(&ucm_client); + if (ret) { + printk(KERN_ERR "ucm: couldn't register client\n"); + goto err_class; + } return 0; + err_class: - cdev_del(&ib_ucm_cdev); -err_cdev: - unregister_chrdev_region(IB_UCM_DEV, 1); -err_chr: - return result; + class_unregister(&ucm_class); +err_chrdev: + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); +err: + return ret; } static void __exit ib_ucm_cleanup(void) { - class_device_destroy(ib_ucm_class, IB_UCM_DEV); - class_destroy(ib_ucm_class); - cdev_del(&ib_ucm_cdev); - unregister_chrdev_region(IB_UCM_DEV, 1); + ib_unregister_client(&ucm_client); + class_unregister(&ucm_class); + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); } module_init(ib_ucm_init); diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 5308683c8c41..0a9fcd59eb43 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004 Voltaire Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. @@ -109,7 +109,6 @@ struct ib_cm_id; struct ib_cm_req_event_param { struct ib_cm_id *listen_id; - struct ib_device *device; u8 port; struct ib_sa_path_rec *primary_path; @@ -220,7 +219,6 @@ struct ib_cm_apr_event_param { struct ib_cm_sidr_req_event_param { struct ib_cm_id *listen_id; - struct ib_device *device; u8 port; u16 pkey; }; @@ -284,6 +282,7 @@ typedef int (*ib_cm_handler)(struct ib_cm_id *cm_id, struct ib_cm_id { ib_cm_handler cm_handler; void *context; + struct ib_device *device; __be64 service_id; __be64 service_mask; enum ib_cm_state state; /* internal CM/debug use */ @@ -295,6 +294,8 @@ struct ib_cm_id { /** * ib_create_cm_id - Allocate a communication identifier. + * @device: Device associated with the cm_id. All related communication will + * be associated with the specified device. * @cm_handler: Callback invoked to notify the user of CM events. * @context: User specified context associated with the communication * identifier. @@ -302,7 +303,8 @@ struct ib_cm_id { * Communication identifiers are used to track connection states, service * ID resolution requests, and listen requests. */ -struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, +struct ib_cm_id *ib_create_cm_id(struct ib_device *device, + ib_cm_handler cm_handler, void *context); /** diff --git a/include/rdma/ib_user_cm.h b/include/rdma/ib_user_cm.h index e4d1654276ad..3037588b8464 100644 --- a/include/rdma/ib_user_cm.h +++ b/include/rdma/ib_user_cm.h @@ -38,7 +38,7 @@ #include -#define IB_USER_CM_ABI_VERSION 2 +#define IB_USER_CM_ABI_VERSION 3 enum { IB_USER_CM_CMD_CREATE_ID, @@ -299,8 +299,6 @@ struct ib_ucm_event_get { }; struct ib_ucm_req_event_resp { - /* device */ - /* port */ struct ib_ucm_path_rec primary_path; struct ib_ucm_path_rec alternate_path; __be64 remote_ca_guid; @@ -316,6 +314,7 @@ struct ib_ucm_req_event_resp { __u8 retry_count; __u8 rnr_retry_count; __u8 srq; + __u8 port; }; struct ib_ucm_rep_event_resp { @@ -353,10 +352,9 @@ struct ib_ucm_apr_event_resp { }; struct ib_ucm_sidr_req_event_resp { - /* device */ - /* port */ __u16 pkey; - __u8 reserved[2]; + __u8 port; + __u8 reserved; }; struct ib_ucm_sidr_rep_event_resp { From 762a03e21ed08daa5170d9cd98e83539861e7692 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 17 Oct 2005 15:38:50 -0700 Subject: [PATCH 0426/1939] [IB] ucm: quiet sparse warnings Make ctx_id_mutex and ctx_id_table static to quiet sparse warnings. Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index d208ea29e07a..02ca642089bd 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -113,8 +113,8 @@ static struct ib_client ucm_client = { .remove = ib_ucm_remove_one }; -DECLARE_MUTEX(ctx_id_mutex); -DEFINE_IDR(ctx_id_table); +static DECLARE_MUTEX(ctx_id_mutex); +static DEFINE_IDR(ctx_id_table); static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES); static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) From 81e7009ea46c951860b8716ee427ff4f54dd26fc Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 18 Oct 2005 11:17:58 +1000 Subject: [PATCH 0427/1939] powerpc: merge ppc signal.c and ppc64 signal32.c Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 2 +- .../signal32.c => powerpc/kernel/signal_32.c} | 977 +++++++++++------- arch/ppc/kernel/Makefile | 4 +- arch/ppc/kernel/signal.c | 771 -------------- arch/ppc64/kernel/Makefile | 2 +- include/asm-ppc64/ppc32.h | 14 +- 6 files changed, 635 insertions(+), 1135 deletions(-) rename arch/{ppc64/kernel/signal32.c => powerpc/kernel/signal_32.c} (55%) delete mode 100644 arch/ppc/kernel/signal.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 1ca740bc5b47..043ddd09521d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o cputable.o ptrace.o +obj-y := semaphore.o cputable.o ptrace.o signal_32.o obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o diff --git a/arch/ppc64/kernel/signal32.c b/arch/powerpc/kernel/signal_32.c similarity index 55% rename from arch/ppc64/kernel/signal32.c rename to arch/powerpc/kernel/signal_32.c index a8b7a5a56bb4..e53127ec373d 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -1,56 +1,352 @@ /* - * signal32.c: Support 32bit signal syscalls. + * Signal handling for 32bit PPC and 32bit tasks on 64bit PPC * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright (C) 2001 IBM * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * - * These routines maintain argument size conversion between 32bit and 64bit - * environment. + * Derived from "arch/i386/kernel/signal.c" + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * - * 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 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 +#ifdef CONFIG_PPC64 +#include #include #include -#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + #include +#include +#ifdef CONFIG_PPC64 +#include #include #include -#include #include +#else +#include +#include +#endif -#define DEBUG_SIG 0 +#undef DEBUG_SIG #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -#define GP_REGS_SIZE32 min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) +#ifdef CONFIG_PPC64 +#define do_signal do_signal32 +#define sys_sigsuspend sys32_sigsuspend +#define sys_rt_sigsuspend sys32_rt_sigsuspend +#define sys_rt_sigreturn sys32_rt_sigreturn +#define sys_sigaction sys32_sigaction +#define sys_swapcontext sys32_swapcontext +#define sys_sigreturn sys32_sigreturn + +#define old_sigaction old_sigaction32 +#define sigcontext sigcontext32 +#define mcontext mcontext32 +#define ucontext ucontext32 + +/* + * Returning 0 means we return to userspace via + * ret_from_except and thus restore all user + * registers from *regs. This is what we need + * to do when a signal has been delivered. + */ +#define sigreturn_exit(regs) return 0 + +#define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) +#undef __SIGNAL_FRAMESIZE +#define __SIGNAL_FRAMESIZE __SIGNAL_FRAMESIZE32 +#undef ELF_NVRREG +#define ELF_NVRREG ELF_NVRREG32 + +/* + * Functions for flipping sigsets (thanks to brain dead generic + * implementation that makes things simple for little endian only) + */ +static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) +{ + compat_sigset_t cset; + + switch (_NSIG_WORDS) { + case 4: cset.sig[5] = set->sig[3] & 0xffffffffull; + cset.sig[7] = set->sig[3] >> 32; + case 3: cset.sig[4] = set->sig[2] & 0xffffffffull; + cset.sig[5] = set->sig[2] >> 32; + case 2: cset.sig[2] = set->sig[1] & 0xffffffffull; + cset.sig[3] = set->sig[1] >> 32; + case 1: cset.sig[0] = set->sig[0] & 0xffffffffull; + cset.sig[1] = set->sig[0] >> 32; + } + return copy_to_user(uset, &cset, sizeof(*uset)); +} + +static inline int get_sigset_t(sigset_t *set, compat_sigset_t __user *uset) +{ + compat_sigset_t s32; + + if (copy_from_user(&s32, uset, sizeof(*uset))) + return -EFAULT; + + /* + * Swap the 2 words of the 64-bit sigset_t (they are stored + * in the "wrong" endian in 32-bit user storage). + */ + switch (_NSIG_WORDS) { + case 4: set->sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: set->sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: set->sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + return 0; +} + +static inline int get_old_sigaction(struct k_sigaction *new_ka, + struct old_sigaction __user *act) +{ + compat_old_sigset_t mask; + compat_uptr_t handler, restorer; + + if (get_user(handler, &act->sa_handler) || + __get_user(restorer, &act->sa_restorer) || + __get_user(new_ka->sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) + return -EFAULT; + new_ka->sa.sa_handler = compat_ptr(handler); + new_ka->sa.sa_restorer = compat_ptr(restorer); + siginitset(&new_ka->sa.sa_mask, mask); + return 0; +} + +static inline compat_uptr_t to_user_ptr(void *kp) +{ + return (compat_uptr_t)(u64)kp; +} + +#define from_user_ptr(p) compat_ptr(p) + +static inline int save_general_regs(struct pt_regs *regs, + struct mcontext __user *frame) +{ + elf_greg_t64 *gregs = (elf_greg_t64 *)regs; + int i; + + for (i = 0; i <= PT_RESULT; i ++) + if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) + return -EFAULT; + return 0; +} + +static inline int restore_general_regs(struct pt_regs *regs, + struct mcontext __user *sr) +{ + elf_greg_t64 *gregs = (elf_greg_t64 *)regs; + int i; + + for (i = 0; i <= PT_RESULT; i++) { + if ((i == PT_MSR) || (i == PT_SOFTE)) + continue; + if (__get_user(gregs[i], &sr->mc_gregs[i])) + return -EFAULT; + } + return 0; +} + +#else /* CONFIG_PPC64 */ + +extern void sigreturn_exit(struct pt_regs *); + +#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) + +static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) +{ + return copy_to_user(uset, set, sizeof(*uset)); +} + +static inline int get_sigset_t(sigset_t *set, sigset_t __user *uset) +{ + return copy_from_user(set, uset, sizeof(*uset)); +} + +static inline int get_old_sigaction(struct k_sigaction *new_ka, + struct old_sigaction __user *act) +{ + old_sigset_t mask; + + 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; + __get_user(new_ka->sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka->sa.sa_mask, mask); + return 0; +} + +#define to_user_ptr(p) (p) +#define from_user_ptr(p) (p) + +static inline int save_general_regs(struct pt_regs *regs, + struct mcontext __user *frame) +{ + return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); +} + +static inline int restore_general_regs(struct pt_regs *regs, + struct mcontext __user *sr) +{ + /* copy up to but not including MSR */ + if (__copy_from_user(regs, &sr->mc_gregs, + PT_MSR * sizeof(elf_greg_t))) + return -EFAULT; + /* copy from orig_r3 (the word after the MSR) up to the end */ + if (__copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3], + GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t))) + return -EFAULT; + return 0; +} + +#endif /* CONFIG_PPC64 */ + +int do_signal(sigset_t *oldset, struct pt_regs *regs); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, + struct pt_regs *regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->result = -EINTR; + regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + sigreturn_exit(regs); + } +} + +long sys_rt_sigsuspend( +#ifdef CONFIG_PPC64 + compat_sigset_t __user *unewset, +#else + sigset_t __user *unewset, +#endif + size_t sigsetsize, int p3, int p4, + int p6, int p7, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (get_sigset_t(&newset, unewset)) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->result = -EINTR; + regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + sigreturn_exit(regs); + } +} + +#ifdef CONFIG_PPC32 +long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5, + int r6, int r7, int r8, struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->gpr[1]); +} +#endif + +long sys_sigaction(int sig, struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + +#ifdef CONFIG_PPC64 + if (sig < 0) + sig = -sig; +#endif + + if (act) { + if (get_old_sigaction(&new_ka, act)) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(to_user_ptr(old_ka.sa.sa_handler), + &oact->sa_handler) || + __put_user(to_user_ptr(old_ka.sa.sa_restorer), + &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) + return -EFAULT; + } + + return ret; +} /* * When we have signals to deliver, we set up on the * user stack, going down from the original stack pointer: - * a sigregs32 struct - * a sigcontext32 struct - * a gap of __SIGNAL_FRAMESIZE32 bytes + * a sigregs struct + * a sigcontext struct + * a gap of __SIGNAL_FRAMESIZE bytes * * Each of these things must be a multiple of 16 bytes in size. * */ -struct sigregs32 { - struct mcontext32 mctx; /* all the register values */ +struct sigregs { + struct mcontext mctx; /* all the register values */ /* * Programs using the rs6000/xcoff abi can save up to 19 gp * regs and 18 fp regs below sp before decrementing it. @@ -64,17 +360,21 @@ struct sigregs32 { /* * When we have rt signals to deliver, we set up on the * user stack, going down from the original stack pointer: - * one rt_sigframe32 struct (siginfo + ucontext + ABI gap) - * a gap of __SIGNAL_FRAMESIZE32+16 bytes - * (the +16 is to get the siginfo and ucontext32 in the same + * one rt_sigframe struct (siginfo + ucontext + ABI gap) + * a gap of __SIGNAL_FRAMESIZE+16 bytes + * (the +16 is to get the siginfo and ucontext in the same * positions as in older kernels). * * Each of these things must be a multiple of 16 bytes in size. * */ -struct rt_sigframe32 { - compat_siginfo_t info; - struct ucontext32 uc; +struct rt_sigframe { +#ifdef CONFIG_PPC64 + compat_siginfo_t info; +#else + struct siginfo info; +#endif + struct ucontext uc; /* * Programs using the rs6000/xcoff abi can save up to 19 gp * regs and 18 fp regs below sp before decrementing it. @@ -82,66 +382,24 @@ struct rt_sigframe32 { int abigap[56]; }; - -/* - * Common utility functions used by signal and context support - * - */ - -/* - * Restore the user process's signal mask - * (implemented in signal.c) - */ -extern void restore_sigmask(sigset_t *set); - -/* - * Functions for flipping sigsets (thanks to brain dead generic - * implementation that makes things simple for little endian only - */ -static inline void compat_from_sigset(compat_sigset_t *compat, sigset_t *set) -{ - switch (_NSIG_WORDS) { - case 4: compat->sig[5] = set->sig[3] & 0xffffffffull ; - compat->sig[7] = set->sig[3] >> 32; - case 3: compat->sig[4] = set->sig[2] & 0xffffffffull ; - compat->sig[5] = set->sig[2] >> 32; - case 2: compat->sig[2] = set->sig[1] & 0xffffffffull ; - compat->sig[3] = set->sig[1] >> 32; - case 1: compat->sig[0] = set->sig[0] & 0xffffffffull ; - compat->sig[1] = set->sig[0] >> 32; - } -} - -static inline void sigset_from_compat(sigset_t *set, compat_sigset_t *compat) -{ - switch (_NSIG_WORDS) { - case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32); - case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32); - case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32); - case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32); - } -} - - /* * Save the current user registers on the user stack. - * We only save the altivec registers if the process has used - * altivec instructions at some point. + * We only save the altivec/spe registers if the process has used + * altivec/spe instructions at some point. */ -static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, int sigret) +static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, + int sigret) { - elf_greg_t64 *gregs = (elf_greg_t64 *)regs; - int i, err = 0; - +#ifdef CONFIG_PPC32 + CHECK_FULL_REGS(regs); +#endif /* Make sure floating point registers are stored in regs */ flush_fp_to_thread(current); /* save general and floating-point registers */ - for (i = 0; i <= PT_RESULT; i ++) - err |= __put_user((unsigned int)gregs[i], &frame->mc_gregs[i]); - err |= __copy_to_user(&frame->mc_fregs, current->thread.fpr, - ELF_NFPREG * sizeof(double)); - if (err) + if (save_general_regs(regs, frame) || + __copy_to_user(&frame->mc_fregs, current->thread.fpr, + ELF_NFPREG * sizeof(double))) return 1; current->thread.fpscr = 0; /* turn off all fp exceptions */ @@ -151,7 +409,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, if (current->thread.used_vr) { flush_altivec_to_thread(current); if (__copy_to_user(&frame->mc_vregs, current->thread.vr, - ELF_NVRREG32 * sizeof(vector128))) + ELF_NVRREG * sizeof(vector128))) return 1; /* set MSR_VEC in the saved MSR value to indicate that frame->mc_vregs contains valid data */ @@ -169,6 +427,25 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, return 1; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + /* save spe registers */ + if (current->thread.used_spe) { + flush_spe_to_thread(current); + if (__copy_to_user(&frame->mc_vregs, current->thread.evr, + ELF_NEVRREG * sizeof(u32))) + return 1; + /* set MSR_SPE in the saved MSR value to indicate that + frame->mc_vregs contains valid data */ + if (__put_user(regs->msr | MSR_SPE, &frame->mc_gregs[PT_MSR])) + return 1; + } + /* else assert((regs->msr & MSR_SPE) == 0) */ + + /* We always copy to/from spefscr */ + if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG)) + return 1; +#endif /* CONFIG_SPE */ + if (sigret) { /* Set up the sigreturn trampoline: li r0,sigret; sc */ if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) @@ -186,13 +463,11 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, * (except for MSR). */ static long restore_user_regs(struct pt_regs *regs, - struct mcontext32 __user *sr, int sig) + struct mcontext __user *sr, int sig) { - elf_greg_t64 *gregs = (elf_greg_t64 *)regs; - int i; - long err = 0; + long err; unsigned int save_r2 = 0; -#ifdef CONFIG_ALTIVEC +#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE) unsigned long msr; #endif @@ -202,11 +477,7 @@ static long restore_user_regs(struct pt_regs *regs, */ if (!sig) save_r2 = (unsigned int)regs->gpr[2]; - for (i = 0; i <= PT_RESULT; i++) { - if ((i == PT_MSR) || (i == PT_SOFTE)) - continue; - err |= __get_user(gregs[i], &sr->mc_gregs[i]); - } + err = restore_general_regs(regs, sr); if (!sig) regs->gpr[2] = (unsigned long) save_r2; if (err) @@ -229,135 +500,51 @@ static long restore_user_regs(struct pt_regs *regs, sizeof(sr->mc_vregs))) return 1; } else if (current->thread.used_vr) - memset(current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128)); + memset(current->thread.vr, 0, ELF_NVRREG * sizeof(vector128)); /* Always get VRSAVE back */ if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) return 1; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_SPE + /* 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) { + /* restore spe registers from the stack */ + if (__copy_from_user(current->thread.evr, &sr->mc_vregs, + ELF_NEVRREG * sizeof(u32))) + return 1; + } else if (current->thread.used_spe) + memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32)); + + /* Always get SPEFSCR back */ + if (__get_user(current->thread.spefscr, (u32 __user *)&sr->mc_vregs + ELF_NEVRREG)) + return 1; +#endif /* CONFIG_SPE */ + #ifndef CONFIG_SMP preempt_disable(); if (last_task_used_math == current) last_task_used_math = NULL; if (last_task_used_altivec == current) last_task_used_altivec = NULL; +#ifdef CONFIG_SPE + if (last_task_used_spe == current) + last_task_used_spe = NULL; +#endif preempt_enable(); #endif return 0; } - -/* - * Start of nonRT signal support - * - * sigset_t is 32 bits for non-rt signals - * - * System Calls - * sigaction sys32_sigaction - * sigreturn sys32_sigreturn - * - * Note sigsuspend has no special 32 bit routine - uses the 64 bit routine - * - * Other routines - * setup_frame32 - */ - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, - struct pt_regs *regs) -{ - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, regs)) - /* - * Returning 0 means we return to userspace via - * ret_from_except and thus restore all user - * registers from *regs. This is what we need - * to do when a signal has been delivered. - */ - return 0; - } -} - -long sys32_sigaction(int sig, struct old_sigaction32 __user *act, - struct old_sigaction32 __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (sig < 0) - sig = -sig; - - if (act) { - compat_old_sigset_t mask; - compat_uptr_t handler, restorer; - - if (get_user(handler, &act->sa_handler) || - __get_user(restorer, &act->sa_restorer) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user(mask, &act->sa_mask)) - return -EFAULT; - new_ka.sa.sa_handler = compat_ptr(handler); - new_ka.sa.sa_restorer = compat_ptr(restorer); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - if (put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) - return -EFAULT; - } - - return ret; -} - - - -/* - * Start of RT signal support - * - * sigset_t is 64 bits for rt signals - * - * System Calls - * sigaction sys32_rt_sigaction - * sigpending sys32_rt_sigpending - * sigprocmask sys32_rt_sigprocmask - * sigreturn sys32_rt_sigreturn - * sigqueueinfo sys32_rt_sigqueueinfo - * sigsuspend sys32_rt_sigsuspend - * - * Other routines - * setup_rt_frame32 - * copy_siginfo_to_user32 - * siginfo32to64 - */ - - +#ifdef CONFIG_PPC64 long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; int ret; - compat_sigset_t set32; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(compat_sigset_t)) @@ -368,9 +555,7 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, ret = get_user(handler, &act->sa_handler); new_ka.sa.sa_handler = compat_ptr(handler); - ret |= __copy_from_user(&set32, &act->sa_mask, - sizeof(compat_sigset_t)); - sigset_from_compat(&new_ka.sa.sa_mask, &set32); + ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask); ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); if (ret) return -EFAULT; @@ -378,10 +563,8 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - compat_from_sigset(&set32, &old_ka.sa.sa_mask); ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __copy_to_user(&oact->sa_mask, &set32, - sizeof(compat_sigset_t)); + ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask); ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); } return ret; @@ -399,27 +582,24 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set, { sigset_t s; sigset_t __user *up; - compat_sigset_t s32; int ret; mm_segment_t old_fs = get_fs(); if (set) { - if (copy_from_user (&s32, set, sizeof(compat_sigset_t))) - return -EFAULT; - sigset_from_compat(&s, &s32); + if (get_sigset_t(&s, set)) + return -EFAULT; } - + set_fs(KERNEL_DS); /* This is valid because of the set_fs() */ up = (sigset_t __user *) &s; ret = sys_rt_sigprocmask((int)how, set ? up : NULL, oset ? up : NULL, - sigsetsize); + sigsetsize); set_fs(old_fs); if (ret) return ret; if (oset) { - compat_from_sigset(&s32, &s); - if (copy_to_user (oset, &s32, sizeof(compat_sigset_t))) + if (put_sigset_t(oset, &s)) return -EFAULT; } return 0; @@ -428,7 +608,6 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set, long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) { sigset_t s; - compat_sigset_t s32; int ret; mm_segment_t old_fs = get_fs(); @@ -437,8 +616,7 @@ long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); set_fs(old_fs); if (!ret) { - compat_from_sigset(&s32, &s); - if (copy_to_user (set, &s32, sizeof(compat_sigset_t))) + if (put_sigset_t(set, &s)) return -EFAULT; } return ret; @@ -500,6 +678,8 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s) return err; } +#define copy_siginfo_to_user copy_siginfo_to_user32 + /* * Note: it is necessary to treat pid and sig as unsigned ints, with the * corresponding cast to a signed int to insure that the proper conversion @@ -512,7 +692,7 @@ long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) siginfo_t info; int ret; mm_segment_t old_fs = get_fs(); - + if (copy_from_user (&info, uinfo, 3*sizeof(int)) || copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE32)) return -EFAULT; @@ -522,50 +702,6 @@ long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) set_fs (old_fs); return ret; } - -int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int p3, - int p4, int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - compat_sigset_t s32; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&s32, unewset, sizeof(s32))) - return -EFAULT; - - /* - * Swap the 2 words of the 64-bit sigset_t (they are stored - * in the "wrong" endian in 32-bit user storage). - */ - sigset_from_compat(&newset, &s32); - - sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, regs)) - /* - * Returning 0 means we return to userspace via - * ret_from_except and thus restore all user - * registers from *regs. This is what we need - * to do when a signal has been delivered. - */ - return 0; - } -} - /* * Start Alternate signal stack support * @@ -615,76 +751,95 @@ int sys32_sigaltstack(u32 __new, u32 __old, int r5, return -EFAULT; return ret; } +#endif /* CONFIG_PPC64 */ +/* + * Restore the user process's signal mask + */ +#ifdef CONFIG_PPC64 +extern void restore_sigmask(sigset_t *set); +#else /* CONFIG_PPC64 */ +static void restore_sigmask(sigset_t *set) +{ + sigdelsetmask(set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = *set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} +#endif + /* * Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */ -static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long newsp) +static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, + struct pt_regs *regs, unsigned long newsp) { - struct rt_sigframe32 __user *rt_sf; - struct mcontext32 __user *frame; + struct rt_sigframe __user *rt_sf; + struct mcontext __user *frame; unsigned long origsp = newsp; - compat_sigset_t c_oldset; /* Set up Signal Frame */ /* Put a Real Time Context onto stack */ newsp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe32 __user *)newsp; + rt_sf = (struct rt_sigframe __user *)newsp; /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE32 + 16; + newsp -= __SIGNAL_FRAMESIZE + 16; if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp)) goto badframe; - compat_from_sigset(&c_oldset, oldset); - /* Put the siginfo & fill in most of the ucontext */ - if (copy_siginfo_to_user32(&rt_sf->info, info) + if (copy_siginfo_to_user(&rt_sf->info, info) || __put_user(0, &rt_sf->uc.uc_flags) || __put_user(0, &rt_sf->uc.uc_link) || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) || __put_user(sas_ss_flags(regs->gpr[1]), &rt_sf->uc.uc_stack.ss_flags) || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) - || __put_user((u32)(u64)&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs) - || __copy_to_user(&rt_sf->uc.uc_sigmask, &c_oldset, sizeof(c_oldset))) + || __put_user(to_user_ptr(&rt_sf->uc.uc_mcontext), + &rt_sf->uc.uc_regs) + || put_sigset_t(&rt_sf->uc.uc_sigmask, oldset)) goto badframe; /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; - if (put_user(regs->gpr[1], (u32 __user *)newsp)) - goto badframe; - +#ifdef CONFIG_PPC64 if (vdso32_rt_sigtramp && current->thread.vdso_base) { if (save_user_regs(regs, frame, 0)) goto badframe; regs->link = current->thread.vdso_base + vdso32_rt_sigtramp; - } else { + } else +#endif + { if (save_user_regs(regs, frame, __NR_rt_sigreturn)) goto badframe; regs->link = (unsigned long) frame->tramp; } - regs->gpr[1] = (unsigned long) newsp; + if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) + goto badframe; + regs->gpr[1] = newsp; regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) &rt_sf->info; regs->gpr[5] = (unsigned long) &rt_sf->uc; regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; + regs->link = (unsigned long) frame->tramp; regs->trap = 0; +#ifdef CONFIG_PPC64 regs->result = 0; if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); - +#endif return 1; badframe: -#if DEBUG_SIG +#ifdef DEBUG_SIG printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif @@ -692,46 +847,50 @@ static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, return 0; } -static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig) +static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig) { - compat_sigset_t c_set; sigset_t set; - u32 mcp; + struct mcontext __user *mcp; - if (__copy_from_user(&c_set, &ucp->uc_sigmask, sizeof(c_set)) - || __get_user(mcp, &ucp->uc_regs)) + if (get_sigset_t(&set, &ucp->uc_sigmask)) return -EFAULT; - sigset_from_compat(&set, &c_set); +#ifdef CONFIG_PPC64 + { + u32 cmcp; + + if (__get_user(cmcp, &ucp->uc_regs)) + return -EFAULT; + mcp = (struct mcontext __user *)(u64)cmcp; + } +#else + if (__get_user(mcp, &ucp->uc_regs)) + return -EFAULT; +#endif restore_sigmask(&set); - if (restore_user_regs(regs, (struct mcontext32 __user *)(u64)mcp, sig)) + if (restore_user_regs(regs, mcp, sig)) return -EFAULT; return 0; } -/* - * Handle {get,set,swap}_context operations for 32 bits processes - */ - -long sys32_swapcontext(struct ucontext32 __user *old_ctx, - struct ucontext32 __user *new_ctx, +long sys_swapcontext(struct ucontext __user *old_ctx, + struct ucontext __user *new_ctx, int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) { unsigned char tmp; - compat_sigset_t c_set; /* Context size is for future use. Right now, we only make sure * we are passed something we understand */ - if (ctx_size < sizeof(struct ucontext32)) + if (ctx_size < sizeof(struct ucontext)) return -EINVAL; if (old_ctx != NULL) { - compat_from_sigset(&c_set, ¤t->blocked); if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) || save_user_regs(regs, &old_ctx->uc_mcontext, 0) - || __copy_to_user(&old_ctx->uc_sigmask, &c_set, sizeof(c_set)) - || __put_user((u32)(u64)&old_ctx->uc_mcontext, &old_ctx->uc_regs)) + || put_sigset_t(&old_ctx->uc_sigmask, ¤t->blocked) + || __put_user(to_user_ptr(&old_ctx->uc_mcontext), + &old_ctx->uc_regs)) return -EFAULT; } if (new_ctx == NULL) @@ -752,27 +911,26 @@ long sys32_swapcontext(struct ucontext32 __user *old_ctx, * or if another thread unmaps the region containing the context. * We kill the task with a SIGSEGV in this situation. */ - if (do_setcontext32(new_ctx, regs, 0)) + if (do_setcontext(new_ctx, regs, 0)) do_exit(SIGSEGV); - + sigreturn_exit(regs); + /* doesn't actually return back to here */ return 0; } -long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, +long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, struct pt_regs *regs) { - struct rt_sigframe32 __user *rt_sf; - int ret; - + struct rt_sigframe __user *rt_sf; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; - rt_sf = (struct rt_sigframe32 __user *) - (regs->gpr[1] + __SIGNAL_FRAMESIZE32 + 16); + rt_sf = (struct rt_sigframe __user *) + (regs->gpr[1] + __SIGNAL_FRAMESIZE + 16); if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf))) goto bad; - if (do_setcontext32(&rt_sf->uc, regs, 1)) + if (do_setcontext(&rt_sf->uc, regs, 1)) goto bad; /* @@ -781,62 +939,165 @@ long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, * signal return. But other architectures do this and we have * always done it up until now so it is probably better not to * change it. -- paulus + */ +#ifdef CONFIG_PPC64 + /* * We use the sys32_ version that does the 32/64 bits conversion * and takes userland pointer directly. What about error checking ? * nobody does any... */ - sys32_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); - - ret = regs->result; - - return ret; + sys32_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); + return (int)regs->result; +#else + do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); + sigreturn_exit(regs); /* doesn't return here */ + return 0; +#endif bad: force_sig(SIGSEGV, current); return 0; } +#ifdef CONFIG_PPC32 +int sys_debug_setcontext(struct ucontext __user *ctx, + int ndbg, struct sig_dbg_op __user *dbg, + int r6, int r7, int r8, + struct pt_regs *regs) +{ + struct sig_dbg_op op; + int i; + unsigned long new_msr = regs->msr; +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + unsigned long new_dbcr0 = current->thread.dbcr0; +#endif + + for (i=0; imsr = new_msr; +#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) + current->thread.dbcr0 = new_dbcr0; +#endif + + /* + * If we get a fault copying the context into the kernel's + * image of the user's registers, we can't just return -EFAULT + * because the user's registers will be corrupted. For instance + * the NIP value may have been updated but not some of the + * other registers. Given that we have done the access_ok + * and successfully read the first and last bytes of the region + * above, this should only happen in an out-of-memory situation + * or if another thread unmaps the region containing the context. + * We kill the task with a SIGSEGV in this situation. + */ + if (do_setcontext(ctx, regs, 1)) { + force_sig(SIGSEGV, current); + goto out; + } + + /* + * It's not clear whether or why it is desirable to save the + * sigaltstack setting on signal delivery and restore it on + * signal return. But other architectures do this and we have + * always done it up until now so it is probably better not to + * change it. -- paulus + */ + do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); + + sigreturn_exit(regs); + /* doesn't actually return back to here */ + + out: + return 0; +} +#endif /* * OK, we're invoking a handler */ -static int handle_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long newsp) +static int handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, + unsigned long newsp) { - struct sigcontext32 __user *sc; - struct sigregs32 __user *frame; + struct sigcontext __user *sc; + struct sigregs __user *frame; unsigned long origsp = newsp; /* Set up Signal Frame */ - newsp -= sizeof(struct sigregs32); - frame = (struct sigregs32 __user *) newsp; + newsp -= sizeof(struct sigregs); + frame = (struct sigregs __user *) newsp; /* Put a sigcontext on the stack */ newsp -= sizeof(*sc); - sc = (struct sigcontext32 __user *) newsp; + sc = (struct sigcontext __user *) newsp; /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE32; + newsp -= __SIGNAL_FRAMESIZE; if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) goto badframe; #if _NSIG != 64 -#error "Please adjust handle_signal32()" +#error "Please adjust handle_signal()" #endif - if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler) + if (__put_user(to_user_ptr(ka->sa.sa_handler), &sc->handler) || __put_user(oldset->sig[0], &sc->oldmask) +#ifdef CONFIG_PPC64 || __put_user((oldset->sig[0] >> 32), &sc->_unused[3]) - || __put_user((u32)(u64)frame, &sc->regs) +#else + || __put_user(oldset->sig[1], &sc->_unused[3]) +#endif + || __put_user(to_user_ptr(frame), &sc->regs) || __put_user(sig, &sc->signal)) goto badframe; +#ifdef CONFIG_PPC64 if (vdso32_sigtramp && current->thread.vdso_base) { if (save_user_regs(regs, &frame->mctx, 0)) goto badframe; regs->link = current->thread.vdso_base + vdso32_sigtramp; - } else { + } else +#endif + { if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) goto badframe; regs->link = (unsigned long) frame->mctx.tramp; @@ -844,22 +1105,24 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka, if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe; - regs->gpr[1] = (unsigned long) newsp; + regs->gpr[1] = newsp; regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; +#ifdef CONFIG_PPC64 regs->result = 0; if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); +#endif return 1; badframe: -#if DEBUG_SIG - printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n", - regs, frame, *newspp); +#ifdef DEBUG_SIG + printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); #endif force_sigsegv(sig, current); return 0; @@ -868,65 +1131,69 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka, /* * Do a signal return; undo the signal stack. */ -long sys32_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, +long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, struct pt_regs *regs) { - struct sigcontext32 __user *sc; - struct sigcontext32 sigctx; - struct mcontext32 __user *sr; + struct sigcontext __user *sc; + struct sigcontext sigctx; + struct mcontext __user *sr; sigset_t set; - int ret; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; - sc = (struct sigcontext32 __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32); + sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); if (copy_from_user(&sigctx, sc, sizeof(sigctx))) goto badframe; +#ifdef CONFIG_PPC64 /* * Note that PPC32 puts the upper 32 bits of the sigmask in the * unused part of the signal stackframe */ set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3]) << 32); +#else + set.sig[0] = sigctx.oldmask; + set.sig[1] = sigctx._unused[3]; +#endif restore_sigmask(&set); - sr = (struct mcontext32 __user *)(u64)sigctx.regs; + sr = (struct mcontext __user *)from_user_ptr(sigctx.regs); if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) || restore_user_regs(regs, sr, 1)) goto badframe; - ret = regs->result; - return ret; +#ifdef CONFIG_PPC64 + return (int)regs->result; +#else + sigreturn_exit(regs); /* doesn't return */ + return 0; +#endif badframe: force_sig(SIGSEGV, current); return 0; } - - -/* - * Start of do_signal32 routine - * - * This routine gets control when a pending signal needs to be processed - * in the 32 bit target thread - - * - * It handles both rt and non-rt signals - */ - /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ - -int do_signal32(sigset_t *oldset, struct pt_regs *regs) +int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; + struct k_sigaction ka; unsigned int frame, newsp; int signr, ret; - struct k_sigaction ka; + +#ifdef CONFIG_PPC32 + if (try_to_freeze()) { + signr = 0; + if (!signal_pending(current)) + goto no_signal; + } +#endif if (!oldset) oldset = ¤t->blocked; @@ -934,7 +1201,9 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) newsp = frame = 0; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - +#ifdef CONFIG_PPC32 +no_signal: +#endif if (TRAP(regs) == 0x0C00 /* System Call! */ && regs->ccr & 0x10000000 /* error signalled */ && ((ret = regs->gpr[3]) == ERESTARTSYS @@ -964,12 +1233,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) return 0; /* no signals delivered */ if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size - && (!on_sig_stack(regs->gpr[1]))) - newsp = (current->sas_ss_sp + current->sas_ss_size); + && !on_sig_stack(regs->gpr[1])) + newsp = current->sas_ss_sp + current->sas_ss_size; else newsp = regs->gpr[1]; newsp &= ~0xfUL; +#ifdef CONFIG_PPC64 /* * Reenable the DABR before delivering the signal to * user space. The DABR will have been cleared if it @@ -977,12 +1247,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) */ if (current->thread.dabr) set_dabr(current->thread.dabr); +#endif /* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags & SA_SIGINFO) - ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); + ret = handle_rt_signal(signr, &ka, &info, oldset, regs, newsp); else - ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp); + ret = handle_signal(signr, &ka, &info, oldset, regs, newsp); if (ret) { spin_lock_irq(¤t->sighand->siglock); diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 87d3be4af820..c178397c50af 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -13,7 +13,7 @@ extra-$(CONFIG_POWER4) += idle_power4.o extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ - process.o signal.o align.o \ + process.o align.o \ syscalls.o setup.o \ ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o @@ -38,7 +38,7 @@ endif else obj-y := irq.o idle.o time.o \ - signal.o align.o perfmon.o + align.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c deleted file mode 100644 index 2244bf91e593..000000000000 --- a/arch/ppc/kernel/signal.c +++ /dev/null @@ -1,771 +0,0 @@ -/* - * arch/ppc/kernel/signal.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/i386/kernel/signal.c" - * Copyright (C) 1991, 1992 Linus Torvalds - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * - * 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 - -#undef DEBUG_SIG - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -extern void sigreturn_exit(struct pt_regs *); - -#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) - -int do_signal(sigset_t *oldset, struct pt_regs *regs); - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -int -sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, - struct pt_regs *regs) -{ - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); - } -} - -int -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, - int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); - } -} - - -int -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5, - int r6, int r7, int r8, struct pt_regs *regs) -{ - return do_sigaltstack(uss, uoss, regs->gpr[1]); -} - -int -sys_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - 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; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, (act? &new_ka: NULL), (oact? &old_ka: NULL)); - - if (!ret && 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; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - -/* - * When we have signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * a sigregs struct - * a sigcontext struct - * a gap of __SIGNAL_FRAMESIZE bytes - * - * Each of these things must be a multiple of 16 bytes in size. - * - */ -struct sigregs { - struct mcontext mctx; /* all the register values */ - /* Programs using the rs6000/xcoff abi can save up to 19 gp regs - and 18 fp regs below sp before decrementing it. */ - int abigap[56]; -}; - -/* We use the mc_pad field for the signal return trampoline. */ -#define tramp mc_pad - -/* - * When we have rt signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * one rt_sigframe struct (siginfo + ucontext + ABI gap) - * a gap of __SIGNAL_FRAMESIZE+16 bytes - * (the +16 is to get the siginfo and ucontext in the same - * positions as in older kernels). - * - * Each of these things must be a multiple of 16 bytes in size. - * - */ -struct rt_sigframe -{ - struct siginfo info; - struct ucontext uc; - /* Programs using the rs6000/xcoff abi can save up to 19 gp regs - and 18 fp regs below sp before decrementing it. */ - int abigap[56]; -}; - -/* - * Save the current user registers on the user stack. - * We only save the altivec/spe registers if the process has used - * altivec/spe instructions at some point. - */ -static int -save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, int sigret) -{ - /* save general and floating-point registers */ - CHECK_FULL_REGS(regs); - preempt_disable(); - if (regs->msr & MSR_FP) - giveup_fpu(current); -#ifdef CONFIG_ALTIVEC - if (current->thread.used_vr && (regs->msr & MSR_VEC)) - giveup_altivec(current); -#endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_SPE - if (current->thread.used_spe && (regs->msr & MSR_SPE)) - giveup_spe(current); -#endif /* CONFIG_ALTIVEC */ - preempt_enable(); - - if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE) - || __copy_to_user(&frame->mc_fregs, current->thread.fpr, - ELF_NFPREG * sizeof(double))) - return 1; - - current->thread.fpscr = 0; /* turn off all fp exceptions */ - -#ifdef CONFIG_ALTIVEC - /* save altivec registers */ - if (current->thread.used_vr) { - if (__copy_to_user(&frame->mc_vregs, current->thread.vr, - ELF_NVRREG * sizeof(vector128))) - return 1; - /* set MSR_VEC in the saved MSR value to indicate that - frame->mc_vregs contains valid data */ - if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR])) - return 1; - } - /* else assert((regs->msr & MSR_VEC) == 0) */ - - /* We always copy to/from vrsave, it's 0 if we don't have or don't - * use altivec. Since VSCR only contains 32 bits saved in the least - * significant bits of a vector, we "cheat" and stuff VRSAVE in the - * most significant bits of that same vector. --BenH - */ - if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) - return 1; -#endif /* CONFIG_ALTIVEC */ - -#ifdef CONFIG_SPE - /* save spe registers */ - if (current->thread.used_spe) { - if (__copy_to_user(&frame->mc_vregs, current->thread.evr, - ELF_NEVRREG * sizeof(u32))) - return 1; - /* set MSR_SPE in the saved MSR value to indicate that - frame->mc_vregs contains valid data */ - if (__put_user(regs->msr | MSR_SPE, &frame->mc_gregs[PT_MSR])) - return 1; - } - /* else assert((regs->msr & MSR_SPE) == 0) */ - - /* We always copy to/from spefscr */ - if (__put_user(current->thread.spefscr, (u32 *)&frame->mc_vregs + ELF_NEVRREG)) - return 1; -#endif /* CONFIG_SPE */ - - if (sigret) { - /* Set up the sigreturn trampoline: li r0,sigret; sc */ - if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) - || __put_user(0x44000002UL, &frame->tramp[1])) - return 1; - flush_icache_range((unsigned long) &frame->tramp[0], - (unsigned long) &frame->tramp[2]); - } - - return 0; -} - -/* - * Restore the current user register values from the user stack, - * (except for MSR). - */ -static int -restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig) -{ - unsigned long save_r2 = 0; -#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE) - unsigned long msr; -#endif - - /* backup/restore the TLS as we don't want it to be modified */ - if (!sig) - save_r2 = regs->gpr[2]; - /* copy up to but not including MSR */ - if (__copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t))) - return 1; - /* copy from orig_r3 (the word after the MSR) up to the end */ - if (__copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3], - GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t))) - return 1; - if (!sig) - regs->gpr[2] = save_r2; - - /* force the process to reload the FP registers from - current->thread when it next does FP instructions */ - regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); - if (__copy_from_user(current->thread.fpr, &sr->mc_fregs, - sizeof(sr->mc_fregs))) - return 1; - -#ifdef CONFIG_ALTIVEC - /* 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) { - /* restore altivec registers from the stack */ - if (__copy_from_user(current->thread.vr, &sr->mc_vregs, - sizeof(sr->mc_vregs))) - return 1; - } else if (current->thread.used_vr) - memset(¤t->thread.vr, 0, ELF_NVRREG * sizeof(vector128)); - - /* Always get VRSAVE back */ - if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) - return 1; -#endif /* CONFIG_ALTIVEC */ - -#ifdef CONFIG_SPE - /* 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) { - /* restore spe registers from the stack */ - if (__copy_from_user(current->thread.evr, &sr->mc_vregs, - ELF_NEVRREG * sizeof(u32))) - return 1; - } else if (current->thread.used_spe) - memset(¤t->thread.evr, 0, ELF_NEVRREG * sizeof(u32)); - - /* Always get SPEFSCR back */ - if (__get_user(current->thread.spefscr, (u32 *)&sr->mc_vregs + ELF_NEVRREG)) - return 1; -#endif /* CONFIG_SPE */ - -#ifndef CONFIG_SMP - preempt_disable(); - if (last_task_used_math == current) - last_task_used_math = NULL; - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; - if (last_task_used_spe == current) - last_task_used_spe = NULL; - preempt_enable(); -#endif - return 0; -} - -/* - * Restore the user process's signal mask - */ -static void -restore_sigmask(sigset_t *set) -{ - sigdelsetmask(set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); -} - -/* - * Set up a signal frame for a "real-time" signal handler - * (one which gets siginfo). - */ -static void -handle_rt_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, - unsigned long newsp) -{ - struct rt_sigframe __user *rt_sf; - struct mcontext __user *frame; - unsigned long origsp = newsp; - - /* Set up Signal Frame */ - /* Put a Real Time Context onto stack */ - newsp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe __user *) newsp; - - /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE + 16; - - if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) - goto badframe; - - /* Put the siginfo & fill in most of the ucontext */ - if (copy_siginfo_to_user(&rt_sf->info, info) - || __put_user(0, &rt_sf->uc.uc_flags) - || __put_user(0, &rt_sf->uc.uc_link) - || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) - || __put_user(sas_ss_flags(regs->gpr[1]), - &rt_sf->uc.uc_stack.ss_flags) - || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) - || __put_user(&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs) - || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))) - goto badframe; - - /* Save user registers on the stack */ - frame = &rt_sf->uc.uc_mcontext; - if (save_user_regs(regs, frame, __NR_rt_sigreturn)) - goto badframe; - - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) - goto badframe; - regs->gpr[1] = newsp; - regs->gpr[3] = sig; - regs->gpr[4] = (unsigned long) &rt_sf->info; - regs->gpr[5] = (unsigned long) &rt_sf->uc; - regs->gpr[6] = (unsigned long) rt_sf; - regs->nip = (unsigned long) ka->sa.sa_handler; - regs->link = (unsigned long) frame->tramp; - regs->trap = 0; - - return; - -badframe: -#ifdef DEBUG_SIG - printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); -#endif - force_sigsegv(sig, current); -} - -static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig) -{ - sigset_t set; - struct mcontext __user *mcp; - - if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set)) - || __get_user(mcp, &ucp->uc_regs)) - return -EFAULT; - restore_sigmask(&set); - if (restore_user_regs(regs, mcp, sig)) - return -EFAULT; - - return 0; -} - -int sys_swapcontext(struct ucontext __user *old_ctx, - struct ucontext __user *new_ctx, - int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) -{ - unsigned char tmp; - - /* Context size is for future use. Right now, we only make sure - * we are passed something we understand - */ - if (ctx_size < sizeof(struct ucontext)) - return -EINVAL; - - if (old_ctx != NULL) { - if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) - || save_user_regs(regs, &old_ctx->uc_mcontext, 0) - || __copy_to_user(&old_ctx->uc_sigmask, - ¤t->blocked, sizeof(sigset_t)) - || __put_user(&old_ctx->uc_mcontext, &old_ctx->uc_regs)) - return -EFAULT; - } - if (new_ctx == NULL) - return 0; - if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) - || __get_user(tmp, (u8 __user *) new_ctx) - || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) - return -EFAULT; - - /* - * If we get a fault copying the context into the kernel's - * image of the user's registers, we can't just return -EFAULT - * because the user's registers will be corrupted. For instance - * the NIP value may have been updated but not some of the - * other registers. Given that we have done the access_ok - * and successfully read the first and last bytes of the region - * above, this should only happen in an out-of-memory situation - * or if another thread unmaps the region containing the context. - * We kill the task with a SIGSEGV in this situation. - */ - if (do_setcontext(new_ctx, regs, 0)) - do_exit(SIGSEGV); - sigreturn_exit(regs); - /* doesn't actually return back to here */ - return 0; -} - -int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) -{ - struct rt_sigframe __user *rt_sf; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - rt_sf = (struct rt_sigframe __user *) - (regs->gpr[1] + __SIGNAL_FRAMESIZE + 16); - if (!access_ok(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe))) - goto bad; - if (do_setcontext(&rt_sf->uc, regs, 1)) - goto bad; - - /* - * It's not clear whether or why it is desirable to save the - * sigaltstack setting on signal delivery and restore it on - * signal return. But other architectures do this and we have - * always done it up until now so it is probably better not to - * change it. -- paulus - */ - do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); - - sigreturn_exit(regs); /* doesn't return here */ - return 0; - - bad: - force_sig(SIGSEGV, current); - return 0; -} - -int sys_debug_setcontext(struct ucontext __user *ctx, - int ndbg, struct sig_dbg_op __user *dbg, - int r6, int r7, int r8, - struct pt_regs *regs) -{ - struct sig_dbg_op op; - int i; - unsigned long new_msr = regs->msr; -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - unsigned long new_dbcr0 = current->thread.dbcr0; -#endif - - for (i=0; imsr = new_msr; -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - current->thread.dbcr0 = new_dbcr0; -#endif - - /* - * If we get a fault copying the context into the kernel's - * image of the user's registers, we can't just return -EFAULT - * because the user's registers will be corrupted. For instance - * the NIP value may have been updated but not some of the - * other registers. Given that we have done the access_ok - * and successfully read the first and last bytes of the region - * above, this should only happen in an out-of-memory situation - * or if another thread unmaps the region containing the context. - * We kill the task with a SIGSEGV in this situation. - */ - if (do_setcontext(ctx, regs, 1)) { - force_sig(SIGSEGV, current); - goto out; - } - - /* - * It's not clear whether or why it is desirable to save the - * sigaltstack setting on signal delivery and restore it on - * signal return. But other architectures do this and we have - * always done it up until now so it is probably better not to - * change it. -- paulus - */ - do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); - - sigreturn_exit(regs); - /* doesn't actually return back to here */ - - out: - return 0; -} - -/* - * OK, we're invoking a handler - */ -static void -handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, - unsigned long newsp) -{ - struct sigcontext __user *sc; - struct sigregs __user *frame; - unsigned long origsp = newsp; - - /* Set up Signal Frame */ - newsp -= sizeof(struct sigregs); - frame = (struct sigregs __user *) newsp; - - /* Put a sigcontext on the stack */ - newsp -= sizeof(*sc); - sc = (struct sigcontext __user *) newsp; - - /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE; - - if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) - goto badframe; - -#if _NSIG != 64 -#error "Please adjust handle_signal()" -#endif - if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) - || __put_user(oldset->sig[1], &sc->_unused[3]) - || __put_user((struct pt_regs __user *)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; - - if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) - goto badframe; - - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) - goto badframe; - regs->gpr[1] = newsp; - regs->gpr[3] = sig; - regs->gpr[4] = (unsigned long) sc; - regs->nip = (unsigned long) ka->sa.sa_handler; - regs->link = (unsigned long) frame->mctx.tramp; - regs->trap = 0; - - return; - -badframe: -#ifdef DEBUG_SIG - printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); -#endif - force_sigsegv(sig, current); -} - -/* - * Do a signal return; undo the signal stack. - */ -int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) -{ - struct sigcontext __user *sc; - struct sigcontext sigctx; - struct mcontext __user *sr; - sigset_t set; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); - if (copy_from_user(&sigctx, sc, sizeof(sigctx))) - goto badframe; - - set.sig[0] = sigctx.oldmask; - set.sig[1] = sigctx._unused[3]; - restore_sigmask(&set); - - sr = (struct mcontext __user *) sigctx.regs; - if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) - || restore_user_regs(regs, sr, 1)) - goto badframe; - - sigreturn_exit(regs); /* doesn't return */ - return 0; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ -int do_signal(sigset_t *oldset, struct pt_regs *regs) -{ - siginfo_t info; - struct k_sigaction ka; - unsigned long frame, newsp; - int signr, ret; - - if (try_to_freeze()) { - signr = 0; - if (!signal_pending(current)) - goto no_signal; - } - - if (!oldset) - oldset = ¤t->blocked; - - newsp = frame = 0; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - no_signal: - if (TRAP(regs) == 0x0C00 /* System Call! */ - && regs->ccr & 0x10000000 /* error signalled */ - && ((ret = regs->gpr[3]) == ERESTARTSYS - || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR - || ret == ERESTART_RESTARTBLOCK)) { - - if (signr > 0 - && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK - || (ret == ERESTARTSYS - && !(ka.sa.sa_flags & SA_RESTART)))) { - /* make the system call return an EINTR error */ - regs->result = -EINTR; - regs->gpr[3] = EINTR; - /* note that the cr0.SO bit is already set */ - } else { - regs->nip -= 4; /* Back up & retry system call */ - regs->result = 0; - regs->trap = 0; - if (ret == ERESTART_RESTARTBLOCK) - regs->gpr[0] = __NR_restart_syscall; - else - regs->gpr[3] = regs->orig_gpr3; - } - } - - if (signr == 0) - return 0; /* no signals delivered */ - - if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size - && !on_sig_stack(regs->gpr[1])) - newsp = current->sas_ss_sp + current->sas_ss_size; - else - newsp = regs->gpr[1]; - newsp &= ~0xfUL; - - /* Whee! Actually deliver the signal. */ - if (ka.sa.sa_flags & SA_SIGINFO) - handle_rt_signal(signr, &ka, &info, oldset, regs, newsp); - else - handle_signal(signr, &ka, &info, oldset, regs, newsp); - - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - return 1; -} - diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 0be7c7ecefdf..19846d78b329 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -15,7 +15,7 @@ obj-y += irq.o idle.o dma.o \ time.o signal.o \ align.o bitops.o pacaData.o \ udbg.o ioctl32.o \ - ptrace32.o signal32.o rtc.o \ + ptrace32.o rtc.o \ cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o obj-y += vdso32/ vdso64/ diff --git a/include/asm-ppc64/ppc32.h b/include/asm-ppc64/ppc32.h index 6b44a8caf395..3945a55d112a 100644 --- a/include/asm-ppc64/ppc32.h +++ b/include/asm-ppc64/ppc32.h @@ -70,18 +70,18 @@ typedef struct compat_siginfo { #define __old_sigaction32 old_sigaction32 struct __old_sigaction32 { - unsigned sa_handler; + compat_uptr_t sa_handler; compat_old_sigset_t sa_mask; unsigned int sa_flags; - unsigned sa_restorer; /* not used by Linux/SPARC yet */ + compat_uptr_t sa_restorer; /* not used by Linux/SPARC yet */ }; struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ + compat_uptr_t sa_handler; /* Really a pointer, but need to deal with 32 bits */ unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ + compat_uptr_t sa_restorer; /* Another 32 bit pointer */ compat_sigset_t sa_mask; /* A 32 bit mask */ }; @@ -94,9 +94,9 @@ typedef struct sigaltstack_32 { struct sigcontext32 { unsigned int _unused[4]; int signal; - unsigned int handler; + compat_uptr_t handler; unsigned int oldmask; - u32 regs; /* 4 byte pointer to the pt_regs32 structure. */ + compat_uptr_t regs; /* 4 byte pointer to the pt_regs32 structure. */ }; struct mcontext32 { @@ -111,7 +111,7 @@ struct ucontext32 { unsigned int uc_link; stack_32_t uc_stack; int uc_pad[7]; - u32 uc_regs; /* points to uc_mcontext field */ + compat_uptr_t uc_regs; /* points to uc_mcontext field */ compat_sigset_t uc_sigmask; /* mask last for extensibility */ /* glibc has 1024-bit signal masks, ours are 64-bit */ int uc_maskext[30]; From 77f543cb467c44960bafa6c91f5af75919d693e4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 18 Oct 2005 14:19:41 +1000 Subject: [PATCH 0428/1939] powerpc: Fix various compile errors with ARCH=ppc, ppc64 and powerpc This makes ppc use the syscalls.c from arch/powerpc/kernel, exports copy_and_flush from head_32.S for use by prom_init.c (ARCH=powerpc), and consolidates the sys_fadvise64_64 implementations for 32-bit. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 1 - arch/powerpc/kernel/Makefile | 10 +++++----- arch/powerpc/kernel/head_32.S | 2 +- arch/powerpc/kernel/sys_ppc32.c | 7 ------- arch/powerpc/kernel/syscalls.c | 7 +++++++ arch/powerpc/kernel/systbl.S | 2 +- arch/ppc/kernel/Makefile | 2 +- arch/ppc64/kernel/misc.S | 2 +- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a5f2eb5f89ce..29cda0732703 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -121,7 +121,6 @@ head-$(CONFIG_4xx) := arch/powerpc/kernel/head_4xx.o head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o -head-$(CONFIG_6xx) += arch/powerpc/kernel/idle_6xx.o head-$(CONFIG_PPC64) += arch/powerpc/kernel/entry_64.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 043ddd09521d..01b6d630edc9 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,7 +10,8 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o cputable.o ptrace.o signal_32.o +obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ + signal_32.o obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o @@ -24,14 +25,13 @@ extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o -extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_PPC64) += entry_64.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y += process.o init_task.o \ - prom.o systbl.o traps.o syscalls.o -obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o + prom.o systbl.o traps.o +obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o @@ -44,7 +44,7 @@ endif else # stuff used from here for ARCH=ppc or ARCH=ppc64 -obj-$(CONFIG_PPC64) += traps.o process.o init_task.o syscalls.o +obj-$(CONFIG_PPC64) += traps.o process.o init_task.o fpux-$(CONFIG_PPC32) += fpu.o extra-$(CONFIG_PPC_FPU) += $(fpux-y) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 7ef9a3e3002b..cd51fe585fcd 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -831,7 +831,7 @@ relocate_kernel: * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. */ -copy_and_flush: +_GLOBAL(copy_and_flush) addi r5,r5,-4 addi r6,r6,-4 4: li r0,L1_CACHE_BYTES/4 diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 9babe055356e..2f1e41a82876 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -1069,13 +1069,6 @@ long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low, advice); } -long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, - u32 len_high, u32 len_low) -{ - return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, - (u64)len_high << 32 | len_low, advice); -} - long ppc32_timer_create(clockid_t clock, struct compat_sigevent __user *ev32, timer_t __user *timer_id) diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 3e3a4f67de96..7a23721365a6 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -336,6 +336,13 @@ time_t sys64_time(time_t __user * tloc) } #endif +long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, + u32 len_high, u32 len_low) +{ + return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, + (u64)len_high << 32 | len_low, advice); +} + void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index b364141ec01c..1b807f79d5da 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -297,7 +297,7 @@ SYSCALL32(tgkill) SYSCALL32(utimes) COMPAT_SYS(statfs64) COMPAT_SYS(fstatfs64) -SYSX(sys_ni_syscall, ppc32_fadvise64_64, sys_fadvise64_64) +SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64) PPC_SYS(rtas) OLDSYS(debug_setcontext) SYSCALL(ni_syscall) diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index c178397c50af..5a742c7b0509 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -14,7 +14,7 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o align.o \ - syscalls.o setup.o \ + setup.o \ ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index eb407c429bb0..755d73f222e2 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -1175,7 +1175,7 @@ _GLOBAL(sys_call_table32) .llong .sys32_utimes .llong .compat_sys_statfs64 .llong .compat_sys_fstatfs64 - .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ + .llong .ppc_fadvise64_64 /* 32bit only fadvise64_64 */ .llong .ppc_rtas /* 255 */ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ .llong .sys_ni_syscall /* 257 reserved for vserver */ From b09a4913b15d2544f8918f05b9937cb4e99a2319 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 18 Oct 2005 14:51:57 +1000 Subject: [PATCH 0429/1939] powerpc: change sys32_ to compat_sys_ This allows us to get rid of one type of entry in systbl.S. In passing we remove the duplicate compat_sys_getdents and compat_sys_utimes for which there are generic versions. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/entry_64.S | 10 +- arch/powerpc/kernel/signal_32.c | 28 ++--- arch/powerpc/kernel/sys_ppc32.c | 216 ++++++++------------------------ arch/powerpc/kernel/systbl.S | 116 +++++++++-------- arch/ppc64/kernel/entry.S | 10 +- arch/ppc64/kernel/misc.S | 122 +++++++++--------- arch/ppc64/kernel/ptrace32.c | 2 +- 7 files changed, 195 insertions(+), 309 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 22796e28881a..984a10630714 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -262,7 +262,7 @@ _GLOBAL(save_nvgprs) */ _GLOBAL(ppc32_sigsuspend) bl .save_nvgprs - bl .sys32_sigsuspend + bl .compat_sys_sigsuspend b 70f _GLOBAL(ppc64_rt_sigsuspend) @@ -272,7 +272,7 @@ _GLOBAL(ppc64_rt_sigsuspend) _GLOBAL(ppc32_rt_sigsuspend) bl .save_nvgprs - bl .sys32_rt_sigsuspend + bl .compat_sys_rt_sigsuspend 70: cmpdi 0,r3,0 /* If it returned an error, we need to return via syscall_exit to set the SO bit in cr0 and potentially stop for ptrace. */ @@ -307,7 +307,7 @@ _GLOBAL(ppc_clone) _GLOBAL(ppc32_swapcontext) bl .save_nvgprs - bl .sys32_swapcontext + bl .compat_sys_swapcontext b 80f _GLOBAL(ppc64_swapcontext) @@ -316,11 +316,11 @@ _GLOBAL(ppc64_swapcontext) b 80f _GLOBAL(ppc32_sigreturn) - bl .sys32_sigreturn + bl .compat_sys_sigreturn b 80f _GLOBAL(ppc32_rt_sigreturn) - bl .sys32_rt_sigreturn + bl .compat_sys_rt_sigreturn b 80f _GLOBAL(ppc64_rt_sigreturn) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index e53127ec373d..e7e7aac11f89 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -58,12 +58,12 @@ #ifdef CONFIG_PPC64 #define do_signal do_signal32 -#define sys_sigsuspend sys32_sigsuspend -#define sys_rt_sigsuspend sys32_rt_sigsuspend -#define sys_rt_sigreturn sys32_rt_sigreturn -#define sys_sigaction sys32_sigaction -#define sys_swapcontext sys32_swapcontext -#define sys_sigreturn sys32_sigreturn +#define sys_sigsuspend compat_sys_sigsuspend +#define sys_rt_sigsuspend compat_sys_rt_sigsuspend +#define sys_rt_sigreturn compat_sys_rt_sigreturn +#define sys_sigaction compat_sys_sigaction +#define sys_swapcontext compat_sys_swapcontext +#define sys_sigreturn compat_sys_sigreturn #define old_sigaction old_sigaction32 #define sigcontext sigcontext32 @@ -540,7 +540,7 @@ static long restore_user_regs(struct pt_regs *regs, } #ifdef CONFIG_PPC64 -long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, +long compat_sys_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; @@ -577,7 +577,7 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, * of a signed int (msr in 32-bit mode) and the register representation * of a signed int (msr in 64-bit mode) is performed. */ -long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set, +long compat_sys_rt_sigprocmask(u32 how, compat_sigset_t __user *set, compat_sigset_t __user *oset, size_t sigsetsize) { sigset_t s; @@ -605,7 +605,7 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set, return 0; } -long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) +long compat_sys_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) { sigset_t s; int ret; @@ -687,7 +687,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s) * (msr in 32-bit mode) and the register representation of a signed int * (msr in 64-bit mode) is performed. */ -long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) +long compat_sys_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) { siginfo_t info; int ret; @@ -706,10 +706,10 @@ long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) * Start Alternate signal stack support * * System Calls - * sigaltatck sys32_sigaltstack + * sigaltatck compat_sys_sigaltstack */ -int sys32_sigaltstack(u32 __new, u32 __old, int r5, +int compat_sys_sigaltstack(u32 __new, u32 __old, int r5, int r6, int r7, int r8, struct pt_regs *regs) { stack_32_t __user * newstack = (stack_32_t __user *)(long) __new; @@ -942,11 +942,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, */ #ifdef CONFIG_PPC64 /* - * We use the sys32_ version that does the 32/64 bits conversion + * We use the compat_sys_ version that does the 32/64 bits conversion * and takes userland pointer directly. What about error checking ? * nobody does any... */ - sys32_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); + compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); return (int)regs->result; #else do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 9babe055356e..501333f89d23 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -113,96 +113,6 @@ asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user * return error; } -struct linux_dirent32 { - u32 d_ino; - u32 d_off; - unsigned short d_reclen; - char d_name[1]; -}; - -struct getdents_callback32 { - struct linux_dirent32 __user * current_dir; - struct linux_dirent32 __user * previous; - int count; - int error; -}; - -static int filldir(void * __buf, const char * name, int namlen, off_t offset, - ino_t ino, unsigned int d_type) -{ - struct linux_dirent32 __user * dirent; - struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf; - int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); - - buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; - dirent = buf->previous; - if (dirent) { - if (__put_user(offset, &dirent->d_off)) - goto efault; - } - dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) - goto efault; - if (copy_to_user(dirent->d_name, name, namlen)) - goto efault; - if (__put_user(0, dirent->d_name + namlen)) - goto efault; - if (__put_user(d_type, (char __user *) dirent + reclen - 1)) - goto efault; - buf->previous = dirent; - dirent = (void __user *)dirent + reclen; - buf->current_dir = dirent; - buf->count -= reclen; - return 0; -efault: - buf->error = -EFAULT; - return -EFAULT; -} - -asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 __user *dirent, - unsigned int count) -{ - struct file * file; - struct linux_dirent32 __user * lastdirent; - struct getdents_callback32 buf; - int error; - - error = -EFAULT; - if (!access_ok(VERIFY_WRITE, dirent, count)) - goto out; - - error = -EBADF; - file = fget(fd); - if (!file) - goto out; - - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(file, (filldir_t)filldir, &buf); - if (error < 0) - goto out_putf; - error = buf.error; - lastdirent = buf.previous; - if (lastdirent) { - if (put_user(file->f_pos, &lastdirent->d_off)) - error = -EFAULT; - else - error = count - buf.count; - } - -out_putf: - fput(file); -out: - return error; -} - asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, compat_uptr_t tvp_x) @@ -247,7 +157,7 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2) +asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2) { return sys_sysfs((int)option, arg1, arg2); } @@ -269,7 +179,7 @@ struct timex32 { extern int do_adjtimex(struct timex *); extern void ppc_adjtimex(void); -asmlinkage long sys32_adjtimex(struct timex32 __user *utp) +asmlinkage long compat_sys_adjtimex(struct timex32 __user *utp) { struct timex txc; int ret; @@ -328,7 +238,7 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp) return ret; } -asmlinkage long sys32_pause(void) +asmlinkage long compat_sys_pause(void) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -374,7 +284,7 @@ struct sysinfo32 { char _f[20-2*sizeof(int)-sizeof(int)]; }; -asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) +asmlinkage long compat_sys_sysinfo(struct sysinfo32 __user *info) { struct sysinfo s; int ret, err; @@ -431,7 +341,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) sorts of things, like timeval and itimerval. */ extern struct timezone sys_tz; -asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) +asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { if (tv) { struct timeval ktv; @@ -449,7 +359,7 @@ asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct time -asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) +asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { struct timespec kts; struct timezone ktz; @@ -467,7 +377,7 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct time } #ifdef CONFIG_SYSVIPC -long sys32_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, +long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth) { int version; @@ -538,7 +448,7 @@ long sys32_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count) +asmlinkage long compat_sys_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -560,7 +470,7 @@ asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offs return ret; } -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) +asmlinkage int compat_sys_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -582,7 +492,7 @@ asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *off return ret; } -long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2, +long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs *regs) { @@ -614,7 +524,7 @@ long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2, * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) { return sys_prctl((int)option, (unsigned long) arg2, @@ -628,7 +538,7 @@ asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval) +asmlinkage long compat_sys_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval) { struct timespec t; int ret; @@ -643,7 +553,7 @@ asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec __us return ret; } -asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +asmlinkage int compat_sys_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) { return sys_pciconfig_read((unsigned long) bus, (unsigned long) dfn, @@ -652,7 +562,7 @@ asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf compat_ptr(ubuf)); } -asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +asmlinkage int compat_sys_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) { return sys_pciconfig_write((unsigned long) bus, (unsigned long) dfn, @@ -661,7 +571,7 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu compat_ptr(ubuf)); } -asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) +asmlinkage int compat_sys_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) { return sys_pciconfig_iobase(which, in_bus, in_devfn); } @@ -672,7 +582,7 @@ asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_access(const char __user * filename, u32 mode) +asmlinkage long compat_sys_access(const char __user * filename, u32 mode) { return sys_access(filename, (int)mode); } @@ -683,7 +593,7 @@ asmlinkage long sys32_access(const char __user * filename, u32 mode) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_creat(const char __user * pathname, u32 mode) +asmlinkage long compat_sys_creat(const char __user * pathname, u32 mode) { return sys_creat(pathname, (int)mode); } @@ -694,7 +604,7 @@ asmlinkage long sys32_creat(const char __user * pathname, u32 mode) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options) +asmlinkage long compat_sys_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options) { return sys_waitpid((int)pid, stat_addr, (int)options); } @@ -705,7 +615,7 @@ asmlinkage long sys32_waitpid(u32 pid, unsigned int __user * stat_addr, u32 opti * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t __user *grouplist) +asmlinkage long compat_sys_getgroups(u32 gidsetsize, gid_t __user *grouplist) { return sys_getgroups((int)gidsetsize, grouplist); } @@ -716,7 +626,7 @@ asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t __user *grouplist) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_getpgid(u32 pid) +asmlinkage long compat_sys_getpgid(u32 pid) { return sys_getpgid((int)pid); } @@ -728,7 +638,7 @@ asmlinkage long sys32_getpgid(u32 pid) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_getsid(u32 pid) +asmlinkage long compat_sys_getsid(u32 pid) { return sys_getsid((int)pid); } @@ -739,7 +649,7 @@ asmlinkage long sys32_getsid(u32 pid) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_kill(u32 pid, u32 sig) +asmlinkage long compat_sys_kill(u32 pid, u32 sig) { return sys_kill((int)pid, (int)sig); } @@ -750,12 +660,12 @@ asmlinkage long sys32_kill(u32 pid, u32 sig) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_mkdir(const char __user * pathname, u32 mode) +asmlinkage long compat_sys_mkdir(const char __user * pathname, u32 mode) { return sys_mkdir(pathname, (int)mode); } -long sys32_nice(u32 increment) +long compat_sys_nice(u32 increment) { /* sign extend increment */ return sys_nice((int)increment); @@ -772,7 +682,7 @@ off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_readlink(const char __user * path, char __user * buf, u32 bufsiz) +asmlinkage long compat_sys_readlink(const char __user * path, char __user * buf, u32 bufsiz) { return sys_readlink(path, buf, (int)bufsiz); } @@ -782,7 +692,7 @@ asmlinkage long sys32_readlink(const char __user * path, char __user * buf, u32 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_get_priority_max(u32 policy) +asmlinkage long compat_sys_sched_get_priority_max(u32 policy) { return sys_sched_get_priority_max((int)policy); } @@ -793,7 +703,7 @@ asmlinkage long sys32_sched_get_priority_max(u32 policy) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_get_priority_min(u32 policy) +asmlinkage long compat_sys_sched_get_priority_min(u32 policy) { return sys_sched_get_priority_min((int)policy); } @@ -804,7 +714,7 @@ asmlinkage long sys32_sched_get_priority_min(u32 policy) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param __user *param) +asmlinkage long compat_sys_sched_getparam(u32 pid, struct sched_param __user *param) { return sys_sched_getparam((int)pid, param); } @@ -815,7 +725,7 @@ asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param __user *param) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_getscheduler(u32 pid) +asmlinkage long compat_sys_sched_getscheduler(u32 pid) { return sys_sched_getscheduler((int)pid); } @@ -826,7 +736,7 @@ asmlinkage long sys32_sched_getscheduler(u32 pid) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param __user *param) +asmlinkage long compat_sys_sched_setparam(u32 pid, struct sched_param __user *param) { return sys_sched_setparam((int)pid, param); } @@ -837,7 +747,7 @@ asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param __user *param) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param) +asmlinkage long compat_sys_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param) { return sys_sched_setscheduler((int)pid, (int)policy, param); } @@ -848,7 +758,7 @@ asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_setdomainname(char __user *name, u32 len) +asmlinkage long compat_sys_setdomainname(char __user *name, u32 len) { return sys_setdomainname(name, (int)len); } @@ -859,13 +769,13 @@ asmlinkage long sys32_setdomainname(char __user *name, u32 len) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t __user *grouplist) +asmlinkage long compat_sys_setgroups(u32 gidsetsize, gid_t __user *grouplist) { return sys_setgroups((int)gidsetsize, grouplist); } -asmlinkage long sys32_sethostname(char __user *name, u32 len) +asmlinkage long compat_sys_sethostname(char __user *name, u32 len) { /* sign extend len */ return sys_sethostname(name, (int)len); @@ -877,30 +787,30 @@ asmlinkage long sys32_sethostname(char __user *name, u32 len) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_setpgid(u32 pid, u32 pgid) +asmlinkage long compat_sys_setpgid(u32 pid, u32 pgid) { return sys_setpgid((int)pid, (int)pgid); } -long sys32_getpriority(u32 which, u32 who) +long compat_sys_getpriority(u32 which, u32 who) { /* sign extend which and who */ return sys_getpriority((int)which, (int)who); } -long sys32_setpriority(u32 which, u32 who, u32 niceval) +long compat_sys_setpriority(u32 which, u32 who, u32 niceval) { /* sign extend which, who and niceval */ return sys_setpriority((int)which, (int)who, (int)niceval); } -long sys32_ioprio_get(u32 which, u32 who) +long compat_sys_ioprio_get(u32 which, u32 who) { /* sign extend which and who */ return sys_ioprio_get((int)which, (int)who); } -long sys32_ioprio_set(u32 which, u32 who, u32 ioprio) +long compat_sys_ioprio_set(u32 which, u32 who, u32 ioprio) { /* sign extend which, who and ioprio */ return sys_ioprio_set((int)which, (int)who, (int)ioprio); @@ -911,12 +821,12 @@ long sys32_ioprio_set(u32 which, u32 who, u32 ioprio) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_ssetmask(u32 newmask) +asmlinkage long compat_sys_ssetmask(u32 newmask) { return sys_ssetmask((int) newmask); } -asmlinkage long sys32_syslog(u32 type, char __user * buf, u32 len) +asmlinkage long compat_sys_syslog(u32 type, char __user * buf, u32 len) { /* sign extend len */ return sys_syslog(type, buf, (int)len); @@ -928,7 +838,7 @@ asmlinkage long sys32_syslog(u32 type, char __user * buf, u32 len) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */ -asmlinkage long sys32_umask(u32 mask) +asmlinkage long compat_sys_umask(u32 mask) { return sys_umask((int)mask); } @@ -944,7 +854,7 @@ struct __sysctl_args32 { u32 __unused[4]; }; -asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) +asmlinkage long compat_sys_sysctl(struct __sysctl_args32 __user *args) { struct __sysctl_args32 tmp; int error; @@ -985,7 +895,7 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) } #endif -unsigned long sys32_mmap2(unsigned long addr, size_t len, +unsigned long compat_sys_mmap2(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { @@ -993,29 +903,7 @@ unsigned long sys32_mmap2(unsigned long addr, size_t len, return sys_mmap(addr, len, prot, flags, fd, pgoff << 12); } -int get_compat_timeval(struct timeval *tv, struct compat_timeval __user *ctv) -{ - return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || - __get_user(tv->tv_sec, &ctv->tv_sec) || - __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; -} - -asmlinkage long sys32_utimes(char __user *filename, struct compat_timeval __user *tvs) -{ - struct timeval ktvs[2], *ptr; - - ptr = NULL; - if (tvs) { - if (get_compat_timeval(&ktvs[0], &tvs[0]) || - get_compat_timeval(&ktvs[1], &tvs[1])) - return -EFAULT; - ptr = ktvs; - } - - return do_utimes(filename, ptr); -} - -long sys32_tgkill(u32 tgid, u32 pid, int sig) +long compat_sys_tgkill(u32 tgid, u32 pid, int sig) { /* sign extend tgid, pid */ return sys_tgkill((int)tgid, (int)pid, sig); @@ -1026,30 +914,30 @@ long sys32_tgkill(u32 tgid, u32 pid, int sig) * The 32 bit ABI passes long longs in an odd even register pair. */ -compat_ssize_t sys32_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, +compat_ssize_t compat_sys_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, u32 reg6, u32 poshi, u32 poslo) { return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); } -compat_ssize_t sys32_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count, +compat_ssize_t compat_sys_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count, u32 reg6, u32 poshi, u32 poslo) { return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); } -compat_ssize_t sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count) +compat_ssize_t compat_sys_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count) { return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count); } -asmlinkage int sys32_truncate64(const char __user * path, u32 reg4, +asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4, unsigned long high, unsigned long low) { return sys_truncate(path, (high << 32) | low); } -asmlinkage int sys32_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, +asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, unsigned long low) { return sys_ftruncate(fd, (high << 32) | low); @@ -1108,7 +996,7 @@ long ppc32_timer_create(clockid_t clock, return err; } -asmlinkage long sys32_add_key(const char __user *_type, +asmlinkage long compat_sys_add_key(const char __user *_type, const char __user *_description, const void __user *_payload, u32 plen, @@ -1117,7 +1005,7 @@ asmlinkage long sys32_add_key(const char __user *_type, return sys_add_key(_type, _description, _payload, plen, ringid); } -asmlinkage long sys32_request_key(const char __user *_type, +asmlinkage long compat_sys_request_key(const char __user *_type, const char __user *_description, const char __user *_callout_info, u32 destringid) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index b364141ec01c..2103f78f6445 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -19,15 +19,13 @@ #ifdef CONFIG_PPC64 #define SYSCALL(func) .llong .sys_##func,.sys_##func -#define SYSCALL32(func) .llong .sys_##func,.sys32_##func #define COMPAT_SYS(func) .llong .sys_##func,.compat_sys_##func #define PPC_SYS(func) .llong .ppc_##func,.ppc_##func #define OLDSYS(func) .llong .sys_ni_syscall,.sys_ni_syscall -#define SYS32ONLY(func) .llong .sys_ni_syscall,.sys32_##func +#define SYS32ONLY(func) .llong .sys_ni_syscall,.compat_sys_##func #define SYSX(f, f3264, f32) .llong .f,.f3264 #else #define SYSCALL(func) .long sys_##func -#define SYSCALL32(func) .long sys_##func #define COMPAT_SYS(func) .long sys_##func #define PPC_SYS(func) .long ppc_##func #define OLDSYS(func) .long sys_##func @@ -50,11 +48,11 @@ SYSCALL(read) SYSCALL(write) COMPAT_SYS(open) SYSCALL(close) -SYSCALL32(waitpid) -SYSCALL32(creat) +COMPAT_SYS(waitpid) +COMPAT_SYS(creat) SYSCALL(link) SYSCALL(unlink) -SYSCALL32(execve) +COMPAT_SYS(execve) SYSCALL(chdir) SYSX(sys64_time,compat_sys_time,sys_time) SYSCALL(mknod) @@ -69,20 +67,20 @@ SYSX(sys_ni_syscall,sys_oldumount,sys_oldumount) SYSCALL(setuid) SYSCALL(getuid) COMPAT_SYS(stime) -SYSCALL32(ptrace) +COMPAT_SYS(ptrace) SYSCALL(alarm) OLDSYS(fstat) -SYSCALL32(pause) +COMPAT_SYS(pause) COMPAT_SYS(utime) SYSCALL(ni_syscall) SYSCALL(ni_syscall) -SYSCALL32(access) -SYSCALL32(nice) +COMPAT_SYS(access) +COMPAT_SYS(nice) SYSCALL(ni_syscall) SYSCALL(sync) -SYSCALL32(kill) +COMPAT_SYS(kill) SYSCALL(rename) -SYSCALL32(mkdir) +COMPAT_SYS(mkdir) SYSCALL(rmdir) SYSCALL(dup) SYSCALL(pipe) @@ -100,10 +98,10 @@ SYSCALL(ni_syscall) COMPAT_SYS(ioctl) COMPAT_SYS(fcntl) SYSCALL(ni_syscall) -SYSCALL32(setpgid) +COMPAT_SYS(setpgid) SYSCALL(ni_syscall) SYSX(sys_ni_syscall,sys_olduname, sys_olduname) -SYSCALL32(umask) +COMPAT_SYS(umask) SYSCALL(chroot) SYSCALL(ustat) SYSCALL(dup2) @@ -112,23 +110,23 @@ SYSCALL(getpgrp) SYSCALL(setsid) SYS32ONLY(sigaction) SYSCALL(sgetmask) -SYSCALL32(ssetmask) +COMPAT_SYS(ssetmask) SYSCALL(setreuid) SYSCALL(setregid) SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) COMPAT_SYS(sigpending) -SYSCALL32(sethostname) +COMPAT_SYS(sethostname) COMPAT_SYS(setrlimit) COMPAT_SYS(old_getrlimit) COMPAT_SYS(getrusage) -SYSCALL32(gettimeofday) -SYSCALL32(settimeofday) -SYSCALL32(getgroups) -SYSCALL32(setgroups) +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) -SYSCALL32(readlink) +COMPAT_SYS(readlink) SYSCALL(uselib) SYSCALL(swapon) SYSCALL(reboot) @@ -139,14 +137,14 @@ SYSCALL(truncate) SYSCALL(ftruncate) SYSCALL(fchmod) SYSCALL(fchown) -SYSCALL32(getpriority) -SYSCALL32(setpriority) +COMPAT_SYS(getpriority) +COMPAT_SYS(setpriority) SYSCALL(ni_syscall) COMPAT_SYS(statfs) COMPAT_SYS(fstatfs) SYSCALL(ni_syscall) COMPAT_SYS(socketcall) -SYSCALL32(syslog) +COMPAT_SYS(syslog) COMPAT_SYS(setitimer) COMPAT_SYS(getitimer) COMPAT_SYS(newstat) @@ -159,15 +157,15 @@ SYSCALL(ni_syscall) SYSCALL(ni_syscall) COMPAT_SYS(wait4) SYSCALL(swapoff) -SYSCALL32(sysinfo) -SYSCALL32(ipc) +COMPAT_SYS(sysinfo) +COMPAT_SYS(ipc) SYSCALL(fsync) SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) PPC_SYS(clone) -SYSCALL32(setdomainname) +COMPAT_SYS(setdomainname) PPC_SYS(newuname) SYSCALL(ni_syscall) -SYSCALL32(adjtimex) +COMPAT_SYS(adjtimex) SYSCALL(mprotect) SYSX(sys_ni_syscall,compat_sys_sigprocmask,sys_sigprocmask) SYSCALL(ni_syscall) @@ -175,36 +173,36 @@ SYSCALL(init_module) SYSCALL(delete_module) SYSCALL(ni_syscall) SYSCALL(quotactl) -SYSCALL32(getpgid) +COMPAT_SYS(getpgid) SYSCALL(fchdir) SYSCALL(bdflush) -SYSCALL32(sysfs) +COMPAT_SYS(sysfs) SYSX(ppc64_personality,ppc64_personality,sys_personality) SYSCALL(ni_syscall) SYSCALL(setfsuid) SYSCALL(setfsgid) SYSCALL(llseek) -SYSCALL32(getdents) +COMPAT_SYS(getdents) SYSX(sys_select,ppc32_select,ppc_select) SYSCALL(flock) SYSCALL(msync) COMPAT_SYS(readv) COMPAT_SYS(writev) -SYSCALL32(getsid) +COMPAT_SYS(getsid) SYSCALL(fdatasync) -SYSCALL32(sysctl) +COMPAT_SYS(sysctl) SYSCALL(mlock) SYSCALL(munlock) SYSCALL(mlockall) SYSCALL(munlockall) -SYSCALL32(sched_setparam) -SYSCALL32(sched_getparam) -SYSCALL32(sched_setscheduler) -SYSCALL32(sched_getscheduler) +COMPAT_SYS(sched_setparam) +COMPAT_SYS(sched_getparam) +COMPAT_SYS(sched_setscheduler) +COMPAT_SYS(sched_getscheduler) SYSCALL(sched_yield) -SYSCALL32(sched_get_priority_max) -SYSCALL32(sched_get_priority_min) -SYSCALL32(sched_rr_get_interval) +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) @@ -214,36 +212,36 @@ SYSCALL(poll) COMPAT_SYS(nfsservctl) SYSCALL(setresgid) SYSCALL(getresgid) -SYSCALL32(prctl) +COMPAT_SYS(prctl) SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) -SYSCALL32(rt_sigaction) -SYSCALL32(rt_sigprocmask) -SYSCALL32(rt_sigpending) +COMPAT_SYS(rt_sigaction) +COMPAT_SYS(rt_sigprocmask) +COMPAT_SYS(rt_sigpending) COMPAT_SYS(rt_sigtimedwait) -SYSCALL32(rt_sigqueueinfo) +COMPAT_SYS(rt_sigqueueinfo) SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) -SYSCALL32(pread64) -SYSCALL32(pwrite64) +COMPAT_SYS(pread64) +COMPAT_SYS(pwrite64) SYSCALL(chown) SYSCALL(getcwd) SYSCALL(capget) SYSCALL(capset) -SYSCALL32(sigaltstack) -SYSX(sys_sendfile64,sys32_sendfile,sys_sendfile) +COMPAT_SYS(sigaltstack) +SYSX(sys_sendfile64,compat_sys_sendfile,sys_sendfile) SYSCALL(ni_syscall) SYSCALL(ni_syscall) PPC_SYS(vfork) COMPAT_SYS(getrlimit) -SYSCALL32(readahead) +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) -SYSCALL32(pciconfig_read) -SYSCALL32(pciconfig_write) -SYSCALL32(pciconfig_iobase) +COMPAT_SYS(pciconfig_read) +COMPAT_SYS(pciconfig_write) +COMPAT_SYS(pciconfig_iobase) SYSCALL(ni_syscall) SYSCALL(getdents64) SYSCALL(pivot_root) @@ -293,8 +291,8 @@ COMPAT_SYS(clock_gettime) COMPAT_SYS(clock_getres) COMPAT_SYS(clock_nanosleep) SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) -SYSCALL32(tgkill) -SYSCALL32(utimes) +COMPAT_SYS(tgkill) +COMPAT_SYS(utimes) COMPAT_SYS(statfs64) COMPAT_SYS(fstatfs64) SYSX(sys_ni_syscall, ppc32_fadvise64_64, sys_fadvise64_64) @@ -312,12 +310,12 @@ COMPAT_SYS(mq_timedreceive) COMPAT_SYS(mq_notify) COMPAT_SYS(mq_getsetattr) COMPAT_SYS(kexec_load) -SYSCALL32(add_key) -SYSCALL32(request_key) +COMPAT_SYS(add_key) +COMPAT_SYS(request_key) COMPAT_SYS(keyctl) COMPAT_SYS(waitid) -SYSCALL32(ioprio_set) -SYSCALL32(ioprio_get) +COMPAT_SYS(ioprio_set) +COMPAT_SYS(ioprio_get) SYSCALL(inotify_init) SYSCALL(inotify_add_watch) SYSCALL(inotify_rm_watch) diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index ea30af810e0c..5d2fcbe384c1 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -265,7 +265,7 @@ _GLOBAL(save_nvgprs) */ _GLOBAL(ppc32_sigsuspend) bl .save_nvgprs - bl .sys32_sigsuspend + bl .compat_sys_sigsuspend b 70f _GLOBAL(ppc64_rt_sigsuspend) @@ -275,7 +275,7 @@ _GLOBAL(ppc64_rt_sigsuspend) _GLOBAL(ppc32_rt_sigsuspend) bl .save_nvgprs - bl .sys32_rt_sigsuspend + bl .compat_sys_rt_sigsuspend 70: cmpdi 0,r3,0 /* If it returned an error, we need to return via syscall_exit to set the SO bit in cr0 and potentially stop for ptrace. */ @@ -310,7 +310,7 @@ _GLOBAL(ppc_clone) _GLOBAL(ppc32_swapcontext) bl .save_nvgprs - bl .sys32_swapcontext + bl .compat_sys_swapcontext b 80f _GLOBAL(ppc64_swapcontext) @@ -319,11 +319,11 @@ _GLOBAL(ppc64_swapcontext) b 80f _GLOBAL(ppc32_sigreturn) - bl .sys32_sigreturn + bl .compat_sys_sigreturn b 80f _GLOBAL(ppc32_rt_sigreturn) - bl .sys32_rt_sigreturn + bl .compat_sys_rt_sigreturn b 80f _GLOBAL(ppc64_rt_sigreturn) diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index eb407c429bb0..ea8b6cf32c38 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -928,11 +928,11 @@ _GLOBAL(sys_call_table32) .llong .sys_write .llong .compat_sys_open /* 5 */ .llong .sys_close - .llong .sys32_waitpid - .llong .sys32_creat + .llong .compat_sys_waitpid + .llong .compat_sys_creat .llong .sys_link .llong .sys_unlink /* 10 */ - .llong .sys32_execve + .llong .compat_sys_execve .llong .sys_chdir .llong .compat_sys_time .llong .sys_mknod @@ -947,20 +947,20 @@ _GLOBAL(sys_call_table32) .llong .sys_setuid .llong .sys_getuid .llong .compat_sys_stime /* 25 */ - .llong .sys32_ptrace + .llong .compat_sys_ptrace .llong .sys_alarm .llong .sys_ni_syscall /* old fstat syscall */ - .llong .sys32_pause + .llong .compat_sys_pause .llong .compat_sys_utime /* 30 */ .llong .sys_ni_syscall /* old stty syscall */ .llong .sys_ni_syscall /* old gtty syscall */ - .llong .sys32_access - .llong .sys32_nice + .llong .compat_sys_access + .llong .compat_sys_nice .llong .sys_ni_syscall /* 35 - old ftime syscall */ .llong .sys_sync - .llong .sys32_kill + .llong .compat_sys_kill .llong .sys_rename - .llong .sys32_mkdir + .llong .compat_sys_mkdir .llong .sys_rmdir /* 40 */ .llong .sys_dup .llong .sys_pipe @@ -978,35 +978,35 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_ioctl .llong .compat_sys_fcntl /* 55 */ .llong .sys_ni_syscall /* old mpx syscall */ - .llong .sys32_setpgid + .llong .compat_sys_setpgid .llong .sys_ni_syscall /* old ulimit syscall */ .llong .sys_olduname - .llong .sys32_umask /* 60 */ + .llong .compat_sys_umask /* 60 */ .llong .sys_chroot .llong .sys_ustat .llong .sys_dup2 .llong .sys_getppid .llong .sys_getpgrp /* 65 */ .llong .sys_setsid - .llong .sys32_sigaction + .llong .compat_sys_sigaction .llong .sys_sgetmask - .llong .sys32_ssetmask + .llong .compat_sys_ssetmask .llong .sys_setreuid /* 70 */ .llong .sys_setregid .llong .ppc32_sigsuspend .llong .compat_sys_sigpending - .llong .sys32_sethostname + .llong .compat_sys_sethostname .llong .compat_sys_setrlimit /* 75 */ .llong .compat_sys_old_getrlimit .llong .compat_sys_getrusage - .llong .sys32_gettimeofday - .llong .sys32_settimeofday - .llong .sys32_getgroups /* 80 */ - .llong .sys32_setgroups + .llong .compat_sys_gettimeofday + .llong .compat_sys_settimeofday + .llong .compat_sys_getgroups /* 80 */ + .llong .compat_sys_setgroups .llong .sys_ni_syscall /* old select syscall */ .llong .sys_symlink .llong .sys_ni_syscall /* old lstat syscall */ - .llong .sys32_readlink /* 85 */ + .llong .compat_sys_readlink /* 85 */ .llong .sys_uselib .llong .sys_swapon .llong .sys_reboot @@ -1017,14 +1017,14 @@ _GLOBAL(sys_call_table32) .llong .sys_ftruncate .llong .sys_fchmod .llong .sys_fchown /* 95 */ - .llong .sys32_getpriority - .llong .sys32_setpriority + .llong .compat_sys_getpriority + .llong .compat_sys_setpriority .llong .sys_ni_syscall /* old profil syscall */ .llong .compat_sys_statfs .llong .compat_sys_fstatfs /* 100 */ .llong .sys_ni_syscall /* old ioperm syscall */ .llong .compat_sys_socketcall - .llong .sys32_syslog + .llong .compat_sys_syslog .llong .compat_sys_setitimer .llong .compat_sys_getitimer /* 105 */ .llong .compat_sys_newstat @@ -1037,15 +1037,15 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall /* old vm86 syscall */ .llong .compat_sys_wait4 .llong .sys_swapoff /* 115 */ - .llong .sys32_sysinfo - .llong .sys32_ipc + .llong .compat_sys_sysinfo + .llong .compat_sys_ipc .llong .sys_fsync .llong .ppc32_sigreturn .llong .ppc_clone /* 120 */ - .llong .sys32_setdomainname + .llong .compat_sys_setdomainname .llong .ppc_newuname .llong .sys_ni_syscall /* old modify_ldt syscall */ - .llong .sys32_adjtimex + .llong .compat_sys_adjtimex .llong .sys_mprotect /* 125 */ .llong .compat_sys_sigprocmask .llong .sys_ni_syscall /* old create_module syscall */ @@ -1053,36 +1053,36 @@ _GLOBAL(sys_call_table32) .llong .sys_delete_module .llong .sys_ni_syscall /* 130 old get_kernel_syms syscall */ .llong .sys_quotactl - .llong .sys32_getpgid + .llong .compat_sys_getpgid .llong .sys_fchdir .llong .sys_bdflush - .llong .sys32_sysfs /* 135 */ + .llong .compat_sys_sysfs /* 135 */ .llong .ppc64_personality .llong .sys_ni_syscall /* for afs_syscall */ .llong .sys_setfsuid .llong .sys_setfsgid .llong .sys_llseek /* 140 */ - .llong .sys32_getdents + .llong .compat_sys_getdents .llong .ppc32_select .llong .sys_flock .llong .sys_msync .llong .compat_sys_readv /* 145 */ .llong .compat_sys_writev - .llong .sys32_getsid + .llong .compat_sys_getsid .llong .sys_fdatasync - .llong .sys32_sysctl + .llong .compat_sys_sysctl .llong .sys_mlock /* 150 */ .llong .sys_munlock .llong .sys_mlockall .llong .sys_munlockall - .llong .sys32_sched_setparam - .llong .sys32_sched_getparam /* 155 */ - .llong .sys32_sched_setscheduler - .llong .sys32_sched_getscheduler + .llong .compat_sys_sched_setparam + .llong .compat_sys_sched_getparam /* 155 */ + .llong .compat_sys_sched_setscheduler + .llong .compat_sys_sched_getscheduler .llong .sys_sched_yield - .llong .sys32_sched_get_priority_max - .llong .sys32_sched_get_priority_min /* 160 */ - .llong .sys32_sched_rr_get_interval + .llong .compat_sys_sched_get_priority_max + .llong .compat_sys_sched_get_priority_min /* 160 */ + .llong .compat_sys_sched_rr_get_interval .llong .compat_sys_nanosleep .llong .sys_mremap .llong .sys_setresuid @@ -1092,36 +1092,36 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_nfsservctl .llong .sys_setresgid .llong .sys_getresgid /* 170 */ - .llong .sys32_prctl + .llong .compat_sys_prctl .llong .ppc32_rt_sigreturn - .llong .sys32_rt_sigaction - .llong .sys32_rt_sigprocmask - .llong .sys32_rt_sigpending /* 175 */ + .llong .compat_sys_rt_sigaction + .llong .compat_sys_rt_sigprocmask + .llong .compat_sys_rt_sigpending /* 175 */ .llong .compat_sys_rt_sigtimedwait - .llong .sys32_rt_sigqueueinfo + .llong .compat_sys_rt_sigqueueinfo .llong .ppc32_rt_sigsuspend - .llong .sys32_pread64 - .llong .sys32_pwrite64 /* 180 */ + .llong .compat_sys_pread64 + .llong .compat_sys_pwrite64 /* 180 */ .llong .sys_chown .llong .sys_getcwd .llong .sys_capget .llong .sys_capset - .llong .sys32_sigaltstack /* 185 */ - .llong .sys32_sendfile + .llong .compat_sys_sigaltstack /* 185 */ + .llong .compat_sys_sendfile .llong .sys_ni_syscall /* reserved for streams1 */ .llong .sys_ni_syscall /* reserved for streams2 */ .llong .ppc_vfork .llong .compat_sys_getrlimit /* 190 */ - .llong .sys32_readahead - .llong .sys32_mmap2 - .llong .sys32_truncate64 - .llong .sys32_ftruncate64 + .llong .compat_sys_readahead + .llong .compat_sys_mmap2 + .llong .compat_sys_truncate64 + .llong .compat_sys_ftruncate64 .llong .sys_stat64 /* 195 */ .llong .sys_lstat64 .llong .sys_fstat64 - .llong .sys32_pciconfig_read - .llong .sys32_pciconfig_write - .llong .sys32_pciconfig_iobase /* 200 - pciconfig_iobase */ + .llong .compat_sys_pciconfig_read + .llong .compat_sys_pciconfig_write + .llong .compat_sys_pciconfig_iobase /* 200 - pciconfig_iobase */ .llong .sys_ni_syscall /* reserved for MacOnLinux */ .llong .sys_getdents64 .llong .sys_pivot_root @@ -1147,7 +1147,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_sched_getaffinity .llong .sys_ni_syscall .llong .sys_ni_syscall /* 225 - reserved for tux */ - .llong .sys32_sendfile64 + .llong .compat_sys_sendfile64 .llong .compat_sys_io_setup .llong .sys_io_destroy .llong .compat_sys_io_getevents @@ -1171,8 +1171,8 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_clock_getres .llong .compat_sys_clock_nanosleep .llong .ppc32_swapcontext - .llong .sys32_tgkill /* 250 */ - .llong .sys32_utimes + .llong .compat_sys_tgkill /* 250 */ + .llong .compat_sys_utimes .llong .compat_sys_statfs64 .llong .compat_sys_fstatfs64 .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ @@ -1190,12 +1190,12 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_mq_notify .llong .compat_sys_mq_getsetattr .llong .compat_sys_kexec_load - .llong .sys32_add_key - .llong .sys32_request_key /* 270 */ + .llong .compat_sys_add_key + .llong .compat_sys_request_key /* 270 */ .llong .compat_sys_keyctl .llong .compat_sys_waitid - .llong .sys32_ioprio_set - .llong .sys32_ioprio_get + .llong .compat_sys_ioprio_set + .llong .compat_sys_ioprio_get .llong .sys_inotify_init /* 275 */ .llong .sys_inotify_add_watch .llong .sys_inotify_rm_watch diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index fb8c22d6084a..2e1df3ddd9fb 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -40,7 +40,7 @@ * in exit.c or in signal.c. */ -int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) +int compat_sys_ptrace(long request, long pid, unsigned long addr, unsigned long data) { struct task_struct *child; int ret = -EPERM; From 4b2d319b53810ab00ef3d8fdfc1c1ab0647ab0a7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 18 Oct 2005 12:20:06 -0700 Subject: [PATCH 0430/1939] [IPoIB] Improve ipoib_timeout() output Use jiffies_to_msecs() so we print a human-readable time so we don't have to worry about what HZ is configured to, and print out a few values to make post-mortem analysis easier. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6c5bf07489f4..ee303859b044 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -637,8 +637,11 @@ static void ipoib_timeout(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_warn(priv, "transmit timeout: latency %ld\n", - jiffies - dev->trans_start); + ipoib_warn(priv, "transmit timeout: latency %d msecs\n", + jiffies_to_msecs(jiffies - dev->trans_start)); + ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", + netif_queue_stopped(dev), + priv->tx_head, priv->tx_tail); /* XXX reset QP, etc. */ } From c6f5cb7be0ab478e0618e3c2c6ada27f56d1e7fb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 18 Oct 2005 13:22:16 -0700 Subject: [PATCH 0431/1939] [IB] mthca: Use enum in mthca_alloc_db() prototype Make the type parameter of mthca_alloc_db() be an enum mthca_db_type instead of an int. This doesn't have any practical effect but documents the functions a little better. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_memfree.c | 3 ++- drivers/infiniband/hw/mthca/mthca_memfree.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 7bd7a4bec7b4..d63b1a147100 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -487,7 +487,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, } } -int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db) +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db) { int group; int start, end, dir; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index bafa51544aa3..29c01a4b2656 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -173,7 +173,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, int mthca_init_db_tab(struct mthca_dev *dev); void mthca_cleanup_db_tab(struct mthca_dev *dev); -int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db); +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db); void mthca_free_db(struct mthca_dev *dev, int type, int db_index); #endif /* MTHCA_MEMFREE_H */ From ad4ebed00fbf570411edbf6eb6c391e16b71df25 Mon Sep 17 00:00:00 2001 From: "ravinandan.arakali@neterion.com" Date: Mon, 17 Oct 2005 18:26:20 -0700 Subject: [PATCH 0432/1939] [PATCH] S2io: Offline diagnostics fixes This patch fixes the following bugs with offline diagnostics code(run with "ethtool -t"). 1. After running offline diagnostics, adapter would report corrupted packets on receive. This was because of adapter not being brought out of "RLDRAM test mode". 2. Current EEPROM test works only for Xframe I. Since Xframe II uses different interface(SPI), support for this interface has been added. Also, since SPI supports write access to all areas of EEPROM, negative testing is done only for Xframe I. 3. Return values from subfunctions of offline diagnostics have been corrected. 4. In register test, expected value from rx_queue_cfg register is made to depend on adapter type. 5. After the test, need to restore values at EEPROM offsets 0x4F0 and 0x7F0. These locations were modified as part of test. 6. Use macro SPECIAL_REG_WRITE for write access to mc_rldram_test_ctrl register. Also, couple of unnecessary writes to mc_rldram_test_ctrl have been removed. Signed-off-by: Ravinandan Arakali Signed-off-by: Jeff Garzik --- drivers/net/s2io-regs.h | 11 ++ drivers/net/s2io.c | 235 ++++++++++++++++++++++++++-------------- 2 files changed, 164 insertions(+), 82 deletions(-) diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 7cefe5507b9e..00179bc3437f 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -814,6 +814,17 @@ typedef struct _XENA_dev_config { u64 rxgxs_ber_0; /* CHANGED */ u64 rxgxs_ber_1; /* CHANGED */ + u64 spi_control; +#define SPI_CONTROL_KEY(key) vBIT(key,0,4) +#define SPI_CONTROL_BYTECNT(cnt) vBIT(cnt,29,3) +#define SPI_CONTROL_CMD(cmd) vBIT(cmd,32,8) +#define SPI_CONTROL_ADDR(addr) vBIT(addr,40,24) +#define SPI_CONTROL_SEL1 BIT(4) +#define SPI_CONTROL_REQ BIT(7) +#define SPI_CONTROL_NACK BIT(5) +#define SPI_CONTROL_DONE BIT(6) + u64 spi_data; +#define SPI_DATA_WRITE(data,len) vBIT(data,0,len) } XENA_dev_config_t; #define XENA_REG_SPACE sizeof(XENA_dev_config_t) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index fcf61107046e..30fbaf04773f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4378,29 +4378,53 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(nic_t * sp, int off, u32 * data) +static int read_eeprom(nic_t * sp, int off, u64 * data) { int ret = -1; u32 exit_cnt = 0; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - *data = I2C_CONTROL_GET_DATA(val64); - ret = 0; - break; + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + *data = I2C_CONTROL_GET_DATA(val64); + ret = 0; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(0x3) | + SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { + *data = readq(&bar0->spi_data); + *data &= 0xffffff; + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } return ret; } @@ -4419,28 +4443,53 @@ static int read_eeprom(nic_t * sp, int off, u32 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) +static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - if (!(val64 & I2C_CONTROL_NACK)) - ret = 0; - break; + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + if (!(val64 & I2C_CONTROL_NACK)) + ret = 0; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } + if (sp->device_type == XFRAME_II_DEVICE) { + int write_cnt = (cnt == 8) ? 0 : cnt; + writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data); + + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(write_cnt) | + SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } return ret; } @@ -4460,7 +4509,8 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) static int s2io_ethtool_geeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * data_buf) { - u32 data, i, valid; + u32 i, valid; + u64 data; nic_t *sp = dev->priv; eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -4498,7 +4548,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, u8 * data_buf) { int len = eeprom->len, cnt = 0; - u32 valid = 0, data; + u64 valid = 0, data; nic_t *sp = dev->priv; if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { @@ -4546,7 +4596,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, static int s2io_register_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; - u64 val64 = 0; + u64 val64 = 0, exp_val; int fail = 0; val64 = readq(&bar0->pif_rd_swapper_fb); @@ -4562,7 +4612,11 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } val64 = readq(&bar0->rx_queue_cfg); - if (val64 != 0x0808080808080808ULL) { + if (sp->device_type == XFRAME_II_DEVICE) + exp_val = 0x0404040404040404ULL; + else + exp_val = 0x0808080808080808ULL; + if (val64 != exp_val) { fail = 1; DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n"); } @@ -4590,7 +4644,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } *data = fail; - return 0; + return fail; } /** @@ -4609,58 +4663,83 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) static int s2io_eeprom_test(nic_t * sp, uint64_t * data) { int fail = 0; - u32 ret_data; + u64 ret_data, org_4F0, org_7F0; + u8 saved_4F0 = 0, saved_7F0 = 0; + struct net_device *dev = sp->dev; /* Test Write Error at offset 0 */ - if (!write_eeprom(sp, 0, 0, 3)) - fail = 1; + /* Note that SPI interface allows write access to all areas + * of EEPROM. Hence doing all negative testing only for Xframe I. + */ + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0, 0, 3)) + fail = 1; + + /* Save current values at offsets 0x4F0 and 0x7F0 */ + if (!read_eeprom(sp, 0x4F0, &org_4F0)) + saved_4F0 = 1; + if (!read_eeprom(sp, 0x7F0, &org_7F0)) + saved_7F0 = 1; /* Test Write at offset 4f0 */ - if (write_eeprom(sp, 0x4F0, 0x01234567, 3)) + if (write_eeprom(sp, 0x4F0, 0x012345, 3)) fail = 1; if (read_eeprom(sp, 0x4F0, &ret_data)) fail = 1; - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x4F0, 0xFFFFFF, 3); /* Test Write Request Error at offset 0x7c */ - if (!write_eeprom(sp, 0x07C, 0, 3)) + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0x07C, 0, 3)) + fail = 1; + + /* Test Write Request at offset 0x7f0 */ + if (write_eeprom(sp, 0x7F0, 0x012345, 3)) + fail = 1; + if (read_eeprom(sp, 0x7F0, &ret_data)) fail = 1; - /* Test Write Request at offset 0x7fc */ - if (write_eeprom(sp, 0x7FC, 0x01234567, 3)) - fail = 1; - if (read_eeprom(sp, 0x7FC, &ret_data)) - fail = 1; - - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x7F0, 0xFFFFFF, 3); - /* Test Write Error at offset 0x80 */ - if (!write_eeprom(sp, 0x080, 0, 3)) - fail = 1; + if (sp->device_type == XFRAME_I_DEVICE) { + /* Test Write Error at offset 0x80 */ + if (!write_eeprom(sp, 0x080, 0, 3)) + fail = 1; - /* Test Write Error at offset 0xfc */ - if (!write_eeprom(sp, 0x0FC, 0, 3)) - fail = 1; + /* Test Write Error at offset 0xfc */ + if (!write_eeprom(sp, 0x0FC, 0, 3)) + fail = 1; - /* Test Write Error at offset 0x100 */ - if (!write_eeprom(sp, 0x100, 0, 3)) - fail = 1; + /* Test Write Error at offset 0x100 */ + if (!write_eeprom(sp, 0x100, 0, 3)) + fail = 1; - /* Test Write Error at offset 4ec */ - if (!write_eeprom(sp, 0x4EC, 0, 3)) - fail = 1; + /* Test Write Error at offset 4ec */ + if (!write_eeprom(sp, 0x4EC, 0, 3)) + fail = 1; + } + + /* Restore values at offsets 0x4F0 and 0x7F0 */ + if (saved_4F0) + write_eeprom(sp, 0x4F0, org_4F0, 3); + if (saved_7F0) + write_eeprom(sp, 0x7F0, org_7F0, 3); *data = fail; - return 0; + return fail; } /** @@ -4742,7 +4821,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; - int cnt, iteration = 0, test_pass = 0; + int cnt, iteration = 0, test_fail = 0; val64 = readq(&bar0->adapter_control); val64 &= ~ADAPTER_ECC_EN; @@ -4750,7 +4829,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) val64 = readq(&bar0->mc_rldram_test_ctrl); val64 |= MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); val64 = readq(&bar0->mc_rldram_mrs); val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE; @@ -4778,17 +4857,12 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) } writeq(val64, &bar0->mc_rldram_test_d2); - val64 = (u64) (0x0000003fffff0000ULL); + val64 = (u64) (0x0000003ffffe0100ULL); writeq(val64, &bar0->mc_rldram_test_add); - - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= - MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | - MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | + MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4800,11 +4874,8 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) if (cnt == 5) break; - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4817,18 +4888,18 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) break; val64 = readq(&bar0->mc_rldram_test_ctrl); - if (val64 & MC_RLDRAM_TEST_PASS) - test_pass = 1; + if (!(val64 & MC_RLDRAM_TEST_PASS)) + test_fail = 1; iteration++; } - if (!test_pass) - *data = 1; - else - *data = 0; + *data = test_fail; - return 0; + /* Bring the adapter out of test mode */ + SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF); + + return test_fail; } /** From bc0a7438605c5e0cafdb32a3caf46254e146b116 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 17 Oct 2005 12:42:32 +0100 Subject: [PATCH 0433/1939] [PATCH] rcu in bpqether driver. From Suzanne Wood : Clarify RCU implementation in bpqether.c. Because bpq_new_device() calls list_add_rcu() and bpq_free_device() calls list_del_rcu(), substitute list_for_each_entry_rcu() for list_for_each_entry() in bpq_get_ax25_dev() and in bpq_seq_start(). Add rcu dereference protection in bpq_seq_next(). The rcu_read_lock()/unlock() in bpq_device_event() are removed because netdev event handlers are called with RTNL locking in place. FYI: bpq_free_device() calls list_del_rcu() which, per list.h, requires synchronize_rcu() which can block or call_rcu() or call_rcu_bh() which cannot block. Herbert Xu notes that synchronization is done here by unregister_netdevice(). This calls synchronize_net() which in turn uses synchronize_rcu(). Signed-off-by: Ralf Baechle DL5RB Signed-off-by: Jeff Garzik --- drivers/net/hamradio/bpqether.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1756f0ed54cc..cb43a9d28774 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) { struct bpqdev *bpq; - list_for_each_entry(bpq, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) { if (bpq->ethdev == dev) return bpq->axdev; } @@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - list_for_each_entry(bpqdev, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) { if (i == *pos) return bpqdev; } @@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) p = ((struct bpqdev *)v)->bpq_list.next; return (p == &bpq_devices) ? NULL - : list_entry(p, struct bpqdev, bpq_list); + : rcu_dereference(list_entry(p, struct bpqdev, bpq_list)); } static void bpq_seq_stop(struct seq_file *seq, void *v) @@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi if (!dev_is_ethdev(dev)) return NOTIFY_DONE; - rcu_read_lock(); - switch (event) { case NETDEV_UP: /* new ethernet device -> new BPQ interface */ if (bpq_get_ax25_dev(dev) == NULL) @@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi default: break; } - rcu_read_unlock(); return NOTIFY_DONE; } From 5793f4be23f0171b4999ca68a39a9157b44139f3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 14 Oct 2005 14:28:09 +0100 Subject: [PATCH 0434/1939] [PATCH] SMACK support for mkiss SMACK (Stuttgart Modified Amateurradio CRC KISS) is a KISS variant that uses CRC16 checksums to secure data transfers between the modem and host. It's also used to communicate over a pty to applications such as Wampes. Patches for Linux 2.4 by Thomas Osterried DL9SAU, upgraded to the latest mkiss 2.6 mkiss driver by me. Signed-off-by: Thomas Osterried DL9SAU Signed-off-by: Ralf Baechle DL5RB Signed-off-by: Jeff Garzik --- drivers/net/hamradio/Kconfig | 1 + drivers/net/hamradio/mkiss.c | 180 ++++++++++++++++++++++++++++------- 2 files changed, 149 insertions(+), 32 deletions(-) diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index de087cd609d9..896aa02000d7 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -1,6 +1,7 @@ config MKISS tristate "Serial port KISS driver" depends on AX25 + select CRC16 ---help--- KISS is a protocol used for the exchange of data between a computer and a Terminal Node Controller (a small embedded system commonly diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 331a75c8aee2..7961f5b41c4b 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -14,13 +14,14 @@ * * Copyright (C) Hans Alblas PE1AYX * Copyright (C) 2004, 05 Ralf Baechle DL5RB + * Copyright (C) 2004, 05 Thomas Osterried DL9SAU */ - #include #include #include #include #include +#include #include #include #include @@ -39,11 +40,6 @@ #include -#ifdef CONFIG_INET -#include -#include -#endif - #define AX_MTU 236 /* SLIP/KISS protocol characters. */ @@ -80,9 +76,13 @@ struct mkiss { int mode; int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 + int crcauto; /* CRC auto mode */ + +#define CRC_MODE_NONE 0 +#define CRC_MODE_FLEX 1 +#define CRC_MODE_SMACK 2 +#define CRC_MODE_FLEX_TEST 3 +#define CRC_MODE_SMACK_TEST 4 atomic_t refcnt; struct semaphore dead_sem; @@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size) return 0; } +static int check_crc_16(unsigned char *cp, int size) +{ + unsigned short crc = 0x0000; + + if (size < 3) + return -1; + + crc = crc16(0, cp, size); + + if (crc != 0x0000) + return -1; + + return 0; +} + /* * Standard encapsulation */ @@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax) spin_lock_bh(&ax->buflock); if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x20) { - ax->crcmode = CRC_MODE_FLEX; - if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->stats.rx_errors++; + if (ax->rbuff[0] & 0x80) { + if (check_crc_16(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); + return; } + if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-smack\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK; + } ax->rcount -= 2; - /* dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have - * to correct the kissparm signature, because it - * indicates a crc but there's none + *ax->rbuff &= ~0x80; + } else if (ax->rbuff[0] & 0x20) { + if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); + return; + } + if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-flexnet\n", + ax->dev->name); + ax->crcmode = CRC_MODE_FLEX; + } + ax->rcount -= 2; + + /* + * dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have to + * correct the kissparm signature, because it indicates + * a crc but there's none */ - *ax->rbuff &= ~0x20; + *ax->rbuff &= ~0x20; } } spin_unlock_bh(&ax->buflock); @@ -417,20 +455,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) p = icp; spin_lock_bh(&ax->buflock); - switch (ax->crcmode) { - unsigned short crc; + if ((*p & 0x0f) != 0) { + /* Configuration Command (kissparms(1). + * Protocol spec says: never append CRC. + * This fixes a very old bug in the linux + * kiss driver. -- dl9sau */ + switch (*p & 0xff) { + case 0x85: + /* command from userspace especially for us, + * not for delivery to the tnc */ + if (len > 1) { + int cmd = (p[1] & 0xff); + switch(cmd) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + break; + case 0: + default: + ax->crcmode = CRC_MODE_SMACK_TEST; + cmd = 0; + } + ax->crcauto = (cmd ? 0 : 1); + printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); + } + spin_unlock_bh(&ax->buflock); + netif_start_queue(dev); - case CRC_MODE_FLEX: - *p |= 0x20; - crc = calc_crc_flex(p, len); - count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); - break; + return; + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } else { + unsigned short crc; + switch (ax->crcmode) { + case CRC_MODE_SMACK_TEST: + ax->crcmode = CRC_MODE_FLEX_TEST; + printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name); + // fall through + case CRC_MODE_SMACK: + *p |= 0x80; + crc = swab16(crc16(0, p, len)); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + case CRC_MODE_FLEX_TEST: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name); + // fall through + case CRC_MODE_FLEX: + *p |= 0x20; + crc = calc_crc_flex(p, len); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } - default: - count = kiss_esc(p, (unsigned char *)ax->xbuff, len); - break; - } - set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); ax->stats.tx_packets++; @@ -439,8 +526,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; - - spin_unlock_bh(&ax->buflock); } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ @@ -643,6 +728,8 @@ static void mkiss_put(struct mkiss *ax) up(&ax->dead_sem); } +static int crc_force = 0; /* Can be overridden with insmod */ + static int mkiss_open(struct tty_struct *tty) { struct net_device *dev; @@ -682,6 +769,33 @@ static int mkiss_open(struct tty_struct *tty) if (register_netdev(dev)) goto out_free_buffers; + /* after register_netdev() - because else printk smashes the kernel */ + switch (crc_force) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n", + ax->dev->name); + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n", + ax->dev->name); + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: crc mode disabled.\n", + ax->dev->name); + break; + case 0: + /* fall through */ + default: + crc_force = 0; + printk(KERN_INFO "mkiss: %s: crc mode is auto.\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK_TEST; + } + ax->crcauto = (crc_force ? 0 : 1); + netif_start_queue(dev); /* Done. We have linked the TTY line to a channel. */ @@ -903,6 +1017,8 @@ static void __exit mkiss_exit_driver(void) MODULE_AUTHOR("Ralf Baechle DL5RB "); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); +MODULE_PARM(crc_force, "i"); +MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); From 74cfe03f80adc320bde4dd37616354aefe2271aa Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 12 Oct 2005 23:11:01 +0100 Subject: [PATCH 0435/1939] [PATCH] Initialize the .owner field the tty_ldisc structure. If .owner isn't set the module can be unloaded even while still active. Signed-off-by: Ralf Baechle DL5RB Signed-off-by: Jeff Garzik --- drivers/net/hamradio/mkiss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 7961f5b41c4b..85d6dc005be0 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -977,6 +977,7 @@ static void mkiss_write_wakeup(struct tty_struct *tty) } static struct tty_ldisc ax_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, From d476306f1cc9156ce4b42586aacce70a356ef656 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 18 Oct 2005 14:07:07 -0700 Subject: [PATCH 0436/1939] [IB] mthca: Add struct pci_driver.owner field Set mthca_driver.owner to THIS_MODULE. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 7c35abec81ea..883d1e5a79bc 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1196,6 +1196,7 @@ MODULE_DEVICE_TABLE(pci, mthca_pci_table); static struct pci_driver mthca_driver = { .name = DRV_NAME, + .owner = THIS_MODULE, .id_table = mthca_pci_table, .probe = mthca_init_one, .remove = __devexit_p(mthca_remove_one) From ba8e9310244180bbc820e865d2e4378809b4a443 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 18 Oct 2005 14:14:56 -0700 Subject: [PATCH 0437/1939] [IB] Fail sysfs queries after device is unregistered We keep IB device structures around until the last sysfs reference is gone, but we shouldn't ask the low-level driver to do anything after the LLD unregisters the device. To handle this, check the reg_state field and just fail sysfs show() requests if the device has already been unregistered. Signed-off-by: Roland Dreier --- drivers/infiniband/core/sysfs.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 211ba3223f65..7ce7a6c782fa 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -65,6 +65,11 @@ struct port_table_attribute { int index; }; +static inline int ibdev_is_alive(const struct ib_device *dev) +{ + return dev->reg_state == IB_DEV_REGISTERED; +} + static ssize_t port_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -74,6 +79,8 @@ static ssize_t port_attr_show(struct kobject *kobj, if (!port_attr->show) return -EIO; + if (!ibdev_is_alive(p->ibdev)) + return -ENODEV; return port_attr->show(p, port_attr, buf); } @@ -581,6 +588,9 @@ static ssize_t show_node_type(struct class_device *cdev, char *buf) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); + if (!ibdev_is_alive(dev)) + return -ENODEV; + switch (dev->node_type) { case IB_NODE_CA: return sprintf(buf, "%d: CA\n", dev->node_type); case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type); @@ -595,6 +605,9 @@ static ssize_t show_sys_image_guid(struct class_device *cdev, char *buf) struct ib_device_attr attr; ssize_t ret; + if (!ibdev_is_alive(dev)) + return -ENODEV; + ret = ib_query_device(dev, &attr); if (ret) return ret; @@ -612,6 +625,9 @@ static ssize_t show_node_guid(struct class_device *cdev, char *buf) struct ib_device_attr attr; ssize_t ret; + if (!ibdev_is_alive(dev)) + return -ENODEV; + ret = ib_query_device(dev, &attr); if (ret) return ret; From 07506697d1c615924298406f2357810709c09bcd Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 12 Oct 2005 15:04:18 +0800 Subject: [PATCH 0438/1939] [PATCH] libata CHS: move the initialization of taskfile LBA flags (revise #6) move the initialization of taskfile LBA flags "ATA_TFLAG_LBA" and "ATA_TFLAG_LBA48 flags" to the SCSI translation functions Signed-off-by: Albert Lee ============= Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 7 ------- drivers/scsi/libata-scsi.c | 42 +++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index d568914c4344..55d4dee133af 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3195,13 +3195,6 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, qc->nbytes = qc->curbytes = 0; ata_tf_init(ap, &qc->tf, dev->devno); - - if (dev->flags & ATA_DFLAG_LBA) { - qc->tf.flags |= ATA_TFLAG_LBA; - - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; - } } return qc; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index c64169ca7ff0..ea7a4d8a6fc9 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -492,7 +492,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((tf->flags & ATA_TFLAG_LBA48) && + if ((qc->dev->flags & ATA_DFLAG_LBA48) && (ata_id_has_flush_ext(qc->dev->id))) tf->command = ATA_CMD_FLUSH_EXT; else @@ -612,8 +612,6 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; - unsigned int lba = tf->flags & ATA_TFLAG_LBA; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 dev_sectors = qc->dev->n_sectors; u64 block; u32 n_block; @@ -634,16 +632,16 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) goto out_of_range; if ((block + n_block) > dev_sectors) goto out_of_range; - if (lba48) { - if (n_block > (64 * 1024)) - goto invalid_fld; - } else { - if (n_block > 256) - goto invalid_fld; - } - if (lba) { - if (lba48) { + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) { + if (n_block > (64 * 1024)) + goto invalid_fld; + + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; tf->command = ATA_CMD_VERIFY_EXT; tf->hob_nsect = (n_block >> 8) & 0xff; @@ -652,6 +650,10 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->hob_lbam = (block >> 32) & 0xff; tf->hob_lbal = (block >> 24) & 0xff; } else { + if (n_block > 256) + goto invalid_fld; + + /* use LBA28 */ tf->command = ATA_CMD_VERIFY; tf->device |= (block >> 24) & 0xf; @@ -668,6 +670,9 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* CHS */ u32 sect, head, cyl, track; + if (n_block > 256) + goto invalid_fld; + /* Convert LBA to CHS */ track = (u32)block / dev->sectors; cyl = track / dev->heads; @@ -733,8 +738,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; - unsigned int lba = tf->flags & ATA_TFLAG_LBA; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 block; u32 n_block; @@ -783,19 +786,24 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) */ goto nothing_to_do; - if (lba) { - if (lba48) { + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) { /* The request -may- be too large for LBA48. */ if ((block >> 48) || (n_block > 65536)) goto out_of_range; + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + tf->hob_nsect = (n_block >> 8) & 0xff; tf->hob_lbah = (block >> 40) & 0xff; tf->hob_lbam = (block >> 32) & 0xff; tf->hob_lbal = (block >> 24) & 0xff; } else { - /* LBA28 */ + /* use LBA28 */ /* The request -may- be too large for LBA28. */ if ((block >> 28) || (n_block > 256)) From 8cbd6df1f0ce977ab7b61feffa59879bb5e0ed8f Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 12 Oct 2005 15:06:27 +0800 Subject: [PATCH 0439/1939] [PATCH] libata CHS: calculate read/write commands and protocol on the fly (revise #6) - merge ata_prot_to_cmd() and ata_dev_set_protocol() as ata_rwcmd_protocol() - pave road for read/write multiple support - remove usage of pre-cached command and protocol values and call ata_rwcmd_protocol() instead Signed-off-by: Albert Lee ============== Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 105 +++++++++++++------------------------ drivers/scsi/libata-scsi.c | 13 +++-- drivers/scsi/libata.h | 1 + include/linux/ata.h | 4 ++ include/linux/libata.h | 6 +-- 5 files changed, 50 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 55d4dee133af..19d3d717faf6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) tf->hob_nsect = fis[13]; } -/** - * ata_prot_to_cmd - determine which read/write opcodes to use - * @protocol: ATA_PROT_xxx taskfile protocol - * @lba48: true is lba48 is present - * - * Given necessary input, determine which read/write commands - * to use to transfer data. - * - * LOCKING: - * None. - */ -static int ata_prot_to_cmd(int protocol, int lba48) -{ - int rcmd = 0, wcmd = 0; - - switch (protocol) { - case ATA_PROT_PIO: - if (lba48) { - rcmd = ATA_CMD_PIO_READ_EXT; - wcmd = ATA_CMD_PIO_WRITE_EXT; - } else { - rcmd = ATA_CMD_PIO_READ; - wcmd = ATA_CMD_PIO_WRITE; - } - break; - - case ATA_PROT_DMA: - if (lba48) { - rcmd = ATA_CMD_READ_EXT; - wcmd = ATA_CMD_WRITE_EXT; - } else { - rcmd = ATA_CMD_READ; - wcmd = ATA_CMD_WRITE; - } - break; - - default: - return -1; - } - - return rcmd | (wcmd << 8); -} +static const u8 ata_rw_cmds[] = { + /* pio multi */ + ATA_CMD_READ_MULTI, + ATA_CMD_WRITE_MULTI, + ATA_CMD_READ_MULTI_EXT, + ATA_CMD_WRITE_MULTI_EXT, + /* pio */ + ATA_CMD_PIO_READ, + ATA_CMD_PIO_WRITE, + ATA_CMD_PIO_READ_EXT, + ATA_CMD_PIO_WRITE_EXT, + /* dma */ + ATA_CMD_READ, + ATA_CMD_WRITE, + ATA_CMD_READ_EXT, + ATA_CMD_WRITE_EXT +}; /** - * ata_dev_set_protocol - set taskfile protocol and r/w commands - * @dev: device to examine and configure + * ata_rwcmd_protocol - set taskfile r/w commands and protocol + * @qc: command to examine and configure * - * Examine the device configuration, after we have - * read the identify-device page and configured the - * data transfer mode. Set internal state related to - * the ATA taskfile protocol (pio, pio mult, dma, etc.) - * and calculate the proper read/write commands to use. + * Examine the device configuration and tf->flags to calculate + * the proper read/write commands and protocol to use. * * LOCKING: * caller. */ -static void ata_dev_set_protocol(struct ata_device *dev) +void ata_rwcmd_protocol(struct ata_queued_cmd *qc) { - int pio = (dev->flags & ATA_DFLAG_PIO); - int lba48 = (dev->flags & ATA_DFLAG_LBA48); - int proto, cmd; + struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; - if (pio) - proto = dev->xfer_protocol = ATA_PROT_PIO; - else - proto = dev->xfer_protocol = ATA_PROT_DMA; + int index, lba48, write; + + lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0; + write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0; - cmd = ata_prot_to_cmd(proto, lba48); - if (cmd < 0) - BUG(); + if (dev->flags & ATA_DFLAG_PIO) { + tf->protocol = ATA_PROT_PIO; + index = dev->multi_count ? 0 : 4; + } else { + tf->protocol = ATA_PROT_DMA; + index = 8; + } - dev->read_cmd = cmd & 0xff; - dev->write_cmd = (cmd >> 8) & 0xff; + tf->command = ata_rw_cmds[index + lba48 + write]; } static const char * xfer_mode_str[] = { @@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, */ static void ata_set_mode(struct ata_port *ap) { - unsigned int i, xfer_shift; + unsigned int xfer_shift; u8 xfer_mode; int rc; @@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port *ap) if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); - for (i = 0; i < 2; i++) { - struct ata_device *dev = &ap->device[i]; - ata_dev_set_protocol(dev); - } - return; err_out: diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index ea7a4d8a6fc9..90bf22204668 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -742,15 +742,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->protocol = qc->dev->xfer_protocol; - if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || - scsicmd[0] == READ_16) { - tf->command = qc->dev->read_cmd; - } else { - tf->command = qc->dev->write_cmd; + if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || + scsicmd[0] == WRITE_16) tf->flags |= ATA_TFLAG_WRITE; - } /* Calculate the SCSI LBA and transfer length. */ switch (scsicmd[0]) { @@ -812,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->device |= (block >> 24) & 0xf; } + ata_rwcmd_protocol(qc); + qc->nsect = n_block; tf->nsect = n_block & 0xff; @@ -828,6 +825,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) if ((block >> 28) || (n_block > 256)) goto out_of_range; + ata_rwcmd_protocol(qc); + /* Convert LBA to CHS */ track = (u32)block / dev->sectors; cyl = track / dev->heads; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index a18f2ac1d4a1..67d752ca8ae2 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -42,6 +42,7 @@ extern int atapi_enabled; extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); +extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); diff --git a/include/linux/ata.h b/include/linux/ata.h index ecb7346d0c16..630908c9378b 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -128,6 +128,10 @@ enum { ATA_CMD_PIO_READ_EXT = 0x24, ATA_CMD_PIO_WRITE = 0x30, ATA_CMD_PIO_WRITE_EXT = 0x34, + ATA_CMD_READ_MULTI = 0xC4, + ATA_CMD_READ_MULTI_EXT = 0x29, + ATA_CMD_WRITE_MULTI = 0xC5, + ATA_CMD_WRITE_MULTI_EXT = 0x39, ATA_CMD_SET_FEATURES = 0xEF, ATA_CMD_PACKET = 0xA0, ATA_CMD_VERIFY = 0x40, diff --git a/include/linux/libata.h b/include/linux/libata.h index 7929cfc9318d..0261c55f3483 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -283,10 +283,8 @@ struct ata_device { u8 xfer_mode; unsigned int xfer_shift; /* ATA_SHIFT_xxx */ - /* cache info about current transfer mode */ - u8 xfer_protocol; /* taskfile xfer protocol */ - u8 read_cmd; /* opcode to use on read */ - u8 write_cmd; /* opcode to use on write */ + unsigned int multi_count; /* sectors count for + READ/WRITE MULTIPLE */ /* for CHS addressing */ u16 cylinders; /* Number of cylinders */ From 59a10b172fccaea793352c00fd9065f0a5b4ef70 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 12 Oct 2005 15:09:42 +0800 Subject: [PATCH 0440/1939] [PATCH] libata CHS: reread device identify info (revise #6) problem: id[53-58] might be changed after initializing device CHS settings. changes: - call ata_dev_reread_id() to reread the identify device info, after initializing device CHS settings. Signed-off-by: Albert Lee ============ Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 65 +++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 19d3d717faf6..175d4646333d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -63,6 +63,7 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); @@ -1240,9 +1241,15 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) * anything else.. * Some drives were very specific about that exact sequence. */ - if (major_version < 4 || (!ata_id_has_lba(dev->id))) + if (major_version < 4 || (!ata_id_has_lba(dev->id))) { ata_dev_init_params(ap, dev); + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + ata_dev_reread_id(ap, dev); + } + if (ata_id_has_lba(dev->id)) { dev->flags |= ATA_DFLAG_LBA; @@ -2150,6 +2157,62 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) DPRINTK("EXIT\n"); } +/** + * ata_dev_reread_id - Reread the device identify device info + * @ap: port where the device is + * @dev: device to reread the identify device info + * + * LOCKING: + */ + +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->dma_dir = DMA_FROM_DEVICE; + + if (dev->class == ATA_DEV_ATA) { + qc->tf.command = ATA_CMD_ID_ATA; + DPRINTK("do ATA identify\n"); + } else { + qc->tf.command = ATA_CMD_ID_ATAPI; + DPRINTK("do ATAPI identify\n"); + } + + qc->tf.flags |= ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + goto err_out; + + wait_for_completion(&wait); + + swap_buf_le16(dev->id, ATA_ID_WORDS); + + ata_dump_id(dev); + + DPRINTK("EXIT\n"); + + return; +err_out: + ata_port_disable(ap); +} + /** * ata_dev_init_params - Issue INIT DEV PARAMS command * @ap: Port associated with device @dev From ea635a517e350eb03ab5f01618417f31b82a9a4d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 6 Oct 2005 23:12:58 -0400 Subject: [PATCH 0441/1939] SUNRPC: Retry rpcbind requests if the server's portmapper isn't up After a server crash/reboot, rebinding should always retry, otherwise requests on "hard" mounts will fail when they shouldn't. Test plan: Run a lock-intensive workload against a server while rebooting the server repeatedly. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5a8f01d726e9..a5f7029b1daa 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -759,7 +759,8 @@ call_bind_status(struct rpc_task *task) case -EACCES: dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", task->tk_pid); - break; + rpc_delay(task, 3*HZ); + goto retry_bind; case -ETIMEDOUT: dprintk("RPC: %4d rpcbind request timed out\n", task->tk_pid); From 5e5ce5be6f0161d2a069a4f8a1154fe639c5c02f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:11 -0700 Subject: [PATCH 0442/1939] RPC: allow call_encode() to delay transmission of an RPC call. Currently, call_encode will cause the entire RPC call to abort if it returns an error. This is unnecessarily rigid, and gets in the way of attempts to allow the NFSv4 layer to order RPC calls that carry sequence ids. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/clnt.c | 23 ++++++++++++----------- net/sunrpc/xprt.c | 8 ++++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 99cad3ead81d..068e1fb0868b 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -211,6 +211,7 @@ int xprt_reserve_xprt(struct rpc_task *task); int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); +void xprt_abort_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index a5f7029b1daa..534274056329 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -678,13 +678,11 @@ call_allocate(struct rpc_task *task) static void call_encode(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; struct xdr_buf *sndbuf = &req->rq_snd_buf; struct xdr_buf *rcvbuf = &req->rq_rcv_buf; unsigned int bufsiz; kxdrproc_t encode; - int status; u32 *p; dprintk("RPC: %4d call_encode (status %d)\n", @@ -712,12 +710,9 @@ call_encode(struct rpc_task *task) rpc_exit(task, -EIO); return; } - if (encode && (status = rpcauth_wrap_req(task, encode, req, p, - task->tk_msg.rpc_argp)) < 0) { - printk(KERN_WARNING "%s: can't encode arguments: %d\n", - clnt->cl_protname, -status); - rpc_exit(task, status); - } + if (encode != NULL) + task->tk_status = rpcauth_wrap_req(task, encode, req, p, + task->tk_msg.rpc_argp); } /* @@ -865,10 +860,12 @@ call_transmit(struct rpc_task *task) if (task->tk_status != 0) return; /* Encode here so that rpcsec_gss can use correct sequence number. */ - if (!task->tk_rqstp->rq_bytes_sent) + if (task->tk_rqstp->rq_bytes_sent == 0) { call_encode(task); - if (task->tk_status < 0) - return; + /* Did the encode result in an error condition? */ + if (task->tk_status != 0) + goto out_nosend; + } xprt_transmit(task); if (task->tk_status < 0) return; @@ -876,6 +873,10 @@ call_transmit(struct rpc_task *task) task->tk_action = NULL; rpc_wake_up_task(task); } + return; +out_nosend: + /* release socket write lock before attempting to handle error */ + xprt_abort_transmit(task); } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 215be0d0ef6b..1ba55dc38b7a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -709,6 +709,14 @@ int xprt_prepare_transmit(struct rpc_task *task) return err; } +void +xprt_abort_transmit(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + + xprt_release_write(xprt, task); +} + /** * xprt_transmit - send an RPC request on a transport * @task: controlling RPC task From cee54fc944422c44e476736c045a9e8053cb0644 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:12 -0700 Subject: [PATCH 0443/1939] NFSv4: Add functions to order RPC calls NFSv4 file state-changing functions such as OPEN, CLOSE, LOCK,... are all labelled with "sequence identifiers" in order to prevent the server from reordering RPC requests, as this could cause its file state to become out of sync with the client. Currently the NFS client code enforces this ordering locally using semaphores to restrict access to structures until the RPC call is done. This, of course, only works with synchronous RPC calls, since the user process must first grab the semaphore. By dropping semaphores, and instead teaching the RPC engine to hold the RPC calls until they are ready to be sent, we can extend this process to work nicely with asynchronous RPC calls too. This patch adds a new list called "rpc_sequence" that defines the order of the RPC calls to be sent. We add one such list for each state_owner. When an RPC call is ready to be sent, it checks if it is top of the rpc_sequence list. If so, it proceeds. If not, it goes back to sleep, and loops until it hits top of the list. Once the RPC call has completed, it can then bump the sequence id counter, and remove itself from the rpc_sequence list, and then wake up the next sleeper. Note that the state_owner sequence ids and lock_owner sequence ids are all indexed to the same rpc_sequence list, so OPEN, LOCK,... requests are all ordered w.r.t. each other. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 42 ++++++++++-- fs/nfs/nfs4proc.c | 111 ++++++++++++++++++++----------- fs/nfs/nfs4state.c | 143 +++++++++++++++++++++++++++++++++------- fs/nfs/nfs4xdr.c | 43 +++++++++--- include/linux/nfs_xdr.h | 15 +++-- 5 files changed, 272 insertions(+), 82 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index ec1a22d7b876..6ac6708484f5 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -92,6 +92,35 @@ struct nfs4_client { unsigned char cl_id_uniquifier; }; +/* + * struct rpc_sequence ensures that RPC calls are sent in the exact + * order that they appear on the list. + */ +struct rpc_sequence { + struct rpc_wait_queue wait; /* RPC call delay queue */ + spinlock_t lock; /* Protects the list */ + struct list_head list; /* Defines sequence of RPC calls */ +}; + +#define NFS_SEQID_CONFIRMED 1 +struct nfs_seqid_counter { + struct rpc_sequence *sequence; + int flags; + u32 counter; +}; + +struct nfs_seqid { + struct list_head list; + struct nfs_seqid_counter *sequence; + struct rpc_task *task; +}; + +static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status) +{ + if (seqid_mutating_err(-status)) + seqid->flags |= NFS_SEQID_CONFIRMED; +} + /* * NFS4 state_owners and lock_owners are simply labels for ordered * sequences of RPC calls. Their sole purpose is to provide once-only @@ -106,12 +135,13 @@ struct nfs4_state_owner { struct nfs4_client *so_client; u32 so_id; /* 32-bit identifier, unique */ struct semaphore so_sema; - u32 so_seqid; /* protected by so_sema */ atomic_t so_count; struct rpc_cred *so_cred; /* Associated cred */ struct list_head so_states; struct list_head so_delegations; + struct nfs_seqid_counter so_seqid; + struct rpc_sequence so_sequence; }; /* @@ -132,7 +162,7 @@ struct nfs4_lock_state { fl_owner_t ls_owner; /* POSIX lock owner */ #define NFS_LOCK_INITIALIZED 1 int ls_flags; - u32 ls_seqid; + struct nfs_seqid_counter ls_seqid; u32 ls_id; nfs4_stateid ls_stateid; atomic_t ls_count; @@ -224,12 +254,16 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_close_state(struct nfs4_state *, mode_t); extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); -extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); extern void nfs4_schedule_state_recovery(struct nfs4_client *); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); -extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); +extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); +extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); +extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); +extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); +extern void nfs_free_seqid(struct nfs_seqid *seqid); + extern const nfs4_stateid zero_stateid; /* nfs4xdr.c */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9701ca8c9428..9ba89e7cdd28 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -218,7 +218,6 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st struct nfs_delegation *delegation = NFS_I(inode)->delegation; struct nfs_openargs o_arg = { .fh = NFS_FH(inode), - .seqid = sp->so_seqid, .id = sp->so_id, .open_flags = state->state, .clientid = server->nfs4_state->cl_clientid, @@ -245,8 +244,13 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st } o_arg.u.delegation_type = delegation->type; } + o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); + if (o_arg.seqid == NULL) + return -ENOMEM; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); + /* Confirm the sequence as being established */ + nfs_confirm_seqid(&sp->so_seqid, status); + nfs_increment_open_seqid(status, o_arg.seqid); if (status == 0) { memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); if (o_res.delegation_type != 0) { @@ -256,6 +260,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st nfs_async_inode_return_delegation(inode, &o_res.stateid); } } + nfs_free_seqid(o_arg.seqid); clear_bit(NFS_DELEGATED_STATE, &state->flags); /* Ensure we update the inode attributes */ NFS_CACHEINV(inode); @@ -307,16 +312,20 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state goto out; if (state->state == 0) goto out; - arg.seqid = sp->so_seqid; + arg.seqid = nfs_alloc_seqid(&sp->so_seqid); + status = -ENOMEM; + if (arg.seqid == NULL) + goto out; arg.open_flags = state->state; memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); + nfs_increment_open_seqid(status, arg.seqid); if (status >= 0) { memcpy(state->stateid.data, res.stateid.data, sizeof(state->stateid.data)); clear_bit(NFS_DELEGATED_STATE, &state->flags); } + nfs_free_seqid(arg.seqid); out: up(&sp->so_sema); dput(parent); @@ -345,11 +354,11 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) return err; } -static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) +static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) { struct nfs_open_confirmargs arg = { .fh = fh, - .seqid = sp->so_seqid, + .seqid = seqid, .stateid = *stateid, }; struct nfs_open_confirmres res; @@ -362,7 +371,9 @@ static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nf int status; status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); + /* Confirm the sequence as being established */ + nfs_confirm_seqid(&sp->so_seqid, status); + nfs_increment_open_seqid(status, seqid); if (status >= 0) memcpy(stateid, &res.stateid, sizeof(*stateid)); return status; @@ -380,21 +391,21 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru int status; /* Update sequence id. The caller must serialize! */ - o_arg->seqid = sp->so_seqid; o_arg->id = sp->so_id; o_arg->clientid = sp->so_client->cl_clientid; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); + nfs_increment_open_seqid(status, o_arg->seqid); if (status != 0) goto out; update_changeattr(dir, &o_res->cinfo); if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { status = _nfs4_proc_open_confirm(server->client, &o_res->fh, - sp, &o_res->stateid); + sp, &o_res->stateid, o_arg->seqid); if (status != 0) goto out; } + nfs_confirm_seqid(&sp->so_seqid, 0); if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); out: @@ -465,6 +476,10 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st set_bit(NFS_DELEGATED_STATE, &state->flags); goto out; } + o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); + status = -ENOMEM; + if (o_arg.seqid == NULL) + goto out; status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_nodeleg; @@ -490,6 +505,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); } out_nodeleg: + nfs_free_seqid(o_arg.seqid); clear_bit(NFS_DELEGATED_STATE, &state->flags); out: dput(parent); @@ -667,6 +683,9 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st /* Serialization for the sequence id */ down(&sp->so_sema); + o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); + if (o_arg.seqid == NULL) + return -ENOMEM; status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_err; @@ -681,6 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st update_open_stateid(state, &o_res.stateid, flags); if (o_res.delegation_type != 0) nfs_inode_set_delegation(inode, cred, &o_res); + nfs_free_seqid(o_arg.seqid); up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&clp->cl_sem); @@ -690,6 +710,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st if (sp != NULL) { if (state != NULL) nfs4_put_open_state(state); + nfs_free_seqid(o_arg.seqid); up(&sp->so_sema); nfs4_put_state_owner(sp); } @@ -718,7 +739,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, * It is actually a sign of a bug on the client or on the server. * * If we receive a BAD_SEQID error in the particular case of - * doing an OPEN, we assume that nfs4_increment_seqid() will + * doing an OPEN, we assume that nfs_increment_open_seqid() will * have unhashed the old state_owner for us, and that we can * therefore safely retry using a new one. We should still warn * the user though... @@ -799,7 +820,7 @@ static void nfs4_close_done(struct rpc_task *task) /* hmm. we are done with the inode, and in the process of freeing * the state_owner. we keep this around to process errors */ - nfs4_increment_seqid(task->tk_status, sp); + nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); switch (task->tk_status) { case 0: memcpy(&state->stateid, &calldata->res.stateid, @@ -818,6 +839,7 @@ static void nfs4_close_done(struct rpc_task *task) } state->state = calldata->arg.open_flags; nfs4_put_open_state(state); + nfs_free_seqid(calldata->arg.seqid); up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&server->nfs4_state->cl_sem); @@ -865,7 +887,11 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) calldata->state = state; calldata->arg.fh = NFS_FH(inode); /* Serialization for the sequence id */ - calldata->arg.seqid = state->owner->so_seqid; + calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); + if (calldata->arg.seqid == NULL) { + kfree(calldata); + return -ENOMEM; + } calldata->arg.open_flags = mode; memcpy(&calldata->arg.stateid, &state->stateid, sizeof(calldata->arg.stateid)); @@ -2729,15 +2755,19 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock /* We might have lost the locks! */ if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) goto out; - luargs.seqid = lsp->ls_seqid; - memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); + luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); + status = -ENOMEM; + if (luargs.seqid == NULL) + goto out; + memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data)); arg.u.locku = &luargs; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_lock_seqid(status, lsp); + nfs_increment_lock_seqid(status, luargs.seqid); if (status == 0) - memcpy(&lsp->ls_stateid, &res.u.stateid, - sizeof(lsp->ls_stateid)); + memcpy(lsp->ls_stateid.data, res.u.stateid.data, + sizeof(lsp->ls_stateid.data)); + nfs_free_seqid(luargs.seqid); out: up(&state->lock_sema); if (status == 0) @@ -2783,9 +2813,13 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r .reclaim = reclaim, .new_lock_owner = 0, }; - int status; + struct nfs_seqid *lock_seqid; + int status = -ENOMEM; - if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { + lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); + if (lock_seqid == NULL) + return -ENOMEM; + if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { struct nfs4_state_owner *owner = state->owner; struct nfs_open_to_lock otl = { .lock_owner = { @@ -2793,39 +2827,40 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r }, }; - otl.lock_seqid = lsp->ls_seqid; + otl.lock_seqid = lock_seqid; otl.lock_owner.id = lsp->ls_id; memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid)); largs.u.open_lock = &otl; largs.new_lock_owner = 1; arg.u.lock = &largs; down(&owner->so_sema); - otl.open_seqid = owner->so_seqid; - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - /* increment open_owner seqid on success, and - * seqid mutating errors */ - nfs4_increment_seqid(status, owner); - up(&owner->so_sema); - if (status == 0) { - lsp->ls_flags |= NFS_LOCK_INITIALIZED; - lsp->ls_seqid++; + otl.open_seqid = nfs_alloc_seqid(&owner->so_seqid); + if (otl.open_seqid != NULL) { + status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + /* increment seqid on success, and seqid mutating errors */ + nfs_increment_open_seqid(status, otl.open_seqid); + nfs_free_seqid(otl.open_seqid); } + up(&owner->so_sema); + if (status == 0) + nfs_confirm_seqid(&lsp->ls_seqid, 0); } else { - struct nfs_exist_lock el = { - .seqid = lsp->ls_seqid, - }; + struct nfs_exist_lock el; memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); largs.u.exist_lock = ⪙ arg.u.lock = &largs; + el.seqid = lock_seqid; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - /* increment seqid on success, and * seqid mutating errors*/ - nfs4_increment_lock_seqid(status, lsp); } + /* increment seqid on success, and seqid mutating errors*/ + nfs_increment_lock_seqid(status, lock_seqid); /* save the returned stateid. */ - if (status == 0) - memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); - else if (status == -NFS4ERR_DENIED) + if (status == 0) { + memcpy(lsp->ls_stateid.data, res.u.stateid.data, sizeof(lsp->ls_stateid.data)); + lsp->ls_flags |= NFS_LOCK_INITIALIZED; + } else if (status == -NFS4ERR_DENIED) status = -EAGAIN; + nfs_free_seqid(lock_seqid); return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index afe587d82f1e..f535c219cf3a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -264,13 +264,16 @@ nfs4_alloc_state_owner(void) { struct nfs4_state_owner *sp; - sp = kmalloc(sizeof(*sp),GFP_KERNEL); + sp = kzalloc(sizeof(*sp),GFP_KERNEL); if (!sp) return NULL; init_MUTEX(&sp->so_sema); - sp->so_seqid = 0; /* arbitrary */ INIT_LIST_HEAD(&sp->so_states); INIT_LIST_HEAD(&sp->so_delegations); + rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); + sp->so_seqid.sequence = &sp->so_sequence; + spin_lock_init(&sp->so_sequence.lock); + INIT_LIST_HEAD(&sp->so_sequence.list); atomic_set(&sp->so_count, 1); return sp; } @@ -553,12 +556,10 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f struct nfs4_lock_state *lsp; struct nfs4_client *clp = state->owner->so_client; - lsp = kmalloc(sizeof(*lsp), GFP_KERNEL); + lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); if (lsp == NULL) return NULL; - lsp->ls_flags = 0; - lsp->ls_seqid = 0; /* arbitrary */ - memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); + lsp->ls_seqid.sequence = &state->owner->so_sequence; atomic_set(&lsp->ls_count, 1); lsp->ls_owner = fl_owner; spin_lock(&clp->cl_lock); @@ -673,29 +674,102 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f nfs4_put_lock_state(lsp); } -/* -* Called with state->lock_sema and clp->cl_sem held. -*/ -void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) +struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) { - if (status == NFS_OK || seqid_mutating_err(-status)) - lsp->ls_seqid++; + struct rpc_sequence *sequence = counter->sequence; + struct nfs_seqid *new; + + new = kmalloc(sizeof(*new), GFP_KERNEL); + if (new != NULL) { + new->sequence = counter; + new->task = NULL; + spin_lock(&sequence->lock); + list_add_tail(&new->list, &sequence->list); + spin_unlock(&sequence->lock); + } + return new; +} + +void nfs_free_seqid(struct nfs_seqid *seqid) +{ + struct rpc_sequence *sequence = seqid->sequence->sequence; + struct rpc_task *next = NULL; + + spin_lock(&sequence->lock); + list_del(&seqid->list); + if (!list_empty(&sequence->list)) { + next = list_entry(sequence->list.next, struct nfs_seqid, list)->task; + if (next) + rpc_wake_up_task(next); + } + spin_unlock(&sequence->lock); + kfree(seqid); } /* -* Called with sp->so_sema and clp->cl_sem held. -* -* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or -* failed with a seqid incrementing error - -* see comments nfs_fs.h:seqid_mutating_error() -*/ -void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp) + * Called with sp->so_sema and clp->cl_sem held. + * + * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or + * failed with a seqid incrementing error - + * see comments nfs_fs.h:seqid_mutating_error() + */ +static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid) { - if (status == NFS_OK || seqid_mutating_err(-status)) - sp->so_seqid++; - /* If the server returns BAD_SEQID, unhash state_owner here */ - if (status == -NFS4ERR_BAD_SEQID) + switch (status) { + case 0: + break; + case -NFS4ERR_BAD_SEQID: + case -NFS4ERR_STALE_CLIENTID: + case -NFS4ERR_STALE_STATEID: + case -NFS4ERR_BAD_STATEID: + case -NFS4ERR_BADXDR: + case -NFS4ERR_RESOURCE: + case -NFS4ERR_NOFILEHANDLE: + /* Non-seqid mutating errors */ + return; + }; + /* + * Note: no locking needed as we are guaranteed to be first + * on the sequence list + */ + seqid->sequence->counter++; +} + +void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) +{ + if (status == -NFS4ERR_BAD_SEQID) { + struct nfs4_state_owner *sp = container_of(seqid->sequence, + struct nfs4_state_owner, so_seqid); nfs4_drop_state_owner(sp); + } + return nfs_increment_seqid(status, seqid); +} + +/* + * Called with ls->lock_sema and clp->cl_sem held. + * + * Increment the seqid if the LOCK/LOCKU succeeded, or + * failed with a seqid incrementing error - + * see comments nfs_fs.h:seqid_mutating_error() + */ +void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) +{ + return nfs_increment_seqid(status, seqid); +} + +int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) +{ + struct rpc_sequence *sequence = seqid->sequence->sequence; + int status = 0; + + spin_lock(&sequence->lock); + if (sequence->list.next != &seqid->list) { + seqid->task = task; + rpc_sleep_on(&sequence->wait, task, NULL, NULL); + status = -EAGAIN; + } + spin_unlock(&sequence->lock); + return status; } static int reclaimer(void *); @@ -791,8 +865,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n if (state->state == 0) continue; status = ops->recover_open(sp, state); - list_for_each_entry(lock, &state->lock_states, ls_locks) - lock->ls_flags &= ~NFS_LOCK_INITIALIZED; if (status >= 0) { status = nfs4_reclaim_locks(ops, state); if (status < 0) @@ -831,6 +903,26 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n return status; } +static void nfs4_state_mark_reclaim(struct nfs4_client *clp) +{ + struct nfs4_state_owner *sp; + struct nfs4_state *state; + struct nfs4_lock_state *lock; + + /* Reset all sequence ids to zero */ + list_for_each_entry(sp, &clp->cl_state_owners, so_list) { + sp->so_seqid.counter = 0; + sp->so_seqid.flags = 0; + list_for_each_entry(state, &sp->so_states, open_states) { + list_for_each_entry(lock, &state->lock_states, ls_locks) { + lock->ls_seqid.counter = 0; + lock->ls_seqid.flags = 0; + lock->ls_flags &= ~NFS_LOCK_INITIALIZED; + } + } + } +} + static int reclaimer(void *ptr) { struct reclaimer_args *args = (struct reclaimer_args *)ptr; @@ -864,6 +956,7 @@ static int reclaimer(void *ptr) default: ops = &nfs4_network_partition_recovery_ops; }; + nfs4_state_mark_reclaim(clp); status = __nfs4_init_client(clp); if (status) goto out_error; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6c564ef9489e..fcd28a29a2f8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -604,7 +604,7 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) RESERVE_SPACE(8+sizeof(arg->stateid.data)); WRITE32(OP_CLOSE); - WRITE32(arg->seqid); + WRITE32(arg->seqid->sequence->counter); WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); return 0; @@ -732,9 +732,9 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) struct nfs_open_to_lock *ol = opargs->u.open_lock; RESERVE_SPACE(40); - WRITE32(ol->open_seqid); + WRITE32(ol->open_seqid->sequence->counter); WRITEMEM(&ol->open_stateid, sizeof(ol->open_stateid)); - WRITE32(ol->lock_seqid); + WRITE32(ol->lock_seqid->sequence->counter); WRITE64(ol->lock_owner.clientid); WRITE32(4); WRITE32(ol->lock_owner.id); @@ -744,7 +744,7 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) RESERVE_SPACE(20); WRITEMEM(&el->stateid, sizeof(el->stateid)); - WRITE32(el->seqid); + WRITE32(el->seqid->sequence->counter); } return 0; @@ -775,7 +775,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) RESERVE_SPACE(44); WRITE32(OP_LOCKU); WRITE32(arg->type); - WRITE32(opargs->seqid); + WRITE32(opargs->seqid->sequence->counter); WRITEMEM(&opargs->stateid, sizeof(opargs->stateid)); WRITE64(arg->offset); WRITE64(arg->length); @@ -826,7 +826,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena */ RESERVE_SPACE(8); WRITE32(OP_OPEN); - WRITE32(arg->seqid); + WRITE32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->open_flags); RESERVE_SPACE(16); WRITE64(arg->clientid); @@ -941,7 +941,7 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con RESERVE_SPACE(8+sizeof(arg->stateid.data)); WRITE32(OP_OPEN_CONFIRM); WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); - WRITE32(arg->seqid); + WRITE32(arg->seqid->sequence->counter); return 0; } @@ -953,7 +953,7 @@ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closea RESERVE_SPACE(8+sizeof(arg->stateid.data)); WRITE32(OP_OPEN_DOWNGRADE); WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); - WRITE32(arg->seqid); + WRITE32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->open_flags); return 0; } @@ -1416,6 +1416,9 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos }; int status; + status = nfs_wait_on_sequence(args->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1437,6 +1440,9 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena }; int status; + status = nfs_wait_on_sequence(args->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1464,6 +1470,9 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n }; int status; + status = nfs_wait_on_sequence(args->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1485,6 +1494,9 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nf }; int status; + status = nfs_wait_on_sequence(args->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1506,6 +1518,9 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct }; int status; + status = nfs_wait_on_sequence(args->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1525,8 +1540,17 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_locka struct compound_hdr hdr = { .nops = 2, }; + struct nfs_lock_opargs *opargs = args->u.lock; + struct nfs_seqid *seqid; int status; + if (opargs->new_lock_owner) + seqid = opargs->u.open_lock->lock_seqid; + else + seqid = opargs->u.exist_lock->seqid; + status = nfs_wait_on_sequence(seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1569,6 +1593,9 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lock }; int status; + status = nfs_wait_on_sequence(args->u.locku->seqid, req->rq_task); + if (status != 0) + goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index a2bf6914ff1b..d578912bf9a9 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -96,12 +96,13 @@ struct nfs4_change_info { u64 after; }; +struct nfs_seqid; /* * Arguments to the open call. */ struct nfs_openargs { const struct nfs_fh * fh; - __u32 seqid; + struct nfs_seqid * seqid; int open_flags; __u64 clientid; __u32 id; @@ -136,7 +137,7 @@ struct nfs_openres { struct nfs_open_confirmargs { const struct nfs_fh * fh; nfs4_stateid stateid; - __u32 seqid; + struct nfs_seqid * seqid; }; struct nfs_open_confirmres { @@ -149,7 +150,7 @@ struct nfs_open_confirmres { struct nfs_closeargs { struct nfs_fh * fh; nfs4_stateid stateid; - __u32 seqid; + struct nfs_seqid * seqid; int open_flags; }; @@ -165,15 +166,15 @@ struct nfs_lowner { }; struct nfs_open_to_lock { - __u32 open_seqid; + struct nfs_seqid * open_seqid; nfs4_stateid open_stateid; - __u32 lock_seqid; + struct nfs_seqid * lock_seqid; struct nfs_lowner lock_owner; }; struct nfs_exist_lock { nfs4_stateid stateid; - __u32 seqid; + struct nfs_seqid * seqid; }; struct nfs_lock_opargs { @@ -186,7 +187,7 @@ struct nfs_lock_opargs { }; struct nfs_locku_opargs { - __u32 seqid; + struct nfs_seqid * seqid; nfs4_stateid stateid; }; From 9512135df14f8293b9bc5e8fb22d4279dee5ff66 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:12 -0700 Subject: [PATCH 0444/1939] NFSv4: Fix a potential CLOSE race Once the state_owner and lock_owner semaphores get removed, it will be possible for other OPEN requests to reopen the same file if they have lower sequence ids than our CLOSE call. This patch ensures that we recheck the file state once nfs_wait_on_sequence() has completed waiting. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 110 ++++++++++++++++++++++++++++------------ fs/nfs/nfs4state.c | 6 ++- fs/nfs/nfs4xdr.c | 14 ++--- include/linux/nfs_xdr.h | 2 +- 4 files changed, 87 insertions(+), 45 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9ba89e7cdd28..5154ddf6d9a5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -189,6 +189,21 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf nfsi->change_attr = cinfo->after; } +/* Helper for asynchronous RPC calls */ +static int nfs4_call_async(struct rpc_clnt *clnt, rpc_action tk_begin, + rpc_action tk_exit, void *calldata) +{ + struct rpc_task *task; + + if (!(task = rpc_new_task(clnt, tk_exit, RPC_TASK_ASYNC))) + return -ENOMEM; + + task->tk_calldata = calldata; + task->tk_action = tk_begin; + rpc_execute(task); + return 0; +} + static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) { struct inode *inode = state->inode; @@ -810,11 +825,24 @@ struct nfs4_closedata { struct nfs_closeres res; }; +static void nfs4_free_closedata(struct nfs4_closedata *calldata) +{ + struct nfs4_state *state = calldata->state; + struct nfs4_state_owner *sp = state->owner; + struct nfs_server *server = NFS_SERVER(calldata->inode); + + nfs4_put_open_state(calldata->state); + nfs_free_seqid(calldata->arg.seqid); + up(&sp->so_sema); + nfs4_put_state_owner(sp); + up_read(&server->nfs4_state->cl_sem); + kfree(calldata); +} + static void nfs4_close_done(struct rpc_task *task) { struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; struct nfs4_state *state = calldata->state; - struct nfs4_state_owner *sp = state->owner; struct nfs_server *server = NFS_SERVER(calldata->inode); /* hmm. we are done with the inode, and in the process of freeing @@ -838,25 +866,46 @@ static void nfs4_close_done(struct rpc_task *task) } } state->state = calldata->arg.open_flags; - nfs4_put_open_state(state); - nfs_free_seqid(calldata->arg.seqid); - up(&sp->so_sema); - nfs4_put_state_owner(sp); - up_read(&server->nfs4_state->cl_sem); - kfree(calldata); + nfs4_free_closedata(calldata); } -static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata *calldata) +static void nfs4_close_begin(struct rpc_task *task) { + struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; + struct nfs4_state *state = calldata->state; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], .rpc_argp = &calldata->arg, .rpc_resp = &calldata->res, - .rpc_cred = calldata->state->owner->so_cred, + .rpc_cred = state->owner->so_cred, }; - if (calldata->arg.open_flags != 0) + int mode = 0; + int status; + + status = nfs_wait_on_sequence(calldata->arg.seqid, task); + if (status != 0) + return; + /* Don't reorder reads */ + smp_rmb(); + /* Recalculate the new open mode in case someone reopened the file + * while we were waiting in line to be scheduled. + */ + if (state->nreaders != 0) + mode |= FMODE_READ; + if (state->nwriters != 0) + mode |= FMODE_WRITE; + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) + state->state = mode; + if (mode == state->state) { + nfs4_free_closedata(calldata); + task->tk_exit = NULL; + rpc_exit(task, 0); + return; + } + if (mode != 0) msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; - return rpc_call_async(clnt, &msg, 0, nfs4_close_done, calldata); + calldata->arg.open_flags = mode; + rpc_call_setup(task, &msg, 0); } /* @@ -873,35 +922,30 @@ static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata * int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) { struct nfs4_closedata *calldata; - int status; + int status = -ENOMEM; - /* Tell caller we're done */ - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { - state->state = mode; - return 0; - } - calldata = (struct nfs4_closedata *)kmalloc(sizeof(*calldata), GFP_KERNEL); + calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); if (calldata == NULL) - return -ENOMEM; + goto out; calldata->inode = inode; calldata->state = state; calldata->arg.fh = NFS_FH(inode); + calldata->arg.stateid = &state->stateid; /* Serialization for the sequence id */ calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); - if (calldata->arg.seqid == NULL) { - kfree(calldata); - return -ENOMEM; - } - calldata->arg.open_flags = mode; - memcpy(&calldata->arg.stateid, &state->stateid, - sizeof(calldata->arg.stateid)); - status = nfs4_close_call(NFS_SERVER(inode)->client, calldata); - /* - * Return -EINPROGRESS on success in order to indicate to the - * caller that an asynchronous RPC call has been launched, and - * that it will release the semaphores on completion. - */ - return (status == 0) ? -EINPROGRESS : status; + if (calldata->arg.seqid == NULL) + goto out_free_calldata; + + status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_close_begin, + nfs4_close_done, calldata); + if (status == 0) + goto out; + + nfs_free_seqid(calldata->arg.seqid); +out_free_calldata: + kfree(calldata); +out: + return status; } struct inode * diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f535c219cf3a..59c93f37e1b2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -518,7 +518,11 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) newstate |= FMODE_WRITE; if (state->state == newstate) goto out; - if (nfs4_do_close(inode, state, newstate) == -EINPROGRESS) + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { + state->state = newstate; + goto out; + } + if (nfs4_do_close(inode, state, newstate) == 0) return; } out: diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index fcd28a29a2f8..934ec50ea6bf 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -602,10 +602,10 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; - RESERVE_SPACE(8+sizeof(arg->stateid.data)); + RESERVE_SPACE(8+sizeof(arg->stateid->data)); WRITE32(OP_CLOSE); WRITE32(arg->seqid->sequence->counter); - WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); + WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data)); return 0; } @@ -950,9 +950,9 @@ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closea { uint32_t *p; - RESERVE_SPACE(8+sizeof(arg->stateid.data)); + RESERVE_SPACE(8+sizeof(arg->stateid->data)); WRITE32(OP_OPEN_DOWNGRADE); - WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); + WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data)); WRITE32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->open_flags); return 0; @@ -1416,9 +1416,6 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos }; int status; - status = nfs_wait_on_sequence(args->seqid, req->rq_task); - if (status != 0) - goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -1518,9 +1515,6 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct }; int status; - status = nfs_wait_on_sequence(args->seqid, req->rq_task); - if (status != 0) - goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index d578912bf9a9..cac0df950c66 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -149,7 +149,7 @@ struct nfs_open_confirmres { */ struct nfs_closeargs { struct nfs_fh * fh; - nfs4_stateid stateid; + nfs4_stateid * stateid; struct nfs_seqid * seqid; int open_flags; }; From e6dfa553cffcb9740f932311dff42f81d6ac63bb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:13 -0700 Subject: [PATCH 0445/1939] NFSv4: Remove obsolete state_owner and lock_owner semaphores OPEN, CLOSE, etc no longer need these semaphores to ensure ordering of requests. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 6 ------ fs/nfs/nfs4proc.c | 18 ------------------ fs/nfs/nfs4state.c | 15 ++++----------- 3 files changed, 4 insertions(+), 35 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6ac6708484f5..d4fcb5d0ce6c 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -125,16 +125,11 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status * NFS4 state_owners and lock_owners are simply labels for ordered * sequences of RPC calls. Their sole purpose is to provide once-only * semantics by allowing the server to identify replayed requests. - * - * The ->so_sema is held during all state_owner seqid-mutating operations: - * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize - * so_seqid. */ struct nfs4_state_owner { struct list_head so_list; /* per-clientid list of state_owners */ struct nfs4_client *so_client; u32 so_id; /* 32-bit identifier, unique */ - struct semaphore so_sema; atomic_t so_count; struct rpc_cred *so_cred; /* Associated cred */ @@ -183,7 +178,6 @@ struct nfs4_state { struct inode *inode; /* Pointer to the inode */ unsigned long flags; /* Do we hold any locks? */ - struct semaphore lock_sema; /* Serializes file locking operations */ spinlock_t state_lock; /* Protects the lock_states list */ nfs4_stateid stateid; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5154ddf6d9a5..25bab6032dfe 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -224,7 +224,6 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, /* * OPEN_RECLAIM: * reclaim state on the server after a reboot. - * Assumes caller is holding the sp->so_sem */ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) { @@ -322,7 +321,6 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state }; int status = 0; - down(&sp->so_sema); if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out; if (state->state == 0) @@ -342,7 +340,6 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state } nfs_free_seqid(arg.seqid); out: - up(&sp->so_sema); dput(parent); return status; } @@ -595,7 +592,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); goto out_err; } - down(&sp->so_sema); state = nfs4_get_open_state(inode, sp); if (state == NULL) goto out_err; @@ -620,7 +616,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred set_bit(NFS_DELEGATED_STATE, &state->flags); update_open_stateid(state, &delegation->stateid, open_flags); out_ok: - up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&nfsi->rwsem); up_read(&clp->cl_sem); @@ -631,7 +626,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred if (sp != NULL) { if (state != NULL) nfs4_put_open_state(state); - up(&sp->so_sema); nfs4_put_state_owner(sp); } up_read(&nfsi->rwsem); @@ -696,7 +690,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st } else o_arg.u.attrs = sattr; /* Serialization for the sequence id */ - down(&sp->so_sema); o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); if (o_arg.seqid == NULL) @@ -716,7 +709,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st if (o_res.delegation_type != 0) nfs_inode_set_delegation(inode, cred, &o_res); nfs_free_seqid(o_arg.seqid); - up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&clp->cl_sem); *res = state; @@ -726,7 +718,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st if (state != NULL) nfs4_put_open_state(state); nfs_free_seqid(o_arg.seqid); - up(&sp->so_sema); nfs4_put_state_owner(sp); } /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ @@ -833,7 +824,6 @@ static void nfs4_free_closedata(struct nfs4_closedata *calldata) nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); - up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&server->nfs4_state->cl_sem); kfree(calldata); @@ -2702,7 +2692,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock down_read(&clp->cl_sem); nlo.clientid = clp->cl_clientid; - down(&state->lock_sema); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; @@ -2729,7 +2718,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock status = 0; } out: - up(&state->lock_sema); up_read(&clp->cl_sem); return status; } @@ -2791,7 +2779,6 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock int status; down_read(&clp->cl_sem); - down(&state->lock_sema); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; @@ -2813,7 +2800,6 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock sizeof(lsp->ls_stateid.data)); nfs_free_seqid(luargs.seqid); out: - up(&state->lock_sema); if (status == 0) do_vfs_lock(request->fl_file, request); up_read(&clp->cl_sem); @@ -2877,7 +2863,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r largs.u.open_lock = &otl; largs.new_lock_owner = 1; arg.u.lock = &largs; - down(&owner->so_sema); otl.open_seqid = nfs_alloc_seqid(&owner->so_seqid); if (otl.open_seqid != NULL) { status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); @@ -2885,7 +2870,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r nfs_increment_open_seqid(status, otl.open_seqid); nfs_free_seqid(otl.open_seqid); } - up(&owner->so_sema); if (status == 0) nfs_confirm_seqid(&lsp->ls_seqid, 0); } else { @@ -2944,11 +2928,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock int status; down_read(&clp->cl_sem); - down(&state->lock_sema); status = nfs4_set_lock_state(state, request); if (status == 0) status = _nfs4_do_setlk(state, cmd, request, 0); - up(&state->lock_sema); if (status == 0) { /* Note: we always want to sleep here! */ request->fl_flags |= FL_SLEEP; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 59c93f37e1b2..86c08c165ce7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -267,7 +267,6 @@ nfs4_alloc_state_owner(void) sp = kzalloc(sizeof(*sp),GFP_KERNEL); if (!sp) return NULL; - init_MUTEX(&sp->so_sema); INIT_LIST_HEAD(&sp->so_states); INIT_LIST_HEAD(&sp->so_delegations); rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); @@ -362,7 +361,6 @@ nfs4_alloc_open_state(void) memset(state->stateid.data, 0, sizeof(state->stateid.data)); atomic_set(&state->count, 1); INIT_LIST_HEAD(&state->lock_states); - init_MUTEX(&state->lock_sema); spin_lock_init(&state->state_lock); return state; } @@ -444,7 +442,6 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) state = __nfs4_find_state_byowner(inode, owner); if (state == NULL && new != NULL) { state = new; - /* Caller *must* be holding owner->so_sem */ /* Note: The reclaim code dictates that we add stateless * and read-only stateids to the end of the list */ list_add_tail(&state->open_states, &owner->so_states); @@ -464,7 +461,7 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) /* * Beware! Caller must be holding exactly one - * reference to clp->cl_sem and owner->so_sema! + * reference to clp->cl_sem! */ void nfs4_put_open_state(struct nfs4_state *state) { @@ -485,7 +482,6 @@ void nfs4_put_open_state(struct nfs4_state *state) /* * Beware! Caller must be holding no references to clp->cl_sem! - * of owner->so_sema! */ void nfs4_close_state(struct nfs4_state *state, mode_t mode) { @@ -496,7 +492,6 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) atomic_inc(&owner->so_count); down_read(&clp->cl_sem); - down(&owner->so_sema); /* Protect against nfs4_find_state() */ spin_lock(&inode->i_lock); if (mode & FMODE_READ) @@ -527,7 +522,6 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) } out: nfs4_put_open_state(state); - up(&owner->so_sema); nfs4_put_state_owner(owner); up_read(&clp->cl_sem); } @@ -553,7 +547,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. * - * The caller must be holding state->lock_sema */ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) { @@ -577,7 +570,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. * - * The caller must be holding state->lock_sema and clp->cl_sem + * The caller must be holding clp->cl_sem */ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) { @@ -711,7 +704,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid) } /* - * Called with sp->so_sema and clp->cl_sem held. + * Called with clp->cl_sem held. * * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or * failed with a seqid incrementing error - @@ -750,7 +743,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) } /* - * Called with ls->lock_sema and clp->cl_sem held. + * Called with clp->cl_sem held. * * Increment the seqid if the LOCK/LOCKU succeeded, or * failed with a seqid incrementing error - From 83c9d41e456033000ccfadf535f3098d8739488d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:13 -0700 Subject: [PATCH 0446/1939] NFSv4: Remove nfs4_client->cl_sem from close() path We no longer need to worry about collisions between close() and the state recovery code, since the new close will automatically recheck the file state once it is done waiting on its sequence slot. Ditto for the nfs4_proc_locku() procedure. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 5 ----- fs/nfs/nfs4state.c | 9 +-------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 25bab6032dfe..611052bacaff 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -820,12 +820,10 @@ static void nfs4_free_closedata(struct nfs4_closedata *calldata) { struct nfs4_state *state = calldata->state; struct nfs4_state_owner *sp = state->owner; - struct nfs_server *server = NFS_SERVER(calldata->inode); nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); nfs4_put_state_owner(sp); - up_read(&server->nfs4_state->cl_sem); kfree(calldata); } @@ -2758,7 +2756,6 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock { struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(inode); - struct nfs4_client *clp = server->nfs4_state; struct nfs_lockargs arg = { .fh = NFS_FH(inode), .type = nfs4_lck_type(cmd, request), @@ -2778,7 +2775,6 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock struct nfs_locku_opargs luargs; int status; - down_read(&clp->cl_sem); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; @@ -2802,7 +2798,6 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock out: if (status == 0) do_vfs_lock(request->fl_file, request); - up_read(&clp->cl_sem); return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 86c08c165ce7..bb3574361958 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -481,17 +481,15 @@ void nfs4_put_open_state(struct nfs4_state *state) } /* - * Beware! Caller must be holding no references to clp->cl_sem! + * Close the current file. */ void nfs4_close_state(struct nfs4_state *state, mode_t mode) { struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; - struct nfs4_client *clp = owner->so_client; int newstate; atomic_inc(&owner->so_count); - down_read(&clp->cl_sem); /* Protect against nfs4_find_state() */ spin_lock(&inode->i_lock); if (mode & FMODE_READ) @@ -523,7 +521,6 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) out: nfs4_put_open_state(state); nfs4_put_state_owner(owner); - up_read(&clp->cl_sem); } /* @@ -704,8 +701,6 @@ void nfs_free_seqid(struct nfs_seqid *seqid) } /* - * Called with clp->cl_sem held. - * * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or * failed with a seqid incrementing error - * see comments nfs_fs.h:seqid_mutating_error() @@ -743,8 +738,6 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) } /* - * Called with clp->cl_sem held. - * * Increment the seqid if the LOCK/LOCKU succeeded, or * failed with a seqid incrementing error - * see comments nfs_fs.h:seqid_mutating_error() From 0a8838f972883112f0a7b259141b24db17583c2d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:14 -0700 Subject: [PATCH 0447/1939] NFSv4: Add missing handling of OPEN_CONFIRM requests on CLAIM_DELEGATE_CUR. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 611052bacaff..f57dba815099 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -56,6 +56,7 @@ #define NFS4_POLL_RETRY_MIN (1*HZ) #define NFS4_POLL_RETRY_MAX (15*HZ) +static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); @@ -333,11 +334,21 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs_increment_open_seqid(status, arg.seqid); + if (status != 0) + goto out_free; + if(res.rflags & NFS4_OPEN_RESULT_CONFIRM) { + status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), + sp, &res.stateid, arg.seqid); + if (status != 0) + goto out_free; + } + nfs_confirm_seqid(&sp->so_seqid, 0); if (status >= 0) { memcpy(state->stateid.data, res.stateid.data, sizeof(state->stateid.data)); clear_bit(NFS_DELEGATED_STATE, &state->flags); } +out_free: nfs_free_seqid(arg.seqid); out: dput(parent); @@ -366,7 +377,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) return err; } -static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) +static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) { struct nfs_open_confirmargs arg = { .fh = fh, From faf5f49c2d9c0af2847837c232a432cc146e203b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:15 -0700 Subject: [PATCH 0448/1939] NFSv4: Make NFS clean up byte range locks asynchronously Currently we fail to do so if the process was signalled. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 165 +++++++++++++++++++++++++++------------- fs/nfs/nfs4state.c | 2 +- fs/nfs/nfs4xdr.c | 9 +-- include/linux/nfs_xdr.h | 2 +- 5 files changed, 118 insertions(+), 61 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index d4fcb5d0ce6c..2215cdee43ae 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -249,6 +249,7 @@ extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_close_state(struct nfs4_state *, mode_t); extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); extern void nfs4_schedule_state_recovery(struct nfs4_client *); +extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f57dba815099..612a9a14aed3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -58,9 +58,9 @@ static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); -static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); +static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); -static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception); +static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; @@ -2422,7 +2422,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen } static int -nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) +nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) { struct nfs4_client *clp = server->nfs4_state; @@ -2500,7 +2500,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) /* This is the error handling routine for processes that are allowed * to sleep. */ -int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) +int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) { struct nfs4_client *clp = server->nfs4_state; int ret = errorcode; @@ -2763,66 +2763,125 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) return res; } -static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) +struct nfs4_unlockdata { + struct nfs_lockargs arg; + struct nfs_locku_opargs luargs; + struct nfs_lockres res; + struct nfs4_lock_state *lsp; + struct nfs_open_context *ctx; + atomic_t refcount; + struct completion completion; +}; + +static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) { - struct inode *inode = state->inode; - struct nfs_server *server = NFS_SERVER(inode); - struct nfs_lockargs arg = { - .fh = NFS_FH(inode), - .type = nfs4_lck_type(cmd, request), - .offset = request->fl_start, - .length = nfs4_lck_length(request), - }; - struct nfs_lockres res = { - .server = server, - }; + if (atomic_dec_and_test(&calldata->refcount)) { + nfs_free_seqid(calldata->luargs.seqid); + nfs4_put_lock_state(calldata->lsp); + put_nfs_open_context(calldata->ctx); + kfree(calldata); + } +} + +static void nfs4_locku_complete(struct nfs4_unlockdata *calldata) +{ + complete(&calldata->completion); + nfs4_locku_release_calldata(calldata); +} + +static void nfs4_locku_done(struct rpc_task *task) +{ + struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; + + nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); + switch (task->tk_status) { + case 0: + memcpy(calldata->lsp->ls_stateid.data, + calldata->res.u.stateid.data, + sizeof(calldata->lsp->ls_stateid.data)); + break; + case -NFS4ERR_STALE_STATEID: + case -NFS4ERR_EXPIRED: + nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); + break; + default: + if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { + rpc_restart_call(task); + return; + } + } + nfs4_locku_complete(calldata); +} + +static void nfs4_locku_begin(struct rpc_task *task) +{ + struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], - .rpc_argp = &arg, - .rpc_resp = &res, - .rpc_cred = state->owner->so_cred, + .rpc_argp = &calldata->arg, + .rpc_resp = &calldata->res, + .rpc_cred = calldata->lsp->ls_state->owner->so_cred, }; - struct nfs4_lock_state *lsp; - struct nfs_locku_opargs luargs; int status; - - status = nfs4_set_lock_state(state, request); - if (status != 0) - goto out; - lsp = request->fl_u.nfs4_fl.owner; - /* We might have lost the locks! */ - if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) - goto out; - luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); - status = -ENOMEM; - if (luargs.seqid == NULL) - goto out; - memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data)); - arg.u.locku = &luargs; - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs_increment_lock_seqid(status, luargs.seqid); - if (status == 0) - memcpy(lsp->ls_stateid.data, res.u.stateid.data, - sizeof(lsp->ls_stateid.data)); - nfs_free_seqid(luargs.seqid); -out: - if (status == 0) - do_vfs_lock(request->fl_file, request); - return status; + status = nfs_wait_on_sequence(calldata->luargs.seqid, task); + if (status != 0) + return; + if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { + nfs4_locku_complete(calldata); + task->tk_exit = NULL; + rpc_exit(task, 0); + return; + } + rpc_call_setup(task, &msg, 0); } static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) { - struct nfs4_exception exception = { }; - int err; + struct nfs4_unlockdata *calldata; + struct inode *inode = state->inode; + struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_lock_state *lsp; + int status; - do { - err = nfs4_handle_exception(NFS_SERVER(state->inode), - _nfs4_proc_unlck(state, cmd, request), - &exception); - } while (exception.retry); - return err; + status = nfs4_set_lock_state(state, request); + if (status != 0) + return status; + lsp = request->fl_u.nfs4_fl.owner; + /* We might have lost the locks! */ + if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) + return 0; + calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); + if (calldata == NULL) + return -ENOMEM; + calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); + if (calldata->luargs.seqid == NULL) { + kfree(calldata); + return -ENOMEM; + } + calldata->luargs.stateid = &lsp->ls_stateid; + calldata->arg.fh = NFS_FH(inode); + calldata->arg.type = nfs4_lck_type(cmd, request); + calldata->arg.offset = request->fl_start; + calldata->arg.length = nfs4_lck_length(request); + calldata->arg.u.locku = &calldata->luargs; + calldata->res.server = server; + calldata->lsp = lsp; + atomic_inc(&lsp->ls_count); + + /* Ensure we don't close file until we're done freeing locks! */ + calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); + + atomic_set(&calldata->refcount, 2); + init_completion(&calldata->completion); + + status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin, + nfs4_locku_done, calldata); + if (status == 0) + wait_for_completion_interruptible(&calldata->completion); + do_vfs_lock(request->fl_file, request); + nfs4_locku_release_calldata(calldata); + return status; } static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index bb3574361958..23834c8fb740 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -600,7 +600,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ * Release reference to lock_state, and free it if we see that * it is no longer in use */ -static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) +void nfs4_put_lock_state(struct nfs4_lock_state *lsp) { struct nfs4_state *state; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 934ec50ea6bf..4706192cfb07 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -776,7 +776,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) WRITE32(OP_LOCKU); WRITE32(arg->type); WRITE32(opargs->seqid->sequence->counter); - WRITEMEM(&opargs->stateid, sizeof(opargs->stateid)); + WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data)); WRITE64(arg->offset); WRITE64(arg->length); @@ -1587,9 +1587,6 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lock }; int status; - status = nfs_wait_on_sequence(args->u.locku->seqid, req->rq_task); - if (status != 0) - goto out; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -2934,8 +2931,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) status = decode_op_hdr(xdr, OP_LOCKU); if (status == 0) { - READ_BUF(sizeof(nfs4_stateid)); - COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); + READ_BUF(sizeof(res->u.stateid.data)); + COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); } return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index cac0df950c66..849f95c5fae4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -188,7 +188,7 @@ struct nfs_lock_opargs { struct nfs_locku_opargs { struct nfs_seqid * seqid; - nfs4_stateid stateid; + nfs4_stateid * stateid; }; struct nfs_lockargs { From 06735b3454824bd561decbde46111f144e905923 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:15 -0700 Subject: [PATCH 0449/1939] NFSv4: Fix up handling of open_to_lock sequence ids Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 69 +++++++++++++++++++---------------------- fs/nfs/nfs4xdr.c | 32 ++++++++----------- include/linux/nfs_xdr.h | 21 +++---------- 3 files changed, 50 insertions(+), 72 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 612a9a14aed3..35da15342e05 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2889,11 +2889,23 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(inode); struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; + struct nfs_lock_opargs largs = { + .lock_stateid = &lsp->ls_stateid, + .open_stateid = &state->stateid, + .lock_owner = { + .clientid = server->nfs4_state->cl_clientid, + .id = lsp->ls_id, + }, + .reclaim = reclaim, + }; struct nfs_lockargs arg = { .fh = NFS_FH(inode), .type = nfs4_lck_type(cmd, request), .offset = request->fl_start, .length = nfs4_lck_length(request), + .u = { + .lock = &largs, + }, }; struct nfs_lockres res = { .server = server, @@ -2904,56 +2916,39 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r .rpc_resp = &res, .rpc_cred = state->owner->so_cred, }; - struct nfs_lock_opargs largs = { - .reclaim = reclaim, - .new_lock_owner = 0, - }; - struct nfs_seqid *lock_seqid; int status = -ENOMEM; - lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); - if (lock_seqid == NULL) + largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); + if (largs.lock_seqid == NULL) return -ENOMEM; if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { struct nfs4_state_owner *owner = state->owner; - struct nfs_open_to_lock otl = { - .lock_owner = { - .clientid = server->nfs4_state->cl_clientid, - }, - }; - otl.lock_seqid = lock_seqid; - otl.lock_owner.id = lsp->ls_id; - memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid)); - largs.u.open_lock = &otl; + largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); + if (largs.open_seqid == NULL) + goto out; largs.new_lock_owner = 1; - arg.u.lock = &largs; - otl.open_seqid = nfs_alloc_seqid(&owner->so_seqid); - if (otl.open_seqid != NULL) { - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - /* increment seqid on success, and seqid mutating errors */ - nfs_increment_open_seqid(status, otl.open_seqid); - nfs_free_seqid(otl.open_seqid); - } - if (status == 0) - nfs_confirm_seqid(&lsp->ls_seqid, 0); - } else { - struct nfs_exist_lock el; - memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); - largs.u.exist_lock = ⪙ - arg.u.lock = &largs; - el.seqid = lock_seqid; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - } - /* increment seqid on success, and seqid mutating errors*/ - nfs_increment_lock_seqid(status, lock_seqid); + /* increment open seqid on success, and seqid mutating errors */ + if (largs.new_lock_owner != 0) { + nfs_increment_open_seqid(status, largs.open_seqid); + if (status == 0) + nfs_confirm_seqid(&lsp->ls_seqid, 0); + } + nfs_free_seqid(largs.open_seqid); + } else + status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + /* increment lock seqid on success, and seqid mutating errors*/ + nfs_increment_lock_seqid(status, largs.lock_seqid); /* save the returned stateid. */ if (status == 0) { - memcpy(lsp->ls_stateid.data, res.u.stateid.data, sizeof(lsp->ls_stateid.data)); + memcpy(lsp->ls_stateid.data, res.u.stateid.data, + sizeof(lsp->ls_stateid.data)); lsp->ls_flags |= NFS_LOCK_INITIALIZED; } else if (status == -NFS4ERR_DENIED) status = -EAGAIN; - nfs_free_seqid(lock_seqid); +out: + nfs_free_seqid(largs.lock_seqid); return status; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4706192cfb07..c5c75235c5b8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -729,22 +729,18 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) WRITE64(arg->length); WRITE32(opargs->new_lock_owner); if (opargs->new_lock_owner){ - struct nfs_open_to_lock *ol = opargs->u.open_lock; - RESERVE_SPACE(40); - WRITE32(ol->open_seqid->sequence->counter); - WRITEMEM(&ol->open_stateid, sizeof(ol->open_stateid)); - WRITE32(ol->lock_seqid->sequence->counter); - WRITE64(ol->lock_owner.clientid); + WRITE32(opargs->open_seqid->sequence->counter); + WRITEMEM(opargs->open_stateid->data, sizeof(opargs->open_stateid->data)); + WRITE32(opargs->lock_seqid->sequence->counter); + WRITE64(opargs->lock_owner.clientid); WRITE32(4); - WRITE32(ol->lock_owner.id); + WRITE32(opargs->lock_owner.id); } else { - struct nfs_exist_lock *el = opargs->u.exist_lock; - RESERVE_SPACE(20); - WRITEMEM(&el->stateid, sizeof(el->stateid)); - WRITE32(el->seqid->sequence->counter); + WRITEMEM(opargs->lock_stateid->data, sizeof(opargs->lock_stateid->data)); + WRITE32(opargs->lock_seqid->sequence->counter); } return 0; @@ -1535,16 +1531,14 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_locka .nops = 2, }; struct nfs_lock_opargs *opargs = args->u.lock; - struct nfs_seqid *seqid; int status; - if (opargs->new_lock_owner) - seqid = opargs->u.open_lock->lock_seqid; - else - seqid = opargs->u.exist_lock->seqid; - status = nfs_wait_on_sequence(seqid, req->rq_task); + status = nfs_wait_on_sequence(opargs->lock_seqid, req->rq_task); if (status != 0) goto out; + /* Do we need to do an open_to_lock_owner? */ + if (opargs->lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED) + opargs->new_lock_owner = 0; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); @@ -2908,8 +2902,8 @@ static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) status = decode_op_hdr(xdr, OP_LOCK); if (status == 0) { - READ_BUF(sizeof(nfs4_stateid)); - COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); + READ_BUF(sizeof(res->u.stateid.data)); + COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); } else if (status == -NFS4ERR_DENIED) return decode_lock_denied(xdr, &res->u.denied); return status; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 849f95c5fae4..57efcc27f20b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -165,25 +165,14 @@ struct nfs_lowner { u32 id; }; -struct nfs_open_to_lock { - struct nfs_seqid * open_seqid; - nfs4_stateid open_stateid; - struct nfs_seqid * lock_seqid; - struct nfs_lowner lock_owner; -}; - -struct nfs_exist_lock { - nfs4_stateid stateid; - struct nfs_seqid * seqid; -}; - struct nfs_lock_opargs { + struct nfs_seqid * lock_seqid; + nfs4_stateid * lock_stateid; + struct nfs_seqid * open_seqid; + nfs4_stateid * open_stateid; + struct nfs_lowner lock_owner; __u32 reclaim; __u32 new_lock_owner; - union { - struct nfs_open_to_lock *open_lock; - struct nfs_exist_lock *exist_lock; - } u; }; struct nfs_locku_opargs { From 039c4d7a82d8268ec71f59679460b41d0dd9b225 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:16 -0700 Subject: [PATCH 0450/1939] NFS: Fix up a race in the NFS implementation of GETLK ...and fix a memory corruption bug due to improper use of memcpy() on a struct file_lock. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 6bdcfa95de94..572d8593486f 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -376,22 +376,31 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) { + struct file_lock *cfl; struct inode *inode = filp->f_mapping->host; int status = 0; lock_kernel(); - /* Use local locking if mounted with "-onolock" */ - if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) - status = NFS_PROTO(inode)->lock(filp, cmd, fl); - else { - struct file_lock *cfl = posix_test_lock(filp, fl); - - fl->fl_type = F_UNLCK; - if (cfl != NULL) - memcpy(fl, cfl, sizeof(*fl)); + /* Try local locking first */ + cfl = posix_test_lock(filp, fl); + if (cfl != NULL) { + locks_copy_lock(fl, cfl); + goto out; } + + if (nfs_have_delegation(inode, FMODE_READ)) + goto out_noconflict; + + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) + goto out_noconflict; + + status = NFS_PROTO(inode)->lock(filp, cmd, fl); +out: unlock_kernel(); return status; +out_noconflict: + fl->fl_type = F_UNLCK; + goto out; } static int do_vfs_lock(struct file *file, struct file_lock *fl) From 834f2a4a1554dc5b2598038b3fe8703defcbe467 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:16 -0700 Subject: [PATCH 0451/1939] VFS: Allow the filesystem to return a full file pointer on open intent This is needed by NFSv4 for atomicity reasons: our open command is in fact a lookup+open, so we need to be able to propagate open context information from lookup() into the resulting struct file's private_data field. Signed-off-by: Trond Myklebust --- fs/exec.c | 12 +++--- fs/namei.c | 93 +++++++++++++++++++++++++++++++++++++++---- fs/open.c | 79 +++++++++++++++++++++++++++++------- include/linux/namei.h | 8 ++++ 4 files changed, 165 insertions(+), 27 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index a04a575ad433..d2208f7c87db 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -126,8 +126,7 @@ asmlinkage long sys_uselib(const char __user * library) struct nameidata nd; int error; - nd.intent.open.flags = FMODE_READ; - error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); + error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ); if (error) goto out; @@ -139,7 +138,7 @@ asmlinkage long sys_uselib(const char __user * library) if (error) goto exit; - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nameidata_to_filp(&nd, O_RDONLY); error = PTR_ERR(file); if (IS_ERR(file)) goto out; @@ -167,6 +166,7 @@ asmlinkage long sys_uselib(const char __user * library) out: return error; exit: + release_open_intent(&nd); path_release(&nd); goto out; } @@ -490,8 +490,7 @@ struct file *open_exec(const char *name) int err; struct file *file; - nd.intent.open.flags = FMODE_READ; - err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); + err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ); file = ERR_PTR(err); if (!err) { @@ -504,7 +503,7 @@ struct file *open_exec(const char *name) err = -EACCES; file = ERR_PTR(err); if (!err) { - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nameidata_to_filp(&nd, O_RDONLY); if (!IS_ERR(file)) { err = deny_write_access(file); if (err) { @@ -516,6 +515,7 @@ struct file *open_exec(const char *name) return file; } } + release_open_intent(&nd); path_release(&nd); } goto out; diff --git a/fs/namei.c b/fs/namei.c index aa62dbda93ac..0d1dff7d3d95 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -317,6 +318,18 @@ void path_release_on_umount(struct nameidata *nd) mntput_no_expire(nd->mnt); } +/** + * release_open_intent - free up open intent resources + * @nd: pointer to nameidata + */ +void release_open_intent(struct nameidata *nd) +{ + if (nd->intent.open.file->f_dentry == NULL) + put_filp(nd->intent.open.file); + else + fput(nd->intent.open.file); +} + /* * Internal lookup() using the new generic dcache. * SMP-safe @@ -1052,6 +1065,70 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata return retval; } +static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, + struct nameidata *nd, int open_flags, int create_mode) +{ + struct file *filp = get_empty_filp(); + int err; + + if (filp == NULL) + return -ENFILE; + nd->intent.open.file = filp; + nd->intent.open.flags = open_flags; + nd->intent.open.create_mode = create_mode; + err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); + if (IS_ERR(nd->intent.open.file)) { + if (err == 0) { + err = PTR_ERR(nd->intent.open.file); + path_release(nd); + } + } else if (err != 0) + release_open_intent(nd); + return err; +} + +/** + * path_lookup_open - lookup a file path with open intent + * @name: pointer to file name + * @lookup_flags: lookup intent flags + * @nd: pointer to nameidata + * @open_flags: open intent flags + */ +int path_lookup_open(const char *name, unsigned int lookup_flags, + struct nameidata *nd, int open_flags) +{ + return __path_lookup_intent_open(name, lookup_flags, nd, + open_flags, 0); +} + +/** + * path_lookup_create - lookup a file path with open + create intent + * @name: pointer to file name + * @lookup_flags: lookup intent flags + * @nd: pointer to nameidata + * @open_flags: open intent flags + * @create_mode: create intent flags + */ +int path_lookup_create(const char *name, unsigned int lookup_flags, + struct nameidata *nd, int open_flags, int create_mode) +{ + return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, + open_flags, create_mode); +} + +int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, + struct nameidata *nd, int open_flags) +{ + char *tmp = getname(name); + int err = PTR_ERR(tmp); + + if (!IS_ERR(tmp)) { + err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); + putname(tmp); + } + return err; +} + /* * Restricted form of lookup. Doesn't follow links, single-component only, * needs parent already locked. Doesn't follow mounts. @@ -1416,27 +1493,27 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) */ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) { - int acc_mode, error = 0; + int acc_mode, error; struct path path; struct dentry *dir; int count = 0; acc_mode = ACC_MODE(flag); + /* O_TRUNC implies we need access checks for write permissions */ + if (flag & O_TRUNC) + acc_mode |= MAY_WRITE; + /* Allow the LSM permission hook to distinguish append access from general write access. */ if (flag & O_APPEND) acc_mode |= MAY_APPEND; - /* Fill in the open() intent data */ - nd->intent.open.flags = flag; - nd->intent.open.create_mode = mode; - /* * The simplest case - just a plain lookup. */ if (!(flag & O_CREAT)) { - error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); + error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); if (error) return error; goto ok; @@ -1445,7 +1522,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) /* * Create - we need to know the parent. */ - error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd); + error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); if (error) return error; @@ -1520,6 +1597,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) exit_dput: dput_path(&path, nd); exit: + if (!IS_ERR(nd->intent.open.file)) + release_open_intent(nd); path_release(nd); return error; diff --git a/fs/open.c b/fs/open.c index f0d90cf0495c..8d06ec911fd9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -739,7 +739,8 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) } static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, - int flags, struct file *f) + int flags, struct file *f, + int (*open)(struct inode *, struct file *)) { struct inode *inode; int error; @@ -761,11 +762,14 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); - if (f->f_op && f->f_op->open) { - error = f->f_op->open(inode,f); + if (!open && f->f_op) + open = f->f_op->open; + if (open) { + error = open(inode, f); if (error) goto cleanup_all; } + f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); @@ -814,28 +818,75 @@ struct file *filp_open(const char * filename, int flags, int mode) { int namei_flags, error; struct nameidata nd; - struct file *f; namei_flags = flags; if ((namei_flags+1) & O_ACCMODE) namei_flags++; - if (namei_flags & O_TRUNC) - namei_flags |= 2; - - error = -ENFILE; - f = get_empty_filp(); - if (f == NULL) - return ERR_PTR(error); error = open_namei(filename, namei_flags, mode, &nd); if (!error) - return __dentry_open(nd.dentry, nd.mnt, flags, f); + return nameidata_to_filp(&nd, flags); - put_filp(f); return ERR_PTR(error); } EXPORT_SYMBOL(filp_open); +/** + * lookup_instantiate_filp - instantiates the open intent filp + * @nd: pointer to nameidata + * @dentry: pointer to dentry + * @open: open callback + * + * Helper for filesystems that want to use lookup open intents and pass back + * a fully instantiated struct file to the caller. + * This function is meant to be called from within a filesystem's + * lookup method. + * Note that in case of error, nd->intent.open.file is destroyed, but the + * path information remains valid. + * If the open callback is set to NULL, then the standard f_op->open() + * filesystem callback is substituted. + */ +struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, + int (*open)(struct inode *, struct file *)) +{ + if (IS_ERR(nd->intent.open.file)) + goto out; + if (IS_ERR(dentry)) + goto out_err; + nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->mnt), + nd->intent.open.flags - 1, + nd->intent.open.file, + open); +out: + return nd->intent.open.file; +out_err: + release_open_intent(nd); + nd->intent.open.file = (struct file *)dentry; + goto out; +} +EXPORT_SYMBOL_GPL(lookup_instantiate_filp); + +/** + * nameidata_to_filp - convert a nameidata to an open filp. + * @nd: pointer to nameidata + * @flags: open flags + * + * Note that this function destroys the original nameidata + */ +struct file *nameidata_to_filp(struct nameidata *nd, int flags) +{ + struct file *filp; + + /* Pick up the filp from the open intent */ + filp = nd->intent.open.file; + /* Has the filesystem initialised the file for us? */ + if (filp->f_dentry == NULL) + filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL); + else + path_release(nd); + return filp; +} + struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { int error; @@ -846,7 +897,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) if (f == NULL) return ERR_PTR(error); - return __dentry_open(dentry, mnt, flags, f); + return __dentry_open(dentry, mnt, flags, f, NULL); } EXPORT_SYMBOL(dentry_open); diff --git a/include/linux/namei.h b/include/linux/namei.h index 7db67b008cac..1c975d0d9e94 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -8,6 +8,7 @@ struct vfsmount; struct open_intent { int flags; int create_mode; + struct file *file; }; enum { MAX_NESTED_LINKS = 5 }; @@ -65,6 +66,13 @@ extern int FASTCALL(link_path_walk(const char *, struct nameidata *)); extern void path_release(struct nameidata *); extern void path_release_on_umount(struct nameidata *); +extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags); +extern int path_lookup_open(const char *, unsigned lookup_flags, struct nameidata *, int open_flags); +extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, + int (*open)(struct inode *, struct file *)); +extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); +extern void release_open_intent(struct nameidata *); + extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry * lookup_hash(struct qstr *, struct dentry *); From 02a913a73b52071e93f4b76db3e86138d19efffd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:17 -0700 Subject: [PATCH 0452/1939] NFSv4: Eliminate nfsv4 open race... Make NFSv4 return the fully initialized file pointer with the stateid that it created in the lookup w/intent. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 29 ++++----- fs/nfs/nfs3proc.c | 2 +- fs/nfs/nfs4_fs.h | 4 +- fs/nfs/nfs4proc.c | 137 ++++++++++++++++------------------------ fs/nfs/proc.c | 2 +- include/linux/nfs_xdr.h | 2 +- 6 files changed, 74 insertions(+), 102 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c70eabd6d179..a6e251f21fd8 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -914,7 +914,6 @@ static int is_atomic_open(struct inode *dir, struct nameidata *nd) static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *res = NULL; - struct inode *inode = NULL; int error; /* Check that we are indeed trying to open this file */ @@ -928,8 +927,10 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry dentry->d_op = NFS_PROTO(dir)->dentry_ops; /* Let vfs_create() deal with O_EXCL */ - if (nd->intent.open.flags & O_EXCL) - goto no_entry; + if (nd->intent.open.flags & O_EXCL) { + d_add(dentry, NULL); + goto out; + } /* Open the file on the server */ lock_kernel(); @@ -943,18 +944,18 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry if (nd->intent.open.flags & O_CREAT) { nfs_begin_data_update(dir); - inode = nfs4_atomic_open(dir, dentry, nd); + res = nfs4_atomic_open(dir, dentry, nd); nfs_end_data_update(dir); } else - inode = nfs4_atomic_open(dir, dentry, nd); + res = nfs4_atomic_open(dir, dentry, nd); unlock_kernel(); - if (IS_ERR(inode)) { - error = PTR_ERR(inode); + if (IS_ERR(res)) { + error = PTR_ERR(res); switch (error) { /* Make a negative dentry */ case -ENOENT: - inode = NULL; - break; + res = NULL; + goto out; /* This turned out not to be a regular file */ case -ELOOP: if (!(nd->intent.open.flags & O_NOFOLLOW)) @@ -962,13 +963,9 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry /* case -EISDIR: */ /* case -EINVAL: */ default: - res = ERR_PTR(error); goto out; } - } -no_entry: - res = d_add_unique(dentry, inode); - if (res != NULL) + } else if (res != NULL) dentry = res; nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); @@ -1012,7 +1009,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) */ lock_kernel(); verifier = nfs_save_change_attribute(dir); - ret = nfs4_open_revalidate(dir, dentry, openflags); + ret = nfs4_open_revalidate(dir, dentry, openflags, nd); if (!ret) nfs_set_verifier(dentry, verifier); unlock_kernel(); @@ -1135,7 +1132,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, lock_kernel(); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); nfs_end_data_update(dir); if (error != 0) goto out_err; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index edc95514046d..df80477c5af4 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -299,7 +299,7 @@ static int nfs3_proc_commit(struct nfs_write_data *cdata) */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct nameidata *nd) { struct nfs_fh fhandle; struct nfs_fattr fattr; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 2215cdee43ae..8a3788199052 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -215,8 +215,8 @@ extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); extern int nfs4_proc_async_renew(struct nfs4_client *); extern int nfs4_proc_renew(struct nfs4_client *); extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); -extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); -extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); +extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); +extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 35da15342e05..c9ecb8119632 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "nfs4_fs.h" #include "delegation.h" @@ -947,12 +948,26 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) return status; } -struct inode * +static void nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) +{ + struct file *filp; + + filp = lookup_instantiate_filp(nd, dentry, NULL); + if (!IS_ERR(filp)) { + struct nfs_open_context *ctx; + ctx = (struct nfs_open_context *)filp->private_data; + ctx->state = state; + } else + nfs4_close_state(state, nd->intent.open.flags); +} + +struct dentry * nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct iattr attr; struct rpc_cred *cred; struct nfs4_state *state; + struct dentry *res; if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; @@ -966,16 +981,23 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); if (IS_ERR(cred)) - return (struct inode *)cred; + return (struct dentry *)cred; state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); put_rpccred(cred); - if (IS_ERR(state)) - return (struct inode *)state; - return state->inode; + if (IS_ERR(state)) { + if (PTR_ERR(state) == -ENOENT) + d_add(dentry, NULL); + return (struct dentry *)state; + } + res = d_add_unique(dentry, state->inode); + if (res != NULL) + dentry = res; + nfs4_intent_set_file(nd, dentry, state); + return res; } int -nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) +nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) { struct rpc_cred *cred; struct nfs4_state *state; @@ -988,18 +1010,30 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) if (IS_ERR(state)) state = nfs4_do_open(dir, dentry, openflags, NULL, cred); put_rpccred(cred); - if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) - return 1; - if (IS_ERR(state)) - return 0; + if (IS_ERR(state)) { + switch (PTR_ERR(state)) { + case -EPERM: + case -EACCES: + case -EDQUOT: + case -ENOSPC: + case -EROFS: + lookup_instantiate_filp(nd, (struct dentry *)state, NULL); + return 1; + case -ENOENT: + if (dentry->d_inode == NULL) + return 1; + } + goto out_drop; + } inode = state->inode; + iput(inode); if (inode == dentry->d_inode) { - iput(inode); + nfs4_intent_set_file(nd, dentry, state); return 1; } - d_drop(dentry); nfs4_close_state(state, openflags); - iput(inode); +out_drop: + d_drop(dentry); return 0; } @@ -1500,7 +1534,7 @@ static int nfs4_proc_commit(struct nfs_write_data *cdata) static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct nameidata *nd) { struct nfs4_state *state; struct rpc_cred *cred; @@ -1522,13 +1556,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, struct nfs_fattr fattr; status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, NFS_FH(state->inode), sattr, state); - if (status == 0) { + if (status == 0) nfs_setattr_update_inode(state->inode, sattr); - goto out; - } - } else if (flags != 0) - goto out; - nfs4_close_state(state, flags); + } + if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) + nfs4_intent_set_file(nd, dentry, state); + else + nfs4_close_state(state, flags); out: return status; } @@ -2175,65 +2209,6 @@ nfs4_proc_renew(struct nfs4_client *clp) return 0; } -/* - * We will need to arrange for the VFS layer to provide an atomic open. - * Until then, this open method is prone to inefficiency and race conditions - * due to the lookup, potential create, and open VFS calls from sys_open() - * placed on the wire. - */ -static int -nfs4_proc_file_open(struct inode *inode, struct file *filp) -{ - struct dentry *dentry = filp->f_dentry; - struct nfs_open_context *ctx; - struct nfs4_state *state = NULL; - struct rpc_cred *cred; - int status = -ENOMEM; - - dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n", - (int)dentry->d_parent->d_name.len, - dentry->d_parent->d_name.name, - (int)dentry->d_name.len, dentry->d_name.name); - - - /* Find our open stateid */ - cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); - if (IS_ERR(cred)) - return PTR_ERR(cred); - ctx = alloc_nfs_open_context(dentry, cred); - put_rpccred(cred); - if (unlikely(ctx == NULL)) - return -ENOMEM; - status = -EIO; /* ERACE actually */ - state = nfs4_find_state(inode, cred, filp->f_mode); - if (unlikely(state == NULL)) - goto no_state; - ctx->state = state; - nfs4_close_state(state, filp->f_mode); - ctx->mode = filp->f_mode; - nfs_file_set_open_context(filp, ctx); - put_nfs_open_context(ctx); - if (filp->f_mode & FMODE_WRITE) - nfs_begin_data_update(inode); - return 0; -no_state: - printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__); - put_nfs_open_context(ctx); - return status; -} - -/* - * Release our state - */ -static int -nfs4_proc_file_release(struct inode *inode, struct file *filp) -{ - if (filp->f_mode & FMODE_WRITE) - nfs_end_data_update(inode); - nfs_file_clear_open_context(filp); - return 0; -} - static inline int nfs4_server_supports_acls(struct nfs_server *server) { return (server->caps & NFS_CAP_ACLS) @@ -3145,8 +3120,8 @@ struct nfs_rpc_ops nfs_v4_clientops = { .read_setup = nfs4_proc_read_setup, .write_setup = nfs4_proc_write_setup, .commit_setup = nfs4_proc_commit_setup, - .file_open = nfs4_proc_file_open, - .file_release = nfs4_proc_file_release, + .file_open = nfs_open, + .file_release = nfs_release, .lock = nfs4_proc_lock, .clear_acl_cache = nfs4_zap_acl_attr, }; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index be23c3fb9260..8fef86523d7f 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -216,7 +216,7 @@ static int nfs_proc_write(struct nfs_write_data *wdata) static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct nameidata *nd) { struct nfs_fh fhandle; struct nfs_fattr fattr; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 57efcc27f20b..60086dac11d5 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -712,7 +712,7 @@ struct nfs_rpc_ops { int (*write) (struct nfs_write_data *); int (*commit) (struct nfs_write_data *); int (*create) (struct inode *, struct dentry *, - struct iattr *, int); + struct iattr *, int, struct nameidata *); int (*remove) (struct inode *, struct qstr *); int (*unlink_setup) (struct rpc_message *, struct dentry *, struct qstr *); From 6f926b5ba75c568296ec227e7d782db4ddbdca5c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:18 -0700 Subject: [PATCH 0453/1939] [NFS]: Check that the server returns a valid regular file to our OPEN request Since it appears that some servers don't... Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 4 +++- fs/nfs/nfs4proc.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a6e251f21fd8..ac331d2d4c4a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -957,10 +957,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry res = NULL; goto out; /* This turned out not to be a regular file */ + case -EISDIR: + case -ENOTDIR: + goto no_open; case -ELOOP: if (!(nd->intent.open.flags & O_NOFOLLOW)) goto no_open; - /* case -EISDIR: */ /* case -EINVAL: */ default: goto out; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c9ecb8119632..3db1c9f0b09c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -419,6 +419,22 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru o_arg->clientid = sp->so_client->cl_clientid; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + if (status == 0) { + /* OPEN on anything except a regular file is disallowed in NFSv4 */ + switch (o_res->f_attr->mode & S_IFMT) { + case S_IFREG: + break; + case S_IFLNK: + status = -ELOOP; + break; + case S_IFDIR: + status = -EISDIR; + break; + default: + status = -ENOTDIR; + } + } + nfs_increment_open_seqid(status, o_arg->seqid); if (status != 0) goto out; From cdce5d6b94b6182f6d8a5b7b52923933e98cbc92 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:18 -0700 Subject: [PATCH 0454/1939] VFS: Make link_path_walk set LOOKUP_CONTINUE before calling permission(). This will allow nfs_permission() to perform additional optimizations when walking the path, by folding the ACCESS(MAY_EXEC) call on the directory into the lookup revalidation. Signed-off-by: Trond Myklebust --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index 0d1dff7d3d95..aaaa81036234 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -763,6 +763,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) struct qstr this; unsigned int c; + nd->flags |= LOOKUP_CONTINUE; err = exec_permission_lite(inode, nd); if (err == -EAGAIN) { err = permission(inode, MAY_EXEC, nd); @@ -815,7 +816,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) if (err < 0) break; } - nd->flags |= LOOKUP_CONTINUE; /* This does the actual lookups.. */ err = do_lookup(nd, &this, &next); if (err) From cae7a073a4c5484cc5713eab606bf54b46724ab3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:19 -0700 Subject: [PATCH 0455/1939] NFSv4: Return delegation upon rename or removal of file. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 2 +- fs/nfs/delegation.h | 16 +++++++++++++++- fs/nfs/dir.c | 3 +++ fs/nfs/inode.c | 3 +-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 4a36839f0bbd..44135af9894c 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -142,7 +142,7 @@ static void nfs_msync_inode(struct inode *inode) /* * Basic procedure for returning a delegation to the server */ -int nfs_inode_return_delegation(struct inode *inode) +int __nfs_inode_return_delegation(struct inode *inode) { struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; struct nfs_inode *nfsi = NFS_I(inode); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 3f6c45a29d6a..8017846b561f 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -25,7 +25,7 @@ struct nfs_delegation { int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); -int nfs_inode_return_delegation(struct inode *inode); +int __nfs_inode_return_delegation(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); @@ -47,11 +47,25 @@ static inline int nfs_have_delegation(struct inode *inode, int flags) return 1; return 0; } + +static inline int nfs_inode_return_delegation(struct inode *inode) +{ + int err = 0; + + if (NFS_I(inode)->delegation != NULL) + err = __nfs_inode_return_delegation(inode); + return err; +} #else static inline int nfs_have_delegation(struct inode *inode, int flags) { return 0; } + +static inline int nfs_inode_return_delegation(struct inode *inode) +{ + return 0; +} #endif #endif diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ac331d2d4c4a..72f50c0117b1 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -801,6 +801,7 @@ static int nfs_dentry_delete(struct dentry *dentry) */ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { + nfs_inode_return_delegation(inode); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { lock_kernel(); inode->i_nlink--; @@ -1329,6 +1330,7 @@ static int nfs_safe_remove(struct dentry *dentry) nfs_begin_data_update(dir); if (inode != NULL) { + nfs_inode_return_delegation(inode); nfs_begin_data_update(inode); error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); /* The VFS may want to delete this inode */ @@ -1547,6 +1549,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, nfs_wb_all(old_inode); shrink_dcache_parent(old_dentry); } + nfs_inode_return_delegation(old_inode); if (new_inode) d_delete(new_dentry); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d7abaa00473a..6b0f7fe6bd1d 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1671,8 +1671,7 @@ static void nfs4_clear_inode(struct inode *inode) struct nfs_inode *nfsi = NFS_I(inode); /* If we are holding a delegation, return it! */ - if (nfsi->delegation != NULL) - nfs_inode_return_delegation(inode); + nfs_inode_return_delegation(inode); /* First call standard NFS clear_inode() code */ nfs_clear_inode(inode); /* Now clear out any remaining state */ From 642ac54923e0291ae2c8e42edde18d8c9c0a3c84 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:19 -0700 Subject: [PATCH 0456/1939] NFSv4: Return delegations in case we're changing ACLs Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 5 +++++ fs/nfs/nfs4proc.c | 1 + 2 files changed, 6 insertions(+) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6b0f7fe6bd1d..65d5ab45ddc5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -853,6 +853,11 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) filemap_fdatawait(inode->i_mapping); nfs_wb_all(inode); } + /* + * Return any delegations if we're going to change ACLs + */ + if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) + nfs_inode_return_delegation(inode); error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); if (error == 0) nfs_refresh_inode(inode, &fattr); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3db1c9f0b09c..c10dcd12af51 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2405,6 +2405,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen if (!nfs4_server_supports_acls(server)) return -EOPNOTSUPP; + nfs_inode_return_delegation(inode); buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); if (ret == 0) From b8e5c4c2978fa666287525a9de2fa648a7581262 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:20 -0700 Subject: [PATCH 0457/1939] NFSv4: If a delegated open fails, ensure that we return the delegation Unless of course the open fails due to permission issues. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c10dcd12af51..a8be9af610ac 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -658,6 +658,8 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred } up_read(&nfsi->rwsem); up_read(&clp->cl_sem); + if (err != -EACCES) + nfs_inode_return_delegation(inode); return err; } From 550f57470c6506f5ef3c708335dea6bd48bf3dc4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:21 -0700 Subject: [PATCH 0458/1939] NFSv4: Ensure that we recover from the OPEN + OPEN_CONFIRM BAD_STATEID race If the server is in the unconfirmed OPEN state for a given open owner and receives a second OPEN for the same open owner, it will cancel the state of the first request and set up an OPEN_CONFIRM for the second. This can cause a race that is discussed in rfc3530 on page 181. The following patch allows the client to recover by retrying the original open request. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a8be9af610ac..ff378126ccd7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -785,6 +785,16 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, exception.retry = 1; continue; } + /* + * BAD_STATEID on OPEN means that the server cancelled our + * state before it received the OPEN_CONFIRM. + * Recover by retrying the request as per the discussion + * on Page 181 of RFC3530. + */ + if (status == -NFS4ERR_BAD_STATEID) { + exception.retry = 1; + continue; + } res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), status, &exception)); } while (exception.retry); From 4c780a4688b421baa896b59778c05d7e068e479f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:21 -0700 Subject: [PATCH 0459/1939] Fix Connectathon locking test failure We currently fail Connectathon test 6.10 in the case of 32-bit locks due to incorrect error checking. Also add support for l->l_len < 0 to 64-bit locks. Signed-off-by: Trond Myklebust --- fs/locks.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 7eb1d77b9204..a1e8b2248014 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -316,21 +316,22 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, /* POSIX-1996 leaves the case l->l_len < 0 undefined; POSIX-2001 defines it. */ start += l->l_start; - end = start + l->l_len - 1; - if (l->l_len < 0) { - end = start - 1; - start += l->l_len; - } - if (start < 0) return -EINVAL; - if (l->l_len > 0 && end < 0) - return -EOVERFLOW; - + fl->fl_end = OFFSET_MAX; + if (l->l_len > 0) { + end = start + l->l_len - 1; + fl->fl_end = end; + } else if (l->l_len < 0) { + end = start - 1; + fl->fl_end = end; + start += l->l_len; + if (start < 0) + return -EINVAL; + } fl->fl_start = start; /* we record the absolute position */ - fl->fl_end = end; - if (l->l_len == 0) - fl->fl_end = OFFSET_MAX; + if (fl->fl_end < fl->fl_start) + return -EOVERFLOW; fl->fl_owner = current->files; fl->fl_pid = current->tgid; @@ -362,14 +363,21 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, return -EINVAL; } - if (((start += l->l_start) < 0) || (l->l_len < 0)) + start += l->l_start; + if (start < 0) return -EINVAL; - fl->fl_end = start + l->l_len - 1; - if (l->l_len > 0 && fl->fl_end < 0) - return -EOVERFLOW; + fl->fl_end = OFFSET_MAX; + if (l->l_len > 0) { + fl->fl_end = start + l->l_len - 1; + } else if (l->l_len < 0) { + fl->fl_end = start - 1; + start += l->l_len; + if (start < 0) + return -EINVAL; + } fl->fl_start = start; /* we record the absolute position */ - if (l->l_len == 0) - fl->fl_end = OFFSET_MAX; + if (fl->fl_end < fl->fl_start) + return -EOVERFLOW; fl->fl_owner = current->files; fl->fl_pid = current->tgid; From 6fe43f9e3701f7a9f2be151a5e6cfe94b87e92f9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 14:20:22 -0700 Subject: [PATCH 0460/1939] NFS: Fix rename of directory onto empty directory If someone tries to rename a directory onto an empty directory, we currently fail and return EBUSY. This patch ensures that we try the rename if both source and target are directories, and that we fail with a correct error of EISDIR if the source is not a directory. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 72f50c0117b1..eb50c19fc253 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1511,9 +1511,11 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, */ if (!new_inode) goto go_ahead; - if (S_ISDIR(new_inode->i_mode)) - goto out; - else if (atomic_read(&new_dentry->d_count) > 2) { + if (S_ISDIR(new_inode->i_mode)) { + error = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto out; + } else if (atomic_read(&new_dentry->d_count) > 2) { int err; /* copy the target dentry's name */ dentry = d_alloc(new_dentry->d_parent, From 757d18faee58aa4c43bcaf9a44decf17fa68adeb Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Mon, 10 Oct 2005 19:16:53 +0200 Subject: [PATCH 0461/1939] [PATCH] ieee80211: division by zero fix This fixes division by zero bug in ieee80211_wx_get_scan(). Signed-off-by: Jiri Benc Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_wx.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index ee7a70a13250..1ce7af9bec35 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -152,15 +152,18 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.level = 0; } else { iwe.u.qual.level = network->stats.rssi; - iwe.u.qual.qual = - (100 * - (ieee->perfect_rssi - ieee->worst_rssi) * - (ieee->perfect_rssi - ieee->worst_rssi) - - (ieee->perfect_rssi - network->stats.rssi) * - (15 * (ieee->perfect_rssi - ieee->worst_rssi) + - 62 * (ieee->perfect_rssi - network->stats.rssi))) / - ((ieee->perfect_rssi - ieee->worst_rssi) * - (ieee->perfect_rssi - ieee->worst_rssi)); + if (ieee->perfect_rssi == ieee->worst_rssi) + iwe.u.qual.qual = 100; + else + iwe.u.qual.qual = + (100 * + (ieee->perfect_rssi - ieee->worst_rssi) * + (ieee->perfect_rssi - ieee->worst_rssi) - + (ieee->perfect_rssi - network->stats.rssi) * + (15 * (ieee->perfect_rssi - ieee->worst_rssi) + + 62 * (ieee->perfect_rssi - network->stats.rssi))) / + ((ieee->perfect_rssi - ieee->worst_rssi) * + (ieee->perfect_rssi - ieee->worst_rssi)); if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; else if (iwe.u.qual.qual < 1) From 7150bf8a98f14f1ba67e090ef2778004c746f465 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 18 Oct 2005 14:46:38 -0700 Subject: [PATCH 0462/1939] [IB] mthca: Don't enter QP into MCG more than once. Avoid entering a QP as member of a multicast group multiple times. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mcg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 9a0612a9d304..b47ea7daf088 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -185,7 +185,12 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } for (i = 0; i < MTHCA_QP_PER_MGM; ++i) - if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { + if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { + mthca_dbg(dev, "QP %06x already a member of MGM\n", + ibqp->qp_num); + err = 0; + goto out; + } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); break; } From f567ef935094003ee70ea3fd10f5695d349c0f48 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:24 +0100 Subject: [PATCH 0463/1939] [PATCH] sb1250-mac: Check the actual setting for reporting hw checksumming. Signed-off-by: Ralf Baechle drivers/net/sb1250-mac.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7abd55a4fb21..0f828da0339d 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2419,7 +2419,7 @@ static int sbmac_init(struct net_device *dev, int idx) if (err) goto out_uninit; - if (periph_rev >= 2) { + if (sc->rx_hw_checksum == ENABLE) { printk(KERN_INFO "%s: enabling TCP rcv checksum\n", sc->sbm_dev->name); } From 04115def6ad7ef51440365b65a7324fcb82d5d1d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:36 +0100 Subject: [PATCH 0464/1939] [PATCH] sb1250-mac: Ensure 16-byte alignment of the descriptor ring. Signed-off-by: Ralf Baechle drivers/net/sb1250-mac.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 0f828da0339d..cb4ea4158457 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -750,7 +750,14 @@ static void sbdma_initctx(sbmacdma_t *d, d->sbdma_maxdescr = maxdescr; d->sbdma_dscrtable = (sbdmadscr_t *) - kmalloc(d->sbdma_maxdescr*sizeof(sbdmadscr_t), GFP_KERNEL); + kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); + + /* + * The descriptor table must be aligned to at least 16 bytes or the + * MAC will corrupt it. + */ + d->sbdma_dscrtable = (sbdmadscr_t *) + ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); From 7f553e3db46b36d2662e1118f8b8fdbf086b76df Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:41 +0100 Subject: [PATCH 0465/1939] [PATCH] au1000_eth: Misc Au1000 net driver fixes. o Add support for DP83847 MII. o remove unused variable. o Add some initialisations so even an unknown MII won't result in a crash. o Correct error message to "no known MIIs found". Signed-off-by: Ralf Baechle drivers/net/au1000_eth.c | 13 +++++-------- 1 files changed, 5 insertions(+), 8 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/au1000_eth.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index c82b9cd1c924..78506911d656 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -151,13 +151,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ SUPPORTED_Autoneg -static char *phy_link[] = -{ "unknown", - "10Base2", "10BaseT", - "AUI", - "100BaseT", "100BaseTX", "100BaseFX" -}; - int bcm_5201_init(struct net_device *dev, int phy_addr) { s16 data; @@ -785,6 +778,7 @@ static struct mii_chip_info { {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0}, {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0}, {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1}, + {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0}, {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0}, {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0}, {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0}, @@ -1045,7 +1039,7 @@ static int mii_probe (struct net_device * dev) #endif if (aup->mii->chip_info == NULL) { - printk(KERN_ERR "%s: Au1x No MII transceivers found!\n", + printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n", dev->name); return -1; } @@ -1546,6 +1540,9 @@ au1000_probe(u32 ioaddr, int irq, int port_num) printk(KERN_ERR "%s: out of memory\n", dev->name); goto err_out; } + aup->mii->next = NULL; + aup->mii->chip_info = NULL; + aup->mii->status = 0; aup->mii->mii_control_reg = 0; aup->mii->mii_data_reg = 0; From bc053d45cb0ca5daeaa69ae9ac43cdea42693f60 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:46 +0100 Subject: [PATCH 0466/1939] [PATCH] de2104x: Resurrect Cobalt support for 2.6. Signed-off-by: Ralf Baechle drivers/net/tulip/de2104x.c | 5 +++++ 1 files changed, 5 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index a22d00198e4d..6b8eee8f7bfd 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1787,10 +1787,15 @@ static void __init de21041_get_srom_info (struct de_private *de) /* DEC now has a specification but early board makers just put the address in the first EEPROM locations. */ /* This does memcmp(eedata, eedata+16, 8) */ + +#ifndef CONFIG_MIPS_COBALT + for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) sa_offset = 20; +#endif + /* store MAC address */ for (i = 0; i < 6; i ++) de->dev->dev_addr[i] = ee_data[i + sa_offset]; From 2891439e7378e35534d7eb32f77671dc4d61db4c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:51 +0100 Subject: [PATCH 0467/1939] [PATCH] sgiseeq: Fix resource handling. Signed-off-by: Ralf Baechle drivers/net/sgiseeq.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sgiseeq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 9bc3b1c0dd6a..a9d2e4fd0aec 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -493,11 +493,13 @@ static int sgiseeq_close(struct net_device *dev) { struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; + unsigned int irq = dev->irq; netif_stop_queue(dev); /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); + free_irq(irq, dev); return 0; } @@ -734,7 +736,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) return 0; err_out_free_page: - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); err_out_free_dev: kfree(dev); @@ -754,15 +756,12 @@ static void __exit sgiseeq_exit(void) { struct net_device *next, *dev; struct sgiseeq_private *sp; - int irq; for (dev = root_sgiseeq_dev; dev; dev = next) { sp = (struct sgiseeq_private *) netdev_priv(dev); next = sp->next_module; - irq = dev->irq; unregister_netdev(dev); - free_irq(irq, dev); - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); free_netdev(dev); } } From 302a5c4b3d4d6aff7772a4b3431bb772586e6011 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:50:56 +0100 Subject: [PATCH 0468/1939] [PATCH] sgiseeq: Configure PIO and DMA timing requests. Signed-off-by: Ralf Baechle drivers/net/sgiseeq.c | 28 ++++++++++++++-------------- include/asm-mips/sgi/hpc3.h | 40 ++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 34 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sgiseeq.c | 28 ++++++++++++++-------------- include/asm-mips/sgi/hpc3.h | 36 ++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index a9d2e4fd0aec..a4614df38a90 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -32,8 +32,6 @@ #include "sgiseeq.h" -static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n"; - static char *sgiseeqstr = "SGI Seeq8003"; /* @@ -113,9 +111,9 @@ static struct net_device *root_sgiseeq_dev; static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { - hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ; udelay(20); - hregs->rx_reset = 0; + hregs->reset = 0; } static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs, @@ -252,7 +250,6 @@ void sgiseeq_dump_rings(void) #define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF) #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2) -#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ) static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, struct sgiseeq_regs *sregs) @@ -274,8 +271,6 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, sregs->tstat = TSTAT_INIT_SEEQ; } - hregs->rx_dconfig |= RDMACFG_INIT; - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc); hregs->tx_ndptr = CPHYSADDR(sp->tx_desc); @@ -446,7 +441,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs spin_lock(&sp->tx_lock); /* Ack the IRQ and set software state. */ - hregs->rx_reset = HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CLRIRQ; /* Always check for received packets. */ sgiseeq_rx(dev, sp, hregs, sregs); @@ -646,7 +641,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) -static int sgiseeq_init(struct hpc3_regs* regs, int irq) +static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) { struct sgiseeq_init_block *sr; struct sgiseeq_private *sp; @@ -682,8 +677,8 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) gpriv = sp; gdev = dev; #endif - sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0]; - sp->hregs = &hpc3c0->ethregs; + sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0]; + sp->hregs = &hpcregs->ethregs; sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; @@ -700,6 +695,11 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); + /* Setup PIO and DMA transfer timing */ + sp->hregs->pconfig = 0x161; + sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | + HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; + /* Reset the chip. */ hpc3_eth_reset(sp->hregs); @@ -726,7 +726,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) goto err_out_free_page; } - printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); + printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); @@ -746,8 +746,6 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) static int __init sgiseeq_probe(void) { - printk(version); - /* On board adapter on 1st HPC is always present */ return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); } @@ -769,4 +767,6 @@ static void __exit sgiseeq_exit(void) module_init(sgiseeq_probe); module_exit(sgiseeq_exit); +MODULE_DESCRIPTION("SGI Seeq 8003 driver"); +MODULE_AUTHOR("Linux/MIPS Mailing List "); MODULE_LICENSE("GPL"); diff --git a/include/asm-mips/sgi/hpc3.h b/include/asm-mips/sgi/hpc3.h index ac3dfc7af5b0..fcec52bafb25 100644 --- a/include/asm-mips/sgi/hpc3.h +++ b/include/asm-mips/sgi/hpc3.h @@ -128,26 +128,26 @@ struct hpc3_ethregs { volatile u32 rx_gfptr; /* current GIO fifo ptr */ volatile u32 rx_dfptr; /* current device fifo ptr */ u32 _unused1; /* padding */ - volatile u32 rx_reset; /* reset register */ -#define HPC3_ERXRST_CRESET 0x1 /* Reset dma channel and external controller */ -#define HPC3_ERXRST_CLRIRQ 0x2 /* Clear channel interrupt */ -#define HPC3_ERXRST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */ + volatile u32 reset; /* reset register */ +#define HPC3_ERST_CRESET 0x1 /* Reset dma channel and external controller */ +#define HPC3_ERST_CLRIRQ 0x2 /* Clear channel interrupt */ +#define HPC3_ERST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */ - volatile u32 rx_dconfig; /* DMA configuration register */ -#define HPC3_ERXDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */ -#define HPC3_ERXDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */ -#define HPC3_ERXDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */ -#define HPC3_ERXDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */ -#define HPC3_ERXDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */ -#define HPC3_ERXDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */ -#define HPC3_ERXDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */ -#define HPC3_ERXDCFG_PTO 0x30000 /* Programmed timeout value for above two */ + volatile u32 dconfig; /* DMA configuration register */ +#define HPC3_EDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */ +#define HPC3_EDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */ +#define HPC3_EDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */ +#define HPC3_EDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */ +#define HPC3_EDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */ +#define HPC3_EDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */ +#define HPC3_EDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */ +#define HPC3_EDCFG_PTO 0x30000 /* Programmed timeout value for above two */ - volatile u32 rx_pconfig; /* PIO configuration register */ -#define HPC3_ERXPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */ -#define HPC3_ERXPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */ -#define HPC3_ERXPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */ -#define HPC3_ERXPCFG_TST 0x1000 /* Diagnistic ram test feature bit */ + volatile u32 pconfig; /* PIO configuration register */ +#define HPC3_EPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */ +#define HPC3_EPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */ +#define HPC3_EPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */ +#define HPC3_EPCFG_TST 0x1000 /* Diagnistic ram test feature bit */ u32 _unused2[0x1000/4 - 8]; /* padding */ From da848ec37d9cf9edbe269f8be9b3de52f90d70da Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:01 +0100 Subject: [PATCH 0469/1939] [PATCH] declance: Convert to irqreturn_t. Signed-off-by: Ralf Baechle drivers/net/declance.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/declance.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 521c83137bf6..636763b5102e 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -697,12 +697,13 @@ static void lance_tx(struct net_device *dev) spin_unlock(&lp->lock); } -static void lance_dma_merr_int(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; printk("%s: DMA error\n", dev->name); + return IRQ_HANDLED; } static irqreturn_t From 6684b4e28247f31543edf86ba785aa87e8fa3b39 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:06 +0100 Subject: [PATCH 0470/1939] [PATCH] declance: Fix mapping of device. These should really be addresses obtained with ioremap() or some bus-specific backend, but for now... Signed-off-by: Ralf Baechle drivers/net/declance.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/declance.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 636763b5102e..3af78340d963 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -237,7 +237,7 @@ struct lance_init_block { /* * This works *only* for the ring descriptors */ -#define LANCE_ADDR(x) (PHYSADDR(x) >> 1) +#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1) struct lance_private { struct net_device *next; @@ -1102,7 +1102,7 @@ static int __init dec_lance_init(const int type, const int slot) /* Setup I/O ASIC LANCE DMA. */ lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR]; ioasic_write(IO_REG_LANCE_DMA_P, - PHYSADDR(dev->mem_start) << 3); + CPHYSADDR(dev->mem_start) << 3); break; From 4569504a36cb6223e2b7ad6530326a1563a8f456 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:11 +0100 Subject: [PATCH 0471/1939] [PATCH] declance: Deal with the bloody KSEG vs CKSEG horror... Signed-off-by: Ralf Baechle drivers/net/declance.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/declance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 3af78340d963..b47e3cf16516 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1069,7 +1069,7 @@ static int __init dec_lance_init(const int type, const int slot) /* * FIXME: ugly hack! */ - dev->mem_start = KSEG1ADDR(0x00020000); + dev->mem_start = CKSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = dec_interrupt[DEC_IRQ_LANCE]; esar_base = system_base + IOASIC_ESAR; From 36156cdff17a5ab822898d33cd890a6f8287c43c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:16 +0100 Subject: [PATCH 0472/1939] [PATCH] declance: Use physical addresses at the interface level. Use physical addresses at the interface level, letting drivers remap them as appropriate. Signed-off-by: Ralf Baechle drivers/net/declance.c | 26 ++++++++++---------------- 1 files changed, 10 insertions(+), 16 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/declance.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b47e3cf16516..f130bdab3fd3 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -5,7 +5,7 @@ * * adopted from sunlance.c by Richard van den Berg * - * Copyright (C) 2002, 2003 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, @@ -57,13 +57,15 @@ #include #include +#include + #include #include #include #include #include +#include #include -#include static char version[] __devinitdata = "declance.c: v0.009 by Linux MIPS DECstation task force\n"; @@ -79,10 +81,6 @@ MODULE_LICENSE("GPL"); #define PMAD_LANCE 2 #define PMAX_LANCE 3 -#ifndef CONFIG_TC -unsigned long system_base; -unsigned long dmaptr; -#endif #define LE_CSR0 0 #define LE_CSR1 1 @@ -1027,10 +1025,6 @@ static int __init dec_lance_init(const int type, const int slot) unsigned long esar_base; unsigned char *esar; -#ifndef CONFIG_TC - system_base = KN01_LANCE_BASE; -#endif - if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1063,7 +1057,7 @@ static int __init dec_lance_init(const int type, const int slot) switch (type) { #ifdef CONFIG_TC case ASIC_LANCE: - dev->base_addr = system_base + IOASIC_LANCE; + dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); /* buffer space for the on-board LANCE shared memory */ /* @@ -1072,7 +1066,7 @@ static int __init dec_lance_init(const int type, const int slot) dev->mem_start = CKSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - esar_base = system_base + IOASIC_ESAR; + esar_base = CKSEG1ADDR(dec_kn_slot_base + IOASIC_ESAR); /* Workaround crash with booting KN04 2.1k from Disk */ memset((void *)dev->mem_start, 0, @@ -1109,7 +1103,7 @@ static int __init dec_lance_init(const int type, const int slot) case PMAD_LANCE: claim_tc_card(slot); - dev->mem_start = get_tc_base_addr(slot); + dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); dev->base_addr = dev->mem_start + 0x100000; dev->irq = get_tc_irq_nr(slot); esar_base = dev->mem_start + 0x1c0002; @@ -1138,9 +1132,9 @@ static int __init dec_lance_init(const int type, const int slot) case PMAX_LANCE: dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - dev->base_addr = KN01_LANCE_BASE; - dev->mem_start = KN01_LANCE_BASE + 0x01000000; - esar_base = KN01_RTC_BASE + 1; + dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE); + dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM); + esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1); lp->dma_irq = -1; /* From 9cc975e00ddb291035bc4d2d49cdc8768ddf1cc3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:21 +0100 Subject: [PATCH 0473/1939] [PATCH] ne: Support for RBHMA4500 eval board. Support for Toshiba's RBHMA4500 eval board for the TX4938. Signed-off-by: Ralf Baechle drivers/net/ne.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/ne.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/ne.c b/drivers/net/ne.c index d209a1556b2e..0de8fdd2aa86 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -54,6 +54,10 @@ static const char version2[] = #include #include +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) +#include +#endif + #include "8390.h" #define DRV_NAME "ne" @@ -111,6 +115,9 @@ bad_clone_list[] __initdata = { {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ +#endif {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ {NULL,} }; @@ -226,6 +233,10 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); +#ifdef CONFIG_TOSHIBA_RBTX4938 + dev->base_addr = 0x07f20280; + dev->irq = RBTX4938_RTL_8019_IRQ; +#endif err = do_ne_probe(dev); if (err) goto out; @@ -506,6 +517,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + wordlength = 1; +#endif + #ifdef CONFIG_PLAT_OAKS32R ei_status.word16 = 0; #else From dcbf8477567c312c9f0512545d07e05175d740a4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 10 Oct 2005 14:51:27 +0100 Subject: [PATCH 0474/1939] [PATCH] mipsnet: Virtual ethernet driver for MIPSsim. Signed-off-by: Ralf Baechle drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 drivers/net/mipsnet.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/mipsnet.h | 127 +++++++++++++++++ 4 files changed, 507 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + drivers/net/mipsnet.c | 371 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/mipsnet.h | 127 +++++++++++++++ 4 files changed, 507 insertions(+) create mode 100644 drivers/net/mipsnet.c create mode 100644 drivers/net/mipsnet.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0a30368d2efc..5148d47492a0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -475,6 +475,14 @@ config SGI_IOC3_ETH_HW_TX_CSUM the moment only acceleration of IPv4 is supported. This option enables offloading for checksums on transmit. If unsure, say Y. +config MIPS_SIM_NET + tristate "MIPS simulator Network device (EXPERIMENTAL)" + depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL + help + The MIPSNET device is a simple Ethernet network device which is + emulated by the MIPS Simulator. + If you are not using a MIPSsim or are unsure, say N. + config SGI_O2MACE_ETH tristate "SGI O2 MACE Fast Ethernet support" depends on NET_ETHERNET && SGI_IP32=y diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4c9477cb2127..1a84e0435f64 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -167,6 +167,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o +obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c new file mode 100644 index 000000000000..f79f7ee72ab8 --- /dev/null +++ b/drivers/net/mipsnet.c @@ -0,0 +1,371 @@ +/* + * 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. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mipsnet.h" /* actual device IO mapping */ + +#define MIPSNET_VERSION "2005-06-20" + +#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) + +struct mipsnet_priv { + struct net_device_stats stats; +}; + +static struct platform_device *mips_plat_dev; + +static char mipsnet_string[] = "mipsnet"; + +/* + * Copy data from the MIPSNET rx data port + */ +static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, + int len) +{ + uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount)); + if (available_len < len) + return -EFAULT; + + for (; len > 0; len--, kdata++) { + *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); + } + + return inl(mipsnet_reg_address(dev, rxDataCount)); +} + +static inline ssize_t mipsnet_put_todevice(struct net_device *dev, + struct sk_buff *skb) +{ + int count_to_go = skb->len; + char *buf_ptr = skb->data; + struct mipsnet_priv *mp = netdev_priv(dev); + + pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", + dev->name, __FUNCTION__, skb->len); + + outl(skb->len, mipsnet_reg_address(dev, txDataCount)); + + pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", + dev->name, __FUNCTION__, skb->len); + + for (; count_to_go; buf_ptr++, count_to_go--) { + outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); + } + + mp->stats.tx_packets++; + mp->stats.tx_bytes += skb->len; + + return skb->len; +} + +static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pr_debug("%s:%s(): transmitting %d bytes\n", + dev->name, __FUNCTION__, skb->len); + + /* Only one packet at a time. Once TXDONE interrupt is serviced, the + * queue will be restarted. + */ + netif_stop_queue(dev); + mipsnet_put_todevice(dev, skb); + + return 0; +} + +static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) +{ + struct sk_buff *skb; + size_t len = count; + struct mipsnet_priv *mp = netdev_priv(dev); + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + mp->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) + return -EFAULT; + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + pr_debug("%s:%s(): pushing RXed data to kernel\n", + dev->name, __FUNCTION__); + netif_rx(skb); + + mp->stats.rx_packets++; + mp->stats.rx_bytes += len; + + return count; +} + +static irqreturn_t +mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + + irqreturn_t retval = IRQ_NONE; + uint64_t interruptFlags; + + if (irq == dev->irq) { + pr_debug("%s:%s(): irq %d for device\n", + dev->name, __FUNCTION__, irq); + + retval = IRQ_HANDLED; + + interruptFlags = + inl(mipsnet_reg_address(dev, interruptControl)); + pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, + __FUNCTION__, interruptFlags); + + if (interruptFlags & MIPSNET_INTCTL_TXDONE) { + pr_debug("%s:%s(): got TXDone\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_TXDONE, + mipsnet_reg_address(dev, interruptControl)); + // only one packet at a time, we are done. + netif_wake_queue(dev); + } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { + pr_debug("%s:%s(): got RX data\n", + dev->name, __FUNCTION__); + mipsnet_get_fromdev(dev, + inl(mipsnet_reg_address(dev, rxDataCount))); + pr_debug("%s:%s(): clearing RX int\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_RXDONE, + mipsnet_reg_address(dev, interruptControl)); + + } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { + pr_debug("%s:%s(): got test interrupt\n", + dev->name, __FUNCTION__); + // TESTBIT is cleared on read. + // And takes effect after a write with 0 + outl(0, mipsnet_reg_address(dev, interruptControl)); + } else { + pr_debug("%s:%s(): no valid fags 0x%016llx\n", + dev->name, __FUNCTION__, interruptFlags); + // Maybe shared IRQ, just ignore, no clearing. + retval = IRQ_NONE; + } + + } else { + printk(KERN_INFO "%s: %s(): irq %d for unknown device\n", + dev->name, __FUNCTION__, irq); + retval = IRQ_NONE; + } + return retval; +} //mipsnet_interrupt() + +static int mipsnet_open(struct net_device *dev) +{ + int err; + pr_debug("%s: mipsnet_open\n", dev->name); + + err = request_irq(dev->irq, &mipsnet_interrupt, + SA_SHIRQ, dev->name, (void *) dev); + + if (err) { + pr_debug("%s: %s(): can't get irq %d\n", + dev->name, __FUNCTION__, dev->irq); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + return err; + } + + pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", + dev->name, __FUNCTION__, dev->base_addr, dev->irq); + + + netif_start_queue(dev); + + // test interrupt handler + outl(MIPSNET_INTCTL_TESTBIT, + mipsnet_reg_address(dev, interruptControl)); + + + return 0; +} + +static int mipsnet_close(struct net_device *dev) +{ + pr_debug("%s: %s()\n", dev->name, __FUNCTION__); + netif_stop_queue(dev); + return 0; +} + +static struct net_device_stats *mipsnet_get_stats(struct net_device *dev) +{ + struct mipsnet_priv *mp = netdev_priv(dev); + + return &mp->stats; +} + +static void mipsnet_set_mclist(struct net_device *dev) +{ + // we don't do anything + return; +} + +static int __init mipsnet_probe(struct device *dev) +{ + struct net_device *netdev; + int err; + + netdev = alloc_etherdev(sizeof(struct mipsnet_priv)); + if (!netdev) { + err = -ENOMEM; + goto out; + } + + dev_set_drvdata(dev, netdev); + + netdev->open = mipsnet_open; + netdev->stop = mipsnet_close; + netdev->hard_start_xmit = mipsnet_xmit; + netdev->get_stats = mipsnet_get_stats; + netdev->set_multicast_list = mipsnet_set_mclist; + + /* + * TODO: probe for these or load them from PARAM + */ + netdev->base_addr = 0x4200; + netdev->irq = MIPSCPU_INT_BASE + MIPSCPU_INT_MB0 + + inl(mipsnet_reg_address(netdev, interruptInfo)); + + // Get the io region now, get irq on open() + if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { + pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " + "for dev is not availble.\n", netdev->name, + __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); + err = -EBUSY; + goto out_free_netdev; + } + + /* + * Lacking any better mechanism to allocate a MAC address we use a + * random one ... + */ + random_ether_addr(netdev->dev_addr); + + err = register_netdev(netdev); + if (err) { + printk(KERN_ERR "MIPSNet: failed to register netdev.\n"); + goto out_free_region; + } + + return 0; + +out_free_region: + release_region(netdev->base_addr, MIPSNET_IO_EXTENT); + +out_free_netdev: + free_netdev(netdev); + +out: + return err; +} + +static int __devexit mipsnet_device_remove(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + + unregister_netdev(dev); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + free_netdev(dev); + dev_set_drvdata(device, NULL); + + return 0; +} + +static struct device_driver mipsnet_driver = { + .name = mipsnet_string, + .bus = &platform_bus_type, + .probe = mipsnet_probe, + .remove = __devexit_p(mipsnet_device_remove), +}; + +static void mipsnet_platform_release(struct device *device) +{ + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device(device); + kfree(pldev); +} + +static int __init mipsnet_init_module(void) +{ + struct platform_device *pldev; + int err; + + printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " + "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); + + if (driver_register(&mipsnet_driver)) { + printk(KERN_ERR "Driver registration failed\n"); + err = -ENODEV; + goto out; + } + + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unregister_driver; + } + + memset (pldev, 0, sizeof (*pldev)); + pldev->name = mipsnet_string; + pldev->id = 0; + pldev->dev.release = mipsnet_platform_release; + + if (platform_device_register(pldev)) { + err = -ENODEV; + goto out_free_pldev; + } + + if (!pldev->dev.driver) { + /* + * The driver was not bound to this device, there was + * no hardware at this address. Unregister it, as the + * release fuction will take care of freeing the + * allocated structure + */ + platform_device_unregister (pldev); + } + + mips_plat_dev = pldev; + + return 0; + +out_free_pldev: + kfree(pldev); + +out_unregister_driver: + driver_unregister(&mipsnet_driver); +out: + return err; +} + +static void __exit mipsnet_exit_module(void) +{ + pr_debug("MIPSNet Ethernet driver exiting\n"); + + driver_unregister(&mipsnet_driver); +} + +module_init(mipsnet_init_module); +module_exit(mipsnet_exit_module); diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h new file mode 100644 index 000000000000..878535953cb1 --- /dev/null +++ b/drivers/net/mipsnet.h @@ -0,0 +1,127 @@ +// +// +// Unpublished work (c) MIPS Technologies, Inc. All rights reserved. +// Unpublished rights reserved under the copyright laws of the U.S.A. and +// other countries. +// +// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC. +// FOR INTERNAL USE ONLY. +// +// Under no circumstances (contract or otherwise) may this information be +// disclosed to, or copied, modified or used by anyone other than employees +// or contractors of MIPS Technologies having a need to know. +// +// +//++ +// File: MIPS_Net.h +// +// Description: +// The definition of the emulated MIPSNET device's interface. +// +// Notes: This include file needs to work from a Linux device drivers. +// +//-- +// + +#ifndef __MIPSNET_H +#define __MIPSNET_H + +/* + * Id of this Net device, as seen by the core. + */ +#define MIPS_NET_DEV_ID ((uint64_t) \ + ((uint64_t)'M'<< 0)| \ + ((uint64_t)'I'<< 8)| \ + ((uint64_t)'P'<<16)| \ + ((uint64_t)'S'<<24)| \ + ((uint64_t)'N'<<32)| \ + ((uint64_t)'E'<<40)| \ + ((uint64_t)'T'<<48)| \ + ((uint64_t)'0'<<56)) + +/* + * Net status/control block as seen by sw in the core. + * (Why not use bit fields? can't be bothered with cross-platform struct + * packing.) + */ +typedef struct _net_control_block { + /// dev info for probing + /// reads as MIPSNET%d where %d is some form of version + uint64_t devId; /*0x00 */ + + /* + * read only busy flag. + * Set and cleared by the Net Device to indicate that an rx or a tx + * is in progress. + */ + uint32_t busy; /*0x08 */ + + /* + * Set by the Net Device. + * The device will set it once data has been received. + * The value is the number of bytes that should be read from + * rxDataBuffer. The value will decrease till 0 until all the data + * from rxDataBuffer has been read. + */ + uint32_t rxDataCount; /*0x0c */ +#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) + + /* + * Settable from the MIPS core, cleared by the Net Device. + * The core should set the number of bytes it wants to send, + * then it should write those bytes of data to txDataBuffer. + * The device will clear txDataCount has been processed (not necessarily sent). + */ + uint32_t txDataCount; /*0x10 */ + + /* + * Interrupt control + * + * Used to clear the interrupted generated by this dev. + * Write a 1 to clear the interrupt. (except bit31). + * + * Bit0 is set if it was a tx-done interrupt. + * Bit1 is set when new rx-data is available. + * Until this bit is cleared there will be no other RXs. + * + * Bit31 is used for testing, it clears after a read. + * Writing 1 to this bit will cause an interrupt to be generated. + * To clear the test interrupt, write 0 to this register. + */ + uint32_t interruptControl; /*0x14 */ +#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0)) +#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1)) +#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31)) +#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT) + + /* + * Readonly core-specific interrupt info for the device to signal the core. + * The meaning of the contents of this field might change. + */ + /*###\todo: the whole memIntf interrupt scheme is messy: the device should have + * no control what so ever of what VPE/register set is being used. + * The MemIntf should only expose interrupt lines, and something in the + * config should be responsible for the line<->core/vpe bindings. + */ + uint32_t interruptInfo; /*0x18 */ + + /* + * This is where the received data is read out. + * There is more data to read until rxDataReady is 0. + * Only 1 byte at this regs offset is used. + */ + uint32_t rxDataBuffer; /*0x1c */ + + /* + * This is where the data to transmit is written. + * Data should be written for the amount specified in the txDataCount register. + * Only 1 byte at this regs offset is used. + */ + uint32_t txDataBuffer; /*0x20 */ +} MIPS_T_NetControl; + +#define MIPSNET_IO_EXTENT 0x40 /* being generous */ + +#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field) + +#endif /* __MIPSNET_H */ From 166d823d397b9f5404648cedfdefe13e10683694 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 16 Oct 2005 13:32:14 -0700 Subject: [PATCH 0475/1939] [PATCH] e1000_intr build fix drivers/net/e1000/e1000_main.c: In function `e1000_intr': drivers/net/e1000/e1000_main.c:3156: error: `i' undeclared (first use in this function) drivers/net/e1000/e1000_main.c:3156: error: (Each undeclared identifier is reported only once drivers/net/e1000/e1000_main.c:3156: error: for each function it appears in.) This function is foul. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index dd79449f9a99..18847f9e4d49 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3100,7 +3100,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); -#ifdef CONFIG_E1000_MQ +#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI) int i; #endif From 923833405d8d81b5be036093773d88d87fc7e1bd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 16 Oct 2005 00:11:29 -0700 Subject: [PATCH 0476/1939] [PATCH] s2io build fix Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 30fbaf04773f..d303d162974f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2997,7 +2997,7 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); - if (nic->intr_type == INTA) + if (sp->intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else From 6ba98d311d0a4ff7dc36d8f435ce60174f4c30ec Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:31:02 -0400 Subject: [PATCH 0477/1939] [PATCH] via-rhine: change mdelay to msleep and remove from ISR path Get rid of the mdelay call in rhine_disable_linkmon. The function is called from the via-rhine versions of mdio_read and mdio_write. Those functions are indirectly called from rhine_check_media and rhine_tx_timeout, both of which can be called in interrupt context. So, create tx_timeout_task and check_media_task as instances of struct work_struct inside of rhine_private. Then, change rhine_tx_timeout to invoke schedule_work for tx_timeout_task (i.e. rhine_tx_timeout_task), moving the work to process context. Also, change rhine_error (invoked from rhine_interrupt) to invoke schedule_work for check_media_task (i.e. rhine_check_media_task), which simply calls rhine_check media in process context. Finally, add a call to flush_scheduled_work in rhine_close to avoid any resource conflicts with pending work items. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index e7b4bc3820e3..241871589283 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -490,6 +490,8 @@ struct rhine_private { u8 tx_thresh, rx_thresh; struct mii_if_info mii_if; + struct work_struct tx_timeout_task; + struct work_struct check_media_task; void __iomem *base; }; @@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); +static void rhine_tx_timeout_task(struct net_device *dev); +static void rhine_check_media_task(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void rhine_tx(struct net_device *dev); @@ -851,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; + INIT_WORK(&rp->tx_timeout_task, + (void (*)(void *))rhine_tx_timeout_task, dev); + + INIT_WORK(&rp->check_media_task, + (void (*)(void *))rhine_check_media_task, dev); + /* dev->name not defined before register_netdev()! */ rc = register_netdev(dev); if (rc) @@ -1077,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) ioaddr + ChipCmd1); } +static void rhine_check_media_task(struct net_device *dev) +{ + rhine_check_media(dev, 0); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1130,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) if (quirks & rqRhineI) { iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR - /* Can be called from ISR. Evil. */ - mdelay(1); + /* Do not call from ISR! */ + msleep(1); /* 0x80 must be set immediately before turning it off */ iowrite8(0x80, ioaddr + MIICmd); @@ -1219,6 +1234,16 @@ static int rhine_open(struct net_device *dev) } static void rhine_tx_timeout(struct net_device *dev) +{ + struct rhine_private *rp = netdev_priv(dev); + + /* + * Move bulk of work outside of interrupt context + */ + schedule_work(&rp->tx_timeout_task); +} + +static void rhine_tx_timeout_task(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; @@ -1626,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status) spin_lock(&rp->lock); if (intr_status & IntrLinkChange) - rhine_check_media(dev, 0); + schedule_work(&rp->check_media_task); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); @@ -1874,6 +1899,9 @@ static int rhine_close(struct net_device *dev) spin_unlock_irq(&rp->lock); free_irq(rp->pdev->irq, dev); + + flush_scheduled_work(); + free_rbufs(dev); free_tbufs(dev); free_ring(dev); From b7b1d2021452d0a3562807b6a90dfa5124147a79 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:31:01 -0400 Subject: [PATCH 0478/1939] [PATCH] epic100: fix counting of work_done in epic_poll work_done is overwritten each time through the rx_action loop in epic_poll. This screws-up the NAPI accounting if the loop is executed more than once. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/epic100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 87f522738bfc..f119ec4e89ea 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1334,7 +1334,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep) static int epic_poll(struct net_device *dev, int *budget) { struct epic_private *ep = dev->priv; - int work_done, orig_budget; + int work_done = 0, orig_budget; long ioaddr = dev->base_addr; orig_budget = (*budget > dev->quota) ? dev->quota : *budget; @@ -1343,7 +1343,7 @@ static int epic_poll(struct net_device *dev, int *budget) epic_tx(dev, ep); - work_done = epic_rx(dev, *budget); + work_done += epic_rx(dev, *budget); epic_rx_err(dev, ep); From 4cac018ae30dac8f7fc089a8ff4963904c99725e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:30:59 -0400 Subject: [PATCH 0479/1939] [PATCH] bonding: fix typos in bonding documentation Fix some simple typos in the bonding.txt file. The typos are in areas relating to loading the bonding driver multiple times. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- Documentation/networking/bonding.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index a55f0f95b171..b0fe41da007b 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -777,7 +777,7 @@ doing so is the same as described in the "Configuring Multiple Bonds Manually" section, below. NOTE: It has been observed that some Red Hat supplied kernels -are apparently unable to rename modules at load time (the "-obonding1" +are apparently unable to rename modules at load time (the "-o bond1" part). Attempts to pass that option to modprobe will produce an "Operation not permitted" error. This has been reported on some Fedora Core kernels, and has been seen on RHEL 4 as well. On kernels @@ -883,7 +883,8 @@ the above does not work, and the second bonding instance never sees its options. In that case, the second options line can be substituted as follows: -install bonding1 /sbin/modprobe bonding -obond1 mode=balance-alb miimon=50 +install bond1 /sbin/modprobe --ignore-install bonding -o bond1 \ + mode=balance-alb miimon=50 This may be repeated any number of times, specifying a new and unique name in place of bond1 for each subsequent instance. From 7645baec58b9661366e2038c4ea02bd06aaf1fbc Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:31:00 -0400 Subject: [PATCH 0480/1939] [PATCH] 8139too: fix resume for Realtek 8100B/8139D Add "HasHltClk" flag for RTL-8100B/8139D hardware in order to fix problems resuming from suspend-to-RAM. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/8139too.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 76ef6efd5950..30bee11c48bd 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -552,7 +552,8 @@ const static struct { { "RTL-8100B/8139D", HW_REVID(1, 1, 1, 0, 1, 0, 1), - HasLWake, + HasHltClk /* XXX undocumented? */ + | HasLWake, }, { "RTL-8101", From df49898a47061e82219c991dfbe9ac6ddf7a866b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:30:58 -0400 Subject: [PATCH 0481/1939] [PATCH] bonding: cleanup comment for mode 1 IGMP xmit hack Expand comment explaining MAC address selection for replicated IGMP frames transmitted in bonding mode 1 (active-backup). Also, a small whitespace cleanup. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 58c4e36f87d7..8032126fd589 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4242,8 +4242,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev } static void bond_activebackup_xmit_copy(struct sk_buff *skb, - struct bonding *bond, - struct slave *slave) + struct bonding *bond, + struct slave *slave) { struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); struct ethhdr *eth_data; @@ -4259,7 +4259,11 @@ static void bond_activebackup_xmit_copy(struct sk_buff *skb, skb2->mac.raw = (unsigned char *)skb2->data; eth_data = eth_hdr(skb2); - /* Pick an appropriate source MAC address */ + /* Pick an appropriate source MAC address + * -- use slave's perm MAC addr, unless used by bond + * -- otherwise, borrow active slave's perm MAC addr + * since that will not be used + */ hwaddr = slave->perm_hwaddr; if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN)) hwaddr = bond->curr_active_slave->perm_hwaddr; From 9f38c636ababfb41e58c9ec1e9719492ef7f0479 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:30:59 -0400 Subject: [PATCH 0482/1939] [PATCH] b44: alternate allocation option for DMA descriptors This is a (final?) hack to support the odd DMA allocation requirements of the b44 hardware. The b44 hardware has a 30-bit DMA mask. On x86, anything less than a 32-bit DMA mask forces allocations into the 16MB GFP_DMA range. The memory there is somewhat limited, often resulting in an inability to initialize the b44 driver. This hack uses streaming DMA allocation APIs in order to provide an alternative in case the GFP_DMA allocation fails. It is somewhat ugly, but not much worse than the similar existing hacks to support SKB allocations in the same driver. FWIW, I have received positive feedback on this from several Fedora users. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 134 +++++++++++++++++++++++++++++++++++++++++++--- drivers/net/b44.h | 2 + 2 files changed, 128 insertions(+), 8 deletions(-) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index d27e870e59ab..282ebd15f011 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -106,6 +106,29 @@ static int b44_poll(struct net_device *dev, int *budget); static void b44_poll_controller(struct net_device *dev); #endif +static int dma_desc_align_mask; +static int dma_desc_sync_size; + +static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_device(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + +static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_cpu(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + static inline unsigned long br32(const struct b44 *bp, unsigned long reg) { return readl(bp->regs + reg); @@ -668,6 +691,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dp->ctrl = cpu_to_le32(ctrl); dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dp), + DMA_BIDIRECTIONAL); + return RX_PKT_BUF_SZ; } @@ -692,6 +720,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) pci_unmap_addr_set(dest_map, mapping, pci_unmap_addr(src_map, mapping)); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, + src_idx * sizeof(src_desc), + DMA_BIDIRECTIONAL); + ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) ctrl |= cpu_to_le32(DESC_CTRL_EOT); @@ -700,8 +733,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; + src_map->skb = NULL; + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); @@ -959,6 +998,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); + if (bp->flags & B44_FLAG_TX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, + entry * sizeof(bp->tx_ring[0]), + DMA_TO_DEVICE); + entry = NEXT_TX(entry); bp->tx_prod = entry; @@ -1064,6 +1108,16 @@ static void b44_init_rings(struct b44 *bp) memset(bp->rx_ring, 0, B44_RX_RING_BYTES); memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + if (bp->flags & B44_FLAG_RX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_TODEVICE); + for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) break; @@ -1085,14 +1139,28 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; } if (bp->rx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->rx_ring, bp->rx_ring_dma); + if (bp->flags & B44_FLAG_RX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->tx_ring, bp->tx_ring_dma); + if (bp->flags & B44_FLAG_TX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; } } @@ -1118,12 +1186,56 @@ static int b44_alloc_consistent(struct b44 *bp) size = DMA_TABLE_BYTES; bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); - if (!bp->rx_ring) - goto out_err; + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + + if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(rx_ring, 0, size); + rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + + if (rx_ring_dma + size > B44_DMA_MASK) { + kfree(rx_ring); + goto out_err; + } + + bp->rx_ring = rx_ring; + bp->rx_ring_dma = rx_ring_dma; + bp->flags |= B44_FLAG_RX_RING_HACK; + } bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); - if (!bp->tx_ring) - goto out_err; + if (!bp->tx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *tx_ring; + dma_addr_t tx_ring_dma; + + if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(tx_ring, 0, size); + tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + + if (tx_ring_dma + size > B44_DMA_MASK) { + kfree(tx_ring); + goto out_err; + } + + bp->tx_ring = tx_ring; + bp->tx_ring_dma = tx_ring_dma; + bp->flags |= B44_FLAG_TX_RING_HACK; + } return 0; @@ -1973,6 +2085,12 @@ static struct pci_driver b44_driver = { static int __init b44_init(void) { + unsigned int dma_desc_align_size = dma_get_cache_alignment(); + + /* Setup paramaters for syncing RX/TX DMA descriptors */ + dma_desc_align_mask = ~(dma_desc_align_size - 1); + dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc)); + return pci_module_init(&b44_driver); } diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 11c40a2e71c7..593cb0ad4100 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -400,6 +400,8 @@ struct b44 { #define B44_FLAG_ADV_100HALF 0x04000000 #define B44_FLAG_ADV_100FULL 0x08000000 #define B44_FLAG_INTERNAL_PHY 0x10000000 +#define B44_FLAG_RX_RING_HACK 0x20000000 +#define B44_FLAG_TX_RING_HACK 0x40000000 u32 rx_offset; From 36841c9d02870983c2b08c85d56572c1ff011997 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:30:58 -0400 Subject: [PATCH 0483/1939] [PATCH] orinoco: remove redundance skb length check before padding Checking the skb->len value before calling skb_padto is redundant. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index da4c5e94a959..5db2bbad65c4 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -492,11 +492,9 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) /* Check packet length, pad short packets, round up odd length */ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); - if (skb->len < len) { - skb = skb_padto(skb, len); - if (skb == NULL) - goto fail; - } + skb = skb_padto(skb, len); + if (skb == NULL) + goto fail; len -= ETH_HLEN; eh = (struct ethhdr *)skb->data; From 67ec2f805a5260c041b1c3c7a86ecfbc9670db06 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:31:01 -0400 Subject: [PATCH 0484/1939] [PATCH] sundance: remove if (1) { ... } block in sundance_probe1 Remove an if (1) { ... } block in sundance_probe1. Its purpose seems to be only to allow for delaring some extra local variables. But, it also adds ugly indentation without adding any meaning to the code. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 46 ++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index e148a7212073..8c4eb11ab44e 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -518,6 +518,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif + int phy, phy_idx = 0; /* when built into the kernel, we only print version if device is found */ @@ -606,32 +607,29 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - if (1) { - int phy, phy_idx = 0; - np->phys[0] = 1; /* Default setting */ - np->mii_preamble_required++; - for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); - if ((mii_status & 0x0040) == 0) - np->mii_preamble_required++; - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->mii_if.advertising); - } + np->phys[0] = 1; /* Default setting */ + np->mii_preamble_required++; + for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(dev, phy, MII_BMSR); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); + if ((mii_status & 0x0040) == 0) + np->mii_preamble_required++; + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->mii_if.advertising); } - np->mii_preamble_required--; - - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", - dev->name, ioread32(ioaddr + ASICCtrl)); - goto err_out_unregister; - } - - np->mii_if.phy_id = np->phys[0]; } + np->mii_preamble_required--; + + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", + dev->name, ioread32(ioaddr + ASICCtrl)); + goto err_out_unregister; + } + + np->mii_if.phy_id = np->phys[0]; /* Parse override configuration */ np->an_enable = 1; From 2aa1d82db7a967b748c4b41854c4222cd0484114 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Oct 2005 21:31:02 -0400 Subject: [PATCH 0485/1939] [PATCH] sundance: expand reset mask Expand the mask used when reseting the chip to include the GlobalReset bit. This fix comes from ICPlus and seems to be required for some cards. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 8c4eb11ab44e..d8a7e08cab2b 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -691,7 +691,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, /* Reset the chip to erase previous misconfiguration. */ if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - iowrite16(0x007f, ioaddr + ASICCtrl + 2); + iowrite16(0x00ff, ioaddr + ASICCtrl + 2); if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); From c4cfe567b92d5663f98e2f82f28ffc3069fc982f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 15 Oct 2005 00:32:29 -0700 Subject: [PATCH 0486/1939] [PATCH] e1000 build fix Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 18847f9e4d49..40128b9d16ef 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4347,7 +4347,7 @@ e1000_netpoll(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); disable_irq(adapter->pdev->irq); e1000_intr(adapter->pdev->irq, netdev, NULL); - e1000_clean_tx_irq(adapter); + e1000_clean_tx_irq(adapter, adapter->tx_ring); enable_irq(adapter->pdev->irq); } #endif From 7f709a48fa798cfa0f2f777c8752e12995054f78 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2005 23:19:39 -0700 Subject: [PATCH 0487/1939] NFSv4: Fix an oopsable condition in nfs_free_seqid Storing a pointer to the struct rpc_task in the nfs_seqid is broken since the nfs_seqid may be freed well after the task has been destroyed. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 - fs/nfs/nfs4state.c | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 8a3788199052..45bff1d1a513 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -112,7 +112,6 @@ struct nfs_seqid_counter { struct nfs_seqid { struct list_head list; struct nfs_seqid_counter *sequence; - struct rpc_task *task; }; static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 23834c8fb740..da0861db57fb 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -676,7 +676,6 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) new = kmalloc(sizeof(*new), GFP_KERNEL); if (new != NULL) { new->sequence = counter; - new->task = NULL; spin_lock(&sequence->lock); list_add_tail(&new->list, &sequence->list); spin_unlock(&sequence->lock); @@ -687,15 +686,10 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) void nfs_free_seqid(struct nfs_seqid *seqid) { struct rpc_sequence *sequence = seqid->sequence->sequence; - struct rpc_task *next = NULL; spin_lock(&sequence->lock); list_del(&seqid->list); - if (!list_empty(&sequence->list)) { - next = list_entry(sequence->list.next, struct nfs_seqid, list)->task; - if (next) - rpc_wake_up_task(next); - } + rpc_wake_up(&sequence->wait); spin_unlock(&sequence->lock); kfree(seqid); } @@ -754,7 +748,6 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) spin_lock(&sequence->lock); if (sequence->list.next != &seqid->list) { - seqid->task = task; rpc_sleep_on(&sequence->wait, task, NULL, NULL); status = -EAGAIN; } From 747c5534c9a6da4aa87e7cdc2209ea98ea27f381 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Tue, 18 Oct 2005 23:19:40 -0700 Subject: [PATCH 0488/1939] RPC: stops the release_pipe() funtion from being called twice This patch stops the release_pipe() funtion from being called twice by invalidating the ops pointer in the rpc_inode when rpc_pipe_release() is called. Signed-off-by: Steve Dickson Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ded6c63f11ec..649d609e7d94 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -177,6 +177,8 @@ rpc_pipe_release(struct inode *inode, struct file *filp) __rpc_purge_upcall(inode, -EPIPE); if (rpci->ops->release_pipe) rpci->ops->release_pipe(inode); + if (!rpci->nreaders && !rpci->nwriters) + rpci->ops = NULL; out: up(&inode->i_sem); return 0; From 8c233cf9c2ad6f49df753bdce84fddbf00bf6a75 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:27 -0400 Subject: [PATCH 0489/1939] NFSv4: handle no acl attr Stop handing garbage to userspace in the case where a weird server clears the acl bit in the getattr return (despite the fact that they've already claimed acl support.) Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c5c75235c5b8..cd762648fa9a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3255,7 +3255,8 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, if (attrlen <= *acl_len) xdr_read_pages(xdr, attrlen); *acl_len = attrlen; - } + } else + status = -EOPNOTSUPP; out: return status; From 1d95db8e1688ed54e143a597c5570631a42fa594 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:32 -0400 Subject: [PATCH 0490/1939] NFSv4: Fix acl buffer size resp_len is passed in as buffer size to decode routine; make sure it's set right in case where userspace provides less than a page's worth of buffer. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ff378126ccd7..2d9357cf3fc5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2357,7 +2357,7 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size return -ENOMEM; args.acl_pages[0] = localpage; args.acl_pgbase = 0; - args.acl_len = PAGE_SIZE; + resp_len = args.acl_len = PAGE_SIZE; } else { resp_buf = buf; buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); From 293f1eb551a77fe5c8956a559a3c0baea95cd9bc Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:37 -0400 Subject: [PATCH 0491/1939] SUNRPC: Add support for privacy to generic gss-api code. Add support for privacy to generic gss-api code. This is dead code until we have both a mechanism that supports privacy and code in the client or server that uses it. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_api.h | 22 ++++++++++++++++++++++ net/sunrpc/auth_gss/gss_mech_switch.c | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 689262f63059..e896752ffbf9 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -48,6 +48,17 @@ u32 gss_verify_mic( struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate); +u32 gss_wrap( + struct gss_ctx *ctx_id, + u32 qop, + int offset, + struct xdr_buf *outbuf, + struct page **inpages); +u32 gss_unwrap( + struct gss_ctx *ctx_id, + u32 *qop, + int offset, + struct xdr_buf *inbuf); u32 gss_delete_sec_context( struct gss_ctx **ctx_id); @@ -93,6 +104,17 @@ struct gss_api_ops { struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate); + u32 (*gss_wrap)( + struct gss_ctx *ctx_id, + u32 qop, + int offset, + struct xdr_buf *outbuf, + struct page **inpages); + u32 (*gss_unwrap)( + struct gss_ctx *ctx_id, + u32 *qop, + int offset, + struct xdr_buf *buf); void (*gss_delete_sec_context)( void *internal_ctx_id); }; diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 58aeaddd8c79..06d97cb3481a 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -276,6 +276,28 @@ gss_verify_mic(struct gss_ctx *context_handle, qstate); } +u32 +gss_wrap(struct gss_ctx *ctx_id, + u32 qop, + int offset, + struct xdr_buf *buf, + struct page **inpages) +{ + return ctx_id->mech_type->gm_ops + ->gss_wrap(ctx_id, qop, offset, buf, inpages); +} + +u32 +gss_unwrap(struct gss_ctx *ctx_id, + u32 *qop, + int offset, + struct xdr_buf *buf) +{ + return ctx_id->mech_type->gm_ops + ->gss_unwrap(ctx_id, qop, offset, buf); +} + + /* gss_delete_sec_context: free all resources associated with context_handle. * Note this differs from the RFC 2744-specified prototype in that we don't * bother returning an output token, since it would never be used anyway. */ From ead5e1c26fdcd969cf40c49cb0589d56879d240d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:43 -0400 Subject: [PATCH 0492/1939] SUNRPC: Provide a callback to allow free pages allocated during xdr encoding For privacy, we need to allocate pages to store the encrypted data (passed in pages can't be used without the risk of corrupting data in the page cache). So we need a way to free that memory after the request has been transmitted. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 5 ++++- net/sunrpc/xprt.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 068e1fb0868b..3b8b6e823c70 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -73,7 +73,10 @@ struct rpc_rqst { int rq_cong; /* has incremented xprt->cong */ int rq_received; /* receive completed */ u32 rq_seqno; /* gss seq no. used on req. */ - + int rq_enc_pages_num; + struct page **rq_enc_pages; /* scratch pages for use by + gss privacy code */ + void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */ struct list_head rq_list; struct xdr_buf rq_private_buf; /* The receive buffer diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1ba55dc38b7a..6dda3860351f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -839,6 +839,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) req->rq_task = task; req->rq_xprt = xprt; req->rq_xid = xprt_alloc_xid(xprt); + req->rq_release_snd_buf = NULL; dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, ntohl(req->rq_xid)); } @@ -867,6 +868,8 @@ void xprt_release(struct rpc_task *task) xprt->last_used + xprt->idle_timeout); spin_unlock_bh(&xprt->transport_lock); task->tk_rqstp = NULL; + if (req->rq_release_snd_buf) + req->rq_release_snd_buf(req); memset(req, 0, sizeof(*req)); /* mark unused */ dprintk("RPC: %4d release request %p\n", task->tk_pid, req); From f3680312a737355ddf35c1b68af25e384d7ef0a8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:48 -0400 Subject: [PATCH 0493/1939] SUNRPC: Retry wrap in case of memory allocation failure. For privacy we need to allocate extra pages to hold encrypted page data when wrapping requests. This allocation may fail, and we handle that case by waiting and retrying. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 534274056329..702ede309b06 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -710,9 +710,16 @@ call_encode(struct rpc_task *task) rpc_exit(task, -EIO); return; } - if (encode != NULL) - task->tk_status = rpcauth_wrap_req(task, encode, req, p, - task->tk_msg.rpc_argp); + if (encode == NULL) + return; + + task->tk_status = rpcauth_wrap_req(task, encode, req, p, + task->tk_msg.rpc_argp); + if (task->tk_status == -ENOMEM) { + /* XXX: Is this sane? */ + rpc_delay(task, 3*HZ); + task->tk_status = -EAGAIN; + } } /* From 24b2605becc10ca63c4c30808fa59a8abbf68727 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:53 -0400 Subject: [PATCH 0494/1939] RPCSEC_GSS: cleanup au_rslack calculation Various xdr encode routines use au_rslack to guess where the reply argument will end up, so we can set up the xdr_buf to recieve data into the right place for zero copy. Currently we calculate the au_rslack estimate when we check the verifier. Normally this only depends on the verifier size. In the integrity case we add a few bytes to allow for a length and sequence number. It's a bit simpler to calculate only the verifier size when we check the verifier, and delay the full calculation till we unwrap. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth.h | 7 ++++++- net/sunrpc/auth_gss/auth_gss.c | 20 ++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 04ebc24db348..b68c11a2d6dd 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -66,7 +66,12 @@ struct rpc_cred_cache { struct rpc_auth { unsigned int au_cslack; /* call cred size estimate */ - unsigned int au_rslack; /* reply verf size guess */ + /* guess at number of u32's auth adds before + * reply data; normally the verifier size: */ + unsigned int au_rslack; + /* for gss, used to calculate au_rslack: */ + unsigned int au_verfsize; + unsigned int au_flags; /* various flags */ struct rpc_authops * au_ops; /* operations */ rpc_authflavor_t au_flavor; /* pseudoflavor (note may diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index d2b08f16c257..dc95b797ca65 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -886,8 +886,6 @@ static u32 * gss_validate(struct rpc_task *task, u32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; - struct gss_cred *gss_cred = container_of(cred, struct gss_cred, - gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); u32 seq, qop_state; struct kvec iov; @@ -915,18 +913,9 @@ gss_validate(struct rpc_task *task, u32 *p) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; if (maj_stat) goto out_bad; - switch (gss_cred->gc_service) { - case RPC_GSS_SVC_NONE: - /* verifier data, flavor, length: */ - task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2; - break; - case RPC_GSS_SVC_INTEGRITY: - /* verifier data, flavor, length, length, sequence number: */ - task->tk_auth->au_rslack = XDR_QUADLEN(len) + 4; - break; - case RPC_GSS_SVC_PRIVACY: - goto out_bad; - } + /* We leave it to unwrap to calculate au_rslack. For now we just + * calculate the length of the verifier: */ + task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2; gss_put_ctx(ctx); dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n", task->tk_pid); @@ -1067,6 +1056,7 @@ gss_unwrap_resp(struct rpc_task *task, struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); + u32 *savedp = p; int status = -EIO; if (ctx->gc_proc != RPC_GSS_PROC_DATA) @@ -1082,6 +1072,8 @@ gss_unwrap_resp(struct rpc_task *task, case RPC_GSS_SVC_PRIVACY: break; } + /* take into account extra slack for integrity and privacy cases: */ + task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp); out_decode: status = decode(rqstp, p, obj); out: From 2d2da60c63b67174add32f06e8d54c3a0c5cd9cf Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:54:58 -0400 Subject: [PATCH 0495/1939] RPCSEC_GSS: client-side privacy support Add the code to the client side to handle privacy. This is dead code until we actually add privacy support to krb5. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/auth_gss.c | 149 ++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dc95b797ca65..5e4872058ec7 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -975,6 +976,114 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, return 0; } +static void +priv_release_snd_buf(struct rpc_rqst *rqstp) +{ + int i; + + for (i=0; i < rqstp->rq_enc_pages_num; i++) + __free_page(rqstp->rq_enc_pages[i]); + kfree(rqstp->rq_enc_pages); +} + +static int +alloc_enc_pages(struct rpc_rqst *rqstp) +{ + struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; + int first, last, i; + + if (snd_buf->page_len == 0) { + rqstp->rq_enc_pages_num = 0; + return 0; + } + + first = snd_buf->page_base >> PAGE_CACHE_SHIFT; + last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_CACHE_SHIFT; + rqstp->rq_enc_pages_num = last - first + 1 + 1; + rqstp->rq_enc_pages + = kmalloc(rqstp->rq_enc_pages_num * sizeof(struct page *), + GFP_NOFS); + if (!rqstp->rq_enc_pages) + goto out; + for (i=0; i < rqstp->rq_enc_pages_num; i++) { + rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS); + if (rqstp->rq_enc_pages[i] == NULL) + goto out_free; + } + rqstp->rq_release_snd_buf = priv_release_snd_buf; + return 0; +out_free: + for (i--; i >= 0; i--) { + __free_page(rqstp->rq_enc_pages[i]); + } +out: + return -EAGAIN; +} + +static inline int +gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, + kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj) +{ + struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; + u32 offset; + u32 maj_stat; + int status; + u32 *opaque_len; + struct page **inpages; + int first; + int pad; + struct kvec *iov; + char *tmp; + + opaque_len = p++; + offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; + *p++ = htonl(rqstp->rq_seqno); + + status = encode(rqstp, p, obj); + if (status) + return status; + + status = alloc_enc_pages(rqstp); + if (status) + return status; + first = snd_buf->page_base >> PAGE_CACHE_SHIFT; + inpages = snd_buf->pages + first; + snd_buf->pages = rqstp->rq_enc_pages; + snd_buf->page_base -= first << PAGE_CACHE_SHIFT; + /* Give the tail its own page, in case we need extra space in the + * head when wrapping: */ + if (snd_buf->page_len || snd_buf->tail[0].iov_len) { + tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]); + memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); + snd_buf->tail[0].iov_base = tmp; + } + maj_stat = gss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, offset, + snd_buf, inpages); + /* RPC_SLACK_SPACE should prevent this ever happening: */ + BUG_ON(snd_buf->len > snd_buf->buflen); + status = -EIO; + /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was + * done anyway, so it's safe to put the request on the wire: */ + if (maj_stat == GSS_S_CONTEXT_EXPIRED) + cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; + else if (maj_stat) + return status; + + *opaque_len = htonl(snd_buf->len - offset); + /* guess whether we're in the head or the tail: */ + if (snd_buf->page_len || snd_buf->tail[0].iov_len) + iov = snd_buf->tail; + else + iov = snd_buf->head; + p = iov->iov_base + iov->iov_len; + pad = 3 - ((snd_buf->len - offset - 1) & 3); + memset(p, 0, pad); + iov->iov_len += pad; + snd_buf->len += pad; + + return 0; +} + static int gss_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *p, void *obj) @@ -1002,6 +1111,8 @@ gss_wrap_req(struct rpc_task *task, rqstp, p, obj); break; case RPC_GSS_SVC_PRIVACY: + status = gss_wrap_req_priv(cred, ctx, encode, + rqstp, p, obj); break; } out: @@ -1048,6 +1159,36 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, return 0; } +static inline int +gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, + struct rpc_rqst *rqstp, u32 **p) +{ + struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; + u32 offset; + u32 opaque_len; + u32 maj_stat; + int status = -EIO; + + opaque_len = ntohl(*(*p)++); + offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; + if (offset + opaque_len > rcv_buf->len) + return status; + /* remove padding: */ + rcv_buf->len = offset + opaque_len; + + maj_stat = gss_unwrap(ctx->gc_gss_ctx, NULL, + offset, rcv_buf); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) + cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; + if (maj_stat != GSS_S_COMPLETE) + return status; + if (ntohl(*(*p)++) != rqstp->rq_seqno) + return status; + + return 0; +} + + static int gss_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *p, void *obj) @@ -1057,6 +1198,8 @@ gss_unwrap_resp(struct rpc_task *task, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); u32 *savedp = p; + struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; + int savedlen = head->iov_len; int status = -EIO; if (ctx->gc_proc != RPC_GSS_PROC_DATA) @@ -1070,10 +1213,14 @@ gss_unwrap_resp(struct rpc_task *task, goto out; break; case RPC_GSS_SVC_PRIVACY: + status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p); + if (status) + goto out; break; } /* take into account extra slack for integrity and privacy cases: */ - task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp); + task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp) + + (savedlen - head->iov_len); out_decode: status = decode(rqstp, p, obj); out: From f7b3af64c653c73feb060a9f94f2df9ab4bba4c3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:55:03 -0400 Subject: [PATCH 0496/1939] RPCSEC_GSS: Simplify rpcsec_gss crypto code Factor out some code that will be shared by privacy crypto routines Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_krb5_crypto.c | 106 +++++++++++++++++++------- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index ee6ae74cd1b2..2baf93f8b8f5 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -139,6 +139,82 @@ buf_to_sg(struct scatterlist *sg, char *ptr, int len) { sg->length = len; } +static int +process_xdr_buf(struct xdr_buf *buf, int offset, int len, + int (*actor)(struct scatterlist *, void *), void *data) +{ + int i, page_len, thislen, page_offset, ret = 0; + struct scatterlist sg[1]; + + if (offset >= buf->head[0].iov_len) { + offset -= buf->head[0].iov_len; + } else { + thislen = buf->head[0].iov_len - offset; + if (thislen > len) + thislen = len; + buf_to_sg(sg, buf->head[0].iov_base + offset, thislen); + ret = actor(sg, data); + if (ret) + goto out; + offset = 0; + len -= thislen; + } + if (len == 0) + goto out; + + if (offset >= buf->page_len) { + offset -= buf->page_len; + } else { + page_len = buf->page_len - offset; + if (page_len > len) + page_len = len; + len -= page_len; + page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1); + i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT; + thislen = PAGE_CACHE_SIZE - page_offset; + do { + if (thislen > page_len) + thislen = page_len; + sg->page = buf->pages[i]; + sg->offset = page_offset; + sg->length = thislen; + ret = actor(sg, data); + if (ret) + goto out; + page_len -= thislen; + i++; + page_offset = 0; + thislen = PAGE_CACHE_SIZE; + } while (page_len != 0); + offset = 0; + } + if (len == 0) + goto out; + + if (offset < buf->tail[0].iov_len) { + thislen = buf->tail[0].iov_len - offset; + if (thislen > len) + thislen = len; + buf_to_sg(sg, buf->tail[0].iov_base + offset, thislen); + ret = actor(sg, data); + len -= thislen; + } + if (len != 0) + ret = -EINVAL; +out: + return ret; +} + +static int +checksummer(struct scatterlist *sg, void *data) +{ + struct crypto_tfm *tfm = (struct crypto_tfm *)data; + + crypto_digest_update(tfm, sg, 1); + + return 0; +} + /* checksum the plaintext data and hdrlen bytes of the token header */ s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, @@ -148,8 +224,6 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */ struct scatterlist sg[1]; u32 code = GSS_S_FAILURE; - int len, thislen, offset; - int i; switch (cksumtype) { case CKSUMTYPE_RSA_MD5: @@ -169,33 +243,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, crypto_digest_init(tfm); buf_to_sg(sg, header, hdrlen); crypto_digest_update(tfm, sg, 1); - if (body->head[0].iov_len) { - buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len); - crypto_digest_update(tfm, sg, 1); - } - - len = body->page_len; - if (len != 0) { - offset = body->page_base & (PAGE_CACHE_SIZE - 1); - i = body->page_base >> PAGE_CACHE_SHIFT; - thislen = PAGE_CACHE_SIZE - offset; - do { - if (thislen > len) - thislen = len; - sg->page = body->pages[i]; - sg->offset = offset; - sg->length = thislen; - crypto_digest_update(tfm, sg, 1); - len -= thislen; - i++; - offset = 0; - thislen = PAGE_CACHE_SIZE; - } while(len != 0); - } - if (body->tail[0].iov_len) { - buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len); - crypto_digest_update(tfm, sg, 1); - } + process_xdr_buf(body, 0, body->len, checksummer, tfm); crypto_digest_final(tfm, cksum->data); code = 0; out: From bfa91516b57483fc9c81d8d90325fd2c3c16ac48 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:55:08 -0400 Subject: [PATCH 0497/1939] RPCSEC_GSS: krb5 pre-privacy cleanup The code this was originally derived from processed wrap and mic tokens using the same functions. This required some contortions, and more would be required with the addition of xdr_buf's, so it's better to separate out the two code paths. In preparation for adding privacy support, remove the last vestiges of the old wrap token code. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 5 ++-- net/sunrpc/auth_gss/gss_krb5_mech.c | 5 ++-- net/sunrpc/auth_gss/gss_krb5_seal.c | 38 +++++---------------------- net/sunrpc/auth_gss/gss_krb5_unseal.c | 30 +++++---------------- 4 files changed, 16 insertions(+), 62 deletions(-) diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index ffe31d2eb9ec..cb35833e2ae3 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -121,13 +121,12 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, u32 krb5_make_token(struct krb5_ctx *context_handle, int qop_req, struct xdr_buf *input_message_buffer, - struct xdr_netobj *output_message_buffer, int toktype); + struct xdr_netobj *output_message_buffer); u32 krb5_read_token(struct krb5_ctx *context_handle, struct xdr_netobj *input_token_buffer, - struct xdr_buf *message_buffer, - int *qop_state, int toktype); + struct xdr_buf *message_buffer, int *qop_state); u32 krb5_encrypt(struct crypto_tfm * key, diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 462c5b86b073..8b9066fdfda5 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -199,8 +199,7 @@ gss_verify_mic_kerberos(struct gss_ctx *ctx, int qop_state; struct krb5_ctx *kctx = ctx->internal_ctx_id; - maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state, - KG_TOK_MIC_MSG); + maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state); if (!maj_stat && qop_state) *qstate = qop_state; @@ -216,7 +215,7 @@ gss_get_mic_kerberos(struct gss_ctx *ctx, u32 err = 0; struct krb5_ctx *kctx = ctx->internal_ctx_id; - err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG); + err = krb5_make_token(kctx, qop, message, mic_token); dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index afeeb8715a77..2511834e6e52 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -70,22 +70,12 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -static inline int -gss_krb5_padding(int blocksize, int length) { - /* Most of the code is block-size independent but in practice we - * use only 8: */ - BUG_ON(blocksize != 8); - return 8 - (length & 7); -} - u32 krb5_make_token(struct krb5_ctx *ctx, int qop_req, - struct xdr_buf *text, struct xdr_netobj *token, - int toktype) + struct xdr_buf *text, struct xdr_netobj *token) { s32 checksum_type; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; - int blocksize = 0, tmsglen; unsigned char *ptr, *krb5_hdr, *msg_start; s32 now; @@ -111,21 +101,13 @@ krb5_make_token(struct krb5_ctx *ctx, int qop_req, goto out_err; } - if (toktype == KG_TOK_WRAP_MSG) { - blocksize = crypto_tfm_alg_blocksize(ctx->enc); - tmsglen = blocksize + text->len - + gss_krb5_padding(blocksize, blocksize + text->len); - } else { - tmsglen = 0; - } - - token->len = g_token_size(&ctx->mech_used, 22 + tmsglen); + token->len = g_token_size(&ctx->mech_used, 22); ptr = token->data; - g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr); + g_make_token_header(&ctx->mech_used, 22, &ptr); - *ptr++ = (unsigned char) ((toktype>>8)&0xff); - *ptr++ = (unsigned char) (toktype&0xff); + *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff); + *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff); /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ krb5_hdr = ptr - 2; @@ -133,17 +115,9 @@ krb5_make_token(struct krb5_ctx *ctx, int qop_req, *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg); memset(krb5_hdr + 4, 0xff, 4); - if (toktype == KG_TOK_WRAP_MSG) - *(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg); - if (toktype == KG_TOK_WRAP_MSG) { - /* XXX removing support for now */ + if (make_checksum(checksum_type, krb5_hdr, 8, text, &md5cksum)) goto out_err; - } else { /* Sign only. */ - if (make_checksum(checksum_type, krb5_hdr, 8, text, - &md5cksum)) - goto out_err; - } switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 8767fc53183d..19eba3df6607 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -68,20 +68,13 @@ #endif -/* message_buffer is an input if toktype is MIC and an output if it is WRAP: - * If toktype is MIC: read_token is a mic token, and message_buffer is the - * data that the mic was supposedly taken over. - * If toktype is WRAP: read_token is a wrap token, and message_buffer is used - * to return the decrypted data. - */ +/* read_token is a mic token, and message_buffer is the data that the mic was + * supposedly taken over. */ -/* XXX will need to change prototype and/or just split into a separate function - * when we add privacy (because read_token will be in pages too). */ u32 krb5_read_token(struct krb5_ctx *ctx, struct xdr_netobj *read_token, - struct xdr_buf *message_buffer, - int *qop_state, int toktype) + struct xdr_buf *message_buffer, int *qop_state) { int signalg; int sealalg; @@ -100,16 +93,12 @@ krb5_read_token(struct krb5_ctx *ctx, read_token->len)) goto out; - if ((*ptr++ != ((toktype>>8)&0xff)) || (*ptr++ != (toktype&0xff))) + if ((*ptr++ != ((KG_TOK_MIC_MSG>>8)&0xff)) || + (*ptr++ != ( KG_TOK_MIC_MSG &0xff)) ) goto out; /* XXX sanity-check bodysize?? */ - if (toktype == KG_TOK_WRAP_MSG) { - /* XXX gone */ - goto out; - } - /* get the sign and seal algorithms */ signalg = ptr[0] + (ptr[1] << 8); @@ -120,14 +109,7 @@ krb5_read_token(struct krb5_ctx *ctx, if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) goto out; - if (((toktype != KG_TOK_WRAP_MSG) && (sealalg != 0xffff)) || - ((toktype == KG_TOK_WRAP_MSG) && (sealalg == 0xffff))) - goto out; - - /* in the current spec, there is only one valid seal algorithm per - key type, so a simple comparison is ok */ - - if ((toktype == KG_TOK_WRAP_MSG) && !(sealalg == ctx->sealalg)) + if (sealalg != 0xffff) goto out; /* there are several mappings of seal algorithms to sign algorithms, From 14ae162c24d985593d5b19437d7f3d8fd0062b59 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:55:13 -0400 Subject: [PATCH 0498/1939] RPCSEC_GSS: Add support for privacy to krb5 rpcsec_gss mechanism. Add support for privacy to the krb5 rpcsec_gss mechanism. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 18 +- net/sunrpc/auth_gss/Makefile | 2 +- net/sunrpc/auth_gss/gss_krb5_crypto.c | 156 ++++++++++- net/sunrpc/auth_gss/gss_krb5_mech.c | 7 + net/sunrpc/auth_gss/gss_krb5_seal.c | 4 +- net/sunrpc/auth_gss/gss_krb5_unseal.c | 2 +- net/sunrpc/auth_gss/gss_krb5_wrap.c | 370 ++++++++++++++++++++++++++ 7 files changed, 552 insertions(+), 7 deletions(-) create mode 100644 net/sunrpc/auth_gss/gss_krb5_wrap.c diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index cb35833e2ae3..7f93c2d5ebdb 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -116,7 +116,7 @@ enum seal_alg { s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, - struct xdr_netobj *cksum); + int body_offset, struct xdr_netobj *cksum); u32 krb5_make_token(struct krb5_ctx *context_handle, int qop_req, @@ -128,6 +128,15 @@ krb5_read_token(struct krb5_ctx *context_handle, struct xdr_netobj *input_token_buffer, struct xdr_buf *message_buffer, int *qop_state); +u32 +gss_wrap_kerberos(struct gss_ctx *ctx_id, u32 qop, int offset, + struct xdr_buf *outbuf, struct page **pages); + +u32 +gss_unwrap_kerberos(struct gss_ctx *ctx_id, u32 *qop, int offset, + struct xdr_buf *buf); + + u32 krb5_encrypt(struct crypto_tfm * key, void *iv, void *in, void *out, int length); @@ -136,6 +145,13 @@ u32 krb5_decrypt(struct crypto_tfm * key, void *iv, void *in, void *out, int length); +int +gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *outbuf, int offset, + struct page **pages); + +int +gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *inbuf, int offset); + s32 krb5_make_seq_num(struct crypto_tfm * key, int direction, diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile index fe1b874084bc..f3431a7e33da 100644 --- a/net/sunrpc/auth_gss/Makefile +++ b/net/sunrpc/auth_gss/Makefile @@ -10,7 +10,7 @@ auth_rpcgss-objs := auth_gss.o gss_generic_token.o \ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ - gss_krb5_seqnum.o + gss_krb5_seqnum.o gss_krb5_wrap.o obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 2baf93f8b8f5..3f3d5437f02d 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -218,7 +218,7 @@ checksummer(struct scatterlist *sg, void *data) /* checksum the plaintext data and hdrlen bytes of the token header */ s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, - struct xdr_netobj *cksum) + int body_offset, struct xdr_netobj *cksum) { char *cksumname; struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */ @@ -243,7 +243,8 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, crypto_digest_init(tfm); buf_to_sg(sg, header, hdrlen); crypto_digest_update(tfm, sg, 1); - process_xdr_buf(body, 0, body->len, checksummer, tfm); + process_xdr_buf(body, body_offset, body->len - body_offset, + checksummer, tfm); crypto_digest_final(tfm, cksum->data); code = 0; out: @@ -252,3 +253,154 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, } EXPORT_SYMBOL(make_checksum); + +struct encryptor_desc { + u8 iv[8]; /* XXX hard-coded blocksize */ + struct crypto_tfm *tfm; + int pos; + struct xdr_buf *outbuf; + struct page **pages; + struct scatterlist infrags[4]; + struct scatterlist outfrags[4]; + int fragno; + int fraglen; +}; + +static int +encryptor(struct scatterlist *sg, void *data) +{ + struct encryptor_desc *desc = data; + struct xdr_buf *outbuf = desc->outbuf; + struct page *in_page; + int thislen = desc->fraglen + sg->length; + int fraglen, ret; + int page_pos; + + /* Worst case is 4 fragments: head, end of page 1, start + * of page 2, tail. Anything more is a bug. */ + BUG_ON(desc->fragno > 3); + desc->infrags[desc->fragno] = *sg; + desc->outfrags[desc->fragno] = *sg; + + page_pos = desc->pos - outbuf->head[0].iov_len; + if (page_pos >= 0 && page_pos < outbuf->page_len) { + /* pages are not in place: */ + int i = (page_pos + outbuf->page_base) >> PAGE_CACHE_SHIFT; + in_page = desc->pages[i]; + } else { + in_page = sg->page; + } + desc->infrags[desc->fragno].page = in_page; + desc->fragno++; + desc->fraglen += sg->length; + desc->pos += sg->length; + + fraglen = thislen & 7; /* XXX hardcoded blocksize */ + thislen -= fraglen; + + if (thislen == 0) + return 0; + + ret = crypto_cipher_encrypt_iv(desc->tfm, desc->outfrags, desc->infrags, + thislen, desc->iv); + if (ret) + return ret; + if (fraglen) { + desc->outfrags[0].page = sg->page; + desc->outfrags[0].offset = sg->offset + sg->length - fraglen; + desc->outfrags[0].length = fraglen; + desc->infrags[0] = desc->outfrags[0]; + desc->infrags[0].page = in_page; + desc->fragno = 1; + desc->fraglen = fraglen; + } else { + desc->fragno = 0; + desc->fraglen = 0; + } + return 0; +} + +int +gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset, + struct page **pages) +{ + int ret; + struct encryptor_desc desc; + + BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0); + + memset(desc.iv, 0, sizeof(desc.iv)); + desc.tfm = tfm; + desc.pos = offset; + desc.outbuf = buf; + desc.pages = pages; + desc.fragno = 0; + desc.fraglen = 0; + + ret = process_xdr_buf(buf, offset, buf->len - offset, encryptor, &desc); + return ret; +} + +EXPORT_SYMBOL(gss_encrypt_xdr_buf); + +struct decryptor_desc { + u8 iv[8]; /* XXX hard-coded blocksize */ + struct crypto_tfm *tfm; + struct scatterlist frags[4]; + int fragno; + int fraglen; +}; + +static int +decryptor(struct scatterlist *sg, void *data) +{ + struct decryptor_desc *desc = data; + int thislen = desc->fraglen + sg->length; + int fraglen, ret; + + /* Worst case is 4 fragments: head, end of page 1, start + * of page 2, tail. Anything more is a bug. */ + BUG_ON(desc->fragno > 3); + desc->frags[desc->fragno] = *sg; + desc->fragno++; + desc->fraglen += sg->length; + + fraglen = thislen & 7; /* XXX hardcoded blocksize */ + thislen -= fraglen; + + if (thislen == 0) + return 0; + + ret = crypto_cipher_decrypt_iv(desc->tfm, desc->frags, desc->frags, + thislen, desc->iv); + if (ret) + return ret; + if (fraglen) { + desc->frags[0].page = sg->page; + desc->frags[0].offset = sg->offset + sg->length - fraglen; + desc->frags[0].length = fraglen; + desc->fragno = 1; + desc->fraglen = fraglen; + } else { + desc->fragno = 0; + desc->fraglen = 0; + } + return 0; +} + +int +gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset) +{ + struct decryptor_desc desc; + + /* XXXJBF: */ + BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0); + + memset(desc.iv, 0, sizeof(desc.iv)); + desc.tfm = tfm; + desc.fragno = 0; + desc.fraglen = 0; + return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc); +} + +EXPORT_SYMBOL(gss_decrypt_xdr_buf); diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 8b9066fdfda5..37a9ad97ccd4 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -226,6 +226,8 @@ static struct gss_api_ops gss_kerberos_ops = { .gss_import_sec_context = gss_import_sec_context_kerberos, .gss_get_mic = gss_get_mic_kerberos, .gss_verify_mic = gss_verify_mic_kerberos, + .gss_wrap = gss_wrap_kerberos, + .gss_unwrap = gss_unwrap_kerberos, .gss_delete_sec_context = gss_delete_sec_context_kerberos, }; @@ -240,6 +242,11 @@ static struct pf_desc gss_kerberos_pfs[] = { .service = RPC_GSS_SVC_INTEGRITY, .name = "krb5i", }, + [2] = { + .pseudoflavor = RPC_AUTH_GSS_KRB5P, + .service = RPC_GSS_SVC_PRIVACY, + .name = "krb5p", + }, }; static struct gss_api_mech gss_kerberos_mech = { diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 2511834e6e52..fb852d9ab06f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -116,8 +116,8 @@ krb5_make_token(struct krb5_ctx *ctx, int qop_req, *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg); memset(krb5_hdr + 4, 0xff, 4); - if (make_checksum(checksum_type, krb5_hdr, 8, text, &md5cksum)) - goto out_err; + if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum)) + goto out_err; switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 19eba3df6607..c3d6d1bc100c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -136,7 +136,7 @@ krb5_read_token(struct krb5_ctx *ctx, switch (signalg) { case SGN_ALG_DES_MAC_MD5: ret = make_checksum(checksum_type, ptr - 2, 8, - message_buffer, &md5cksum); + message_buffer, 0, &md5cksum); if (ret) goto out; diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c new file mode 100644 index 000000000000..ddcde6e42b23 --- /dev/null +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +static inline int +gss_krb5_padding(int blocksize, int length) +{ + /* Most of the code is block-size independent but currently we + * use only 8: */ + BUG_ON(blocksize != 8); + return 8 - (length & 7); +} + +static inline void +gss_krb5_add_padding(struct xdr_buf *buf, int offset, int blocksize) +{ + int padding = gss_krb5_padding(blocksize, buf->len - offset); + char *p; + struct kvec *iov; + + if (buf->page_len || buf->tail[0].iov_len) + iov = &buf->tail[0]; + else + iov = &buf->head[0]; + p = iov->iov_base + iov->iov_len; + iov->iov_len += padding; + buf->len += padding; + memset(p, padding, padding); +} + +static inline int +gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) +{ + u8 *ptr; + u8 pad; + int len = buf->len; + + if (len <= buf->head[0].iov_len) { + pad = *(u8 *)(buf->head[0].iov_base + len - 1); + if (pad > buf->head[0].iov_len) + return -EINVAL; + buf->head[0].iov_len -= pad; + goto out; + } else + len -= buf->head[0].iov_len; + if (len <= buf->page_len) { + int last = (buf->page_base + len - 1) + >>PAGE_CACHE_SHIFT; + int offset = (buf->page_base + len - 1) + & (PAGE_CACHE_SIZE - 1); + ptr = kmap_atomic(buf->pages[last], KM_SKB_SUNRPC_DATA); + pad = *(ptr + offset); + kunmap_atomic(ptr, KM_SKB_SUNRPC_DATA); + goto out; + } else + len -= buf->page_len; + BUG_ON(len > buf->tail[0].iov_len); + pad = *(u8 *)(buf->tail[0].iov_base + len - 1); +out: + /* XXX: NOTE: we do not adjust the page lengths--they represent + * a range of data in the real filesystem page cache, and we need + * to know that range so the xdr code can properly place read data. + * However adjusting the head length, as we do above, is harmless. + * In the case of a request that fits into a single page, the server + * also uses length and head length together to determine the original + * start of the request to copy the request for deferal; so it's + * easier on the server if we adjust head and tail length in tandem. + * It's not really a problem that we don't fool with the page and + * tail lengths, though--at worst badly formed xdr might lead the + * server to attempt to parse the padding. + * XXX: Document all these weird requirements for gss mechanism + * wrap/unwrap functions. */ + if (pad > blocksize) + return -EINVAL; + if (buf->len > pad) + buf->len -= pad; + else + return -EINVAL; + return 0; +} + +static inline void +make_confounder(char *p, int blocksize) +{ + static u64 i = 0; + u64 *q = (u64 *)p; + + /* rfc1964 claims this should be "random". But all that's really + * necessary is that it be unique. And not even that is necessary in + * our case since our "gssapi" implementation exists only to support + * rpcsec_gss, so we know that the only buffers we will ever encrypt + * already begin with a unique sequence number. Just to hedge my bets + * I'll make a half-hearted attempt at something unique, but ensuring + * uniqueness would mean worrying about atomicity and rollover, and I + * don't care enough. */ + + BUG_ON(blocksize != 8); + *q = i++; +} + +/* Assumptions: the head and tail of inbuf are ours to play with. + * The pages, however, may be real pages in the page cache and we replace + * them with scratch pages from **pages before writing to them. */ +/* XXX: obviously the above should be documentation of wrap interface, + * and shouldn't be in this kerberos-specific file. */ + +/* XXX factor out common code with seal/unseal. */ + +u32 +gss_wrap_kerberos(struct gss_ctx *ctx, u32 qop, int offset, + struct xdr_buf *buf, struct page **pages) +{ + struct krb5_ctx *kctx = ctx->internal_ctx_id; + s32 checksum_type; + struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; + int blocksize = 0, plainlen; + unsigned char *ptr, *krb5_hdr, *msg_start; + s32 now; + int headlen; + struct page **tmp_pages; + + dprintk("RPC: gss_wrap_kerberos\n"); + + now = get_seconds(); + + if (qop != 0) + goto out_err; + + switch (kctx->signalg) { + case SGN_ALG_DES_MAC_MD5: + checksum_type = CKSUMTYPE_RSA_MD5; + break; + default: + dprintk("RPC: gss_krb5_seal: kctx->signalg %d not" + " supported\n", kctx->signalg); + goto out_err; + } + if (kctx->sealalg != SEAL_ALG_NONE && kctx->sealalg != SEAL_ALG_DES) { + dprintk("RPC: gss_krb5_seal: kctx->sealalg %d not supported\n", + kctx->sealalg); + goto out_err; + } + + blocksize = crypto_tfm_alg_blocksize(kctx->enc); + gss_krb5_add_padding(buf, offset, blocksize); + BUG_ON((buf->len - offset) % blocksize); + plainlen = blocksize + buf->len - offset; + + headlen = g_token_size(&kctx->mech_used, 22 + plainlen) - + (buf->len - offset); + + ptr = buf->head[0].iov_base + offset; + /* shift data to make room for header. */ + /* XXX Would be cleverer to encrypt while copying. */ + /* XXX bounds checking, slack, etc. */ + memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset); + buf->head[0].iov_len += headlen; + buf->len += headlen; + BUG_ON((buf->len - offset - headlen) % blocksize); + + g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr); + + + *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff); + *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff); + + /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ + krb5_hdr = ptr - 2; + msg_start = krb5_hdr + 24; + /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize); + + *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg); + memset(krb5_hdr + 4, 0xff, 4); + *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg); + + make_confounder(msg_start, blocksize); + + /* XXXJBF: UGH!: */ + tmp_pages = buf->pages; + buf->pages = pages; + if (make_checksum(checksum_type, krb5_hdr, 8, buf, + offset + headlen - blocksize, &md5cksum)) + goto out_err; + buf->pages = tmp_pages; + + switch (kctx->signalg) { + case SGN_ALG_DES_MAC_MD5: + if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, + md5cksum.data, md5cksum.len)) + goto out_err; + memcpy(krb5_hdr + 16, + md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, + KRB5_CKSUM_LENGTH); + + dprintk("RPC: make_seal_token: cksum data: \n"); + print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); + break; + default: + BUG(); + } + + kfree(md5cksum.data); + + /* XXX would probably be more efficient to compute checksum + * and encrypt at the same time: */ + if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, + kctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) + goto out_err; + + if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, + pages)) + goto out_err; + + kctx->seq_send++; + + return ((kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); +out_err: + if (md5cksum.data) kfree(md5cksum.data); + return GSS_S_FAILURE; +} + +u32 +gss_unwrap_kerberos(struct gss_ctx *ctx, u32 *qop, int offset, + struct xdr_buf *buf) +{ + struct krb5_ctx *kctx = ctx->internal_ctx_id; + int signalg; + int sealalg; + s32 checksum_type; + struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; + s32 now; + int direction; + s32 seqnum; + unsigned char *ptr; + int bodysize; + u32 ret = GSS_S_DEFECTIVE_TOKEN; + void *data_start, *orig_start; + int data_len; + int blocksize; + + dprintk("RPC: gss_unwrap_kerberos\n"); + + ptr = (u8 *)buf->head[0].iov_base + offset; + if (g_verify_token_header(&kctx->mech_used, &bodysize, &ptr, + buf->len - offset)) + goto out; + + if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) || + (*ptr++ != (KG_TOK_WRAP_MSG &0xff)) ) + goto out; + + /* XXX sanity-check bodysize?? */ + + /* get the sign and seal algorithms */ + + signalg = ptr[0] + (ptr[1] << 8); + sealalg = ptr[2] + (ptr[3] << 8); + + /* Sanity checks */ + + if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) + goto out; + + if (sealalg == 0xffff) + goto out; + + /* in the current spec, there is only one valid seal algorithm per + key type, so a simple comparison is ok */ + + if (sealalg != kctx->sealalg) + goto out; + + /* there are several mappings of seal algorithms to sign algorithms, + but few enough that we can try them all. */ + + if ((kctx->sealalg == SEAL_ALG_NONE && signalg > 1) || + (kctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) || + (kctx->sealalg == SEAL_ALG_DES3KD && + signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) + goto out; + + if (gss_decrypt_xdr_buf(kctx->enc, buf, + ptr + 22 - (unsigned char *)buf->head[0].iov_base)) + goto out; + + /* compute the checksum of the message */ + + /* initialize the the cksum */ + switch (signalg) { + case SGN_ALG_DES_MAC_MD5: + checksum_type = CKSUMTYPE_RSA_MD5; + break; + default: + ret = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + switch (signalg) { + case SGN_ALG_DES_MAC_MD5: + ret = make_checksum(checksum_type, ptr - 2, 8, buf, + ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum); + if (ret) + goto out; + + ret = krb5_encrypt(kctx->seq, NULL, md5cksum.data, + md5cksum.data, md5cksum.len); + if (ret) + goto out; + + if (memcmp(md5cksum.data + 8, ptr + 14, 8)) { + ret = GSS_S_BAD_SIG; + goto out; + } + break; + default: + ret = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + /* it got through unscathed. Make sure the context is unexpired */ + + if (qop) + *qop = GSS_C_QOP_DEFAULT; + + now = get_seconds(); + + ret = GSS_S_CONTEXT_EXPIRED; + if (now > kctx->endtime) + goto out; + + /* do sequencing checks */ + + ret = GSS_S_BAD_SIG; + if ((ret = krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction, + &seqnum))) + goto out; + + if ((kctx->initiate && direction != 0xff) || + (!kctx->initiate && direction != 0)) + goto out; + + /* Copy the data back to the right position. XXX: Would probably be + * better to copy and encrypt at the same time. */ + + blocksize = crypto_tfm_alg_blocksize(kctx->enc); + data_start = ptr + 22 + blocksize; + orig_start = buf->head[0].iov_base + offset; + data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start; + memmove(orig_start, data_start, data_len); + buf->head[0].iov_len -= (data_start - orig_start); + buf->len -= (data_start - orig_start); + + ret = GSS_S_DEFECTIVE_TOKEN; + if (gss_krb5_remove_padding(buf, blocksize)) + goto out; + + ret = GSS_S_COMPLETE; +out: + if (md5cksum.data) kfree(md5cksum.data); + return ret; +} From 00fd6e14255fe7a249315746386d640bc4e9e758 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:55:18 -0400 Subject: [PATCH 0499/1939] RPCSEC_GSS remove all qop parameters Not only are the qop parameters that are passed around throughout the gssapi unused by any currently implemented mechanism, but there appears to be some doubt as to whether they will ever be used. Let's just kill them off for now. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_api.h | 13 ++----------- include/linux/sunrpc/gss_err.h | 10 ---------- include/linux/sunrpc/gss_krb5.h | 8 ++++---- include/linux/sunrpc/gss_spkm3.h | 4 ++-- net/sunrpc/auth_gss/auth_gss.c | 20 +++++++------------- net/sunrpc/auth_gss/gss_krb5_mech.c | 12 ++++-------- net/sunrpc/auth_gss/gss_krb5_seal.c | 5 +---- net/sunrpc/auth_gss/gss_krb5_unseal.c | 5 +---- net/sunrpc/auth_gss/gss_krb5_wrap.c | 11 ++--------- net/sunrpc/auth_gss/gss_mech_switch.c | 14 ++++---------- net/sunrpc/auth_gss/gss_spkm3_mech.c | 21 ++++++++------------- net/sunrpc/auth_gss/gss_spkm3_seal.c | 4 +--- net/sunrpc/auth_gss/gss_spkm3_unseal.c | 2 +- net/sunrpc/auth_gss/svcauth_gss.c | 9 ++++----- 14 files changed, 41 insertions(+), 97 deletions(-) diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index e896752ffbf9..9b8bcf125c18 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -40,23 +40,19 @@ int gss_import_sec_context( struct gss_ctx **ctx_id); u32 gss_get_mic( struct gss_ctx *ctx_id, - u32 qop, struct xdr_buf *message, struct xdr_netobj *mic_token); u32 gss_verify_mic( struct gss_ctx *ctx_id, struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate); + struct xdr_netobj *mic_token); u32 gss_wrap( struct gss_ctx *ctx_id, - u32 qop, int offset, struct xdr_buf *outbuf, struct page **inpages); u32 gss_unwrap( struct gss_ctx *ctx_id, - u32 *qop, int offset, struct xdr_buf *inbuf); u32 gss_delete_sec_context( @@ -67,7 +63,6 @@ char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); struct pf_desc { u32 pseudoflavor; - u32 qop; u32 service; char *name; char *auth_domain_name; @@ -96,23 +91,19 @@ struct gss_api_ops { struct gss_ctx *ctx_id); u32 (*gss_get_mic)( struct gss_ctx *ctx_id, - u32 qop, struct xdr_buf *message, struct xdr_netobj *mic_token); u32 (*gss_verify_mic)( struct gss_ctx *ctx_id, struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate); + struct xdr_netobj *mic_token); u32 (*gss_wrap)( struct gss_ctx *ctx_id, - u32 qop, int offset, struct xdr_buf *outbuf, struct page **inpages); u32 (*gss_unwrap)( struct gss_ctx *ctx_id, - u32 *qop, int offset, struct xdr_buf *buf); void (*gss_delete_sec_context)( diff --git a/include/linux/sunrpc/gss_err.h b/include/linux/sunrpc/gss_err.h index 92608a2e574c..a6807867bd21 100644 --- a/include/linux/sunrpc/gss_err.h +++ b/include/linux/sunrpc/gss_err.h @@ -65,16 +65,6 @@ typedef unsigned int OM_uint32; #define GSS_C_MECH_CODE 2 -/* - * Define the default Quality of Protection for per-message services. Note - * that an implementation that offers multiple levels of QOP may either reserve - * a value (for example zero, as assumed here) to mean "default protection", or - * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit - * QOP value. However a value of 0 should always be interpreted by a GSSAPI - * implementation as a request for the default protection level. - */ -#define GSS_C_QOP_DEFAULT 0 - /* * Expiration time of 2^32-1 seconds means infinite lifetime for a * credential or security context diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 7f93c2d5ebdb..a7bda4edb853 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -119,21 +119,21 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, int body_offset, struct xdr_netobj *cksum); u32 -krb5_make_token(struct krb5_ctx *context_handle, int qop_req, +krb5_make_token(struct krb5_ctx *context_handle, struct xdr_buf *input_message_buffer, struct xdr_netobj *output_message_buffer); u32 krb5_read_token(struct krb5_ctx *context_handle, struct xdr_netobj *input_token_buffer, - struct xdr_buf *message_buffer, int *qop_state); + struct xdr_buf *message_buffer); u32 -gss_wrap_kerberos(struct gss_ctx *ctx_id, u32 qop, int offset, +gss_wrap_kerberos(struct gss_ctx *ctx_id, int offset, struct xdr_buf *outbuf, struct page **pages); u32 -gss_unwrap_kerberos(struct gss_ctx *ctx_id, u32 *qop, int offset, +gss_unwrap_kerberos(struct gss_ctx *ctx_id, int offset, struct xdr_buf *buf); diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h index b5c9968c3c17..0beb2cf00a84 100644 --- a/include/linux/sunrpc/gss_spkm3.h +++ b/include/linux/sunrpc/gss_spkm3.h @@ -41,9 +41,9 @@ struct spkm3_ctx { #define SPKM_WRAP_TOK 5 #define SPKM_DEL_TOK 6 -u32 spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, struct xdr_buf * text, struct xdr_netobj * token, int toktype); +u32 spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_netobj * token, int toktype); -u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int *qop_state, int toktype); +u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype); #define CKSUMTYPE_RSA_MD5 0x0007 diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5e4872058ec7..f44f46f1d8e0 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -854,9 +854,7 @@ gss_marshal(struct rpc_task *task, u32 *p) *p++ = htonl(RPC_AUTH_GSS); mic.data = (u8 *)(p + 1); - maj_stat = gss_get_mic(ctx->gc_gss_ctx, - GSS_C_QOP_DEFAULT, - &verf_buf, &mic); + maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); if (maj_stat == GSS_S_CONTEXT_EXPIRED) { cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; } else if (maj_stat != 0) { @@ -888,7 +886,7 @@ gss_validate(struct rpc_task *task, u32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 seq, qop_state; + u32 seq; struct kvec iov; struct xdr_buf verf_buf; struct xdr_netobj mic; @@ -909,7 +907,7 @@ gss_validate(struct rpc_task *task, u32 *p) mic.data = (u8 *)p; mic.len = len; - maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state); + maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); if (maj_stat == GSS_S_CONTEXT_EXPIRED) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; if (maj_stat) @@ -961,8 +959,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, p = iov->iov_base + iov->iov_len; mic.data = (u8 *)(p + 1); - maj_stat = gss_get_mic(ctx->gc_gss_ctx, - GSS_C_QOP_DEFAULT, &integ_buf, &mic); + maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic); status = -EIO; /* XXX? */ if (maj_stat == GSS_S_CONTEXT_EXPIRED) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; @@ -1057,8 +1054,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); snd_buf->tail[0].iov_base = tmp; } - maj_stat = gss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, offset, - snd_buf, inpages); + maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages); /* RPC_SLACK_SPACE should prevent this ever happening: */ BUG_ON(snd_buf->len > snd_buf->buflen); status = -EIO; @@ -1150,8 +1146,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) return status; - maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, - &mic, NULL); + maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); if (maj_stat == GSS_S_CONTEXT_EXPIRED) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; if (maj_stat != GSS_S_COMPLETE) @@ -1176,8 +1171,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, /* remove padding: */ rcv_buf->len = offset + opaque_len; - maj_stat = gss_unwrap(ctx->gc_gss_ctx, NULL, - offset, rcv_buf); + maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); if (maj_stat == GSS_S_CONTEXT_EXPIRED) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; if (maj_stat != GSS_S_COMPLETE) diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 37a9ad97ccd4..9ffac2c50b94 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -193,15 +193,12 @@ gss_delete_sec_context_kerberos(void *internal_ctx) { static u32 gss_verify_mic_kerberos(struct gss_ctx *ctx, struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate) { + struct xdr_netobj *mic_token) +{ u32 maj_stat = 0; - int qop_state; struct krb5_ctx *kctx = ctx->internal_ctx_id; - maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state); - if (!maj_stat && qop_state) - *qstate = qop_state; + maj_stat = krb5_read_token(kctx, mic_token, message); dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat); return maj_stat; @@ -209,13 +206,12 @@ gss_verify_mic_kerberos(struct gss_ctx *ctx, static u32 gss_get_mic_kerberos(struct gss_ctx *ctx, - u32 qop, struct xdr_buf *message, struct xdr_netobj *mic_token) { u32 err = 0; struct krb5_ctx *kctx = ctx->internal_ctx_id; - err = krb5_make_token(kctx, qop, message, mic_token); + err = krb5_make_token(kctx, message, mic_token); dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index fb852d9ab06f..15227c727c8b 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -71,7 +71,7 @@ #endif u32 -krb5_make_token(struct krb5_ctx *ctx, int qop_req, +krb5_make_token(struct krb5_ctx *ctx, struct xdr_buf *text, struct xdr_netobj *token) { s32 checksum_type; @@ -83,9 +83,6 @@ krb5_make_token(struct krb5_ctx *ctx, int qop_req, now = get_seconds(); - if (qop_req != 0) - goto out_err; - switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: checksum_type = CKSUMTYPE_RSA_MD5; diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index c3d6d1bc100c..bcf978627a71 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -74,7 +74,7 @@ u32 krb5_read_token(struct krb5_ctx *ctx, struct xdr_netobj *read_token, - struct xdr_buf *message_buffer, int *qop_state) + struct xdr_buf *message_buffer) { int signalg; int sealalg; @@ -157,9 +157,6 @@ krb5_read_token(struct krb5_ctx *ctx, /* it got through unscathed. Make sure the context is unexpired */ - if (qop_state) - *qop_state = GSS_C_QOP_DEFAULT; - now = get_seconds(); ret = GSS_S_CONTEXT_EXPIRED; diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index ddcde6e42b23..af777cf9f251 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -116,7 +116,7 @@ make_confounder(char *p, int blocksize) /* XXX factor out common code with seal/unseal. */ u32 -gss_wrap_kerberos(struct gss_ctx *ctx, u32 qop, int offset, +gss_wrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf, struct page **pages) { struct krb5_ctx *kctx = ctx->internal_ctx_id; @@ -132,9 +132,6 @@ gss_wrap_kerberos(struct gss_ctx *ctx, u32 qop, int offset, now = get_seconds(); - if (qop != 0) - goto out_err; - switch (kctx->signalg) { case SGN_ALG_DES_MAC_MD5: checksum_type = CKSUMTYPE_RSA_MD5; @@ -229,8 +226,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, u32 qop, int offset, } u32 -gss_unwrap_kerberos(struct gss_ctx *ctx, u32 *qop, int offset, - struct xdr_buf *buf) +gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) { struct krb5_ctx *kctx = ctx->internal_ctx_id; int signalg; @@ -328,9 +324,6 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, u32 *qop, int offset, /* it got through unscathed. Make sure the context is unexpired */ - if (qop) - *qop = GSS_C_QOP_DEFAULT; - now = get_seconds(); ret = GSS_S_CONTEXT_EXPIRED; diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 06d97cb3481a..b048bf672da2 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -250,13 +250,11 @@ gss_import_sec_context(const void *input_token, size_t bufsize, u32 gss_get_mic(struct gss_ctx *context_handle, - u32 qop, struct xdr_buf *message, struct xdr_netobj *mic_token) { return context_handle->mech_type->gm_ops ->gss_get_mic(context_handle, - qop, message, mic_token); } @@ -266,35 +264,31 @@ gss_get_mic(struct gss_ctx *context_handle, u32 gss_verify_mic(struct gss_ctx *context_handle, struct xdr_buf *message, - struct xdr_netobj *mic_token, - u32 *qstate) + struct xdr_netobj *mic_token) { return context_handle->mech_type->gm_ops ->gss_verify_mic(context_handle, message, - mic_token, - qstate); + mic_token); } u32 gss_wrap(struct gss_ctx *ctx_id, - u32 qop, int offset, struct xdr_buf *buf, struct page **inpages) { return ctx_id->mech_type->gm_ops - ->gss_wrap(ctx_id, qop, offset, buf, inpages); + ->gss_wrap(ctx_id, offset, buf, inpages); } u32 gss_unwrap(struct gss_ctx *ctx_id, - u32 *qop, int offset, struct xdr_buf *buf) { return ctx_id->mech_type->gm_ops - ->gss_unwrap(ctx_id, qop, offset, buf); + ->gss_unwrap(ctx_id, offset, buf); } diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index 6c97d61baa9b..39b3edc14694 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -224,18 +224,13 @@ gss_delete_sec_context_spkm3(void *internal_ctx) { static u32 gss_verify_mic_spkm3(struct gss_ctx *ctx, struct xdr_buf *signbuf, - struct xdr_netobj *checksum, - u32 *qstate) { + struct xdr_netobj *checksum) +{ u32 maj_stat = 0; - int qop_state = 0; struct spkm3_ctx *sctx = ctx->internal_ctx_id; dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n"); - maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state, - SPKM_MIC_TOK); - - if (!maj_stat && qop_state) - *qstate = qop_state; + maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK); dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); return maj_stat; @@ -243,15 +238,15 @@ gss_verify_mic_spkm3(struct gss_ctx *ctx, static u32 gss_get_mic_spkm3(struct gss_ctx *ctx, - u32 qop, struct xdr_buf *message_buffer, - struct xdr_netobj *message_token) { + struct xdr_netobj *message_token) +{ u32 err = 0; struct spkm3_ctx *sctx = ctx->internal_ctx_id; dprintk("RPC: gss_get_mic_spkm3\n"); - err = spkm3_make_token(sctx, qop, message_buffer, + err = spkm3_make_token(sctx, message_buffer, message_token, SPKM_MIC_TOK); return err; } @@ -264,8 +259,8 @@ static struct gss_api_ops gss_spkm3_ops = { }; static struct pf_desc gss_spkm3_pfs[] = { - {RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"}, - {RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"}, + {RPC_AUTH_GSS_SPKM, RPC_GSS_SVC_NONE, "spkm3"}, + {RPC_AUTH_GSS_SPKMI, RPC_GSS_SVC_INTEGRITY, "spkm3i"}, }; static struct gss_api_mech gss_spkm3_mech = { diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c index 25339868d462..148201e929d0 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_seal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c @@ -51,7 +51,7 @@ */ u32 -spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, +spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_netobj * token, int toktype) { @@ -68,8 +68,6 @@ spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, dprintk("RPC: spkm3_make_token\n"); now = jiffies; - if (qop_req != 0) - goto out_err; if (ctx->ctx_id.len != 16) { dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index 65ce81bf0bc4..c3c0d9586103 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c @@ -52,7 +52,7 @@ u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, /* checksum */ struct xdr_buf *message_buffer, /* signbuf */ - int *qop_state, int toktype) + int toktype) { s32 code; struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index e3308195374e..e4ada15ed856 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -566,8 +566,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, if (rqstp->rq_deferred) /* skip verification of revisited request */ return SVC_OK; - if (gss_verify_mic(ctx_id, &rpchdr, &checksum, NULL) - != GSS_S_COMPLETE) { + if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) { *authp = rpcsec_gsserr_credproblem; return SVC_DENIED; } @@ -604,7 +603,7 @@ gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq) xdr_buf_from_iov(&iov, &verf_data); p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len; mic.data = (u8 *)(p + 1); - maj_stat = gss_get_mic(ctx_id, 0, &verf_data, &mic); + maj_stat = gss_get_mic(ctx_id, &verf_data, &mic); if (maj_stat != GSS_S_COMPLETE) return -1; *p++ = htonl(mic.len); @@ -710,7 +709,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx) goto out; if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len)) goto out; - maj_stat = gss_verify_mic(ctx, &integ_buf, &mic, NULL); + maj_stat = gss_verify_mic(ctx, &integ_buf, &mic); if (maj_stat != GSS_S_COMPLETE) goto out; if (ntohl(svc_getu32(&buf->head[0])) != seq) @@ -1012,7 +1011,7 @@ svcauth_gss_release(struct svc_rqst *rqstp) resv = &resbuf->tail[0]; } mic.data = (u8 *)resv->iov_base + resv->iov_len + 4; - if (gss_get_mic(gsd->rsci->mechctx, 0, &integ_buf, &mic)) + if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic)) goto out_err; svc_putu32(resv, htonl(mic.len)); memset(mic.data + mic.len, 0, From a0857d03b21fa54653c9d2fe7a315381176015b4 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2005 16:55:23 -0400 Subject: [PATCH 0500/1939] RPCSEC_GSS: krb5 cleanup Remove some senseless wrappers. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 12 ++++-------- net/sunrpc/auth_gss/gss_krb5_mech.c | 28 --------------------------- net/sunrpc/auth_gss/gss_krb5_seal.c | 5 +++-- net/sunrpc/auth_gss/gss_krb5_unseal.c | 6 +++--- 4 files changed, 10 insertions(+), 41 deletions(-) diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index a7bda4edb853..2c3601d31045 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -118,15 +118,11 @@ s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, int body_offset, struct xdr_netobj *cksum); -u32 -krb5_make_token(struct krb5_ctx *context_handle, - struct xdr_buf *input_message_buffer, - struct xdr_netobj *output_message_buffer); +u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, + struct xdr_netobj *); -u32 -krb5_read_token(struct krb5_ctx *context_handle, - struct xdr_netobj *input_token_buffer, - struct xdr_buf *message_buffer); +u32 gss_verify_mic_kerberos(struct gss_ctx *, struct xdr_buf *, + struct xdr_netobj *); u32 gss_wrap_kerberos(struct gss_ctx *ctx_id, int offset, diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 9ffac2c50b94..5f1f806a0b11 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -190,34 +190,6 @@ gss_delete_sec_context_kerberos(void *internal_ctx) { kfree(kctx); } -static u32 -gss_verify_mic_kerberos(struct gss_ctx *ctx, - struct xdr_buf *message, - struct xdr_netobj *mic_token) -{ - u32 maj_stat = 0; - struct krb5_ctx *kctx = ctx->internal_ctx_id; - - maj_stat = krb5_read_token(kctx, mic_token, message); - - dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat); - return maj_stat; -} - -static u32 -gss_get_mic_kerberos(struct gss_ctx *ctx, - struct xdr_buf *message, - struct xdr_netobj *mic_token) { - u32 err = 0; - struct krb5_ctx *kctx = ctx->internal_ctx_id; - - err = krb5_make_token(kctx, message, mic_token); - - dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); - - return err; -} - static struct gss_api_ops gss_kerberos_ops = { .gss_import_sec_context = gss_import_sec_context_kerberos, .gss_get_mic = gss_get_mic_kerberos, diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 15227c727c8b..13f8ae979454 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -71,9 +71,10 @@ #endif u32 -krb5_make_token(struct krb5_ctx *ctx, - struct xdr_buf *text, struct xdr_netobj *token) +gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, + struct xdr_netobj *token) { + struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; s32 checksum_type; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; unsigned char *ptr, *krb5_hdr, *msg_start; diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index bcf978627a71..2030475d98ed 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -72,10 +72,10 @@ * supposedly taken over. */ u32 -krb5_read_token(struct krb5_ctx *ctx, - struct xdr_netobj *read_token, - struct xdr_buf *message_buffer) +gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, + struct xdr_buf *message_buffer, struct xdr_netobj *read_token) { + struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; int signalg; int sealalg; s32 checksum_type; From 7d0ffdb279105d9a87b447758ce4a634496abfd1 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Wed, 19 Oct 2005 12:21:19 +0100 Subject: [PATCH 0501/1939] NTFS: $EA attributes can be both resident non-resident. Minor tidying. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 1 + fs/ntfs/aops.c | 5 ++--- fs/ntfs/attrib.c | 2 +- fs/ntfs/file.c | 14 ++++++++++++++ fs/ntfs/layout.h | 27 +++++++++++++++++---------- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 03015c7b236c..bc6ec16ad1f8 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -75,6 +75,7 @@ ToDo/Notes: for highly fragmented files, i.e. ones whose data attribute is split across multiple extents. When such a case is encountered, EOPNOTSUPP is returned. + - $EA attributes can be both resident non-resident. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 8f23c60030c0..1c0a4315876a 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -1391,8 +1391,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) if (NInoEncrypted(ni)) { unlock_page(page); BUG_ON(ni->type != AT_DATA); - ntfs_debug("Denying write access to encrypted " - "file."); + ntfs_debug("Denying write access to encrypted file."); return -EACCES; } /* Compressed data streams are handled in compress.c. */ @@ -1508,8 +1507,8 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) /* Zero out of bounds area in the page cache page. */ memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); kunmap_atomic(kaddr, KM_USER0); - flush_dcache_mft_record_page(ctx->ntfs_ino); flush_dcache_page(page); + flush_dcache_mft_record_page(ctx->ntfs_ino); /* We are done with the page. */ end_page_writeback(page); /* Finally, mark the mft record dirty, so it gets written back. */ diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 338e47144fc9..df2e2091f936 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1411,7 +1411,7 @@ int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type) */ int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type) { - if (type == AT_INDEX_ALLOCATION || type == AT_EA) + if (type == AT_INDEX_ALLOCATION) return -EPERM; return 0; } diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index cf2a0e2330df..5fb341a16b52 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1857,10 +1857,24 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, if (ni->type != AT_INDEX_ALLOCATION) { /* If file is encrypted, deny access, just like NT4. */ if (NInoEncrypted(ni)) { + /* + * Reminder for later: Encrypted files are _always_ + * non-resident so that the content can always be + * encrypted. + */ ntfs_debug("Denying write access to encrypted file."); return -EACCES; } if (NInoCompressed(ni)) { + /* Only unnamed $DATA attribute can be compressed. */ + BUG_ON(ni->type != AT_DATA); + BUG_ON(ni->name_len); + /* + * Reminder for later: If resident, the data is not + * actually compressed. Only on the switch to non- + * resident does compression kick in. This is in + * contrast to encrypted files (see above). + */ ntfs_error(vi->i_sb, "Writing to compressed files is " "not implemented yet. Sorry."); return -EOPNOTSUPP; diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 5c248d404f05..71b25dab8199 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -1021,10 +1021,17 @@ enum { FILE_NAME_POSIX = 0x00, /* This is the largest namespace. It is case sensitive and allows all Unicode characters except for: '\0' and '/'. Beware that in - WinNT/2k files which eg have the same name except for their case - will not be distinguished by the standard utilities and thus a "del - filename" will delete both "filename" and "fileName" without - warning. */ + WinNT/2k/2003 by default files which eg have the same name except + for their case will not be distinguished by the standard utilities + and thus a "del filename" will delete both "filename" and "fileName" + without warning. However if for example Services For Unix (SFU) are + installed and the case sensitive option was enabled at installation + time, then you can create/access/delete such files. + Note that even SFU places restrictions on the filenames beyond the + '\0' and '/' and in particular the following set of characters is + not allowed: '"', '/', '<', '>', '\'. All other characters, + including the ones no allowed in WIN32 namespace are allowed. + Tested with SFU 3.5 (this is now free) running on Windows XP. */ FILE_NAME_WIN32 = 0x01, /* The standard WinNT/2k NTFS long filenames. Case insensitive. All Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\', @@ -2375,20 +2382,20 @@ typedef u8 EA_FLAGS; /* * Attribute: Extended attribute (EA) (0xe0). * - * NOTE: Always non-resident. (Is this true?) + * NOTE: Can be resident or non-resident. * * Like the attribute list and the index buffer list, the EA attribute value is * a sequence of EA_ATTR variable length records. - * - * FIXME: It appears weird that the EA name is not unicode. Is it true? */ typedef struct { le32 next_entry_offset; /* Offset to the next EA_ATTR. */ EA_FLAGS flags; /* Flags describing the EA. */ - u8 ea_name_length; /* Length of the name of the EA in bytes. */ + u8 ea_name_length; /* Length of the name of the EA in bytes + excluding the '\0' byte terminator. */ le16 ea_value_length; /* Byte size of the EA's value. */ - u8 ea_name[0]; /* Name of the EA. */ - u8 ea_value[0]; /* The value of the EA. Immediately follows + u8 ea_name[0]; /* Name of the EA. Note this is ASCII, not + Unicode and it is zero terminated. */ + u8 ea_value[0]; /* The value of the EA. Immediately follows the name. */ } __attribute__ ((__packed__)) EA_ATTR; From d5aeaef37dc9cb009ab5cb8abf325338d21d2b1a Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Wed, 19 Oct 2005 12:23:10 +0100 Subject: [PATCH 0502/1939] NTFS: Fix serious data corruption issue when writing. Many thanks to Alberto Patino for testing and reporting the data corruption. And many apologies for corrupting his partition. Signed-off-by: Anton Altaparmakov --- fs/ntfs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 5fb341a16b52..a142bf3ba1a5 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -787,6 +787,7 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, vcn_len = rl[1].vcn - vcn; lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits); + cdelta = 0; /* * If the number of remaining clusters in the * @pages is smaller or equal to the number of From 7ed476d17f04473f70d796cb6c172bdcfcc9b8e5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 19 Oct 2005 21:44:51 +1000 Subject: [PATCH 0503/1939] ppc: Minor smp changes for consistency with ppc64 This makes platform code use the smp_ops variable directly instead of ppc_md.smp_ops, removes the two unused `data' and `wait' arguments from the *_message_pass() functions, and removes the call to the never-implemented smp_ops->space_timers() function. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/setup.c | 4 ++-- arch/powerpc/platforms/powermac/smp.c | 5 ++--- arch/ppc/kernel/smp.c | 20 ++++++++------------ arch/ppc/platforms/chrp_setup.c | 2 +- arch/ppc/platforms/gemini_setup.c | 2 +- arch/ppc/platforms/hdpu.c | 4 ++-- arch/ppc/platforms/pmac_setup.c | 4 ++-- arch/ppc/platforms/pmac_smp.c | 3 +-- arch/ppc/platforms/pplus.c | 2 +- arch/ppc/platforms/prep_setup.c | 2 +- arch/ppc/syslib/open_pic.c | 2 +- 11 files changed, 22 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 9416fcaa6daa..7eb0c34b6994 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -312,9 +312,9 @@ pmac_setup_arch(void) #ifdef CONFIG_SMP /* Check for Core99 */ if (find_devices("uni-n") || find_devices("u3")) - ppc_md.smp_ops = &core99_smp_ops; + smp_ops = &core99_smp_ops; else - ppc_md.smp_ops = &psurge_smp_ops; + smp_ops = &psurge_smp_ops; #endif /* CONFIG_SMP */ pci_create_OF_bus_map(); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index fb996336c58b..ccaa0534d60f 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -209,8 +209,7 @@ irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs) return IRQ_HANDLED; } -static void smp_psurge_message_pass(int target, int msg, unsigned long data, - int wait) +static void smp_psurge_message_pass(int target, int msg) { int i; @@ -627,7 +626,7 @@ void smp_core99_give_timebase(void) local_irq_restore(flags); } -void smp_core99_message_pass(int target, int msg, unsigned long data, int wait) +void smp_core99_message_pass(int target, int msg) { cpumask_t mask = CPU_MASK_ALL; /* make sure we're sending something that translates to an IPI */ diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 801c793fdec8..bc5bf1124836 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -51,7 +51,7 @@ EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_possible_map); /* SMP operations for this machine */ -static struct smp_ops_t *smp_ops; +struct smp_ops_t *smp_ops; /* all cpu mappings are 1-1 -- Cort */ volatile unsigned long cpu_callin_map[NR_CPUS]; @@ -74,11 +74,11 @@ extern void __save_cpu_setup(void); #define PPC_MSG_XMON_BREAK 3 static inline void -smp_message_pass(int target, int msg, unsigned long data, int wait) +smp_message_pass(int target, int msg) { - if (smp_ops){ + if (smp_ops) { atomic_inc(&ipi_sent); - smp_ops->message_pass(target,msg,data,wait); + smp_ops->message_pass(target, msg); } } @@ -119,7 +119,7 @@ void smp_message_recv(int msg, struct pt_regs *regs) void smp_send_tlb_invalidate(int cpu) { if ( PVR_VER(mfspr(SPRN_PVR)) == 8 ) - smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0); + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB); } void smp_send_reschedule(int cpu) @@ -135,13 +135,13 @@ void smp_send_reschedule(int cpu) */ /* This is only used if `cpu' is running an idle task, so it will reschedule itself anyway... */ - smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); + smp_message_pass(cpu, PPC_MSG_RESCHEDULE); } #ifdef CONFIG_XMON void smp_send_xmon_break(int cpu) { - smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0); + smp_message_pass(cpu, PPC_MSG_XMON_BREAK); } #endif /* CONFIG_XMON */ @@ -224,7 +224,7 @@ static int __smp_call_function(void (*func) (void *info), void *info, spin_lock(&call_lock); call_data = &data; /* Send a message to all other CPUs and wait for them to respond */ - smp_message_pass(target, PPC_MSG_CALL_FUNCTION, 0, 0); + smp_message_pass(target, PPC_MSG_CALL_FUNCTION); /* Wait for response */ timeout = 1000000; @@ -294,7 +294,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp_store_cpu_info(smp_processor_id()); cpu_callin_map[smp_processor_id()] = 1; - smp_ops = ppc_md.smp_ops; if (smp_ops == NULL) { printk("SMP not supported on this machine.\n"); return; @@ -308,9 +307,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* Backup CPU 0 state */ __save_cpu_setup(); - if (smp_ops->space_timers) - smp_ops->space_timers(num_cpus); - for_each_cpu(cpu) { if (cpu == smp_processor_id()) continue; diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index 8c874e957a4b..56c53bb3dfd4 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -553,7 +553,7 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_SMP - ppc_md.smp_ops = &chrp_smp_ops; + smp_ops = &chrp_smp_ops; #endif /* CONFIG_SMP */ /* diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c index ec6aa04d001e..729897c59033 100644 --- a/arch/ppc/platforms/gemini_setup.c +++ b/arch/ppc/platforms/gemini_setup.c @@ -575,6 +575,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; #ifdef CONFIG_SMP - ppc_md.smp_ops = &gemini_smp_ops; + smp_ops = &gemini_smp_ops; #endif /* CONFIG_SMP */ } diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c index ff3796860123..2cc12b04584a 100644 --- a/arch/ppc/platforms/hdpu.c +++ b/arch/ppc/platforms/hdpu.c @@ -753,7 +753,7 @@ static int smp_hdpu_probe(void) } static void -smp_hdpu_message_pass(int target, int msg, unsigned long data, int wait) +smp_hdpu_message_pass(int target, int msg) { if (msg > 0x3) { printk("SMP %d: smp_message_pass: unknown msg %d\n", @@ -949,7 +949,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif /* CONFIG_SERIAL_TEXT_DEBUG */ #ifdef CONFIG_SMP - ppc_md.smp_ops = &hdpu_smp_ops; + smp_ops = &hdpu_smp_ops; #endif /* CONFIG_SMP */ #if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index 74165684552a..55d2beffe560 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -330,9 +330,9 @@ pmac_setup_arch(void) #ifdef CONFIG_SMP /* Check for Core99 */ if (find_devices("uni-n") || find_devices("u3")) - ppc_md.smp_ops = &core99_smp_ops; + smp_ops = &core99_smp_ops; else - ppc_md.smp_ops = &psurge_smp_ops; + smp_ops = &psurge_smp_ops; #endif /* CONFIG_SMP */ pci_create_OF_bus_map(); diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index e613f0e0d9eb..26ff26238f03 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -209,8 +209,7 @@ irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs) return IRQ_HANDLED; } -static void smp_psurge_message_pass(int target, int msg, unsigned long data, - int wait) +static void smp_psurge_message_pass(int target, int msg) { int i; diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c index c8803214405d..59eb330b2090 100644 --- a/arch/ppc/platforms/pplus.c +++ b/arch/ppc/platforms/pplus.c @@ -903,6 +903,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; #endif #ifdef CONFIG_SMP - ppc_md.smp_ops = &pplus_smp_ops; + smp_ops = &pplus_smp_ops; #endif /* CONFIG_SMP */ } diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 490ff175c902..9e5637e5f5a9 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -1160,6 +1160,6 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_SMP - ppc_md.smp_ops = &prep_smp_ops; + smp_ops = &prep_smp_ops; #endif /* CONFIG_SMP */ } diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 361f113260d7..894779712b46 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -890,7 +890,7 @@ openpic_get_irq(struct pt_regs *regs) #ifdef CONFIG_SMP void -smp_openpic_message_pass(int target, int msg, unsigned long data, int wait) +smp_openpic_message_pass(int target, int msg) { cpumask_t mask = CPU_MASK_ALL; /* make sure we're sending something that translates to an IPI */ From 143a1dec7e04e0a9712ff93e779aabfb21dfd97c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 19 Oct 2005 23:11:21 +1000 Subject: [PATCH 0504/1939] powerpc: Merge machdep.h A few things change for consistency between ppc32 and ppc64: idle functions return void; *_get_boot_time functions return unsigned long (i.e. time_t) rather than filling in a struct rtc_time (since that's useful to the callers and easier for pmac to generate); *_get_rtc_time and *_set_rtc_time functions take a struct rtc_time; irq_canonicalize is gone; nvram_sync returns void. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/mf.c | 14 ++- arch/powerpc/platforms/iseries/setup.c | 12 +- arch/powerpc/platforms/iseries/setup.h | 2 +- arch/powerpc/platforms/powermac/pmac.h | 7 +- arch/powerpc/platforms/powermac/setup.c | 2 +- arch/powerpc/platforms/powermac/time.c | 24 +++- arch/powerpc/platforms/pseries/setup.c | 12 +- arch/ppc64/kernel/idle.c | 8 +- arch/ppc64/kernel/maple_setup.c | 2 +- arch/ppc64/kernel/maple_time.c | 7 +- arch/ppc64/kernel/pmac.h | 2 +- arch/ppc64/kernel/pmac_nvram.c | 4 +- arch/ppc64/kernel/pmac_time.c | 21 +--- arch/ppc64/kernel/rtas-proc.c | 1 + arch/ppc64/kernel/rtc.c | 11 +- include/{asm-ppc64 => asm-powerpc}/machdep.h | 121 +++++++++++++++++-- include/asm-powerpc/rtas.h | 2 +- 17 files changed, 177 insertions(+), 75 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/machdep.h (59%) diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 3f25f7fc79fc..e5de31aa0015 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -1307,11 +1308,14 @@ int iSeries_set_rtc_time(struct rtc_time *tm) return 0; } -void iSeries_get_boot_time(struct rtc_time *tm) +unsigned long iSeries_get_boot_time(void) { - if (piranha_simulator) - return; + struct rtc_time tm; - mf_get_boot_rtc(tm); - tm->tm_mon -= 1; + if (piranha_simulator) + return 0; + + mf_get_boot_rtc(&tm); + return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 93852c2ee5de..41cd5b689545 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -73,8 +73,8 @@ extern void hvlog(char *fmt, ...); extern void ppcdbg_initialize(void); static void build_iSeries_Memory_Map(void); -static int iseries_shared_idle(void); -static int iseries_dedicated_idle(void); +static void iseries_shared_idle(void); +static void iseries_dedicated_idle(void); #ifdef CONFIG_PCI extern void iSeries_pci_final_fixup(void); #else @@ -693,7 +693,7 @@ static void yield_shared_processor(void) process_iSeries_events(); } -static int iseries_shared_idle(void) +static void iseries_shared_idle(void) { while (1) { while (!need_resched() && !hvlpevent_is_pending()) { @@ -715,11 +715,9 @@ static int iseries_shared_idle(void) schedule(); } - - return 0; } -static int iseries_dedicated_idle(void) +static void iseries_dedicated_idle(void) { long oldval; @@ -749,8 +747,6 @@ static int iseries_dedicated_idle(void) ppc64_runlatch_on(); schedule(); } - - return 0; } #ifndef CONFIG_PCI diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h index 6da89ae991ce..5213044ec411 100644 --- a/arch/powerpc/platforms/iseries/setup.h +++ b/arch/powerpc/platforms/iseries/setup.h @@ -17,7 +17,7 @@ #ifndef __ISERIES_SETUP_H__ #define __ISERIES_SETUP_H__ -extern void iSeries_get_boot_time(struct rtc_time *tm); +extern unsigned long iSeries_get_boot_time(void); extern int iSeries_set_rtc_time(struct rtc_time *tm); extern void iSeries_get_rtc_time(struct rtc_time *tm); diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 81f52512b046..0a9ba704865e 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -10,9 +10,12 @@ * pmac_* files. Mostly for use by pmac_setup */ +struct rtc_time; + extern long pmac_time_init(void); -extern unsigned long pmac_get_rtc_time(void); -extern int pmac_set_rtc_time(unsigned long nowtime); +extern unsigned long pmac_get_boot_time(void); +extern void pmac_get_rtc_time(struct rtc_time *); +extern int pmac_set_rtc_time(struct rtc_time *); extern void pmac_read_rtc_time(void); extern void pmac_calibrate_decr(void); extern void pmac_pcibios_fixup(void); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 7eb0c34b6994..b6414e7c37d4 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -562,7 +562,6 @@ void __init pmac_init(void) ppc_md.setup_arch = pmac_setup_arch; ppc_md.show_cpuinfo = pmac_show_cpuinfo; ppc_md.show_percpuinfo = pmac_show_percpuinfo; - ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = pmac_pic_init; ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ @@ -578,6 +577,7 @@ void __init pmac_init(void) ppc_md.time_init = pmac_time_init; ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; + ppc_md.get_boot_time = pmac_get_boot_time; ppc_md.calibrate_decr = pmac_calibrate_decr; ppc_md.feature_call = pmac_do_feature_call; diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index edb9fcc64790..3ee6d8aa14c4 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -77,8 +77,7 @@ pmac_time_init(void) #endif } -unsigned long -pmac_get_rtc_time(void) +unsigned long pmac_get_boot_time(void) { #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; @@ -118,20 +117,33 @@ pmac_get_rtc_time(void) return 0; } -int -pmac_set_rtc_time(unsigned long nowtime) +void pmac_get_rtc_time(struct rtc_time *tm) { + unsigned long now; + + now = pmac_get_boot_time(); + to_tm(now, tm); + tm->tm_year -= 1900; + tm->tm_mon -= 1; /* month is 0-based */ +} + +int pmac_set_rtc_time(struct rtc_time *tm) +{ + unsigned long nowtime; #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; #endif + nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); nowtime += RTC_OFFSET; switch (sys_ctrler) { #ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, - nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) + nowtime >> 24, nowtime >> 16, nowtime >> 8, + nowtime) < 0) return 0; while (!req.complete) cuda_poll(); @@ -221,7 +233,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) case PBOOK_SLEEP_NOW: do { seq = read_seqbegin_irqsave(&xtime_lock, flags); - time_diff = xtime.tv_sec - pmac_get_rtc_time(); + time_diff = xtime.tv_sec - pmac_get_boot_time(); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); break; case PBOOK_WAKE: diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index eb25ee2eead8..0c84a44b43b4 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -84,8 +84,8 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ extern void pSeries_system_reset_exception(struct pt_regs *regs); extern int pSeries_machine_check_exception(struct pt_regs *regs); -static int pseries_shared_idle(void); -static int pseries_dedicated_idle(void); +static void pseries_shared_idle(void); +static void pseries_dedicated_idle(void); static volatile void __iomem * chrp_int_ack_special; struct mpic *pSeries_mpic; @@ -488,8 +488,8 @@ static inline void dedicated_idle_sleep(unsigned int cpu) } } -static int pseries_dedicated_idle(void) -{ +static void pseries_dedicated_idle(void) +{ long oldval; struct paca_struct *lpaca = get_paca(); unsigned int cpu = smp_processor_id(); @@ -544,7 +544,7 @@ static int pseries_dedicated_idle(void) } } -static int pseries_shared_idle(void) +static void pseries_shared_idle(void) { struct paca_struct *lpaca = get_paca(); unsigned int cpu = smp_processor_id(); @@ -586,8 +586,6 @@ static int pseries_shared_idle(void) if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } - - return 0; } static int pSeries_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 954395d42636..8abd2ad92832 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -31,7 +31,7 @@ extern void power4_idle(void); -int default_idle(void) +void default_idle(void) { long oldval; unsigned int cpu = smp_processor_id(); @@ -64,11 +64,9 @@ int default_idle(void) if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } - - return 0; } -int native_idle(void) +void native_idle(void) { while (1) { ppc64_runlatch_off(); @@ -85,8 +83,6 @@ int native_idle(void) system_state == SYSTEM_RUNNING) cpu_die(); } - - return 0; } void cpu_idle(void) diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index 22987675f544..a107ed69a355 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c @@ -70,7 +70,7 @@ extern int maple_set_rtc_time(struct rtc_time *tm); extern void maple_get_rtc_time(struct rtc_time *tm); -extern void maple_get_boot_time(struct rtc_time *tm); +extern unsigned long maple_get_boot_time(void); extern void maple_calibrate_decr(void); extern void maple_pci_init(void); extern void maple_pcibios_fixup(void); diff --git a/arch/ppc64/kernel/maple_time.c b/arch/ppc64/kernel/maple_time.c index d65210abcd03..cf5186335900 100644 --- a/arch/ppc64/kernel/maple_time.c +++ b/arch/ppc64/kernel/maple_time.c @@ -156,8 +156,9 @@ int maple_set_rtc_time(struct rtc_time *tm) return 0; } -void __init maple_get_boot_time(struct rtc_time *tm) +unsigned long __init maple_get_boot_time(void) { + struct rtc_time tm; struct device_node *rtcs; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); @@ -170,6 +171,8 @@ void __init maple_get_boot_time(struct rtc_time *tm) "legacy address (0x%x)\n", maple_rtc_addr); } - maple_get_rtc_time(tm); + maple_get_rtc_time(&tm); + return mktime(time->tm_year+1900, time->tm_mon+1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); } diff --git a/arch/ppc64/kernel/pmac.h b/arch/ppc64/kernel/pmac.h index 40e1c5030f74..fa59f2a5c722 100644 --- a/arch/ppc64/kernel/pmac.h +++ b/arch/ppc64/kernel/pmac.h @@ -9,7 +9,7 @@ * pmac_* files. Mostly for use by pmac_setup */ -extern void pmac_get_boot_time(struct rtc_time *tm); +extern unsigned long pmac_get_boot_time(void); extern void pmac_get_rtc_time(struct rtc_time *tm); extern int pmac_set_rtc_time(struct rtc_time *tm); extern void pmac_read_rtc_time(void); diff --git a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c index 11586d535f81..5fe9785ad7d8 100644 --- a/arch/ppc64/kernel/pmac_nvram.c +++ b/arch/ppc64/kernel/pmac_nvram.c @@ -341,7 +341,7 @@ static int amd_write_bank(int bank, u8* datas) } -static int core99_nvram_sync(void) +static void core99_nvram_sync(void) { struct core99_header* hdr99; unsigned long flags; @@ -369,8 +369,6 @@ static int core99_nvram_sync(void) printk("nvram: Error writing bank %d\n", core99_bank); bail: spin_unlock_irqrestore(&nv_lock, flags); - - return 0; } int __init pmac_nvram_init(void) diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index 9d8c97decd32..c89bfefbbecd 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -135,23 +136,13 @@ int pmac_set_rtc_time(struct rtc_time *tm) } } -void __init pmac_get_boot_time(struct rtc_time *tm) +unsigned long __init pmac_get_boot_time(void) { - pmac_get_rtc_time(tm); + struct rtc_time tm; -#ifdef disabled__CONFIG_NVRAM - s32 delta = 0; - int dst; - - delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; - delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; - delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); - if (delta & 0x00800000UL) - delta |= 0xFF000000UL; - dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); - printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, - dst ? "on" : "off"); -#endif + pmac_get_rtc_time(&tm); + return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); } /* diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c index 1f3ff860fdf0..5bdd5b079d96 100644 --- a/arch/ppc64/kernel/rtas-proc.c +++ b/arch/ppc64/kernel/rtas-proc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 88ae13f81c46..79e7ed2858dd 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -265,7 +265,7 @@ static int rtc_read_proc(char *page, char **start, off_t off, #ifdef CONFIG_PPC_RTAS #define MAX_RTC_WAIT 5000 /* 5 sec */ #define RTAS_CLOCK_BUSY (-2) -void rtas_get_boot_time(struct rtc_time *rtc_tm) +unsigned long rtas_get_boot_time(void) { int ret[8]; int error, wait_time; @@ -285,15 +285,10 @@ void rtas_get_boot_time(struct rtc_time *rtc_tm) if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", error); - return; + return 0; } - rtc_tm->tm_sec = ret[5]; - rtc_tm->tm_min = ret[4]; - rtc_tm->tm_hour = ret[3]; - rtc_tm->tm_mday = ret[2]; - rtc_tm->tm_mon = ret[1] - 1; - rtc_tm->tm_year = ret[0] - 1900; + return mktime(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]); } /* NOTE: get_rtc_time will get an error if executed in interrupt context diff --git a/include/asm-ppc64/machdep.h b/include/asm-powerpc/machdep.h similarity index 59% rename from include/asm-ppc64/machdep.h rename to include/asm-powerpc/machdep.h index d35d9d3e44cf..f060553b997a 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -1,6 +1,6 @@ -#ifdef __KERNEL__ #ifndef _PPC64_MACHDEP_H #define _PPC64_MACHDEP_H +#ifdef __KERNEL__ /* * This program is free software; you can redistribute it and/or @@ -16,6 +16,11 @@ #include +/* We export this macro for external modules like Alsa to know if + * ppc_md.feature_call is implemented or not + */ +#define CONFIG_PPC_HAS_FEATURE_CALLS + struct pt_regs; struct pci_bus; struct device_node; @@ -39,6 +44,7 @@ struct smp_ops_t { #endif struct machdep_calls { +#ifdef CONFIG_PPC64 void (*hpte_invalidate)(unsigned long slot, unsigned long va, int large, @@ -74,6 +80,7 @@ struct machdep_calls { void (*iommu_dev_setup)(struct pci_dev *dev); void (*iommu_bus_setup)(struct pci_bus *bus); void (*irq_bus_setup)(struct pci_bus *bus); +#endif int (*probe)(int platform); void (*setup_arch)(void); @@ -86,6 +93,7 @@ struct machdep_calls { void (*cpu_irq_down)(int secondary); /* PCI stuff */ + /* Called after scanning the bus, before allocating resources */ void (*pcibios_fixup)(void); int (*pci_probe_mode)(struct pci_bus *); @@ -95,9 +103,13 @@ struct machdep_calls { void (*panic)(char *str); void (*cpu_die)(void); + long (*time_init)(void); /* Optional, may be NULL */ + int (*set_rtc_time)(struct rtc_time *); void (*get_rtc_time)(struct rtc_time *); - void (*get_boot_time)(struct rtc_time *); + unsigned long (*get_boot_time)(void); + unsigned char (*rtc_read_val)(int addr); + void (*rtc_write_val)(int addr, unsigned char val); void (*calibrate_decr)(void); @@ -109,7 +121,7 @@ struct machdep_calls { ssize_t (*nvram_write)(char *buf, size_t count, loff_t *index); ssize_t (*nvram_read)(char *buf, size_t count, loff_t *index); ssize_t (*nvram_size)(void); - int (*nvram_sync)(void); + void (*nvram_sync)(void); /* Exception handlers */ void (*system_reset_exception)(struct pt_regs *regs); @@ -134,14 +146,100 @@ struct machdep_calls { pgprot_t vma_prot); /* Idle loop for this platform, leave empty for default idle loop */ - int (*idle_loop)(void); + void (*idle_loop)(void); - /* Function to enable pmcs for this platform, called once per cpu. */ + /* Function to enable performance monitor counters for this + platform, called once per cpu. */ void (*enable_pmcs)(void); + +#ifdef CONFIG_PPC32 /* XXX for now */ + /* Optional, may be NULL. */ + int (*show_cpuinfo)(struct seq_file *m); + int (*show_percpuinfo)(struct seq_file *m, int i); + + /* A general init function, called by ppc_init in init/main.c. + May be NULL. */ + void (*init)(void); + + void (*idle)(void); + void (*power_save)(void); + + void (*heartbeat)(void); + unsigned long heartbeat_reset; + unsigned long heartbeat_count; + + unsigned long (*find_end_of_memory)(void); + void (*setup_io_mappings)(void); + + void (*early_serial_map)(void); + void (*kgdb_map_scc)(void); + + unsigned char (*nvram_read_val)(int addr); + void (*nvram_write_val)(int addr, unsigned char val); + + /* + * optional PCI "hooks" + */ + + /* Called after PPC generic resource fixup to perform + machine specific fixups */ + void (*pcibios_fixup_resources)(struct pci_dev *); + + /* Called for each PCI bus in the system when it's probed */ + void (*pcibios_fixup_bus)(struct pci_bus *); + + /* Called when pci_enable_device() is called (initial=0) or + * when a device with no assigned resource is found (initial=1). + * Returns 0 to allow assignment/enabling of the device. */ + int (*pcibios_enable_device_hook)(struct pci_dev *, int initial); + + /* For interrupt routing */ + unsigned char (*pci_swizzle)(struct pci_dev *, unsigned char *); + int (*pci_map_irq)(struct pci_dev *, unsigned char, unsigned char); + + /* Called in indirect_* to avoid touching devices */ + int (*pci_exclude_device)(unsigned char, unsigned char); + + /* Called at then very end of pcibios_init() */ + void (*pcibios_after_init)(void); + + /* this is for modules, since _machine can be a define -- Cort */ + int ppc_machine; + +#ifdef CONFIG_KEXEC + /* Called to shutdown machine specific hardware not already controlled + * by other drivers. + * XXX Should we move this one out of kexec scope? + */ + void (*machine_shutdown)(void); + + /* Called to do the minimal shutdown needed to run a kexec'd kernel + * to run successfully. + * XXX Should we move this one out of kexec scope? + */ + void (*machine_crash_shutdown)(void); + + /* Called to do what every setup is needed on image and the + * reboot code buffer. Returns 0 on success. + * Provide your own (maybe dummy) implementation if your platform + * claims to support kexec. + */ + int (*machine_kexec_prepare)(struct kimage *image); + + /* Called to handle any machine specific cleanup on image */ + void (*machine_kexec_cleanup)(struct kimage *image); + + /* Called to perform the _real_ kexec. + * Do NOT allocate memory or fail here. We are past the point of + * no return. + */ + void (*machine_kexec)(struct kimage *image); +#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_PPC32 */ }; -extern int default_idle(void); -extern int native_idle(void); +extern void default_idle(void); +extern void native_idle(void); extern struct machdep_calls ppc_md; extern char cmd_line[COMMAND_LINE_SIZE]; @@ -161,6 +259,13 @@ extern sys_ctrler_t sys_ctrler; #endif /* CONFIG_PPC_PMAC */ +extern void setup_pci_ptrs(void); + +#ifdef CONFIG_SMP +/* Poor default implementations */ +extern void __devinit smp_generic_give_timebase(void); +extern void __devinit smp_generic_take_timebase(void); +#endif /* CONFIG_SMP */ /* Functions to produce codes on the leds. @@ -180,5 +285,5 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal) ppc_md.log_error(buf, err_type, fatal); } -#endif /* _PPC64_MACHDEP_H */ #endif /* __KERNEL__ */ +#endif /* _PPC64_MACHDEP_H */ diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h index 5c904d371963..2c050332471d 100644 --- a/include/asm-powerpc/rtas.h +++ b/include/asm-powerpc/rtas.h @@ -190,7 +190,7 @@ extern void rtas_progress(char *s, unsigned short hex); extern void rtas_initialize(void); struct rtc_time; -extern void rtas_get_boot_time(struct rtc_time *rtc_time); +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); From 0b879a31447acd9ebe8b3c5231f72ccebeefad3a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 19 Oct 2005 23:12:01 +1000 Subject: [PATCH 0505/1939] ppc: declare smp_ops in asm/smp.h, since platform setup code needs it Signed-off-by: Paul Mackerras --- include/asm-ppc/smp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index 79c1be3dfe61..063d7dedc691 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -35,6 +35,7 @@ extern cpumask_t cpu_possible_map; extern unsigned long smp_proc_in_lock[]; extern volatile unsigned long cpu_callin_map[]; extern int smp_tb_synchronized; +extern struct smp_ops_t *smp_ops; extern void smp_send_tlb_invalidate(int); extern void smp_send_xmon_break(int cpu); From 9b7cf8b49dc4464b222afc9fa32628bb9a2e70a3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 19 Oct 2005 23:13:04 +1000 Subject: [PATCH 0506/1939] powerpc: Eliminate a compile warning in signal_32.c The second argument of get_sigset_t needed to have the const keyword. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/signal_32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index e7e7aac11f89..1c4eac4c808f 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -105,7 +105,8 @@ static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) return copy_to_user(uset, &cset, sizeof(*uset)); } -static inline int get_sigset_t(sigset_t *set, compat_sigset_t __user *uset) +static inline int get_sigset_t(sigset_t *set, + const compat_sigset_t __user *uset) { compat_sigset_t s32; @@ -187,7 +188,7 @@ static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) return copy_to_user(uset, set, sizeof(*uset)); } -static inline int get_sigset_t(sigset_t *set, sigset_t __user *uset) +static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset) { return copy_from_user(set, uset, sizeof(*uset)); } From 055787e447a6cf50aa1cc42f7d3b07f08223dd9b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 19 Oct 2005 08:22:13 -0400 Subject: [PATCH 0507/1939] [SCSI] scsi_error thread exits in TASK_INTERRUPTIBLE state. Found in the -rt patch set. The scsi_error thread likely will be in the TASK_INTERRUPTIBLE state upon exit. This patch fixes this bug. Signed-off-by: Steven Rostedt Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ad5342165079..52b348c36d56 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1645,6 +1645,8 @@ int scsi_error_handler(void *data) set_current_state(TASK_INTERRUPTIBLE); } + __set_current_state(TASK_RUNNING); + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d" " exiting\n",shost->host_no)); From 5b74eda78db410b979b7d450221c971fdebf5d29 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Wed, 19 Oct 2005 16:31:34 -0500 Subject: [PATCH 0508/1939] Fixed problem with not being able to decrypt/encrypt broadcast packets. Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_rx.c | 3 ++- net/ieee80211/ieee80211_tx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 6b005cb0caa0..ce694cf5c160 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -409,7 +409,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 1; } - if (is_multicast_ether_addr(hdr->addr1) ? ieee->host_mc_decrypt : + if ((is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr2)) ? ieee->host_mc_decrypt : ieee->host_decrypt) { int idx = 0; if (skb->len >= hdrlen + 3) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 42c50619aa8e..2955b7aa5a38 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -338,7 +338,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (host_encrypt || ieee->host_open_frag) { /* Determine fragmentation size based on destination (multicast * and broadcast are not fragmented) */ - if (is_multicast_ether_addr(dest)) + if (is_multicast_ether_addr(dest) || + is_broadcast_ether_addr(dest)) frag_size = MAX_FRAG_THRESHOLD; else frag_size = ieee->fts; From b123923d486d38e1a961e82040a26838401aebb5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 09:11:29 +1000 Subject: [PATCH 0509/1939] powerpc: Move ptrace32.c from arch/ppc64 to arch/powerpc Also corrected my email address in ptrace.c and updated the comments at the top of ptrace32.c. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/ptrace.c | 2 +- arch/{ppc64 => powerpc}/kernel/ptrace32.c | 9 +++++---- arch/ppc64/kernel/Makefile | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename arch/{ppc64 => powerpc}/kernel/ptrace32.c (97%) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 01b6d630edc9..5c5d2b5f3ca2 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,7 +12,7 @@ endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ signal_32.o -obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o +obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 336b8bf542d7..943425a93354 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -8,7 +8,7 @@ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). + * and Paul Mackerras (paulus@samba.org). * * This file is subject to the terms and conditions of the GNU General * Public License. See the file README.legal in the main directory of diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c similarity index 97% rename from arch/ppc64/kernel/ptrace32.c rename to arch/powerpc/kernel/ptrace32.c index 2e1df3ddd9fb..544368277d7e 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -1,5 +1,5 @@ /* - * linux/arch/ppc64/kernel/ptrace32.c + * ptrace for 32-bit processes running on a 64-bit kernel. * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -10,10 +10,10 @@ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). + * and Paul Mackerras (paulus@samba.org). * * This file is subject to the terms and conditions of the GNU General - * Public License. See the file README.legal in the main directory of + * Public License. See the file COPYING in the main directory of * this archive for more details. */ @@ -40,7 +40,8 @@ * in exit.c or in signal.c. */ -int compat_sys_ptrace(long request, long pid, unsigned long addr, unsigned long data) +int compat_sys_ptrace(int request, int pid, unsigned long addr, + unsigned long data) { struct task_struct *child; int ret = -EPERM; diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 19846d78b329..8c9012f0ce6a 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -15,7 +15,7 @@ obj-y += irq.o idle.o dma.o \ time.o signal.o \ align.o bitops.o pacaData.o \ udbg.o ioctl32.o \ - ptrace32.o rtc.o \ + rtc.o \ cpu_setup_power4.o \ iommu.o sysfs.o vdso.o pmc.o firmware.o obj-y += vdso32/ vdso64/ From 03f88e9f7145b03fd0d855918d54a3bf5342ac5e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 09:15:05 +1000 Subject: [PATCH 0510/1939] ppc64: Minor compilation fixes This defines CONFIG_PPC_STD_MMU for ppc64, changes an instance of sys32_ to compat_sys_ in the ppc64 syscall table, and removes a reference to a non-existent arch/powerpc/xmon/Makefile. Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 2 +- arch/ppc64/Kconfig | 3 +++ arch/ppc64/kernel/misc.S | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 29cda0732703..dedf1219761a 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -131,7 +131,7 @@ core-y += arch/powerpc/kernel/ \ arch/powerpc/sysdev/ \ arch/powerpc/platforms/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ -core-$(CONFIG_XMON) += arch/powerpc/xmon/ +#core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_APUS) += arch/ppc/amiga/ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index e656e02d9dd1..8cbac7f32092 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -10,6 +10,9 @@ config MMU bool default y +config PPC_STD_MMU + def_bool y + config UID16 bool diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index c2c3421b8f38..ad73aad8dbb6 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -951,7 +951,7 @@ _GLOBAL(sys_call_table32) .llong .sys_alarm .llong .sys_ni_syscall /* old fstat syscall */ .llong .compat_sys_pause - .llong .compat_sys_utime /* 30 */ + .llong .compat_sys_utime /* 30 */ .llong .sys_ni_syscall /* old stty syscall */ .llong .sys_ni_syscall /* old gtty syscall */ .llong .compat_sys_access @@ -981,7 +981,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_setpgid .llong .sys_ni_syscall /* old ulimit syscall */ .llong .sys_olduname - .llong .compat_sys_umask /* 60 */ + .llong .compat_sys_umask /* 60 */ .llong .sys_chroot .llong .sys_ustat .llong .sys_dup2 @@ -996,17 +996,17 @@ _GLOBAL(sys_call_table32) .llong .ppc32_sigsuspend .llong .compat_sys_sigpending .llong .compat_sys_sethostname - .llong .compat_sys_setrlimit /* 75 */ + .llong .compat_sys_setrlimit /* 75 */ .llong .compat_sys_old_getrlimit .llong .compat_sys_getrusage .llong .compat_sys_gettimeofday .llong .compat_sys_settimeofday - .llong .compat_sys_getgroups /* 80 */ + .llong .compat_sys_getgroups /* 80 */ .llong .compat_sys_setgroups .llong .sys_ni_syscall /* old select syscall */ .llong .sys_symlink .llong .sys_ni_syscall /* old lstat syscall */ - .llong .compat_sys_readlink /* 85 */ + .llong .compat_sys_readlink /* 85 */ .llong .sys_uselib .llong .sys_swapon .llong .sys_reboot @@ -1021,12 +1021,12 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_setpriority .llong .sys_ni_syscall /* old profil syscall */ .llong .compat_sys_statfs - .llong .compat_sys_fstatfs /* 100 */ + .llong .compat_sys_fstatfs /* 100 */ .llong .sys_ni_syscall /* old ioperm syscall */ .llong .compat_sys_socketcall .llong .compat_sys_syslog .llong .compat_sys_setitimer - .llong .compat_sys_getitimer /* 105 */ + .llong .compat_sys_getitimer /* 105 */ .llong .compat_sys_newstat .llong .compat_sys_newlstat .llong .compat_sys_newfstat @@ -1038,7 +1038,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_wait4 .llong .sys_swapoff /* 115 */ .llong .compat_sys_sysinfo - .llong .compat_sys_ipc + .llong .sys32_ipc .llong .sys_fsync .llong .ppc32_sigreturn .llong .ppc_clone /* 120 */ @@ -1056,7 +1056,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_getpgid .llong .sys_fchdir .llong .sys_bdflush - .llong .compat_sys_sysfs /* 135 */ + .llong .compat_sys_sysfs /* 135 */ .llong .ppc64_personality .llong .sys_ni_syscall /* for afs_syscall */ .llong .sys_setfsuid @@ -1101,7 +1101,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_rt_sigqueueinfo .llong .ppc32_rt_sigsuspend .llong .compat_sys_pread64 - .llong .compat_sys_pwrite64 /* 180 */ + .llong .compat_sys_pwrite64 /* 180 */ .llong .sys_chown .llong .sys_getcwd .llong .sys_capget @@ -1166,12 +1166,12 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_timer_gettime .llong .sys_timer_getoverrun .llong .sys_timer_delete - .llong .compat_sys_clock_settime /* 245 */ + .llong .compat_sys_clock_settime/* 245 */ .llong .compat_sys_clock_gettime .llong .compat_sys_clock_getres .llong .compat_sys_clock_nanosleep .llong .ppc32_swapcontext - .llong .compat_sys_tgkill /* 250 */ + .llong .compat_sys_tgkill /* 250 */ .llong .compat_sys_utimes .llong .compat_sys_statfs64 .llong .compat_sys_fstatfs64 From f2783c15007468c14972e2617db51e9affc7fad9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 09:23:26 +1000 Subject: [PATCH 0511/1939] powerpc: Merge time.c and asm/time.h. We now use the merged time.c for both 32-bit and 64-bit compilation with ARCH=powerpc, and for ARCH=ppc64, but not for ARCH=ppc32. This removes setup_default_decr (folds its function into time_init) and moves wakeup_decrementer into time.c. This also makes an asm-powerpc/rtc.h. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 4 +- arch/powerpc/kernel/misc_32.S | 27 ++ arch/powerpc/kernel/ppc_ksyms.c | 1 - arch/powerpc/kernel/setup_64.c | 9 - arch/{ppc64 => powerpc}/kernel/time.c | 515 +++++++++++++--------- arch/powerpc/platforms/powermac/cpufreq.c | 9 - arch/powerpc/platforms/powermac/time.c | 28 +- arch/ppc/kernel/Makefile | 2 +- arch/ppc/kernel/time.c | 9 + arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/pmac_time.c | 2 - arch/ppc64/kernel/setup.c | 9 - drivers/macintosh/via-pmu.c | 11 - include/asm-powerpc/irq.h | 2 + include/asm-powerpc/rtc.h | 80 ++++ include/asm-powerpc/time.h | 212 +++++++++ include/asm-ppc64/time.h | 124 ------ 17 files changed, 659 insertions(+), 387 deletions(-) rename arch/{ppc64 => powerpc}/kernel/time.c (72%) create mode 100644 include/asm-powerpc/rtc.h create mode 100644 include/asm-powerpc/time.h delete mode 100644 include/asm-ppc64/time.h diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 5c5d2b5f3ca2..b347ac320252 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -29,7 +29,7 @@ extra-$(CONFIG_PPC64) += entry_64.o extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds -obj-y += process.o init_task.o \ +obj-y += process.o init_task.o time.o \ prom.o systbl.o traps.o obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o @@ -44,7 +44,7 @@ endif else # stuff used from here for ARCH=ppc or ARCH=ppc64 -obj-$(CONFIG_PPC64) += traps.o process.o init_task.o +obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o fpux-$(CONFIG_PPC32) += fpu.o extra-$(CONFIG_PPC_FPU) += $(fpux-y) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 0b0e908b5065..303229b090b8 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -35,6 +35,33 @@ _GLOBAL(__delay) 1: bdnz 1b blr +/* + * This returns the high 64 bits of the product of two 64-bit numbers. + */ +_GLOBAL(mulhdu) + cmpwi r6,0 + cmpwi cr1,r3,0 + mr r10,r4 + mulhwu r4,r4,r5 + beq 1f + mulhwu r0,r10,r6 + mullw r7,r10,r5 + addc r7,r0,r7 + addze r4,r4 +1: beqlr cr1 /* all done if high part of A is 0 */ + mr r10,r3 + mullw r9,r3,r5 + mulhwu r3,r3,r5 + beq 2f + mullw r0,r10,r6 + mulhwu r8,r10,r6 + addc r7,r0,r7 + adde r4,r4,r8 + addze r3,r3 +2: addc r4,r4,r9 + addze r3,r3 + blr + /* * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 010554e5fe48..40c9e67e1b28 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -260,7 +260,6 @@ EXPORT_SYMBOL(__res); #ifdef CONFIG_PPC32 EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); -EXPORT_SYMBOL(disarm_decr); #endif #ifdef CONFIG_PPC_STD_MMU_32 diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 4fcf67575cbb..6f29614c3581 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -/* This should only be called on processor 0 during calibrate decr */ -void __init setup_default_decr(void) -{ - struct paca_struct *lpaca = get_paca(); - - lpaca->default_decr = tb_ticks_per_jiffy; - lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; -} - #ifndef CONFIG_PPC_ISERIES /* * This function can be used by platforms to "find" legacy serial ports. diff --git a/arch/ppc64/kernel/time.c b/arch/powerpc/kernel/time.c similarity index 72% rename from arch/ppc64/kernel/time.c rename to arch/powerpc/kernel/time.c index 7f63755eddfd..d1608473075f 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -1,5 +1,4 @@ /* - * * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -44,29 +43,32 @@ #include #include #include -#include #include #include #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC64 +#include +#include +#endif #ifdef CONFIG_PPC_ISERIES #include #include #endif -#include -#include -#include -#include -#include -#include -#include u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; @@ -81,27 +83,37 @@ unsigned long iSeries_recal_tb = 0; static unsigned long first_settimeofday = 1; #endif +/* The decrementer counts down by 128 every 128ns on a 601. */ +#define DECREMENTER_COUNT_601 (1000000000 / HZ) + #define XSEC_PER_SEC (1024*1024) +#ifdef CONFIG_PPC64 +#define SCALE_XSEC(xsec, max) (((xsec) * max) / XSEC_PER_SEC) +#else +/* compute ((xsec << 12) * max) >> 32 */ +#define SCALE_XSEC(xsec, max) mulhwu((xsec) << 12, max) +#endif + unsigned long tb_ticks_per_jiffy; unsigned long tb_ticks_per_usec = 100; /* sane default */ EXPORT_SYMBOL(tb_ticks_per_usec); unsigned long tb_ticks_per_sec; -unsigned long tb_to_xs; -unsigned tb_to_us; +u64 tb_to_xs; +unsigned tb_to_us; unsigned long processor_freq; DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock); -unsigned long tb_to_ns_scale; -unsigned long tb_to_ns_shift; +u64 tb_to_ns_scale; +unsigned tb_to_ns_shift; struct gettimeofday_struct do_gtod; extern unsigned long wall_jiffies; -extern int smp_tb_synchronized; extern struct timezone sys_tz; +static long timezone_offset; void ppc_adjtimex(void); @@ -110,6 +122,10 @@ static unsigned adjusting_time = 0; unsigned long ppc_proc_freq; unsigned long ppc_tb_freq; +#ifdef CONFIG_PPC32 /* XXX for now */ +#define boot_cpuid 0 +#endif + static __inline__ void timer_check_rtc(void) { /* @@ -129,30 +145,30 @@ static __inline__ void timer_check_rtc(void) * seconds like on Intel to avoid problems with non UTC clocks. */ if (ntp_synced() && - xtime.tv_sec - last_rtc_update >= 659 && - abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ && - jiffies - wall_jiffies == 1) { - struct rtc_time tm; - to_tm(xtime.tv_sec+1, &tm); - tm.tm_year -= 1900; - tm.tm_mon -= 1; - if (ppc_md.set_rtc_time(&tm) == 0) - last_rtc_update = xtime.tv_sec+1; - else - /* Try again one minute later */ - last_rtc_update += 60; + xtime.tv_sec - last_rtc_update >= 659 && + abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ && + jiffies - wall_jiffies == 1) { + struct rtc_time tm; + to_tm(xtime.tv_sec + 1 + timezone_offset, &tm); + tm.tm_year -= 1900; + tm.tm_mon -= 1; + if (ppc_md.set_rtc_time(&tm) == 0) + last_rtc_update = xtime.tv_sec + 1; + else + /* Try again one minute later */ + last_rtc_update += 60; } } /* * This version of gettimeofday has microsecond resolution. */ -static inline void __do_gettimeofday(struct timeval *tv, unsigned long tb_val) +static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val) { - unsigned long sec, usec, tb_ticks; - unsigned long xsec, tb_xsec; - struct gettimeofday_vars * temp_varp; - unsigned long temp_tb_to_xs, temp_stamp_xsec; + unsigned long sec, usec; + u64 tb_ticks, xsec; + struct gettimeofday_vars *temp_varp; + u64 temp_tb_to_xs, temp_stamp_xsec; /* * These calculations are faster (gets rid of divides) @@ -164,11 +180,10 @@ static inline void __do_gettimeofday(struct timeval *tv, unsigned long tb_val) tb_ticks = tb_val - temp_varp->tb_orig_stamp; temp_tb_to_xs = temp_varp->tb_to_xs; temp_stamp_xsec = temp_varp->stamp_xsec; - tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs ); - xsec = temp_stamp_xsec + tb_xsec; + xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs); sec = xsec / XSEC_PER_SEC; - xsec -= sec * XSEC_PER_SEC; - usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC; + usec = (unsigned long)xsec & (XSEC_PER_SEC - 1); + usec = SCALE_XSEC(usec, 1000000); tv->tv_sec = sec; tv->tv_usec = usec; @@ -185,6 +200,8 @@ EXPORT_SYMBOL(do_gettimeofday); static inline void timer_sync_xtime(unsigned long cur_tb) { +#ifdef CONFIG_PPC64 + /* why do we do this? */ struct timeval my_tv; __do_gettimeofday(&my_tv, cur_tb); @@ -193,6 +210,51 @@ static inline void timer_sync_xtime(unsigned long cur_tb) xtime.tv_sec = my_tv.tv_sec; xtime.tv_nsec = my_tv.tv_usec * 1000; } +#endif +} + +/* + * There are two copies of tb_to_xs and stamp_xsec so that no + * lock is needed to access and use these values in + * do_gettimeofday. We alternate the copies and as long as a + * reasonable time elapses between changes, there will never + * be inconsistent values. ntpd has a minimum of one minute + * between updates. + */ +static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, + unsigned int new_tb_to_xs) +{ + unsigned temp_idx; + struct gettimeofday_vars *temp_varp; + + temp_idx = (do_gtod.var_idx == 0); + temp_varp = &do_gtod.vars[temp_idx]; + + temp_varp->tb_to_xs = new_tb_to_xs; + temp_varp->tb_orig_stamp = new_tb_stamp; + temp_varp->stamp_xsec = new_stamp_xsec; + smp_mb(); + do_gtod.varp = temp_varp; + do_gtod.var_idx = temp_idx; + +#ifdef CONFIG_PPC64 + /* + * tb_update_count is used to allow the userspace gettimeofday code + * to assure itself that it sees a consistent view of the tb_to_xs and + * stamp_xsec variables. It reads the tb_update_count, then reads + * tb_to_xs and stamp_xsec and then reads tb_update_count again. If + * the two values of tb_update_count match and are even then the + * tb_to_xs and stamp_xsec values are consistent. If not, then it + * loops back and reads them again until this criteria is met. + */ + ++(systemcfg->tb_update_count); + smp_wmb(); + systemcfg->tb_orig_stamp = new_tb_stamp; + systemcfg->stamp_xsec = new_stamp_xsec; + systemcfg->tb_to_xs = new_tb_to_xs; + smp_wmb(); + ++(systemcfg->tb_update_count); +#endif } /* @@ -205,35 +267,17 @@ static inline void timer_sync_xtime(unsigned long cur_tb) * with a too big difference, then the vdso will fallback to calling * the syscall */ -static __inline__ void timer_recalc_offset(unsigned long cur_tb) +static __inline__ void timer_recalc_offset(u64 cur_tb) { - struct gettimeofday_vars * temp_varp; - unsigned temp_idx; - unsigned long offset, new_stamp_xsec, new_tb_orig_stamp; + unsigned long offset; + u64 new_stamp_xsec; - if (((cur_tb - do_gtod.varp->tb_orig_stamp) & 0x80000000u) == 0) + offset = cur_tb - do_gtod.varp->tb_orig_stamp; + if ((offset & 0x80000000u) == 0) return; - - temp_idx = (do_gtod.var_idx == 0); - temp_varp = &do_gtod.vars[temp_idx]; - - new_tb_orig_stamp = cur_tb; - offset = new_tb_orig_stamp - do_gtod.varp->tb_orig_stamp; - new_stamp_xsec = do_gtod.varp->stamp_xsec + mulhdu(offset, do_gtod.varp->tb_to_xs); - - temp_varp->tb_to_xs = do_gtod.varp->tb_to_xs; - temp_varp->tb_orig_stamp = new_tb_orig_stamp; - temp_varp->stamp_xsec = new_stamp_xsec; - smp_mb(); - do_gtod.varp = temp_varp; - do_gtod.var_idx = temp_idx; - - ++(systemcfg->tb_update_count); - smp_wmb(); - systemcfg->tb_orig_stamp = new_tb_orig_stamp; - systemcfg->stamp_xsec = new_stamp_xsec; - smp_wmb(); - ++(systemcfg->tb_update_count); + new_stamp_xsec = do_gtod.varp->stamp_xsec + + mulhdu(offset, do_gtod.varp->tb_to_xs); + update_gtod(cur_tb, new_stamp_xsec, do_gtod.varp->tb_to_xs); } #ifdef CONFIG_SMP @@ -313,7 +357,14 @@ static void iSeries_tb_recal(void) * call will not be needed) */ -unsigned long tb_last_stamp __cacheline_aligned_in_smp; +u64 tb_last_stamp __cacheline_aligned_in_smp; + +/* + * Note that on ppc32 this only stores the bottom 32 bits of + * the timebase value, but that's enough to tell when a jiffy + * has passed. + */ +DEFINE_PER_CPU(unsigned long, last_jiffy); /* * timer_interrupt - gets called when the decrementer overflows, @@ -322,17 +373,30 @@ unsigned long tb_last_stamp __cacheline_aligned_in_smp; void timer_interrupt(struct pt_regs * regs) { int next_dec; - unsigned long cur_tb; - struct paca_struct *lpaca = get_paca(); - unsigned long cpu = smp_processor_id(); + int cpu = smp_processor_id(); + unsigned long ticks; + +#ifdef CONFIG_PPC32 + if (atomic_read(&ppc_n_lost_interrupts) != 0) + do_IRQ(regs); +#endif irq_enter(); profile_tick(CPU_PROFILING, regs); - lpaca->lppaca.int_dword.fields.decr_int = 0; +#ifdef CONFIG_PPC_ISERIES + get_paca()->lppaca.int_dword.fields.decr_int = 0; +#endif + + while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) + >= tb_ticks_per_jiffy) { + /* Update last_jiffy */ + per_cpu(last_jiffy, cpu) += tb_ticks_per_jiffy; + /* Handle RTCL overflow on 601 */ + if (__USE_RTC() && per_cpu(last_jiffy, cpu) >= 1000000000) + per_cpu(last_jiffy, cpu) -= 1000000000; - while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) { /* * We cannot disable the decrementer, so in the period * between this cpu's being marked offline in cpu_online_map @@ -342,27 +406,26 @@ void timer_interrupt(struct pt_regs * regs) */ if (!cpu_is_offline(cpu)) update_process_times(user_mode(regs)); + /* * No need to check whether cpu is offline here; boot_cpuid * should have been fixed up by now. */ - if (cpu == boot_cpuid) { - write_seqlock(&xtime_lock); - tb_last_stamp = lpaca->next_jiffy_update_tb; - timer_recalc_offset(lpaca->next_jiffy_update_tb); - do_timer(regs); - timer_sync_xtime(lpaca->next_jiffy_update_tb); - timer_check_rtc(); - write_sequnlock(&xtime_lock); - if ( adjusting_time && (time_adjust == 0) ) - ppc_adjtimex(); - } - lpaca->next_jiffy_update_tb += tb_ticks_per_jiffy; + if (cpu != boot_cpuid) + continue; + + write_seqlock(&xtime_lock); + tb_last_stamp += tb_ticks_per_jiffy; + timer_recalc_offset(tb_last_stamp); + do_timer(regs); + timer_sync_xtime(tb_last_stamp); + timer_check_rtc(); + write_sequnlock(&xtime_lock); + if (adjusting_time && (time_adjust == 0)) + ppc_adjtimex(); } - next_dec = lpaca->next_jiffy_update_tb - cur_tb; - if (next_dec > lpaca->default_decr) - next_dec = lpaca->default_decr; + next_dec = tb_ticks_per_jiffy - ticks; set_dec(next_dec); #ifdef CONFIG_PPC_ISERIES @@ -370,15 +433,47 @@ void timer_interrupt(struct pt_regs * regs) process_hvlpevents(regs); #endif +#ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); cu->current_tb = mfspr(SPRN_PURR); } +#endif irq_exit(); } +void wakeup_decrementer(void) +{ + int i; + + set_dec(tb_ticks_per_jiffy); + /* + * We don't expect this to be called on a machine with a 601, + * so using get_tbl is fine. + */ + tb_last_stamp = get_tb(); + for_each_cpu(i) + per_cpu(last_jiffy, i) = tb_last_stamp; +} + +#ifdef CONFIG_SMPxxx +void __init smp_space_timers(unsigned int max_cpus) +{ + int i; + unsigned long offset = tb_ticks_per_jiffy / max_cpus; + unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); + + for_each_cpu(i) { + if (i != boot_cpuid) { + previous_tb += offset; + per_cpu(last_jiffy, i) = previous_tb; + } + } +} +#endif + /* * Scheduler clock - returns current time in nanosec units. * @@ -396,23 +491,24 @@ int do_settimeofday(struct timespec *tv) time_t wtm_sec, new_sec = tv->tv_sec; long wtm_nsec, new_nsec = tv->tv_nsec; unsigned long flags; - unsigned long delta_xsec; long int tb_delta; - unsigned long new_xsec; + u64 new_xsec; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; write_seqlock_irqsave(&xtime_lock, flags); - /* Updating the RTC is not the job of this code. If the time is - * stepped under NTP, the RTC will be update after STA_UNSYNC - * is cleared. Tool like clock/hwclock either copy the RTC + + /* + * Updating the RTC is not the job of this code. If the time is + * stepped under NTP, the RTC will be updated after STA_UNSYNC + * is cleared. Tools like clock/hwclock either copy the RTC * to the system time, in which case there is no point in writing * to the RTC again, or write to the RTC but then they don't call * settimeofday to perform this operation. */ #ifdef CONFIG_PPC_ISERIES - if ( first_settimeofday ) { + if (first_settimeofday) { iSeries_tb_recal(); first_settimeofday = 0; } @@ -420,7 +516,7 @@ int do_settimeofday(struct timespec *tv) tb_delta = tb_ticks_since(tb_last_stamp); tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; - new_nsec -= tb_delta / tb_ticks_per_usec / 1000; + new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); @@ -435,28 +531,15 @@ int do_settimeofday(struct timespec *tv) ntp_clear(); - delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp), - do_gtod.varp->tb_to_xs ); - - new_xsec = (new_nsec * XSEC_PER_SEC) / NSEC_PER_SEC; - new_xsec += new_sec * XSEC_PER_SEC; - if ( new_xsec > delta_xsec ) { - do_gtod.varp->stamp_xsec = new_xsec - delta_xsec; - systemcfg->stamp_xsec = new_xsec - delta_xsec; - } - else { - /* This is only for the case where the user is setting the time - * way back to a time such that the boot time would have been - * before 1970 ... eg. we booted ten days ago, and we are setting - * the time to Jan 5, 1970 */ - do_gtod.varp->stamp_xsec = new_xsec; - do_gtod.varp->tb_orig_stamp = tb_last_stamp; - systemcfg->stamp_xsec = new_xsec; - systemcfg->tb_orig_stamp = tb_last_stamp; - } + new_xsec = (u64)new_nsec * XSEC_PER_SEC; + do_div(new_xsec, NSEC_PER_SEC); + new_xsec += (u64)new_sec * XSEC_PER_SEC; + update_gtod(tb_last_stamp, new_xsec, do_gtod.varp->tb_to_xs); +#ifdef CONFIG_PPC64 systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; systemcfg->tz_dsttime = sys_tz.tz_dsttime; +#endif write_sequnlock_irqrestore(&xtime_lock, flags); clock_was_set(); @@ -520,21 +603,40 @@ void __init generic_calibrate_decr(void) tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); tb_to_xs = divres.result_low; - - setup_default_decr(); } #endif +unsigned long get_boot_time(void) +{ + struct rtc_time tm; + + if (ppc_md.get_boot_time) + return ppc_md.get_boot_time(); + if (!ppc_md.get_rtc_time) + return 0; + ppc_md.get_rtc_time(&tm); + return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} + +/* This function is only called on the boot processor */ void __init time_init(void) { - /* This function is only called on the boot processor */ unsigned long flags; - struct rtc_time tm; + unsigned long tm = 0; struct div_result res; - unsigned long scale, shift; + u64 scale; + unsigned shift; + + if (ppc_md.time_init != NULL) + timezone_offset = ppc_md.time_init(); ppc_md.calibrate_decr(); +#ifdef CONFIG_PPC64 + get_paca()->default_decr = tb_ticks_per_jiffy; +#endif + /* * Compute scale factor for sched_clock. * The calibrate_decr() function has set tb_ticks_per_sec, @@ -557,29 +659,37 @@ void __init time_init(void) #ifdef CONFIG_PPC_ISERIES if (!piranha_simulator) #endif - ppc_md.get_boot_time(&tm); + tm = get_boot_time(); write_seqlock_irqsave(&xtime_lock, flags); - xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + xtime.tv_sec = tm; + xtime.tv_nsec = 0; tb_last_stamp = get_tb(); do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; do_gtod.varp->tb_orig_stamp = tb_last_stamp; - get_paca()->next_jiffy_update_tb = tb_last_stamp + tb_ticks_per_jiffy; - do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; + __get_cpu_var(last_jiffy) = tb_last_stamp; + do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC; do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; do_gtod.tb_to_us = tb_to_us; +#ifdef CONFIG_PPC64 systemcfg->tb_orig_stamp = tb_last_stamp; systemcfg->tb_update_count = 0; systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; systemcfg->tb_to_xs = tb_to_xs; +#endif time_freq = 0; - xtime.tv_nsec = 0; + /* If platform provided a timezone (pmac), we correct the time */ + if (timezone_offset) { + sys_tz.tz_minuteswest = -timezone_offset / 60; + sys_tz.tz_dsttime = 0; + xtime.tv_sec -= timezone_offset; + } + last_rtc_update = xtime.tv_sec; set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); @@ -602,25 +712,28 @@ void __init time_init(void) void ppc_adjtimex(void) { - unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec; +#ifdef CONFIG_PPC64 + unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, + new_tb_to_xs, new_xsec, new_stamp_xsec; unsigned long tb_ticks_per_sec_delta; long delta_freq, ltemp; struct div_result divres; unsigned long flags; - struct gettimeofday_vars * temp_varp; - unsigned temp_idx; long singleshot_ppm = 0; - /* Compute parts per million frequency adjustment to accomplish the time adjustment - implied by time_offset to be applied over the elapsed time indicated by time_constant. - Use SHIFT_USEC to get it into the same units as time_freq. */ + /* + * Compute parts per million frequency adjustment to + * accomplish the time adjustment implied by time_offset to be + * applied over the elapsed time indicated by time_constant. + * Use SHIFT_USEC to get it into the same units as + * time_freq. + */ if ( time_offset < 0 ) { ltemp = -time_offset; ltemp <<= SHIFT_USEC - SHIFT_UPDATE; ltemp >>= SHIFT_KG + time_constant; ltemp = -ltemp; - } - else { + } else { ltemp = time_offset; ltemp <<= SHIFT_USEC - SHIFT_UPDATE; ltemp >>= SHIFT_KG + time_constant; @@ -637,7 +750,10 @@ void ppc_adjtimex(void) adjusting_time = 1; - /* Compute parts per million frequency adjustment to match time_adjust */ + /* + * Compute parts per million frequency adjustment + * to match time_adjust + */ singleshot_ppm = tickadj * HZ; /* * The adjustment should be tickadj*HZ to match the code in @@ -645,7 +761,7 @@ void ppc_adjtimex(void) * large. 3/4 of tickadj*HZ seems about right */ singleshot_ppm -= singleshot_ppm / 4; - /* Use SHIFT_USEC to get it into the same units as time_freq */ + /* Use SHIFT_USEC to get it into the same units as time_freq */ singleshot_ppm <<= SHIFT_USEC; if ( time_adjust < 0 ) singleshot_ppm = -singleshot_ppm; @@ -661,7 +777,10 @@ void ppc_adjtimex(void) /* Add up all of the frequency adjustments */ delta_freq = time_freq + ltemp + singleshot_ppm; - /* Compute a new value for tb_ticks_per_sec based on the frequency adjustment */ + /* + * Compute a new value for tb_ticks_per_sec based on + * the frequency adjustment + */ den = 1000000 * (1 << (SHIFT_USEC - 8)); if ( delta_freq < 0 ) { tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den; @@ -676,61 +795,37 @@ void ppc_adjtimex(void) printk("ppc_adjtimex: ltemp = %ld, time_freq = %ld, singleshot_ppm = %ld\n", ltemp, time_freq, singleshot_ppm); printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec); #endif - - /* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of - stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp. This - new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs) - which guarantees that the current time remains the same */ - write_seqlock_irqsave( &xtime_lock, flags ); - tb_ticks = get_tb() - do_gtod.varp->tb_orig_stamp; - div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres ); - new_tb_to_xs = divres.result_low; - new_xsec = mulhdu( tb_ticks, new_tb_to_xs ); - - old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs ); - new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec; - - /* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these - values in do_gettimeofday. We alternate the copies and as long as a reasonable time elapses between - changes, there will never be inconsistent values. ntpd has a minimum of one minute between updates */ - - temp_idx = (do_gtod.var_idx == 0); - temp_varp = &do_gtod.vars[temp_idx]; - - temp_varp->tb_to_xs = new_tb_to_xs; - temp_varp->stamp_xsec = new_stamp_xsec; - temp_varp->tb_orig_stamp = do_gtod.varp->tb_orig_stamp; - smp_mb(); - do_gtod.varp = temp_varp; - do_gtod.var_idx = temp_idx; /* - * tb_update_count is used to allow the problem state gettimeofday code - * to assure itself that it sees a consistent view of the tb_to_xs and - * stamp_xsec variables. It reads the tb_update_count, then reads - * tb_to_xs and stamp_xsec and then reads tb_update_count again. If - * the two values of tb_update_count match and are even then the - * tb_to_xs and stamp_xsec values are consistent. If not, then it - * loops back and reads them again until this criteria is met. + * Compute a new value of tb_to_xs (used to convert tb to + * microseconds) and a new value of stamp_xsec which is the + * time (in 1/2^20 second units) corresponding to + * tb_orig_stamp. This new value of stamp_xsec compensates + * for the change in frequency (implied by the new tb_to_xs) + * which guarantees that the current time remains the same. */ - ++(systemcfg->tb_update_count); - smp_wmb(); - systemcfg->tb_to_xs = new_tb_to_xs; - systemcfg->stamp_xsec = new_stamp_xsec; - smp_wmb(); - ++(systemcfg->tb_update_count); + write_seqlock_irqsave( &xtime_lock, flags ); + tb_ticks = get_tb() - do_gtod.varp->tb_orig_stamp; + div128_by_32(1024*1024, 0, new_tb_ticks_per_sec, &divres); + new_tb_to_xs = divres.result_low; + new_xsec = mulhdu(tb_ticks, new_tb_to_xs); + + old_xsec = mulhdu(tb_ticks, do_gtod.varp->tb_to_xs); + new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec; + + update_gtod(do_gtod.varp->tb_orig_stamp, new_stamp_xsec, new_tb_to_xs); write_sequnlock_irqrestore( &xtime_lock, flags ); - +#endif /* CONFIG_PPC64 */ } -#define TICK_SIZE tick #define FEBRUARY 2 #define STARTOFTIME 1970 #define SECDAY 86400L #define SECYR (SECDAY * 365) -#define leapyear(year) ((year) % 4 == 0) +#define leapyear(year) ((year) % 4 == 0 && \ + ((year) % 100 != 0 || (year) % 400 == 0)) #define days_in_year(a) (leapyear(a) ? 366 : 365) #define days_in_month(a) (month_days[(a) - 1]) @@ -748,37 +843,25 @@ void GregorianDay(struct rtc_time * tm) int day; int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - lastYear=tm->tm_year-1; + lastYear = tm->tm_year - 1; /* * Number of leap corrections to apply up to end of last year */ - leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; /* * This year is a leap year if it is divisible by 4 except when it is * divisible by 100 unless it is divisible by 400 * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was */ - if((tm->tm_year%4==0) && - ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && - (tm->tm_mon>2)) - { - /* - * We are past Feb. 29 in a leap year - */ - day=1; - } - else - { - day=0; - } + day = tm->tm_mon > 2 && leapyear(tm->tm_year); day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; - tm->tm_wday=day%7; + tm->tm_wday = day % 7; } void to_tm(int tim, struct rtc_time * tm) @@ -824,14 +907,16 @@ void to_tm(int tim, struct rtc_time * tm) * oscillators and the precision with which the timebase frequency * is measured but does not harm. */ -unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { +unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) +{ unsigned mlt=0, tmp, err; /* No concern for performance, it's done once: use a stupid * but safe and compact method to find the multiplier. */ for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { - if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; + if (mulhwu(inscale, mlt|tmp) < outscale) + mlt |= tmp; } /* We might still be off by 1 for the best approximation. @@ -841,39 +926,53 @@ unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { * some might have been forgotten in the test however. */ - err = inscale*(mlt+1); - if (err <= inscale/2) mlt++; + err = inscale * (mlt+1); + if (err <= inscale/2) + mlt++; return mlt; - } +} /* * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit * result. */ - -void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, - unsigned divisor, struct div_result *dr ) +void div128_by_32(u64 dividend_high, u64 dividend_low, + unsigned divisor, struct div_result *dr) { - unsigned long a,b,c,d, w,x,y,z, ra,rb,rc; + unsigned long a, b, c, d; + unsigned long w, x, y, z; + u64 ra, rb, rc; a = dividend_high >> 32; b = dividend_high & 0xffffffff; c = dividend_low >> 32; d = dividend_low & 0xffffffff; - w = a/divisor; - ra = (a - (w * divisor)) << 32; + w = a / divisor; + ra = ((u64)(a - (w * divisor)) << 32) + b; - x = (ra + b)/divisor; - rb = ((ra + b) - (x * divisor)) << 32; +#ifdef CONFIG_PPC64 + x = ra / divisor; + rb = ((ra - (x * divisor)) << 32) + c; - y = (rb + c)/divisor; - rc = ((rb + b) - (y * divisor)) << 32; + y = rb / divisor; + rc = ((rb - (y * divisor)) << 32) + d; - z = (rc + d)/divisor; + z = rc / divisor; +#else + /* for 32-bit, use do_div from div64.h */ + rb = ((u64) do_div(ra, divisor) << 32) + c; + x = ra; - dr->result_high = (w << 32) + x; - dr->result_low = (y << 32) + z; + rc = ((u64) do_div(rb, divisor) << 32) + d; + y = rb; + + do_div(rc, divisor); + z = rc; +#endif + + dr->result_high = ((u64)w << 32) + x; + dr->result_low = ((u64)y << 32) + z; } diff --git a/arch/powerpc/platforms/powermac/cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq.c index bcd9224f3f90..c47f8b69725c 100644 --- a/arch/powerpc/platforms/powermac/cpufreq.c +++ b/arch/powerpc/platforms/powermac/cpufreq.c @@ -110,15 +110,6 @@ static inline void local_delay(unsigned long ms) msleep(ms); } -static inline void wakeup_decrementer(void) -{ - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - * so use get_tbl, not native - */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); -} - #ifdef DEBUG_FREQ static inline void debug_calc_bogomips(void) { diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index 3ee6d8aa14c4..eb9969b52f96 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -6,6 +6,8 @@ * * Paul Mackerras August 1996. * Copyright (C) 1996 Paul Mackerras. + * Copyright (C) 2003-2005 Benjamin Herrenschmidt. + * */ #include #include @@ -19,7 +21,9 @@ #include #include #include +#include #include +#include #include #include @@ -30,6 +34,14 @@ #include #include +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + /* Apparently the RTC stores seconds since 1 Jan 1904 */ #define RTC_OFFSET 2082844800 @@ -54,10 +66,7 @@ /* Bits in IFR and IER */ #define T1_INT 0x40 /* Timer 1 interrupt */ -extern struct timezone sys_tz; - -long __init -pmac_time_init(void) +long __init pmac_time_init(void) { #ifdef CONFIG_NVRAM s32 delta = 0; @@ -210,7 +219,7 @@ via_calibrate_decr(void) tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n", tb_ticks_per_jiffy, dstart - dend); iounmap(via); @@ -228,6 +237,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) static unsigned long time_diff; unsigned long flags; unsigned long seq; + struct timespec tv; switch (when) { case PBOOK_SLEEP_NOW: @@ -237,11 +247,9 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); break; case PBOOK_WAKE: - write_seqlock_irqsave(&xtime_lock, flags); - xtime.tv_sec = pmac_get_rtc_time() + time_diff; - xtime.tv_nsec = 0; - last_rtc_update = xtime.tv_sec; - write_sequnlock_irqrestore(&xtime_lock, flags); + tv.tv_sec = pmac_get_boot_time() + time_diff; + tv.tv_nsec = 0; + do_settimeofday(&tv); break; } return PBOOK_SLEEP_OK; diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 5a742c7b0509..ccbc442c9ed3 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -37,7 +37,7 @@ endif # These are here while we do the architecture merge else -obj-y := irq.o idle.o time.o \ +obj-y := irq.o idle.o \ align.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 22d7fd1e0aea..76f44ce4772e 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -121,6 +121,15 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif +void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + /* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 8c9012f0ce6a..18f477fa1df2 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := setup.o entry.o misc.o prom.o endif obj-y += irq.o idle.o dma.o \ - time.o signal.o \ + signal.o \ align.o bitops.o pacaData.o \ udbg.o ioctl32.o \ rtc.o \ diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index c89bfefbbecd..56f335115916 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -180,7 +180,5 @@ void __init pmac_calibrate_decr(void) if (fp == 0) panic("can't get cpu processor frequency"); ppc_proc_freq = *fp; - - setup_default_decr(); } diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 776b55b45e1b..3e6c1547b718 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -/* This should only be called on processor 0 during calibrate decr */ -void __init setup_default_decr(void) -{ - struct paca_struct *lpaca = get_paca(); - - lpaca->default_decr = tb_ticks_per_jiffy; - lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; -} - #ifndef CONFIG_PPC_ISERIES /* * This function can be used by platforms to "find" legacy serial ports. diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 503461884528..91920a1140fa 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -588,17 +588,6 @@ pmu_get_model(void) return pmu_kind; } -#ifndef CONFIG_PPC64 -static inline void wakeup_decrementer(void) -{ - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - * so use get_tbl, not native - */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); -} -#endif - static void pmu_set_server_mode(int server_mode) { struct adb_request req; diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 980393a16be2..07c2b3fc4c66 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -496,5 +496,7 @@ extern int call_handle_IRQ_event(int irq, struct pt_regs *regs, #endif /* CONFIG_IRQSTACKS */ +extern void do_IRQ(struct pt_regs *regs); + #endif /* _ASM_IRQ_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/rtc.h b/include/asm-powerpc/rtc.h new file mode 100644 index 000000000000..d38f2a077db2 --- /dev/null +++ b/include/asm-powerpc/rtc.h @@ -0,0 +1,80 @@ +/* + * Real-time clock definitions and interfaces + * + * Author: Tom Rini + * + * 2002 (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. + * + * Based on: + * include/asm-m68k/rtc.h + * + * Copyright Richard Zidlicky + * implementation details for genrtc/q40rtc driver + * + * And the old drivers/macintosh/rtc.c which was heavily based on: + * Linux/SPARC Real Time Clock Driver + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * + * With additional work by Paul Mackerras and Franz Sirl. + */ + +#ifndef __ASM_POWERPC_RTC_H__ +#define __ASM_POWERPC_RTC_H__ + +#ifdef __KERNEL__ + +#include + +#include +#include + +#define RTC_PIE 0x40 /* periodic interrupt enable */ +#define RTC_AIE 0x20 /* alarm interrupt enable */ +#define RTC_UIE 0x10 /* update-finished interrupt enable */ + +/* some dummy definitions */ +#define RTC_BATT_BAD 0x100 /* battery bad */ +#define RTC_SQWE 0x08 /* enable square-wave output */ +#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ +#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ +#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ + +static inline unsigned int get_rtc_time(struct rtc_time *time) +{ + if (ppc_md.get_rtc_time) + ppc_md.get_rtc_time(time); + return RTC_24H; +} + +/* Set the current date and time in the real time clock. */ +static inline int set_rtc_time(struct rtc_time *time) +{ + if (ppc_md.get_rtc_time) { + ppc_md.set_rtc_time(time); + return 0; + } + return -EINVAL; +} + +static inline unsigned int get_rtc_ss(void) +{ + struct rtc_time h; + + get_rtc_time(&h); + return h.tm_sec; +} + +static inline int get_rtc_pll(struct rtc_pll_info *pll) +{ + return -EINVAL; +} +static inline int set_rtc_pll(struct rtc_pll_info *pll) +{ + return -EINVAL; +} + +#endif /* __KERNEL__ */ +#endif /* __ASM_POWERPC_RTC_H__ */ diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h new file mode 100644 index 000000000000..4eecc38f7092 --- /dev/null +++ b/include/asm-powerpc/time.h @@ -0,0 +1,212 @@ +/* + * Common time prototypes and such for all ppc machines. + * + * Written by Cort Dougan (cort@cs.nmt.edu) to merge + * Paul Mackerras' version and mine for PReP and Pmac. + * + * 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 __POWERPC_TIME_H +#define __POWERPC_TIME_H + +#ifdef __KERNEL__ +#include +#include +#include + +#include +#ifdef CONFIG_PPC64 +#include +#include +#endif + +/* time.c */ +extern unsigned long tb_ticks_per_jiffy; +extern unsigned long tb_ticks_per_usec; +extern unsigned long tb_ticks_per_sec; +extern u64 tb_to_xs; +extern unsigned tb_to_us; +extern u64 tb_last_stamp; + +DECLARE_PER_CPU(unsigned long, last_jiffy); + +struct rtc_time; +extern void to_tm(int tim, struct rtc_time * tm); +extern time_t last_rtc_update; + +extern void generic_calibrate_decr(void); +extern void wakeup_decrementer(void); + +/* Some sane defaults: 125 MHz timebase, 1GHz processor */ +extern unsigned long ppc_proc_freq; +#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) +extern unsigned long ppc_tb_freq; +#define DEFAULT_TB_FREQ 125000000UL + +/* + * By putting all of this stuff into a single struct we + * reduce the number of cache lines touched by do_gettimeofday. + * Both by collecting all of the data in one cache line and + * by touching only one TOC entry on ppc64. + */ +struct gettimeofday_vars { + u64 tb_to_xs; + u64 stamp_xsec; + u64 tb_orig_stamp; +}; + +struct gettimeofday_struct { + unsigned long tb_ticks_per_sec; + struct gettimeofday_vars vars[2]; + struct gettimeofday_vars * volatile varp; + unsigned var_idx; + unsigned tb_to_us; +}; + +struct div_result { + u64 result_high; + u64 result_low; +}; + +/* Accessor functions for the timebase (RTC on 601) registers. */ +/* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ +#ifdef CONFIG_6xx +#define __USE_RTC() cpu_has_feature(CPU_FTR_USE_TB) +#else +#define __USE_RTC() 0 +#endif + +/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */ +static inline unsigned long get_tbl(void) +{ + unsigned long tbl; + +#if defined(CONFIG_403GCX) + asm volatile("mfspr %0, 0x3dd" : "=r" (tbl)); +#else + asm volatile("mftb %0" : "=r" (tbl)); +#endif + return tbl; +} + +static inline unsigned int get_tbu(void) +{ + unsigned int tbu; + +#if defined(CONFIG_403GCX) + asm volatile("mfspr %0, 0x3dc" : "=r" (tbu)); +#else + asm volatile("mftbu %0" : "=r" (tbu)); +#endif + return tbu; +} + +static inline unsigned int get_rtcl(void) +{ + unsigned int rtcl; + + asm volatile("mfrtcl %0" : "=r" (rtcl)); + return rtcl; +} + +#ifdef CONFIG_PPC64 +static inline u64 get_tb(void) +{ + return mftb(); +} +#else +static inline u64 get_tb(void) +{ + unsigned int tbhi, tblo, tbhi2; + + do { + tbhi = get_tbu(); + tblo = get_tbl(); + tbhi2 = get_tbu(); + } while (tbhi != tbhi2); + + return ((u64)tbhi << 32) | tblo; +} +#endif + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, upper); + mtspr(SPRN_TBWL, lower); +} + +/* Accessor functions for the decrementer register. + * The 4xx doesn't even have a decrementer. I tried to use the + * generic timer interrupt code, which seems OK, with the 4xx PIT + * in auto-reload mode. The problem is PIT stops counting when it + * hits zero. If it would wrap, we could use it just like a decrementer. + */ +static inline unsigned int get_dec(void) +{ +#if defined(CONFIG_40x) + return (mfspr(SPRN_PIT)); +#else + return (mfspr(SPRN_DEC)); +#endif +} + +static inline void set_dec(int val) +{ +#if defined(CONFIG_40x) + return; /* Have to let it auto-reload */ +#elif defined(CONFIG_8xx_CPU6) + set_dec_cpu6(val); +#else +#ifdef CONFIG_PPC_ISERIES + struct paca_struct *lpaca = get_paca(); + int cur_dec; + + if (lpaca->lppaca.shared_proc) { + lpaca->lppaca.virtual_decr = val; + cur_dec = get_dec(); + if (cur_dec > val) + HvCall_setVirtualDecr(); + } else +#endif + mtspr(SPRN_DEC, val); +#endif /* not 40x or 8xx_CPU6 */ +} + +static inline unsigned long tb_ticks_since(unsigned long tstamp) +{ + if (__USE_RTC()) { + int delta = get_rtcl() - (unsigned int) tstamp; + return delta < 0 ? delta + 1000000000 : delta; + } + return get_tbl() - tstamp; +} + +#define mulhwu(x,y) \ +({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) + +#ifdef CONFIG_PPC64 +#define mulhdu(x,y) \ +({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) +#else +extern u64 mulhdu(u64, u64); +#endif + +unsigned mulhwu_scale_factor(unsigned, unsigned); +void div128_by_32(u64 dividend_high, u64 dividend_low, + unsigned divisor, struct div_result *dr); + +/* Used to store Processor Utilization register (purr) values */ + +struct cpu_usage { + u64 current_tb; /* Holds the current purr register values */ +}; + +DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); + +#endif /* __KERNEL__ */ +#endif /* __PPC64_TIME_H */ diff --git a/include/asm-ppc64/time.h b/include/asm-ppc64/time.h deleted file mode 100644 index c6c762cad8b0..000000000000 --- a/include/asm-ppc64/time.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Common time prototypes and such for all ppc machines. - * - * Written by Cort Dougan (cort@cs.nmt.edu) to merge - * Paul Mackerras' version and mine for PReP and Pmac. - * - * 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 __PPC64_TIME_H -#define __PPC64_TIME_H - -#ifdef __KERNEL__ -#include -#include -#include - -#include -#include -#include - -/* time.c */ -extern unsigned long tb_ticks_per_jiffy; -extern unsigned long tb_ticks_per_usec; -extern unsigned long tb_ticks_per_sec; -extern unsigned long tb_to_xs; -extern unsigned tb_to_us; -extern unsigned long tb_last_stamp; - -struct rtc_time; -extern void to_tm(int tim, struct rtc_time * tm); -extern time_t last_rtc_update; - -void generic_calibrate_decr(void); -void setup_default_decr(void); - -/* Some sane defaults: 125 MHz timebase, 1GHz processor */ -extern unsigned long ppc_proc_freq; -#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) -extern unsigned long ppc_tb_freq; -#define DEFAULT_TB_FREQ 125000000UL - -/* - * By putting all of this stuff into a single struct we - * reduce the number of cache lines touched by do_gettimeofday. - * Both by collecting all of the data in one cache line and - * by touching only one TOC entry - */ -struct gettimeofday_vars { - unsigned long tb_to_xs; - unsigned long stamp_xsec; - unsigned long tb_orig_stamp; -}; - -struct gettimeofday_struct { - unsigned long tb_ticks_per_sec; - struct gettimeofday_vars vars[2]; - struct gettimeofday_vars * volatile varp; - unsigned var_idx; - unsigned tb_to_us; -}; - -struct div_result { - unsigned long result_high; - unsigned long result_low; -}; - -int via_calibrate_decr(void); - -static __inline__ unsigned long get_tb(void) -{ - return mftb(); -} - -/* Accessor functions for the decrementer register. */ -static __inline__ unsigned int get_dec(void) -{ - return (mfspr(SPRN_DEC)); -} - -static __inline__ void set_dec(int val) -{ -#ifdef CONFIG_PPC_ISERIES - struct paca_struct *lpaca = get_paca(); - int cur_dec; - - if (lpaca->lppaca.shared_proc) { - lpaca->lppaca.virtual_decr = val; - cur_dec = get_dec(); - if (cur_dec > val) - HvCall_setVirtualDecr(); - } else -#endif - mtspr(SPRN_DEC, val); -} - -static inline unsigned long tb_ticks_since(unsigned long tstamp) -{ - return get_tb() - tstamp; -} - -#define mulhwu(x,y) \ -({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) -#define mulhdu(x,y) \ -({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) - - -unsigned mulhwu_scale_factor(unsigned, unsigned); -void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, - unsigned divisor, struct div_result *dr ); - -/* Used to store Processor Utilization register (purr) values */ - -struct cpu_usage { - u64 current_tb; /* Holds the current purr register values */ -}; - -DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); - -#endif /* __KERNEL__ */ -#endif /* __PPC64_TIME_H */ From a4bcc95a3ad0ccba6d7b39442dfb81cc57bb7121 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 09:24:18 +1000 Subject: [PATCH 0512/1939] powerpc: Fix a branch-too-far link error for 32-bit targets Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/entry_32.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 094eea6fbd69..fc9dded9ac04 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -633,7 +633,8 @@ sigreturn_exit: rlwinm r12,r1,0,0,18 /* current_thread_info() */ lwz r9,TI_FLAGS(r12) andi. r0,r9,_TIF_SYSCALL_T_OR_A - bnel- do_syscall_trace_leave + beq+ ret_from_except_full + bl do_syscall_trace_leave /* fall through */ .globl ret_from_except_full From 344480b99730bfd205e306d3fd168cdcebe83425 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 09:37:02 +1000 Subject: [PATCH 0513/1939] powerpc: Fix a corner case in __div64_32 The code was incorrectly doing a division by 0 in the case where the denominator was 0x100000000 and the divisor was 0xffffffff. Thanks to Fred Liu of Motorola for pointing this out. Signed-off-by: Paul Mackerras --- arch/powerpc/lib/div64.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/lib/div64.S b/arch/powerpc/lib/div64.S index 3527569e9926..83d9832fd919 100644 --- a/arch/powerpc/lib/div64.S +++ b/arch/powerpc/lib/div64.S @@ -33,9 +33,10 @@ _GLOBAL(__div64_32) cntlzw r0,r5 # we are shifting the dividend right li r10,-1 # to make it < 2^32, and shifting srw r10,r10,r0 # the divisor right the same amount, - add r9,r4,r10 # rounding up (so the estimate cannot + addc r9,r4,r10 # rounding up (so the estimate cannot andc r11,r6,r10 # ever be too large, only too small) andc r9,r9,r10 + addze r9,r9 or r11,r5,r11 rotlw r9,r9,r0 rotlw r11,r11,r0 From b15125fa81a522882247242e569bc7035e28cc82 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 18 Oct 2005 17:42:09 -0500 Subject: [PATCH 0514/1939] [PATCH] powerpc: Some more fixes to allow building for a Book-E processor Some minor fixes that are needed if we are building for a book-e processor. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/mm/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 14b2ffb6c2d8..93441e7a2921 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -7,14 +7,13 @@ EXTRA_CFLAGS += -mno-minimal-toc endif obj-y := fault.o mem.o lmb.o -obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o \ - tlb_32.o +obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o hash-$(CONFIG_PPC_MULTIPLATFORM) := hash_native_64.o obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \ hash_utils_64.o hash_low_64.o tlb_64.o \ slb_low.o slb.o stab.o mmap.o imalloc.o \ $(hash-y) -obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o +obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o tlb_32.o obj-$(CONFIG_40x) += 4xx_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o From 3d904eef54fd145e2ae5fadb52d2c39bc49339ae Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 18 Oct 2005 17:42:41 -0500 Subject: [PATCH 0515/1939] [PATCH] ppc32: replace use of _GLOBAL with .globl for ppc32 The _GLOBAL() macro is for text symbols only. Changed to using .globl for .data symbols. This is also needed in ppc32 land to allow FSL Book-E, 40x, and 44x to work. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/head_44x.S | 18 +++++++++++------- arch/ppc/kernel/head_4xx.S | 16 +++++++++++----- arch/ppc/kernel/head_fsl_booke.S | 17 +++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index b1b9dc08abca..8b49679fad54 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -743,14 +743,18 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 /* * To support >32-bit physical addresses, we use an 8KB pgdir. */ -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 8192 /* Reserved 4k for the critical exception stack & 4k for the machine @@ -759,13 +763,15 @@ _GLOBAL(swapper_pg_dir) .align 12 exception_stack_bottom: .space BOOKE_EXCEPTION_STACK_SIZE -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* * This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* @@ -774,5 +780,3 @@ _GLOBAL(cmd_line) */ abatron_pteptrs: .space 8 - - diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index 5772ce97e24e..10c261c67021 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -988,10 +988,14 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 4096 @@ -1001,12 +1005,14 @@ _GLOBAL(swapper_pg_dir) exception_stack_bottom: .space 4096 critical_stack_top: -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* Room for two PTE pointers, usually the kernel and current user pointers diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index 53949811efda..5063c603fad4 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -1028,10 +1028,14 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data -_GLOBAL(sdata) -_GLOBAL(empty_zero_page) + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: .space 4096 -_GLOBAL(swapper_pg_dir) + .globl swapper_pg_dir +swapper_pg_dir: .space 4096 /* Reserved 4k for the critical exception stack & 4k for the machine @@ -1040,13 +1044,15 @@ _GLOBAL(swapper_pg_dir) .align 12 exception_stack_bottom: .space BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS -_GLOBAL(exception_stack_top) + .globl exception_stack_top +exception_stack_top: /* * This space gets a copy of optional info passed to us by the bootstrap * which is used to pass parameters into the kernel like root=/dev/sda1, etc. */ -_GLOBAL(cmd_line) + .globl cmd_line +cmd_line: .space 512 /* @@ -1055,4 +1061,3 @@ _GLOBAL(cmd_line) */ abatron_pteptrs: .space 8 - From ab7a435a01a9995359a72851ff6896dc110c243f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 21:01:29 +0100 Subject: [PATCH 0516/1939] [PATCH] Remove unused header. mkiss.h has been integrated into mkiss.c earlier. Signed-off-by: Ralf Baechle DL5RB drivers/net/hamradio/mkiss.h | 62 ------------------------------------------- 1 files changed, 62 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/hamradio/mkiss.h | 62 ------------------------------------ 1 file changed, 62 deletions(-) delete mode 100644 drivers/net/hamradio/mkiss.h diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h deleted file mode 100644 index 4ab700478598..000000000000 --- a/drivers/net/hamradio/mkiss.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** - * Defines for the Multi-KISS driver. - ****************************************************************************/ - -#define AX25_MAXDEV 16 /* MAX number of AX25 channels; - This can be overridden with - insmod -oax25_maxdev=nnn */ -#define AX_MTU 236 - -/* SLIP/KISS protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -struct ax_disp { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* SLIP interface statistics. */ - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_bytes; /* inbound bytes counter */ - unsigned long tx_bytes; /* outbound bytes counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ - - /* Detailed SLIP statistics. */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - - unsigned long flags; /* Flag values/ mode etc */ - /* long req'd: used by set_bit --RR */ -#define AXF_INUSE 0 /* Channel in use */ -#define AXF_ESCAPE 1 /* ESC received */ -#define AXF_ERROR 2 /* Parity, etc. error */ -#define AXF_KEEPTEST 3 /* Keepalive test flag */ -#define AXF_OUTWAIT 4 /* is outpacket was flag */ - - int mode; - int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 - spinlock_t buflock; /* lock for rbuf and xbuf */ -}; - -#define AX25_MAGIC 0x5316 From 2039973af59889fea0d14362eae56792cfe8d25a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 19 Oct 2005 15:39:05 +0100 Subject: [PATCH 0517/1939] [PATCH] sb1250-mac: Get rid of all the funny SBMAC_WRITECSR and SBMAC_READCSR macros. Signed-off-by: Ralf Baechle drivers/net/sb1250-mac.c | 303 ++++++++++++++++++++--------------------------- 1 files changed, 132 insertions(+), 171 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 303 +++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 171 deletions(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index cb4ea4158457..f7dda6fabe82 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -118,8 +118,6 @@ MODULE_PARM_DESC(int_timeout, "Timeout value"); ********************************************************************* */ -typedef unsigned long sbmac_port_t; - typedef enum { sbmac_speed_auto, sbmac_speed_10, sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; @@ -144,10 +142,6 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) -#define SBMAC_READCSR(t) __raw_readq((unsigned long)t) -#define SBMAC_WRITECSR(t,v) __raw_writeq(v, (unsigned long)t) - - #define SBMAC_MAX_TXDESCR 32 #define SBMAC_MAX_RXDESCR 32 @@ -187,11 +181,11 @@ typedef struct sbmacdma_s { int sbdma_int_timeout; /* # usec rx/tx interrupt */ #endif - sbmac_port_t sbdma_config0; /* DMA config register 0 */ - sbmac_port_t sbdma_config1; /* DMA config register 1 */ - sbmac_port_t sbdma_dscrbase; /* Descriptor base address */ - sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */ - sbmac_port_t sbdma_curdscr; /* current descriptor address */ + volatile void __iomem *sbdma_config0; /* DMA config register 0 */ + volatile void __iomem *sbdma_config1; /* DMA config register 1 */ + volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ + volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ + volatile void __iomem *sbdma_curdscr; /* current descriptor address */ /* * This stuff is for maintenance of the ring @@ -236,17 +230,17 @@ struct sbmac_softc { * Controller-specific things */ - unsigned long sbm_base; /* MAC's base address */ + volatile void __iomem *sbm_base; /* MAC's base address */ sbmac_state_t sbm_state; /* current state */ - sbmac_port_t sbm_macenable; /* MAC Enable Register */ - sbmac_port_t sbm_maccfg; /* MAC Configuration Register */ - sbmac_port_t sbm_fifocfg; /* FIFO configuration register */ - sbmac_port_t sbm_framecfg; /* Frame configuration register */ - sbmac_port_t sbm_rxfilter; /* receive filter register */ - sbmac_port_t sbm_isr; /* Interrupt status register */ - sbmac_port_t sbm_imr; /* Interrupt mask register */ - sbmac_port_t sbm_mdio; /* MDIO register */ + volatile void __iomem *sbm_macenable; /* MAC Enable Register */ + volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ + volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ + volatile void __iomem *sbm_framecfg; /* Frame configuration register */ + volatile void __iomem *sbm_rxfilter; /* receive filter register */ + volatile void __iomem *sbm_isr; /* Interrupt status register */ + volatile void __iomem *sbm_imr; /* Interrupt mask register */ + volatile void __iomem *sbm_mdio; /* MDIO register */ sbmac_speed_t sbm_speed; /* current speed */ sbmac_duplex_t sbm_duplex; /* current duplex */ @@ -467,15 +461,15 @@ static void sbmac_mii_sync(struct sbmac_softc *s) uint64_t bits; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); for (cnt = 0; cnt < 32; cnt++) { - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); } } @@ -498,10 +492,10 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc unsigned int curmask; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); curmask = 1 << (bitcnt - 1); @@ -509,9 +503,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); curmask >>= 1; } } @@ -559,33 +553,31 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) sbmac_mii_senddata(s,phyaddr, 5); sbmac_mii_senddata(s,regidx, 5); - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; /* * Switch the port around without a clock transition. */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); /* * Send out a clock pulse to signal we want the status */ - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); /* * If an error occurred, the PHY will signal '1' back */ - error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN; + error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); regval = 0; @@ -593,18 +585,16 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) regval <<= 1; if (error == 0) { - if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) + if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); } /* Switch back to output */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); if (error == 0) return regval; @@ -641,9 +631,9 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, sbmac_mii_senddata(s,MII_COMMAND_ACK,2); sbmac_mii_senddata(s,regval,16); - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); } @@ -685,48 +675,27 @@ static void sbdma_initctx(sbmacdma_t *d, s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); /* * initialize register pointers @@ -814,22 +783,19 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) */ #ifdef CONFIG_SBMAC_COALESCE - SBMAC_WRITECSR(d->sbdma_config1, - V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | - 0); - SBMAC_WRITECSR(d->sbdma_config0, - M_DMA_EOP_INT_EN | + __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | + 0, d->sbdma_config1); + __raw_writeq(M_DMA_EOP_INT_EN | V_DMA_RINGSZ(d->sbdma_maxdescr) | V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) | - 0); + 0, d->sbdma_config0); #else - SBMAC_WRITECSR(d->sbdma_config1,0); - SBMAC_WRITECSR(d->sbdma_config0, - V_DMA_RINGSZ(d->sbdma_maxdescr) | - 0); + __raw_writeq(0, d->sbdma_config1); + __raw_writeq(V_DMA_RINGSZ(d->sbdma_maxdescr) | + 0, d->sbdma_config0); #endif - SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys); + __raw_writeq(d->sbdma_dscrtable_phys, d->sbdma_dscrbase); /* * Initialize ring pointers @@ -857,18 +823,18 @@ static void sbdma_channel_stop(sbmacdma_t *d) * Turn off the DMA channel */ - SBMAC_WRITECSR(d->sbdma_config1,0); + __raw_writeq(0, d->sbdma_config1); - SBMAC_WRITECSR(d->sbdma_dscrbase,0); + __raw_writeq(0, d->sbdma_dscrbase); - SBMAC_WRITECSR(d->sbdma_config0,0); + __raw_writeq(0, d->sbdma_config0); /* * Zero ring pointers */ - d->sbdma_addptr = 0; - d->sbdma_remptr = 0; + d->sbdma_addptr = NULL; + d->sbdma_remptr = NULL; } static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) @@ -971,8 +937,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * Do not interrupt per DMA transfer. */ dsc->dscr_a = virt_to_phys(sb_new->data) | - V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | - 0; + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; #else dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | @@ -998,7 +963,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * Give the buffer to the DMA engine. */ - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + __raw_writeq(1, d->sbdma_dscrcnt); return 0; /* we did it */ } @@ -1088,7 +1053,7 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) * Give the buffer to the DMA engine. */ - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + __raw_writeq(1, d->sbdma_dscrcnt); return 0; /* we did it */ } @@ -1184,7 +1149,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) */ curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); /* @@ -1311,7 +1276,7 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) */ curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); /* @@ -1467,7 +1432,7 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) static void sbmac_channel_start(struct sbmac_softc *s) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; @@ -1482,13 +1447,13 @@ static void sbmac_channel_start(struct sbmac_softc *s) * Bring the controller out of reset, but leave it off. */ - SBMAC_WRITECSR(s->sbm_macenable,0); + __raw_writeq(0, s->sbm_macenable); /* * Ignore all received packets */ - SBMAC_WRITECSR(s->sbm_rxfilter,0); + __raw_writeq(0, s->sbm_rxfilter); /* * Calculate values for various control registers. @@ -1532,7 +1497,7 @@ static void sbmac_channel_start(struct sbmac_softc *s) port = s->sbm_base + R_MAC_HASH_BASE; for (idx = 0; idx < MAC_HASH_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } @@ -1542,7 +1507,7 @@ static void sbmac_channel_start(struct sbmac_softc *s) port = s->sbm_base + R_MAC_ADDR_BASE; for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } @@ -1552,14 +1517,14 @@ static void sbmac_channel_start(struct sbmac_softc *s) port = s->sbm_base + R_MAC_CHUP0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } port = s->sbm_base + R_MAC_CHLO0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } @@ -1571,7 +1536,7 @@ static void sbmac_channel_start(struct sbmac_softc *s) reg = sbmac_addr2reg(s->sbm_hwaddr); port = s->sbm_base + R_MAC_ADDR_BASE; - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); port = s->sbm_base + R_MAC_ETHERNET_ADDR; #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS @@ -1580,9 +1545,9 @@ static void sbmac_channel_start(struct sbmac_softc *s) * destination address in the R_MAC_ETHERNET_ADDR register. * Set the value to zero. */ - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); #else - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); #endif /* @@ -1590,11 +1555,11 @@ static void sbmac_channel_start(struct sbmac_softc *s) * to the various config registers */ - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_fifocfg,fifo); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(fifo, s->sbm_fifocfg); + __raw_writeq(cfg, s->sbm_maccfg); /* * Initialize DMA channels (rings should be ok now) @@ -1620,11 +1585,10 @@ static void sbmac_channel_start(struct sbmac_softc *s) * Turn on the rest of the bits in the enable register */ - SBMAC_WRITECSR(s->sbm_macenable, - M_MAC_RXDMA_EN0 | + __raw_writeq(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0 | M_MAC_RX_ENABLE | - M_MAC_TX_ENABLE); + M_MAC_TX_ENABLE, s->sbm_macenable); @@ -1633,23 +1597,21 @@ static void sbmac_channel_start(struct sbmac_softc *s) /* * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0 */ - SBMAC_WRITECSR(s->sbm_imr, - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0)); + __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | + ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); #else /* * Accept any kind of interrupt on TX and RX DMA channel 0 */ - SBMAC_WRITECSR(s->sbm_imr, - (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | - (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)); + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); #endif /* * Enable receiving unicasts and broadcasts */ - SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN); + __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter); /* * we're running now. @@ -1695,8 +1657,8 @@ static void sbmac_channel_stop(struct sbmac_softc *s) /* don't accept any packets, disable all interrupts */ - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); /* Turn off ticker */ @@ -1704,7 +1666,7 @@ static void sbmac_channel_stop(struct sbmac_softc *s) /* turn off receiver and transmitter */ - SBMAC_WRITECSR(s->sbm_macenable,0); + __raw_writeq(0, s->sbm_macenable); /* We're stopped now. */ @@ -1788,14 +1750,14 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) return; if (onoff) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } else { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } @@ -1816,9 +1778,9 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) uint64_t reg; /* Hard code the off set to 15 for now */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); /* read system identification to determine revision */ if (periph_rev >= 2) { @@ -1897,8 +1859,8 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) * Read current register values */ - cfg = SBMAC_READCSR(s->sbm_maccfg); - framecfg = SBMAC_READCSR(s->sbm_framecfg); + cfg = __raw_readq(s->sbm_maccfg); + framecfg = __raw_readq(s->sbm_framecfg); /* * Mask out the stuff we want to change @@ -1947,8 +1909,8 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) * Send the bits back to the hardware */ - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(cfg, s->sbm_maccfg); return 1; } @@ -1987,7 +1949,7 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc * Read current register values */ - cfg = SBMAC_READCSR(s->sbm_maccfg); + cfg = __raw_readq(s->sbm_maccfg); /* * Mask off the stuff we're about to change @@ -2046,7 +2008,7 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc * Send the bits back to the hardware */ - SBMAC_WRITECSR(s->sbm_maccfg,cfg); + __raw_writeq(cfg, s->sbm_maccfg); return 1; } @@ -2079,7 +2041,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) * register, except for counter addr) */ - isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; + isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; if (isr == 0) break; @@ -2180,7 +2142,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) static void sbmac_setmulti(struct sbmac_softc *sc) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; @@ -2193,30 +2155,30 @@ static void sbmac_setmulti(struct sbmac_softc *sc) for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } for (idx = 0; idx < MAC_HASH_COUNT; idx++) { port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } /* * Clear the filter to say we don't want any multicasts. */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); if (dev->flags & IFF_ALLMULTI) { /* * Enable ALL multicasts. Do this by inverting the * multicast enable bit. */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); return; } @@ -2235,7 +2197,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc) while (mclist && (idx < MAC_ADDR_COUNT)) { reg = sbmac_addr2reg(mclist->dmi_addr); port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t)); - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); idx++; mclist = mclist->next; } @@ -2246,9 +2208,9 @@ static void sbmac_setmulti(struct sbmac_softc *sc) */ if (idx > 1) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_MCAST_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } @@ -2377,8 +2339,8 @@ static int sbmac_init(struct net_device *dev, int idx) * for us in the ethernet address register for each mac. */ - ea_reg = SBMAC_READCSR(sc->sbm_base + R_MAC_ETHERNET_ADDR); - SBMAC_WRITECSR(sc->sbm_base + R_MAC_ETHERNET_ADDR, 0); + ea_reg = __raw_readq(sc->sbm_base + R_MAC_ETHERNET_ADDR); + __raw_writeq(0, sc->sbm_base + R_MAC_ETHERNET_ADDR); for (i = 0; i < 6; i++) { eaddr[i] = (uint8_t) (ea_reg & 0xFF); ea_reg >>= 8; @@ -2465,7 +2427,7 @@ static int sbmac_open(struct net_device *dev) * yet) */ - SBMAC_READCSR(sc->sbm_isr); + __raw_readq(sc->sbm_isr); if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) return -EBUSY; @@ -2800,13 +2762,13 @@ sbmac_setup_hwaddr(int chan,char *addr) { uint8_t eaddr[6]; uint64_t val; - sbmac_port_t port; + unsigned long port; port = A_MAC_CHANNEL_BASE(chan); sbmac_parse_hwaddr(addr,eaddr); val = sbmac_addr2reg(eaddr); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),val); - val = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR)); + val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); } #endif @@ -2817,7 +2779,7 @@ sbmac_init_module(void) { int idx; struct net_device *dev; - sbmac_port_t port; + unsigned long port; int chip_max_units; /* @@ -2871,7 +2833,7 @@ sbmac_init_module(void) * If we find a zero, skip this MAC. */ - sbmac_orig_hwaddr[idx] = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); if (sbmac_orig_hwaddr[idx] == 0) { printk(KERN_DEBUG "sbmac: not configuring MAC at " "%lx\n", port); @@ -2893,8 +2855,7 @@ sbmac_init_module(void) dev->mem_end = 0; if (sbmac_init(dev, idx)) { port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR), - sbmac_orig_hwaddr[idx]); + __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR)); free_netdev(dev); continue; } From 74b0247fbd4b6ed1693a420d85cf50267d840ef4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 19 Oct 2005 15:40:02 +0100 Subject: [PATCH 0518/1939] [PATCH] sb1250-mac: Whitespace cleanup. Signed-off-by: Ralf Baechle drivers/net/sb1250-mac.c | 1030 +++++++++++++++++++++++------------------------ 1 files changed, 515 insertions(+), 515 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 1036 +++++++++++++++++++------------------- 1 file changed, 518 insertions(+), 518 deletions(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index f7dda6fabe82..d4c8ecdfa4a7 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -10,7 +10,7 @@ * 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. @@ -127,7 +127,7 @@ typedef enum { sbmac_duplex_auto, sbmac_duplex_half, typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; -typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, +typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, sbmac_state_broken } sbmac_state_t; @@ -147,8 +147,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, #define ETHER_ALIGN 2 #define ETHER_ADDR_LEN 6 -#define ENET_PACKET_SIZE 1518 -/*#define ENET_PACKET_SIZE 9216 */ +#define ENET_PACKET_SIZE 1518 +/*#define ENET_PACKET_SIZE 9216 */ /********************************************************************** * DMA Descriptor structure @@ -166,12 +166,12 @@ typedef unsigned long paddr_t; ********************************************************************* */ typedef struct sbmacdma_s { - - /* + + /* * This stuff is used to identify the channel and the registers * associated with it. */ - + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ int sbdma_channel; /* channel number */ int sbdma_txdir; /* direction (1=transmit) */ @@ -186,16 +186,16 @@ typedef struct sbmacdma_s { volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ volatile void __iomem *sbdma_curdscr; /* current descriptor address */ - + /* * This stuff is for maintenance of the ring */ - + sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ - + struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ - + paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ @@ -207,15 +207,15 @@ typedef struct sbmacdma_s { ********************************************************************* */ struct sbmac_softc { - + /* * Linux-specific things */ - + struct net_device *sbm_dev; /* pointer to linux device */ spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ - struct net_device_stats sbm_stats; + struct net_device_stats sbm_stats; int sbm_devflags; /* current device flags */ int sbm_phy_oldbmsr; @@ -223,16 +223,16 @@ struct sbmac_softc { int sbm_phy_oldk1stsr; int sbm_phy_oldlinkstat; int sbm_buffersize; - + unsigned char sbm_phys[2]; - + /* * Controller-specific things */ - + volatile void __iomem *sbm_base; /* MAC's base address */ sbmac_state_t sbm_state; /* current state */ - + volatile void __iomem *sbm_macenable; /* MAC Enable Register */ volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ @@ -241,13 +241,13 @@ struct sbmac_softc { volatile void __iomem *sbm_isr; /* Interrupt status register */ volatile void __iomem *sbm_imr; /* Interrupt mask register */ volatile void __iomem *sbm_mdio; /* MDIO register */ - + sbmac_speed_t sbm_speed; /* current speed */ sbmac_duplex_t sbm_duplex; /* current duplex */ sbmac_fc_t sbm_fc; /* current flow control setting */ - + unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - + sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ sbmacdma_t sbm_rxdma; int rx_hw_checksum; @@ -444,13 +444,13 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; /********************************************************************** * SBMAC_MII_SYNC(s) - * + * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -462,11 +462,11 @@ static void sbmac_mii_sync(struct sbmac_softc *s) int mac_mdio_genc; mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - + bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); - + for (cnt = 0; cnt < 32; cnt++) { __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); @@ -475,11 +475,11 @@ static void sbmac_mii_sync(struct sbmac_softc *s) /********************************************************************** * SBMAC_MII_SENDDATA(s,data,bitcnt) - * + * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * data - data to send * bitcnt - number of bits to send @@ -493,12 +493,12 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc int mac_mdio_genc; mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - + bits = M_MAC_MDIO_DIR_OUTPUT; __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); - + curmask = 1 << (bitcnt - 1); - + for (i = 0; i < bitcnt; i++) { if (data & curmask) bits |= M_MAC_MDIO_OUT; @@ -514,14 +514,14 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc /********************************************************************** * SBMAC_MII_READ(s,phyaddr,regidx) - * + * * Read a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY's address * regidx = index of register to read - * + * * Return value: * value read, or 0 if an error occurred. ********************************************************************* */ @@ -537,9 +537,9 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ - + sbmac_mii_sync(s); - + /* * Send the data to the PHY. The sequence is * a "start" command (2 bits) @@ -547,55 +547,55 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * the PHY addr (5 bits) * the register index (5 bits) */ - + sbmac_mii_senddata(s,MII_COMMAND_START, 2); sbmac_mii_senddata(s,MII_COMMAND_READ, 2); sbmac_mii_senddata(s,phyaddr, 5); sbmac_mii_senddata(s,regidx, 5); - + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - - /* + + /* * Switch the port around without a clock transition. */ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); - + /* * Send out a clock pulse to signal we want the status */ - + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); - - /* + + /* * If an error occurred, the PHY will signal '1' back */ error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; - - /* + + /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); - + regval = 0; - + for (idx = 0; idx < 16; idx++) { regval <<= 1; - + if (error == 0) { if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - + __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); } - + /* Switch back to output */ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); - + if (error == 0) return regval; return 0; @@ -604,15 +604,15 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) /********************************************************************** * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) - * + * * Write a value to a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY to use * regidx - register within the PHY * regval - data to write to register - * + * * Return value: * nothing ********************************************************************* */ @@ -623,7 +623,7 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, int mac_mdio_genc; sbmac_mii_sync(s); - + sbmac_mii_senddata(s,MII_COMMAND_START,2); sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); sbmac_mii_senddata(s,phyaddr, 5); @@ -640,18 +640,18 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, /********************************************************************** * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) - * + * * Initialize a DMA channel context. Since there are potentially * eight DMA channels per MAC, it's nice to do this in a standard - * way. - * - * Input parameters: + * way. + * + * Input parameters: * d - sbmacdma_t structure (DMA channel context) * s - sbmac_softc structure (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors - * + * * Return value: * nothing ********************************************************************* */ @@ -662,14 +662,14 @@ static void sbdma_initctx(sbmacdma_t *d, int txrx, int maxdescr) { - /* - * Save away interesting stuff in the structure + /* + * Save away interesting stuff in the structure */ - + d->sbdma_eth = s; d->sbdma_channel = chan; d->sbdma_txdir = txrx; - + #if 0 /* RMON clearing */ s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; @@ -697,28 +697,28 @@ static void sbdma_initctx(sbmacdma_t *d, __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); - /* - * initialize register pointers + /* + * initialize register pointers */ - - d->sbdma_config0 = + + d->sbdma_config0 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0); - d->sbdma_config1 = + d->sbdma_config1 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1); - d->sbdma_dscrbase = + d->sbdma_dscrbase = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE); - d->sbdma_dscrcnt = + d->sbdma_dscrcnt = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); - d->sbdma_curdscr = + d->sbdma_curdscr = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); - + /* * Allocate memory for the ring */ - + d->sbdma_maxdescr = maxdescr; - - d->sbdma_dscrtable = (sbdmadscr_t *) + + d->sbdma_dscrtable = (sbdmadscr_t *) kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); /* @@ -727,22 +727,22 @@ static void sbdma_initctx(sbmacdma_t *d, */ d->sbdma_dscrtable = (sbdmadscr_t *) ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); - + memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); - + d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; - + d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable); - + /* * And context table */ - - d->sbdma_ctxtable = (struct sk_buff **) + + d->sbdma_ctxtable = (struct sk_buff **) kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL); - + memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); - + #ifdef CONFIG_SBMAC_COALESCE /* * Setup Rx/Tx DMA coalescing defaults @@ -753,7 +753,7 @@ static void sbdma_initctx(sbmacdma_t *d, } else { d->sbdma_int_pktcnt = 1; } - + if ( int_timeout ) { d->sbdma_int_timeout = int_timeout; } else { @@ -765,13 +765,13 @@ static void sbdma_initctx(sbmacdma_t *d, /********************************************************************** * SBDMA_CHANNEL_START(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd * rxtx - DMA_RX or DMA_TX depending on what type of channel - * + * * Return value: * nothing ********************************************************************* */ @@ -781,7 +781,7 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /* * Turn on the DMA channel */ - + #ifdef CONFIG_SBMAC_COALESCE __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | 0, d->sbdma_config1); @@ -807,12 +807,12 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /********************************************************************** * SBDMA_CHANNEL_STOP(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd - * + * * Return value: * nothing ********************************************************************* */ @@ -822,17 +822,17 @@ static void sbdma_channel_stop(sbmacdma_t *d) /* * Turn off the DMA channel */ - + __raw_writeq(0, d->sbdma_config1); - + __raw_writeq(0, d->sbdma_dscrbase); - + __raw_writeq(0, d->sbdma_config0); - + /* * Zero ring pointers */ - + d->sbdma_addptr = NULL; d->sbdma_remptr = NULL; } @@ -841,25 +841,25 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) { unsigned long addr; unsigned long newaddr; - + addr = (unsigned long) skb->data; - + newaddr = (addr + power2 - 1) & ~(power2 - 1); - + skb_reserve(skb,newaddr-addr+offset); } /********************************************************************** * SBDMA_ADD_RCVBUFFER(d,sb) - * + * * Add a buffer to the specified DMA channel. For receive channels, * this queues a buffer for inbound packets. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add, or NULL if we should allocate one - * + * * Return value: * 0 if buffer could not be added (ring is full) * 1 if buffer added successfully @@ -872,24 +872,24 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) sbdmadscr_t *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - /* - * Allocate a sk_buff if we don't already have one. + /* + * Allocate a sk_buff if we don't already have one. * If we do have an sk_buff, reset it so that it's empty. * * Note: sk_buffs don't seem to be guaranteed to have any sort @@ -898,7 +898,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * * 1. the data does not start in the middle of a cache line. * 2. The data does not end in the middle of a cache line - * 3. The buffer can be aligned such that the IP addresses are + * 3. The buffer can be aligned such that the IP addresses are * naturally aligned. * * Remember, the SOCs MAC writes whole cache lines at a time, @@ -906,7 +906,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * data portion starts in the middle of a cache line, the SOC * DMA will trash the beginning (and ending) portions. */ - + if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { @@ -922,16 +922,16 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) } else { sb_new = sb; - /* + /* * nothing special to reinit buffer, it's already aligned * and sb->data already points to a good place. */ } - + /* - * fill in the descriptor + * fill in the descriptor */ - + #ifdef CONFIG_SBMAC_COALESCE /* * Do not interrupt per DMA transfer. @@ -946,38 +946,38 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) /* receiving: no options */ dsc->dscr_b = 0; - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - + __raw_writeq(1, d->sbdma_dscrcnt); - + return 0; /* we did it */ } /********************************************************************** * SBDMA_ADD_TXBUFFER(d,sb) - * + * * Add a transmit buffer to the specified DMA channel, causing a * transmit to start. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add - * + * * Return value: * 0 transmit queued successfully * otherwise error code @@ -991,70 +991,70 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) uint64_t phys; uint64_t ncb; int length; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - + /* * Under Linux, it's not necessary to copy/coalesce buffers * like it is on NetBSD. We think they're all contiguous, * but that may not be true for GBE. */ - + length = sb->len; - + /* * fill in the descriptor. Note that the number of cache * blocks in the descriptor is the number of blocks * *spanned*, so we need to add in the offset (if any) * while doing the calculation. */ - + phys = virt_to_phys(sb->data); ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1))); - dsc->dscr_a = phys | + dsc->dscr_a = phys | V_DMA_DSCRA_A_SIZE(ncb) | #ifndef CONFIG_SBMAC_COALESCE M_DMA_DSCRA_INTERRUPT | #endif M_DMA_ETHTX_SOP; - + /* transmitting: set outbound options and length */ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | V_DMA_DSCRB_PKT_SIZE(length); - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - + __raw_writeq(1, d->sbdma_dscrcnt); - + return 0; /* we did it */ } @@ -1063,12 +1063,12 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) /********************************************************************** * SBDMA_EMPTYRING(d) - * + * * Free all allocated sk_buffs on the specified DMA channel; - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1077,7 +1077,7 @@ static void sbdma_emptyring(sbmacdma_t *d) { int idx; struct sk_buff *sb; - + for (idx = 0; idx < d->sbdma_maxdescr; idx++) { sb = d->sbdma_ctxtable[idx]; if (sb) { @@ -1090,13 +1090,13 @@ static void sbdma_emptyring(sbmacdma_t *d) /********************************************************************** * SBDMA_FILLRING(d) - * + * * Fill the specified DMA channel (must be receive channel) * with sk_buffs - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1104,7 +1104,7 @@ static void sbdma_emptyring(sbmacdma_t *d) static void sbdma_fillring(sbmacdma_t *d) { int idx; - + for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { if (sbdma_add_rcvbuffer(d,NULL) != 0) break; @@ -1114,16 +1114,16 @@ static void sbdma_fillring(sbmacdma_t *d) /********************************************************************** * SBDMA_RX_PROCESS(sc,d) - * - * Process "completed" receive buffers on the specified DMA channel. - * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. * - * Input parameters: + * Process "completed" receive buffers on the specified DMA channel. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. + * + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1135,56 +1135,56 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sbdmadscr_t *dsc; struct sk_buff *sb; int len; - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - + /* * If they're the same, that means we've processed all * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4; - + /* * Check packet status. If good, process it. * If not, silently drop it and put it back on the * receive ring. */ - + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { - + /* * Add a new buffer to replace the old one. If we fail * to allocate a buffer, we're going to drop this * packet and put it right back on the receive ring. */ - + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { sc->sbm_stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ @@ -1193,7 +1193,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) * Set length into the packet */ skb_put(sb,len); - + /* * Buffer has been replaced on the * receive ring. Pass the buffer to @@ -1212,7 +1212,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sb->ip_summed = CHECKSUM_NONE; } } - + netif_rx(sb); } } else { @@ -1223,14 +1223,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sc->sbm_stats.rx_errors++; sbdma_add_rcvbuffer(d,sb); } - - - /* + + + /* * .. and advance to the next buffer. */ - + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } } @@ -1238,17 +1238,17 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) /********************************************************************** * SBDMA_TX_PROCESS(sc,d) - * - * Process "completed" transmit buffers on the specified DMA channel. + * + * Process "completed" transmit buffers on the specified DMA channel. * This is normally called within the interrupt service routine. * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. + * it processes all of the packets on a given channel before + * returning. * - * Input parameters: + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1262,19 +1262,19 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) unsigned long flags; spin_lock_irqsave(&(sc->sbm_lock), flags); - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); @@ -1284,75 +1284,75 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + /* * Stats */ - + sc->sbm_stats.tx_bytes += sb->len; sc->sbm_stats.tx_packets++; - + /* * for transmits, we just free buffers. */ - + dev_kfree_skb_irq(sb); - - /* + + /* * .. and advance to the next buffer. */ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } - + /* * Decide if we should wake up the protocol or not. * Other drivers seem to do this when we reach a low * watermark on the transmit queue. */ - + netif_wake_queue(d->sbdma_eth->sbm_dev); - + spin_unlock_irqrestore(&(sc->sbm_lock), flags); - + } /********************************************************************** * SBMAC_INITCTX(s) - * + * * Initialize an Ethernet context structure - this is called * once per MAC on the 1250. Memory is allocated here, so don't * call it again from inside the ioctl routines that bring the * interface up/down - * - * Input parameters: + * + * Input parameters: * s - sbmac context structure - * + * * Return value: * 0 ********************************************************************* */ static int sbmac_initctx(struct sbmac_softc *s) { - - /* - * figure out the addresses of some ports + + /* + * figure out the addresses of some ports */ - + s->sbm_macenable = s->sbm_base + R_MAC_ENABLE; s->sbm_maccfg = s->sbm_base + R_MAC_CFG; s->sbm_fifocfg = s->sbm_base + R_MAC_THRSH_CFG; @@ -1369,29 +1369,29 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_phy_oldanlpar = 0; s->sbm_phy_oldk1stsr = 0; s->sbm_phy_oldlinkstat = 0; - + /* * Initialize the DMA channels. Right now, only one per MAC is used * Note: Only do this _once_, as it allocates memory from the kernel! */ - + sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR); sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR); - + /* * initial state is OFF */ - + s->sbm_state = sbmac_state_off; - + /* * Initial speed is (XXX TEMP) 10MBit/s HDX no FC */ - + s->sbm_speed = sbmac_speed_10; s->sbm_duplex = sbmac_duplex_half; s->sbm_fc = sbmac_fc_disabled; - + return 0; } @@ -1402,7 +1402,7 @@ static void sbdma_uninitctx(struct sbmacdma_s *d) kfree(d->sbdma_dscrtable); d->sbdma_dscrtable = NULL; } - + if (d->sbdma_ctxtable) { kfree(d->sbdma_ctxtable); d->sbdma_ctxtable = NULL; @@ -1419,12 +1419,12 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) /********************************************************************** * SBMAC_CHANNEL_START(s) - * + * * Start packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1435,46 +1435,46 @@ static void sbmac_channel_start(struct sbmac_softc *s) volatile void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; - + /* * Don't do this if running */ if (s->sbm_state == sbmac_state_on) return; - + /* * Bring the controller out of reset, but leave it off. */ - + __raw_writeq(0, s->sbm_macenable); - + /* * Ignore all received packets */ - + __raw_writeq(0, s->sbm_rxfilter); - - /* + + /* * Calculate values for various control registers. */ - + cfg = M_MAC_RETRY_EN | - M_MAC_TX_HOLD_SOP_EN | + M_MAC_TX_HOLD_SOP_EN | V_MAC_TX_PAUSE_CNT_16K | M_MAC_AP_STAT_EN | M_MAC_FAST_SYNC | M_MAC_SS_EN | 0; - - /* + + /* * Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above * Use a larger RD_THRSH for gigabit */ - if (periph_rev >= 2) + if (periph_rev >= 2) th_value = 64; - else + else th_value = 28; fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ @@ -1492,29 +1492,29 @@ static void sbmac_channel_start(struct sbmac_softc *s) V_MAC_BACKOFF_SEL(1); /* - * Clear out the hash address map + * Clear out the hash address map */ - + port = s->sbm_base + R_MAC_HASH_BASE; for (idx = 0; idx < MAC_HASH_COUNT; idx++) { __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the exact-match table */ - + port = s->sbm_base + R_MAC_ADDR_BASE; for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the DMA Channel mapping table registers */ - + port = s->sbm_base + R_MAC_CHUP0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { __raw_writeq(0, port); @@ -1527,14 +1527,14 @@ static void sbmac_channel_start(struct sbmac_softc *s) __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Program the hardware address. It goes into the hardware-address * register as well as the first filter register. */ - + reg = sbmac_addr2reg(s->sbm_hwaddr); - + port = s->sbm_base + R_MAC_ADDR_BASE; __raw_writeq(reg, port); port = s->sbm_base + R_MAC_ETHERNET_ADDR; @@ -1549,48 +1549,48 @@ static void sbmac_channel_start(struct sbmac_softc *s) #else __raw_writeq(reg, port); #endif - + /* * Set the receive filter for no packets, and write values * to the various config registers */ - + __raw_writeq(0, s->sbm_rxfilter); __raw_writeq(0, s->sbm_imr); __raw_writeq(framecfg, s->sbm_framecfg); __raw_writeq(fifo, s->sbm_fifocfg); __raw_writeq(cfg, s->sbm_maccfg); - + /* * Initialize DMA channels (rings should be ok now) */ - + sbdma_channel_start(&(s->sbm_rxdma), DMA_RX); sbdma_channel_start(&(s->sbm_txdma), DMA_TX); - + /* * Configure the speed, duplex, and flow control */ sbmac_set_speed(s,s->sbm_speed); sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc); - + /* * Fill the receive ring */ - + sbdma_fillring(&(s->sbm_rxdma)); - - /* + + /* * Turn on the rest of the bits in the enable register - */ - + */ + __raw_writeq(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0 | M_MAC_RX_ENABLE | M_MAC_TX_ENABLE, s->sbm_macenable); - - + + #ifdef CONFIG_SBMAC_COALESCE @@ -1606,44 +1606,44 @@ static void sbmac_channel_start(struct sbmac_softc *s) __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); #endif - - /* - * Enable receiving unicasts and broadcasts - */ - - __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter); - + /* - * we're running now. + * Enable receiving unicasts and broadcasts */ - + + __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter); + + /* + * we're running now. + */ + s->sbm_state = sbmac_state_on; - - /* - * Program multicast addresses + + /* + * Program multicast addresses */ - + sbmac_setmulti(s); - - /* - * If channel was in promiscuous mode before, turn that on + + /* + * If channel was in promiscuous mode before, turn that on */ - + if (s->sbm_devflags & IFF_PROMISC) { sbmac_promiscuous_mode(s,1); } - + } /********************************************************************** * SBMAC_CHANNEL_STOP(s) - * + * * Stop packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1651,49 +1651,49 @@ static void sbmac_channel_start(struct sbmac_softc *s) static void sbmac_channel_stop(struct sbmac_softc *s) { /* don't do this if already stopped */ - + if (s->sbm_state == sbmac_state_off) return; - + /* don't accept any packets, disable all interrupts */ - + __raw_writeq(0, s->sbm_rxfilter); __raw_writeq(0, s->sbm_imr); - + /* Turn off ticker */ - + /* XXX */ - + /* turn off receiver and transmitter */ - + __raw_writeq(0, s->sbm_macenable); - + /* We're stopped now. */ - + s->sbm_state = sbmac_state_off; - + /* * Stop DMA channels (rings should be ok now) */ - + sbdma_channel_stop(&(s->sbm_rxdma)); sbdma_channel_stop(&(s->sbm_txdma)); - + /* Empty the receive and transmit rings */ - + sbdma_emptyring(&(s->sbm_rxdma)); sbdma_emptyring(&(s->sbm_txdma)); - + } /********************************************************************** * SBMAC_SET_CHANNEL_STATE(state) - * + * * Set the channel's state ON or OFF - * - * Input parameters: + * + * Input parameters: * state - new state - * + * * Return value: * old state ********************************************************************* */ @@ -1701,43 +1701,43 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, sbmac_state_t state) { sbmac_state_t oldstate = sc->sbm_state; - + /* * If same as previous state, return */ - + if (state == oldstate) { return oldstate; } - + /* - * If new state is ON, turn channel on + * If new state is ON, turn channel on */ - + if (state == sbmac_state_on) { sbmac_channel_start(sc); } else { sbmac_channel_stop(sc); } - + /* * Return previous state */ - + return oldstate; } /********************************************************************** * SBMAC_PROMISCUOUS_MODE(sc,onoff) - * + * * Turn on or off promiscuous mode - * - * Input parameters: + * + * Input parameters: * sc - softc * onoff - 1 to turn on, 0 to turn off - * + * * Return value: * nothing ********************************************************************* */ @@ -1745,15 +1745,15 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) { uint64_t reg; - + if (sc->sbm_state != sbmac_state_on) return; - + if (onoff) { reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_ALLPKT_EN; __raw_writeq(reg, sc->sbm_rxfilter); - } + } else { reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_ALLPKT_EN; @@ -1763,12 +1763,12 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) /********************************************************************** * SBMAC_SETIPHDR_OFFSET(sc,onoff) - * + * * Set the iphdr offset as 15 assuming ethernet encapsulation - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -1776,12 +1776,12 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) { uint64_t reg; - + /* Hard code the off set to 15 for now */ reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15); __raw_writeq(reg, sc->sbm_rxfilter); - + /* read system identification to determine revision */ if (periph_rev >= 2) { sc->rx_hw_checksum = ENABLE; @@ -1793,13 +1793,13 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) /********************************************************************** * SBMAC_ADDR2REG(ptr) - * + * * Convert six bytes into the 64-bit register value that * we typically write into the SBMAC's address/mcast registers - * - * Input parameters: + * + * Input parameters: * ptr - pointer to 6 bytes - * + * * Return value: * register value ********************************************************************* */ @@ -1807,35 +1807,35 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) static uint64_t sbmac_addr2reg(unsigned char *ptr) { uint64_t reg = 0; - + ptr += 6; - - reg |= (uint64_t) *(--ptr); + + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); - + reg |= (uint64_t) *(--ptr); + return reg; } /********************************************************************** * SBMAC_SET_SPEED(s,speed) - * + * * Configure LAN speed for the specified MAC. * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * speed - speed to set MAC to (see sbmac_speed_t enum) - * + * * Return value: * 1 if successful * 0 indicates invalid parameters @@ -1849,31 +1849,31 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) /* * Save new current values */ - + s->sbm_speed = speed; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ /* - * Read current register values + * Read current register values */ - + cfg = __raw_readq(s->sbm_maccfg); framecfg = __raw_readq(s->sbm_framecfg); - + /* * Mask out the stuff we want to change */ - + cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL); framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH | M_MAC_SLOT_SIZE); - + /* * Now add in the new bits */ - + switch (speed) { case sbmac_speed_10: framecfg |= V_MAC_IFG_RX_10 | @@ -1882,7 +1882,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_10; cfg |= V_MAC_SPEED_SEL_10MBPS; break; - + case sbmac_speed_100: framecfg |= V_MAC_IFG_RX_100 | V_MAC_IFG_TX_100 | @@ -1890,7 +1890,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_100; cfg |= V_MAC_SPEED_SEL_100MBPS ; break; - + case sbmac_speed_1000: framecfg |= V_MAC_IFG_RX_1000 | V_MAC_IFG_TX_1000 | @@ -1898,34 +1898,34 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_1000; cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; break; - + case sbmac_speed_auto: /* XXX not implemented */ /* fall through */ default: return 0; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - + __raw_writeq(framecfg, s->sbm_framecfg); __raw_writeq(cfg, s->sbm_maccfg); - + return 1; } /********************************************************************** * SBMAC_SET_DUPLEX(s,duplex,fc) - * + * * Set Ethernet duplex and flow control options for this MAC * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * duplex - duplex setting (see sbmac_duplex_t) * fc - flow control setting (see sbmac_fc_t) - * + * * Return value: * 1 if ok * 0 if an invalid parameter combination was specified @@ -1934,67 +1934,67 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) { uint64_t cfg; - + /* * Save new current values */ - + s->sbm_duplex = duplex; s->sbm_fc = fc; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ - + /* - * Read current register values + * Read current register values */ - + cfg = __raw_readq(s->sbm_maccfg); - + /* * Mask off the stuff we're about to change */ - + cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN); - - + + switch (duplex) { case sbmac_duplex_half: switch (fc) { case sbmac_fc_disabled: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_collision: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_carrier: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; break; - + case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ case sbmac_fc_frame: /* not valid in half duplex */ default: /* invalid selection */ return 0; } break; - + case sbmac_duplex_full: switch (fc) { case sbmac_fc_disabled: cfg |= V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_frame: cfg |= V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_collision: /* not valid in full duplex */ case sbmac_fc_carrier: /* not valid in full duplex */ case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ default: return 0; } @@ -2003,13 +2003,13 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /* XXX not implemented */ break; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - + __raw_writeq(cfg, s->sbm_maccfg); - + return 1; } @@ -2018,12 +2018,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /********************************************************************** * SBMAC_INTR() - * + * * Interrupt handler for MAC interrupts - * - * Input parameters: + * + * Input parameters: * MAC structure - * + * * Return value: * nothing ********************************************************************* */ @@ -2035,27 +2035,27 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) int handled = 0; for (;;) { - + /* * Read the ISR (this clears the bits in the real * register, except for counter addr) */ - + isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; - + if (isr == 0) break; handled = 1; - + /* * Transmits on channel 0 */ - + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { sbdma_tx_process(sc,&(sc->sbm_txdma)); } - + /* * Receives on channel 0 */ @@ -2075,8 +2075,8 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) * EOP_SEEN here takes care of this case. * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0) */ - - + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { sbdma_rx_process(sc,&(sc->sbm_rxdma)); } @@ -2087,29 +2087,29 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) /********************************************************************** * SBMAC_START_TX(skb,dev) - * - * Start output on the specified interface. Basically, we + * + * Start output on the specified interface. Basically, we * queue as many buffers as we can until the ring fills up, or * we run off the end of the queue, whichever comes first. - * - * Input parameters: - * - * + * + * Input parameters: + * + * * Return value: * nothing ********************************************************************* */ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + /* lock eth irq */ spin_lock_irq (&sc->sbm_lock); - + /* - * Put the buffer on the transmit ring. If we + * Put the buffer on the transmit ring. If we * don't have room, stop the queue. */ - + if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { /* XXX save skb that we could not send */ netif_stop_queue(dev); @@ -2117,24 +2117,24 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) return 1; } - + dev->trans_start = jiffies; - + spin_unlock_irq (&sc->sbm_lock); - + return 0; } /********************************************************************** * SBMAC_SETMULTI(sc) - * + * * Reprogram the multicast table into the hardware, given * the list of multicasts associated with the interface * structure. - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -2146,52 +2146,52 @@ static void sbmac_setmulti(struct sbmac_softc *sc) int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; - - /* + + /* * Clear out entire multicast table. We do this by nuking * the entire hash table and all the direct matches except - * the first one, which is used for our station address + * the first one, which is used for our station address */ - + for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)); __raw_writeq(0, port); } - + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)); __raw_writeq(0, port); } - + /* * Clear the filter to say we don't want any multicasts. */ - + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); __raw_writeq(reg, sc->sbm_rxfilter); - + if (dev->flags & IFF_ALLMULTI) { - /* - * Enable ALL multicasts. Do this by inverting the - * multicast enable bit. + /* + * Enable ALL multicasts. Do this by inverting the + * multicast enable bit. */ reg = __raw_readq(sc->sbm_rxfilter); reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); __raw_writeq(reg, sc->sbm_rxfilter); return; } - - /* + + /* * Progam new multicast entries. For now, only use the * perfect filter. In the future we'll need to use the * hash filter if the perfect filter overflows */ - + /* XXX only using perfect filter for now, need to use hash * XXX if the table overflows */ - + idx = 1; /* skip station address */ mclist = dev->mc_list; while (mclist && (idx < MAC_ADDR_COUNT)) { @@ -2201,12 +2201,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc) idx++; mclist = mclist->next; } - - /* + + /* * Enable the "accept multicast bits" if we programmed at least one - * multicast. + * multicast. */ - + if (idx > 1) { reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_MCAST_EN; @@ -2219,12 +2219,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc) #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) /********************************************************************** * SBMAC_PARSE_XDIGIT(str) - * + * * Parse a hex digit, returning its value - * - * Input parameters: + * + * Input parameters: * str - character - * + * * Return value: * hex value, or -1 if invalid ********************************************************************* */ @@ -2232,7 +2232,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc) static int sbmac_parse_xdigit(char str) { int digit; - + if ((str >= '0') && (str <= '9')) digit = str - '0'; else if ((str >= 'a') && (str <= 'f')) @@ -2241,20 +2241,20 @@ static int sbmac_parse_xdigit(char str) digit = str - 'A' + 10; else return -1; - + return digit; } /********************************************************************** * SBMAC_PARSE_HWADDR(str,hwaddr) - * + * * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte * Ethernet address. - * - * Input parameters: + * + * Input parameters: * str - string * hwaddr - pointer to hardware address - * + * * Return value: * 0 if ok, else -1 ********************************************************************* */ @@ -2263,7 +2263,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) { int digit1,digit2; int idx = 6; - + while (*str && (idx > 0)) { digit1 = sbmac_parse_xdigit(*str); if (digit1 < 0) @@ -2271,7 +2271,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) str++; if (!*str) return -1; - + if ((*str == ':') || (*str == '-')) { digit2 = digit1; digit1 = 0; @@ -2282,10 +2282,10 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) return -1; str++; } - + *hwaddr++ = (digit1 << 4) | digit2; idx--; - + if (*str == '-') str++; if (*str == ':') @@ -2306,12 +2306,12 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) /********************************************************************** * SBMAC_INIT(dev) - * + * * Attach routine - init hardware and hook ourselves into linux - * - * Input parameters: + * + * Input parameters: * dev - net_device structure - * + * * Return value: * status ********************************************************************* */ @@ -2323,53 +2323,53 @@ static int sbmac_init(struct net_device *dev, int idx) uint64_t ea_reg; int i; int err; - + sc = netdev_priv(dev); - + /* Determine controller base address */ - + sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; - + eaddr = sc->sbm_hwaddr; - - /* + + /* * Read the ethernet address. The firwmare left this programmed * for us in the ethernet address register for each mac. */ - + ea_reg = __raw_readq(sc->sbm_base + R_MAC_ETHERNET_ADDR); __raw_writeq(0, sc->sbm_base + R_MAC_ETHERNET_ADDR); for (i = 0; i < 6; i++) { eaddr[i] = (uint8_t) (ea_reg & 0xFF); ea_reg >>= 8; } - + for (i = 0; i < 6; i++) { dev->dev_addr[i] = eaddr[i]; } - - + + /* - * Init packet size + * Init packet size */ - + sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN; - /* + /* * Initialize context (get pointers to registers and stuff), then * allocate the memory for the descriptor tables. */ - + sbmac_initctx(sc); - + /* * Set up Linux device callins */ - + spin_lock_init(&(sc->sbm_lock)); - + dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2399,10 +2399,10 @@ static int sbmac_init(struct net_device *dev, int idx) * was being displayed) */ printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", + "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, dev->base_addr, eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - + return 0; @@ -2416,12 +2416,12 @@ static int sbmac_init(struct net_device *dev, int idx) static int sbmac_open(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + if (debug > 1) { printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); } - - /* + + /* * map/route interrupt (clear status first, in case something * weird is pending; we haven't initialized the mac registers * yet) @@ -2432,35 +2432,35 @@ static int sbmac_open(struct net_device *dev) return -EBUSY; /* - * Configure default speed + * Configure default speed */ sbmac_mii_poll(sc,noisy_mii); - + /* * Turn on the channel */ sbmac_set_channel_state(sc,sbmac_state_on); - + /* * XXX Station address is in dev->dev_addr */ - + if (dev->if_port == 0) - dev->if_port = 0; - + dev->if_port = 0; + netif_start_queue(dev); - + sbmac_set_rx_mode(dev); - + /* Set the timer to check for link beat. */ init_timer(&sc->sbm_timer); sc->sbm_timer.expires = jiffies + 2 * HZ/100; sc->sbm_timer.data = (unsigned long)dev; sc->sbm_timer.function = &sbmac_timer; add_timer(&sc->sbm_timer); - + return 0; } @@ -2578,20 +2578,20 @@ static void sbmac_timer(unsigned long data) int mii_status; spin_lock_irq (&sc->sbm_lock); - + /* make IFF_RUNNING follow the MII status bit "Link established" */ mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); - + if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; if (mii_status & BMSR_LINKSTAT) { netif_carrier_on(dev); } else { - netif_carrier_off(dev); + netif_carrier_off(dev); } } - + /* * Poll the PHY to see what speed we should be running at */ @@ -2609,9 +2609,9 @@ static void sbmac_timer(unsigned long data) sbmac_channel_start(sc); } } - + spin_unlock_irq (&sc->sbm_lock); - + sc->sbm_timer.expires = jiffies + next_tick; add_timer(&sc->sbm_timer); } @@ -2620,13 +2620,13 @@ static void sbmac_timer(unsigned long data) static void sbmac_tx_timeout (struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + spin_lock_irq (&sc->sbm_lock); - - + + dev->trans_start = jiffies; sc->sbm_stats.tx_errors++; - + spin_unlock_irq (&sc->sbm_lock); printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); @@ -2639,13 +2639,13 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; - + spin_lock_irqsave(&sc->sbm_lock, flags); - + /* XXX update other stats here */ - + spin_unlock_irqrestore(&sc->sbm_lock, flags); - + return &sc->sbm_stats; } @@ -2662,8 +2662,8 @@ static void sbmac_set_rx_mode(struct net_device *dev) /* * Promiscuous changed. */ - - if (dev->flags & IFF_PROMISC) { + + if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ msg_flag = 1; sbmac_promiscuous_mode(sc,1); @@ -2674,18 +2674,18 @@ static void sbmac_set_rx_mode(struct net_device *dev) } } spin_unlock_irqrestore(&sc->sbm_lock, flags); - + if (msg_flag) { printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis"); } - + /* * Program the multicasts. Do this every time. */ - + sbmac_setmulti(sc); - + } static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -2694,10 +2694,10 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) u16 *data = (u16 *)&rq->ifr_ifru; unsigned long flags; int retval; - + spin_lock_irqsave(&sc->sbm_lock, flags); retval = 0; - + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = sc->sbm_phys[0] & 0x1f; @@ -2719,7 +2719,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) default: retval = -EOPNOTSUPP; } - + spin_unlock_irqrestore(&sc->sbm_lock, flags); return retval; } @@ -2750,7 +2750,7 @@ static int sbmac_close(struct net_device *dev) sbdma_emptyring(&(sc->sbm_txdma)); sbdma_emptyring(&(sc->sbm_rxdma)); - + return 0; } @@ -2781,7 +2781,7 @@ sbmac_init_module(void) struct net_device *dev; unsigned long port; int chip_max_units; - + /* * For bringup when not using the firmware, we can pre-fill * the MAC addresses using the environment variables @@ -2827,7 +2827,7 @@ sbmac_init_module(void) port = A_MAC_CHANNEL_BASE(idx); - /* + /* * The R_MAC_ETHERNET_ADDR register will be set to some nonzero * value for us by the firmware if we're going to use this MAC. * If we find a zero, skip this MAC. @@ -2845,7 +2845,7 @@ sbmac_init_module(void) */ dev = alloc_etherdev(sizeof(struct sbmac_softc)); - if (!dev) + if (!dev) return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); From f7f6f4fea68d9981d65f99a589ad85f510924d99 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2005 14:53:32 +1000 Subject: [PATCH 0519/1939] [PATCH] powerpc: Merge ppc64 pmc.[ch] with ppc32 perfmon.[ch] This patches the ppc32 and ppc64 versions of the headers and .c files with helper functions for manipulating the performance counting hardware. As a side effect, it removes use of the term "perfmon" from ppc32, thus avoiding confusion with the unrelated performance counter interface from HP Labs also called "perfmon". Built, but not booted, for g5, pSeries, iSeries, and 32-bit Powermac with both ARCH=powerpc and ARCH=ppc{,64} as appropriate. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/{ppc64 => powerpc}/kernel/pmc.c | 26 +++++- arch/powerpc/kernel/traps.c | 3 +- arch/powerpc/oprofile/common.c | 4 - arch/powerpc/oprofile/op_model_fsl_booke.c | 2 +- arch/ppc/kernel/Makefile | 4 +- arch/ppc/kernel/perfmon.c | 96 ---------------------- arch/ppc/kernel/perfmon_fsl_booke.c | 2 +- arch/ppc/kernel/traps.c | 2 +- arch/ppc64/kernel/Makefile | 2 +- include/{asm-ppc64 => asm-powerpc}/pmc.h | 21 ++++- include/asm-ppc/perfmon.h | 22 ----- 12 files changed, 51 insertions(+), 135 deletions(-) rename arch/{ppc64 => powerpc}/kernel/pmc.c (76%) delete mode 100644 arch/ppc/kernel/perfmon.c rename include/{asm-ppc64 => asm-powerpc}/pmc.h (66%) delete mode 100644 include/asm-ppc/perfmon.h diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b347ac320252..6b0f176265e3 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -11,7 +11,7 @@ CFLAGS_btext.o += -fPIC endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ - signal_32.o + signal_32.o pmc.o obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o diff --git a/arch/ppc64/kernel/pmc.c b/arch/powerpc/kernel/pmc.c similarity index 76% rename from arch/ppc64/kernel/pmc.c rename to arch/powerpc/kernel/pmc.c index 944d7df7935f..2d333cc84082 100644 --- a/arch/ppc64/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -1,7 +1,10 @@ /* - * linux/arch/ppc64/kernel/pmc.c + * arch/powerpc/kernel/pmc.c * * Copyright (C) 2004 David Gibson, IBM Corporation. + * Includes code formerly from arch/ppc/kernel/perfmon.c: + * Author: Andy Fleming + * Copyright (c) 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 @@ -17,6 +20,20 @@ #include #include +#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200) +static void dummy_perf(struct pt_regs *regs) +{ + unsigned int pmgc0 = mfpmr(PMRN_PMGC0); + + pmgc0 &= ~PMGC0_PMIE; + mtpmr(PMRN_PMGC0, pmgc0); +} +#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) + +#ifndef MMCR0_PMAO +#define MMCR0_PMAO 0 +#endif + /* Ensure exceptions are disabled */ static void dummy_perf(struct pt_regs *regs) { @@ -25,6 +42,11 @@ static void dummy_perf(struct pt_regs *regs) mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); mtspr(SPRN_MMCR0, mmcr0); } +#else +static void dummy_perf(struct pt_regs *regs) +{ +} +#endif static DEFINE_SPINLOCK(pmc_owner_lock); static void *pmc_owner_caller; /* mostly for debugging */ @@ -66,6 +88,7 @@ void release_pmc_hardware(void) } EXPORT_SYMBOL_GPL(release_pmc_hardware); +#ifdef CONFIG_PPC64 void power4_enable_pmcs(void) { unsigned long hid0; @@ -86,3 +109,4 @@ void power4_enable_pmcs(void) "isync" : "=&r" (hid0) : "i" (SPRN_HID0), "0" (hid0): "memory"); } +#endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6a881e3ea01d..f87580382da4 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -40,9 +40,9 @@ #include #include #include +#include #ifdef CONFIG_PPC32 #include -#include #endif #ifdef CONFIG_PMAC_BACKLIGHT #include @@ -51,7 +51,6 @@ #include #include #include -#include #endif #ifdef CONFIG_PPC64 /* XXX */ diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 0ec12c8f2c01..af2c05d20ba5 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -22,11 +22,7 @@ #include #include #include -#ifdef __powerpc64__ #include -#else /* __powerpc64__ */ -#include -#endif /* __powerpc64__ */ #include #include diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c index 1917f8df8a8b..86124a94c9af 100644 --- a/arch/powerpc/oprofile/op_model_fsl_booke.c +++ b/arch/powerpc/oprofile/op_model_fsl_booke.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include static unsigned long reset_value[OP_MAX_COUNTER]; diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index ccbc442c9ed3..b35346df1e37 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -15,7 +15,7 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o align.o \ setup.o \ - ppc_htab.o perfmon.o + ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o @@ -38,7 +38,7 @@ endif else obj-y := irq.o idle.o \ - align.o perfmon.o + align.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c deleted file mode 100644 index c9a38dd0cdc4..000000000000 --- a/arch/ppc/kernel/perfmon.c +++ /dev/null @@ -1,96 +0,0 @@ -/* kernel/perfmon.c - * PPC 32 Performance Monitor Infrastructure - * - * Author: Andy Fleming - * Copyright (c) 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* A lock to regulate grabbing the interrupt */ -DEFINE_SPINLOCK(perfmon_lock); - -#if defined (CONFIG_FSL_BOOKE) && !defined (CONFIG_E200) -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int pmgc0 = mfpmr(PMRN_PMGC0); - - pmgc0 &= ~PMGC0_PMIE; - mtpmr(PMRN_PMGC0, pmgc0); -} - -#elif defined(CONFIG_6xx) -/* Ensure exceptions are disabled */ -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~MMCR0_PMXE; - mtspr(SPRN_MMCR0, mmcr0); -} -#else -static void dummy_perf(struct pt_regs *regs) -{ -} -#endif - -void (*perf_irq)(struct pt_regs *) = dummy_perf; - -/* Grab the interrupt, if it's free. - * Returns 0 on success, -1 if the interrupt is taken already */ -int reserve_pmc_hardware(void (*handler)(struct pt_regs *)) -{ - int err = 0; - - spin_lock(&perfmon_lock); - - if (perf_irq == dummy_perf) - perf_irq = handler; - else { - pr_info("perfmon irq already handled by %p\n", perf_irq); - err = -EBUSY; - } - - spin_unlock(&perfmon_lock); - - return err; -} - -void release_pmc_hardware(void) -{ - spin_lock(&perfmon_lock); - - perf_irq = dummy_perf; - - spin_unlock(&perfmon_lock); -} - -EXPORT_SYMBOL(perf_irq); -EXPORT_SYMBOL(reserve_pmc_hardware); -EXPORT_SYMBOL(release_pmc_hardware); diff --git a/arch/ppc/kernel/perfmon_fsl_booke.c b/arch/ppc/kernel/perfmon_fsl_booke.c index 03526bfb0840..32455dfcc36b 100644 --- a/arch/ppc/kernel/perfmon_fsl_booke.c +++ b/arch/ppc/kernel/perfmon_fsl_booke.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include static inline u32 get_pmlca(int ctr); static inline void set_pmlca(int ctr, u32 pmlca); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 3145e9773db9..5e4bf88a1ef5 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -41,7 +41,7 @@ #ifdef CONFIG_PMAC_BACKLIGHT #include #endif -#include +#include #ifdef CONFIG_XMON extern int xmon_bpt(struct pt_regs *regs); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 18f477fa1df2..6cce419f4b09 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -17,7 +17,7 @@ obj-y += irq.o idle.o dma.o \ udbg.o ioctl32.o \ rtc.o \ cpu_setup_power4.o \ - iommu.o sysfs.o vdso.o pmc.o firmware.o + iommu.o sysfs.o vdso.o firmware.o obj-y += vdso32/ vdso64/ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o diff --git a/include/asm-ppc64/pmc.h b/include/asm-powerpc/pmc.h similarity index 66% rename from include/asm-ppc64/pmc.h rename to include/asm-powerpc/pmc.h index d1d297dbccfe..2f3c3fc2b796 100644 --- a/include/asm-ppc64/pmc.h +++ b/include/asm-powerpc/pmc.h @@ -16,8 +16,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PPC64_PMC_H -#define _PPC64_PMC_H +#ifndef _POWERPC_PMC_H +#define _POWERPC_PMC_H #include @@ -26,6 +26,21 @@ typedef void (*perf_irq_t)(struct pt_regs *); int reserve_pmc_hardware(perf_irq_t new_perf_irq); void release_pmc_hardware(void); +#ifdef CONFIG_PPC64 void power4_enable_pmcs(void); +#endif -#endif /* _PPC64_PMC_H */ +#ifdef CONFIG_FSL_BOOKE +void init_pmc_stop(int ctr); +void set_pmc_event(int ctr, int event); +void set_pmc_user_kernel(int ctr, int user, int kernel); +void set_pmc_marked(int ctr, int mark0, int mark1); +void pmc_start_ctr(int ctr, int enable); +void pmc_start_ctrs(int enable); +void pmc_stop_ctrs(void); +void dump_pmcs(void); + +extern struct op_powerpc_model op_model_fsl_booke; +#endif + +#endif /* _POWERPC_PMC_H */ diff --git a/include/asm-ppc/perfmon.h b/include/asm-ppc/perfmon.h deleted file mode 100644 index 2ae031594a4e..000000000000 --- a/include/asm-ppc/perfmon.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __PERFMON_H -#define __PERFMON_H - -extern void (*perf_irq)(struct pt_regs *); - -int reserve_pmc_hardware(void (*handler)(struct pt_regs *)); -void release_pmc_hardware(void); - -#ifdef CONFIG_FSL_BOOKE -void init_pmc_stop(int ctr); -void set_pmc_event(int ctr, int event); -void set_pmc_user_kernel(int ctr, int user, int kernel); -void set_pmc_marked(int ctr, int mark0, int mark1); -void pmc_start_ctr(int ctr, int enable); -void pmc_start_ctrs(int enable); -void pmc_stop_ctrs(void); -void dump_pmcs(void); - -extern struct op_powerpc_model op_model_fsl_booke; -#endif - -#endif /* __PERFMON_H */ From 971dc77b64db9466f5caab56019e62a93c0ddfc5 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Wed, 19 Oct 2005 18:45:03 -0500 Subject: [PATCH 0520/1939] [PATCH] powerpc: Merge types.h This patch merges types.h into include/asm-powerpc. The only real change is the removal of the include of linux/config.h from the 32-bit version - it doesn't appear to be necessary. This patch has been built on several different 32 and 64-bit platforms, and booted on mpc8540_ads. Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/types.h | 31 +++++++++- include/asm-ppc/types.h | 69 ---------------------- 2 files changed, 28 insertions(+), 72 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/types.h (74%) delete mode 100644 include/asm-ppc/types.h diff --git a/include/asm-ppc64/types.h b/include/asm-powerpc/types.h similarity index 74% rename from include/asm-ppc64/types.h rename to include/asm-powerpc/types.h index bf294c1761b2..7d803cb547bb 100644 --- a/include/asm-ppc64/types.h +++ b/include/asm-powerpc/types.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_TYPES_H -#define _PPC64_TYPES_H +#ifndef _ASM_POWERPC_TYPES_H +#define _ASM_POWERPC_TYPES_H #ifndef __ASSEMBLY__ @@ -16,7 +16,11 @@ * 2 of the License, or (at your option) any later version. */ +#ifdef __powerpc64__ typedef unsigned int umode_t; +#else +typedef unsigned short umode_t; +#endif /* * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the @@ -32,8 +36,15 @@ typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; +#ifdef __powerpc64__ typedef __signed__ long __s64; typedef unsigned long __u64; +#else +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif +#endif /* __powerpc64__ */ typedef struct { __u32 u[4]; @@ -45,7 +56,11 @@ typedef struct { /* * These aren't exported outside the kernel to avoid name space clashes */ +#ifdef __powerpc64__ #define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif #ifndef __ASSEMBLY__ @@ -58,8 +73,13 @@ typedef unsigned short u16; typedef signed int s32; typedef unsigned int u32; +#ifdef __powerpc64__ typedef signed long s64; typedef unsigned long u64; +#else +typedef signed long long s64; +typedef unsigned long long u64; +#endif typedef __vector128 vector128; @@ -72,8 +92,13 @@ typedef struct { unsigned long env; } func_descr_t; +#ifdef CONFIG_LBD +typedef u64 sector_t; +#define HAVE_SECTOR_T +#endif + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ -#endif /* _PPC64_TYPES_H */ +#endif /* _ASM_POWERPC_TYPES_H */ diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h deleted file mode 100644 index 77dc24d7d2ad..000000000000 --- a/include/asm-ppc/types.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _PPC_TYPES_H -#define _PPC_TYPES_H - -#ifndef __ASSEMBLY__ - -typedef __signed__ char __s8; -typedef unsigned char __u8; - -typedef __signed__ short __s16; -typedef unsigned short __u16; - -typedef __signed__ int __s32; -typedef unsigned int __u32; - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -typedef __signed__ long long __s64; -typedef unsigned long long __u64; -#endif - -typedef struct { - __u32 u[4]; -} __vector128; - -/* - * XXX allowed outside of __KERNEL__ for now, until glibc gets - * a proper set of asm headers of its own. -- paulus - */ -typedef unsigned short umode_t; - -#endif /* __ASSEMBLY__ */ - -#ifdef __KERNEL__ -/* - * These aren't exported outside the kernel to avoid name space clashes - */ -#define BITS_PER_LONG 32 - -#ifndef __ASSEMBLY__ - -#include - -typedef signed char s8; -typedef unsigned char u8; - -typedef signed short s16; -typedef unsigned short u16; - -typedef signed int s32; -typedef unsigned int u32; - -typedef signed long long s64; -typedef unsigned long long u64; - -typedef __vector128 vector128; - -/* DMA addresses are 32-bits wide */ -typedef u32 dma_addr_t; -typedef u64 dma64_addr_t; - -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#endif /* __ASSEMBLY__ */ - -#endif /* __KERNEL__ */ - -#endif From d8699e65c6bc0a81b5e679ca5b135bfe3c3fb483 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 17:02:01 +1000 Subject: [PATCH 0521/1939] ppc64: Change ppc_md.get_cpuinfo to ppc_md.show_cpuinfo ... for consistency with ppc32; also add in ppc32's show_percpuinfo function. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_64.c | 4 ++-- arch/powerpc/platforms/iseries/setup.c | 4 ++-- arch/ppc64/kernel/bpa_setup.c | 4 ++-- arch/ppc64/kernel/pmac_setup.c | 2 +- arch/ppc64/kernel/setup.c | 4 ++-- include/asm-powerpc/machdep.h | 7 ++----- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6f29614c3581..97ffdcf09c03 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -704,8 +704,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_id == NR_CPUS) { seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - if (ppc_md.get_cpuinfo != NULL) - ppc_md.get_cpuinfo(m); + if (ppc_md.show_cpuinfo != NULL) + ppc_md.show_cpuinfo(m); return 0; } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 41cd5b689545..b27901481782 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -587,7 +587,7 @@ static void __init iSeries_setup_arch(void) printk("Processor version = %x\n", systemcfg->processor); } -static void iSeries_get_cpuinfo(struct seq_file *m) +static void iSeries_show_cpuinfo(struct seq_file *m) { seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); } @@ -760,7 +760,7 @@ static int __init iseries_probe(int platform) struct machdep_calls __initdata iseries_md = { .setup_arch = iSeries_setup_arch, - .get_cpuinfo = iSeries_get_cpuinfo, + .show_cpuinfo = iSeries_show_cpuinfo, .init_IRQ = iSeries_init_IRQ, .get_irq = iSeries_get_irq, .init_early = iSeries_init_early, diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c index 017cf23e91fa..c2dc8f282eb8 100644 --- a/arch/ppc64/kernel/bpa_setup.c +++ b/arch/ppc64/kernel/bpa_setup.c @@ -55,7 +55,7 @@ #define DBG(fmt...) #endif -void bpa_get_cpuinfo(struct seq_file *m) +void bpa_show_cpuinfo(struct seq_file *m) { struct device_node *root; const char *model = ""; @@ -129,7 +129,7 @@ struct machdep_calls __initdata bpa_md = { .probe = bpa_probe, .setup_arch = bpa_setup_arch, .init_early = bpa_init_early, - .get_cpuinfo = bpa_get_cpuinfo, + .show_cpuinfo = bpa_show_cpuinfo, .restart = rtas_restart, .power_off = rtas_power_off, .halt = rtas_halt, diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index be4c1693d149..c059805d8cce 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -505,7 +505,7 @@ struct machdep_calls __initdata pmac_md = { .probe = pmac_probe, .setup_arch = pmac_setup_arch, .init_early = pmac_init_early, - .get_cpuinfo = pmac_show_cpuinfo, + .show_cpuinfo = pmac_show_cpuinfo, .init_IRQ = pmac_init_IRQ, .get_irq = mpic_get_irq, .pcibios_fixup = pmac_pcibios_fixup, diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 3e6c1547b718..42019be0c6ad 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -703,8 +703,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_id == NR_CPUS) { seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - if (ppc_md.get_cpuinfo != NULL) - ppc_md.get_cpuinfo(m); + if (ppc_md.show_cpuinfo != NULL) + ppc_md.show_cpuinfo(m); return 0; } diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index f060553b997a..8a0969b6243c 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -86,7 +86,8 @@ struct machdep_calls { void (*setup_arch)(void); void (*init_early)(void); /* Optional, may be NULL. */ - void (*get_cpuinfo)(struct seq_file *m); + void (*show_cpuinfo)(struct seq_file *m); + void (*show_percpuinfo)(struct seq_file *m, int i); void (*init_IRQ)(void); int (*get_irq)(struct pt_regs *); @@ -153,10 +154,6 @@ struct machdep_calls { void (*enable_pmcs)(void); #ifdef CONFIG_PPC32 /* XXX for now */ - /* Optional, may be NULL. */ - int (*show_cpuinfo)(struct seq_file *m); - int (*show_percpuinfo)(struct seq_file *m, int i); - /* A general init function, called by ppc_init in init/main.c. May be NULL. */ void (*init)(void); From a9c59264690aea9d0df2d2d76683bc39ec6b7288 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 17:09:51 +1000 Subject: [PATCH 0522/1939] powerpc: Move smp_mpic_message_pass into mpic.c Having it here rather than in arch/ppc64/kernel/smp.c means that we can use it on 32-bit SMP systems easily with ARCH=powerpc. Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 21 +++++++++++++++++++++ arch/ppc64/kernel/smp.c | 22 ---------------------- include/asm-powerpc/mpic.h | 3 +++ include/asm-ppc64/smp.h | 1 - 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 02b4d2488bfd..3948e759d41a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -904,4 +904,25 @@ void mpic_request_ipis(void) printk("IPIs requested... \n"); } + +void smp_mpic_message_pass(int target, int msg) +{ + /* make sure we're sending something that translates to an IPI */ + if ((unsigned int)msg > 3) { + printk("SMP %d: smp_message_pass: unknown msg %d\n", + smp_processor_id(), msg); + return; + } + switch (target) { + case MSG_ALL: + mpic_send_ipi(msg, 0xffffffff); + break; + case MSG_ALL_BUT_SELF: + mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); + break; + default: + mpic_send_ipi(msg, 1 << target); + break; + } +} #endif /* CONFIG_SMP */ diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 6f4f3da12a63..192e3239fadc 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -69,28 +69,6 @@ void smp_call_function_interrupt(void); int smt_enabled_at_boot = 1; #ifdef CONFIG_MPIC -void smp_mpic_message_pass(int target, int msg) -{ - /* make sure we're sending something that translates to an IPI */ - if ( msg > 0x3 ){ - printk("SMP %d: smp_message_pass: unknown msg %d\n", - smp_processor_id(), msg); - return; - } - switch ( target ) - { - case MSG_ALL: - mpic_send_ipi(msg, 0xffffffff); - break; - case MSG_ALL_BUT_SELF: - mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); - break; - default: - mpic_send_ipi(msg, 1 << target); - break; - } -} - int __init smp_mpic_probe(void) { int nr_cpus; diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 6b558aeb9cb9..7083d1f74260 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -273,6 +273,9 @@ extern void mpic_request_ipis(void); /* Send an IPI (non offseted number 0..3) */ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); +/* Send a message (IPI) to a given target (cpu number or MSG_*) */ +void smp_mpic_message_pass(int target, int msg); + /* Fetch interrupt from a given mpic */ extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); /* This one gets to the primary mpic */ diff --git a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h index d86f742e9a21..c5e9052e7967 100644 --- a/include/asm-ppc64/smp.h +++ b/include/asm-ppc64/smp.h @@ -77,7 +77,6 @@ extern int smt_enabled_at_boot; extern int smp_mpic_probe(void); extern void smp_mpic_setup_cpu(int cpu); -extern void smp_mpic_message_pass(int target, int msg); extern void smp_generic_kick_cpu(int nr); extern void smp_generic_give_timebase(void); From 0dd194d02d2584c34e06ddd26c7a7896a5fa1974 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 20:48:19 +1000 Subject: [PATCH 0523/1939] powerpc: Fix places where ppc_md.show_[per]cpuinfo was treated as int I missed a few places where ppc code was still assuming that the ppc_md.show_[per]cpuinfo functions returned int. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 14 ++---- arch/powerpc/platforms/powermac/setup.c | 66 +++++++------------------ arch/powerpc/platforms/pseries/setup.c | 4 +- 3 files changed, 26 insertions(+), 58 deletions(-) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index b95f7cf693e6..b9269c038af3 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -150,7 +150,6 @@ extern u32 cpu_temp_both(unsigned long cpu); int show_cpuinfo(struct seq_file *m, void *v) { int i = (int) v - 1; - int err = 0; unsigned int pvr; unsigned short maj, min; unsigned long lpj; @@ -167,8 +166,8 @@ int show_cpuinfo(struct seq_file *m, void *v) #endif /* CONFIG_SMP */ if (ppc_md.show_cpuinfo != NULL) - err = ppc_md.show_cpuinfo(m); - return err; + ppc_md.show_cpuinfo(m); + return 0; } #ifdef CONFIG_SMP @@ -210,15 +209,12 @@ int show_cpuinfo(struct seq_file *m, void *v) } #endif /* CONFIG_TAU */ - if (ppc_md.show_percpuinfo != NULL) { - err = ppc_md.show_percpuinfo(m, i); - if (err) - return err; - } + if (ppc_md.show_percpuinfo != NULL) + ppc_md.show_percpuinfo(m, i); /* If we are a Freescale core do a simple check so * we dont have to keep adding cases in the future */ - if ((PVR_VER(pvr) & 0x8000) == 0x8000) { + if (PVR_VER(pvr) & 0x8000) { maj = PVR_MAJ(pvr); min = PVR_MIN(pvr); } else { diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index b6414e7c37d4..0bad53fa36ef 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -104,24 +104,26 @@ extern struct smp_ops_t psurge_smp_ops; extern struct smp_ops_t core99_smp_ops; #endif /* CONFIG_SMP */ -static int -pmac_show_cpuinfo(struct seq_file *m) +static void pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; char *pp; int plen; - int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, - NULL, PMAC_MB_INFO_MODEL, 0); - unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO, - NULL, PMAC_MB_INFO_FLAGS, 0); + int mbmodel; + unsigned int mbflags; char* mbname; - if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0) + mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, + PMAC_MB_INFO_MODEL, 0); + mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, + PMAC_MB_INFO_FLAGS, 0); + if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, + (long) &mbname) != 0) mbname = "Unknown"; /* find motherboard type */ seq_printf(m, "machine\t\t: "); - np = find_devices("device-tree"); + np = of_find_node_by_path("/"); if (np != NULL) { pp = (char *) get_property(np, "model", NULL); if (pp != NULL) @@ -139,6 +141,7 @@ pmac_show_cpuinfo(struct seq_file *m) } seq_printf(m, "\n"); } + of_node_put(np); } else seq_printf(m, "PowerMac\n"); @@ -147,10 +150,10 @@ pmac_show_cpuinfo(struct seq_file *m) seq_printf(m, "pmac flags\t: %08x\n", mbflags); /* find l2 cache info */ - np = find_devices("l2-cache"); - if (np == 0) - np = find_type_devices("cache"); - if (np != 0) { + np = of_find_node_by_name(NULL, "l2-cache"); + if (np == NULL) + np = of_find_node_by_type(NULL, "cache"); + if (np != NULL) { unsigned int *ic = (unsigned int *) get_property(np, "i-cache-size", NULL); unsigned int *dc = (unsigned int *) @@ -170,56 +173,25 @@ pmac_show_cpuinfo(struct seq_file *m) if (pp) seq_printf(m, " %s", pp); seq_printf(m, "\n"); - } - - /* find ram info */ - np = find_devices("memory"); - if (np != 0) { - int n; - struct reg_property *reg = (struct reg_property *) - get_property(np, "reg", &n); - - if (reg != 0) { - unsigned long total = 0; - - for (n /= sizeof(struct reg_property); n > 0; --n) - total += (reg++)->size; - seq_printf(m, "memory\t\t: %luMB\n", total >> 20); - } - } - - /* Checks "l2cr-value" property in the registry */ - np = find_devices("cpus"); - if (np == 0) - np = find_type_devices("cpu"); - if (np != 0) { - unsigned int *l2cr = (unsigned int *) - get_property(np, "l2cr-value", NULL); - if (l2cr != 0) { - seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr); - } + of_node_put(np); } /* Indicate newworld/oldworld */ seq_printf(m, "pmac-generation\t: %s\n", pmac_newworld ? "NewWorld" : "OldWorld"); - - - return 0; } -static int -pmac_show_percpuinfo(struct seq_file *m, int i) +static void pmac_show_percpuinfo(struct seq_file *m, int i) { #ifdef CONFIG_CPU_FREQ_PMAC extern unsigned int pmac_get_one_cpufreq(int i); unsigned int freq = pmac_get_one_cpufreq(i); if (freq != 0) { seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); - return 0; + return; } #endif /* CONFIG_CPU_FREQ_PMAC */ - return of_show_percpuinfo(m, i); + of_show_percpuinfo(m, i); } static volatile u32 *sysctrl_regs; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 0c84a44b43b4..c53dbbb4490a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -90,7 +90,7 @@ static void pseries_dedicated_idle(void); static volatile void __iomem * chrp_int_ack_special; struct mpic *pSeries_mpic; -void pSeries_get_cpuinfo(struct seq_file *m) +void pSeries_show_cpuinfo(struct seq_file *m) { struct device_node *root; const char *model = ""; @@ -599,7 +599,7 @@ struct machdep_calls __initdata pSeries_md = { .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, .init_early = pSeries_init_early, - .get_cpuinfo = pSeries_get_cpuinfo, + .show_cpuinfo = pSeries_show_cpuinfo, .log_error = pSeries_log_error, .pcibios_fixup = pSeries_final_fixup, .pci_probe_mode = pSeries_pci_probe_mode, From ff065ddd96c233d27322de493fa023357939c888 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 20:53:39 +1000 Subject: [PATCH 0524/1939] powerpc: Merge various powermac-related header files. Except for smu.h, which moved from asm-ppc64 to asm-powerpc, all of these moved from asm-ppc to asm-powerpc. In each case the asm-ppc64 version (if there was one) was just a single line including the asm-ppc version. Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/dbdma.h | 0 include/{asm-ppc => asm-powerpc}/heathrow.h | 0 include/{asm-ppc => asm-powerpc}/keylargo.h | 0 include/{asm-ppc => asm-powerpc}/macio.h | 0 include/{asm-ppc => asm-powerpc}/mediabay.h | 0 include/{asm-ppc => asm-powerpc}/ohare.h | 0 include/{asm-ppc => asm-powerpc}/pmac_feature.h | 0 include/{asm-ppc => asm-powerpc}/pmac_low_i2c.h | 0 include/{asm-ppc64 => asm-powerpc}/smu.h | 0 include/{asm-ppc => asm-powerpc}/uninorth.h | 0 include/asm-ppc64/dbdma.h | 2 -- include/asm-ppc64/keylargo.h | 2 -- include/asm-ppc64/macio.h | 2 -- include/asm-ppc64/pmac_feature.h | 2 -- include/asm-ppc64/pmac_low_i2c.h | 2 -- include/asm-ppc64/uninorth.h | 2 -- 16 files changed, 12 deletions(-) rename include/{asm-ppc => asm-powerpc}/dbdma.h (100%) rename include/{asm-ppc => asm-powerpc}/heathrow.h (100%) rename include/{asm-ppc => asm-powerpc}/keylargo.h (100%) rename include/{asm-ppc => asm-powerpc}/macio.h (100%) rename include/{asm-ppc => asm-powerpc}/mediabay.h (100%) rename include/{asm-ppc => asm-powerpc}/ohare.h (100%) rename include/{asm-ppc => asm-powerpc}/pmac_feature.h (100%) rename include/{asm-ppc => asm-powerpc}/pmac_low_i2c.h (100%) rename include/{asm-ppc64 => asm-powerpc}/smu.h (100%) rename include/{asm-ppc => asm-powerpc}/uninorth.h (100%) delete mode 100644 include/asm-ppc64/dbdma.h delete mode 100644 include/asm-ppc64/keylargo.h delete mode 100644 include/asm-ppc64/macio.h delete mode 100644 include/asm-ppc64/pmac_feature.h delete mode 100644 include/asm-ppc64/pmac_low_i2c.h delete mode 100644 include/asm-ppc64/uninorth.h diff --git a/include/asm-ppc/dbdma.h b/include/asm-powerpc/dbdma.h similarity index 100% rename from include/asm-ppc/dbdma.h rename to include/asm-powerpc/dbdma.h diff --git a/include/asm-ppc/heathrow.h b/include/asm-powerpc/heathrow.h similarity index 100% rename from include/asm-ppc/heathrow.h rename to include/asm-powerpc/heathrow.h diff --git a/include/asm-ppc/keylargo.h b/include/asm-powerpc/keylargo.h similarity index 100% rename from include/asm-ppc/keylargo.h rename to include/asm-powerpc/keylargo.h diff --git a/include/asm-ppc/macio.h b/include/asm-powerpc/macio.h similarity index 100% rename from include/asm-ppc/macio.h rename to include/asm-powerpc/macio.h diff --git a/include/asm-ppc/mediabay.h b/include/asm-powerpc/mediabay.h similarity index 100% rename from include/asm-ppc/mediabay.h rename to include/asm-powerpc/mediabay.h diff --git a/include/asm-ppc/ohare.h b/include/asm-powerpc/ohare.h similarity index 100% rename from include/asm-ppc/ohare.h rename to include/asm-powerpc/ohare.h diff --git a/include/asm-ppc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h similarity index 100% rename from include/asm-ppc/pmac_feature.h rename to include/asm-powerpc/pmac_feature.h diff --git a/include/asm-ppc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h similarity index 100% rename from include/asm-ppc/pmac_low_i2c.h rename to include/asm-powerpc/pmac_low_i2c.h diff --git a/include/asm-ppc64/smu.h b/include/asm-powerpc/smu.h similarity index 100% rename from include/asm-ppc64/smu.h rename to include/asm-powerpc/smu.h diff --git a/include/asm-ppc/uninorth.h b/include/asm-powerpc/uninorth.h similarity index 100% rename from include/asm-ppc/uninorth.h rename to include/asm-powerpc/uninorth.h diff --git a/include/asm-ppc64/dbdma.h b/include/asm-ppc64/dbdma.h deleted file mode 100644 index f2d5d5dc3377..000000000000 --- a/include/asm-ppc64/dbdma.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/include/asm-ppc64/keylargo.h b/include/asm-ppc64/keylargo.h deleted file mode 100644 index 4d78e3d0314c..000000000000 --- a/include/asm-ppc64/keylargo.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/include/asm-ppc64/macio.h b/include/asm-ppc64/macio.h deleted file mode 100644 index a3028b364f70..000000000000 --- a/include/asm-ppc64/macio.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/include/asm-ppc64/pmac_feature.h b/include/asm-ppc64/pmac_feature.h deleted file mode 100644 index e07e36c4cbb2..000000000000 --- a/include/asm-ppc64/pmac_feature.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/include/asm-ppc64/pmac_low_i2c.h b/include/asm-ppc64/pmac_low_i2c.h deleted file mode 100644 index 7bcfc72c5c8a..000000000000 --- a/include/asm-ppc64/pmac_low_i2c.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/include/asm-ppc64/uninorth.h b/include/asm-ppc64/uninorth.h deleted file mode 100644 index 7ad7059f2c80..000000000000 --- a/include/asm-ppc64/uninorth.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - From 399fe2bdd315c3a678b59b72659c4ed1ce0e1a24 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 20:57:05 +1000 Subject: [PATCH 0525/1939] ppc: rename pci_assign_all_busses to pci_assign_all_buses ... for consistency with ppc64 and to make merging easier. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pci.c | 6 +++--- arch/ppc/kernel/pci.c | 10 +++++----- arch/ppc/platforms/chrp_pci.c | 2 +- arch/ppc/platforms/pmac_pci.c | 6 +++--- arch/ppc/syslib/m82xx_pci.c | 2 +- arch/ppc/syslib/mpc52xx_pci.c | 2 +- arch/ppc64/kernel/maple_pci.c | 2 +- arch/ppc64/kernel/pmac_pci.c | 2 +- include/asm-ppc/pci.h | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index afb147e6b89f..34dfe1e9706f 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -608,7 +608,7 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) static int __init setup_uninorth(struct pci_controller* hose, struct reg_property* addr) { - pci_assign_all_busses = 1; + pci_assign_all_buses = 1; has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); @@ -640,7 +640,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the + * on AGP, we'll have to move pci_assign_all_buses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * We hard code the address because of the different size of @@ -1007,7 +1007,7 @@ void __init pmac_find_bridges(void) * some offset between bus number and domains for now when we * assign all busses should help for now */ - if (pci_assign_all_busses) + if (pci_assign_all_buses) pcibios_assign_bus_offset = 0x10; } diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 163276be7cc5..ad4ef2aaa6ab 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -54,7 +54,7 @@ static u8* pci_to_OF_bus_map; /* By default, we don't re-assign bus numbers. We do this only on * some pmacs */ -int pci_assign_all_busses; +int pci_assign_all_buses; struct pci_controller* hose_head; struct pci_controller** hose_tail = &hose_head; @@ -827,7 +827,7 @@ EXPORT_SYMBOL(pci_device_to_OF_node); * PCI bus numbers have not yet been assigned, and you need to * issue PCI config cycles to an OF device. * It could also be used to "fix" RTAS config cycles if you want - * to set pci_assign_all_busses to 1 and still use RTAS for PCI + * to set pci_assign_all_buses to 1 and still use RTAS for PCI * config cycles. */ struct pci_controller* @@ -1270,12 +1270,12 @@ pcibios_init(void) /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { - if (pci_assign_all_busses) + if (pci_assign_all_buses) hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose); hose->last_busno = bus->subordinate; - if (pci_assign_all_busses || next_busno <= hose->last_busno) + if (pci_assign_all_buses || next_busno <= hose->last_busno) next_busno = hose->last_busno + pcibios_assign_bus_offset; } pci_bus_count = next_busno; @@ -1284,7 +1284,7 @@ pcibios_init(void) * numbers vs. kernel bus numbers since we may have to * remap them. */ - if (pci_assign_all_busses && have_of) + if (pci_assign_all_buses && have_of) pcibios_make_OF_bus_map(); /* Do machine dependent PCI interrupt routing */ diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c index f12192cc4d42..bd047aac01b1 100644 --- a/arch/ppc/platforms/chrp_pci.c +++ b/arch/ppc/platforms/chrp_pci.c @@ -203,7 +203,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d printk ("RTAS supporting Pegasos OF not found, please upgrade" " your firmware\n"); } - pci_assign_all_busses = 1; + pci_assign_all_buses = 1; } void __init diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c index 1dc638f72239..786295b6ddd0 100644 --- a/arch/ppc/platforms/pmac_pci.c +++ b/arch/ppc/platforms/pmac_pci.c @@ -575,7 +575,7 @@ pmac_find_bridges(void) * some offset between bus number and domains for now when we * assign all busses should help for now */ - if (pci_assign_all_busses) + if (pci_assign_all_buses) pcibios_assign_bus_offset = 0x10; #ifdef CONFIG_POWER4 @@ -643,7 +643,7 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) static int __init setup_uninorth(struct pci_controller* hose, struct reg_property* addr) { - pci_assign_all_busses = 1; + pci_assign_all_buses = 1; has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); @@ -677,7 +677,7 @@ setup_u3_agp(struct pci_controller* hose, struct reg_property* addr) { /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the + * on AGP, we'll have to move pci_assign_all_buses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * We hard code the address because of the different size of diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c index 9db58c587b46..5cce123789f1 100644 --- a/arch/ppc/syslib/m82xx_pci.c +++ b/arch/ppc/syslib/m82xx_pci.c @@ -302,7 +302,7 @@ pq2ads_setup_pci(struct pci_controller *hose) void __init pq2_find_bridges(void) { - extern int pci_assign_all_busses; + extern int pci_assign_all_buses; struct pci_controller * hose; int host_bridge; diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c index 02edff8befd0..4ac19080eb85 100644 --- a/arch/ppc/syslib/mpc52xx_pci.c +++ b/arch/ppc/syslib/mpc52xx_pci.c @@ -182,7 +182,7 @@ mpc52xx_find_bridges(void) struct mpc52xx_pci __iomem *pci_regs; struct pci_controller *hose; - pci_assign_all_busses = 1; + pci_assign_all_buses = 1; pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE); if (!pci_regs) diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 0937649f4961..b901470f55cc 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -275,7 +275,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the + * on AGP, we'll have to move pci_assign_all_buses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * We hard code the address because of the different size of diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index f139fc034199..7a81c8275940 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -381,7 +381,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the + * on AGP, we'll have to move pci_assign_all_buses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * We hard code the address because of the different size of diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index 9dd06cd40096..643740dd727b 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -24,9 +24,9 @@ struct pci_dev; * Set this to 1 if you want the kernel to re-assign all PCI * bus numbers */ -extern int pci_assign_all_busses; +extern int pci_assign_all_buses; -#define pcibios_assign_all_busses() (pci_assign_all_busses) +#define pcibios_assign_all_busses() (pci_assign_all_buses) #define pcibios_scan_all_fns(a, b) 0 #define PCIBIOS_MIN_IO 0x1000 From 0458060c1c59c5378d8fb5daabe18cf4681c35cd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 21:00:20 +1000 Subject: [PATCH 0526/1939] ppc64: Move init_boot_text call and conswitchp init into setup_arch This way they get done in one place for all platforms, and it is more consistent with what ppc32 does. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_64.c | 8 ++++++++ arch/powerpc/platforms/pseries/setup.c | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 97ffdcf09c03..0312422881ae 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -586,6 +586,10 @@ void __init setup_system(void) */ finish_device_tree(); +#ifdef CONFIG_BOOTX_TEXT + init_boot_display(); +#endif + /* * Initialize xmon */ @@ -1039,6 +1043,10 @@ void __init setup_arch(char **cmdline_p) /* initialize the syscall map in systemcfg */ setup_syscall_map(); +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + ppc_md.setup_arch(); /* Use the default idle loop if the platform hasn't provided one. */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index c53dbbb4490a..92d18003f152 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -241,10 +241,6 @@ static void __init pSeries_setup_arch(void) find_and_init_phbs(); eeh_init(); -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - pSeries_nvram_init(); /* Choose an idle loop */ From 374e99d450a0c44dc30041fa83eccfd0890330c7 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 21:04:51 +1000 Subject: [PATCH 0527/1939] powerpc: Move some calculations from xxx_calibrate_decr to time_init Previously the individual xxx_calibrate_decr functions would each print the timebase and cpu frequency and calculate several values such as tb_to_us and tb_to_xs. This moves those printks and calculations into time_init just after the call to the platform's calibrate_decr function. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 27 ++++++++++++--------------- arch/ppc64/kernel/pmac_time.c | 14 ++------------ 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index d1608473075f..7d406b73a855 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -548,11 +548,9 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) || defined(CONFIG_PPC_ISERIES) void __init generic_calibrate_decr(void) { struct device_node *cpu; - struct div_result divres; unsigned int *fp; int node_found; @@ -591,20 +589,7 @@ void __init generic_calibrate_decr(void) "(not found)\n"); of_node_put(cpu); - - printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", - ppc_tb_freq/1000000, ppc_tb_freq%1000000); - printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", - ppc_proc_freq/1000000, ppc_proc_freq%1000000); - - tb_ticks_per_jiffy = ppc_tb_freq / HZ; - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = ppc_tb_freq / 1000000; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); - div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); - tb_to_xs = divres.result_low; } -#endif unsigned long get_boot_time(void) { @@ -633,6 +618,18 @@ void __init time_init(void) ppc_md.calibrate_decr(); + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); + printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", + ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); + + tb_ticks_per_jiffy = ppc_tb_freq / HZ; + tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; + tb_ticks_per_usec = ppc_tb_freq / 1000000; + tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); + div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res); + tb_to_xs = res.result_low; + #ifdef CONFIG_PPC64 get_paca()->default_decr = tb_ticks_per_jiffy; #endif diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index 56f335115916..928bf213ec4e 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -152,8 +152,7 @@ unsigned long __init pmac_get_boot_time(void) void __init pmac_calibrate_decr(void) { struct device_node *cpu; - unsigned int freq, *fp; - struct div_result divres; + unsigned int *fp; /* * The cpu node should have a timebase-frequency property @@ -165,16 +164,7 @@ void __init pmac_calibrate_decr(void) fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); if (fp == 0) panic("can't get cpu timebase frequency"); - freq = *fp; - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = freq / 1000000; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres ); - tb_to_xs = divres.result_low; - ppc_tb_freq = freq; + ppc_tb_freq = *fp; fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL); if (fp == 0) From d85b525e6e1d0886eebd1d4c4f954d9d2f226a63 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 21:06:44 +1000 Subject: [PATCH 0528/1939] ppc64: Use the merged mpic.c This means we now compile in arch/powerpc/sysdev for ARCH=ppc64. Signed-off-by: Paul Mackerras --- arch/ppc64/Makefile | 1 + arch/ppc64/kernel/Makefile | 3 +- arch/ppc64/kernel/mpic.c | 887 ------------------------------------- 3 files changed, 2 insertions(+), 889 deletions(-) delete mode 100644 arch/ppc64/kernel/mpic.c diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 4a9928ef3032..4d18bdb680f0 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -84,6 +84,7 @@ head-y := arch/ppc64/kernel/head.o libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ core-y += arch/powerpc/mm/ +core-y += arch/powerpc/sysdev/ core-y += arch/powerpc/platforms/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 6cce419f4b09..6c02a79955c7 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -55,9 +55,8 @@ obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o -ifneq ($(CONFIG_PPC_MERGE),y) -obj-$(CONFIG_MPIC) += mpic.o +ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ pmac_time.o pmac_nvram.o pmac_low_i2c.o \ udbg_scc.o diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c deleted file mode 100644 index ec22321342ad..000000000000 --- a/arch/ppc64/kernel/mpic.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * arch/ppc64/kernel/mpic.c - * - * Driver for interrupt controllers following the OpenPIC standard, the - * common implementation beeing IBM's MPIC. This driver also can deal - * with various broken implementations of this HW. - * - * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. - * - * 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. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG -#define DBG(fmt...) printk(fmt) -#else -#define DBG(fmt...) -#endif - -static struct mpic *mpics; -static struct mpic *mpic_primary; -static DEFINE_SPINLOCK(mpic_lock); - - -/* - * Register accessor functions - */ - - -static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, - unsigned int reg) -{ - if (be) - return in_be32(base + (reg >> 2)); - else - return in_le32(base + (reg >> 2)); -} - -static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, - unsigned int reg, u32 value) -{ - if (be) - out_be32(base + (reg >> 2), value); - else - out_le32(base + (reg >> 2), value); -} - -static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) -{ - unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; - unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); - - if (mpic->flags & MPIC_BROKEN_IPI) - be = !be; - return _mpic_read(be, mpic->gregs, offset); -} - -static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) -{ - unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); -} - -static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) -{ - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - - return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); -} - -static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) -{ - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); -} - -static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) -{ - unsigned int isu = src_no >> mpic->isu_shift; - unsigned int idx = src_no & mpic->isu_mask; - - return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], - reg + (idx * MPIC_IRQ_STRIDE)); -} - -static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, - unsigned int reg, u32 value) -{ - unsigned int isu = src_no >> mpic->isu_shift; - unsigned int idx = src_no & mpic->isu_mask; - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], - reg + (idx * MPIC_IRQ_STRIDE), value); -} - -#define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) -#define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) -#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) -#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) -#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) -#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) -#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) -#define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) - - -/* - * Low level utility functions - */ - - - -/* Check if we have one of those nice broken MPICs with a flipped endian on - * reads from IPI registers - */ -static void __init mpic_test_broken_ipi(struct mpic *mpic) -{ - u32 r; - - mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK); - r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0); - - if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { - printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); - mpic->flags |= MPIC_BROKEN_IPI; - } -} - -#ifdef CONFIG_MPIC_BROKEN_U3 - -/* Test if an interrupt is sourced from HyperTransport (used on broken U3s) - * to force the edge setting on the MPIC and do the ack workaround. - */ -static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) -{ - if (source_no >= 128 || !mpic->fixups) - return 0; - return mpic->fixups[source_no].base != NULL; -} - -static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) -{ - struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; - u32 tmp; - - spin_lock(&mpic->fixup_lock); - writeb(0x11 + 2 * fixup->irq, fixup->base); - tmp = readl(fixup->base + 2); - writel(tmp | 0x80000000ul, fixup->base + 2); - /* config writes shouldn't be posted but let's be safe ... */ - (void)readl(fixup->base + 2); - spin_unlock(&mpic->fixup_lock); -} - - -static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) -{ - int i, irq; - u32 tmp; - - printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); - - for (i=0; i < 24; i++) { - writeb(0x10 + 2*i, devbase + 0xf2); - tmp = readl(devbase + 0xf4); - if ((tmp & 0x1) || !(tmp & 0x20)) - continue; - irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xf2; - } -} - -static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase) -{ - int i, irq; - u32 tmp; - - printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); - - for (i=0; i < 4; i++) { - writeb(0x10 + 2*i, devbase + 0xba); - tmp = readl(devbase + 0xbc); - if ((tmp & 0x1) || !(tmp & 0x20)) - continue; - irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xba; - } -} - -static void __init mpic_scan_ioapics(struct mpic *mpic) -{ - unsigned int devfn; - u8 __iomem *cfgspace; - - printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); - - /* Allocate fixups array */ - mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); - BUG_ON(mpic->fixups == NULL); - memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); - - /* Init spinlock */ - spin_lock_init(&mpic->fixup_lock); - - /* Map u3 config space. We assume all IO-APICs are on the primary bus - * and slot will never be above "0xf" so we only need to map 32k - */ - cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); - BUG_ON(cfgspace == NULL); - - /* Now we scan all slots. We do a very quick scan, we read the header type, - * vendor ID and device ID only, that's plenty enough - */ - for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { - u8 __iomem *devbase = cfgspace + (devfn << 8); - u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); - u32 l = readl(devbase + PCI_VENDOR_ID); - u16 vendor_id, device_id; - int multifunc = 0; - - DBG("devfn %x, l: %x\n", devfn, l); - - /* If no device, skip */ - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) - goto next; - - /* Check if it's a multifunction device (only really used - * to function 0 though - */ - multifunc = !!(hdr_type & 0x80); - vendor_id = l & 0xffff; - device_id = (l >> 16) & 0xffff; - - /* If a known device, go to fixup setup code */ - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460) - mpic_amd8111_read_irq(mpic, devbase); - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450) - mpic_amd8131_read_irq(mpic, devbase); - next: - /* next device, if function 0 */ - if ((PCI_FUNC(devfn) == 0) && !multifunc) - devfn += 7; - } -} - -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - -/* Find an mpic associated with a given linux interrupt */ -static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) -{ - struct mpic *mpic = mpics; - - while(mpic) { - /* search IPIs first since they may override the main interrupts */ - if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) { - if (is_ipi) - *is_ipi = 1; - return mpic; - } - if (irq >= mpic->irq_offset && - irq < (mpic->irq_offset + mpic->irq_count)) { - if (is_ipi) - *is_ipi = 0; - return mpic; - } - mpic = mpic -> next; - } - return NULL; -} - -/* Convert a cpu mask from logical to physical cpu numbers. */ -static inline u32 mpic_physmask(u32 cpumask) -{ - int i; - u32 mask = 0; - - for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) - mask |= (cpumask & 1) << get_hard_smp_processor_id(i); - return mask; -} - -#ifdef CONFIG_SMP -/* Get the mpic structure from the IPI number */ -static inline struct mpic * mpic_from_ipi(unsigned int ipi) -{ - return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi); -} -#endif - -/* Get the mpic structure from the irq number */ -static inline struct mpic * mpic_from_irq(unsigned int irq) -{ - return container_of(irq_desc[irq].handler, struct mpic, hc_irq); -} - -/* Send an EOI */ -static inline void mpic_eoi(struct mpic *mpic) -{ - mpic_cpu_write(MPIC_CPU_EOI, 0); - (void)mpic_cpu_read(MPIC_CPU_WHOAMI); -} - -#ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) -{ - struct mpic *mpic = dev_id; - - smp_message_recv(irq - mpic->ipi_offset, regs); - return IRQ_HANDLED; -} -#endif /* CONFIG_SMP */ - -/* - * Linux descriptor level callbacks - */ - - -static void mpic_enable_irq(unsigned int irq) -{ - unsigned int loops = 100000; - struct mpic *mpic = mpic_from_irq(irq); - unsigned int src = irq - mpic->irq_offset; - - DBG("%s: enable_irq: %d (src %d)\n", mpic->name, irq, src); - - mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, - mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & ~MPIC_VECPRI_MASK); - - /* make sure mask gets to controller before we return to user */ - do { - if (!loops--) { - printk(KERN_ERR "mpic_enable_irq timeout\n"); - break; - } - } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); -} - -static void mpic_disable_irq(unsigned int irq) -{ - unsigned int loops = 100000; - struct mpic *mpic = mpic_from_irq(irq); - unsigned int src = irq - mpic->irq_offset; - - DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); - - mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, - mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | MPIC_VECPRI_MASK); - - /* make sure mask gets to controller before we return to user */ - do { - if (!loops--) { - printk(KERN_ERR "mpic_enable_irq timeout\n"); - break; - } - } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); -} - -static void mpic_end_irq(unsigned int irq) -{ - struct mpic *mpic = mpic_from_irq(irq); - - DBG("%s: end_irq: %d\n", mpic->name, irq); - - /* We always EOI on end_irq() even for edge interrupts since that - * should only lower the priority, the MPIC should have properly - * latched another edge interrupt coming in anyway - */ - -#ifdef CONFIG_MPIC_BROKEN_U3 - if (mpic->flags & MPIC_BROKEN_U3) { - unsigned int src = irq - mpic->irq_offset; - if (mpic_is_ht_interrupt(mpic, src)) - mpic_apic_end_irq(mpic, src); - } -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - mpic_eoi(mpic); -} - -#ifdef CONFIG_SMP - -static void mpic_enable_ipi(unsigned int irq) -{ - struct mpic *mpic = mpic_from_ipi(irq); - unsigned int src = irq - mpic->ipi_offset; - - DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); - mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); -} - -static void mpic_disable_ipi(unsigned int irq) -{ - /* NEVER disable an IPI... that's just plain wrong! */ -} - -static void mpic_end_ipi(unsigned int irq) -{ - struct mpic *mpic = mpic_from_ipi(irq); - - /* - * IPIs are marked IRQ_PER_CPU. This has the side effect of - * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from - * applying to them. We EOI them late to avoid re-entering. - * We mark IPI's with SA_INTERRUPT as they must run with - * irqs disabled. - */ - mpic_eoi(mpic); -} - -#endif /* CONFIG_SMP */ - -static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) -{ - struct mpic *mpic = mpic_from_irq(irq); - - cpumask_t tmp; - - cpus_and(tmp, cpumask, cpu_online_map); - - mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION, - mpic_physmask(cpus_addr(tmp)[0])); -} - - -/* - * Exported functions - */ - - -struct mpic * __init mpic_alloc(unsigned long phys_addr, - unsigned int flags, - unsigned int isu_size, - unsigned int irq_offset, - unsigned int irq_count, - unsigned int ipi_offset, - unsigned char *senses, - unsigned int senses_count, - const char *name) -{ - struct mpic *mpic; - u32 reg; - const char *vers; - int i; - - mpic = alloc_bootmem(sizeof(struct mpic)); - if (mpic == NULL) - return NULL; - - memset(mpic, 0, sizeof(struct mpic)); - mpic->name = name; - - mpic->hc_irq.typename = name; - mpic->hc_irq.enable = mpic_enable_irq; - mpic->hc_irq.disable = mpic_disable_irq; - mpic->hc_irq.end = mpic_end_irq; - if (flags & MPIC_PRIMARY) - mpic->hc_irq.set_affinity = mpic_set_affinity; -#ifdef CONFIG_SMP - mpic->hc_ipi.typename = name; - mpic->hc_ipi.enable = mpic_enable_ipi; - mpic->hc_ipi.disable = mpic_disable_ipi; - mpic->hc_ipi.end = mpic_end_ipi; -#endif /* CONFIG_SMP */ - - mpic->flags = flags; - mpic->isu_size = isu_size; - mpic->irq_offset = irq_offset; - mpic->irq_count = irq_count; - mpic->ipi_offset = ipi_offset; - mpic->num_sources = 0; /* so far */ - mpic->senses = senses; - mpic->senses_count = senses_count; - - /* Map the global registers */ - mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); - mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2); - BUG_ON(mpic->gregs == NULL); - - /* Reset */ - if (flags & MPIC_WANTS_RESET) { - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, - mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - | MPIC_GREG_GCONF_RESET); - while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - & MPIC_GREG_GCONF_RESET) - mb(); - } - - /* Read feature register, calculate num CPUs and, for non-ISU - * MPICs, num sources as well. On ISU MPICs, sources are counted - * as ISUs are added - */ - reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0); - mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) - >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; - if (isu_size == 0) - mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) - >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; - - /* Map the per-CPU registers */ - for (i = 0; i < mpic->num_cpus; i++) { - mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE + - i * MPIC_CPU_STRIDE, 0x1000); - BUG_ON(mpic->cpuregs[i] == NULL); - } - - /* Initialize main ISU if none provided */ - if (mpic->isu_size == 0) { - mpic->isu_size = mpic->num_sources; - mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE, - MPIC_IRQ_STRIDE * mpic->isu_size); - BUG_ON(mpic->isus[0] == NULL); - } - mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); - mpic->isu_mask = (1 << mpic->isu_shift) - 1; - - /* Display version */ - switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { - case 1: - vers = "1.0"; - break; - case 2: - vers = "1.2"; - break; - case 3: - vers = "1.3"; - break; - default: - vers = ""; - break; - } - printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", - name, vers, phys_addr, mpic->num_cpus); - printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, - mpic->isu_shift, mpic->isu_mask); - - mpic->next = mpics; - mpics = mpic; - - if (flags & MPIC_PRIMARY) - mpic_primary = mpic; - - return mpic; -} - -void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, - unsigned long phys_addr) -{ - unsigned int isu_first = isu_num * mpic->isu_size; - - BUG_ON(isu_num >= MPIC_MAX_ISU); - - mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size); - if ((isu_first + mpic->isu_size) > mpic->num_sources) - mpic->num_sources = isu_first + mpic->isu_size; -} - -void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, - void *data) -{ - struct mpic *mpic = mpic_find(irq, NULL); - unsigned long flags; - - /* Synchronization here is a bit dodgy, so don't try to replace cascade - * interrupts on the fly too often ... but normally it's set up at boot. - */ - spin_lock_irqsave(&mpic_lock, flags); - if (mpic->cascade) - mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); - mpic->cascade = NULL; - wmb(); - mpic->cascade_vec = irq - mpic->irq_offset; - mpic->cascade_data = data; - wmb(); - mpic->cascade = handler; - mpic_enable_irq(irq); - spin_unlock_irqrestore(&mpic_lock, flags); -} - -void __init mpic_init(struct mpic *mpic) -{ - int i; - - BUG_ON(mpic->num_sources == 0); - - printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); - - /* Set current processor priority to max */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); - - /* Initialize timers: just disable them all */ - for (i = 0; i < 4; i++) { - mpic_write(mpic->tmregs, - i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0); - mpic_write(mpic->tmregs, - i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI, - MPIC_VECPRI_MASK | - (MPIC_VEC_TIMER_0 + i)); - } - - /* Initialize IPIs to our reserved vectors and mark them disabled for now */ - mpic_test_broken_ipi(mpic); - for (i = 0; i < 4; i++) { - mpic_ipi_write(i, - MPIC_VECPRI_MASK | - (10 << MPIC_VECPRI_PRIORITY_SHIFT) | - (MPIC_VEC_IPI_0 + i)); -#ifdef CONFIG_SMP - if (!(mpic->flags & MPIC_PRIMARY)) - continue; - irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; - irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi; - -#endif /* CONFIG_SMP */ - } - - /* Initialize interrupt sources */ - if (mpic->irq_count == 0) - mpic->irq_count = mpic->num_sources; - -#ifdef CONFIG_MPIC_BROKEN_U3 - /* Do the ioapic fixups on U3 broken mpic */ - DBG("MPIC flags: %x\n", mpic->flags); - if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) - mpic_scan_ioapics(mpic); -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - for (i = 0; i < mpic->num_sources; i++) { - /* start with vector = source number, and masked */ - u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); - int level = 0; - - /* if it's an IPI, we skip it */ - if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) && - (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4)) - continue; - - /* do senses munging */ - if (mpic->senses && i < mpic->senses_count) { - if (mpic->senses[i] & IRQ_SENSE_LEVEL) - vecpri |= MPIC_VECPRI_SENSE_LEVEL; - if (mpic->senses[i] & IRQ_POLARITY_POSITIVE) - vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; - } else - vecpri |= MPIC_VECPRI_SENSE_LEVEL; - - /* remember if it was a level interrupts */ - level = (vecpri & MPIC_VECPRI_SENSE_LEVEL); - - /* deal with broken U3 */ - if (mpic->flags & MPIC_BROKEN_U3) { -#ifdef CONFIG_MPIC_BROKEN_U3 - if (mpic_is_ht_interrupt(mpic, i)) { - vecpri &= ~(MPIC_VECPRI_SENSE_MASK | - MPIC_VECPRI_POLARITY_MASK); - vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; - } -#else - printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n"); -#endif - } - - DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri, - (level != 0)); - - /* init hw */ - mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - 1 << get_hard_smp_processor_id(boot_cpuid)); - - /* init linux descriptors */ - if (i < mpic->irq_count) { - irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; - irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq; - } - } - - /* Init spurrious vector */ - mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS); - - /* Disable 8259 passthrough */ - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, - mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - | MPIC_GREG_GCONF_8259_PTHROU_DIS); - - /* Set current processor priority to 0 */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); -} - - - -void mpic_irq_set_priority(unsigned int irq, unsigned int pri) -{ - int is_ipi; - struct mpic *mpic = mpic_find(irq, &is_ipi); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&mpic_lock, flags); - if (is_ipi) { - reg = mpic_ipi_read(irq - mpic->ipi_offset) & MPIC_VECPRI_PRIORITY_MASK; - mpic_ipi_write(irq - mpic->ipi_offset, - reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); - } else { - reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI) - & MPIC_VECPRI_PRIORITY_MASK; - mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI, - reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); - } - spin_unlock_irqrestore(&mpic_lock, flags); -} - -unsigned int mpic_irq_get_priority(unsigned int irq) -{ - int is_ipi; - struct mpic *mpic = mpic_find(irq, &is_ipi); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&mpic_lock, flags); - if (is_ipi) - reg = mpic_ipi_read(irq - mpic->ipi_offset); - else - reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI); - spin_unlock_irqrestore(&mpic_lock, flags); - return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; -} - -void mpic_setup_this_cpu(void) -{ -#ifdef CONFIG_SMP - struct mpic *mpic = mpic_primary; - unsigned long flags; - u32 msk = 1 << hard_smp_processor_id(); - unsigned int i; - - BUG_ON(mpic == NULL); - - DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); - - spin_lock_irqsave(&mpic_lock, flags); - - /* let the mpic know we want intrs. default affinity is 0xffffffff - * until changed via /proc. That's how it's done on x86. If we want - * it differently, then we should make sure we also change the default - * values of irq_affinity in irq.c. - */ - if (distribute_irqs) { - for (i = 0; i < mpic->num_sources ; i++) - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk); - } - - /* Set current processor priority to 0 */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); - - spin_unlock_irqrestore(&mpic_lock, flags); -#endif /* CONFIG_SMP */ -} - -/* - * XXX: someone who knows mpic should check this. - * do we need to eoi the ipi including for kexec cpu here (see xics comments)? - * or can we reset the mpic in the new kernel? - */ -void mpic_teardown_this_cpu(int secondary) -{ - struct mpic *mpic = mpic_primary; - unsigned long flags; - u32 msk = 1 << hard_smp_processor_id(); - unsigned int i; - - BUG_ON(mpic == NULL); - - DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); - spin_lock_irqsave(&mpic_lock, flags); - - /* let the mpic know we don't want intrs. */ - for (i = 0; i < mpic->num_sources ; i++) - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk); - - /* Set current processor priority to max */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); - - spin_unlock_irqrestore(&mpic_lock, flags); -} - - -void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); - - mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, - mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); -} - -int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) -{ - u32 irq; - - irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; - DBG("%s: get_one_irq(): %d\n", mpic->name, irq); - - if (mpic->cascade && irq == mpic->cascade_vec) { - DBG("%s: cascading ...\n", mpic->name); - irq = mpic->cascade(regs, mpic->cascade_data); - mpic_eoi(mpic); - return irq; - } - if (unlikely(irq == MPIC_VEC_SPURRIOUS)) - return -1; - if (irq < MPIC_VEC_IPI_0) - return irq + mpic->irq_offset; - DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); - return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; -} - -int mpic_get_irq(struct pt_regs *regs) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - return mpic_get_one_irq(mpic, regs); -} - - -#ifdef CONFIG_SMP -void mpic_request_ipis(void) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - printk("requesting IPIs ... \n"); - - /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ - request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT, - "IPI0 (call function)", mpic); - request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT, - "IPI1 (reschedule)", mpic); - request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT, - "IPI2 (unused)", mpic); - request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT, - "IPI3 (debugger break)", mpic); - - printk("IPIs requested... \n"); -} -#endif /* CONFIG_SMP */ From 17a6392d30b4ed89b88a47a318b2b6de6ae7b946 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 21:10:09 +1000 Subject: [PATCH 0529/1939] powerpc/ppc/ppc64: Various compile fixes. This declares powersave_nap in system.h and makes it an int everywhere, fixes typos for the maple platform, fixes a couple of places where I missed removing the last two arguments from a message_pass function, and makes ppc64 consistent with ppc32 in the type of the pci_bridge.cfg_data field. Signed-off-by: Paul Mackerras --- arch/ppc/kernel/idle.c | 2 +- arch/ppc64/kernel/maple_time.c | 4 ++-- include/asm-powerpc/system.h | 2 ++ include/asm-ppc/machdep.h | 2 +- include/asm-ppc/open_pic.h | 3 +-- include/asm-ppc64/pci-bridge.h | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 0a12fbef7347..11e5b44713f7 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -75,7 +75,7 @@ void cpu_idle(void) /* * Register the sysctl to set/clear powersave_nap. */ -extern unsigned long powersave_nap; +extern int powersave_nap; static ctl_table powersave_nap_ctl_table[]={ { diff --git a/arch/ppc64/kernel/maple_time.c b/arch/ppc64/kernel/maple_time.c index cf5186335900..445cb7470bf5 100644 --- a/arch/ppc64/kernel/maple_time.c +++ b/arch/ppc64/kernel/maple_time.c @@ -172,7 +172,7 @@ unsigned long __init maple_get_boot_time(void) } maple_get_rtc_time(&tm); - return mktime(time->tm_year+1900, time->tm_mon+1, time->tm_mday, - time->tm_hour, time->tm_min, time->tm_sec); + return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); } diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 6463453b61a3..d60c8c928922 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -180,6 +180,8 @@ extern struct task_struct *_switch(struct thread_struct *prev, extern unsigned int rtas_data; extern int mem_init_done; /* set on boot once kmalloc can be called */ +extern int powersave_nap; /* set if nap mode can be used in idle loop */ + /* * Atomic exchange * diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 1d4ab70a56f3..6c6d23abbe91 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -167,7 +167,7 @@ extern sys_ctrler_t sys_ctrler; #ifdef CONFIG_SMP struct smp_ops_t { - void (*message_pass)(int target, int msg, unsigned long data, int wait); + void (*message_pass)(int target, int msg); int (*probe)(void); void (*kick_cpu)(int nr); void (*setup_cpu)(int nr); diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h index 7848aa610c05..ec2f46629ca2 100644 --- a/include/asm-ppc/open_pic.h +++ b/include/asm-ppc/open_pic.h @@ -58,8 +58,7 @@ extern int openpic_get_irq(struct pt_regs *regs); extern void openpic_reset_processor_phys(u_int cpumask); extern void openpic_setup_ISU(int isu_num, unsigned long addr); extern void openpic_cause_IPI(u_int ipi, cpumask_t cpumask); -extern void smp_openpic_message_pass(int target, int msg, unsigned long data, - int wait); +extern void smp_openpic_message_pass(int target, int msg); extern void openpic_set_k2_cascade(int irq); extern void openpic_set_priority(u_int pri); extern u_int openpic_get_priority(void); diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 1136cb6433bf..7d8ecb507a3d 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -36,7 +36,7 @@ struct pci_controller { struct pci_ops *ops; volatile unsigned int __iomem *cfg_addr; - volatile unsigned char __iomem *cfg_data; + volatile void __iomem *cfg_data; /* Currently, we limit ourselves to 1 IO range and 3 mem * ranges since the common pci_bus structure can't handle more From 5d14a18d59b661356409e5a1f624236155a209ba Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Oct 2005 22:33:06 +1000 Subject: [PATCH 0530/1939] powerpc: Fix some bugs in the new merged time code I had the sense of the test for when to use the old 601-style RTC registers inverted. pmac_calibrate_decr and via_calibrate_decr weren't setting ppc_tb_freq, on which all the further calculations depended. Lastly, update_gtod was losing the top 32 bits of the new tb_to_xs value. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 2 +- arch/powerpc/platforms/powermac/time.c | 5 ++--- include/asm-powerpc/time.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 7d406b73a855..3e722370113b 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -222,7 +222,7 @@ static inline void timer_sync_xtime(unsigned long cur_tb) * between updates. */ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, - unsigned int new_tb_to_xs) + u64 new_tb_to_xs) { unsigned temp_idx; struct gettimeofday_vars *temp_varp; diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index eb9969b52f96..a6d2d231d5a0 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -216,8 +216,8 @@ via_calibrate_decr(void) ; dend = get_dec(); + ppc_tb_freq = (dstart - dend) * 100 / 6; tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); - tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n", tb_ticks_per_jiffy, dstart - dend); @@ -306,6 +306,5 @@ pmac_calibrate_decr(void) freq = *fp; printk("time_init: decrementer frequency = %u.%.6u MHz\n", freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); + ppc_tb_freq = freq; } diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index 4eecc38f7092..f8ef186c81e4 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -75,7 +75,7 @@ struct div_result { /* Accessor functions for the timebase (RTC on 601) registers. */ /* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ #ifdef CONFIG_6xx -#define __USE_RTC() cpu_has_feature(CPU_FTR_USE_TB) +#define __USE_RTC() (!cpu_has_feature(CPU_FTR_USE_TB)) #else #define __USE_RTC() 0 #endif From b06c093ed2dc968b3c140dafa55fa6c7b72169e5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 19 Oct 2005 08:07:34 -0400 Subject: [PATCH 0531/1939] [PATCH] sundance: include MII address 0 in PHY probe Include MII address 0 at the end of the PHY scan. This covers the entire range of possible MII addresses. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d8a7e08cab2b..5de0554fd7c6 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -609,16 +609,17 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; - for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { + for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, MII_BMSR); + int phyx = phy & 0x1f; if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); + np->phys[phy_idx++] = phyx; + np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); if ((mii_status & 0x0040) == 0) np->mii_preamble_required++; printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->mii_if.advertising); + dev->name, phyx, mii_status, np->mii_if.advertising); } } np->mii_preamble_required--; From 07b8fede6da76ae6a0f547716c44b801a116bb4a Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Wed, 19 Oct 2005 10:40:08 -0400 Subject: [PATCH 0532/1939] [PATCH] e1000: Driver version, white space, comments, device id & other Driver version, white space, comments, device id & other Originally posted on 8/31 (and perhaps before)...I think it has not been committed because the patch from that posting was damaged. I'm reposting to make sure it gets in... :-) Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 40128b9d16ef..6b72f6acdd54 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -43,7 +43,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "6.0.60-k2"DRIVERNAPI +#define DRV_VERSION "6.1.16-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; @@ -80,6 +80,9 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x105E), + INTEL_E1000_ETHERNET_DEVICE(0x105F), + INTEL_E1000_ETHERNET_DEVICE(0x1060), INTEL_E1000_ETHERNET_DEVICE(0x1075), INTEL_E1000_ETHERNET_DEVICE(0x1076), INTEL_E1000_ETHERNET_DEVICE(0x1077), @@ -88,10 +91,13 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x107A), INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), + INTEL_E1000_ETHERNET_DEVICE(0x107D), + INTEL_E1000_ETHERNET_DEVICE(0x107E), + INTEL_E1000_ETHERNET_DEVICE(0x107F), INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x108B), INTEL_E1000_ETHERNET_DEVICE(0x108C), - INTEL_E1000_ETHERNET_DEVICE(0x1099), + INTEL_E1000_ETHERNET_DEVICE(0x109A), /* required last entry */ {0,} }; @@ -398,8 +404,7 @@ e1000_down(struct e1000_adapter *adapter) e1000_clean_all_tx_rings(adapter); e1000_clean_all_rx_rings(adapter); - /* If WoL is not enabled - * and management mode is not IAMT + /* If WoL is not enabled and management mode is not IAMT * Power down the PHY so no link is implied when interface is down */ if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper && From f0f15ab5542f73d07e35eeee713df289599427b2 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Thu, 20 Oct 2005 11:06:36 -0500 Subject: [PATCH 0533/1939] Fixed oops if an uninitialized key is used for encryption. Without this patch, if you try and use a key that has not been configured, for example: % iwconfig eth1 key deadbeef00 [2] without having configured key [1], then the active key will still be [1], but privacy will now be enabled. Transmission of a packet in this situation will result in a kernel oops. Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_tx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 2955b7aa5a38..f4f2a33973a7 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -157,11 +157,14 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; int res; + if (crypt == NULL) + return -1; + /* To encrypt, frame format is: * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ atomic_inc(&crypt->refcnt); res = 0; - if (crypt->ops->encrypt_mpdu) + if (crypt->ops && crypt->ops->encrypt_mpdu) res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); atomic_dec(&crypt->refcnt); @@ -264,9 +267,9 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ieee->sec.encrypt; - host_encrypt = ieee->host_encrypt && encrypt; - host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt; - host_build_iv = ieee->host_build_iv && encrypt; + host_encrypt = ieee->host_encrypt && encrypt && crypt; + host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt; + host_build_iv = ieee->host_build_iv && encrypt && crypt; if (!encrypt && ieee->ieee802_1x && ieee->drop_unencrypted && ether_type != ETH_P_PAE) { From fda0fd6c5b722cc48e904e0daafedca275d332af Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 14 Oct 2005 16:38:49 +1000 Subject: [PATCH 0534/1939] [DCCP]: Use skb_set_owner_w in dccp_transmit_skb when skb->sk is NULL David S. Miller wrote: > One thing you can probably do for this bug is to mark data packets > explicitly somehow, perhaps in the SKB control block DCCP already > uses for other data. Put some boolean in there, set it true for > data packets. Then change the test in dccp_transmit_skb() as > appropriate to test the boolean flag instead of "skb_cloned(skb)". I agree. In fact we already have that flag, it's called skb->sk. So here is patch to test that instead of skb_cloned(). Signed-off-by: Herbert Xu Acked-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/output.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index 4786bdcddcc9..946ec2db75de 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -62,10 +62,8 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) skb->h.raw = skb_push(skb, dccp_header_size); dh = dccp_hdr(skb); - /* - * Data packets are not cloned as they are never retransmitted - */ - if (skb_cloned(skb)) + + if (!skb->sk) skb_set_owner_w(skb, sk); /* Build DCCP header and checksum it. */ From ffa29347dfbc158d1f47f5925324a6f5713659c1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 16 Oct 2005 21:08:46 +1000 Subject: [PATCH 0535/1939] [DCCP]: Make dccp_write_xmit always free the packet icmp_send doesn't use skb->sk at all so even if skb->sk has already been freed it can't cause crash there (it would've crashed somewhere else first, e.g., ip_queue_xmit). I found a double-free on an skb that could explain this though. dccp_sendmsg and dccp_write_xmit are a little confused as to what should free the packet when something goes wrong. Sometimes they both go for the ball and end up in each other's way. This patch makes dccp_write_xmit always free the packet no matter what. This makes sense since dccp_transmit_skb which in turn comes from the fact that ip_queue_xmit always frees the packet. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/output.c | 3 ++- net/dccp/proto.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index 946ec2db75de..7006549f7050 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -241,7 +241,8 @@ int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) err = dccp_transmit_skb(sk, skb); ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); - } + } else + kfree_skb(skb); return err; } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index a1cfd0e9e3bc..a021c3422f67 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -402,8 +402,6 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * This bug was _quickly_ found & fixed by just looking at an OSTRA * generated callgraph 8) -acme */ - if (rc != 0) - goto out_discard; out_release: release_sock(sk); return rc ? : len; From 49c5bfaffe8ae6e6440dc4bf78b03800960d93f5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 18 Oct 2005 12:03:28 +1000 Subject: [PATCH 0536/1939] [DCCP]: Clear the IPCB area Turns out the problem has nothing to do with use-after-free or double-free. It's just that we're not clearing the CB area and DCCP unlike TCP uses a CB format that's incompatible with IP. Signed-off-by: Herbert Xu Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/ipv4.c | 2 ++ net/dccp/output.c | 1 + 2 files changed, 3 insertions(+) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ae088d1347af..6298cf58ff9e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -463,6 +463,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, if (skb != NULL) { const struct inet_request_sock *ireq = inet_rsk(req); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); @@ -647,6 +648,7 @@ int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) if (skb != NULL) { const struct inet_sock *inet = inet_sk(sk); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, inet->saddr, inet->daddr, NULL); if (err == NET_XMIT_CN) diff --git a/net/dccp/output.c b/net/dccp/output.c index 7006549f7050..29250749f16f 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -100,6 +100,7 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) DCCP_INC_STATS(DCCP_MIB_OUTSEGS); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_queue_xmit(skb, 0); if (err <= 0) return err; From b2cc99f04c5a732c793519aca61a20f719b50db4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 20 Oct 2005 17:13:13 -0200 Subject: [PATCH 0537/1939] [TCP] Allow len == skb->len in tcp_fragment It is legitimate to call tcp_fragment with len == skb->len since that is done for FIN packets and the FIN flag counts as one byte. So we should only check for the len > skb->len case. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_output.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7114031fdc70..b907456a79f4 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -435,17 +435,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss int nsize, old_factor; u16 flags; - if (unlikely(len >= skb->len)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "TCP: seg_size=%u, mss=%u, seq=%u, " - "end_seq=%u, skb->len=%u.\n", len, mss_now, - TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - skb->len); - WARN_ON(1); - } - return 0; - } - + BUG_ON(len > skb->len); nsize = skb_headlen(skb) - len; if (nsize < 0) nsize = 0; From 3910f44d79a8a4a26fcfefbf16c5b8e1a7743175 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 20 Oct 2005 12:29:36 -0700 Subject: [PATCH 0538/1939] [IB] cm: Add missing break in switch Add missing "break" in switch statement. Without the break, the CM ended up always falling through and setting every connection request to use RC transport, which meant that UC connections didn't work. Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm_msgs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h index 813ab70bf6d5..4d3aee90c249 100644 --- a/drivers/infiniband/core/cm_msgs.h +++ b/drivers/infiniband/core/cm_msgs.h @@ -186,6 +186,7 @@ static inline void cm_req_set_qp_type(struct cm_req_msg *req_msg, req_msg->offset40 = cpu_to_be32((be32_to_cpu( req_msg->offset40) & 0xFFFFFFF9) | 0x2); + break; default: req_msg->offset40 = cpu_to_be32(be32_to_cpu( req_msg->offset40) & From 2e0c512aff978a7040464e81fc9c0dfdf4639c23 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 20 Oct 2005 12:30:16 -0700 Subject: [PATCH 0539/1939] [IB] user_mad: trivial coding style fixes Add spaces after "sizeof" operator to match the rest of file. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index a64d6b4dcc16..38f4bfbb7135 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -280,14 +280,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, length = count - sizeof (struct ib_user_mad); packet = kmalloc(sizeof *packet + sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr), GFP_KERNEL); + sizeof (struct ib_rmpp_hdr), GFP_KERNEL); if (!packet) return -ENOMEM; if (copy_from_user(&packet->mad, buf, sizeof (struct ib_user_mad) + - sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr))) { + sizeof (struct ib_mad_hdr) + + sizeof (struct ib_rmpp_hdr))) { ret = -EFAULT; goto err; } @@ -349,7 +349,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, } rmpp_active = 1; } else { - if (length > sizeof(struct ib_mad)) { + if (length > sizeof (struct ib_mad)) { ret = -EINVAL; goto err_ah; } @@ -376,17 +376,17 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, if (!rmpp_active) { /* Copy message from user into send buffer */ if (copy_from_user(packet->msg->mad, - buf + sizeof(struct ib_user_mad), length)) { + buf + sizeof (struct ib_user_mad), length)) { ret = -EFAULT; goto err_msg; } } else { - rmpp_hdr_size = sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr); + rmpp_hdr_size = sizeof (struct ib_mad_hdr) + + sizeof (struct ib_rmpp_hdr); /* Only copy MAD headers (RMPP header in place) */ memcpy(packet->msg->mad, packet->mad.data, - sizeof(struct ib_mad_hdr)); + sizeof (struct ib_mad_hdr)); /* Now, copy rest of message from user into send buffer */ if (copy_from_user(((struct ib_rmpp_mad *) packet->msg->mad)->data, From bbf207860931b6a033d0fbcd170ae2332c0d8216 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 20 Oct 2005 12:54:01 -0700 Subject: [PATCH 0540/1939] [IB] user_mad: Use class_device.devt Use devt member of struct class_device so that we don't have to create our own "dev" file in sysfs. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 38f4bfbb7135..fd200c064a2e 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -671,17 +671,6 @@ static struct ib_client umad_client = { .remove = ib_umad_remove_one }; -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - struct ib_umad_port *port = class_get_devdata(class_dev); - - if (class_dev == &port->class_dev) - return print_dev_t(buf, port->dev.dev); - else - return print_dev_t(buf, port->sm_dev.dev); -} -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { struct ib_umad_port *port = class_get_devdata(class_dev); @@ -762,6 +751,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, port->class_dev.class = &umad_class; port->class_dev.dev = device->dma_device; + port->class_dev.devt = port->dev.dev; snprintf(port->class_dev.class_id, BUS_ID_SIZE, "umad%d", port->devnum); @@ -771,8 +761,6 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, class_set_devdata(&port->class_dev, port); kref_get(&port->umad_dev->ref); - if (class_device_create_file(&port->class_dev, &class_device_attr_dev)) - goto err_class; if (class_device_create_file(&port->class_dev, &class_device_attr_ibdev)) goto err_class; if (class_device_create_file(&port->class_dev, &class_device_attr_port)) @@ -786,6 +774,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, port->sm_class_dev.class = &umad_class; port->sm_class_dev.dev = device->dma_device; + port->sm_class_dev.devt = port->sm_dev.dev; snprintf(port->sm_class_dev.class_id, BUS_ID_SIZE, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); @@ -795,8 +784,6 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, class_set_devdata(&port->sm_class_dev, port); kref_get(&port->umad_dev->ref); - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_dev)) - goto err_sm_class; if (class_device_create_file(&port->sm_class_dev, &class_device_attr_ibdev)) goto err_sm_class; if (class_device_create_file(&port->sm_class_dev, &class_device_attr_port)) From 7e6c1208598004a80b1c1fca4953eb9f2a6aa8bc Mon Sep 17 00:00:00 2001 From: Brett Russ Date: Thu, 20 Oct 2005 08:39:43 -0400 Subject: [PATCH 0541/1939] [PATCH] libata: Marvell endian fix Jeff found an endian bug in the Marvell driver (thanks!). Here's the fix for it. Signed-off-by: Brett Russ Signed-off-by: Jeff Garzik --- drivers/scsi/sata_mv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index d457f5673476..9b6213928f7a 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.24" +#define DRV_VERSION "0.25" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -800,7 +800,8 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); } if (0 < qc->n_elem) { - pp->sg_tbl[qc->n_elem - 1].flags_size |= EPRD_FLAG_END_OF_TBL; + pp->sg_tbl[qc->n_elem - 1].flags_size |= + cpu_to_le32(EPRD_FLAG_END_OF_TBL); } } From 59b81827071a8ae7f399da533d268e1e33bfeeb7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 20 Oct 2005 12:01:28 +0100 Subject: [PATCH 0542/1939] [PATCH] sb1250-mac: PHY probing fixes. Improve sb1250-mac driver to probe for PHYs at addresses other than 1, such as the PHYs on BigSur. Signed-Off-By: Andy Isaacson Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index d4c8ecdfa4a7..aa4ca1821759 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -296,6 +296,7 @@ static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); +static int sbmac_mii_probe(struct net_device *dev); static void sbmac_mii_sync(struct sbmac_softc *s); static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); @@ -433,6 +434,9 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; #define MII_BMCR 0x00 /* Basic mode control register (rw) */ #define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define MII_PHYIDR1 0x02 +#define MII_PHYIDR2 0x03 + #define MII_K1STSR 0x0A /* 1K Status Register (ro) */ #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ @@ -2431,6 +2435,15 @@ static int sbmac_open(struct net_device *dev) if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) return -EBUSY; + /* + * Probe phy address + */ + + if(sbmac_mii_probe(dev) == -1) { + printk("%s: failed to probe PHY.\n", dev->name); + return -EINVAL; + } + /* * Configure default speed */ @@ -2464,6 +2477,29 @@ static int sbmac_open(struct net_device *dev) return 0; } +static int sbmac_mii_probe(struct net_device *dev) +{ + int i; + struct sbmac_softc *s = netdev_priv(dev); + u16 bmsr, id1, id2; + u32 vendor, device; + + for (i=1; i<31; i++) { + bmsr = sbmac_mii_read(s, i, MII_BMSR); + if (bmsr != 0) { + s->sbm_phys[0] = i; + id1 = sbmac_mii_read(s, i, MII_PHYIDR1); + id2 = sbmac_mii_read(s, i, MII_PHYIDR2); + vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f); + device = (id2 >> 4) & 0x3f; + + printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n", + dev->name, i, vendor, device); + return i; + } + } + return -1; +} static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) From 4e51336a00bdcb42960acca52c23e90e9f4e6959 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Oct 2005 14:22:41 -0700 Subject: [PATCH 0543/1939] NFSv4: Final tweak to sequence id Sacrifice queueing fairness for performance. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4state.c | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 45bff1d1a513..5c0dd26d0985 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -110,8 +110,8 @@ struct nfs_seqid_counter { }; struct nfs_seqid { - struct list_head list; struct nfs_seqid_counter *sequence; + struct list_head list; }; static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index da0861db57fb..c59ef90e956b 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -670,15 +670,12 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) { - struct rpc_sequence *sequence = counter->sequence; struct nfs_seqid *new; new = kmalloc(sizeof(*new), GFP_KERNEL); if (new != NULL) { new->sequence = counter; - spin_lock(&sequence->lock); - list_add_tail(&new->list, &sequence->list); - spin_unlock(&sequence->lock); + INIT_LIST_HEAD(&new->list); } return new; } @@ -687,10 +684,12 @@ void nfs_free_seqid(struct nfs_seqid *seqid) { struct rpc_sequence *sequence = seqid->sequence->sequence; - spin_lock(&sequence->lock); - list_del(&seqid->list); - rpc_wake_up(&sequence->wait); - spin_unlock(&sequence->lock); + if (!list_empty(&seqid->list)) { + spin_lock(&sequence->lock); + list_del(&seqid->list); + spin_unlock(&sequence->lock); + } + rpc_wake_up_next(&sequence->wait); kfree(seqid); } @@ -746,12 +745,16 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) struct rpc_sequence *sequence = seqid->sequence->sequence; int status = 0; + if (sequence->list.next == &seqid->list) + goto out; spin_lock(&sequence->lock); - if (sequence->list.next != &seqid->list) { + if (!list_empty(&sequence->list)) { rpc_sleep_on(&sequence->wait, task, NULL, NULL); status = -EAGAIN; - } + } else + list_add(&seqid->list, &sequence->list); spin_unlock(&sequence->lock); +out: return status; } From ec073428281b401f1142cb84b277a5b00c7994c9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Oct 2005 14:22:47 -0700 Subject: [PATCH 0544/1939] NFSv4: Fix up locking for nfs4_state_owner Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 2 ++ fs/nfs/nfs4state.c | 20 +++++++++++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 5c0dd26d0985..78a53f5a9f18 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -126,6 +126,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status * semantics by allowing the server to identify replayed requests. */ struct nfs4_state_owner { + spinlock_t so_lock; struct list_head so_list; /* per-clientid list of state_owners */ struct nfs4_client *so_client; u32 so_id; /* 32-bit identifier, unique */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2d9357cf3fc5..9c1da34036aa 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -212,6 +212,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, open_flags &= (FMODE_READ|FMODE_WRITE); /* Protect against nfs4_find_state() */ + spin_lock(&state->owner->so_lock); spin_lock(&inode->i_lock); state->state |= open_flags; /* NB! List reordering - see the reclaim code for why. */ @@ -221,6 +222,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, state->nreaders++; memcpy(&state->stateid, stateid, sizeof(state->stateid)); spin_unlock(&inode->i_lock); + spin_unlock(&state->owner->so_lock); } /* diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c59ef90e956b..2d5a6a2b9dec 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -267,6 +267,7 @@ nfs4_alloc_state_owner(void) sp = kzalloc(sizeof(*sp),GFP_KERNEL); if (!sp) return NULL; + spin_lock_init(&sp->so_lock); INIT_LIST_HEAD(&sp->so_states); INIT_LIST_HEAD(&sp->so_delegations); rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); @@ -438,20 +439,23 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) if (state) goto out; new = nfs4_alloc_open_state(); + spin_lock(&owner->so_lock); spin_lock(&inode->i_lock); state = __nfs4_find_state_byowner(inode, owner); if (state == NULL && new != NULL) { state = new; - /* Note: The reclaim code dictates that we add stateless - * and read-only stateids to the end of the list */ - list_add_tail(&state->open_states, &owner->so_states); state->owner = owner; atomic_inc(&owner->so_count); list_add(&state->inode_states, &nfsi->open_states); state->inode = igrab(inode); spin_unlock(&inode->i_lock); + /* Note: The reclaim code dictates that we add stateless + * and read-only stateids to the end of the list */ + list_add_tail(&state->open_states, &owner->so_states); + spin_unlock(&owner->so_lock); } else { spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); if (new) nfs4_free_open_state(new); } @@ -468,12 +472,14 @@ void nfs4_put_open_state(struct nfs4_state *state) struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; - if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) + if (!atomic_dec_and_lock(&state->count, &owner->so_lock)) return; + spin_lock(&inode->i_lock); if (!list_empty(&state->inode_states)) list_del(&state->inode_states); - spin_unlock(&inode->i_lock); list_del(&state->open_states); + spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); iput(inode); BUG_ON (state->state != 0); nfs4_free_open_state(state); @@ -491,6 +497,7 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) atomic_inc(&owner->so_count); /* Protect against nfs4_find_state() */ + spin_lock(&owner->so_lock); spin_lock(&inode->i_lock); if (mode & FMODE_READ) state->nreaders--; @@ -503,6 +510,7 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) list_move_tail(&state->open_states, &owner->so_states); } spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); newstate = 0; if (state->state != 0) { if (state->nreaders) @@ -899,6 +907,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) list_for_each_entry(sp, &clp->cl_state_owners, so_list) { sp->so_seqid.counter = 0; sp->so_seqid.flags = 0; + spin_lock(&sp->so_lock); list_for_each_entry(state, &sp->so_states, open_states) { list_for_each_entry(lock, &state->lock_states, ls_locks) { lock->ls_seqid.counter = 0; @@ -906,6 +915,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) lock->ls_flags &= ~NFS_LOCK_INITIALIZED; } } + spin_unlock(&sp->so_lock); } } From b2640b420a806c91f6b8799314ca96bb88a246d2 Mon Sep 17 00:00:00 2001 From: Matt Reimer Date: Thu, 20 Oct 2005 23:21:18 +0100 Subject: [PATCH 0545/1939] [ARM] 3025/1: Add I2S platform device for PXA Patch from Matt Reimer Adds an I2S platform_device for PXA. I2S is used to interface with sound chips on systems like iPAQ h1910/h2200/hx4700 and Asus 716. Signed-off-by: mreimer@vpop.net Signed-off-by: Russell King --- arch/arm/mach-pxa/generic.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index d327c127eddb..1d7677669a76 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -250,6 +250,25 @@ void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) i2c_device.dev.platform_data = info; } +static struct resource i2s_resources[] = { + { + .start = 0x40400000, + .end = 0x40400083, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_I2S, + .end = IRQ_I2S, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2s_device = { + .name = "pxa2xx-i2s", + .id = -1, + .resource = i2c_resources, + .num_resources = ARRAY_SIZE(i2s_resources), +}; + static struct platform_device *devices[] __initdata = { &pxamci_device, &udc_device, @@ -258,6 +277,7 @@ static struct platform_device *devices[] __initdata = { &btuart_device, &stuart_device, &i2c_device, + &i2s_device, }; static int __init pxa_init(void) From a7ce8edc8232da51dc3a804ec9c734019d115b40 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Oct 2005 23:21:18 +0100 Subject: [PATCH 0546/1939] [ARM] 3026/1: S3C2410 - avoid possible overflow in pll calculations Patch from Ben Dooks Avoid the possiblity that if the board is using a 16.9334 or higher crystal with a high PLL multiplier, then the pll value could overflow the capability of an int. Also fix the value types of the intermediate variables to unsigned int. Rewrite of patch from Guillaume Gourat Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-clock.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index 16f4c3cc1388..66794b13e185 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -18,7 +18,8 @@ * 10-Feb-2005 Ben Dooks Fixed CAMDIVN address (Guillaume Gourat) * 10-Mar-2005 Lucas Villa Real Changed S3C2410_VA to S3C24XX_VA * 27-Aug-2005 Ben Dooks Add clock-slow info - */ + * 20-Oct-2005 Ben Dooks Fixed overflow in PLL (Guillaume Gourat) +*/ #ifndef __ASM_ARM_REGS_CLOCK #define __ASM_ARM_REGS_CLOCK "$Id: clock.h,v 1.4 2003/04/30 14:50:51 ben Exp $" @@ -83,10 +84,13 @@ #ifndef __ASSEMBLY__ +#include + static inline unsigned int -s3c2410_get_pll(int pllval, int baseclk) +s3c2410_get_pll(unsigned int pllval, unsigned int baseclk) { - int mdiv, pdiv, sdiv; + unsigned int mdiv, pdiv, sdiv; + uint64_t fvco; mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT; pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT; @@ -96,7 +100,10 @@ s3c2410_get_pll(int pllval, int baseclk) pdiv &= S3C2410_PLLCON_PDIVMASK; sdiv &= S3C2410_PLLCON_SDIVMASK; - return (baseclk * (mdiv + 8)) / ((pdiv + 2) << sdiv); + fvco = (uint64_t)baseclk * (mdiv + 8); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned int)fvco; } #endif /* __ASSEMBLY__ */ From b048dbf4d428c89f219efc2eddf2771f13500503 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Oct 2005 23:21:19 +0100 Subject: [PATCH 0547/1939] [ARM] 3027/1: BAST - reduce NAND timings slightly Patch from Ben Dooks The current Simtec BAST nand area timings are a little too slow to be obtained by a 2410 running at 266MHz, so reduce the timings slightly to bring them into the acceptable range. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-bast.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 8ca955984645..7b51bfd0ba6d 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -307,9 +307,9 @@ static void bast_nand_select(struct s3c2410_nand_set *set, int slot) } static struct s3c2410_platform_nand bast_nand_info = { - .tacls = 40, - .twrph0 = 80, - .twrph1 = 80, + .tacls = 30, + .twrph0 = 60, + .twrph1 = 60, .nr_sets = ARRAY_SIZE(bast_nand_sets), .sets = bast_nand_sets, .select_chip = bast_nand_select, From 7fe8785e4198ad6b5dfd4a76c44c97e9b4463534 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Oct 2005 23:21:20 +0100 Subject: [PATCH 0548/1939] [ARM] 3028/1: S3C2410 - add DCLK mask definitions Patch from Ben Dooks From: Guillaume Gourat Add MASK definitions for DCLK0 and DCLK1 Signed-off-by: Guillaume Gourat Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-clock.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index 66794b13e185..34360706e016 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -19,6 +19,7 @@ * 10-Mar-2005 Lucas Villa Real Changed S3C2410_VA to S3C24XX_VA * 27-Aug-2005 Ben Dooks Add clock-slow info * 20-Oct-2005 Ben Dooks Fixed overflow in PLL (Guillaume Gourat) + * 20-Oct-2005 Ben Dooks Add masks for DCLK (Guillaume Gourat) */ #ifndef __ASM_ARM_REGS_CLOCK @@ -67,11 +68,16 @@ #define S3C2410_DCLKCON_DCLK0_UCLK (1<<1) #define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4) #define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8) +#define S3C2410_DCLKCON_DCLK0_DIV_MASK ((0xf)<<4) +#define S3C2410_DCLKCON_DCLK0_CMP_MASK ((0xf)<<8) #define S3C2410_DCLKCON_DCLK1EN (1<<16) #define S3C2410_DCLKCON_DCLK1_PCLK (0<<17) #define S3C2410_DCLKCON_DCLK1_UCLK (1<<17) #define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20) +#define S3C2410_DCLKCON_DCLK1_CMP(x) (((x) - 1) <<24) +#define S3C2410_DCLKCON_DCLK1_DIV_MASK ((0xf) <<20) +#define S3C2410_DCLKCON_DCLK1_CMP_MASK ((0xf) <<24) #define S3C2410_CLKDIVN_PDIVN (1<<0) #define S3C2410_CLKDIVN_HDIVN (1<<1) From 9ee0c0a2ccd66b90eaeb2f197c0a7da43071af52 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0549/1939] [PATCH] iomem annotations (sata_nv) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_nv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 9fa2535dd937..8866530bc491 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -331,7 +331,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) return 0xffffffffU; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -345,7 +345,7 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) return; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } From 1e4f2a96aeb373000ccd783e0f5b40294b5e668a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0550/1939] [PATCH] iomem annotations (ahci) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/ahci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 5ec866b00479..cfa22e4ee547 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -407,7 +407,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) return 0xffffffffU; } - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -425,7 +425,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, return; } - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_phy_reset(struct ata_port *ap) @@ -453,14 +453,14 @@ static void ahci_phy_reset(struct ata_port *ap) static u8 ahci_check_status(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } static u8 ahci_check_err(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; } From b181d3b0121e141cb410ea3126b4dbe4f8e1751a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0551/1939] [PATCH] iomem annotations (sata_promise) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_promise.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index def7e0d9dacb..9bf8cbd29901 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -324,7 +324,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -333,7 +333,7 @@ static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -523,8 +523,8 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) From 0420dd121d395e76f6b80fe232e7b4bc6a046f18 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0552/1939] [PATCH] enum safety (sata_qstor) sata_qstor strays into a nasty area - gcc handling of wide enums is full of bugs that got fixed between gcc versions creating portability nightmare. Single-member enums are safe, so are ones that stay within the range of int or unsigned int. Anything beyond that is asking for trouble. Declaration of constants split in two enums, taking the ~0UL one into a separate enum. Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_qstor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index ffcdeb68641c..e1c1dae27c52 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -51,8 +51,6 @@ enum { QS_PRD_BYTES = QS_MAX_PRD * 16, QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, - QS_DMA_BOUNDARY = ~0UL, - /* global register offsets */ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ QS_HID_HPHY = 0x0004, /* host physical interface info */ @@ -101,6 +99,10 @@ enum { board_2068_idx = 0, /* QStor 4-port SATA/RAID */ }; +enum { + QS_DMA_BOUNDARY = ~0UL +}; + typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; struct qs_port_priv { From a9afd7cd2f65ff85f5ffe931beb879ccf12540e0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0553/1939] [PATCH] iomem annotations (sata_sx4) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sx4.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 540a85191172..d6d350a0b5e9 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -137,7 +137,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void *dimm_mmio; + void __iomem *dimm_mmio; unsigned int doing_hdma; unsigned int hdma_prod; @@ -247,7 +247,7 @@ static void pdc20621_host_stop(struct ata_host_set *host_set) { struct pci_dev *pdev = to_pci_dev(host_set->dev); struct pdc_host_priv *hpriv = host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; pci_iounmap(pdev, dimm_mmio); kfree(hpriv); @@ -669,8 +669,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -747,8 +747,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -1014,7 +1014,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist); + memcpy_toio(dimm_mmio + offset / 4, psource, dist); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -1023,8 +1023,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, - window_size / 4); + memcpy_toio(dimm_mmio, psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += window_size; @@ -1035,7 +1034,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4); + memcpy_toio(dimm_mmio, psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); } From 9aa36e89b5677a98d951cf7bef6d99a0f93ea633 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0554/1939] [PATCH] iomem annotations (sata_sil) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index ba98a175ee3a..f6f0184e1ac8 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -289,7 +289,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -297,7 +297,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } From 307e4dc28ee255bf22b431f242f847c9d96fe3fa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 06:46:02 +0100 Subject: [PATCH 0555/1939] [PATCH] iomem annotations (sata_vsc) Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/scsi/sata_vsc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index cf94e0158a8d..877b9fda3965 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -86,7 +86,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -95,16 +95,16 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { - unsigned long mask_addr; + void __iomem *mask_addr; u8 mask; - mask_addr = (unsigned long) ap->host_set->mmio_base + + mask_addr = ap->host_set->mmio_base + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -283,7 +283,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d struct ata_probe_ent *probe_ent = NULL; unsigned long base; int pci_dev_busy = 0; - void *mmio_base; + void __iomem *mmio_base; int rc; if (!printed_version++) From d18566376055046fca0b51ad536f1778ef34966a Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 21 Oct 2005 10:17:37 +0100 Subject: [PATCH 0556/1939] [ARM] Fix Integrator IM/PD-1 support Signed-off-by: Russell King --- arch/arm/mach-integrator/impd1.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index c3c2f17d030e..a1b153d1626c 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -67,7 +67,7 @@ static void impd1_setvco(struct clk *clk, struct icst525_vco vco) } writel(0, impd1->base + IMPD1_LOCK); -#if DEBUG +#ifdef DEBUG vco.v = val & 0x1ff; vco.r = (val >> 9) & 0x7f; vco.s = (val >> 16) & 7; @@ -427,17 +427,18 @@ static int impd1_probe(struct lm_device *dev) return ret; } +static int impd1_remove_one(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + static void impd1_remove(struct lm_device *dev) { struct impd1_module *impd1 = lm_get_drvdata(dev); - struct list_head *l, *n; int i; - list_for_each_safe(l, n, &dev->dev.children) { - struct device *d = list_to_dev(l); - - device_unregister(d); - } + device_for_each_child(&dev->dev, NULL, impd1_remove_one); for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) clk_unregister(&impd1->vcos[i]); From b0faa28493f97b55b36ff5b1a2b8c81bf253a460 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 21 Oct 2005 15:43:42 +1000 Subject: [PATCH 0557/1939] [PATCH] Fix broken initialization of conswitchp for ARCH=ppc64 In the merge tree, commit 0458060c1c59c5378d8fb5daabe18cf4681c35cd broke boot on some machines because the initialization of conswitchp was moved to arch/powerpc/kernel/setup_64.c, but a corresponding copy was not added to arch/ppc64/kernel/setup.c. This patch fixes it. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 42019be0c6ad..b7885028fcf1 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1039,6 +1039,10 @@ void __init setup_arch(char **cmdline_p) /* initialize the syscall map in systemcfg */ setup_syscall_map(); +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + ppc_md.setup_arch(); /* Use the default idle loop if the platform hasn't provided one. */ From 6cb7bfebb145af5ea1d052512a2ae7ff07a47202 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 21 Oct 2005 15:45:50 +1000 Subject: [PATCH 0558/1939] [PATCH] powerpc: Merge thread_info.h Merge ppc32 and ppc64 versions of thread_info.h. They were pretty similar already, the chief changes are: - Instead of inline asm to implement current_thread_info(), which needs to be different for ppc32 and ppc64, we use C with an asm("r1") register variable. gcc turns it into the same asm as we used to have for both platforms. - We replace ppc32's 'local_flags' with the ppc64 'syscall_noerror' field. The noerror flag was in fact the only thing in the local_flags field anyway, so the ppc64 approach is simpler, and means we only need a load-immediate/store instead of load/mask/store when clearing the flag. - In readiness for 64k pages, when THREAD_SIZE will be less than a page, ppc64 used kmalloc() rather than get_free_pages() to allocate the kernel stack. With this patch we do the same for ppc32, since there's no strong reason not to. - For ppc64, we no longer export THREAD_SHIFT and THREAD_SIZE via asm-offsets, thread_info.h can now be safely included in asm, as on ppc32. Built and booted on G4 Powerbook (ARCH=ppc and ARCH=powerpc) and Power5 (ARCH=ppc64 and ARCH=powerpc). Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 6 +- arch/powerpc/kernel/entry_32.S | 25 ++-- arch/powerpc/kernel/head_64.S | 1 + arch/powerpc/kernel/misc_64.S | 1 + arch/ppc/kernel/asm-offsets.c | 2 +- arch/ppc/kernel/entry.S | 9 +- arch/ppc64/kernel/asm-offsets.c | 2 - arch/ppc64/kernel/head.S | 1 + arch/ppc64/kernel/misc.S | 1 + .../{asm-ppc64 => asm-powerpc}/thread_info.h | 34 ++++-- include/asm-ppc/ptrace.h | 2 +- include/asm-ppc/thread_info.h | 107 ------------------ 12 files changed, 45 insertions(+), 146 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/thread_info.h (84%) delete mode 100644 include/asm-ppc/thread_info.h diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b0d6a7cd85e9..1c83abd9f37c 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -56,8 +56,6 @@ int main(void) DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(MM, offsetof(struct task_struct, mm)); #ifdef CONFIG_PPC64 - DEFINE(THREAD_SHIFT, THREAD_SHIFT); - DEFINE(THREAD_SIZE, THREAD_SIZE); DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); @@ -94,12 +92,10 @@ int main(void) DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); -#ifdef CONFIG_PPC64 DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); -#else +#ifdef CONFIG_PPC32 DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); - DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index fc9dded9ac04..37b4396ca978 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -199,10 +199,9 @@ _GLOBAL(DoSyscall) #ifdef SHOW_SYSCALLS bl do_show_syscall #endif /* SHOW_SYSCALLS */ - rlwinm r10,r1,0,0,18 /* current_thread_info() */ - lwz r11,TI_LOCAL_FLAGS(r10) - rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR - stw r11,TI_LOCAL_FLAGS(r10) + rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ + li r11,0 + stb r11,TI_SC_NOERR(r10) lwz r11,TI_FLAGS(r10) andi. r11,r11,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace @@ -225,10 +224,10 @@ ret_from_syscall: mr r6,r3 li r11,-_LAST_ERRNO cmplw 0,r3,r11 - rlwinm r12,r1,0,0,18 /* current_thread_info() */ + rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ blt+ 30f - lwz r11,TI_LOCAL_FLAGS(r12) - andi. r11,r11,_TIFL_FORCE_NOERROR + lbz r11,TI_SC_NOERR(r12) + cmpwi r11,0 bne 30f neg r3,r3 lwz r10,_CCR(r1) /* Set SO bit in CR */ @@ -315,7 +314,7 @@ syscall_exit_work: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ SYNC MTMSRD(r10) /* disable interrupts again */ - rlwinm r12,r1,0,0,18 /* current_thread_info() */ + rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ lwz r9,TI_FLAGS(r12) 5: andi. r0,r9,_TIF_NEED_RESCHED @@ -630,7 +629,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) .globl sigreturn_exit sigreturn_exit: subi r1,r3,STACK_FRAME_OVERHEAD - rlwinm r12,r1,0,0,18 /* current_thread_info() */ + rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ lwz r9,TI_FLAGS(r12) andi. r0,r9,_TIF_SYSCALL_T_OR_A beq+ ret_from_except_full @@ -657,7 +656,7 @@ ret_from_except: user_exc_return: /* r10 contains MSR_KERNEL here */ /* Check current_thread_info()->flags */ - rlwinm r9,r1,0,0,18 + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r9,TI_FLAGS(r9) andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) bne do_work @@ -677,7 +676,7 @@ restore_user: /* N.B. the only way to get here is from the beq following ret_from_except. */ resume_kernel: /* check current_thread_info->preempt_count */ - rlwinm r9,r1,0,0,18 + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r0,TI_PREEMPT(r9) cmpwi 0,r0,0 /* if non-zero, just restore regs and return */ bne restore @@ -687,7 +686,7 @@ resume_kernel: andi. r0,r3,MSR_EE /* interrupts off? */ beq restore /* don't schedule if so */ 1: bl preempt_schedule_irq - rlwinm r9,r1,0,0,18 + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r3,TI_FLAGS(r9) andi. r0,r3,_TIF_NEED_RESCHED bne- 1b @@ -889,7 +888,7 @@ recheck: LOAD_MSR_KERNEL(r10,MSR_KERNEL) SYNC MTMSRD(r10) /* disable interrupts */ - rlwinm r9,r1,0,0,18 + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r9,TI_FLAGS(r9) andi. r0,r9,_TIF_NEED_RESCHED bne- do_resched diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index a4ceb9ae20fc..72b0d26e41d4 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 8fe295693c09..4775bed42cac 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -26,6 +26,7 @@ #include #include #include +#include .text diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index 7972db1f6570..968261d69572 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -130,10 +130,10 @@ main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); + DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 68fc61221776..f044edbb454f 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -200,9 +200,8 @@ _GLOBAL(DoSyscall) bl do_show_syscall #endif /* SHOW_SYSCALLS */ rlwinm r10,r1,0,0,18 /* current_thread_info() */ - lwz r11,TI_LOCAL_FLAGS(r10) - rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR - stw r11,TI_LOCAL_FLAGS(r10) + li r11,0 + stb r11,TI_SC_NOERR(r10) lwz r11,TI_FLAGS(r10) andi. r11,r11,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace @@ -227,8 +226,8 @@ ret_from_syscall: cmplw 0,r3,r11 rlwinm r12,r1,0,0,18 /* current_thread_info() */ blt+ 30f - lwz r11,TI_LOCAL_FLAGS(r12) - andi. r11,r11,_TIFL_FORCE_NOERROR + lbz r11,TI_SC_NOERR(r12) + cmpwi r11,0 bne 30f neg r3,r3 lwz r10,_CCR(r1) /* Set SO bit in CR */ diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 1378fbbe1e57..5e6046cb414e 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -46,8 +46,6 @@ int main(void) { /* thread struct on stack */ - DEFINE(THREAD_SHIFT, THREAD_SHIFT); - DEFINE(THREAD_SIZE, THREAD_SIZE); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index d5e6be200764..15c5f0c48043 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index ad73aad8dbb6..a33448c2bd91 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -28,6 +28,7 @@ #include #include #include +#include .text diff --git a/include/asm-ppc64/thread_info.h b/include/asm-powerpc/thread_info.h similarity index 84% rename from include/asm-ppc64/thread_info.h rename to include/asm-powerpc/thread_info.h index 71244d8a427d..0b4c24551c21 100644 --- a/include/asm-ppc64/thread_info.h +++ b/include/asm-powerpc/thread_info.h @@ -1,15 +1,25 @@ -/* thread_info.h: PPC low-level thread information +/* thread_info.h: PowerPC low-level thread information * adapted from the i386 version by Paul Mackerras * * Copyright (C) 2002 David Howells (dhowells@redhat.com) * - Incorporating suggestions made by Linus Torvalds and Dave Miller */ -#ifndef _ASM_THREAD_INFO_H -#define _ASM_THREAD_INFO_H +#ifndef _ASM_POWERPC_THREAD_INFO_H +#define _ASM_POWERPC_THREAD_INFO_H #ifdef __KERNEL__ +/* We have 8k stacks on ppc32 and 16k on ppc64 */ + +#ifdef CONFIG_PPC64 +#define THREAD_SHIFT 14 +#else +#define THREAD_SHIFT 13 +#endif + +#define THREAD_SIZE (1 << THREAD_SHIFT) + #ifndef __ASSEMBLY__ #include #include @@ -24,7 +34,8 @@ struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ int cpu; /* cpu we're on */ - int preempt_count; /* 0 => preemptable, <0 => BUG */ + int preempt_count; /* 0 => preemptable, + <0 => BUG */ struct restart_block restart_block; /* set by force_successful_syscall_return */ unsigned char syscall_noerror; @@ -54,9 +65,6 @@ struct thread_info { /* thread information allocation */ -#define THREAD_SHIFT 14 -#define THREAD_ORDER (THREAD_SHIFT - PAGE_SHIFT) -#define THREAD_SIZE (1 << THREAD_SHIFT) #ifdef CONFIG_DEBUG_STACK_USAGE #define alloc_thread_info(tsk) \ ({ \ @@ -68,7 +76,7 @@ struct thread_info { ret; \ }) #else -#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL) +#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL) #endif #define free_thread_info(ti) kfree(ti) #define get_thread_info(ti) get_task_struct((ti)->task) @@ -77,9 +85,11 @@ struct thread_info { /* how to get the thread information struct from C */ static inline struct thread_info *current_thread_info(void) { - struct thread_info *ti; - __asm__("clrrdi %0,1,%1" : "=r"(ti) : "i" (THREAD_SHIFT)); - return ti; + register unsigned long sp asm("r1"); + + /* gcc4, at least, is smart enough to turn this into a single + * rlwinm for ppc32 and clrrdi for ppc64 */ + return (struct thread_info *)(sp & ~(THREAD_SIZE-1)); } #endif /* __ASSEMBLY__ */ @@ -122,4 +132,4 @@ static inline struct thread_info *current_thread_info(void) #endif /* __KERNEL__ */ -#endif /* _ASM_THREAD_INFO_H */ +#endif /* _ASM_POWERPC_THREAD_INFO_H */ diff --git a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h index 7043c164b537..c34fb4e37a97 100644 --- a/include/asm-ppc/ptrace.h +++ b/include/asm-ppc/ptrace.h @@ -57,7 +57,7 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define force_successful_syscall_return() \ do { \ - current_thread_info()->local_flags |= _TIFL_FORCE_NOERROR; \ + current_thread_info()->syscall_noerror = 1; \ } while(0) /* diff --git a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h deleted file mode 100644 index 27903db42efc..000000000000 --- a/include/asm-ppc/thread_info.h +++ /dev/null @@ -1,107 +0,0 @@ -/* thread_info.h: PPC low-level thread information - * adapted from the i386 version by Paul Mackerras - * - * Copyright (C) 2002 David Howells (dhowells@redhat.com) - * - Incorporating suggestions made by Linus Torvalds and Dave Miller - */ - -#ifndef _ASM_THREAD_INFO_H -#define _ASM_THREAD_INFO_H - -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ -/* - * low level task data. - * If you change this, change the TI_* offsets below to match. - */ -struct thread_info { - struct task_struct *task; /* main task structure */ - struct exec_domain *exec_domain; /* execution domain */ - unsigned long flags; /* low level flags */ - unsigned long local_flags; /* non-racy flags */ - int cpu; /* cpu we're on */ - int preempt_count; /* 0 => preemptable, - <0 => BUG */ - struct restart_block restart_block; -}; - -#define INIT_THREAD_INFO(tsk) \ -{ \ - .task = &tsk, \ - .exec_domain = &default_exec_domain, \ - .flags = 0, \ - .local_flags = 0, \ - .cpu = 0, \ - .preempt_count = 1, \ - .restart_block = { \ - .fn = do_no_restart_syscall, \ - }, \ -} - -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - -/* - * macros/functions for gaining access to the thread information structure - */ - -/* how to get the thread information struct from C */ -static inline struct thread_info *current_thread_info(void) -{ - struct thread_info *ti; - __asm__("rlwinm %0,1,0,0,18" : "=r"(ti)); - return ti; -} - -/* thread information allocation */ -#define alloc_thread_info(tsk) ((struct thread_info *) \ - __get_free_pages(GFP_KERNEL, 1)) -#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) -#define get_thread_info(ti) get_task_struct((ti)->task) -#define put_thread_info(ti) put_task_struct((ti)->task) -#endif /* __ASSEMBLY__ */ - -/* - * Size of kernel stack for each process. - */ -#define THREAD_SIZE 8192 /* 2 pages */ - -#define PREEMPT_ACTIVE 0x10000000 - -/* - * thread information flag bit numbers - */ -#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ -#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ -#define TIF_SIGPENDING 2 /* signal pending */ -#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling - TIF_NEED_RESCHED */ -#define TIF_MEMDIE 5 -#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ -#define TIF_SECCOMP 7 /* secure computing */ - -/* as above, but as bit values */ -#define _TIF_SYSCALL_TRACE (1< Date: Fri, 21 Oct 2005 16:01:33 +1000 Subject: [PATCH 0559/1939] [PATCH] powerpc: Don't blow away load_addr in start_thread The patch to make process.c work for 32-bit and 64-bit (06d67d54741a5bfefa31945ef195dfa748c29025) broke some 64-bit binaries. We were blowing away load_addr in gpr[2], so we weren't properly relocating the entry point. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 193c8c1bf132..047da1ae21fe 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -595,6 +595,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, */ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { +#ifdef CONFIG_PPC64 + unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */ +#endif + set_fs(USER_DS); /* @@ -621,7 +625,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->msr = MSR_USER; #else if (!test_thread_flag(TIF_32BIT)) { - unsigned long entry, toc, load_addr = regs->gpr[2]; + unsigned long entry, toc; /* start is a relocated pointer to the function descriptor for * the elf _start routine. The first entry in the function From 05d84681abcb33fe34accb5982c413daeb4208c4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 21 Oct 2005 16:01:34 +1000 Subject: [PATCH 0560/1939] [PATCH] powerpc: Fix mmap returning 64 bit addresses The merge of syscalls.c & sys_ppc32.c (30286ef6e044bc3d9019c3d8b900572e3fa05e65) broke mmap, if the mmap returned a 64 bit address. do_mmap2 was taking the return value from do_mmap_pgoff (an unsigned long), and storing it in an int, before returning it to sys_mmap as an unsigned long. So we were losing the high bits of the address. You would have thought the compiler could catch this for us ... Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/syscalls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 7a23721365a6..f72ced11212d 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -162,7 +162,7 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len, unsigned long fd, unsigned long off, int shift) { struct file * file = NULL; - int ret = -EINVAL; + unsigned long ret = -EINVAL; if (shift) { if (off & ((1 << shift) - 1)) From d3f7bf4fa9626d371f26cd310477202628a8126a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 21 Oct 2005 12:39:52 -0500 Subject: [PATCH 0561/1939] ieee80211 subsystem: * Use GFP mask on TX skb allocation. * Use the tx_headroom and reserve requested space. Signed-off-by: Michael Buesch Signed-off-by: James Ketrenos --- net/ieee80211/ieee80211_tx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index f4f2a33973a7..fb4509032402 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -190,7 +190,7 @@ void ieee80211_txb_free(struct ieee80211_txb *txb) } static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, - gfp_t gfp_mask) + int headroom, gfp_t gfp_mask) { struct ieee80211_txb *txb; int i; @@ -204,11 +204,13 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, txb->frag_size = txb_size; for (i = 0; i < nr_frags; i++) { - txb->fragments[i] = dev_alloc_skb(txb_size); + txb->fragments[i] = __dev_alloc_skb(txb_size + headroom, + gfp_mask); if (unlikely(!txb->fragments[i])) { i--; break; } + skb_reserve(txb->fragments[i], headroom); } if (unlikely(i != nr_frags)) { while (i >= 0) @@ -384,7 +386,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); + txb = ieee80211_alloc_txb(nr_frags, frag_size, + ieee->tx_headroom, GFP_ATOMIC); if (unlikely(!txb)) { printk(KERN_WARNING "%s: Could not allocate TXB\n", ieee->dev->name); From 519a62bb8a0b0b383e6022cad6242cf63efc015c Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 20 Oct 2005 15:57:03 -0500 Subject: [PATCH 0562/1939] Update version ieee80211 stamp to 1.1.6 --- include/net/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 58f62224e7ea..5e38dca1d082 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -29,7 +29,7 @@ #include /* ARRAY_SIZE */ #include -#define IEEE80211_VERSION "git-1.1.5" +#define IEEE80211_VERSION "git-1.1.6" #define IEEE80211_DATA_LEN 2304 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section From 024358eeafd44ecffd0e7a1002ef3ccc1d0acd4d Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Fri, 21 Oct 2005 20:56:36 +0200 Subject: [PATCH 0563/1939] [PATCH] mptsas: fix phy identifiers This fixes handling of the phy identifiers in mptsas. Signed-off-by: Eric Moore [ split it a pre-2.6.14 portion from Eric's bigger patch ] Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds --- drivers/message/fusion/mptsas.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 429820e48c69..7de19a84dc74 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -257,8 +257,8 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); printk("Target ID=0x%X\n", pg0->TargetID); printk("Bus=0x%X\n", pg0->Bus); - printk("PhyNum=0x%X\n", pg0->PhyNum); - printk("AccessStatus=0x%X\n", le16_to_cpu(pg0->AccessStatus)); + printk("Parent Phy Num=0x%X\n", pg0->PhyNum); + printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)); printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)); printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags)); printk("Physical Port=0x%X\n", pg0->PhysicalPort); @@ -270,7 +270,7 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) printk("---- SAS EXPANDER PAGE 1 ------------\n"); printk("Physical Port=0x%X\n", pg1->PhysicalPort); - printk("PHY Identifier=0x%X\n", pg1->Phy); + printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier); printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate); printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate); printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate); @@ -604,7 +604,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, mptsas_print_expander_pg1(buffer); /* save config data */ - phy_info->phy_id = buffer->Phy; + phy_info->phy_id = buffer->PhyIdentifier; phy_info->port_id = buffer->PhysicalPort; phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; @@ -825,6 +825,8 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; handle = port_info->phy_info[i].identify.handle; if (port_info->phy_info[i].attached.handle) { @@ -881,6 +883,8 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].identify.handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; } if (port_info->phy_info[i].attached.handle) { From a1c7e111934b6375baf07a970d6c890d18d7e34f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Oct 2005 22:39:36 +1000 Subject: [PATCH 0564/1939] [PATCH] ppc64: Fix typo in time calculations This fixes a typo in the div128_by_32 function used in the timekeeping calculations on ppc64. If you look at the code it's quite obvious that we need (rb + c) rather than (rb + b). The "b" is clearly just a typo. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 9939c206afa4..b56c6a324e17 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -870,7 +870,7 @@ void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, rb = ((ra + b) - (x * divisor)) << 32; y = (rb + c)/divisor; - rc = ((rb + b) - (y * divisor)) << 32; + rc = ((rb + c) - (y * divisor)) << 32; z = (rc + d)/divisor; From 5d96551541a8f5521dcc8c634a18d42a3d349ec9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 21 Oct 2005 14:12:51 +1000 Subject: [PATCH 0565/1939] [PATCH] ppc64: Fix pages marked dirty abusively While working on 64K pages, I found this little buglet in our update_mmu_cache() implementation. The code calls __hash_page() passing it an "access" parameter (the type of access that triggers the hash) containing the bits _PAGE_RW and _PAGE_USER of the linux PTE. The latter is useless in this case and the former is wrong. In fact, if we have a writeable PTE and we pass _PAGE_RW to hash_page(), it will set _PAGE_DIRTY (since we track dirty that way, by hash faulting !dirty) which is not what we want. In fact, the correct fix is to always pass 0. That means that only read-only or already dirty read write PTEs will be preloaded. The (hopefully rare) case of a non dirty read write PTE can't be preloaded this way, it will have to fault in hash_page on the actual access. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc64/mm/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index c2157c9c3acb..be64b157afce 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -799,8 +799,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea, if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp)) local = 1; - __hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep, - 0x300, local); + __hash_page(ea, 0, vsid, ptep, 0x300, local); local_irq_restore(flags); } From e29971f9a4ca08c3c31b98be96c293ef9f7dcc32 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 20 Oct 2005 23:49:00 +0100 Subject: [PATCH 0566/1939] [PATCH] drm: another mga bug The wrong state emission routines were being called for G550, and consistent maps weren't correctly mapped... Signed-off-by: Dave Airlie Signed-off-by: Linus Torvalds --- drivers/char/drm/drm_vm.c | 3 ++- drivers/char/drm/mga_drv.h | 2 +- drivers/char/drm/mga_state.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index ced4215e2275..39ea96e42c5b 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -148,7 +148,8 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - page = vmalloc_to_page((void *)i); + page = (map->type == _DRM_CONSISTENT) ? + virt_to_page((void *)i) : vmalloc_to_page((void *)i); if (!page) return NOPAGE_OOM; get_page(page); diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index b22fdbd4f830..6059c5a5b105 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -227,7 +227,7 @@ static inline u32 _MGA_READ(u32 *addr) #define MGA_EMIT_STATE( dev_priv, dirty ) \ do { \ if ( (dirty) & ~MGA_UPLOAD_CLIPRECTS ) { \ - if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) { \ + if ( dev_priv->chipset >= MGA_CARD_TYPE_G400 ) { \ mga_g400_emit_state( dev_priv ); \ } else { \ mga_g200_emit_state( dev_priv ); \ diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c index 05bbb4719376..6ac5e006226f 100644 --- a/drivers/char/drm/mga_state.c +++ b/drivers/char/drm/mga_state.c @@ -53,7 +53,7 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv, /* Force reset of DWGCTL on G400 (eliminates clip disable bit). */ - if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl, MGA_LEN + MGA_EXEC, 0x80000000, MGA_DWGCTL, ctx->dwgctl, From 3078fcc1d18c7235b034dc889642c5300959fa20 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 21 Oct 2005 13:41:19 +1000 Subject: [PATCH 0567/1939] [PATCH] ppc64: Fix typo bug in iSeries hash code This fixes a stupid typo bug in the iSeries hash table code. When we place a hash PTE in the secondary bucket, instead of setting the SECONDARY flag bit, as we should, we (redundantly) set the VALID flag. This was introduced with the patch abolishing bitfields from the hash table code. Mea culpa, oops. It hasn't been noticed until now because in practice we don't hit the secondary bucket terribly often. Signed-off-by: David Gibson Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/iSeries_htab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c index 2192055a90a0..073b76661747 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/ppc64/kernel/iSeries_htab.c @@ -66,7 +66,7 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, } if (slot < 0) { /* MSB set means secondary group */ - vflags |= HPTE_V_VALID; + vflags |= HPTE_V_SECONDARY; secondary = 1; slot &= 0x7fffffffffffffff; } From 0213df74315bbab9ccaa73146f3e11972ea6de46 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2005 17:21:03 -0400 Subject: [PATCH 0568/1939] [PATCH] cpufreq: fix pending powernow timer stuck condition AMD recently discovered that on some hardware, there is a race condition possible when a C-state change request goes onto the bus at the same time as a P-state change request. Both requests happen, but the southbridge hardware only acknowledges the C-state change. The PowerNow! driver is then stuck in a loop, waiting for the P-state change acknowledgement. The driver eventually times out, but can no longer perform P-state changes. It turns out the solution is to resend the P-state change, which the southbridge will acknowledge normally. Thanks to Johannes Winkelmann for reporting this and testing the fix. Signed-off-by: Mark Langsdorf Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index ab6e0611303d..ec3a9e335aa3 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -44,7 +44,7 @@ #define PFX "powernow-k8: " #define BFX PFX "BIOS error: " -#define VERSION "version 1.50.3" +#define VERSION "version 1.50.4" #include "powernow-k8.h" /* serialize freq changes */ @@ -111,8 +111,8 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data) u32 i = 0; do { - if (i++ > 0x1000000) { - printk(KERN_ERR PFX "detected change pending stuck\n"); + if (i++ > 10000) { + dprintk("detected change pending stuck\n"); return 1; } rdmsr(MSR_FIDVID_STATUS, lo, hi); @@ -159,6 +159,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) { u32 lo; u32 savevid = data->currvid; + u32 i = 0; if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) { printk(KERN_ERR PFX "internal error - overflow on fid write\n"); @@ -170,10 +171,13 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n", fid, lo, data->plllock * PLL_LOCK_CONVERSION); - wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); - - if (query_current_values_with_pending_wait(data)) - return 1; + do { + wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); + if (i++ > 100) { + printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n"); + retrun 1; + } + } while (query_current_values_with_pending_wait(data)); count_off_irt(data); @@ -197,6 +201,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) { u32 lo; u32 savefid = data->currfid; + int i = 0; if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) { printk(KERN_ERR PFX "internal error - overflow on vid write\n"); @@ -208,10 +213,13 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n", vid, lo, STOP_GRANT_5NS); - wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); - - if (query_current_values_with_pending_wait(data)) - return 1; + do { + wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); + if (i++ > 100) { + printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n"); + return 1; + } + } while (query_current_values_with_pending_wait(data)); if (savefid != data->currfid) { printk(KERN_ERR PFX "fid changed on vid trans, old 0x%x new 0x%x\n", From 9465bee863bc4c6cf1566c12d6f92a8133e3da5c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 21 Oct 2005 15:36:00 -0700 Subject: [PATCH 0569/1939] Revert "Fix cpu timers exit deadlock and races" Revert commit e03d13e985d48ac4885382c9e3b1510c78bd047f, to be replaced by a much nicer fix from Roland. --- kernel/posix-cpu-timers.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index b3f3edc475de..7a51a5597c33 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -387,19 +387,25 @@ int posix_cpu_timer_del(struct k_itimer *timer) if (unlikely(p == NULL)) return 0; - spin_lock(&p->sighand->siglock); if (!list_empty(&timer->it.cpu.entry)) { - /* - * Take us off the task's timer list. We don't need to - * take tasklist_lock and check for the task being reaped. - * If it was reaped, it already called posix_cpu_timers_exit - * and posix_cpu_timers_exit_group to clear all the timers - * that pointed to it. - */ - list_del(&timer->it.cpu.entry); - put_task_struct(p); + read_lock(&tasklist_lock); + if (unlikely(p->signal == NULL)) { + /* + * We raced with the reaping of the task. + * The deletion should have cleared us off the list. + */ + BUG_ON(!list_empty(&timer->it.cpu.entry)); + } else { + /* + * Take us off the task's timer list. + */ + spin_lock(&p->sighand->siglock); + list_del(&timer->it.cpu.entry); + spin_unlock(&p->sighand->siglock); + } + read_unlock(&tasklist_lock); } - spin_unlock(&p->sighand->siglock); + put_task_struct(p); return 0; } From 25f407f0b668f5e4ebd5d13e1fb4306ba6427ead Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 21 Oct 2005 15:03:29 -0700 Subject: [PATCH 0570/1939] [PATCH] Call exit_itimers from do_exit, not __exit_signal When I originally moved exit_itimers into __exit_signal, that was the only place where we could reliably know it was the last thread in the group dying, without races. Since then we've gotten the signal_struct.live counter, and do_exit can reliably do group-wide cleanup work. This patch moves the call to do_exit, where it's made without locks. This avoids the deadlock issues that the old __exit_signal code's comment talks about, and the one that Oleg found recently with process CPU timers. [ This replaces e03d13e985d48ac4885382c9e3b1510c78bd047f, which is why it was just reverted. ] Signed-off-by: Roland McGrath Signed-off-by: Linus Torvalds --- kernel/exit.c | 1 + kernel/posix-timers.c | 2 +- kernel/signal.c | 14 +------------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 43077732619b..3b25b182d2be 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -843,6 +843,7 @@ fastcall NORET_TYPE void do_exit(long code) group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { del_timer_sync(&tsk->signal->real_timer); + exit_itimers(tsk->signal); acct_process(code); } exit_mm(tsk); diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index b7b532acd9fc..dda3cda73c77 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -1157,7 +1157,7 @@ static inline void itimer_delete(struct k_itimer *timer) } /* - * This is called by __exit_signal, only when there are no more + * This is called by do_exit or de_thread, only when there are no more * references to the shared signal_struct. */ void exit_itimers(struct signal_struct *sig) diff --git a/kernel/signal.c b/kernel/signal.c index 50c992643771..f2b96b08fb44 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -397,20 +397,8 @@ void __exit_signal(struct task_struct *tsk) flush_sigqueue(&tsk->pending); if (sig) { /* - * We are cleaning up the signal_struct here. We delayed - * calling exit_itimers until after flush_sigqueue, just in - * case our thread-local pending queue contained a queued - * timer signal that would have been cleared in - * exit_itimers. When that called sigqueue_free, it would - * attempt to re-take the tasklist_lock and deadlock. This - * can never happen if we ensure that all queues the - * timer's signal might be queued on have been flushed - * first. The shared_pending queue, and our own pending - * queue are the only queues the timer could be on, since - * there are no other threads left in the group and timer - * signals are constrained to threads inside the group. + * We are cleaning up the signal_struct here. */ - exit_itimers(sig); exit_thread_group_keys(sig); kmem_cache_free(signal_cachep, sig); } From 11e29e21514517f3022a1f30998ac4c7b1197658 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 21 Oct 2005 18:46:32 -0400 Subject: [PATCH 0571/1939] libata: handle early device PIO modes correctly --- drivers/scsi/libata-core.c | 31 +++++++++++++++++++++++++++---- include/linux/ata.h | 13 +++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 175d4646333d..09639e7aaa71 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1082,6 +1082,31 @@ static inline void ata_dump_id(struct ata_device *dev) dev->id[93]); } +/* + * Compute the PIO modes available for this device. This is not as + * trivial as it seems if we must consider early devices correctly. + * + * FIXME: pre IDE drive timing (do we care ?). + */ + +static unsigned int ata_pio_modes(struct ata_device *adev) +{ + u16 modes; + + /* Usual case. Word 53 indicates word 88 is valid */ + if (adev->id[ATA_ID_FIELD_VALID] & (1 << 2)) { + modes = adev->id[ATA_ID_PIO_MODES] & 0x03; + modes <<= 3; + modes |= 0x7; + return modes; + } + + /* If word 88 isn't valid then Word 51 holds the PIO timing number + for the maximum. Turn it into a mask and return it */ + modes = (2 << (adev->id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + return modes; +} + /** * ata_dev_identify - obtain IDENTIFY x DEVICE page * @ap: port on which device we wish to probe resides @@ -1215,10 +1240,8 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) xfer_modes = dev->id[ATA_ID_UDMA_MODES]; if (!xfer_modes) xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; - if (!xfer_modes) { - xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); - xfer_modes |= (0x7 << ATA_SHIFT_PIO); - } + if (!xfer_modes) + xfer_modes = ata_pio_modes(dev); ata_dump_id(dev); diff --git a/include/linux/ata.h b/include/linux/ata.h index 630908c9378b..33276d1d05d2 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -42,13 +42,18 @@ enum { ATA_SECT_SIZE = 512, ATA_ID_WORDS = 256, - ATA_ID_PROD_OFS = 27, - ATA_ID_FW_REV_OFS = 23, ATA_ID_SERNO_OFS = 10, - ATA_ID_MAJOR_VER = 80, - ATA_ID_PIO_MODES = 64, + ATA_ID_FW_REV_OFS = 23, + ATA_ID_PROD_OFS = 27, + ATA_ID_OLD_PIO_MODES = 51, + ATA_ID_FIELD_VALID = 53, ATA_ID_MWDMA_MODES = 63, + ATA_ID_PIO_MODES = 64, + ATA_ID_EIDE_DMA_MIN = 65, + ATA_ID_EIDE_PIO = 67, + ATA_ID_EIDE_PIO_IORDY = 68, ATA_ID_UDMA_MODES = 88, + ATA_ID_MAJOR_VER = 80, ATA_ID_PIO4 = (1 << 1), ATA_PCI_CTL_OFS = 2, From 452503f993feffe96e8cc9fbff4888b96e2c5e40 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 21 Oct 2005 19:01:32 -0400 Subject: [PATCH 0572/1939] Add ide-timing functionality to libata. This is needed for full AMD and VIA drivers and possibly more. Functions to turn actual clocking and cycle timings into register values. Also to merge shared timings to compute an optimal timing set. Built from the drivers/ide version by Vojtech Pavlik Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 149 +++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 39 ++++++++++ 2 files changed, 188 insertions(+) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 09639e7aaa71..9269fd9b814f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1538,6 +1538,152 @@ void ata_port_disable(struct ata_port *ap) ap->flags |= ATA_FLAG_PORT_DISABLED; } +/* + * This mode timing computation functionality is ported over from + * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik + */ +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. + */ + +static const struct ata_timing ata_timing[] = { + + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + +/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + +/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */ + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + + { 0xFF } +}; + +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT) +{ + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); +} + +void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, + struct ata_timing *m, unsigned int what) +{ + if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup); + if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); + if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); + if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active); + if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover); + if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); + if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); +} + +static const struct ata_timing* ata_timing_find_mode(unsigned short speed) +{ + const struct ata_timing *t; + + for (t = ata_timing; t->mode != speed; t++) + if (t->mode != 0xFF) + return NULL; + return t; +} + +int ata_timing_compute(struct ata_device *adev, unsigned short speed, + struct ata_timing *t, int T, int UT) +{ + const struct ata_timing *s; + struct ata_timing p; + + /* + * Find the mode. + */ + + if (!(s = ata_timing_find_mode(speed))) + return -EINVAL; + + /* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MW_DMA cycle timing. + */ + + if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + memset(&p, 0, sizeof(p)); + if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) { + if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO]; + else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY]; + } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { + p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN]; + } + ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); + } + + /* + * Convert the timing to bus clock counts. + */ + + ata_timing_quantize(s, t, T, UT); + + /* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T + * and some other commands. We have to ensure that the DMA cycle timing is + * slower/equal than the fastest PIO timing. + */ + + if (speed > XFER_PIO_4) { + ata_timing_compute(adev, adev->pio_mode, &p, T, UT); + ata_timing_merge(&p, t, t, ATA_TIMING_ALL); + } + + /* + * Lenghten active & recovery time so that cycle time is correct. + */ + + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} + static struct { unsigned int shift; u8 base; @@ -4764,6 +4910,9 @@ EXPORT_SYMBOL_GPL(ata_dev_id_string); EXPORT_SYMBOL_GPL(ata_dev_config); EXPORT_SYMBOL_GPL(ata_scsi_simulate); +EXPORT_SYMBOL_GPL(ata_timing_compute); +EXPORT_SYMBOL_GPL(ata_timing_merge); + #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_host_stop); diff --git a/include/linux/libata.h b/include/linux/libata.h index 0261c55f3483..0e214f8c8f9f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -388,6 +388,19 @@ struct ata_port_info { struct ata_port_operations *port_ops; }; +struct ata_timing { + unsigned short mode; /* ATA mode */ + unsigned short setup; /* t1 */ + unsigned short act8b; /* t2 for 8-bit I/O */ + unsigned short rec8b; /* t2i for 8-bit I/O */ + unsigned short cyc8b; /* t0 for 8-bit I/O */ + unsigned short active; /* t2 or tD */ + unsigned short recover; /* t2i or tK */ + unsigned short cycle; /* t0 */ + unsigned short udma; /* t2CYCTYP/2 */ +}; + +#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); @@ -451,6 +464,32 @@ extern int ata_std_bios_param(struct scsi_device *sdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); +/* + * Timing helpers + */ +extern int ata_timing_compute(struct ata_device *, unsigned short, + struct ata_timing *, int, int); +extern void ata_timing_merge(const struct ata_timing *, + const struct ata_timing *, struct ata_timing *, + unsigned int); + +enum { + ATA_TIMING_SETUP = (1 << 0), + ATA_TIMING_ACT8B = (1 << 1), + ATA_TIMING_REC8B = (1 << 2), + ATA_TIMING_CYC8B = (1 << 3), + ATA_TIMING_8BIT = ATA_TIMING_ACT8B | ATA_TIMING_REC8B | + ATA_TIMING_CYC8B, + ATA_TIMING_ACTIVE = (1 << 4), + ATA_TIMING_RECOVER = (1 << 5), + ATA_TIMING_CYCLE = (1 << 6), + ATA_TIMING_UDMA = (1 << 7), + ATA_TIMING_ALL = ATA_TIMING_SETUP | ATA_TIMING_ACT8B | + ATA_TIMING_REC8B | ATA_TIMING_CYC8B | + ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER | + ATA_TIMING_CYCLE | ATA_TIMING_UDMA, +}; + #ifdef CONFIG_PCI struct pci_bits { From 63172cb3d5ef762dcb60a292bc7f016b85cf6e1f Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 21 Oct 2005 16:56:08 -0700 Subject: [PATCH 0573/1939] [PATCH] typo fix in last cpufreq powernow patch Not sure how it slipped by, but here's a trivial typo fix for powernow. Signed-off-by: Chris Wright [ It's "nurter" backwards.. Maybe we have a hillbilly The Shining fan? ] Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index ec3a9e335aa3..58ca98fdc2ca 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -175,7 +175,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); if (i++ > 100) { printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n"); - retrun 1; + return 1; } } while (query_current_values_with_pending_wait(data)); From 5658374766d9e0249bd04e9d62bdb8456b916b64 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:33:38 -0400 Subject: [PATCH 0574/1939] [PARISC] Convert parisc_device tree to use struct device klists Fix parse_tree_node. much more needs to be done to fix this file. Signed-off-by: Matthew Wilcox Make drivers.c compile based on a patch from Pat Mochel. From: Patrick Mochel Signed-off-by: Kyle McMartin Fix drivers.c to create new device tree nodes when no match is found. Signed-off-by: Richard Hirst Do a proper depth-first search returning parents before children, using the new klist infrastructure. Signed-off-by: Richard Hirst Fixed parisc_device traversal so that pdc_stable works again Fixed check_dev so it doesn't dereference a parisc_device until it has verified the bus type Signed-off-by: Randolph Chung Convert pa_dev->hpa from an unsigned long to a struct resource. Use insert_resource() instead of request_mem_region(). Request resources at bus walk time instead of driver probe time. Don't release the resources as we don't have any hotplug parisc_device support yet. Add parisc_pathname() to conveniently get the textual representation of the hwpath used in sysfs. Inline the remnants of claim_device() into its caller. Signed-off-by: Matthew Wilcox I noticed that some of the STI regions weren't showing up in iomem. Reading the STI spec indicated that all STI devices occupy at least 32MB. So check for STI HPAs and give them 32MB instead of 4kB. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/drivers.c | 273 ++++++++++++++++++++--------- drivers/parisc/gsc.c | 11 +- drivers/parisc/sba_iommu.c | 20 ++- include/asm-parisc/parisc-device.h | 5 + 4 files changed, 217 insertions(+), 92 deletions(-) diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index d34bbe7ae0e3..988844a169e6 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -46,36 +46,51 @@ static struct device root = { .bus_id = "parisc", }; -#define for_each_padev(padev) \ - for (padev = next_dev(&root); padev != NULL; \ - padev = next_dev(&padev->dev)) +static inline int check_dev(struct device *dev) +{ + if (dev->bus == &parisc_bus_type) { + struct parisc_device *pdev; + pdev = to_parisc_device(dev); + return pdev->id.hw_type != HPHW_FAULTY; + } + return 1; +} -#define check_dev(padev) \ - (padev->id.hw_type != HPHW_FAULTY) ? padev : next_dev(&padev->dev) +static struct device * +parse_tree_node(struct device *parent, int index, struct hardware_path *modpath); + +struct recurse_struct { + void * obj; + int (*fn)(struct device *, void *); +}; + +static int descend_children(struct device * dev, void * data) +{ + struct recurse_struct * recurse_data = (struct recurse_struct *)data; + + if (recurse_data->fn(dev, recurse_data->obj)) + return 1; + else + return device_for_each_child(dev, recurse_data, descend_children); +} /** - * next_dev - enumerates registered devices - * @dev: the previous device returned from next_dev + * for_each_padev - Iterate over all devices in the tree + * @fn: Function to call for each device. + * @data: Data to pass to the called function. * - * next_dev does a depth-first search of the tree, returning parents - * before children. Returns NULL when there are no more devices. + * This performs a depth-first traversal of the tree, calling the + * function passed for each node. It calls the function for parents + * before children. */ -static struct parisc_device *next_dev(struct device *dev) + +static int for_each_padev(int (*fn)(struct device *, void *), void * data) { - if (!list_empty(&dev->children)) { - dev = list_to_dev(dev->children.next); - return check_dev(to_parisc_device(dev)); - } - - while (dev != &root) { - if (dev->node.next != &dev->parent->children) { - dev = list_to_dev(dev->node.next); - return to_parisc_device(dev); - } - dev = dev->parent; - } - - return NULL; + struct recurse_struct recurse_data = { + .obj = data, + .fn = fn, + }; + return device_for_each_child(&root, &recurse_data, descend_children); } /** @@ -105,12 +120,6 @@ static int match_device(struct parisc_driver *driver, struct parisc_device *dev) return 0; } -static void claim_device(struct parisc_driver *driver, struct parisc_device *dev) -{ - dev->driver = driver; - request_mem_region(dev->hpa, 0x1000, driver->name); -} - static int parisc_driver_probe(struct device *dev) { int rc; @@ -119,8 +128,8 @@ static int parisc_driver_probe(struct device *dev) rc = pa_drv->probe(pa_dev); - if(!rc) - claim_device(pa_drv, pa_dev); + if (!rc) + pa_dev->driver = pa_drv; return rc; } @@ -131,7 +140,6 @@ static int parisc_driver_remove(struct device *dev) struct parisc_driver *pa_drv = to_parisc_driver(dev->driver); if (pa_drv->remove) pa_drv->remove(pa_dev); - release_mem_region(pa_dev->hpa, 0x1000); return 0; } @@ -173,6 +181,24 @@ int register_parisc_driver(struct parisc_driver *driver) } EXPORT_SYMBOL(register_parisc_driver); + +struct match_count { + struct parisc_driver * driver; + int count; +}; + +static int match_and_count(struct device * dev, void * data) +{ + struct match_count * m = data; + struct parisc_device * pdev = to_parisc_device(dev); + + if (check_dev(dev)) { + if (match_device(m->driver, pdev)) + m->count++; + } + return 0; +} + /** * count_parisc_driver - count # of devices this driver would match * @driver: the PA-RISC driver to try @@ -182,15 +208,14 @@ EXPORT_SYMBOL(register_parisc_driver); */ int count_parisc_driver(struct parisc_driver *driver) { - struct parisc_device *device; - int cnt = 0; + struct match_count m = { + .driver = driver, + .count = 0, + }; - for_each_padev(device) { - if (match_device(driver, device)) - cnt++; - } + for_each_padev(match_and_count, &m); - return cnt; + return m.count; } @@ -206,14 +231,34 @@ int unregister_parisc_driver(struct parisc_driver *driver) } EXPORT_SYMBOL(unregister_parisc_driver); +struct find_data { + unsigned long hpa; + struct parisc_device * dev; +}; + +static int find_device(struct device * dev, void * data) +{ + struct parisc_device * pdev = to_parisc_device(dev); + struct find_data * d = (struct find_data*)data; + + if (check_dev(dev)) { + if (pdev->hpa.start == d->hpa) { + d->dev = pdev; + return 1; + } + } + return 0; +} + static struct parisc_device *find_device_by_addr(unsigned long hpa) { - struct parisc_device *dev; - for_each_padev(dev) { - if (dev->hpa == hpa) - return dev; - } - return NULL; + struct find_data d = { + .hpa = hpa, + }; + int ret; + + ret = for_each_padev(find_device, &d); + return ret ? d.dev : NULL; } /** @@ -387,6 +432,23 @@ struct parisc_device * create_tree_node(char id, struct device *parent) return dev; } +struct match_id_data { + char id; + struct parisc_device * dev; +}; + +static int match_by_id(struct device * dev, void * data) +{ + struct parisc_device * pdev = to_parisc_device(dev); + struct match_id_data * d = data; + + if (pdev->hw_path == d->id) { + d->dev = pdev; + return 1; + } + return 0; +} + /** * alloc_tree_node - returns a device entry in the iotree * @parent: the parent node in the tree @@ -397,15 +459,13 @@ struct parisc_device * create_tree_node(char id, struct device *parent) */ static struct parisc_device * alloc_tree_node(struct device *parent, char id) { - struct device *dev; - - list_for_each_entry(dev, &parent->children, node) { - struct parisc_device *padev = to_parisc_device(dev); - if (padev->hw_path == id) - return padev; - } - - return create_tree_node(id, parent); + struct match_id_data d = { + .id = id, + }; + if (device_for_each_child(parent, &d, match_by_id)) + return d.dev; + else + return create_tree_node(id, parent); } static struct parisc_device *create_parisc_device(struct hardware_path *modpath) @@ -439,10 +499,8 @@ alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path) dev = create_parisc_device(mod_path); if (dev->id.hw_type != HPHW_FAULTY) { - char p[64]; - print_pa_hwpath(dev, p); printk("Two devices have hardware path %s. Please file a bug with HP.\n" - "In the meantime, you could try rearranging your cards.\n", p); + "In the meantime, you could try rearranging your cards.\n", parisc_pathname(dev)); return NULL; } @@ -451,12 +509,27 @@ alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path) dev->id.hversion_rev = iodc_data[1] & 0x0f; dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) | (iodc_data[5] << 8) | iodc_data[6]; - dev->hpa = hpa; + dev->hpa.name = parisc_pathname(dev); + dev->hpa.start = hpa; + if (hpa == 0xf4000000 || hpa == 0xf6000000 || + hpa == 0xf8000000 || hpa == 0xfa000000) { + dev->hpa.end = hpa + 0x01ffffff; + } else { + dev->hpa.end = hpa + 0xfff; + } + dev->hpa.flags = IORESOURCE_MEM; name = parisc_hardware_description(&dev->id); if (name) { strlcpy(dev->name, name, sizeof(dev->name)); } + /* Silently fail things like mouse ports which are subsumed within + * the keyboard controller + */ + if ((hpa & 0xfff) == 0 && insert_resource(&iomem_resource, &dev->hpa)) + printk("Unable to claim HPA %lx for device %s\n", + hpa, name); + return dev; } @@ -555,6 +628,33 @@ static int match_parisc_device(struct device *dev, int index, return (curr->hw_path == id); } +struct parse_tree_data { + int index; + struct hardware_path * modpath; + struct device * dev; +}; + +static int check_parent(struct device * dev, void * data) +{ + struct parse_tree_data * d = data; + + if (check_dev(dev)) { + if (dev->bus == &parisc_bus_type) { + if (match_parisc_device(dev, d->index, d->modpath)) + d->dev = dev; + } else if (is_pci_dev(dev)) { + if (match_pci_device(dev, d->index, d->modpath)) + d->dev = dev; + } else if (dev->bus == NULL) { + /* we are on a bus bridge */ + struct device *new = parse_tree_node(dev, d->index, d->modpath); + if (new) + d->dev = new; + } + } + return d->dev != NULL; +} + /** * parse_tree_node - returns a device entry in the iotree * @parent: the parent node in the tree @@ -568,24 +668,18 @@ static int match_parisc_device(struct device *dev, int index, static struct device * parse_tree_node(struct device *parent, int index, struct hardware_path *modpath) { - struct device *device; - - list_for_each_entry(device, &parent->children, node) { - if (device->bus == &parisc_bus_type) { - if (match_parisc_device(device, index, modpath)) - return device; - } else if (is_pci_dev(device)) { - if (match_pci_device(device, index, modpath)) - return device; - } else if (device->bus == NULL) { - /* we are on a bus bridge */ - struct device *new = parse_tree_node(device, index, modpath); - if (new) - return new; - } - } + struct parse_tree_data d = { + .index = index, + .modpath = modpath, + }; - return NULL; + struct recurse_struct recurse_data = { + .obj = &d, + .fn = check_parent, + }; + + device_for_each_child(parent, &recurse_data, descend_children); + return d.dev; } /** @@ -636,7 +730,7 @@ EXPORT_SYMBOL(device_to_hwpath); ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT)) #define IS_LOWER_PORT(dev) \ - ((gsc_readl(dev->hpa + offsetof(struct bc_module, io_status)) \ + ((gsc_readl(dev->hpa.start + offsetof(struct bc_module, io_status)) \ & BC_PORT_MASK) == BC_LOWER_PORT) #define MAX_NATIVE_DEVICES 64 @@ -645,8 +739,8 @@ EXPORT_SYMBOL(device_to_hwpath); #define FLEX_MASK F_EXTEND(0xfffc0000) #define IO_IO_LOW offsetof(struct bc_module, io_io_low) #define IO_IO_HIGH offsetof(struct bc_module, io_io_high) -#define READ_IO_IO_LOW(dev) (unsigned long)(signed int)gsc_readl(dev->hpa + IO_IO_LOW) -#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)gsc_readl(dev->hpa + IO_IO_HIGH) +#define READ_IO_IO_LOW(dev) (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_LOW) +#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_HIGH) static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, struct device *parent); @@ -655,10 +749,10 @@ void walk_lower_bus(struct parisc_device *dev) { unsigned long io_io_low, io_io_high; - if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev)) + if (!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev)) return; - if(dev->id.hw_type == HPHW_IOA) { + if (dev->id.hw_type == HPHW_IOA) { io_io_low = (unsigned long)(signed int)(READ_IO_IO_LOW(dev) << 16); io_io_high = io_io_low + MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET; } else { @@ -731,7 +825,7 @@ static void print_parisc_device(struct parisc_device *dev) print_pa_hwpath(dev, hw_path); printk(KERN_INFO "%d. %s at 0x%lx [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }", - ++count, dev->name, dev->hpa, hw_path, dev->id.hw_type, + ++count, dev->name, dev->hpa.start, hw_path, dev->id.hw_type, dev->id.hversion_rev, dev->id.hversion, dev->id.sversion); if (dev->num_addrs) { @@ -753,13 +847,20 @@ void init_parisc_bus(void) get_device(&root); } + +static int print_one_device(struct device * dev, void * data) +{ + struct parisc_device * pdev = to_parisc_device(dev); + + if (check_dev(dev)) + print_parisc_device(pdev); + return 0; +} + /** * print_parisc_devices - Print out a list of devices found in this system */ void print_parisc_devices(void) { - struct parisc_device *dev; - for_each_padev(dev) { - print_parisc_device(dev); - } + for_each_padev(print_one_device, NULL); } diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index af5e02526a18..16d40f95978d 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -183,12 +183,20 @@ void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp) *irqp = irq; } +static struct device *next_device(struct klist_iter *i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, void (*choose_irq)(struct parisc_device *, void *)) { struct device *dev; + struct klist_iter i; - list_for_each_entry(dev, &parent->dev.children, node) { + klist_iter_init(&parent->dev.klist_children, &i); + while ((dev = next_device(&i))) { struct parisc_device *padev = to_parisc_device(dev); /* work-around for 715/64 and others which have parent @@ -197,6 +205,7 @@ void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, return gsc_fixup_irqs(padev, ctrl, choose_irq); choose_irq(padev, ctrl); } + klist_iter_exit(&i); } int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 82ea68b55df4..a8405f05fb5f 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1322,19 +1322,29 @@ sba_alloc_pdir(unsigned int pdir_size) return (void *) pdir_base; } -/* setup Mercury or Elroy IBASE/IMASK registers. */ -static void setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num) +static struct device *next_device(struct klist_iter *i) { - /* lba_set_iregs() is in drivers/parisc/lba_pci.c */ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + +/* setup Mercury or Elroy IBASE/IMASK registers. */ +static void +setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num) +{ + /* lba_set_iregs() is in drivers/parisc/lba_pci.c */ extern void lba_set_iregs(struct parisc_device *, u32, u32); struct device *dev; + struct klist_iter i; - list_for_each_entry(dev, &sba->dev.children, node) { + klist_iter_init(&sba->dev.klist_children, &i); + while ((dev = next_device(&i))) { struct parisc_device *lba = to_parisc_device(dev); - int rope_num = (lba->hpa >> 13) & 0xf; + int rope_num = (lba->hpa.start >> 13) & 0xf; if (rope_num >> 3 == ioc_num) lba_set_iregs(lba, ioc->ibase, ioc->imask); } + klist_iter_exit(&i); } static void diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h index ef69ab4b17a9..cbde8b41c84b 100644 --- a/include/asm-parisc/parisc-device.h +++ b/include/asm-parisc/parisc-device.h @@ -39,6 +39,11 @@ struct parisc_driver { #define to_parisc_driver(d) container_of(d, struct parisc_driver, drv) #define parisc_parent(d) to_parisc_device(d->dev.parent) +static inline char *parisc_pathname(struct parisc_device *d) +{ + return d->dev.bus_id; +} + static inline void parisc_set_drvdata(struct parisc_device *d, void *p) { From bdad1f836ab1ca2b18a625222f63f630cfd14e41 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:36:23 -0400 Subject: [PATCH 0575/1939] [PARISC] Change the driver names so /sys/bus/parisc/drivers/ looks better Make /sys/bus/parisc/drivers look better by cleaning up parisc_driver names. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/input/keyboard/hilkbd.c | 2 +- drivers/input/serio/gscps2.c | 2 +- drivers/input/serio/hp_sdc.c | 2 +- drivers/net/lasi_82596.c | 2 +- drivers/parisc/asp.c | 2 +- drivers/parisc/ccio-dma.c | 2 +- drivers/parisc/dino.c | 4 ++-- drivers/parisc/eisa.c | 2 +- drivers/parisc/hppb.c | 2 +- drivers/parisc/lasi.c | 2 +- drivers/scsi/lasi700.c | 2 +- drivers/serial/mux.c | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index eecb77db0847..8aa81c9ac2f7 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -299,7 +299,7 @@ static struct parisc_device_id hil_tbl[] = { MODULE_DEVICE_TABLE(parisc, hil_tbl); static struct parisc_driver hil_driver = { - .name = "HIL", + .name = "hil", .id_table = hil_tbl, .probe = hil_init_chip, }; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 897e4c12b642..4bad2810190c 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -444,7 +444,7 @@ static struct parisc_device_id gscps2_device_tbl[] = { }; static struct parisc_driver parisc_ps2_driver = { - .name = "GSC PS2", + .name = "gsc_ps2", .id_table = gscps2_device_tbl, .probe = gscps2_probe, .remove = gscps2_remove, diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 7629452dd64b..045b9a7a9dbb 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -764,7 +764,7 @@ MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl); static int __init hp_sdc_init_hppa(struct parisc_device *d); static struct parisc_driver hp_sdc_driver = { - .name = "HP SDC", + .name = "hp_sdc", .id_table = hp_sdc_tbl, .probe = hp_sdc_init_hppa, }; diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 41bad07ac1ac..180e526a2049 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1566,7 +1566,7 @@ static struct parisc_device_id lan_tbl[] = { MODULE_DEVICE_TABLE(parisc, lan_tbl); static struct parisc_driver lan_driver = { - .name = "Apricot", + .name = "lasi_82596", .id_table = lan_tbl, .probe = lan_init_chip, }; diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 388609967133..52f37b424318 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -126,7 +126,7 @@ static struct parisc_device_id asp_tbl[] = { }; struct parisc_driver asp_driver = { - .name = "Asp", + .name = "asp", .id_table = asp_tbl, .probe = asp_init_chip, }; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 0e98a9d9834c..2bb1889c4c4f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1251,7 +1251,7 @@ static struct parisc_device_id ccio_tbl[] = { static int ccio_probe(struct parisc_device *dev); static struct parisc_driver ccio_driver = { - .name = "U2:Uturn", + .name = "ccio", .id_table = ccio_tbl, .probe = ccio_probe, }; diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 2f2dbef2c3b7..8c61705e67a5 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -1027,9 +1027,9 @@ static struct parisc_device_id dino_tbl[] = { }; static struct parisc_driver dino_driver = { - .name = "Dino", + .name = "dino", .id_table = dino_tbl, - .probe = dino_driver_callback, + .probe = dino_probe, }; /* diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 043d47aea75b..0afeedddf535 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -397,7 +397,7 @@ static struct parisc_device_id eisa_tbl[] = { MODULE_DEVICE_TABLE(parisc, eisa_tbl); static struct parisc_driver eisa_driver = { - .name = "EISA Bus Adapter", + .name = "eisa_ba", .id_table = eisa_tbl, .probe = eisa_probe, }; diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index e869c6020370..a6eae3e7c0cd 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -93,7 +93,7 @@ static struct parisc_device_id hppb_tbl[] = { }; static struct parisc_driver hppb_driver = { - .name = "Gecko Boa", + .name = "gecko_boa", .id_table = hppb_tbl, .probe = hppb_probe, }; diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index cb84a4e84a2f..c776c372ae4e 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -233,7 +233,7 @@ static struct parisc_device_id lasi_tbl[] = { }; struct parisc_driver lasi_driver = { - .name = "Lasi", + .name = "lasi", .id_table = lasi_tbl, .probe = lasi_init_chip, }; diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 4cbb6187cc44..123f4933d8f5 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -168,7 +168,7 @@ lasi700_driver_remove(struct parisc_device *dev) } static struct parisc_driver lasi700_driver = { - .name = "Lasi SCSI", + .name = "lasi_scsi", .id_table = lasi700_ids, .probe = lasi700_probe, .remove = __devexit_p(lasi700_driver_remove), diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 189064607709..a12005b08bca 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -497,7 +497,7 @@ static struct parisc_device_id mux_tbl[] = { MODULE_DEVICE_TABLE(parisc, mux_tbl); static struct parisc_driver serial_mux_driver = { - .name = "Serial MUX", + .name = "serial_mux", .id_table = mux_tbl, .probe = mux_probe, }; From 53f01bba49938f115237fe43a261c31ac13ae5c6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:36:40 -0400 Subject: [PATCH 0576/1939] [PARISC] Convert parisc_device to use struct resource for hpa Convert pa_dev->hpa from an unsigned long to a struct resource. Signed-off-by: Matthew Wilcox Fix up users of ->hpa to use ->hpa.start instead. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/perf.c | 12 +++++++----- arch/parisc/kernel/processor.c | 8 ++++---- drivers/input/keyboard/hilkbd.c | 4 ++-- drivers/input/serio/gscps2.c | 2 +- drivers/input/serio/hp_sdc.c | 6 +++--- drivers/net/lasi_82596.c | 7 ++++--- drivers/parisc/asp.c | 4 ++-- drivers/parisc/ccio-dma.c | 4 ++-- drivers/parisc/ccio-rm-dma.c | 2 +- drivers/parisc/dino.c | 6 +++--- drivers/parisc/eisa.c | 2 +- drivers/parisc/hppb.c | 8 ++++---- drivers/parisc/lasi.c | 2 +- drivers/parisc/lba_pci.c | 14 +++++++------- drivers/parisc/sba_iommu.c | 6 +++--- drivers/parisc/wax.c | 2 +- drivers/parport/parport_gsc.c | 5 +++-- drivers/scsi/lasi700.c | 2 +- drivers/scsi/zalon.c | 4 ++-- drivers/serial/8250_gsc.c | 5 +++-- drivers/serial/mux.c | 2 +- include/asm-parisc/parisc-device.h | 2 +- sound/parisc/harmony.c | 6 +++--- 23 files changed, 60 insertions(+), 55 deletions(-) diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index b3ad0a505b87..44670d6e06f4 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -746,7 +746,8 @@ static int perf_write_image(uint64_t *memaddr) uint64_t *bptr; uint32_t dwords; uint32_t *intrigue_rdr; - uint64_t *intrigue_bitmask, tmp64, proc_hpa; + uint64_t *intrigue_bitmask, tmp64; + void __iomem *runway; struct rdr_tbl_ent *tentry; int i; @@ -798,15 +799,16 @@ static int perf_write_image(uint64_t *memaddr) return -1; } - proc_hpa = cpu_device->hpa; + runway = ioremap(cpu_device->hpa.start, 4096); /* Merge intrigue bits into Runway STATUS 0 */ - tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecfffffffffffful; - __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), proc_hpa + RUNWAY_STATUS); + tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful; + __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), + runway + RUNWAY_STATUS); /* Write RUNWAY DEBUG registers */ for (i = 0; i < 8; i++) { - __raw_writeq(*memaddr++, proc_hpa + RUNWAY_DEBUG + i); + __raw_writeq(*memaddr++, runway + RUNWAY_DEBUG); } return 0; diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 13b721cb9f55..4f5bbcf1f5a4 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -92,7 +92,7 @@ static int __init processor_probe(struct parisc_device *dev) * May get overwritten by PAT code. */ cpuid = boot_cpu_data.cpu_count; - txn_addr = dev->hpa; /* for legacy PDC */ + txn_addr = dev->hpa.start; /* for legacy PDC */ #ifdef __LP64__ if (is_pdc_pat()) { @@ -122,7 +122,7 @@ static int __init processor_probe(struct parisc_device *dev) * boot time (ie shutdown a CPU from an OS perspective). */ /* get the cpu number */ - status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa); + status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start); BUG_ON(PDC_OK != status); @@ -130,7 +130,7 @@ static int __init processor_probe(struct parisc_device *dev) printk(KERN_WARNING "IGNORING CPU at 0x%x," " cpu_slot_id > NR_CPUS" " (%ld > %d)\n", - dev->hpa, cpu_info.cpu_num, NR_CPUS); + dev->hpa.start, cpu_info.cpu_num, NR_CPUS); /* Ignore CPU since it will only crash */ boot_cpu_data.cpu_count--; return 1; @@ -149,7 +149,7 @@ static int __init processor_probe(struct parisc_device *dev) p->loops_per_jiffy = loops_per_jiffy; p->dev = dev; /* Save IODC data in case we need it */ - p->hpa = dev->hpa; /* save CPU hpa */ + p->hpa = dev->hpa.start; /* save CPU hpa */ p->cpuid = cpuid; /* save CPU id */ p->txn_addr = txn_addr; /* save CPU IRQ address */ #ifdef CONFIG_SMP diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 8aa81c9ac2f7..e7a1e14f8b0c 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -278,11 +278,11 @@ static int __init hil_init_chip(struct parisc_device *dev) { if (!dev->irq) { - printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa); + printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start); return -ENODEV; } - hil_base = dev->hpa; + hil_base = dev->hpa.start; hil_irq = dev->irq; hil_dev.dev_id = dev; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 4bad2810190c..9790d7169a53 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -331,7 +331,7 @@ static int __init gscps2_probe(struct parisc_device *dev) { struct gscps2port *ps2port; struct serio *serio; - unsigned long hpa = dev->hpa; + unsigned long hpa = dev->hpa.start; int ret; if (!dev->irq) diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 045b9a7a9dbb..a10348bb25e9 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -875,9 +875,9 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d) hp_sdc.dev = d; hp_sdc.irq = d->irq; hp_sdc.nmi = d->aux_irq; - hp_sdc.base_io = d->hpa; - hp_sdc.data_io = d->hpa + 0x800; - hp_sdc.status_io = d->hpa + 0x801; + hp_sdc.base_io = d->hpa.start; + hp_sdc.data_io = d->hpa.start + 0x800; + hp_sdc.status_io = d->hpa.start + 0x801; return hp_sdc_init(); } diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 180e526a2049..a63d8a317d9e 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1528,17 +1528,18 @@ lan_init_chip(struct parisc_device *dev) if (!dev->irq) { printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n", - __FILE__, dev->hpa); + __FILE__, dev->hpa.start); return -ENODEV; } - printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq); + printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start, + dev->irq); netdevice = alloc_etherdev(0); if (!netdevice) return -ENOMEM; - netdevice->base_addr = dev->hpa; + netdevice->base_addr = dev->hpa.start; netdevice->irq = dev->irq; retval = i82596_probe(netdevice, &dev->dev); diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 52f37b424318..558420bc9f88 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -77,12 +77,12 @@ asp_init_chip(struct parisc_device *dev) struct gsc_irq gsc_irq; int ret; - asp.version = gsc_readb(dev->hpa + ASP_VER_OFFSET) & 0xf; + asp.version = gsc_readb(dev->hpa.start + ASP_VER_OFFSET) & 0xf; asp.name = (asp.version == 1) ? "Asp" : "Cutoff"; asp.hpa = ASP_INTERRUPT_ADDR; printk(KERN_INFO "%s version %d at 0x%lx found.\n", - asp.name, asp.version, dev->hpa); + asp.name, asp.version, dev->hpa.start); /* the IRQ ASP should use */ ret = -EBUSY; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 2bb1889c4c4f..80d0927dc8a4 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1546,7 +1546,7 @@ static int ccio_probe(struct parisc_device *dev) ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn"; - printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa); + printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa.start); for (i = 0; i < ioc_count; i++) { ioc_p = &(*ioc_p)->next; @@ -1554,7 +1554,7 @@ static int ccio_probe(struct parisc_device *dev) *ioc_p = ioc; ioc->hw_path = dev->hw_path; - ioc->ioc_hpa = (struct ioa_registers *)dev->hpa; + ioc->ioc_regs = ioremap(dev->hpa.start, 4096); ccio_ioc_init(ioc); ccio_init_resources(ioc); hppa_dma_ops = &ccio_ops; diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c index 57e6385976e2..356b8357bccc 100644 --- a/drivers/parisc/ccio-rm-dma.c +++ b/drivers/parisc/ccio-rm-dma.c @@ -167,7 +167,7 @@ ccio_probe(struct parisc_device *dev) { printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME, dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn", - dev->hpa); + dev->hpa.start); /* ** FIXME - should check U2 registers to verify it's really running diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 8c61705e67a5..37820b0ae5ee 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -902,15 +902,15 @@ void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp); ** If so, initialize the chip appropriately (card-mode vs bridge mode). ** Much of the initialization is common though. */ -static int __init -dino_driver_callback(struct parisc_device *dev) +static int __init dino_probe(struct parisc_device *dev) { struct dino_device *dino_dev; // Dino specific control struct const char *version = "unknown"; char *name; int is_cujo = 0; struct pci_bus *bus; - + unsigned long hpa = dev->hpa.start; + name = "Dino"; if (is_card_dino(&dev->id)) { version = "3.x (card mode)"; diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 0afeedddf535..6362bf99eff6 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -315,7 +315,7 @@ static int __devinit eisa_probe(struct parisc_device *dev) char *name = is_mongoose(dev) ? "Mongoose" : "Wax"; printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", - name, dev->hpa); + name, dev->hpa.start); eisa_dev.hba.dev = dev; eisa_dev.hba.iommu = ccio_get_iommu(dev); diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index a6eae3e7c0cd..5edf93f80757 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -68,14 +68,14 @@ static int hppb_probe(struct parisc_device *dev) memset(card->next, '\0', sizeof(struct hppb_card)); card = card->next; } - printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa); + printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start); - card->hpa = dev->hpa; + card->hpa = dev->hpa.start; card->mmio_region.name = "HP-PB Bus"; card->mmio_region.flags = IORESOURCE_MEM; - card->mmio_region.start = __raw_readl(dev->hpa + IO_IO_LOW); - card->mmio_region.end = __raw_readl(dev->hpa + IO_IO_HIGH) - 1; + card->mmio_region.start = gsc_readl(dev->hpa.start + IO_IO_LOW); + card->mmio_region.end = gsc_readl(dev->hpa.start + IO_IO_HIGH) - 1; status = ccio_request_resource(dev, &card->mmio_region); if(status < 0) { diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index c776c372ae4e..a8c20396ffbe 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -175,7 +175,7 @@ lasi_init_chip(struct parisc_device *dev) return -ENOMEM; lasi->name = "Lasi"; - lasi->hpa = dev->hpa; + lasi->hpa = dev->hpa.start; /* Check the 4-bit (yes, only 4) version register */ lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf; diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 7fdd80b7eb47..5e495dcbc58a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1288,7 +1288,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ** Adjust "window" for this rope. */ rsize /= ROPES_PER_IOC; - r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa); + r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa.start); r->end = r->start + rsize; } else { r->end = r->start = 0; /* Not enabled. */ @@ -1458,7 +1458,7 @@ lba_driver_probe(struct parisc_device *dev) u32 func_class; void *tmp_obj; char *version; - void __iomem *addr = ioremap(dev->hpa, 4096); + void __iomem *addr = ioremap(dev->hpa.start, 4096); /* Read HW Rev First */ func_class = READ_REG32(addr + LBA_FCLASS); @@ -1476,7 +1476,7 @@ lba_driver_probe(struct parisc_device *dev) } printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xf, dev->hpa); + MODULE_NAME, version, func_class & 0xf, dev->hpa.start); if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than " @@ -1503,17 +1503,17 @@ lba_driver_probe(struct parisc_device *dev) * but for the mask for func_class. */ printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xff, dev->hpa); + MODULE_NAME, version, func_class & 0xff, dev->hpa.start); cfg_ops = &mercury_cfg_ops; } else { - printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa); + printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start); return -ENODEV; } /* ** Tell I/O SAPIC driver we have a IRQ handler/region. */ - tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE); + tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE); /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't ** have an IRT entry will get NULL back from iosapic code. @@ -1635,7 +1635,7 @@ void __init lba_init(void) */ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) { - void __iomem * base_addr = ioremap(lba->hpa, 4096); + void __iomem * base_addr = ioremap(lba->hpa.start, 4096); imask <<= 2; /* adjust for hints - 2 more bits */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index a8405f05fb5f..6256ad365d0b 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1600,7 +1600,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset) { - return ioremap(sba_dev->dev->hpa + offset, SBA_FUNC_SIZE); + return ioremap(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE); } static void sba_hw_init(struct sba_device *sba_dev) @@ -1978,7 +1978,7 @@ sba_driver_callback(struct parisc_device *dev) u32 func_class; int i; char *version; - void __iomem *sba_addr = ioremap(dev->hpa, SBA_FUNC_SIZE); + void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE); sba_dump_ranges(sba_addr); @@ -2020,7 +2020,7 @@ sba_driver_callback(struct parisc_device *dev) } printk(KERN_INFO "%s found %s at 0x%lx\n", - MODULE_NAME, version, dev->hpa); + MODULE_NAME, version, dev->hpa.start); sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); if (!sba_dev) { diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c index e547d7d024d8..17dce2adf7fe 100644 --- a/drivers/parisc/wax.c +++ b/drivers/parisc/wax.c @@ -81,7 +81,7 @@ wax_init_chip(struct parisc_device *dev) return -ENOMEM; wax->name = "wax"; - wax->hpa = dev->hpa; + wax->hpa = dev->hpa.start; wax->version = 0; /* gsc_readb(wax->hpa+WAX_VER); */ printk(KERN_INFO "%s at 0x%lx found.\n", wax->name, wax->hpa); diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 02d72acd1c89..fde29a75f888 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -359,11 +359,12 @@ static int __devinit parport_init_chip(struct parisc_device *dev) unsigned long port; if (!dev->irq) { - printk("IRQ not found for parallel device at 0x%lx\n", dev->hpa); + printk(KERN_WARNING "IRQ not found for parallel device at 0x%lx\n", + dev->hpa.start); return -ENODEV; } - port = dev->hpa + PARPORT_GSC_OFFSET; + port = dev->hpa.start + PARPORT_GSC_OFFSET; /* some older machines with ASP-chip don't support * the enhanced parport modes. diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 123f4933d8f5..8028418b3ad6 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -98,7 +98,7 @@ MODULE_DEVICE_TABLE(parisc, lasi700_ids); static int __init lasi700_probe(struct parisc_device *dev) { - unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; + unsigned long base = dev->hpa.start + LASI_SCSI_CORE_OFFSET; struct NCR_700_Host_Parameters *hostdata; struct Scsi_Host *host; diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 5a51051e31f0..b131432c677d 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -88,7 +88,7 @@ zalon_probe(struct parisc_device *dev) struct gsc_irq gsc_irq; u32 zalon_vers; int error = -ENODEV; - void __iomem *zalon = ioremap(dev->hpa, 4096); + void __iomem *zalon = ioremap(dev->hpa.start, 4096); void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; static int unit = 0; struct Scsi_Host *host; @@ -127,7 +127,7 @@ zalon_probe(struct parisc_device *dev) device.chip = zalon720_chip; device.host_id = 7; device.dev = &dev->dev; - device.slot.base = dev->hpa + GSC_SCSI_ZALON_OFFSET; + device.slot.base = dev->hpa.start + GSC_SCSI_ZALON_OFFSET; device.slot.base_v = io_port; device.slot.irq = dev->irq; device.differential = 2; diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 431aa5761a7a..abc5a0cfe243 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -42,12 +42,13 @@ serial_init_chip(struct parisc_device *dev) */ if (parisc_parent(dev)->id.hw_type != HPHW_IOA) { printk(KERN_INFO "Serial: device 0x%lx not configured.\n" - "Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa); + "Enable support for Wax, Lasi, Asp or Dino.\n", + dev->hpa.start); } return -ENODEV; } - address = dev->hpa; + address = dev->hpa.start; if (dev->id.sversion != 0x8d) { address += 0x800; } diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index a12005b08bca..009ce83c8ef5 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -444,7 +444,7 @@ static int __init mux_probe(struct parisc_device *dev) unsigned long bytecnt; struct uart_port *port; - status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32); + status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); if(status != PDC_OK) { printk(KERN_ERR "Serial mux: Unable to read IODC.\n"); return 1; diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h index cbde8b41c84b..1d247e32a608 100644 --- a/include/asm-parisc/parisc-device.h +++ b/include/asm-parisc/parisc-device.h @@ -1,7 +1,7 @@ #include struct parisc_device { - unsigned long hpa; /* Hard Physical Address */ + struct resource hpa; /* Hard Physical Address */ struct parisc_device_id id; struct parisc_driver *driver; /* Driver for this device */ char name[80]; /* The hardware description */ diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index f560dd8cdb90..8b3ea26469ad 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -852,14 +852,14 @@ snd_harmony_create(snd_card_t *card, memset(&h->pbuf, 0, sizeof(h->pbuf)); memset(&h->cbuf, 0, sizeof(h->cbuf)); - h->hpa = padev->hpa; + h->hpa = padev->hpa.start; h->card = card; h->dev = padev; h->irq = padev->irq; - h->iobase = ioremap_nocache(padev->hpa, HARMONY_SIZE); + h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE); if (h->iobase == NULL) { printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n", - padev->hpa); + padev->hpa.start); err = -EBUSY; goto free_and_ret; } From 64908ad95c34f25849412d6d4735ac10f8fb6575 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:37:20 -0400 Subject: [PATCH 0577/1939] [PARISC] Update sba_iommu from parisc tree revert use of %%sr0 in fdc asm. Thanks to Joel Soete for pointing out this oversight. Signed-off-by: Grant Grundler 2.6.14-rc2-pa3 move "sync" outside the main loop that fills IO Pdir. Signed-off-by: Grant Grundler remove explicit use of sr0 in fdc ops. Thanks to Joel Soete for reminding me were I added those... Signed-off-by: Grant Grundler 2.6.14-rc2-pa2 - make SBA more anal about invalidating pdir entries Previous code cleared the valid flag a pdir entry but it did NOT guarantee this change was visible to the PDIR before writing the PCOM register. Ie the SBA could pick up a stale entry if the write happened to hit the SBA before the cacheline was flushed from the cache. Long term, I think I want to make this a compile time flag. Developement tree should enable anal pdir checking by default and Debian can disable it with either a CONFIG option or one-line patch. fdc/sync options can only negatively affect performance though I haven't measure how much yet. If someone can run netperf TCP_RR across gige and compare -pa1 and -pa2, that would be sufficient. Cleaned up the use of "fdc" to make sure it's using "kernel" space id (specify sr0 but maps to sr4-7). It seems a bit fragile to assume "sr1" gets loaded with KERNEL_SPACE which is how the code works today. Tested on 32 and 64-bit SMP kernels on j6k. Signed-off-by: Grant Grundler remove PDC_NARROW from SBA and document history of PDC_NARROW a bit. It will still show up in an older kernel's .config file. Signed-off-by: Grant Grundler if/ifdef cleanups from Joel Soete. Signed-off-by: Grant Grundler 2.6.12-rc4-pa2 fix 32-bit support for Astro platforms o Since my last SBA code change, SBA could allocate more than 1GB of IOVA space on Astro boxes with more than 1GB of RAM when running 32-bit kernel. This is bad since IOMMU can only talk to the first 1GB at most. Kudos to jejb for quickly spotting that bug. o jejb also noted SBA should *always* reject DMA masks > 32-bits since DMA-mapping.txt indicates caller should try again with 32-bits. o off-by-one error when comparing the mask to IOVA space size. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 140 ++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 49 deletions(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 6256ad365d0b..48591badd4ce 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -91,8 +91,8 @@ extern struct proc_dir_entry * proc_mckinley_root; #define DBG_RES(x...) #endif -#if defined(__LP64__) && !defined(CONFIG_PDC_NARROW) -/* "low end" PA8800 machines use ZX1 chipset */ +#if defined(CONFIG_64BIT) +/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ #define ZX1_SUPPORT #endif @@ -231,7 +231,7 @@ struct ioc { spinlock_t res_lock; unsigned int res_bitshift; /* from the LEFT! */ unsigned int res_size; /* size of resource map in bytes */ -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT /* FIXME : DMA HINTs not used */ unsigned long hint_mask_pdir; /* bits used for DMA hints */ unsigned int hint_shift_pdir; @@ -294,7 +294,7 @@ static unsigned long piranha_bad_128k = 0; /* Looks nice and keeps the compiler happy */ #define SBA_DEV(d) ((struct sba_device *) (d)) -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT static int reserve_sba_gart = 1; #endif @@ -314,7 +314,7 @@ static int reserve_sba_gart = 1; #define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr) #define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr) -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define READ_REG(addr) READ_REG64(addr) #define WRITE_REG(value, addr) WRITE_REG64(value, addr) #else @@ -324,7 +324,7 @@ static int reserve_sba_gart = 1; #ifdef DEBUG_SBA_INIT -/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */ +/* NOTE: When CONFIG_64BIT isn't defined, READ_REG64() is two 32-bit reads */ /** * sba_dump_ranges - debugging only - print ranges assigned to this IOA @@ -364,7 +364,7 @@ static void sba_dump_tlb(void __iomem *hpa) #else #define sba_dump_ranges(x) #define sba_dump_tlb(x) -#endif +#endif /* DEBUG_SBA_INIT */ #ifdef ASSERT_PDIR_SANITY @@ -674,7 +674,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) * ***************************************************************/ -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT #define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) #endif @@ -743,9 +743,8 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, * (bit #61, big endian), we have to flush and sync every time * IO-PDIR is changed in Ike/Astro. */ - if (ioc_needs_fdc) { - asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr)); - } + if (ioc_needs_fdc) + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); } @@ -769,42 +768,57 @@ static SBA_INLINE void sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) { u32 iovp = (u32) SBA_IOVP(ioc,iova); - - /* Even though this is a big-endian machine, the entries - ** in the iopdir are little endian. That's why we clear the byte - ** at +7 instead of at +0. - */ - int off = PDIR_INDEX(iovp)*sizeof(u64)+7; + u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)]; #ifdef ASSERT_PDIR_SANITY - /* Assert first pdir entry is set */ - if (0x80 != (((u8 *) ioc->pdir_base)[off])) { + /* Assert first pdir entry is set. + ** + ** Even though this is a big-endian machine, the entries + ** in the iopdir are little endian. That's why we look at + ** the byte at +7 instead of at +0. + */ + if (0x80 != (((u8 *) pdir_ptr)[7])) { sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); } #endif - if (byte_cnt <= IOVP_SIZE) + if (byte_cnt > IOVP_SIZE) { - iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ +#if 0 + unsigned long entries_per_cacheline = ioc_needs_fdc ? + L1_CACHE_ALIGN(((unsigned long) pdir_ptr)) + - (unsigned long) pdir_ptr; + : 262144; +#endif - /* - ** clear I/O PDIR entry "valid" bit - ** Do NOT clear the rest - save it for debugging. - ** We should only clear bits that have previously - ** been enabled. - */ - ((u8 *)(ioc->pdir_base))[off] = 0; - } else { - u32 t = get_order(byte_cnt) + PAGE_SHIFT; + /* set "size" field for PCOM */ + iovp |= get_order(byte_cnt) + PAGE_SHIFT; - iovp |= t; do { /* clear I/O Pdir entry "valid" bit first */ - ((u8 *)(ioc->pdir_base))[off] = 0; - off += sizeof(u64); + ((u8 *) pdir_ptr)[7] = 0; + if (ioc_needs_fdc) { + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); +#if 0 + entries_per_cacheline = L1_CACHE_SHIFT - 3; +#endif + } + pdir_ptr++; byte_cnt -= IOVP_SIZE; - } while (byte_cnt > 0); - } + } while (byte_cnt > IOVP_SIZE); + } else + iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ + + /* + ** clear I/O PDIR entry "valid" bit. + ** We have to R/M/W the cacheline regardless how much of the + ** pdir entry that we clobber. + ** The rest of the entry would be useful for debugging if we + ** could dump core on HPMC. + */ + ((u8 *) pdir_ptr)[7] = 0; + if (ioc_needs_fdc) + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); } @@ -819,18 +833,29 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) static int sba_dma_supported( struct device *dev, u64 mask) { struct ioc *ioc; + if (dev == NULL) { printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); BUG(); return(0); } + /* Documentation/DMA-mapping.txt tells drivers to try 64-bit first, + * then fall back to 32-bit if that fails. + * We are just "encouraging" 32-bit DMA masks here since we can + * never allow IOMMU bypass unless we add special support for ZX1. + */ + if (mask > ~0U) + return 0; + ioc = GET_IOC(dev); - /* check if mask is > than the largest IO Virt Address */ - - return((int) (mask >= (ioc->ibase + - (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) ))); + /* + * check if mask is >= than the current max IO Virt Address + * The max IO Virt address will *always* < 30 bits. + */ + return((int)(mask >= (ioc->ibase - 1 + + (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) ))); } @@ -898,11 +923,17 @@ sba_map_single(struct device *dev, void *addr, size_t size, size -= IOVP_SIZE; pdir_start++; } - /* form complete address */ + + /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + #ifdef ASSERT_PDIR_SANITY sba_check_pdir(ioc,"Check after sba_map_single()"); #endif spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* form complete address */ return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); } @@ -958,12 +989,19 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, d--; } ioc->saved_cnt = 0; + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ } #else /* DELAYED_RESOURCE_CNT == 0 */ sba_free_range(ioc, iova, size); + + /* If fdc's were issued, force fdc's to be visible now */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ + spin_unlock_irqrestore(&ioc->res_lock, flags); /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support. @@ -1106,6 +1144,10 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, */ filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); + /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) { @@ -1234,8 +1276,10 @@ sba_alloc_pdir(unsigned int pdir_size) unsigned long pdir_order = get_order(pdir_size); pdir_base = __get_free_pages(GFP_KERNEL, pdir_order); - if (NULL == (void *) pdir_base) - panic("sba_ioc_init() could not allocate I/O Page Table\n"); + if (NULL == (void *) pdir_base) { + panic("%s() could not allocate I/O Page Table\n", + __FUNCTION__); + } /* If this is not PA8700 (PCX-W2) ** OR newer than ver 2.2 @@ -1353,7 +1397,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) u32 iova_space_mask; u32 iova_space_size; int iov_order, tcnfg; -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT int agp_found = 0; #endif /* @@ -1390,7 +1434,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) DBG_INIT("%s() pdir %p size %x\n", __FUNCTION__, ioc->pdir_base, ioc->pdir_size); -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); @@ -1414,7 +1458,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK); -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* ** Setting the upper bits makes checking for bypass addresses ** a little faster later on. @@ -1447,7 +1491,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) */ WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM); -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT /* ** If an AGP device is present, only use half of the IOV space ** for PCI DMA. Unfortunately we can't know ahead of time @@ -1499,11 +1543,9 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) if (iova_space_size < (1 << (20 - PAGE_SHIFT))) { iova_space_size = 1 << (20 - PAGE_SHIFT); } -#ifdef __LP64__ else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) { iova_space_size = 1 << (30 - PAGE_SHIFT); } -#endif /* ** iova space must be log2() in size. @@ -1529,7 +1571,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) DBG_INIT("%s() pdir %p size %x\n", __FUNCTION__, ioc->pdir_base, pdir_size); -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT /* FIXME : DMA HINTs not used */ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); From 86a61ee9c9f3d8b632d29e86ac6610c43ebbb4f0 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:37:43 -0400 Subject: [PATCH 0578/1939] [PARISC] Update ccio-dma from parisc tree revert use of %%sr0 in fdc asm. Thanks to Joel Soete for pointing out this oversight. Signed-off-by: Grant Grundler 2.6.14-rc2-pa3 fdc/lci should be %r0 instead 0 for index (PA 1.1 compliance) From: Joel Soete Signed-off-by: Grant Grundler Explain why we need insert_resource() instead of request_resource(). Fundementally, this is more convoluted for ccio driver because of o legacy (HP-PB) transperant bridges. o support for MMIO behind card-mode Dino (PCI) o support for above bridges without ccio in the box SBA driver doesn't have to worry about those issues. Signed-off-by: Grant Grundler Use insert_resource instead of request_resource now that the subdevices will already have their resources claimed Signed-off-by: Matthew Wilcox re-enable use of "inline" for perf critical functions. Signed-off-by: Grant Grundler 2.6.12-rc4-pa5 fix sign extension of MMIO range Fixes the problem of claiming a range that is disabled on 64-bit kernel: ccio_init_resource() claimed CCIO bus address space (ffffffff00000000, ffffffffffffffff) also removes use of __FILE__. Tested on both 32 and 64-bit systems by Joel. From: Joel Soete Signed-off-by: Grant Grundler 2.6.12-rc1-pa7 incorrect BUG_ON in ccio ccio-dma.c line 1317 was preventing K-class with 4GB RAM from booting. Any ccio machine with >=2GB of RAM would have (incorrectly) triggered this. Signed-off-by: Grant Grundler Convert to ioremap and __raw_read/write Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/parisc/ccio-dma.c | 136 ++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 80d0927dc8a4..f1c442ab9102 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -100,9 +100,9 @@ #define DBG_RUN_SG(x...) #endif -#define CCIO_INLINE /* inline */ -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr)) -#define READ_U32(addr) gsc_readl((u32 *)(addr)) +#define CCIO_INLINE inline +#define WRITE_U32(value, addr) __raw_writel(value, addr) +#define READ_U32(addr) __raw_readl(addr) #define U2_IOA_RUNWAY 0x580 #define U2_BC_GSC 0x501 @@ -115,28 +115,28 @@ struct ioa_registers { /* Runway Supervisory Set */ - volatile int32_t unused1[12]; - volatile uint32_t io_command; /* Offset 12 */ - volatile uint32_t io_status; /* Offset 13 */ - volatile uint32_t io_control; /* Offset 14 */ - volatile int32_t unused2[1]; + int32_t unused1[12]; + uint32_t io_command; /* Offset 12 */ + uint32_t io_status; /* Offset 13 */ + uint32_t io_control; /* Offset 14 */ + int32_t unused2[1]; /* Runway Auxiliary Register Set */ - volatile uint32_t io_err_resp; /* Offset 0 */ - volatile uint32_t io_err_info; /* Offset 1 */ - volatile uint32_t io_err_req; /* Offset 2 */ - volatile uint32_t io_err_resp_hi; /* Offset 3 */ - volatile uint32_t io_tlb_entry_m; /* Offset 4 */ - volatile uint32_t io_tlb_entry_l; /* Offset 5 */ - volatile uint32_t unused3[1]; - volatile uint32_t io_pdir_base; /* Offset 7 */ - volatile uint32_t io_io_low_hv; /* Offset 8 */ - volatile uint32_t io_io_high_hv; /* Offset 9 */ - volatile uint32_t unused4[1]; - volatile uint32_t io_chain_id_mask; /* Offset 11 */ - volatile uint32_t unused5[2]; - volatile uint32_t io_io_low; /* Offset 14 */ - volatile uint32_t io_io_high; /* Offset 15 */ + uint32_t io_err_resp; /* Offset 0 */ + uint32_t io_err_info; /* Offset 1 */ + uint32_t io_err_req; /* Offset 2 */ + uint32_t io_err_resp_hi; /* Offset 3 */ + uint32_t io_tlb_entry_m; /* Offset 4 */ + uint32_t io_tlb_entry_l; /* Offset 5 */ + uint32_t unused3[1]; + uint32_t io_pdir_base; /* Offset 7 */ + uint32_t io_io_low_hv; /* Offset 8 */ + uint32_t io_io_high_hv; /* Offset 9 */ + uint32_t unused4[1]; + uint32_t io_chain_id_mask; /* Offset 11 */ + uint32_t unused5[2]; + uint32_t io_io_low; /* Offset 14 */ + uint32_t io_io_high; /* Offset 15 */ }; /* @@ -226,7 +226,7 @@ struct ioa_registers { */ struct ioc { - struct ioa_registers *ioc_hpa; /* I/O MMU base address */ + struct ioa_registers __iomem *ioc_regs; /* I/O MMU base address */ u8 *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ u32 pdir_size; /* bytes, function of IOV Space size */ @@ -595,7 +595,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** Grab virtual index [0:11] ** Deposit virt_idx bits into I/O PDIR word */ - asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); @@ -613,7 +613,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** the real mode coherence index generation of U2, the PDIR entry ** must be flushed to memory to retain coherence." */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr)); + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); asm volatile("sync"); } @@ -636,7 +636,7 @@ ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) byte_cnt += chain_size; while(byte_cnt > chain_size) { - WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command); + WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_regs->io_command); iovp += chain_size; byte_cnt -= chain_size; } @@ -684,7 +684,7 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** Hopefully someone figures out how to patch (NOP) the ** FDC/SYNC out at boot time. */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7])); + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); iovp += IOVP_SIZE; byte_cnt -= IOVP_SIZE; @@ -1314,14 +1314,13 @@ ccio_ioc_init(struct ioc *ioc) ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - BUG_ON(ioc->pdir_size >= 4 * 1024 * 1024); /* max pdir size < 4MB */ + BUG_ON(ioc->pdir_size > 8 * 1024 * 1024); /* max pdir size <= 8MB */ /* Verify it's a power of two */ BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); - DBG_INIT("%s() hpa 0x%lx mem %luMB IOV %dMB (%d bits)\n", - __FUNCTION__, - ioc->ioc_hpa, + DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n", + __FUNCTION__, ioc->ioc_regs, (unsigned long) num_physpages >> (20 - PAGE_SHIFT), iova_space_size>>20, iov_order + PAGE_SHIFT); @@ -1329,13 +1328,12 @@ ccio_ioc_init(struct ioc *ioc) ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); if(NULL == ioc->pdir_base) { - panic("%s:%s() could not allocate I/O Page Table\n", __FILE__, - __FUNCTION__); + panic("%s() could not allocate I/O Page Table\n", __FUNCTION__); } memset(ioc->pdir_base, 0, ioc->pdir_size); BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base); - DBG_INIT(" base %p", ioc->pdir_base); + DBG_INIT(" base %p\n", ioc->pdir_base); /* resource map size dictated by pdir_size */ ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; @@ -1344,8 +1342,7 @@ ccio_ioc_init(struct ioc *ioc) ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, get_order(ioc->res_size)); if(NULL == ioc->res_map) { - panic("%s:%s() could not allocate resource map\n", __FILE__, - __FUNCTION__); + panic("%s() could not allocate resource map\n", __FUNCTION__); } memset(ioc->res_map, 0, ioc->res_size); @@ -1366,44 +1363,58 @@ ccio_ioc_init(struct ioc *ioc) ** Initialize IOA hardware */ WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, - &ioc->ioc_hpa->io_chain_id_mask); + &ioc->ioc_regs->io_chain_id_mask); WRITE_U32(virt_to_phys(ioc->pdir_base), - &ioc->ioc_hpa->io_pdir_base); + &ioc->ioc_regs->io_pdir_base); /* ** Go to "Virtual Mode" */ - WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control); + WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_regs->io_control); /* ** Initialize all I/O TLB entries to 0 (Valid bit off). */ - WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m); - WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l); + WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_m); + WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_l); for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), - &ioc->ioc_hpa->io_command); + &ioc->ioc_regs->io_command); } } static void -ccio_init_resource(struct resource *res, char *name, unsigned long ioaddr) +ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) { int result; res->parent = NULL; res->flags = IORESOURCE_MEM; - res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16; - res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1; + /* + * bracing ((signed) ...) are required for 64bit kernel because + * we only want to sign extend the lower 16 bits of the register. + * The upper 16-bits of range registers are hardcoded to 0xffff. + */ + res->start = (unsigned long)((signed) READ_U32(ioaddr) << 16); + res->end = (unsigned long)((signed) (READ_U32(ioaddr + 4) << 16) - 1); res->name = name; + /* + * Check if this MMIO range is disable + */ if (res->end + 1 == res->start) return; - result = request_resource(&iomem_resource, res); + + /* On some platforms (e.g. K-Class), we have already registered + * resources for devices reported by firmware. Some are children + * of ccio. + * "insert" ccio ranges in the mmio hierarchy (/proc/iomem). + */ + result = insert_resource(&iomem_resource, res); if (result < 0) { - printk(KERN_ERR "%s: failed to claim CCIO bus address space (%08lx,%08lx)\n", - __FILE__, res->start, res->end); + printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", + __FUNCTION__, res->start, res->end); } } @@ -1414,9 +1425,8 @@ static void __init ccio_init_resources(struct ioc *ioc) sprintf(name, "GSC Bus [%d/]", ioc->hw_path); - ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low); - ccio_init_resource(res + 1, name, - (unsigned long)&ioc->ioc_hpa->io_io_low_hv); + ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low); + ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv); } static int new_ioc_area(struct resource *res, unsigned long size, @@ -1427,7 +1437,12 @@ static int new_ioc_area(struct resource *res, unsigned long size, res->start = (max - size + 1) &~ (align - 1); res->end = res->start + size; - if (!request_resource(&iomem_resource, res)) + + /* We might be trying to expand the MMIO range to include + * a child device that has already registered it's MMIO space. + * Use "insert" instead of request_resource(). + */ + if (!insert_resource(&iomem_resource, res)) return 0; return new_ioc_area(res, size, min, max - size, align); @@ -1486,15 +1501,15 @@ int ccio_allocate_resource(const struct parisc_device *dev, if (!expand_ioc_area(parent, size, min, max, align)) { __raw_writel(((parent->start)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_low)); + &ioc->ioc_regs->io_io_low); __raw_writel(((parent->end)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_high)); + &ioc->ioc_regs->io_io_high); } else if (!expand_ioc_area(parent + 1, size, min, max, align)) { parent++; __raw_writel(((parent->start)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_low_hv)); + &ioc->ioc_regs->io_io_low_hv); __raw_writel(((parent->end)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_high_hv)); + &ioc->ioc_regs->io_io_high_hv); } else { return -EBUSY; } @@ -1521,7 +1536,12 @@ int ccio_request_resource(const struct parisc_device *dev, return -EBUSY; } - return request_resource(parent, res); + /* "transparent" bus bridges need to register MMIO resources + * firmware assigned them. e.g. children of hppb.c (e.g. K-class) + * registered their resources in the PDC "bus walk" (See + * arch/parisc/kernel/inventory.c). + */ + return insert_resource(parent, res); } /** From 92b919fe46509820c639a08962cbf78bc8d227d9 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:38:23 -0400 Subject: [PATCH 0579/1939] [PARISC] Update dino from parisc tree Fix card-mode Dino crashes on 725 (and probably other Snake) systems. Dino was coming up in fatal mode after a warm reboot. Resetting Dino brings it out of fatal mode, so do that if the status register indicates we're in fatal mode. Since this was never observed on any later systems, I presume firmware does this for us on those. Signed-off-by: Matthew Wilcox Add debug statements in the cfg_read and cfg_write functions Fix debug statements from the IRQ overhaul last winter Rename dino_driver_callback() to dino_probe() Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/parisc/dino.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 37820b0ae5ee..5ab75334c579 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -178,6 +178,8 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; + DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + size); spin_lock_irqsave(&d->dinosaur_pen, flags); /* tell HW which CFG address */ @@ -211,6 +213,8 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; + DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + size); spin_lock_irqsave(&d->dinosaur_pen, flags); /* avoid address stepping feature */ @@ -295,7 +299,7 @@ static void dino_disable_irq(unsigned int irq) struct dino_device *dino_dev = irq_desc[irq].handler_data; int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); @@ -308,7 +312,7 @@ static void dino_enable_irq(unsigned int irq) int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); u32 tmp; - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); /* ** clear pending IRQ bits @@ -490,7 +494,7 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr) if (res->start == F_EXTEND(0xf0000000UL | (i * _8MB))) break; } - DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %lx\n", + DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %p\n", i, res->start, base_addr + DINO_IO_ADDR_EN); __raw_writel(1 << i, base_addr + DINO_IO_ADDR_EN); } @@ -683,6 +687,14 @@ static void __init dino_card_init(struct dino_device *dino_dev) { u32 brdg_feat = 0x00784e05; + unsigned long status; + + status = __raw_readl(dino_dev->hba.base_addr+DINO_IO_STATUS); + if (status & 0x0000ff80) { + __raw_writel(0x00000005, + dino_dev->hba.base_addr+DINO_IO_COMMAND); + udelay(1); + } __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK); __raw_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN); @@ -928,11 +940,11 @@ static int __init dino_probe(struct parisc_device *dev) } } - printk("%s version %s found at 0x%lx\n", name, version, dev->hpa); + printk("%s version %s found at 0x%lx\n", name, version, hpa); - if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) { + if (!request_mem_region(hpa, PAGE_SIZE, name)) { printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n", - dev->hpa); + hpa); return 1; } @@ -940,12 +952,12 @@ static int __init dino_probe(struct parisc_device *dev) if (is_cujo && dev->id.hversion_rev == 1) { #ifdef CONFIG_IOMMU_CCIO printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n"); - if (dev->hpa == (unsigned long)CUJO_RAVEN_ADDR) { + if (hpa == (unsigned long)CUJO_RAVEN_ADDR) { ccio_cujo20_fixup(dev, CUJO_RAVEN_BADPAGE); - } else if (dev->hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { + } else if (hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { ccio_cujo20_fixup(dev, CUJO_FIREHAWK_BADPAGE); } else { - printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa); + printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", hpa); } #endif } else if (!is_cujo && !is_card_dino(&dev->id) && @@ -970,7 +982,7 @@ static int __init dino_probe(struct parisc_device *dev) memset(dino_dev, 0, sizeof(struct dino_device)); dino_dev->hba.dev = dev; - dino_dev->hba.base_addr = ioremap(dev->hpa, 4096); /* faster access */ + dino_dev->hba.base_addr = ioremap(hpa, 4096); dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ spin_lock_init(&dino_dev->dinosaur_pen); dino_dev->hba.iommu = ccio_get_iommu(dev); From b2c1fe81df7471de9f7e2918877ac04ec9cde35f Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:39:43 -0400 Subject: [PATCH 0580/1939] [PARISC] Allow STI_CONSOLE access to some FONTS add || STI_CONSOLE to some of the basic FONTs. May need to get at least one of them to default to "Y" for parisc. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- drivers/video/console/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index eb83a7874c71..7e731691e2a9 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -110,7 +110,7 @@ config STI_CONSOLE config FONTS bool "Select compiled-in fonts" - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE help Say Y here if you would like to use fonts other than the default your frame buffer console usually use. @@ -123,7 +123,7 @@ config FONTS config FONT_8x8 bool "VGA 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -137,7 +137,7 @@ config FONT_8x8 config FONT_8x16 bool "VGA 8x16 font" if FONTS - depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON + depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || STI_CONSOLE || USB_SISUSBVGA_CON default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -147,7 +147,7 @@ config FONT_8x16 config FONT_6x11 bool "Mac console 6x11 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS && MAC help Small console font with Macintosh-style high-half glyphs. Some Mac From 896a375623c3643a3f189353e7d4828c48a7fdf8 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:40:07 -0400 Subject: [PATCH 0581/1939] [PARISC] Make sure use of RFI conforms to PA 2.0 and 1.1 arch docs 2.6.12-rc4-pa3 : first pass at making sure use of RFI conforms to PA 2.0 arch pages F-4 and F-5, PA 1.1 Arch page 3-19 and 3-20. The discussion revolves around all the rules for clearing PSW Q-bit. The hard part is meeting all the rules for "relied upon translation". .align directive is used to guarantee the critical sequence ends more than 8 instructions (32 bytes) from the end of page. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 51 +++++++------- arch/parisc/kernel/head.S | 47 +++---------- arch/parisc/kernel/pacache.S | 121 +++++++++++++++++----------------- arch/parisc/kernel/real2.S | 18 ++--- include/asm-parisc/assembly.h | 25 +++++++ include/asm-parisc/psw.h | 51 +++++++------- include/asm-parisc/tlbflush.h | 9 +-- 7 files changed, 154 insertions(+), 168 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index be0f07f2fa58..65a82c2645a7 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -30,9 +30,9 @@ * - save registers to kernel stack and handle in assembly or C */ +#include #include /* for LDREG/STREG defines */ #include -#include #include #include #include @@ -67,19 +67,22 @@ /* Switch to virtual mapping, trashing only %r1 */ .macro virt_map - rsm PSW_SM_Q,%r0 - tovirt_r1 %r29 - mfsp %sr7, %r1 - or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */ - mtsp %r1, %sr3 + /* pcxt_ssm_bug */ + rsm PSW_SM_I, %r0 /* barrier for "Relied upon Translation */ mtsp %r0, %sr4 mtsp %r0, %sr5 + mfsp %sr7, %r1 + or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */ + mtsp %r1, %sr3 + tovirt_r1 %r29 + load32 KERNEL_PSW, %r1 + + rsm PSW_SM_QUIET,%r0 /* second "heavy weight" ctl op */ mtsp %r0, %sr6 mtsp %r0, %sr7 - load32 KERNEL_PSW, %r1 - mtctl %r1, %cr22 mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ + mtctl %r1, %ipsw load32 4f, %r1 mtctl %r1, %cr18 /* Set IIAOQ tail */ ldo 4(%r1), %r1 @@ -888,9 +891,6 @@ _switch_to_ret: * this way, then we will need to copy %sr3 in to PT_SR[3..7], and * adjust IASQ[0..1]. * - * Note that the following code uses a "relied upon translation". - * See the parisc ACD for details. The ssm is necessary due to a - * PCXT bug. */ .align 4096 @@ -985,24 +985,19 @@ intr_restore: rest_fp %r1 rest_general %r29 - /* Create a "relied upon translation" PA 2.0 Arch. F-5 */ - ssm 0,%r0 - nop - nop - nop - nop - nop - nop - nop + /* inverse of virt_map */ + pcxt_ssm_bug + rsm PSW_SM_QUIET,%r0 /* prepare for rfi */ tophys_r1 %r29 - rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0 /* Restore space id's and special cr's from PT_REGS - * structure pointed to by r29 */ + * structure pointed to by r29 + */ rest_specials %r29 - /* Important: Note that rest_stack restores r29 - * last (we are using it)! It also restores r1 and r30. */ + /* IMPORTANT: rest_stack restores r29 last (we are using it)! + * It also restores r1 and r30. + */ rest_stack rfi @@ -1153,15 +1148,17 @@ intr_save: CMPIB=,n 6,%r26,skip_save_ior - /* save_specials left ipsw value in r8 for us to test */ mfctl %cr20, %r16 /* isr */ + nop /* serialize mfctl on PA 2.0 to avoid 4 cycle penalty */ mfctl %cr21, %r17 /* ior */ + #ifdef __LP64__ /* * If the interrupted code was running with W bit off (32 bit), * clear the b bits (bits 0 & 1) in the ior. + * save_specials left ipsw value in r8 for us to test. */ extrd,u,*<> %r8,PSW_W_BIT,1,%r0 depdi 0,1,2,%r17 @@ -1487,10 +1484,10 @@ nadtlb_emulate: add,l %r1,%r24,%r1 /* doesn't affect c/b bits */ nadtlb_nullify: - mfctl %cr22,%r8 /* Get ipsw */ + mfctl %ipsw,%r8 ldil L%PSW_N,%r9 or %r8,%r9,%r8 /* Set PSW_N */ - mtctl %r8,%cr22 + mtctl %r8,%ipsw rfir nop diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 28405edf8448..2b8738576ec2 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -224,8 +224,6 @@ stext_pdc_ret: mtctl %r0,%cr12 mtctl %r0,%cr13 - /* Prepare to RFI! Man all the cannons! */ - /* Initialize the global data pointer */ loadgp @@ -254,46 +252,16 @@ $is_pa20: $install_iva: mtctl %r10,%cr14 -#ifdef __LP64__ - b aligned_rfi + b aligned_rfi /* Prepare to RFI! Man all the cannons! */ nop - .align 256 + .align 128 aligned_rfi: - ssm 0,0 - nop /* 1 */ - nop /* 2 */ - nop /* 3 */ - nop /* 4 */ - nop /* 5 */ - nop /* 6 */ - nop /* 7 */ - nop /* 8 */ -#endif + pcxt_ssm_bug -#ifdef __LP64__ /* move to psw.h? */ -#define PSW_BITS PSW_Q+PSW_I+PSW_D+PSW_P+PSW_R -#else -#define PSW_BITS PSW_SM_Q -#endif + rsm PSW_SM_QUIET,%r0 /* off troublesome PSW bits */ + /* Don't need NOPs, have 8 compliant insn before rfi */ -$rfi: - /* turn off troublesome PSW bits */ - rsm PSW_BITS,%r0 - - /* kernel PSW: - * - no interruptions except HPMC and TOC (which are handled by PDC) - * - Q bit set (IODC / PDC interruptions) - * - big-endian - * - virtually mapped - */ - load32 KERNEL_PSW,%r10 - mtctl %r10,%ipsw - - /* Set the space pointers for the post-RFI world - ** Clear the two-level IIA Space Queue, effectively setting - ** Kernel space. - */ mtctl %r0,%cr17 /* Clear IIASQ tail */ mtctl %r0,%cr17 /* Clear IIASQ head */ @@ -301,8 +269,11 @@ $rfi: mtctl %r11,%cr18 /* IIAOQ head */ ldo 4(%r11),%r11 mtctl %r11,%cr18 /* IIAOQ tail */ + + load32 KERNEL_PSW,%r10 + mtctl %r10,%ipsw - /* Jump to hyperspace */ + /* Jump through hyperspace to Virt Mode */ rfi nop diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 77e03bc0f935..71ade44c4618 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -40,8 +40,8 @@ .level 2.0 #endif -#include #include +#include #include #include @@ -62,32 +62,23 @@ flush_tlb_all_local: * to happen in real mode with all interruptions disabled. */ - /* - * Once again, we do the rfi dance ... some day we need examine - * all of our uses of this type of code and see what can be - * consolidated. - */ + /* pcxt_ssm_bug - relied upon translation! PA 2.0 Arch. F-4 and F-5 */ + rsm PSW_SM_I, %r19 /* save I-bit state */ + load32 PA(1f), %r1 + nop + nop + nop + nop + nop - rsm PSW_SM_I, %r19 /* relied upon translation! PA 2.0 Arch. F-5 */ - nop - nop - nop - nop - nop - nop - nop - - rsm PSW_SM_Q, %r0 /* Turn off Q bit to load iia queue */ - ldil L%REAL_MODE_PSW, %r1 - ldo R%REAL_MODE_PSW(%r1), %r1 - mtctl %r1, %cr22 + rsm PSW_SM_Q, %r0 /* prep to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - ldil L%PA(1f), %r1 - ldo R%PA(1f)(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ + load32 REAL_MODE_PSW, %r1 + mtctl %r1, %ipsw rfi nop @@ -178,29 +169,36 @@ fdtonemiddle: /* Loop if LOOP = 1 */ ADDIB> -1, %r22, fdtoneloop /* Outer loop count decr */ add %r21, %r20, %r20 /* increment space */ + fdtdone: + /* + * Switch back to virtual mode + */ + /* pcxt_ssm_bug */ + rsm PSW_SM_I, %r0 + load32 2f, %r1 + nop + nop + nop + nop + nop - /* Switch back to virtual mode */ - - rsm PSW_SM_Q, %r0 /* clear Q bit to load iia queue */ - ldil L%KERNEL_PSW, %r1 - ldo R%KERNEL_PSW(%r1), %r1 - or %r1, %r19, %r1 /* Set I bit if set on entry */ - mtctl %r1, %cr22 + rsm PSW_SM_Q, %r0 /* prep to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - ldil L%(2f), %r1 - ldo R%(2f)(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ + load32 KERNEL_PSW, %r1 + or %r1, %r19, %r1 /* I-bit to state on entry */ + mtctl %r1, %ipsw /* restore I-bit (entire PSW) */ rfi nop 2: bv %r0(%r2) nop - .exit + .exit .procend .export flush_instruction_cache_local,code @@ -238,7 +236,7 @@ fioneloop: /* Loop if LOOP = 1 */ fisync: sync - mtsm %r22 + mtsm %r22 /* restore I-bit */ bv %r0(%r2) nop .exit @@ -281,7 +279,7 @@ fdoneloop: /* Loop if LOOP = 1 */ fdsync: syncdma sync - mtsm %r22 + mtsm %r22 /* restore I-bit */ bv %r0(%r2) nop .exit @@ -988,11 +986,12 @@ flush_kernel_icache_range_asm: bv %r0(%r2) nop .exit - .procend - .align 128 - + /* align should cover use of rfi in disable_sr_hashing_asm and + * srdis_done. + */ + .align 256 .export disable_sr_hashing_asm,code disable_sr_hashing_asm: @@ -1000,28 +999,26 @@ disable_sr_hashing_asm: .callinfo NO_CALLS .entry - /* Switch to real mode */ + /* + * Switch to real mode + */ + /* pcxt_ssm_bug */ + rsm PSW_SM_I, %r0 + load32 PA(1f), %r1 + nop + nop + nop + nop + nop - ssm 0, %r0 /* relied upon translation! */ - nop - nop - nop - nop - nop - nop - nop - - rsm (PSW_SM_Q|PSW_SM_I), %r0 /* disable Q&I to load the iia queue */ - ldil L%REAL_MODE_PSW, %r1 - ldo R%REAL_MODE_PSW(%r1), %r1 - mtctl %r1, %cr22 + rsm PSW_SM_Q, %r0 /* prep to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - ldil L%PA(1f), %r1 - ldo R%PA(1f)(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ + load32 REAL_MODE_PSW, %r1 + mtctl %r1, %ipsw rfi nop @@ -1053,27 +1050,31 @@ srdis_pcxl: srdis_pa20: - /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */ + /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+,PCXW2 */ .word 0x144008bc /* mfdiag %dr2, %r28 */ depdi 0, 54,1, %r28 /* clear DIAG_SPHASH_ENAB (bit 54) */ .word 0x145c1840 /* mtdiag %r28, %dr2 */ + srdis_done: - /* Switch back to virtual mode */ + rsm PSW_SM_I, %r0 /* prep to load iia queue */ + load32 2f, %r1 + nop + nop + nop + nop + nop - rsm PSW_SM_Q, %r0 /* clear Q bit to load iia queue */ - ldil L%KERNEL_PSW, %r1 - ldo R%KERNEL_PSW(%r1), %r1 - mtctl %r1, %cr22 + rsm PSW_SM_Q, %r0 /* prep to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - ldil L%(2f), %r1 - ldo R%(2f)(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ + load32 KERNEL_PSW, %r1 + mtctl %r1, %ipsw rfi nop diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 8dd5defb7316..2310fc1b06a9 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -7,8 +7,8 @@ * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) * */ -#include #include +#include .section .bss .export real_stack @@ -147,20 +147,17 @@ restore_control_regs: .text rfi_virt2real: /* switch to real mode... */ - ssm 0,0 /* See "relied upon translation" */ - nop /* PA 2.0 Arch. F-5 */ - nop - nop + rsm PSW_SM_I,%r0 + load32 PA(rfi_v2r_1), %r1 nop nop nop nop nop - rsm (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q & I bits to load iia queue */ + rsm PSW_SM_Q,%r0 /* disable Q & I bits to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - load32 PA(rfi_v2r_1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ @@ -184,10 +181,8 @@ rfi_v2r_1: .text .align 128 rfi_real2virt: - ssm 0,0 /* See "relied upon translation" */ - nop /* PA 2.0 Arch. F-5 */ - nop - nop + rsm PSW_SM_I,%r0 + load32 (rfi_r2v_1), %r1 nop nop nop @@ -197,7 +192,6 @@ rfi_real2virt: rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */ mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ - load32 (rfi_r2v_1), %r1 mtctl %r1, %cr18 /* IIAOQ head */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* IIAOQ tail */ diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index 30b023411fef..b24a99e3ef9c 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -450,5 +450,30 @@ REST_CR (%cr22, PT_PSW (\regs)) .endm + + /* First step to create a "relied upon translation" + * See PA 2.0 Arch. page F-4 and F-5. + * + * The ssm was originally necessary due to a "PCxT bug". + * But someone decided it needed to be added to the architecture + * and this "feature" went into rev3 of PA-RISC 1.1 Arch Manual. + * It's been carried forward into PA 2.0 Arch as well. :^( + * + * "ssm 0,%r0" is a NOP with side effects (prefetch barrier). + * rsm/ssm prevents the ifetch unit from speculatively fetching + * instructions past this line in the code stream. + * PA 2.0 processor will single step all insn in the same QUAD (4 insn). + */ + .macro pcxt_ssm_bug + rsm PSW_SM_I,%r0 + nop /* 1 */ + nop /* 2 */ + nop /* 3 */ + nop /* 4 */ + nop /* 5 */ + nop /* 6 */ + nop /* 7 */ + .endm + #endif /* __ASSEMBLY__ */ #endif diff --git a/include/asm-parisc/psw.h b/include/asm-parisc/psw.h index 51323029f377..4334d6ca2add 100644 --- a/include/asm-parisc/psw.h +++ b/include/asm-parisc/psw.h @@ -1,4 +1,7 @@ #ifndef _PARISC_PSW_H + +#include + #define PSW_I 0x00000001 #define PSW_D 0x00000002 #define PSW_P 0x00000004 @@ -9,6 +12,16 @@ #define PSW_G 0x00000040 /* PA1.x only */ #define PSW_O 0x00000080 /* PA2.0 only */ +/* ssm/rsm instructions number PSW_W and PSW_E differently */ +#define PSW_SM_I PSW_I /* Enable External Interrupts */ +#define PSW_SM_D PSW_D +#define PSW_SM_P PSW_P +#define PSW_SM_Q PSW_Q /* Enable Interrupt State Collection */ +#define PSW_SM_R PSW_R /* Enable Recover Counter Trap */ +#define PSW_SM_W 0x200 /* PA2.0 only : Enable Wide Mode */ + +#define PSW_SM_QUIET PSW_SM_R+PSW_SM_Q+PSW_SM_P+PSW_SM_D+PSW_SM_I + #define PSW_CB 0x0000ff00 #define PSW_M 0x00010000 @@ -30,33 +43,21 @@ #define PSW_Z 0x40000000 /* PA1.x only */ #define PSW_Y 0x80000000 /* PA1.x only */ -#ifdef __LP64__ -#define PSW_HI_CB 0x000000ff /* PA2.0 only */ +#ifdef CONFIG_64BIT +# define PSW_HI_CB 0x000000ff /* PA2.0 only */ #endif -/* PSW bits to be used with ssm/rsm */ -#define PSW_SM_I 0x1 -#define PSW_SM_D 0x2 -#define PSW_SM_P 0x4 -#define PSW_SM_Q 0x8 -#define PSW_SM_R 0x10 -#define PSW_SM_F 0x20 -#define PSW_SM_G 0x40 -#define PSW_SM_O 0x80 -#define PSW_SM_E 0x100 -#define PSW_SM_W 0x200 - -#ifdef __LP64__ -# define USER_PSW (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I) -# define KERNEL_PSW (PSW_W | PSW_C | PSW_Q | PSW_P | PSW_D) -# define REAL_MODE_PSW (PSW_W | PSW_Q) -# define USER_PSW_MASK (PSW_W | PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB) -# define USER_PSW_HI_MASK (PSW_HI_CB) -#else -# define USER_PSW (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I) -# define KERNEL_PSW (PSW_C | PSW_Q | PSW_P | PSW_D) -# define REAL_MODE_PSW (PSW_Q) -# define USER_PSW_MASK (PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB) +#ifdef CONFIG_64BIT +# define USER_PSW_HI_MASK PSW_HI_CB +# define WIDE_PSW PSW_W +#else +# define WIDE_PSW 0 #endif +/* Used when setting up for rfi */ +#define KERNEL_PSW (WIDE_PSW | PSW_C | PSW_Q | PSW_P | PSW_D) +#define REAL_MODE_PSW (WIDE_PSW | PSW_Q) +#define USER_PSW_MASK (WIDE_PSW | PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB) +#define USER_PSW (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I) + #endif diff --git a/include/asm-parisc/tlbflush.h b/include/asm-parisc/tlbflush.h index eb27b78930e8..efbb2d8625b1 100644 --- a/include/asm-parisc/tlbflush.h +++ b/include/asm-parisc/tlbflush.h @@ -64,29 +64,26 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, { unsigned long npages; - npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - if (npages >= 512) /* XXX arbitrary, should be tuned */ + if (npages >= 512) /* 2MB of space: arbitrary, should be tuned */ flush_tlb_all(); else { mtsp(vma->vm_mm->context,1); + purge_tlb_start(); if (split_tlb) { - purge_tlb_start(); while (npages--) { pdtlb(start); pitlb(start); start += PAGE_SIZE; } - purge_tlb_end(); } else { - purge_tlb_start(); while (npages--) { pdtlb(start); start += PAGE_SIZE; } - purge_tlb_end(); } + purge_tlb_end(); } } From 04d472dc83388c59deb6241e9aed841926aa1c8c Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:40:24 -0400 Subject: [PATCH 0582/1939] [PARISC] Move pa_tlb_lock to tlb_flush.h move pa_tlb_lock and it's primary consumers to tlb_flush.h Future step will be to move spinlock_t definition out of system.h. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- include/asm-parisc/system.h | 19 ------------------- include/asm-parisc/tlbflush.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index 26ff844a21c1..a25e9dcd2e79 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -164,25 +164,6 @@ static inline void set_eiem(unsigned long val) #endif #define KERNEL_START (0x10100000 - 0x1000) - -/* This is for the serialisation of PxTLB broadcasts. At least on the - * N class systems, only one PxTLB inter processor broadcast can be - * active at any one time on the Merced bus. This tlb purge - * synchronisation is fairly lightweight and harmless so we activate - * it on all SMP systems not just the N class. */ -#ifdef CONFIG_SMP -extern spinlock_t pa_tlb_lock; - -#define purge_tlb_start(x) spin_lock(&pa_tlb_lock) -#define purge_tlb_end(x) spin_unlock(&pa_tlb_lock) - -#else - -#define purge_tlb_start(x) do { } while(0) -#define purge_tlb_end(x) do { } while (0) - -#endif - #define arch_align_stack(x) (x) #endif diff --git a/include/asm-parisc/tlbflush.h b/include/asm-parisc/tlbflush.h index efbb2d8625b1..84af4ab1fe51 100644 --- a/include/asm-parisc/tlbflush.h +++ b/include/asm-parisc/tlbflush.h @@ -7,6 +7,26 @@ #include #include + +/* This is for the serialisation of PxTLB broadcasts. At least on the + * N class systems, only one PxTLB inter processor broadcast can be + * active at any one time on the Merced bus. This tlb purge + * synchronisation is fairly lightweight and harmless so we activate + * it on all SMP systems not just the N class. */ +#ifdef CONFIG_SMP +extern spinlock_t pa_tlb_lock; + +#define purge_tlb_start(x) spin_lock(&pa_tlb_lock) +#define purge_tlb_end(x) spin_unlock(&pa_tlb_lock) + +#else + +#define purge_tlb_start(x) do { } while(0) +#define purge_tlb_end(x) do { } while (0) + +#endif + + extern void flush_tlb_all(void); /* From 14e256c107304367eff401d20f2ab9fa72e33136 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:41:25 -0400 Subject: [PATCH 0583/1939] [PARISC] Update spinlocks from parisc tree Neaten up the CONFIG_PA20 ifdefs More merge fixes, this time for SMP Signed-off-by: Matthew Wilcox Prettify the CONFIG_DEBUG_SPINLOCK __SPIN_LOCK_UNLOCKED initializers. Clean up some warnings with CONFIG_DEBUG_SPINLOCK enabled. Fix build with spinlock debugging turned on. Patch is cleaner like this, too. Remove mandatory 16-byte alignment requirement on PA2.0 processors by using the ldcw,CO completer. Provides a nice insn savings. Signed-off-by: Kyle McMartin --- include/asm-parisc/spinlock.h | 5 ----- include/asm-parisc/spinlock_types.h | 8 ++++++-- include/asm-parisc/system.h | 31 ++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index 43eaa6e742e0..7c3f406a746a 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -5,11 +5,6 @@ #include #include -/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked - * since it only has load-and-zero. Moreover, at least on some PA processors, - * the semaphore address has to be 16-byte aligned. - */ - static inline int __raw_spin_is_locked(raw_spinlock_t *x) { volatile unsigned int *a = __ldcw_align(x); diff --git a/include/asm-parisc/spinlock_types.h b/include/asm-parisc/spinlock_types.h index 785bba822fbf..d6b479bdb886 100644 --- a/include/asm-parisc/spinlock_types.h +++ b/include/asm-parisc/spinlock_types.h @@ -6,11 +6,15 @@ #endif typedef struct { +#ifdef CONFIG_PA20 + volatile unsigned int slock; +# define __RAW_SPIN_LOCK_UNLOCKED { 1 } +#else volatile unsigned int lock[4]; +# define __RAW_SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } } +#endif } raw_spinlock_t; -#define __RAW_SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } } - typedef struct { raw_spinlock_t lock; volatile int counter; diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index a25e9dcd2e79..f3928d3a80cb 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -138,13 +138,7 @@ static inline void set_eiem(unsigned long val) #define set_wmb(var, value) do { var = value; wmb(); } while (0) -/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ -#define __ldcw(a) ({ \ - unsigned __ret; \ - __asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \ - __ret; \ -}) - +#ifndef CONFIG_PA20 /* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data, and GCC only guarantees 8-byte alignment for stack locals, we can't be assured of 16-byte alignment for atomic lock data even if we @@ -152,12 +146,35 @@ static inline void set_eiem(unsigned long val) we use a struct containing an array of four ints for the atomic lock type and dynamically select the 16-byte aligned int from the array for the semaphore. */ + #define __PA_LDCW_ALIGNMENT 16 #define __ldcw_align(a) ({ \ unsigned long __ret = (unsigned long) &(a)->lock[0]; \ __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \ (volatile unsigned int *) __ret; \ }) +#define LDCW "ldcw" + +#else /*CONFIG_PA20*/ +/* From: "Jim Hull" + I've attached a summary of the change, but basically, for PA 2.0, as + long as the ",CO" (coherent operation) completer is specified, then the + 16-byte alignment requirement for ldcw and ldcd is relaxed, and instead + they only require "natural" alignment (4-byte for ldcw, 8-byte for + ldcd). */ + +#define __PA_LDCW_ALIGNMENT 4 +#define __ldcw_align(a) ((volatile unsigned int *)a) +#define LDCW "ldcw,co" + +#endif /*!CONFIG_PA20*/ + +/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ +#define __ldcw(a) ({ \ + unsigned __ret; \ + __asm__ __volatile__(LDCW " 0(%1),%0" : "=r" (__ret) : "r" (a)); \ + __ret; \ +}) #ifdef CONFIG_SMP # define __lock_aligned __attribute__((__section__(".data.lock_aligned"))) From 951a0150135c46c7791d68e0d1112900d99302d7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:41:49 -0400 Subject: [PATCH 0584/1939] [PARISC] Reorganize sticore probe routine to be a little less convoluted Fix some whitespace issues Reorganise parisc_device probe routine to be a little less convoluted Use ->hpa.start instead of ->hpa Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/video/console/sticore.c | 126 +++++++++++++++----------------- 1 file changed, 60 insertions(+), 66 deletions(-) diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index d940f605acb6..a7bcd17112c0 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -511,12 +511,12 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) struct sti_cooked_font *cooked_font; if (!fbfont_name || !strlen(fbfont_name)) - return NULL; + return NULL; fbfont = find_font(fbfont_name); if (!fbfont) - fbfont = get_default_font(1024,768); + fbfont = get_default_font(1024,768); if (!fbfont) - return NULL; + return NULL; DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n", fbfont->width, fbfont->height, fbfont->name)); @@ -527,7 +527,7 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) nf = kmalloc(size, GFP_KERNEL); if (!nf) - return NULL; + return NULL; memset(nf, 0, size); nf->first_char = 0; @@ -546,8 +546,8 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); if (!cooked_font) { - kfree(nf); - return NULL; + kfree(nf); + return NULL; } cooked_font->raw = nf; @@ -595,7 +595,7 @@ sti_select_font(struct sti_cooked_rom *rom, static void __init sti_dump_rom(struct sti_rom *rom) { - printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", + printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", rom->graphics_id[0], rom->graphics_id[1], rom->revno[0] >> 4, @@ -651,15 +651,16 @@ sti_search_font(struct sti_cooked_rom *rom, int height, int width) struct sti_cooked_font *font; int i = 0; - for(font = rom->font_start; font; font = font->next_font, i++) { - if((font->raw->width == width) && (font->raw->height == height)) + for (font = rom->font_start; font; font = font->next_font, i++) { + if ((font->raw->width == width) && + (font->raw->height == height)) return i; } return 0; } -#define BMODE_RELOCATE(offset) offset = (offset) / 4; -#define BMODE_LAST_ADDR_OFFS 0x50 +#define BMODE_RELOCATE(offset) offset = (offset) / 4; +#define BMODE_LAST_ADDR_OFFS 0x50 static void * __init sti_bmode_font_raw(struct sti_cooked_font *f) @@ -700,35 +701,35 @@ sti_get_bmode_rom (unsigned long address) { struct sti_rom *raw; u32 size; - struct sti_rom_font *raw_font, *font_start; - + struct sti_rom_font *raw_font, *font_start; + sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); - - size = (size+3) / 4; + + size = (size+3) / 4; raw = kmalloc(size, GFP_KERNEL); if (raw) { - sti_bmode_rom_copy(address, size, raw); - memmove (&raw->res004, &raw->type[0], 0x3c); - raw->type[3] = raw->res004; + sti_bmode_rom_copy(address, size, raw); + memmove (&raw->res004, &raw->type[0], 0x3c); + raw->type[3] = raw->res004; - BMODE_RELOCATE (raw->region_list); - BMODE_RELOCATE (raw->font_start); + BMODE_RELOCATE (raw->region_list); + BMODE_RELOCATE (raw->font_start); - BMODE_RELOCATE (raw->init_graph); - BMODE_RELOCATE (raw->state_mgmt); - BMODE_RELOCATE (raw->font_unpmv); - BMODE_RELOCATE (raw->block_move); - BMODE_RELOCATE (raw->inq_conf); + BMODE_RELOCATE (raw->init_graph); + BMODE_RELOCATE (raw->state_mgmt); + BMODE_RELOCATE (raw->font_unpmv); + BMODE_RELOCATE (raw->block_move); + BMODE_RELOCATE (raw->inq_conf); - raw_font = ((void *)raw) + raw->font_start; - font_start = raw_font; + raw_font = ((void *)raw) + raw->font_start; + font_start = raw_font; - while (raw_font->next_font) { - BMODE_RELOCATE (raw_font->next_font); - raw_font = ((void *)font_start) + raw_font->next_font; - } + while (raw_font->next_font) { + BMODE_RELOCATE (raw_font->next_font); + raw_font = ((void *)font_start) + raw_font->next_font; + } } - return raw; + return raw; } struct sti_rom * __init @@ -736,15 +737,15 @@ sti_get_wmode_rom (unsigned long address) { struct sti_rom *raw; unsigned long size; - + /* read the ROM size directly from the struct in ROM */ size = gsc_readl(address + offsetof(struct sti_rom,last_addr)); raw = kmalloc(size, GFP_KERNEL); - if(raw) - sti_rom_copy(address, size, raw); + if (raw) + sti_rom_copy(address, size, raw); - return raw; + return raw; } int __init @@ -757,14 +758,14 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) if (!cooked) goto out_err; - if (wordmode) - raw = sti_get_wmode_rom (address); - else - raw = sti_get_bmode_rom (address); + if (wordmode) + raw = sti_get_wmode_rom (address); + else + raw = sti_get_bmode_rom (address); + + if (!raw) + goto out_err; - if (!raw) - goto out_err; - if (!sti_cook_fonts(cooked, raw)) { printk(KERN_ERR "No font found for STI at %08lx\n", address); goto out_err; @@ -787,7 +788,7 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) sti->font_width = sti->font->raw->width; sti->font_height = sti->font->raw->height; if (!wordmode) - sti->font->raw = sti_bmode_font_raw(sti->font); + sti->font->raw = sti_bmode_font_raw(sti->font); sti->sti_mem_request = raw->sti_mem_req; sti->graphics_id[0] = raw->graphics_id[0]; @@ -811,16 +812,16 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd u32 sig; if (num_sti_roms >= MAX_STI_ROMS) { - printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); - return NULL; + printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); + return NULL; } sti = kmalloc(sizeof(*sti), GFP_KERNEL); if (!sti) { - printk(KERN_ERR "Not enough memory !\n"); - return NULL; + printk(KERN_ERR "Not enough memory !\n"); + return NULL; } - + memset(sti, 0, sizeof(*sti)); spin_lock_init(&sti->lock); @@ -932,28 +933,21 @@ static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *p */ static int __init sticore_pa_init(struct parisc_device *dev) { - unsigned long rom = 0; char pa_path[21]; struct sti_struct *sti = NULL; - - if(dev->num_addrs) { - rom = dev->addr[0]; - } - if (!rom) { - rom = dev->hpa; - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - rom = PAGE0->proc_sti; - } - if (!sti) { - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - } + int hpa = dev->hpa.start; + + if (dev->num_addrs && dev->addr[0]) + sti = sti_try_rom_generic(dev->addr[0], hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(hpa, hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(PAGE0->proc_sti, hpa, NULL); if (!sti) return 1; - + print_pa_hwpath(dev, pa_path); - sticore_check_for_default_sti (sti, pa_path); + sticore_check_for_default_sti(sti, pa_path); return 0; } From 5cd55b0edee7f979530c86b23728d461ddeb9f3f Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:42:18 -0400 Subject: [PATCH 0585/1939] [PARISC] Take into account nullified insn and lock functions for profiling export profile_pc() symbol - oprofile needs it when built as a module. Signed-off-by: Grant Grundler Take into account nullified insn and lock functions for profiling This is needed at the end of functions; it is typical that the return branch nullifies the next insn, which is in the next function. This causes profiling data to show up against the "wrong" function. We also count lock times against the locker. This is consistent with other architectures. Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 18 ++++++++++++++++++ include/asm-parisc/ptrace.h | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 7ff67f8e9f8c..163cdf39be20 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -104,6 +104,24 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } + +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (regs->gr[0] & PSW_N) + pc -= 4; + +#ifdef CONFIG_SMP + if (in_lock_functions(pc)) + pc = regs->gr[2]; +#endif + + return pc; +} +EXPORT_SYMBOL(profile_pc); + + /*** converted from ia64 ***/ /* * Return the number of micro-seconds that elapsed since the last diff --git a/include/asm-parisc/ptrace.h b/include/asm-parisc/ptrace.h index 3f428aa371a4..93f990e418f1 100644 --- a/include/asm-parisc/ptrace.h +++ b/include/asm-parisc/ptrace.h @@ -49,7 +49,7 @@ struct pt_regs { #define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0) #define user_space(regs) (((regs)->iasq[1] != 0) ? 1 : 0) #define instruction_pointer(regs) ((regs)->iaoq[0] & ~3) -#define profile_pc(regs) instruction_pointer(regs) +unsigned long profile_pc(struct pt_regs *); extern void show_regs(struct pt_regs *); #endif From 3a165680168758733b7a9f7fb835954fbe6b91a8 Mon Sep 17 00:00:00 2001 From: Stuart Brady Date: Fri, 21 Oct 2005 22:42:38 -0400 Subject: [PATCH 0586/1939] [PARISC] Update harmony from parisc tree o Added a control for the input source (which can be either "line" or "mic") o Mute the speaker/line-out/headphone outputs by default. o Increased the buffer size from 10 pages to 16. Signed-off-by: Stuart Brady ALSA Harmony was resetting the capture position when preparing the capture substream, which it shouldn't do. This should fix the problem. Signed-off-by: Stuart Brady ALSA Harmony should no longer play junk (left in the buffers from a previous stream) at the start of a new stream. Implement the monitor mixer channel for ALSA Harmony. Also prevent snd_harmony_volume_get from returning negative values. Signed-off-by: Stuart Brady Use the graveyard/silence buffers in ALSA Harmony. Signed-off-by: Stuart Brady Signed-off-by: Kyle McMartin --- sound/parisc/harmony.c | 118 ++++++++++++++++++++++++++++++++++------- sound/parisc/harmony.h | 17 +++--- 2 files changed, 109 insertions(+), 26 deletions(-) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 8b3ea26469ad..d833349ed518 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -197,7 +197,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) spin_unlock(&h->lock); if (dstatus & HARMONY_DSTATUS_PN) { - if (h->psubs) { + if (h->psubs && h->st.playing) { spin_lock(&h->lock); h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ @@ -216,7 +216,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) } if (dstatus & HARMONY_DSTATUS_RN) { - if (h->csubs) { + if (h->csubs && h->st.capturing) { spin_lock(&h->lock); h->cbuf.buf += h->cbuf.count; h->cbuf.buf %= h->cbuf.size; @@ -316,6 +316,7 @@ snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd) case SNDRV_PCM_TRIGGER_STOP: h->st.playing = 0; harmony_mute(h); + harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); harmony_disable_interrupts(h); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -351,8 +352,9 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: h->st.capturing = 0; - harmony_mute(h); - harmony_disable_interrupts(h); + harmony_mute(h); + harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); + harmony_disable_interrupts(h); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -408,7 +410,8 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss) h->pbuf.size = snd_pcm_lib_buffer_bytes(ss); h->pbuf.count = snd_pcm_lib_period_bytes(ss); - h->pbuf.buf = 0; + if (h->pbuf.buf >= h->pbuf.size) + h->pbuf.buf = 0; h->st.playing = 0; h->st.rate = snd_harmony_rate_bits(rt->rate); @@ -437,7 +440,8 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss) h->cbuf.size = snd_pcm_lib_buffer_bytes(ss); h->cbuf.count = snd_pcm_lib_period_bytes(ss); - h->cbuf.buf = 0; + if (h->cbuf.buf >= h->cbuf.size) + h->cbuf.buf = 0; h->st.capturing = 0; h->st.rate = snd_harmony_rate_bits(rt->rate); @@ -712,13 +716,14 @@ snd_harmony_volume_get(snd_kcontrol_t *kc, left = (h->st.gain >> shift_left) & mask; right = (h->st.gain >> shift_right) & mask; - if (invert) { left = mask - left; right = mask - right; } + ucontrol->value.integer.value[0] = left; - ucontrol->value.integer.value[1] = right; + if (shift_left != shift_right) + ucontrol->value.integer.value[1] = right; spin_unlock_irqrestore(&h->mixer_lock, flags); @@ -738,22 +743,82 @@ snd_harmony_volume_put(snd_kcontrol_t *kc, int old_gain = h->st.gain; unsigned long flags; - left = ucontrol->value.integer.value[0] & mask; - right = ucontrol->value.integer.value[1] & mask; - if (invert) { - left = mask - left; - right = mask - right; - } - spin_lock_irqsave(&h->mixer_lock, flags); - h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) ); - h->st.gain |= ( (left << shift_left) | (right << shift_right) ); + left = ucontrol->value.integer.value[0] & mask; + if (invert) + left = mask - left; + h->st.gain &= ~( (mask << shift_left ) ); + h->st.gain |= (left << shift_left); + + if (shift_left != shift_right) { + right = ucontrol->value.integer.value[1] & mask; + if (invert) + right = mask - right; + h->st.gain &= ~( (mask << shift_right) ); + h->st.gain |= (right << shift_right); + } + snd_harmony_set_new_gain(h); spin_unlock_irqrestore(&h->mixer_lock, flags); - return (old_gain - h->st.gain); + return h->st.gain != old_gain; +} + +static int +snd_harmony_captureroute_info(snd_kcontrol_t *kc, + snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "Line", "Mic" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int +snd_harmony_captureroute_get(snd_kcontrol_t *kc, + snd_ctl_elem_value_t *ucontrol) +{ + harmony_t *h = snd_kcontrol_chip(kc); + int value; + unsigned long flags; + + spin_lock_irqsave(&h->mixer_lock, flags); + + value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1; + ucontrol->value.enumerated.item[0] = value; + + spin_unlock_irqrestore(&h->mixer_lock, flags); + + return 0; +} + +static int +snd_harmony_captureroute_put(snd_kcontrol_t *kc, + snd_ctl_elem_value_t *ucontrol) +{ + harmony_t *h = snd_kcontrol_chip(kc); + int value; + int old_gain = h->st.gain; + unsigned long flags; + + spin_lock_irqsave(&h->mixer_lock, flags); + + value = ucontrol->value.enumerated.item[0] & 1; + h->st.gain &= ~HARMONY_GAIN_IS_MASK; + h->st.gain |= value << HARMONY_GAIN_IS_SHIFT; + + snd_harmony_set_new_gain(h); + + spin_unlock_irqrestore(&h->mixer_lock, flags); + + return h->st.gain != old_gain; } #define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \ @@ -767,10 +832,25 @@ snd_harmony_volume_put(snd_kcontrol_t *kc, ((mask) << 16) | ((invert) << 24)) } static snd_kcontrol_new_t snd_harmony_controls[] = { - HARMONY_VOLUME("Playback Volume", HARMONY_GAIN_LO_SHIFT, + HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT, HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1), HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT, HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0), + HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT, + HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Route", + .info = snd_harmony_captureroute_info, + .get = snd_harmony_captureroute_get, + .put = snd_harmony_captureroute_put + }, + HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT, + HARMONY_GAIN_SE_SHIFT, 1, 0), + HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT, + HARMONY_GAIN_LE_SHIFT, 1, 0), + HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT, + HARMONY_GAIN_HE_SHIFT, 1, 0), }; static void __init diff --git a/sound/parisc/harmony.h b/sound/parisc/harmony.h index ef77f9a577d5..526c52389de2 100644 --- a/sound/parisc/harmony.h +++ b/sound/parisc/harmony.h @@ -61,7 +61,7 @@ typedef struct snd_card_harmony { #define HARMONY_SIZE 64 #define BUF_SIZE PAGE_SIZE -#define MAX_BUFS 10 +#define MAX_BUFS 16 #define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE) #define PLAYBACK_BUFS MAX_BUFS @@ -101,28 +101,31 @@ typedef struct snd_card_harmony { #define HARMONY_SS_MONO 0x00000000 #define HARMONY_SS_STEREO 0x00000001 -#define HARMONY_GAIN_SILENCE 0x00F00FFF -#define HARMONY_GAIN_DEFAULT 0x0FF00000 +#define HARMONY_GAIN_SILENCE 0x01F00FFF +#define HARMONY_GAIN_DEFAULT 0x01F00FFF -#define HARMONY_GAIN_HE_SHIFT 27 +#define HARMONY_GAIN_HE_SHIFT 27 /* headphones enabled */ #define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT) -#define HARMONY_GAIN_LE_SHIFT 26 +#define HARMONY_GAIN_LE_SHIFT 26 /* line-out enabled */ #define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT) -#define HARMONY_GAIN_SE_SHIFT 25 +#define HARMONY_GAIN_SE_SHIFT 25 /* internal-speaker enabled */ #define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT) -#define HARMONY_GAIN_IS_SHIFT 24 +#define HARMONY_GAIN_IS_SHIFT 24 /* input select - 0 for line, 1 for mic */ #define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT) +/* monitor attenuation */ #define HARMONY_GAIN_MA 0x0f #define HARMONY_GAIN_MA_SHIFT 20 #define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT) +/* input gain */ #define HARMONY_GAIN_IN 0x0f #define HARMONY_GAIN_LI_SHIFT 16 #define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT) #define HARMONY_GAIN_RI_SHIFT 12 #define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT) +/* output gain (master volume) */ #define HARMONY_GAIN_OUT 0x3f #define HARMONY_GAIN_LO_SHIFT 6 #define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT) From 99ac79479928bae42d694b7cb53644be5d3b6dd2 Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:42:57 -0400 Subject: [PATCH 0587/1939] [PARISC] Replace some calls to bl with b,l or bv to use longer offsets convert some bl calls to b,l or bv to use longer offsets Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 65a82c2645a7..ec04e0ad77fa 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -821,7 +821,12 @@ ret_from_kernel_thread: ldo -16(%r30),%r29 /* Reference param save area */ loadgp /* Thread could have been in a module */ #endif +#ifndef CONFIG_64BIT b sys_exit +#else + load32 sys_exit, %r1 + bv %r0(%r1) +#endif ldi 0, %r26 .import sys_execve, code @@ -1012,7 +1017,7 @@ intr_restore: .import do_softirq,code intr_do_softirq: - bl do_softirq,%r2 + BL do_softirq,%r2 #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #else @@ -1036,7 +1041,12 @@ intr_do_resched: #endif ldil L%intr_check_sig, %r2 +#ifndef CONFIG_64BIT b schedule +#else + load32 schedule, %r20 + bv %r0(%r20) +#endif ldo R%intr_check_sig(%r2), %r2 @@ -1897,7 +1907,7 @@ sys_vfork_wrapper: #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif - bl \execve,%r2 + BL \execve,%r2 copy %r1,%arg0 ldo -FRAME_SIZE(%r30),%r30 @@ -2226,7 +2236,7 @@ pt_regs_ok: .import do_softirq,code syscall_do_softirq: - bl do_softirq,%r2 + BL do_softirq,%r2 nop /* NOTE: We enable I-bit incase we schedule later, * and we might be going back to userspace if we were From f053725b8985d10c2cc4b837a80a381104c936a4 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Oct 2005 22:43:15 -0400 Subject: [PATCH 0588/1939] [PARISC] Add ability for prctl to change unaligned trap behaviour Add support for changing unaligned trap behaviour on a per-thread basis. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/unaligned.c | 16 ++++++++++------ include/asm-parisc/processor.h | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 62eea35bcd69..eaae8a021f9f 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -513,15 +513,18 @@ void handle_unaligned(struct pt_regs *regs) register int flop=0; /* true if this is a flop */ /* log a message with pacing */ - if (user_mode(regs)) - { - if (unaligned_count > 5 && jiffies - last_time > 5*HZ) - { + if (user_mode(regs)) { + if (current->thread.flags & PARISC_UAC_SIGBUS) { + goto force_sigbus; + } + + if (unaligned_count > 5 && jiffies - last_time > 5*HZ) { unaligned_count = 0; last_time = jiffies; } - if (++unaligned_count < 5) - { + + if (!(current->thread.flags & PARISC_UAC_NOPRINT) + && ++unaligned_count < 5) { char buf[256]; sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n", current->comm, current->pid, regs->ior, regs->iaoq[0]); @@ -530,6 +533,7 @@ void handle_unaligned(struct pt_regs *regs) show_regs(regs); #endif } + if (!unaligned_enabled) goto force_sigbus; } diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index a9dfadd05658..aae40e8c3aa8 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -122,8 +122,27 @@ struct thread_struct { }; /* Thread struct flags. */ +#define PARISC_UAC_NOPRINT (1UL << 0) /* see prctl and unaligned.c */ +#define PARISC_UAC_SIGBUS (1UL << 1) #define PARISC_KERNEL_DEATH (1UL << 31) /* see die_if_kernel()... */ +#define PARISC_UAC_SHIFT 0 +#define PARISC_UAC_MASK (PARISC_UAC_NOPRINT|PARISC_UAC_SIGBUS) + +#define SET_UNALIGN_CTL(task,value) \ + ({ \ + (task)->thread.flags = (((task)->thread.flags & ~PARISC_UAC_MASK) \ + | (((value) << PARISC_UAC_SHIFT) & \ + PARISC_UAC_MASK)); \ + 0; \ + }) + +#define GET_UNALIGN_CTL(task,addr) \ + ({ \ + put_user(((task)->thread.flags & PARISC_UAC_MASK) \ + >> PARISC_UAC_SHIFT, (int __user *) (addr)); \ + }) + #define INIT_THREAD { \ regs: { gr: { 0, }, \ fr: { 0, }, \ From 2464212f68136527f6364d63c23a529e1fd7d168 Mon Sep 17 00:00:00 2001 From: Stuart Brady Date: Fri, 21 Oct 2005 22:44:14 -0400 Subject: [PATCH 0589/1939] [PARISC] Fix parisc_setup_cache_timing to choose a better flush threshold update comment about CAFL_STRIDE Signed-off-by: Kyle McMartin Fixed a bug in parisc_setup_cache_timing() which caused it to calculate a poor value for parisc_cache_flush_threshold. Thanks to Joel Soete for spotting the bug. Thanks to James Bottomley for pointing out the clean way to fix this. Signed-off-by: Stuart Brady Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index f46a07a79218..e15f09eaed12 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -27,6 +27,7 @@ #include #include #include +#include int split_tlb; int dcache_stride; @@ -207,6 +208,9 @@ parisc_cache_init(void) /* "New and Improved" version from Jim Hull * (1 << (cc_block-1)) * (cc_line << (4 + cnf.cc_shift)) + * The following CAFL_STRIDE is an optimized version, see + * http://lists.parisc-linux.org/pipermail/parisc-linux/2004-June/023625.html + * http://lists.parisc-linux.org/pipermail/parisc-linux/2004-June/023671.html */ #define CAFL_STRIDE(cnf) (cnf.cc_line << (3 + cnf.cc_block + cnf.cc_shift)) dcache_stride = CAFL_STRIDE(cache_info.dc_conf); @@ -339,17 +343,15 @@ int parisc_cache_flush_threshold = FLUSH_THRESHOLD; void parisc_setup_cache_timing(void) { unsigned long rangetime, alltime; - extern char _text; /* start of kernel code, defined by linker */ - extern char _end; /* end of BSS, defined by linker */ unsigned long size; alltime = mfctl(16); flush_data_cache(); alltime = mfctl(16) - alltime; - size = (unsigned long)(&_end - _text); + size = (unsigned long)(_end - _text); rangetime = mfctl(16); - flush_kernel_dcache_range((unsigned long)&_text, size); + flush_kernel_dcache_range((unsigned long)_text, size); rangetime = mfctl(16) - rangetime; printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n", From a366064c3ff46c985a3c7243468be197d29874dc Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:45:22 -0400 Subject: [PATCH 0590/1939] [PARISC] Update bitops from parisc tree Optimize ext2_find_next_zero_bit. Gives about 25% perf improvement with a rsync test with ext3. Signed-off-by: Randolph Chung fix ext3 performance - ext2_find_next_zero() was culprit. Kudos to jejb for pointing out the the possibility that ext2_test_bit and ext2_find_next_zero() may in fact not be enumerating bits in the bitmap because of endianess. Took sparc64 implementation and adapted it to our tree. I suspect the real problem is ffz() wants an unsigned long and was getting garbage in the top half of the unsigned int. Not confirmed but that's what I suspect. Signed-off-by: Grant Grundler Fix find_next_bit for 32-bit Make masking consistent for bitops From: Joel Soete Signed-off-by: Randolph Chung Add back incorrectly removed ext2_find_first_zero_bit definition Signed-off-by: James Bottomley Fixup bitops.h to use volatile for *_bit() ops Based on this email thread: http://marc.theaimsgroup.com/?t=108826637900003 In a nutshell: *_bit() want use of volatile. __*_bit() are "relaxed" and don't use spinlock or volatile. other minor changes: o replaces hweight64() macro with alias to generic_hweight64() (Joel Soete) o cleanup ext2* macros so (a) it's obvious what the XOR magic is about and (b) one version that works for both 32/64-bit. o replace 2 uses of CONFIG_64BIT with __LP64__. bitops.h used both. I think header files that might go to user space should use something userspace will know about (__LP64__). Signed-off-by: Grant Grundler Move SHIFT_PER_LONG to standard location for BITS_PER_LONG (asm/types.h) and ditch the second definition of BITS_PER_LONG in bitops.h Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- include/asm-parisc/bitops.h | 292 ++++++++++++++++-------------------- include/asm-parisc/types.h | 2 + 2 files changed, 135 insertions(+), 159 deletions(-) diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h index af7db694b22d..55b98c67fd82 100644 --- a/include/asm-parisc/bitops.h +++ b/include/asm-parisc/bitops.h @@ -2,7 +2,7 @@ #define _PARISC_BITOPS_H #include -#include +#include /* for BITS_PER_LONG/SHIFT_PER_LONG */ #include #include @@ -12,193 +12,157 @@ * to include/asm-i386/bitops.h or kerneldoc */ -#ifdef __LP64__ -# define SHIFT_PER_LONG 6 -#ifndef BITS_PER_LONG -# define BITS_PER_LONG 64 -#endif -#else -# define SHIFT_PER_LONG 5 -#ifndef BITS_PER_LONG -# define BITS_PER_LONG 32 -#endif -#endif - -#define CHOP_SHIFTCOUNT(x) ((x) & (BITS_PER_LONG - 1)) +#define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1)) #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() -static __inline__ void set_bit(int nr, volatile unsigned long * address) +/* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion + * on use of volatile and __*_bit() (set/clear/change): + * *_bit() want use of volatile. + * __*_bit() are "relaxed" and don't use spinlock or volatile. + */ + +static __inline__ void set_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); *addr |= mask; _atomic_spin_unlock_irqrestore(addr, flags); } -static __inline__ void __set_bit(int nr, volatile unsigned long * address) +static __inline__ void __set_bit(unsigned long nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG); - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - *addr |= mask; + *m |= 1UL << CHOP_SHIFTCOUNT(nr); } -static __inline__ void clear_bit(int nr, volatile unsigned long * address) +static __inline__ void clear_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long mask = ~(1UL << CHOP_SHIFTCOUNT(nr)); unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); - *addr &= ~mask; + *addr &= mask; _atomic_spin_unlock_irqrestore(addr, flags); } -static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long * address) +static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG); - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - *addr &= ~mask; + *m &= ~(1UL << CHOP_SHIFTCOUNT(nr)); } -static __inline__ void change_bit(int nr, volatile unsigned long * address) +static __inline__ void change_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); *addr ^= mask; _atomic_spin_unlock_irqrestore(addr, flags); } -static __inline__ void __change_bit(int nr, volatile unsigned long * address) +static __inline__ void __change_bit(unsigned long nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; + unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG); - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - *addr ^= mask; + *m ^= 1UL << CHOP_SHIFTCOUNT(nr); } -static __inline__ int test_and_set_bit(int nr, volatile unsigned long * address) +static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long oldbit; unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); - oldbit = (*addr & mask) ? 1 : 0; - *addr |= mask; + oldbit = *addr; + *addr = oldbit | mask; _atomic_spin_unlock_irqrestore(addr, flags); - return oldbit; + return (oldbit & mask) ? 1 : 0; } static __inline__ int __test_and_set_bit(int nr, volatile unsigned long * address) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long oldbit; + unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG); - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - oldbit = (*addr & mask) ? 1 : 0; - *addr |= mask; + oldbit = *addr; + *addr = oldbit | mask; - return oldbit; + return (oldbit & mask) ? 1 : 0; } -static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * address) +static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long oldbit; unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); - oldbit = (*addr & mask) ? 1 : 0; - *addr &= ~mask; + oldbit = *addr; + *addr = oldbit & ~mask; _atomic_spin_unlock_irqrestore(addr, flags); - return oldbit; + return (oldbit & mask) ? 1 : 0; } static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long * address) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG); + unsigned long oldbit; - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - oldbit = (*addr & mask) ? 1 : 0; - *addr &= ~mask; + oldbit = *addr; + *addr = oldbit & ~mask; - return oldbit; + return (oldbit & mask) ? 1 : 0; } -static __inline__ int test_and_change_bit(int nr, volatile unsigned long * address) +static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long oldbit; unsigned long flags; addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); _atomic_spin_lock_irqsave(addr, flags); - oldbit = (*addr & mask) ? 1 : 0; - *addr ^= mask; + oldbit = *addr; + *addr = oldbit ^ mask; _atomic_spin_unlock_irqrestore(addr, flags); - return oldbit; + return (oldbit & mask) ? 1 : 0; } static __inline__ int __test_and_change_bit(int nr, volatile unsigned long * address) { - unsigned long mask; - unsigned long *addr = (unsigned long *) address; - int oldbit; + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG); + unsigned long oldbit; - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); - oldbit = (*addr & mask) ? 1 : 0; - *addr ^= mask; + oldbit = *addr; + *addr = oldbit ^ mask; - return oldbit; + return (oldbit & mask) ? 1 : 0; } static __inline__ int test_bit(int nr, const volatile unsigned long *address) { - unsigned long mask; - const unsigned long *addr = (const unsigned long *)address; - - addr += (nr >> SHIFT_PER_LONG); - mask = 1L << CHOP_SHIFTCOUNT(nr); + unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); + const unsigned long *addr = (const unsigned long *)address + (nr >> SHIFT_PER_LONG); return !!(*addr & mask); } @@ -229,7 +193,7 @@ static __inline__ unsigned long __ffs(unsigned long x) unsigned long ret; __asm__( -#if BITS_PER_LONG > 32 +#ifdef __LP64__ " ldi 63,%1\n" " extrd,u,*<> %0,63,32,%%r0\n" " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */ @@ -304,14 +268,7 @@ static __inline__ int fls(int x) * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word */ -#define hweight64(x) \ -({ \ - unsigned long __x = (x); \ - unsigned int __w; \ - __w = generic_hweight32((unsigned int) __x); \ - __w += generic_hweight32((unsigned int) (__x>>32)); \ - __w; \ -}) +#define hweight64(x) generic_hweight64(x) #define hweight32(x) generic_hweight32(x) #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) @@ -324,7 +281,13 @@ static __inline__ int fls(int x) */ static inline int sched_find_first_bit(const unsigned long *b) { -#ifndef __LP64__ +#ifdef __LP64__ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 64; + return __ffs(b[2]) + 128; +#else if (unlikely(b[0])) return __ffs(b[0]); if (unlikely(b[1])) @@ -334,14 +297,6 @@ static inline int sched_find_first_bit(const unsigned long *b) if (b[3]) return __ffs(b[3]) + 96; return __ffs(b[4]) + 128; -#else - if (unlikely(b[0])) - return __ffs(b[0]); - if (unlikely(((unsigned int)b[1]))) - return __ffs(b[1]) + 64; - if (b[1] >> 32) - return __ffs(b[1] >> 32) + 96; - return __ffs(b[2]) + 128; #endif } @@ -391,7 +346,7 @@ static __inline__ unsigned long find_next_zero_bit(const void * addr, unsigned l static __inline__ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { - const unsigned long *p = addr + (offset >> 6); + const unsigned long *p = addr + (offset >> SHIFT_PER_LONG); unsigned long result = offset & ~(BITS_PER_LONG-1); unsigned long tmp; @@ -445,71 +400,90 @@ static __inline__ unsigned long find_next_bit(const unsigned long *addr, unsigne * test_and_{set,clear}_bit guarantee atomicity without * disabling interrupts. */ -#ifdef __LP64__ -#define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x38, (unsigned long *)addr) -#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x38, (unsigned long *)addr) -#define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x38, (unsigned long *)addr) -#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x38, (unsigned long *)addr) -#else -#define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x18, (unsigned long *)addr) -#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x18, (unsigned long *)addr) -#define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x18, (unsigned long *)addr) -#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x18, (unsigned long *)addr) -#endif + +/* '3' is bits per byte */ +#define LE_BYTE_ADDR ((sizeof(unsigned long) - 1) << 3) + +#define ext2_test_bit(nr, addr) \ + test_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr) +#define ext2_set_bit(nr, addr) \ + __test_and_set_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr) +#define ext2_clear_bit(nr, addr) \ + __test_and_clear_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr) + +#define ext2_set_bit_atomic(l,nr,addr) \ + test_and_set_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr) +#define ext2_clear_bit_atomic(l,nr,addr) \ + test_and_clear_bit( (nr) ^ LE_BYTE_ADDR, (unsigned long *)addr) #endif /* __KERNEL__ */ -static __inline__ int ext2_test_bit(int nr, __const__ void * addr) -{ - __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; - - return (ADDR[nr >> 3] >> (nr & 7)) & 1; -} - -/* - * This implementation of ext2_find_{first,next}_zero_bit was stolen from - * Linus' asm-alpha/bitops.h and modified for a big-endian machine. - */ #define ext2_find_first_zero_bit(addr, size) \ - ext2_find_next_zero_bit((addr), (size), 0) + ext2_find_next_zero_bit((addr), (size), 0) -extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, - unsigned long size, unsigned long offset) +/* include/linux/byteorder does not support "unsigned long" type */ +static inline unsigned long ext2_swabp(unsigned long * x) { - unsigned int *p = ((unsigned int *) addr) + (offset >> 5); - unsigned int result = offset & ~31UL; - unsigned int tmp; +#ifdef __LP64__ + return (unsigned long) __swab64p((u64 *) x); +#else + return (unsigned long) __swab32p((u32 *) x); +#endif +} + +/* include/linux/byteorder doesn't support "unsigned long" type */ +static inline unsigned long ext2_swab(unsigned long y) +{ +#ifdef __LP64__ + return (unsigned long) __swab64((u64) y); +#else + return (unsigned long) __swab32((u32) y); +#endif +} + +static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = (unsigned long *) addr + (offset >> SHIFT_PER_LONG); + unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long tmp; if (offset >= size) return size; size -= result; - offset &= 31UL; + offset &= (BITS_PER_LONG - 1UL); if (offset) { - tmp = cpu_to_le32p(p++); - tmp |= ~0UL >> (32-offset); - if (size < 32) + tmp = ext2_swabp(p++); + tmp |= (~0UL >> (BITS_PER_LONG - offset)); + if (size < BITS_PER_LONG) goto found_first; - if (tmp != ~0U) + if (~tmp) goto found_middle; - size -= 32; - result += 32; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; } - while (size >= 32) { - if ((tmp = cpu_to_le32p(p++)) != ~0U) - goto found_middle; - result += 32; - size -= 32; + + while (size & ~(BITS_PER_LONG - 1)) { + if (~(tmp = *(p++))) + goto found_middle_swap; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; } if (!size) return result; - tmp = cpu_to_le32p(p); + tmp = ext2_swabp(p); found_first: - tmp |= ~0U << size; + tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. Skip ffz */ found_middle: return result + ffz(tmp); + +found_middle_swap: + return result + ffz(ext2_swab(tmp)); } + /* Bitmap functions for the minix filesystem. */ #define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr) #define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr)) diff --git a/include/asm-parisc/types.h b/include/asm-parisc/types.h index d21b9d0d63ea..34fdce361a5a 100644 --- a/include/asm-parisc/types.h +++ b/include/asm-parisc/types.h @@ -33,8 +33,10 @@ typedef unsigned long long __u64; #ifdef __LP64__ #define BITS_PER_LONG 64 +#define SHIFT_PER_LONG 6 #else #define BITS_PER_LONG 32 +#define SHIFT_PER_LONG 5 #endif #ifndef __ASSEMBLY__ From ba1f188cae2f58e6bf3ecf4ea99a8dc4b0e2ea0e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 21 Oct 2005 22:45:57 -0400 Subject: [PATCH 0591/1939] [PARISC] Add new ioprio_{set,get} syscalls add syscall entries for ioprio_set/get as per Jens Axboe. Signed-off-by: Jens Axboe Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/syscall_table.S | 6 ++++++ include/asm-parisc/unistd.h | 16 +++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index dcfa4d3d0e7d..065ab809659d 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -368,5 +368,11 @@ ENTRY_COMP(mbind) /* 260 */ ENTRY_COMP(get_mempolicy) ENTRY_COMP(set_mempolicy) + ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ + ENTRY_SAME(add_key) + ENTRY_SAME(request_key) /* 265 */ + ENTRY_SAME(keyctl) + ENTRY_SAME(ioprio_set) + ENTRY_SAME(ioprio_get) /* Nothing yet */ diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 6a9f0cadff58..e7a620c5c5e6 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h @@ -687,8 +687,8 @@ #define __NR_shmget (__NR_Linux + 194) #define __NR_shmctl (__NR_Linux + 195) -#define __NR_getpmsg (__NR_Linux + 196) /* some people actually want streams */ -#define __NR_putpmsg (__NR_Linux + 197) /* some people actually want streams */ +#define __NR_getpmsg (__NR_Linux + 196) /* Somebody *wants* streams? */ +#define __NR_putpmsg (__NR_Linux + 197) #define __NR_lstat64 (__NR_Linux + 198) #define __NR_truncate64 (__NR_Linux + 199) @@ -755,8 +755,14 @@ #define __NR_mbind (__NR_Linux + 260) #define __NR_get_mempolicy (__NR_Linux + 261) #define __NR_set_mempolicy (__NR_Linux + 262) +#define __NR_vserver (__NR_Linux + 263) +#define __NR_add_key (__NR_Linux + 264) +#define __NR_request_key (__NR_Linux + 265) +#define __NR_keyctl (__NR_Linux + 266) +#define __NR_ioprio_set (__NR_Linux + 267) +#define __NR_ioprio_get (__NR_Linux + 268) -#define __NR_Linux_syscalls 263 +#define __NR_Linux_syscalls 269 #define HPUX_GATEWAY_ADDR 0xC0000004 #define LINUX_GATEWAY_ADDR 0x100 @@ -807,10 +813,10 @@ #define K_INLINE_SYSCALL(name, nr, args...) ({ \ long __sys_res; \ { \ - register unsigned long __res asm("r28"); \ + register unsigned long __res __asm__("r28"); \ K_LOAD_ARGS_##nr(args) \ /* FIXME: HACK stw/ldw r19 around syscall */ \ - asm volatile( \ + __asm__ volatile( \ K_STW_ASM_PIC \ " ble 0x100(%%sr2, %%r0)\n" \ " ldi %1, %%r20\n" \ From 3499495205a676d85fcc2f3c28e35ec9b43c47e3 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:46:18 -0400 Subject: [PATCH 0592/1939] [PARISC] Use work queue in LED/LCD driver instead of tasklet. 2.6.12-rc1-pa6 use work queue in LED/LCD driver instead of tasklet. Main advantage is it allows use of msleep() in the led_LCD_driver to "atomically" perform two MMIO writes (CMD, then DATA). Lead to nice cleanup of the main led_work_func() and led_LCD_driver(). Kudos to David for being persistent. From: David Pye Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 8 -- drivers/parisc/led.c | 225 +++++++++++++++++++------------------- include/asm-parisc/led.h | 3 - 3 files changed, 112 insertions(+), 124 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 163cdf39be20..bc979e1abdec 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -89,14 +89,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } -#ifdef CONFIG_CHASSIS_LCD_LED - /* Only schedule the led tasklet on cpu 0, and only if it - * is enabled. - */ - if (cpu == 0 && !atomic_read(&led_tasklet.count)) - tasklet_schedule(&led_tasklet); -#endif - /* check soft power switch status */ if (cpu == 0 && !atomic_read(&power_tasklet.count)) tasklet_schedule(&power_tasklet); diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 286902298e33..95bd07b8b61b 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -18,6 +18,9 @@ * Changes: * - Audit copy_from_user in led_proc_write. * Daniele Bellucci + * - Switch from using a tasklet to a work queue, so the led_LCD_driver + * can sleep. + * David Pye */ #include @@ -37,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -47,25 +51,30 @@ #include /* The control of the LEDs and LCDs on PARISC-machines have to be done - completely in software. The necessary calculations are done in a tasklet - which is scheduled at every timer interrupt and since the calculations - may consume relatively much CPU-time some of the calculations can be + completely in software. The necessary calculations are done in a work queue + task which is scheduled regularly, and since the calculations may consume a + relatively large amount of CPU time, some of the calculations can be turned off with the following variables (controlled via procfs) */ static int led_type = -1; -static int led_heartbeat = 1; -static int led_diskio = 1; -static int led_lanrxtx = 1; +static unsigned char lastleds; /* LED state from most recent update */ +static unsigned int led_heartbeat = 1; +static unsigned int led_diskio = 1; +static unsigned int led_lanrxtx = 1; static char lcd_text[32]; static char lcd_text_default[32]; + +static struct workqueue_struct *led_wq; +static void led_work_func(void *); +static DECLARE_WORK(led_task, led_work_func, NULL); + #if 0 #define DPRINTK(x) printk x #else #define DPRINTK(x) #endif - struct lcd_block { unsigned char command; /* stores the command byte */ unsigned char on; /* value for turning LED on */ @@ -116,12 +125,27 @@ lcd_info __attribute__((aligned(8))) = #define LCD_DATA_REG lcd_info.lcd_data_reg_addr #define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ +#define LED_HASLCD 1 +#define LED_NOLCD 0 + +/* The workqueue must be created at init-time */ +static int start_task(void) +{ + /* Display the default text now */ + if (led_type == LED_HASLCD) lcd_print( lcd_text_default ); + + /* Create the work queue and queue the LED task */ + led_wq = create_singlethread_workqueue("led_wq"); + queue_work(led_wq, &led_task); + + return 0; +} + +device_initcall(start_task); /* ptr to LCD/LED-specific function */ static void (*led_func_ptr) (unsigned char); -#define LED_HASLCD 1 -#define LED_NOLCD 0 #ifdef CONFIG_PROC_FS static int led_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -286,52 +310,35 @@ static void led_LASI_driver(unsigned char leds) /* ** ** led_LCD_driver() - ** - ** The logic of the LCD driver is, that we write at every scheduled call - ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers. - ** That way we don't need to let this tasklet busywait for min_cmd_delay - ** milliseconds. - ** - ** TODO: check the value of "min_cmd_delay" against the value of HZ. ** */ static void led_LCD_driver(unsigned char leds) { - static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ - static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */ - struct lcd_block *block_ptr; - int value; - - switch (last_index) { - case 0: block_ptr = &lcd_info.heartbeat; - value = leds & LED_HEARTBEAT; - break; - case 1: block_ptr = &lcd_info.disk_io; - value = leds & LED_DISK_IO; - break; - case 2: block_ptr = &lcd_info.lan_rcv; - value = leds & LED_LAN_RCV; - break; - case 3: block_ptr = &lcd_info.lan_tx; - value = leds & LED_LAN_TX; - break; - default: /* should never happen: */ - return; - } - - if (last_was_cmd) { - /* write the value to the LCD data port */ - gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG ); - } else { - /* write the command-byte to the LCD command register */ - gsc_writeb( block_ptr->command, LCD_CMD_REG ); - } + static int i; + static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO, + LED_LAN_RCV, LED_LAN_TX }; - /* now update the vars for the next interrupt iteration */ - if (++last_was_cmd == 2) { /* switch between cmd & data */ - last_was_cmd = 0; - if (++last_index == 4) - last_index = 0; /* switch back to heartbeat index */ + static struct lcd_block * blockp[4] = { + &lcd_info.heartbeat, + &lcd_info.disk_io, + &lcd_info.lan_rcv, + &lcd_info.lan_tx + }; + + /* Convert min_cmd_delay to milliseconds */ + unsigned int msec_cmd_delay = 1 + (lcd_info.min_cmd_delay / 1000); + + for (i=0; i<4; ++i) + { + if ((leds & mask[i]) != (lastleds & mask[i])) + { + gsc_writeb( blockp[i]->command, LCD_CMD_REG ); + msleep(msec_cmd_delay); + + gsc_writeb( leds & mask[i] ? blockp[i]->on : + blockp[i]->off, LCD_DATA_REG ); + msleep(msec_cmd_delay); + } } } @@ -356,7 +363,7 @@ static __inline__ int led_get_net_activity(void) rx_total = tx_total = 0; - /* we are running as tasklet, so locking dev_base + /* we are running as a workqueue task, so locking dev_base * for reading should be OK */ read_lock(&dev_base_lock); rcu_read_lock(); @@ -405,7 +412,7 @@ static __inline__ int led_get_diskio_activity(void) static unsigned long last_pgpgin, last_pgpgout; struct page_state pgstat; int changed; - + get_full_page_state(&pgstat); /* get no of sectors in & out */ /* Just use a very simple calculation here. Do not care about overflow, @@ -413,87 +420,71 @@ static __inline__ int led_get_diskio_activity(void) changed = (pgstat.pgpgin != last_pgpgin) || (pgstat.pgpgout != last_pgpgout); last_pgpgin = pgstat.pgpgin; last_pgpgout = pgstat.pgpgout; - + return (changed ? LED_DISK_IO : 0); } /* - ** led_tasklet_func() + ** led_work_func() ** - ** is scheduled at every timer interrupt from time.c and - ** updates the chassis LCD/LED + ** manages when and which chassis LCD/LED gets updated TODO: - display load average (older machines like 715/64 have 4 "free" LED's for that) - optimizations */ -#define HEARTBEAT_LEN (HZ*6/100) -#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) +#define HEARTBEAT_LEN (HZ*10/100) +#define HEARTBEAT_2ND_RANGE_START (HZ*28/100) #define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) -#define NORMALIZED_COUNT(count) (count/(HZ/100)) +#define LED_UPDATE_INTERVAL (1 + (HZ*19/1000)) -static void led_tasklet_func(unsigned long unused) +static void led_work_func (void *unused) { - static unsigned char lastleds; - unsigned char currentleds; /* stores current value of the LEDs */ - static unsigned long count; /* static incremented value, not wrapped */ + static unsigned long last_jiffies; static unsigned long count_HZ; /* counter in range 0..HZ */ + unsigned char currentleds = 0; /* stores current value of the LEDs */ /* exit if not initialized */ if (!led_func_ptr) return; - /* increment the local counters */ - ++count; - if (++count_HZ == HZ) + /* increment the heartbeat timekeeper */ + count_HZ += jiffies - last_jiffies; + last_jiffies = jiffies; + if (count_HZ >= HZ) count_HZ = 0; - currentleds = lastleds; - - if (led_heartbeat) + if (likely(led_heartbeat)) { - /* flash heartbeat-LED like a real heart (2 x short then a long delay) */ - if (count_HZ=HEARTBEAT_2ND_RANGE_START && count_HZ= HEARTBEAT_2ND_RANGE_START && + count_HZ < HEARTBEAT_2ND_RANGE_END)) + currentleds |= LED_HEARTBEAT; } - /* look for network activity and flash LEDs respectively */ - if (led_lanrxtx && ((NORMALIZED_COUNT(count)+(8/2)) & 7) == 0) - { - currentleds &= ~(LED_LAN_RCV | LED_LAN_TX); - currentleds |= led_get_net_activity(); - } - - /* avoid to calculate diskio-stats at same irq as netio-stats */ - if (led_diskio && (NORMALIZED_COUNT(count) & 7) == 0) - { - currentleds &= ~LED_DISK_IO; - currentleds |= led_get_diskio_activity(); - } + if (likely(led_lanrxtx)) currentleds |= led_get_net_activity(); + if (likely(led_diskio)) currentleds |= led_get_diskio_activity(); /* blink all LEDs twice a second if we got an Oops (HPMC) */ - if (oops_in_progress) { + if (unlikely(oops_in_progress)) currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff; + + if (currentleds != lastleds) + { + led_func_ptr(currentleds); /* Update the LCD/LEDs */ + lastleds = currentleds; } - - /* update the LCD/LEDs */ - if (currentleds != lastleds) { - led_func_ptr(currentleds); - lastleds = currentleds; - } + + queue_delayed_work(led_wq, &led_task, LED_UPDATE_INTERVAL); } -/* main led tasklet struct (scheduled from time.c) */ -DECLARE_TASKLET_DISABLED(led_tasklet, led_tasklet_func, 0); - - /* ** led_halt() ** @@ -522,9 +513,13 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) default: return NOTIFY_DONE; } - /* completely stop the LED/LCD tasklet */ - tasklet_disable(&led_tasklet); - + /* Cancel the work item and delete the queue */ + if (led_wq) { + cancel_rearming_delayed_workqueue(led_wq, &led_task); + destroy_workqueue(led_wq); + led_wq = NULL; + } + if (lcd_info.model == DISPLAY_MODEL_LCD) lcd_print(txt); else @@ -559,7 +554,6 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d printk(KERN_INFO "LCD display at %lx,%lx registered\n", LCD_CMD_REG , LCD_DATA_REG); led_func_ptr = led_LCD_driver; - lcd_print( lcd_text_default ); led_type = LED_HASLCD; break; @@ -589,9 +583,11 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d initialized++; register_reboot_notifier(&led_notifier); - /* start the led tasklet for the first time */ - tasklet_enable(&led_tasklet); - + /* Ensure the work is queued */ + if (led_wq) { + queue_work(led_wq, &led_task); + } + return 0; } @@ -626,8 +622,8 @@ void __init register_led_regions(void) ** lcd_print() ** ** Displays the given string on the LCD-Display of newer machines. - ** lcd_print() disables the timer-based led tasklet during its - ** execution and enables it afterwards again. + ** lcd_print() disables/enables the timer-based led work queue to + ** avoid a race condition while writing the CMD/DATA register pair. ** */ int lcd_print( char *str ) @@ -637,12 +633,13 @@ int lcd_print( char *str ) if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD) return 0; - /* temporarily disable the led tasklet */ - tasklet_disable(&led_tasklet); + /* temporarily disable the led work task */ + if (led_wq) + cancel_rearming_delayed_workqueue(led_wq, &led_task); /* copy display string to buffer for procfs */ strlcpy(lcd_text, str, sizeof(lcd_text)); - + /* Set LCD Cursor to 1st character */ gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG); udelay(lcd_info.min_cmd_delay); @@ -656,8 +653,10 @@ int lcd_print( char *str ) udelay(lcd_info.min_cmd_delay); } - /* re-enable the led tasklet */ - tasklet_enable(&led_tasklet); + /* re-queue the work */ + if (led_wq) { + queue_work(led_wq, &led_task); + } return lcd_info.lcd_width; } diff --git a/include/asm-parisc/led.h b/include/asm-parisc/led.h index 1ac8ab6c580d..efadfd543ec6 100644 --- a/include/asm-parisc/led.h +++ b/include/asm-parisc/led.h @@ -23,9 +23,6 @@ #define LED_CMD_REG_NONE 0 /* NULL == no addr for the cmd register */ -/* led tasklet struct */ -extern struct tasklet_struct led_tasklet; - /* register_led_driver() */ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg); From 413059f28e9949d9ad2d04d1070c63169798176e Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:46:48 -0400 Subject: [PATCH 0593/1939] [PARISC] Replace uses of __LP64__ with CONFIG_64BIT 2.6.12-rc4-pa3 s/__LP64__/CONFIG_64BIT/ and fixup config.h usage Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 98 +++++++++++++++--------------- arch/parisc/kernel/head.S | 26 ++++---- arch/parisc/kernel/pacache.S | 30 ++++----- arch/parisc/kernel/real2.S | 16 ++--- arch/parisc/kernel/smp.c | 2 +- arch/parisc/kernel/syscall.S | 37 ++++++----- arch/parisc/kernel/syscall_table.S | 4 +- 7 files changed, 108 insertions(+), 105 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index ec04e0ad77fa..0ca49710d95e 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -37,7 +37,7 @@ #include #include -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define CMPIB cmpib,* #define CMPB cmpb,* #define COND(x) *x @@ -217,7 +217,7 @@ va = r8 /* virtual address for which the trap occured */ spc = r24 /* space for which the trap occured */ -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* * itlb miss interruption handler (parisc 1.1 - 32 bit) @@ -239,7 +239,7 @@ .macro itlb_20 code mfctl %pcsq, spc -#ifdef __LP64__ +#ifdef CONFIG_64BIT b itlb_miss_20w #else b itlb_miss_20 @@ -249,7 +249,7 @@ .align 32 .endm -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* * naitlb miss interruption handler (parisc 1.1 - 32 bit) * @@ -286,7 +286,7 @@ .macro naitlb_20 code mfctl %isr,spc -#ifdef __LP64__ +#ifdef CONFIG_64BIT b itlb_miss_20w #else b itlb_miss_20 @@ -299,7 +299,7 @@ .align 32 .endm -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* * dtlb miss interruption handler (parisc 1.1 - 32 bit) */ @@ -321,7 +321,7 @@ .macro dtlb_20 code mfctl %isr, spc -#ifdef __LP64__ +#ifdef CONFIG_64BIT b dtlb_miss_20w #else b dtlb_miss_20 @@ -331,7 +331,7 @@ .align 32 .endm -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro nadtlb_11 code @@ -349,7 +349,7 @@ .macro nadtlb_20 code mfctl %isr,spc -#ifdef __LP64__ +#ifdef CONFIG_64BIT b nadtlb_miss_20w #else b nadtlb_miss_20 @@ -359,7 +359,7 @@ .align 32 .endm -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* * dirty bit trap interruption handler (parisc 1.1 - 32 bit) */ @@ -381,7 +381,7 @@ .macro dbit_20 code mfctl %isr,spc -#ifdef __LP64__ +#ifdef CONFIG_64BIT b dbit_trap_20w #else b dbit_trap_20 @@ -394,7 +394,7 @@ /* The following are simple 32 vs 64 bit instruction * abstractions for the macros */ .macro EXTR reg1,start,length,reg2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u \reg1,32+\start,\length,\reg2 #else extrw,u \reg1,\start,\length,\reg2 @@ -402,7 +402,7 @@ .endm .macro DEP reg1,start,length,reg2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depd \reg1,32+\start,\length,\reg2 #else depw \reg1,\start,\length,\reg2 @@ -410,7 +410,7 @@ .endm .macro DEPI val,start,length,reg -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi \val,32+\start,\length,\reg #else depwi \val,\start,\length,\reg @@ -421,7 +421,7 @@ * fault. We have to extract this and place it in the va, * zeroing the corresponding bits in the space register */ .macro space_adjust spc,va,tmp -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u \spc,63,SPACEID_SHIFT,\tmp depd %r0,63,SPACEID_SHIFT,\spc depd \tmp,31,SPACEID_SHIFT,\va @@ -479,7 +479,7 @@ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ copy \pmd,%r9 -#ifdef __LP64__ +#ifdef CONFIG_64BIT shld %r9,PxD_VALUE_SHIFT,\pmd #else shlw %r9,PxD_VALUE_SHIFT,\pmd @@ -610,7 +610,7 @@ .macro do_alias spc,tmp,tmp1,va,pte,prot,fault cmpib,COND(<>),n 0,\spc,\fault ldil L%(TMPALIAS_MAP_START),\tmp -#if defined(__LP64__) && (TMPALIAS_MAP_START >= 0x80000000) +#if defined(CONFIG_64BIT) && (TMPALIAS_MAP_START >= 0x80000000) /* on LP64, ldi will sign extend into the upper 32 bits, * which is behaviour we don't want */ depdi 0,31,32,\tmp @@ -624,7 +624,7 @@ * OK, it is in the temp alias region, check whether "from" or "to". * Check "subtle" note in pacache.S re: r23/r26. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u,*= \va,41,1,%r0 #else extrw,u,= \va,9,1,%r0 @@ -691,7 +691,7 @@ fault_vector_20: def 30 def 31 -#ifndef __LP64__ +#ifndef CONFIG_64BIT .export fault_vector_11 @@ -764,7 +764,7 @@ __kernel_thread: copy %r30, %r1 ldo PT_SZ_ALGN(%r30),%r30 -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Yo, function pointers in wide mode are little structs... -PB */ ldd 24(%r26), %r2 STREG %r2, PT_GR27(%r1) /* Store childs %dp */ @@ -780,7 +780,7 @@ __kernel_thread: or %r26, %r24, %r26 /* will have kernel mappings. */ ldi 1, %r25 /* stack_start, signals kernel thread */ stw %r0, -52(%r30) /* user_tid */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif BL do_fork, %r2 @@ -809,7 +809,7 @@ ret_from_kernel_thread: LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1 LDREG TASK_PT_GR25(%r1), %r26 -#ifdef __LP64__ +#ifdef CONFIG_64BIT LDREG TASK_PT_GR27(%r1), %r27 LDREG TASK_PT_GR22(%r1), %r22 #endif @@ -817,7 +817,7 @@ ret_from_kernel_thread: ble 0(%sr7, %r1) copy %r31, %r2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ loadgp /* Thread could have been in a module */ #endif @@ -838,7 +838,7 @@ __execve: STREG %r26, PT_GR26(%r16) STREG %r25, PT_GR25(%r16) STREG %r24, PT_GR24(%r16) -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif BL sys_execve, %r2 @@ -916,7 +916,7 @@ syscall_exit_rfi: STREG %r19,PT_IAOQ1(%r16) LDREG PT_PSW(%r16),%r19 load32 USER_PSW_MASK,%r1 -#ifdef __LP64__ +#ifdef CONFIG_64BIT load32 USER_PSW_HI_MASK,%r20 depd %r20,31,32,%r1 #endif @@ -960,7 +960,7 @@ intr_return: /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount ** irq_stat[] is defined using ____cacheline_aligned. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT shld %r1, 6, %r20 #else shlw %r1, 5, %r20 @@ -1018,7 +1018,7 @@ intr_restore: .import do_softirq,code intr_do_softirq: BL do_softirq,%r2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #else nop @@ -1036,7 +1036,7 @@ intr_do_resched: CMPIB= 0,%r20,intr_restore /* backward */ nop -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1069,7 +1069,7 @@ intr_do_signal: copy %r0, %r24 /* unsigned long in_syscall */ copy %r16, %r25 /* struct pt_regs *regs */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1093,7 +1093,7 @@ intr_extint: mfctl %cr31,%r1 copy %r30,%r17 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/ -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi 0,63,15,%r17 #else depi 0,31,15,%r17 @@ -1120,7 +1120,7 @@ intr_extint: ldil L%intr_return, %r2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1164,7 +1164,7 @@ intr_save: mfctl %cr21, %r17 /* ior */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* * If the interrupted code was running with W bit off (32 bit), * clear the b bits (bits 0 & 1) in the ior. @@ -1199,7 +1199,7 @@ skip_save_ior: loadgp copy %r29, %r25 /* arg1 is pt_regs */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1237,7 +1237,7 @@ skip_save_ior: spc = r24 /* space for which the trap occured */ ptp = r25 /* page directory/page table pointer */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT dtlb_miss_20w: space_adjust spc,va,t0 @@ -1528,7 +1528,7 @@ nadtlb_probe_check: nop -#ifdef __LP64__ +#ifdef CONFIG_64BIT itlb_miss_20w: /* @@ -1595,7 +1595,7 @@ itlb_miss_20: #endif -#ifdef __LP64__ +#ifdef CONFIG_64BIT dbit_trap_20w: space_adjust spc,va,t0 @@ -1804,7 +1804,7 @@ sys_fork_wrapper: STREG %r2,-RP_OFFSET(%r30) ldo FRAME_SIZE(%r30),%r30 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1854,7 +1854,7 @@ sys_clone_wrapper: STREG %r2,-RP_OFFSET(%r30) ldo FRAME_SIZE(%r30),%r30 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1876,7 +1876,7 @@ sys_vfork_wrapper: STREG %r2,-RP_OFFSET(%r30) ldo FRAME_SIZE(%r30),%r30 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1904,7 +1904,7 @@ sys_vfork_wrapper: STREG %r2,-RP_OFFSET(%r30) ldo FRAME_SIZE(%r30),%r30 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif BL \execve,%r2 @@ -1930,7 +1930,7 @@ error_\execve: sys_execve_wrapper: execve_wrapper sys_execve -#ifdef __LP64__ +#ifdef CONFIG_64BIT .export sys32_execve_wrapper .import sys32_execve @@ -1944,7 +1944,7 @@ sys_rt_sigreturn_wrapper: ldo TASK_REGS(%r26),%r26 /* get pt regs */ /* Don't save regs, we are going to restore them from sigcontext. */ STREG %r2, -RP_OFFSET(%r30) -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo FRAME_SIZE(%r30), %r30 BL sys_rt_sigreturn,%r2 ldo -16(%r30),%r29 /* Reference param save area */ @@ -1975,7 +1975,7 @@ sys_sigaltstack_wrapper: ldo TASK_REGS(%r1),%r24 /* get pt regs */ LDREG TASK_PT_GR30(%r24),%r24 STREG %r2, -RP_OFFSET(%r30) -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo FRAME_SIZE(%r30), %r30 b,l do_sigaltstack,%r2 ldo -16(%r30),%r29 /* Reference param save area */ @@ -1989,7 +1989,7 @@ sys_sigaltstack_wrapper: bv %r0(%r2) nop -#ifdef __LP64__ +#ifdef CONFIG_64BIT .export sys32_sigaltstack_wrapper sys32_sigaltstack_wrapper: /* Get the user stack pointer */ @@ -2013,7 +2013,7 @@ sys_rt_sigsuspend_wrapper: reg_save %r24 STREG %r2, -RP_OFFSET(%r30) -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo FRAME_SIZE(%r30), %r30 b,l sys_rt_sigsuspend,%r2 ldo -16(%r30),%r29 /* Reference param save area */ @@ -2086,7 +2086,7 @@ syscall_check_bh: ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT shld %r26, 6, %r20 #else shlw %r26, 5, %r20 @@ -2151,7 +2151,7 @@ syscall_restore: depi 3,31,2,%r31 /* ensure return to user mode. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* decide whether to reset the wide mode bit * * For a syscall, the W bit is stored in the lowest bit @@ -2247,7 +2247,7 @@ syscall_do_softirq: .import schedule,code syscall_do_resched: BL schedule,%r2 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #else nop @@ -2267,7 +2267,7 @@ syscall_do_signal: ldi 1, %r24 /* unsigned long in_syscall */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif BL do_signal,%r2 diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 2b8738576ec2..0b47afc20690 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -12,7 +12,7 @@ * Initial Version 04-23-1999 by Helge Deller */ -#include /* for CONFIG_SMP */ +#include /* for CONFIG_SMP */ #include #include @@ -36,10 +36,10 @@ boot_args: .align 4 .import init_thread_union,data .import fault_vector_20,code /* IVA parisc 2.0 32 bit */ -#ifndef __LP64__ +#ifndef CONFIG_64BIT .import fault_vector_11,code /* IVA parisc 1.1 32 bit */ .import $global$ /* forward declaration */ -#endif /*!LP64*/ +#endif /*!CONFIG_64BIT*/ .export stext .export _stext,data /* Kernel want it this way! */ _stext: @@ -76,7 +76,7 @@ $bss_loop: mtctl %r4,%cr24 /* Initialize kernel root pointer */ mtctl %r4,%cr25 /* Initialize user root pointer */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Set pmd in pgd */ load32 PA(pmd0),%r5 shrd %r5,PxD_VALUE_SHIFT,%r3 @@ -99,7 +99,7 @@ $bss_loop: stw %r3,0(%r4) ldo (ASM_PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3 addib,> -1,%r1,1b -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo ASM_PMD_ENTRY_SIZE(%r4),%r4 #else ldo ASM_PGD_ENTRY_SIZE(%r4),%r4 @@ -170,7 +170,7 @@ common_stext: stw %r0,0x28(%r0) /* MEM_RENDEZ_HI */ #endif /*CONFIG_SMP*/ -#ifdef __LP64__ +#ifdef CONFIG_64BIT tophys_r1 %sp /* Save the rfi target address */ @@ -233,7 +233,7 @@ stext_pdc_ret: * following short sequence of instructions can determine this * (without being illegal on a PA1.1 machine). */ -#ifndef __LP64__ +#ifndef CONFIG_64BIT ldi 32,%r10 mtctl %r10,%cr11 .level 2.0 @@ -246,7 +246,7 @@ stext_pdc_ret: $is_pa20: .level LEVEL /* restore 1.1 || 2.0w */ -#endif /*!LP64*/ +#endif /*!CONFIG_64BIT*/ load32 PA(fault_vector_20),%r10 $install_iva: @@ -284,7 +284,7 @@ aligned_rfi: .import smp_init_current_idle_task,data .import smp_callin,code -#ifndef __LP64__ +#ifndef CONFIG_64BIT smp_callin_rtn: .proc .callinfo @@ -292,7 +292,7 @@ smp_callin_rtn: nop nop .procend -#endif /*!LP64*/ +#endif /*!CONFIG_64BIT*/ /*************************************************************************** * smp_slave_stext is executed by all non-monarch Processors when the Monarch @@ -327,7 +327,7 @@ smp_slave_stext: mtctl %r4,%cr24 /* Initialize kernel root pointer */ mtctl %r4,%cr25 /* Initialize user root pointer */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Setup PDCE_PROC entry */ copy %arg0,%r3 #else @@ -344,7 +344,7 @@ smp_slave_stext: .procend #endif /* CONFIG_SMP */ -#ifndef __LP64__ +#ifndef CONFIG_64BIT .data .align 4 @@ -354,4 +354,4 @@ smp_slave_stext: .size $global$,4 $global$: .word 0 -#endif /*!LP64*/ +#endif /*!CONFIG_64BIT*/ diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 71ade44c4618..4a7d9c8903f4 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -26,7 +26,7 @@ * can be used. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define ADDIB addib,* #define CMPB cmpb,* #define ANDCM andcm,* @@ -40,6 +40,8 @@ .level 2.0 #endif +#include + #include #include #include @@ -294,7 +296,7 @@ copy_user_page_asm: .callinfo NO_CALLS .entry -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. * Unroll the loop by hand and arrange insn appropriately. * GCC probably can do this just as well. @@ -454,7 +456,7 @@ copy_user_page_asm: sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */ ldil L%(TMPALIAS_MAP_START), %r28 -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */ extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */ depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */ @@ -541,7 +543,7 @@ __clear_user_page_asm: tophys_r1 %r26 ldil L%(TMPALIAS_MAP_START), %r28 -#ifdef __LP64__ +#ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) depdi 0, 31,32, %r28 /* clear any sign extension */ #endif @@ -558,7 +560,7 @@ __clear_user_page_asm: pdtlb 0(%r28) -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldi 32, %r1 /* PAGE_SIZE/128 == 32 */ /* PREFETCH (Write) has not (yet) been proven to help here */ @@ -583,7 +585,7 @@ __clear_user_page_asm: ADDIB> -1, %r1, 1b ldo 128(%r28), %r28 -#else /* ! __LP64 */ +#else /* ! CONFIG_64BIT */ ldi 64, %r1 /* PAGE_SIZE/64 == 64 */ @@ -606,7 +608,7 @@ __clear_user_page_asm: stw %r0, 60(%r28) ADDIB> -1, %r1, 1b ldo 64(%r28), %r28 -#endif /* __LP64 */ +#endif /* CONFIG_64BIT */ bv %r0(%r2) nop @@ -624,7 +626,7 @@ flush_kernel_dcache_page: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 #else depwi,z 1, 31-PAGE_SHIFT,1, %r25 @@ -668,7 +670,7 @@ flush_user_dcache_page: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1,63-PAGE_SHIFT,1, %r25 #else depwi,z 1,31-PAGE_SHIFT,1, %r25 @@ -712,7 +714,7 @@ flush_user_icache_page: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 #else depwi,z 1, 31-PAGE_SHIFT,1, %r25 @@ -757,7 +759,7 @@ purge_kernel_dcache_page: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 #else depwi,z 1, 31-PAGE_SHIFT,1, %r25 @@ -805,7 +807,7 @@ flush_alias_page: tophys_r1 %r26 ldil L%(TMPALIAS_MAP_START), %r28 -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u %r26, 56,32, %r26 /* convert phys addr to tlb insert format */ depd %r25, 63,22, %r28 /* Form aliased virtual address 'to' */ depdi 0, 63,12, %r28 /* Clear any offset bits */ @@ -822,7 +824,7 @@ flush_alias_page: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r29 #else depwi,z 1, 31-PAGE_SHIFT,1, %r29 @@ -933,7 +935,7 @@ flush_kernel_icache_page: ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 #else depwi,z 1, 31-PAGE_SHIFT,1, %r25 diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 2310fc1b06a9..085bff7c569d 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -7,6 +7,8 @@ * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) * */ +#include + #include #include @@ -20,7 +22,7 @@ real32_stack: real64_stack: .block 8192 -#ifdef __LP64__ +#ifdef CONFIG_64BIT # define REG_SZ 8 #else # define REG_SZ 4 @@ -50,7 +52,7 @@ save_cr_end: real32_call_asm: STREG %rp, -RP_OFFSET(%sp) /* save RP */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT callee_save ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */ STREG %r27, -1*REG_SZ(%sp) @@ -77,7 +79,7 @@ real32_call_asm: b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ nop -#ifdef __LP64__ +#ifdef CONFIG_64BIT rsm PSW_SM_W, %r0 /* go narrow */ #endif @@ -85,7 +87,7 @@ real32_call_asm: bv 0(%r31) nop ric_ret: -#ifdef __LP64__ +#ifdef CONFIG_64BIT ssm PSW_SM_W, %r0 /* go wide */ #endif /* restore CRs before going virtual in case we page fault */ @@ -97,7 +99,7 @@ ric_ret: tovirt_r1 %sp LDREG -REG_SZ(%sp), %sp /* restore SP */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT LDREG -1*REG_SZ(%sp), %r27 LDREG -2*REG_SZ(%sp), %r29 ldo -2*REG_SZ(%sp), %sp @@ -212,7 +214,7 @@ rfi_r2v_1: bv 0(%r2) nop -#ifdef __LP64__ +#ifdef CONFIG_64BIT /************************ 64-bit real-mode calls ***********************/ /* This is only usable in wide kernels right now and will probably stay so */ @@ -290,7 +292,7 @@ pc_in_user_space: ** comparing function pointers. */ __canonicalize_funcptr_for_compare: -#ifdef __LP64__ +#ifdef CONFIG_64BIT bve (%r2) #else bv %r0(%r2) diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index bcc7e83f5142..5db3be4e2704 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -18,7 +18,7 @@ */ #undef ENTRY_SYS_CPUS /* syscall support for iCOD-like functionality */ -#include +#include #include #include diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 8c7a7185cd3b..b29b76b42bb7 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -6,6 +6,7 @@ * thanks to Philipp Rumpf, Mike Shaver and various others * sorry about the wall, puffin.. */ +#include /* for CONFIG_SMP */ #include #include @@ -22,15 +23,13 @@ */ #define KILL_INSN break 0,0 -#include /* for CONFIG_SMP */ - -#ifdef __LP64__ +#ifdef CONFIG_64BIT .level 2.0w #else .level 1.1 #endif -#ifndef __LP64__ +#ifndef CONFIG_64BIT .macro fixup_branch,lbl b \lbl .endm @@ -103,7 +102,7 @@ linux_gateway_entry: mfsp %sr7,%r1 /* save user sr7 */ mtsp %r1,%sr3 /* and store it in sr3 */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* for now we can *always* set the W bit on entry to the syscall * since we don't support wide userland processes. We could * also save the current SM other than in r0 and restore it on @@ -155,7 +154,7 @@ linux_gateway_entry: STREG %r19, TASK_PT_GR19(%r1) LDREGM -FRAME_SIZE(%r30), %r2 /* get users sp back */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT extrd,u %r2,63,1,%r19 /* W hidden in bottom bit */ #if 0 xor %r19,%r2,%r2 /* clear bottom bit */ @@ -186,7 +185,7 @@ linux_gateway_entry: loadgp -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ copy %r19,%r2 /* W bit back to r2 */ #else @@ -205,7 +204,7 @@ linux_gateway_entry: /* Note! We cannot use the syscall table that is mapped nearby since the gateway page is mapped execute-only. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldil L%sys_call_table, %r1 or,= %r2,%r2,%r2 addil L%(sys_call_table64-sys_call_table), %r1 @@ -321,7 +320,7 @@ tracesys_next: LDREG TASK_PT_GR25(%r1), %r25 LDREG TASK_PT_GR24(%r1), %r24 LDREG TASK_PT_GR23(%r1), %r23 -#ifdef __LP64__ +#ifdef CONFIG_64BIT LDREG TASK_PT_GR22(%r1), %r22 LDREG TASK_PT_GR21(%r1), %r21 ldo -16(%r30),%r29 /* Reference param save area */ @@ -350,7 +349,7 @@ tracesys_next: tracesys_exit: ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */ LDREG TI_TASK(%r1), %r1 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif bl syscall_trace, %r2 @@ -371,7 +370,7 @@ tracesys_exit: tracesys_sigexit: ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */ LDREG 0(%r1), %r1 -#ifdef __LP64__ +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif bl syscall_trace, %r2 @@ -404,7 +403,7 @@ lws_start: gate .+8, %r0 depi 3, 31, 2, %r31 /* Ensure we return to userspace */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* FIXME: If we are a 64-bit kernel just * turn this on unconditionally. */ @@ -440,7 +439,7 @@ lws_exit_nosys: /* Fall through: Return to userspace */ lws_exit: -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* decide whether to reset the wide mode bit * * For a syscall, the W bit is stored in the lowest bit @@ -486,7 +485,7 @@ lws_exit: /* ELF64 Process entry path */ lws_compare_and_swap64: -#ifdef __LP64__ +#ifdef CONFIG_64BIT b,n lws_compare_and_swap #else /* If we are not a 64-bit kernel, then we don't @@ -497,7 +496,7 @@ lws_compare_and_swap64: /* ELF32 Process entry path */ lws_compare_and_swap32: -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Clip all the input registers */ depdi 0, 31, 32, %r26 depdi 0, 31, 32, %r25 @@ -608,7 +607,7 @@ cas_action: the other for the store. Either return -EFAULT. Each of the entries must be relocated. */ .section __ex_table,"aw" -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Pad the address calculation */ .word 0,(2b - linux_gateway_page) .word 0,(3b - linux_gateway_page) @@ -619,7 +618,7 @@ cas_action: .previous .section __ex_table,"aw" -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* Pad the address calculation */ .word 0,(1b - linux_gateway_page) .word 0,(3b - linux_gateway_page) @@ -638,7 +637,7 @@ end_linux_gateway_page: /* Relocate symbols assuming linux_gateway_page is mapped to virtual address 0x0 */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* FIXME: The code will always be on the gateay page and thus it will be on the first 4k, the assembler seems to think that the final @@ -666,7 +665,7 @@ lws_table: sys_call_table: #include "syscall_table.S" -#ifdef __LP64__ +#ifdef CONFIG_64BIT .align 4096 .export sys_call_table64 .Lsys_call_table64: diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 065ab809659d..32cbc0489324 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -35,7 +35,7 @@ #undef ENTRY_UHOH #undef ENTRY_COMP #undef ENTRY_OURS -#if defined(__LP64__) && !defined(SYSCALL_TABLE_64BIT) +#if defined(CONFIG_64BIT) && !defined(SYSCALL_TABLE_64BIT) /* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and * narrow palinux. Use ENTRY_DIFF for those where a 32-bit specific * implementation is required on wide palinux. Use ENTRY_COMP where @@ -46,7 +46,7 @@ #define ENTRY_UHOH(_name_) .dword sys32_##unimplemented #define ENTRY_OURS(_name_) .dword parisc_##_name_ #define ENTRY_COMP(_name_) .dword compat_sys_##_name_ -#elif defined(__LP64__) && defined(SYSCALL_TABLE_64BIT) +#elif defined(CONFIG_64BIT) && defined(SYSCALL_TABLE_64BIT) #define ENTRY_SAME(_name_) .dword sys_##_name_ #define ENTRY_DIFF(_name_) .dword sys_##_name_ #define ENTRY_UHOH(_name_) .dword sys_##_name_ From 3aa0862ce7c120e035bc2aa25997fd000d964d6e Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:47:04 -0400 Subject: [PATCH 0594/1939] [PARISC] Minor iosapic.c cleanup minor cleanup: qualify constant with "UL" Acked-by: "Hmamouche, Youssef" Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- drivers/parisc/iosapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 7a57c1b8373f..a39fbfef789a 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -244,7 +244,7 @@ static struct irt_entry *iosapic_alloc_irt(int num_entries) * 4-byte alignment on 32-bit kernels */ a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL); - a = (a + 7) & ~7; + a = (a + 7UL) & ~7UL; return (struct irt_entry *)a; } From 91313d60d8ad96fa79a833e55e8c13b56f893614 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:47:40 -0400 Subject: [PATCH 0595/1939] [PARISC] Add sync required after fdc to enforce insn ordering PA20 arch book (page 7-52 and 7-55) indicate a "sync" is required after the FDC "to enforce instruction ordering". And we want to make sure FIC is executed after FDC has retired. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/signal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 0224651fd8f1..6c905c128c2a 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -636,6 +636,7 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) /* Stack is 64-byte aligned, and we only * need to flush 1 cache line */ asm("fdc 0(%%sr3, %0)\n" + "sync\n" "fic 0(%%sr3, %0)\n" "sync\n" : : "r"(regs->gr[30])); From 7efe1611b2db9025ffc52a686897ab91820caeb4 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Oct 2005 22:48:03 -0400 Subject: [PATCH 0596/1939] [PARISC] Initialize serial spinlocks in superio.c git commit 976ecd12b8144d066a23fe97c6fbfc1ac8470af7 changed our locking characteristics, and put the onus of spin_lock_init on superio.c. Signed-off-by: Kyle McMartin --- drivers/parisc/superio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index e0efed796b92..bab3bcabcb6e 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -11,6 +11,7 @@ * (C) Copyright 2000 Alex deVries * (C) Copyright 2001 John Marvin * (C) Copyright 2003 Grant Grundler + * (C) Copyright 2005 Kyle McMartin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -405,6 +406,7 @@ static void __devinit superio_serial_init(void) serial[0].iobase = sio_dev.sp1_base; serial[0].irq = SP1_IRQ; + spin_lock_init(&serial[0].lock); retval = early_serial_setup(&serial[0]); if (retval < 0) { @@ -414,6 +416,7 @@ static void __devinit superio_serial_init(void) serial[1].iobase = sio_dev.sp2_base; serial[1].irq = SP2_IRQ; + spin_lock_init(&serial[1].lock); retval = early_serial_setup(&serial[1]); if (retval < 0) From fa681a1800a58234afe4d876c1752c0751826d22 Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:48:34 -0400 Subject: [PATCH 0597/1939] [PARISC] Disable use of fpregs in pa_memcpy Disable use of fpregs in pa_memcpy, and turn on the -mdisable-fpregs flag. Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- arch/parisc/Makefile | 2 +- arch/parisc/lib/memcpy.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 3b339b1cce13..e3549f480fa5 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -43,7 +43,7 @@ cflags-y += -mno-space-regs -mfast-indirect-calls # Currently we save and restore fpregs on all kernel entry/interruption paths. # If that gets optimized, we might need to disable the use of fpregs in the # kernel. -#cflags-y += -mdisable-fpregs +cflags-y += -mdisable-fpregs # Without this, "ld -r" results in .text sections that are too big # (> 0x40000) for branches to reach stubs. diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c index feb1b9f42c2b..b7098035321f 100644 --- a/arch/parisc/lib/memcpy.c +++ b/arch/parisc/lib/memcpy.c @@ -339,6 +339,7 @@ unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) pds = (double *)pcs; pdd = (double *)pcd; +#if 0 /* Copy 8 doubles at a time */ while (len >= 8*sizeof(double)) { register double r1, r2, r3, r4, r5, r6, r7, r8; @@ -366,6 +367,7 @@ unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) fstdma(d_space, r8, pdd, pmc_store_exc); len -= 8*sizeof(double); } +#endif pws = (unsigned int *)pds; pwd = (unsigned int *)pdd; From 74d13f84a9905e02a025d952ced6abb2e064f1c1 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:49:05 -0400 Subject: [PATCH 0598/1939] [PARISC] Fix compile warning in pci.h Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index d0b761f690b5..fa39d07d49e9 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -69,7 +69,7 @@ struct pci_hba_data { #define PCI_PORT_HBA(a) ((a) >> HBA_PORT_SPACE_BITS) #define PCI_PORT_ADDR(a) ((a) & (HBA_PORT_SPACE_SIZE - 1)) -#if CONFIG_64BIT +#ifdef CONFIG_64BIT #define PCI_F_EXTEND 0xffffffff00000000UL #define PCI_IS_LMMIO(hba,a) pci_is_lmmio(hba,a) From eba917273eb8579dd8ae36f6645518ca5579a2ab Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Fri, 21 Oct 2005 22:49:25 -0400 Subject: [PATCH 0599/1939] [PARISC] Add printing of fpregs state to stack dump We're using fp regs now in the kernel, so we want to print them on stack dump Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- arch/parisc/kernel/traps.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index d2e5b229a2f4..15914f0235a0 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -74,7 +74,10 @@ void show_regs(struct pt_regs *regs) char *level; unsigned long cr30; unsigned long cr31; - + /* carlos says that gcc understands better memory in a struct, + * and it makes our life easier with fpregs -- T-Bone */ + struct { u32 sw[2]; } s; + level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT; printk("%s\n", level); /* don't want to have that pretty register dump messed up */ @@ -103,11 +106,33 @@ void show_regs(struct pt_regs *regs) printk("%s\n", buf); } -#if RIDICULOUSLY_VERBOSE - for (i = 0; i < 32; i += 2) - printk("%sFR%02d : %016lx FR%2d : %016lx", level, i, - regs->fr[i], i+1, regs->fr[i+1]); -#endif + /* FR are 64bit everywhere. Need to use asm to get the content + * of fpsr/fper1, and we assume that we won't have a FP Identify + * in our way, otherwise we're screwed. + * The fldd is used to restore the T-bit if there was one, as the + * store clears it anyway. + * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ + __asm__ ( + "fstd %%fr0,0(%1) \n\t" + "fldd 0(%1),%%fr0 \n\t" + : "=m" (s) : "r" (&s) : "%r0" + ); + + printk("%s\n", level); + printk("%s VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level); + printbinary(buf, s.sw[0], 32); + printk("%sFPSR: %s\n", level, buf); + printk("%sFPER1: %08x\n", level, s.sw[1]); + + /* here we'll print fr0 again, tho it'll be meaningless */ + for (i = 0; i < 32; i += 4) { + int j; + p = buf; + p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3); + for (j = 0; j < 4; j++) + p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]); + printk("%s\n", buf); + } cr30 = mfctl(30); cr31 = mfctl(31); From 40c72f20e89300dfaea28300ee17aa56d230d63f Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:49:47 -0400 Subject: [PATCH 0600/1939] [PARISC] Prevent signal loops if we have a problem setting up a frame 2.6.13-rc6-pa2 use force_sigsegv() if we have a problem setting up a frame. This is required to prevent SIGSEGV loops. Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- arch/parisc/kernel/signal.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 6c905c128c2a..befdfe700616 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -490,15 +490,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, give_sigsegv: DBG(1,"setup_rt_frame: sending SIGSEGV\n"); - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = SI_KERNEL; - si.si_pid = current->pid; - si.si_uid = current->uid; - si.si_addr = frame; - force_sig_info(SIGSEGV, &si, current); + force_sigsegv(sig, current); return 0; } From 7c92e972da0dd5b6a9ddf01030aab7dec9912b1f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:50:06 -0400 Subject: [PATCH 0601/1939] [PARISC] Update pdc console from parisc tree Get rid of some unnecessary includes Remove a layer of macro indirection around pdc_console_device Delete pdc_console_die() as it is unused Avoid double-printing on panic by clearing CON_PRINTBUFFER rather than setting con_start to be log_end Make con_start and log_end static again Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pdc_cons.c | 46 ++++++++--------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index 01f676d1673b..215d78c87bc5 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -41,7 +41,7 @@ /* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */ -#undef EARLY_BOOTUP_DEBUG +#define EARLY_BOOTUP_DEBUG #include @@ -49,14 +49,8 @@ #include #include #include -#include -#include -#include #include #include -#include -#include -#include #include /* for iodc_call() proto and friends */ @@ -96,7 +90,6 @@ static int pdc_console_setup(struct console *co, char *options) } #if defined(CONFIG_PDC_CONSOLE) -#define PDC_CONSOLE_DEVICE pdc_console_device static struct tty_driver * pdc_console_device (struct console *c, int *index) { extern struct tty_driver console_driver; @@ -104,22 +97,19 @@ static struct tty_driver * pdc_console_device (struct console *c, int *index) return &console_driver; } #else -#define PDC_CONSOLE_DEVICE NULL +#define pdc_console_device NULL #endif static struct console pdc_cons = { .name = "ttyB", .write = pdc_console_write, - .device = PDC_CONSOLE_DEVICE, + .device = pdc_console_device, .setup = pdc_console_setup, - .flags = CON_BOOT|CON_PRINTBUFFER|CON_ENABLED, + .flags = CON_BOOT | CON_PRINTBUFFER | CON_ENABLED, .index = -1, }; static int pdc_console_initialized; -extern unsigned long con_start; /* kernel/printk.c */ -extern unsigned long log_end; /* kernel/printk.c */ - static void pdc_console_init_force(void) { @@ -146,27 +136,11 @@ void __init pdc_console_init(void) } -/* Unregister the pdc console with the printk console layer */ -void pdc_console_die(void) -{ - if (!pdc_console_initialized) - return; - --pdc_console_initialized; - - printk(KERN_INFO "Switching from PDC console\n"); - - /* Don't repeat what we've already printed */ - con_start = log_end; - - unregister_console(&pdc_cons); -} - - /* * Used for emergencies. Currently only used if an HPMC occurs. If an * HPMC occurs, it is possible that the current console may not be - * properly initialed after the PDC IO reset. This routine unregisters all - * of the current consoles, reinitializes the pdc console and + * properly initialised after the PDC IO reset. This routine unregisters + * all of the current consoles, reinitializes the pdc console and * registers it. */ @@ -177,13 +151,13 @@ void pdc_console_restart(void) if (pdc_console_initialized) return; + /* If we've already seen the output, don't bother to print it again */ + if (console_drivers != NULL) + pdc_cons.flags &= ~CON_PRINTBUFFER; + while ((console = console_drivers) != NULL) unregister_console(console_drivers); - /* Don't repeat what we've already printed */ - con_start = log_end; - /* force registering the pdc console */ pdc_console_init_force(); } - From 8054f03f6330f20e9d47e2f6c7b1d01ddf5adeef Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:50:33 -0400 Subject: [PATCH 0602/1939] [PARISC] More informative error message in pcibios_link_hba_resources Generate a more informative message when a resource does not have a parent. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index e6a891a0cad0..88cba49c5301 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -202,7 +202,8 @@ static void pcibios_link_hba_resources( struct resource *hba_res, struct resource *r) { if (!r->parent) { - printk(KERN_EMERG "PCI: Tell willy he's wrong\n"); + printk(KERN_EMERG "PCI: resource not parented! [%lx-%lx]\n", + r->start, r->end); r->parent = hba_res; /* reverse link is harder *sigh* */ From b8db800295fd31f8beb39fd1de63660aa7aef47b Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:50:48 -0400 Subject: [PATCH 0603/1939] [PARISC] Cleanup whitespace and handle proc_mkdir() failures in pci-dma.c 1) cleanup whitespace and handle proc_mkdir() failures. From: Christophe Lucas 2) rename "dino" entry to "pcxl_dma"...also seems like it's in the wrong location. 3) don't dump resource bitmap in /proc/pcxl_dma output 4) fixup compiler warning Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pci-dma.c | 48 ++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 368cc095c99f..d9b447cb1a0d 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -31,7 +31,7 @@ #include /* get_order */ #include #include - +#include /* for purge_tlb_*() macros */ static struct proc_dir_entry * proc_gsc_root = NULL; static int pcxl_proc_info(char *buffer, char **start, off_t offset, int length); @@ -333,18 +333,28 @@ pcxl_free_range(unsigned long vaddr, size_t size) static int __init pcxl_dma_init(void) { - if (pcxl_dma_start == 0) - return 0; + if (pcxl_dma_start == 0) + return 0; - spin_lock_init(&pcxl_res_lock); - pcxl_res_size = PCXL_DMA_MAP_SIZE >> (PAGE_SHIFT + 3); - pcxl_res_hint = 0; - pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL, + spin_lock_init(&pcxl_res_lock); + pcxl_res_size = PCXL_DMA_MAP_SIZE >> (PAGE_SHIFT + 3); + pcxl_res_hint = 0; + pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL, get_order(pcxl_res_size)); - memset(pcxl_res_map, 0, pcxl_res_size); - proc_gsc_root = proc_mkdir("gsc", 0); - create_proc_info_entry("dino", 0, proc_gsc_root, pcxl_proc_info); - return 0; + memset(pcxl_res_map, 0, pcxl_res_size); + proc_gsc_root = proc_mkdir("gsc", 0); + if (!proc_gsc_root) + printk(KERN_WARNING + "pcxl_dma_init: Unable to create gsc /proc dir entry\n"); + else { + struct proc_dir_entry* ent; + ent = create_proc_info_entry("pcxl_dma", 0, + proc_gsc_root, pcxl_proc_info); + if (!ent) + printk(KERN_WARNING + "pci-dma.c: Unable to create pcxl_dma /proc entry.\n"); + } + return 0; } __initcall(pcxl_dma_init); @@ -545,16 +555,16 @@ struct hppa_dma_ops pcx_dma_ops = { static int pcxl_proc_info(char *buf, char **start, off_t offset, int len) { +#if 0 u_long i = 0; unsigned long *res_ptr = (u_long *)pcxl_res_map; - unsigned long total_pages = pcxl_res_size << 3; /* 8 bits per byte */ +#endif + unsigned long total_pages = pcxl_res_size << 3; /* 8 bits per byte */ - sprintf(buf, "\nDMA Mapping Area size : %d bytes (%d pages)\n", - PCXL_DMA_MAP_SIZE, - (pcxl_res_size << 3) ); /* 1 bit per page */ + sprintf(buf, "\nDMA Mapping Area size : %d bytes (%ld pages)\n", + PCXL_DMA_MAP_SIZE, total_pages); - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, pcxl_res_size, pcxl_res_size << 3); /* 8 bits per byte */ + sprintf(buf, "%sResource bitmap : %d bytes\n", buf, pcxl_res_size); strcat(buf, " total: free: used: % used:\n"); sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, pcxl_res_size, @@ -564,7 +574,8 @@ static int pcxl_proc_info(char *buf, char **start, off_t offset, int len) sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, total_pages - pcxl_used_pages, pcxl_used_pages, (pcxl_used_pages * 100 / total_pages)); - + +#if 0 strcat(buf, "\nResource bitmap:"); for(; i < (pcxl_res_size / sizeof(u_long)); ++i, ++res_ptr) { @@ -572,6 +583,7 @@ static int pcxl_proc_info(char *buf, char **start, off_t offset, int len) strcat(buf,"\n "); sprintf(buf, "%s %08lx", buf, *res_ptr); } +#endif strcat(buf, "\n"); return strlen(buf); } From c8e8b1937a788ec46ee11d84437311d4cb8be218 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 21 Oct 2005 22:51:23 -0400 Subject: [PATCH 0604/1939] [PARISC] kfree cleanups to ioctl32.c 2.6.12-rc2-pa2 kfree cleanups from Jesper Juhl Signed-off-by: Jesper Juhl Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/ioctl32.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/arch/parisc/kernel/ioctl32.c b/arch/parisc/kernel/ioctl32.c index 1d3824b670d1..8cad8f004f00 100644 --- a/arch/parisc/kernel/ioctl32.c +++ b/arch/parisc/kernel/ioctl32.c @@ -104,12 +104,9 @@ static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg) } out: - if (kversion.name) - kfree(kversion.name); - if (kversion.date) - kfree(kversion.date); - if (kversion.desc) - kfree(kversion.desc); + kfree(kversion.name); + kfree(kversion.date); + kfree(kversion.desc); return ret; } @@ -166,9 +163,7 @@ static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long a ret = -EFAULT; } - if (karg.unique != NULL) - kfree(karg.unique); - + kfree(karg.unique); return ret; } @@ -265,7 +260,6 @@ static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) } kfree(karg.list); - return ret; } @@ -305,7 +299,6 @@ static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) out: kfree(karg.list); - return ret; } @@ -494,15 +487,10 @@ static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg) } out: - if (karg.send_indices) - kfree(karg.send_indices); - if (karg.send_sizes) - kfree(karg.send_sizes); - if (karg.request_indices) - kfree(karg.request_indices); - if (karg.request_sizes) - kfree(karg.request_sizes); - + kfree(karg.send_indices); + kfree(karg.send_sizes); + kfree(karg.request_indices); + kfree(karg.request_sizes); return ret; } @@ -555,9 +543,7 @@ static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) ret = -EFAULT; } - if (karg.contexts) - kfree(karg.contexts); - + kfree(karg.contexts); return ret; } From 675ec7a56a77da2dda27180c95ee82ae4879142a Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:51:40 -0400 Subject: [PATCH 0605/1939] [PARISC] Document history of PDC_NARROW as it is now obsolete Document history of PDC_NARROW a bit as it will still show up in an older kernel's .config file. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/firmware.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index f244fb200db1..553f8fe03224 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -83,15 +83,15 @@ static unsigned long pdc_result2[32] __attribute__ ((aligned (8))); int parisc_narrow_firmware = 1; #endif -/* on all currently-supported platforms, IODC I/O calls are always - * 32-bit calls, and MEM_PDC calls are always the same width as the OS. - * This means Cxxx boxes can't run wide kernels right now. -PB +/* On most currently-supported platforms, IODC I/O calls are 32-bit calls + * and MEM_PDC calls are always the same width as the OS. + * Some PAT boxes may have 64-bit IODC I/O. * - * CONFIG_PDC_NARROW has been added to allow 64-bit kernels to run on - * systems with 32-bit MEM_PDC calls. This will allow wide kernels to - * run on Cxxx boxes now. -RB - * - * Note that some PAT boxes may have 64-bit IODC I/O... + * Ryan Bradetich added the now obsolete CONFIG_PDC_NARROW to allow + * 64-bit kernels to run on systems with 32-bit MEM_PDC calls. + * This allowed wide kernels to run on Cxxx boxes. + * We now detect 32-bit-only PDC and dynamically switch to 32-bit mode + * when running a 64-bit kernel on such boxes (e.g. C200 or C360). */ #ifdef __LP64__ From 5beb5f32c56b70f79117e13a1abd54824a78466c Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:52:00 -0400 Subject: [PATCH 0606/1939] [PARISC] Update minimum compiler version and CROSS_COMPILE for parisc64 Prefix changed in debian, include "gnu" in the commandline. Signed-off-by: Carlos O'Donell Ensure the compiler version is new enough (>= 3.3) Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- arch/parisc/Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index e3549f480fa5..9b7e42490dd1 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -20,7 +20,8 @@ NM = sh $(srctree)/arch/parisc/nm CHECKFLAGS += -D__hppa__=1 ifdef CONFIG_64BIT -CROSS_COMPILE := hppa64-linux- +CROSS_COMPILE := $(shell if [ -x /usr/bin/hppa64-linux-gnu-gcc ]; then \ + echo hppa64-linux-gnu-; else echo hppa64-linux-; fi) UTS_MACHINE := parisc64 CHECKFLAGS += -D__LP64__=1 -m64 else @@ -34,6 +35,14 @@ FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align OBJCOPY_FLAGS =-O binary -R .note -R .comment -S +GCC_VERSION := $(call cc-version) +ifneq ($(shell if [ -z $(GCC_VERSION) ] ; then echo "bad"; fi ;),) +$(error Sorry, couldn't find ($(cc-version)).) +endif +ifneq ($(shell if [ $(GCC_VERSION) -lt 0303 ] ; then echo "bad"; fi ;),) +$(error Sorry, your compiler is too old ($(GCC_VERSION)). GCC v3.3 or above is required.) +endif + cflags-y := -pipe # These flags should be implied by an hppa-linux configuration, but they From 8b631342dd9db9ca272e11814e041e4ee3d1a948 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:52:46 -0400 Subject: [PATCH 0607/1939] [PARISC] Update Kconfig for itimer selection 2.6.14-rc2-pa1: enable 100/250/1000HZ itimer selection Signed-off-by: Grant Grundler Mark floppy as broken. Thanks Joel Signed-off-by: Matthew Wilcox make DISCONTIGMEM depend on 64BIT Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- arch/parisc/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 0b07922a2ac6..874a283edb95 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -47,10 +47,10 @@ config PM config ISA_DMA_API bool - default y config ARCH_MAY_HAVE_PC_FDC bool + depends on BROKEN default y source "init/Kconfig" @@ -154,13 +154,14 @@ config HOTPLUG_CPU config ARCH_DISCONTIGMEM_ENABLE bool "Discontiguous memory support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on 64BIT && EXPERIMENTAL help Say Y to support efficient handling of discontiguous physical memory, for architectures which are either NUMA (Non-Uniform Memory Access) or have huge holes in the physical address space for other reasons. See for more. +source "kernel/Kconfig.hz" source "mm/Kconfig" config PREEMPT From b2450cc1b7ce07d73545ece32db50197d649e230 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Fri, 21 Oct 2005 22:53:04 -0400 Subject: [PATCH 0608/1939] [PARISC] Implement 5 argument clone. * arch/parisc/kernel/process.c (sys_clone): Use 5 args, and process CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID. (copy_thread): First cut at CLONE_SETTLS. Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin --- arch/parisc/kernel/process.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 46b759385115..7fdca87ef647 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -9,7 +9,7 @@ * Copyright (C) 2000-2003 Paul Bame * Copyright (C) 2000 Philipp Rumpf * Copyright (C) 2000 David Kennedy - * Copyright (C) 2000 Richard Hirst + * Copyright (C) 2000 Richard Hirst * Copyright (C) 2000 Grant Grundler * Copyright (C) 2001 Alan Modra * Copyright (C) 2001-2002 Ryan Bradetich @@ -245,7 +245,17 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { - int __user *user_tid = (int __user *)regs->gr[26]; + /* Arugments from userspace are: + r26 = Clone flags. + r25 = Child stack. + r24 = parent_tidptr. + r23 = Is the TLS storage descriptor + r22 = child_tidptr + + However, these last 3 args are only examined + if the proper flags are set. */ + int __user *child_tidptr; + int __user *parent_tidptr; /* usp must be word aligned. This also prevents users from * passing in the value 1 (which is the signal for a special @@ -253,10 +263,20 @@ sys_clone(unsigned long clone_flags, unsigned long usp, usp = ALIGN(usp, 4); /* A zero value for usp means use the current stack */ - if(usp == 0) - usp = regs->gr[30]; + if (usp == 0) + usp = regs->gr[30]; - return do_fork(clone_flags, usp, regs, 0, user_tid, NULL); + if (clone_flags & CLONE_PARENT_SETTID) + parent_tidptr = (int __user *)regs->gr[24]; + else + parent_tidptr = NULL; + + if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) + child_tidptr = (int __user *)regs->gr[22]; + else + child_tidptr = NULL; + + return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr); } int @@ -332,6 +352,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, } else { cregs->kpc = (unsigned long) &child_return; } + /* Setup thread TLS area from the 4th parameter in clone */ + if (clone_flags & CLONE_SETTLS) + cregs->cr27 = pregs->gr[23]; + } return 0; From 618febd6784054eea928d712b7e564558a7cefd5 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 21 Oct 2005 22:53:26 -0400 Subject: [PATCH 0609/1939] [PARISC] Fix the alloc_slabmgmt panic Fix the alloc_slabmgmt panic Hopefully this should also fix a lot of other intermittent kernel bugs. The problem has been around since 2.6.9-rc2-pa6 when we allowed floating point registers to be used in kernel code. The essence of the problem is that gcc prefers to use floating point for integer divides and multiples. Further, it can rely on the values in the no clobber fp regs being correct across a function call. Unfortunately, our task switch function only saves the integer no clobber registers, not the fp ones, so if gcc makes a function call to any function in the kernel which could sleep, the values it is relying on in any no clobber floating point register may be lost. In the case of alloc_slabmgmt, the value of the page offset is being stored in %fr12 across a call to kmem_getpages(), which sleeps if no pages are available. Thus, the offset can be trashed and the slab code can end up with a completely bogus address leading to corruption. Kudos to Randolph who came up with the program to trip this problem at will and thus allowed it to be tracked and fixed. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 2 ++ include/asm-parisc/assembly.h | 40 +++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 0ca49710d95e..166df5bab769 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -863,6 +863,7 @@ __execve: _switch_to: STREG %r2, -RP_OFFSET(%r30) + callee_save_float callee_save load32 _switch_to_ret, %r2 @@ -879,6 +880,7 @@ _switch_to: _switch_to_ret: mtctl %r0, %cr0 /* Needed for single stepping */ callee_rest + callee_rest_float LDREG -RP_OFFSET(%r30), %r2 bv %r0(%r2) diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index b24a99e3ef9c..fb8bc7c16e0e 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -21,6 +21,7 @@ #ifndef _PARISC_ASSEMBLY_H #define _PARISC_ASSEMBLY_H +#define CALLEE_FLOAT_FRAME_SIZE 80 #ifdef __LP64__ #define LDREG ldd #define STREG std @@ -30,7 +31,7 @@ #define SHRREG shrd #define RP_OFFSET 16 #define FRAME_SIZE 128 -#define CALLEE_SAVE_FRAME_SIZE 144 +#define CALLEE_REG_FRAME_SIZE 144 #else #define LDREG ldw #define STREG stw @@ -40,8 +41,9 @@ #define SHRREG shr #define RP_OFFSET 20 #define FRAME_SIZE 64 -#define CALLEE_SAVE_FRAME_SIZE 128 +#define CALLEE_REG_FRAME_SIZE 128 #endif +#define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE) #ifdef CONFIG_PA20 #define BL b,l @@ -300,9 +302,35 @@ fldd,mb -8(\regs), %fr0 .endm + .macro callee_save_float + fstd,ma %fr12, 8(%r30) + fstd,ma %fr13, 8(%r30) + fstd,ma %fr14, 8(%r30) + fstd,ma %fr15, 8(%r30) + fstd,ma %fr16, 8(%r30) + fstd,ma %fr17, 8(%r30) + fstd,ma %fr18, 8(%r30) + fstd,ma %fr19, 8(%r30) + fstd,ma %fr20, 8(%r30) + fstd,ma %fr21, 8(%r30) + .endm + + .macro callee_rest_float + fldd,mb -8(%r30), %fr21 + fldd,mb -8(%r30), %fr20 + fldd,mb -8(%r30), %fr19 + fldd,mb -8(%r30), %fr18 + fldd,mb -8(%r30), %fr17 + fldd,mb -8(%r30), %fr16 + fldd,mb -8(%r30), %fr15 + fldd,mb -8(%r30), %fr14 + fldd,mb -8(%r30), %fr13 + fldd,mb -8(%r30), %fr12 + .endm + #ifdef __LP64__ .macro callee_save - std,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30) + std,ma %r3, CALLEE_REG_FRAME_SIZE(%r30) mfctl %cr27, %r3 std %r4, -136(%r30) std %r5, -128(%r30) @@ -340,13 +368,13 @@ ldd -128(%r30), %r5 ldd -136(%r30), %r4 mtctl %r3, %cr27 - ldd,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3 + ldd,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3 .endm #else /* ! __LP64__ */ .macro callee_save - stw,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30) + stw,ma %r3, CALLEE_REG_FRAME_SIZE(%r30) mfctl %cr27, %r3 stw %r4, -124(%r30) stw %r5, -120(%r30) @@ -384,7 +412,7 @@ ldw -120(%r30), %r5 ldw -124(%r30), %r4 mtctl %r3, %cr27 - ldw,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3 + ldw,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3 .endm #endif /* ! __LP64__ */ From 05aa10de701409b893484d2901c8974b3382f8fe Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:53:43 -0400 Subject: [PATCH 0610/1939] [PARISC] Add ECANCELED to errno.h add ECANCELED - SuSv3 wants one L. IB/SDP actually returns this error. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- include/asm-parisc/errno.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-parisc/errno.h b/include/asm-parisc/errno.h index 08464c405471..e2f3ddc796be 100644 --- a/include/asm-parisc/errno.h +++ b/include/asm-parisc/errno.h @@ -114,6 +114,7 @@ #define ENOTSUP 252 /* Function not implemented (POSIX.4 / HPUX) */ #define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */ +#define ECANCELED ECANCELLED /* SuSv3 and Solaris wants one 'L' */ /* for robust mutexes */ #define EOWNERDEAD 254 /* Owner died */ From b4b45313e58bf25886072a4ab111fac553747802 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Oct 2005 22:54:00 -0400 Subject: [PATCH 0611/1939] [PARISC] Add other CRT_ID for newer cards to grfioctl.h Add IDs for some other STI graphics cards found on HP PA-RISC machines. Signed-off-by: Kyle McMartin --- include/asm-parisc/grfioctl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-parisc/grfioctl.h b/include/asm-parisc/grfioctl.h index d3cfc0168fb1..6a910311b56b 100644 --- a/include/asm-parisc/grfioctl.h +++ b/include/asm-parisc/grfioctl.h @@ -69,6 +69,8 @@ #define CRT_ID_TVRX S9000_ID_98765 /* TVRX (gto/falcon) */ #define CRT_ID_ARTIST S9000_ID_ARTIST /* Artist */ #define CRT_ID_SUMMIT 0x2FC1066B /* Summit FX2, FX4, FX6 ... */ +#define CRT_ID_LEGO 0x35ACDA30 /* Lego FX5, FX10 ... */ +#define CRT_ID_PINNACLE 0x35ACDA16 /* Pinnacle FXe */ /* structure for ioctl(GCDESCRIBE) */ From 63af965d2bc8d8c5d4c5949b8d3dbdc3c7b7d97a Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:54:20 -0400 Subject: [PATCH 0612/1939] [PARISC] Define pgprot_noncached macro in pgtable.h drivers/infiniband depends on definition of pgprot_noncached() macro. Someone else will have to fix it's wrong. Signed-off-by: Grant Grundler --- include/asm-parisc/pgtable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h index 820c6e712cd7..c28fb6f48c6c 100644 --- a/include/asm-parisc/pgtable.h +++ b/include/asm-parisc/pgtable.h @@ -501,6 +501,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) +#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE) + #define MK_IOSPACE_PFN(space, pfn) (pfn) #define GET_IOSPACE(pfn) 0 #define GET_PFN(pfn) (pfn) From dd0fd51dc1585941c2edccdb40e5f11ea3a64496 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 21 Oct 2005 22:54:38 -0400 Subject: [PATCH 0613/1939] [PARISC] Remove the spurious do_softirq calls from entry.S remove the spurious do_softirq calls from entry.S With these in we were calling do_softirq twice; plus the calls in entry.S took no account of nesting. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 166df5bab769..c7e66ee5b083 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -970,9 +970,6 @@ intr_return: add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ - LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */ - cmpib,<>,n 0,%r20,intr_do_softirq /* forward */ - intr_check_resched: /* check for reschedule */ @@ -1017,17 +1014,6 @@ intr_restore: nop nop - .import do_softirq,code -intr_do_softirq: - BL do_softirq,%r2 -#ifdef CONFIG_64BIT - ldo -16(%r30),%r29 /* Reference param save area */ -#else - nop -#endif - b intr_check_resched - nop - .import schedule,code intr_do_resched: /* Only do reschedule if we are returning to user space */ @@ -2096,9 +2082,6 @@ syscall_check_bh: add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ - LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */ - cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */ - syscall_check_resched: /* check for reschedule */ @@ -2236,16 +2219,6 @@ pt_regs_ok: b intr_restore nop - .import do_softirq,code -syscall_do_softirq: - BL do_softirq,%r2 - nop - /* NOTE: We enable I-bit incase we schedule later, - * and we might be going back to userspace if we were - * traced. */ - b syscall_check_resched - ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */ - .import schedule,code syscall_do_resched: BL schedule,%r2 From c2709020adb442f7d25f0805af08a3b6cfedd7be Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Fri, 21 Oct 2005 22:55:15 -0400 Subject: [PATCH 0614/1939] [PARISC] Add NETPOLL support to lasi_82596 add netpoll support Patch by Sven Schnelle Signed-off-by: Sven Schnelle Signed-off-by: Helge Deller Signed-off-by: Kyle McMartin --- drivers/net/lasi_82596.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index a63d8a317d9e..f7b7238d8352 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -415,6 +415,10 @@ static int rx_ring_size = RX_RING_SIZE; static int ticks_limit = 100; static int max_cmd_backlog = TX_RING_SIZE-1; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void i596_poll_controller(struct net_device *dev); +#endif + static inline void CA(struct net_device *dev) { @@ -636,11 +640,11 @@ static int init_i596_mem(struct net_device *dev) disable_irq(dev->irq); /* disable IRQs from LAN */ DEB(DEB_INIT, - printk("RESET 82596 port: %p (with IRQ %d disabled)\n", - (void*)(dev->base_addr + PA_I82596_RESET), + printk("RESET 82596 port: %lx (with IRQ %d disabled)\n", + (dev->base_addr + PA_I82596_RESET), dev->irq)); - gsc_writel(0, (void*)(dev->base_addr + PA_I82596_RESET)); /* Hard Reset */ + gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */ udelay(100); /* Wait 100us - seems to help */ /* change the scp address */ @@ -1209,6 +1213,9 @@ static int __devinit i82596_probe(struct net_device *dev, dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = i596_poll_controller; +#endif dev->priv = (void *)(dev->mem_start); @@ -1242,6 +1249,14 @@ static int __devinit i82596_probe(struct net_device *dev, return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void i596_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + i596_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) { From 37318a3cb1028933417533084ddbf9d84be06878 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:55:34 -0400 Subject: [PATCH 0615/1939] [PARISC] Fix copy_user_page_asm to NOT access past end of page 2.6.12-rc2-pa3 fix copy_user_page_asm to NOT access past end of page. My bad. /o\ Lamont confirmed that instructions following a conditional branch are *alway* executed regardless if the branch is taken or not. Unless they are nullified (which was missing in this case). He also noted: Conditional branches nullify on forward taken branch, and on non-taken backward branch. Note that .+4 is a backwards branch. This makes alot more sense than the giberish in the PA20 arch book. Compiles and boots on both 64-bit (a500) and 32-bit (j6k). Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pacache.S | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 4a7d9c8903f4..e217ae369fbb 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -351,7 +351,11 @@ copy_user_page_asm: std %r22, 120(%r26) ldo 128(%r26), %r26 - ADDIB> -1, %r1, 1b /* bundle 10 */ + /* conditional branches nullify on forward taken branch, and on + * non-taken backward branch. Note that .+4 is a backwards branch. + * The ldd should only get executed if the branch is taken. + */ + ADDIB>,n -1, %r1, 1b /* bundle 10 */ ldd 0(%r25), %r19 /* start next loads */ #else @@ -363,10 +367,10 @@ copy_user_page_asm: * the full 64 bit register values on interrupt, we can't * use ldd/std on a 32 bit kernel. */ + ldw 0(%r25), %r19 ldi 64, %r1 /* PAGE_SIZE/64 == 64 */ 1: - ldw 0(%r25), %r19 ldw 4(%r25), %r20 ldw 8(%r25), %r21 ldw 12(%r25), %r22 @@ -396,11 +400,12 @@ copy_user_page_asm: ldw 60(%r25), %r22 stw %r19, 48(%r26) stw %r20, 52(%r26) + ldo 64(%r25), %r25 stw %r21, 56(%r26) stw %r22, 60(%r26) ldo 64(%r26), %r26 - ADDIB> -1, %r1, 1b - ldo 64(%r25), %r25 + ADDIB>,n -1, %r1, 1b + ldw 0(%r25), %r19 #endif bv %r0(%r2) nop From 9b3b331d0322b60de1bde20528bf974f62804ffa Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:55:51 -0400 Subject: [PATCH 0616/1939] [PARISC] Properly specify index field to I/D cache flush ops replace use of "0" with "%r0" since PA 1.1 I/D flush ops only take a general register and not an immediate value for the index field. This just forces the code to always be PA 1.1 "clean". From: Joel Soete Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pacache.S | 4 ++-- arch/parisc/kernel/signal.c | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index e217ae369fbb..08cde5addfca 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -227,7 +227,7 @@ flush_instruction_cache_local: fimanyloop: /* Loop if LOOP >= 2 */ ADDIB> -1, %r31, fimanyloop /* Adjusted inner loop decr */ - fice 0(%sr1, %arg0) + fice %r0(%sr1, %arg0) fice,m %arg1(%sr1, %arg0) /* Last fice and addr adjust */ movb,tr %arg3, %r31, fimanyloop /* Re-init inner loop count */ ADDIB<=,n -1, %arg2, fisync /* Outer loop decr */ @@ -269,7 +269,7 @@ flush_data_cache_local: fdmanyloop: /* Loop if LOOP >= 2 */ ADDIB> -1, %r31, fdmanyloop /* Adjusted inner loop decr */ - fdce 0(%sr1, %arg0) + fdce %r0(%sr1, %arg0) fdce,m %arg1(%sr1, %arg0) /* Last fdce and addr adjust */ movb,tr %arg3, %r31, fdmanyloop /* Re-init inner loop count */ ADDIB<=,n -1, %arg2, fdsync /* Outer loop decr */ diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index befdfe700616..82c24e62ab63 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -625,11 +625,14 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) put_user(0xe0008200, &usp[3]); put_user(0x34140000, &usp[4]); - /* Stack is 64-byte aligned, and we only - * need to flush 1 cache line */ - asm("fdc 0(%%sr3, %0)\n" + /* Stack is 64-byte aligned, and we only need + * to flush 1 cache line. + * Flushing one cacheline is cheap. + * "sync" on bigger (> 4 way) boxes is not. + */ + asm("fdc %%r0(%%sr3, %0)\n" "sync\n" - "fic 0(%%sr3, %0)\n" + "fic %%r0(%%sr3, %0)\n" "sync\n" : : "r"(regs->gr[30])); From e635c96ed6c972e1b3cb0c0fc3681c1204697287 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:56:14 -0400 Subject: [PATCH 0617/1939] [PARISC] Explicitly specify sr4 when flushing kernel space Specify sr4 when flushing kernel space (we could equally well use sr5-7, but must not use sr0). Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pacache.S | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 08cde5addfca..9534ee17b9be 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -949,23 +949,23 @@ flush_kernel_icache_page: sub %r25, %r23, %r25 -1: fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) - fic,m %r23(%r26) +1: fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) + fic,m %r23(%sr4, %r26) CMPB<< %r26, %r25, 1b - fic,m %r23(%r26) + fic,m %r23(%sr4, %r26) sync bv %r0(%r2) @@ -987,7 +987,7 @@ flush_kernel_icache_range_asm: ANDCM %r26, %r21, %r26 1: CMPB<<,n %r26, %r25, 1b - fic,m %r23(%r26) + fic,m %r23(%sr4, %r26) sync bv %r0(%r2) From 61520e1f8f5ec3a78510a3254947324711944b98 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:56:35 -0400 Subject: [PATCH 0618/1939] [PARISC] Specify level to fix binutils level promotion bug fixup.S needs to specify .level and use correct LDREG macro. New binutils has a bug where it doesn't "promote" from PA1.0 to PA1.1 correctly when using ",s" completer. remove use of __LP64__ in assembly.h and add some white space. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/lib/fixup.S | 4 +++- include/asm-parisc/assembly.h | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/parisc/lib/fixup.S b/arch/parisc/lib/fixup.S index 1b91612ed964..e0661c2978ed 100644 --- a/arch/parisc/lib/fixup.S +++ b/arch/parisc/lib/fixup.S @@ -35,7 +35,7 @@ extrd,u \t2,63,32,\t2 #endif /* t2 = &__per_cpu_offset[smp_processor_id()]; */ - LDREG,s \t2(\t1),\t2 + LDREGX \t2(\t1),\t2 addil LT%per_cpu__exception_data,%r27 LDREG RT%per_cpu__exception_data(%r1),\t1 /* t1 = &__get_cpu_var(exception_data) */ @@ -53,6 +53,8 @@ .endm #endif + .level LEVEL + .text .section .fixup, "ax" diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index fb8bc7c16e0e..3ce3440d1b0c 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -22,7 +22,8 @@ #define _PARISC_ASSEMBLY_H #define CALLEE_FLOAT_FRAME_SIZE 80 -#ifdef __LP64__ + +#ifdef CONFIG_64BIT #define LDREG ldd #define STREG std #define LDREGX ldd,s @@ -32,7 +33,7 @@ #define RP_OFFSET 16 #define FRAME_SIZE 128 #define CALLEE_REG_FRAME_SIZE 144 -#else +#else /* CONFIG_64BIT */ #define LDREG ldw #define STREG stw #define LDREGX ldwx,s @@ -43,6 +44,7 @@ #define FRAME_SIZE 64 #define CALLEE_REG_FRAME_SIZE 128 #endif + #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE) #ifdef CONFIG_PA20 From e55fb3e787ccfbbdb3198ec859d5689e5413c7bd Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 21 Oct 2005 22:56:53 -0400 Subject: [PATCH 0619/1939] [PARISC] Properly specify section alignment for real2.S .align applies to the current section - ie section directives come first. Thanks to Joel Soete for catching this. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/real2.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 085bff7c569d..8c2859cca77e 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -145,8 +145,8 @@ restore_control_regs: /* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for * more general-purpose use by the several places which need RFIs */ - .align 128 .text + .align 128 rfi_virt2real: /* switch to real mode... */ rsm PSW_SM_I,%r0 From abff75439fd6e9b5774e5984d4c3b3b59cb3038b Mon Sep 17 00:00:00 2001 From: Randolph Chung Date: Fri, 21 Oct 2005 22:57:13 -0400 Subject: [PATCH 0620/1939] [PARISC] Avoid use of floating point in the kernel don't use *printf %f in the kernel, mm'kay? Signed-off-by: Randolph Chung Signed-off-by: Kyle McMartin --- drivers/parisc/pdc_stable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 67c8f3b44848..273a74179720 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -536,7 +536,7 @@ pdcs_info_read(struct subsystem *entry, char *buf) out += sprintf(out, "Memory tested: "); if ((result & 0x0F) < 0x0E) - out += sprintf(out, "%.3f MB", 0.256*(1<<(result & 0x0F))); + out += sprintf(out, "%d kB", (1<<(result & 0x0F))*256); else out += sprintf(out, "All"); out += sprintf(out, "\n"); From 27ee073cd2f72aa794299ef1ead31072f5176533 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:57:43 -0400 Subject: [PATCH 0621/1939] [PARISC] Update scsi drivers from parisc tree Fix lasi700 for James's ioread*be() changes Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/scsi/lasi700.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 8028418b3ad6..459a4daebece 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -125,8 +125,6 @@ lasi700_probe(struct parisc_device *dev) hostdata->dmode_extra = DMODE_FC2; } - NCR_700_set_mem_mapped(hostdata); - host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev); if (!host) goto out_kfree; From ae8c75c1c47029a64976690c37336a2be6b49778 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:58:03 -0400 Subject: [PATCH 0622/1939] [PARISC] Fix mux.c driver Missing spin_lock_init() made the Mux driver hang on SMP systems. Fix up users of ->hpa to use ->hpa.start instead Remove warning in 8250_gsc.c by eliminating serial_line_nr Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/serial/8250_gsc.c | 1 - drivers/serial/mux.c | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index abc5a0cfe243..8b4947933d9b 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -29,7 +29,6 @@ static int __init serial_init_chip(struct parisc_device *dev) { - static int serial_line_nr; struct uart_port port; unsigned long address; int err; diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 009ce83c8ef5..660bae5ba179 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -27,6 +27,7 @@ #include /* for udelay */ #include #include +#include #include #ifdef CONFIG_MAGIC_SYSRQ @@ -469,16 +470,18 @@ static int __init mux_probe(struct parisc_device *dev) for(i = 0; i < ports; ++i, ++port_cnt) { port = &mux_ports[port_cnt]; port->iobase = 0; - port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET); + port->mapbase = dev->hpa.start + MUX_OFFSET + + (i * MUX_LINE_OFFSET); port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET); port->iotype = SERIAL_IO_MEM; port->type = PORT_MUX; - port->irq = SERIAL_IRQ_NONE; + port->irq = NO_IRQ; port->uartclk = 0; port->fifosize = MUX_FIFO_SIZE; port->ops = &mux_pops; port->flags = UPF_BOOT_AUTOCONF; port->line = port_cnt; + spin_lock_init(&port->lock); status = uart_add_one_port(&mux_driver, port); BUG_ON(status); } From 6ab0f5cd364476fe5cb329fd46ee41bea6d4c69c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 21 Oct 2005 22:58:51 -0400 Subject: [PATCH 0623/1939] [PARISC] Update parisc specific input code from parisc tree Update drivers to new input layer changes. Signed-off-by: Helge Deller Signed-off-by: Matthew Wilcox Reorder code in gscps2_interrupt() and only enable ports when opened. This fixes issues with hangs booting an SMP kernel on my C360. Previously serio_interrupt() could be called before the lock in struct serio was initialised. Signed-off-by: Richard Hirst Signed-off-by: Kyle McMartin --- drivers/input/keyboard/hil_kbd.c | 28 +- drivers/input/keyboard/hilkbd.c | 2 +- drivers/input/mouse/hil_ptr.c | 33 ++- drivers/input/serio/gscps2.c | 13 +- drivers/input/serio/hil_mlc.c | 14 +- include/linux/hil.h | 483 +++++++++++++++++++++++++++++++ include/linux/hil_mlc.h | 168 +++++++++++ include/linux/hp_sdc.h | 300 +++++++++++++++++++ include/linux/input.h | 1 + 9 files changed, 1011 insertions(+), 31 deletions(-) create mode 100644 include/linux/hil.h create mode 100644 include/linux/hil_mlc.h create mode 100644 include/linux/hp_sdc.h diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index ef78bffed5e7..0a90962c38e7 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -204,7 +204,7 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio, hil_packet packet; int idx; - kbd = (struct hil_kbd *)serio->private; + kbd = serio_get_drvdata(serio); if (kbd == NULL) { BUG(); return IRQ_HANDLED; @@ -234,7 +234,7 @@ static void hil_kbd_disconnect(struct serio *serio) { struct hil_kbd *kbd; - kbd = (struct hil_kbd *)serio->private; + kbd = serio_get_drvdata(serio); if (kbd == NULL) { BUG(); return; @@ -245,20 +245,20 @@ static void hil_kbd_disconnect(struct serio *serio) kfree(kbd); } -static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) +static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) { struct hil_kbd *kbd; uint8_t did, *idd; int i; - if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; - - if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; + kbd = kmalloc(sizeof(*kbd), GFP_KERNEL); + if (!kbd) + return -ENOMEM; memset(kbd, 0, sizeof(struct hil_kbd)); if (serio_open(serio, drv)) goto bail0; - serio->private = kbd; + serio_set_drvdata(serio, kbd); kbd->serio = serio; kbd->dev.private = kbd; @@ -342,19 +342,31 @@ static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) down(&(kbd->sem)); up(&(kbd->sem)); - return; + return 0; bail1: serio_close(serio); bail0: kfree(kbd); + serio_set_drvdata(serio, NULL); + return -EIO; } +static struct serio_device_id hil_kbd_ids[] = { + { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; struct serio_driver hil_kbd_serio_drv = { .driver = { .name = "hil_kbd", }, .description = "HP HIL keyboard driver", + .id_table = hil_kbd_ids, .connect = hil_kbd_connect, .disconnect = hil_kbd_disconnect, .interrupt = hil_kbd_interrupt diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index e7a1e14f8b0c..e95bc052e32a 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index bc22849c6c79..c2bf2ed07dc6 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -196,7 +196,7 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio, hil_packet packet; int idx; - ptr = (struct hil_ptr *)serio->private; + ptr = serio_get_drvdata(serio); if (ptr == NULL) { BUG(); return IRQ_HANDLED; @@ -227,7 +227,7 @@ static void hil_ptr_disconnect(struct serio *serio) { struct hil_ptr *ptr; - ptr = (struct hil_ptr *)serio->private; + ptr = serio_get_drvdata(serio); if (ptr == NULL) { BUG(); return; @@ -238,21 +238,19 @@ static void hil_ptr_disconnect(struct serio *serio) kfree(ptr); } -static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) +static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) { struct hil_ptr *ptr; char *txt; unsigned int i, naxsets, btntype; uint8_t did, *idd; - if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; - - if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return; + if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM; memset(ptr, 0, sizeof(struct hil_ptr)); if (serio_open(serio, driver)) goto bail0; - serio->private = ptr; + serio_set_drvdata(serio, ptr); ptr->serio = serio; ptr->dev.private = ptr; @@ -380,23 +378,34 @@ static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", did); - return; + return 0; bail1: serio_close(serio); bail0: kfree(ptr); - return; + serio_set_drvdata(serio, NULL); + return -ENODEV; } +static struct serio_device_id hil_ptr_ids[] = { + { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; static struct serio_driver hil_ptr_serio_driver = { .driver = { .name = "hil_ptr", }, .description = "HP HIL mouse/tablet driver", - .connect = hil_ptr_connect, - .disconnect = hil_ptr_disconnect, - .interrupt = hil_ptr_interrupt + .id_table = hil_ptr_ids, + .connect = hil_ptr_connect, + .disconnect = hil_ptr_disconnect, + .interrupt = hil_ptr_interrupt }; static int __init hil_ptr_init(void) diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 9790d7169a53..a7b0de0f92b2 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -211,9 +211,6 @@ static void gscps2_reset(struct gscps2port *ps2port) writeb(0xff, addr+GSC_RESET); gscps2_flush(ps2port); spin_unlock_irqrestore(&ps2port->lock, flags); - - /* enable it */ - gscps2_enable(ps2port, ENABLE); } static LIST_HEAD(ps2port_list); @@ -307,6 +304,9 @@ static int gscps2_open(struct serio *port) gscps2_reset(ps2port); + /* enable it */ + gscps2_enable(ps2port, ENABLE); + gscps2_interrupt(0, NULL, NULL); return 0; @@ -370,8 +370,6 @@ static int __init gscps2_probe(struct parisc_device *dev) serio->port_data = ps2port; serio->dev.parent = &dev->dev; - list_add_tail(&ps2port->node, &ps2port_list); - ret = -EBUSY; if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; @@ -396,15 +394,16 @@ static int __init gscps2_probe(struct parisc_device *dev) serio_register_port(ps2port->port); + list_add_tail(&ps2port->node, &ps2port_list); + return 0; fail: free_irq(dev->irq, ps2port); fail_miserably: - list_del(&ps2port->node); iounmap(ps2port->addr); - release_mem_region(dev->hpa, GSC_STATUS + 4); + release_mem_region(dev->hpa.start, GSC_STATUS + 4); fail_nomem: kfree(ps2port); diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index c243cb6fdfc4..5704204964a3 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -801,7 +801,8 @@ static int hil_mlc_serio_open(struct serio *serio) { struct hil_mlc_serio_map *map; struct hil_mlc *mlc; - if (serio->private != NULL) return -EBUSY; + if (serio_get_drvdata(serio) != NULL) + return -EBUSY; map = serio->port_data; if (map == NULL) { @@ -832,11 +833,18 @@ static void hil_mlc_serio_close(struct serio *serio) { return; } - serio->private = NULL; + serio_set_drvdata(serio, NULL); serio->drv = NULL; /* TODO wake up interruptable */ } +static struct serio_device_id hil_mlc_serio_id = { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .extra = SERIO_ANY, + .id = SERIO_ANY, +}; + int hil_mlc_register(hil_mlc *mlc) { int i; unsigned long flags; @@ -867,7 +875,7 @@ int hil_mlc_register(hil_mlc *mlc) { mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc->serio[i] = mlc_serio; memset(mlc_serio, 0, sizeof(*mlc_serio)); - mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; + mlc_serio->id = hil_mlc_serio_id; mlc_serio->write = hil_mlc_serio_write; mlc_serio->open = hil_mlc_serio_open; mlc_serio->close = hil_mlc_serio_close; diff --git a/include/linux/hil.h b/include/linux/hil.h new file mode 100644 index 000000000000..13352d7d0caf --- /dev/null +++ b/include/linux/hil.h @@ -0,0 +1,483 @@ +#ifndef _HIL_H_ +#define _HIL_H_ + +/* + * Hewlett Packard Human Interface Loop (HP-HIL) Protocol -- header. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + * A note of thanks to HP for providing and shipping reference materials + * free of charge to help in the development of HIL support for Linux. + * + */ + +#include + +/* Physical constants relevant to raw loop/device timing. + */ + +#define HIL_CLOCK 8MHZ +#define HIL_EK1_CLOCK 30HZ +#define HIL_EK2_CLOCK 60HZ + +#define HIL_TIMEOUT_DEV 5 /* ms */ +#define HIL_TIMEOUT_DEVS 10 /* ms */ +#define HIL_TIMEOUT_NORESP 10 /* ms */ +#define HIL_TIMEOUT_DEVS_DATA 16 /* ms */ +#define HIL_TIMEOUT_SELFTEST 200 /* ms */ + + +/* Actual wire line coding. These will only be useful if someone is + * implementing a software MLC to run HIL devices on a non-parisc machine. + */ + +#define HIL_WIRE_PACKET_LEN 15 +enum hil_wire_bitpos { + HIL_WIRE_START = 0, + HIL_WIRE_ADDR2, + HIL_WIRE_ADDR1, + HIL_WIRE_ADDR0, + HIL_WIRE_COMMAND, + HIL_WIRE_DATA7, + HIL_WIRE_DATA6, + HIL_WIRE_DATA5, + HIL_WIRE_DATA4, + HIL_WIRE_DATA3, + HIL_WIRE_DATA2, + HIL_WIRE_DATA1, + HIL_WIRE_DATA0, + HIL_WIRE_PARITY, + HIL_WIRE_STOP +}; + +/* HP documentation uses these bit positions to refer to commands; + * we will call these "packets". + */ +enum hil_pkt_bitpos { + HIL_PKT_CMD = 0x00000800, + HIL_PKT_ADDR2 = 0x00000400, + HIL_PKT_ADDR1 = 0x00000200, + HIL_PKT_ADDR0 = 0x00000100, + HIL_PKT_ADDR_MASK = 0x00000700, + HIL_PKT_ADDR_SHIFT = 8, + HIL_PKT_DATA7 = 0x00000080, + HIL_PKT_DATA6 = 0x00000040, + HIL_PKT_DATA5 = 0x00000020, + HIL_PKT_DATA4 = 0x00000010, + HIL_PKT_DATA3 = 0x00000008, + HIL_PKT_DATA2 = 0x00000004, + HIL_PKT_DATA1 = 0x00000002, + HIL_PKT_DATA0 = 0x00000001, + HIL_PKT_DATA_MASK = 0x000000FF, + HIL_PKT_DATA_SHIFT = 0 +}; + +/* The HIL MLC also has several error/status/control bits. We extend the + * "packet" to include these when direct access to the MLC is available, + * or emulate them in cases where they are not available. + * + * This way the device driver knows that the underlying MLC driver + * has had to deal with loop errors. + */ +enum hil_error_bitpos { + HIL_ERR_OB = 0x00000800, /* MLC is busy sending an auto-poll, + or we have filled up the output + buffer and must wait. */ + HIL_ERR_INT = 0x00010000, /* A normal interrupt has occurred. */ + HIL_ERR_NMI = 0x00020000, /* An NMI has occurred. */ + HIL_ERR_LERR = 0x00040000, /* A poll didn't come back. */ + HIL_ERR_PERR = 0x01000000, /* There was a Parity Error. */ + HIL_ERR_FERR = 0x02000000, /* There was a Framing Error. */ + HIL_ERR_FOF = 0x04000000 /* Input FIFO Overflowed. */ +}; + +enum hil_control_bitpos { + HIL_CTRL_TEST = 0x00010000, + HIL_CTRL_IPF = 0x00040000, + HIL_CTRL_APE = 0x02000000 +}; + +/* Bits 30,31 are unused, we use them to control write behavior. */ +#define HIL_DO_ALTER_CTRL 0x40000000 /* Write MSW of packet to control + before writing LSW to loop */ +#define HIL_CTRL_ONLY 0xc0000000 /* *Only* alter the control registers */ + +/* This gives us a 32-bit "packet" + */ +typedef u32 hil_packet; + + +/* HIL Loop commands + */ +enum hil_command { + HIL_CMD_IFC = 0x00, /* Interface Clear */ + HIL_CMD_EPT = 0x01, /* Enter Pass-Thru Mode */ + HIL_CMD_ELB = 0x02, /* Enter Loop-Back Mode */ + HIL_CMD_IDD = 0x03, /* Identify and Describe */ + HIL_CMD_DSR = 0x04, /* Device Soft Reset */ + HIL_CMD_PST = 0x05, /* Perform Self Test */ + HIL_CMD_RRG = 0x06, /* Read Register */ + HIL_CMD_WRG = 0x07, /* Write Register */ + HIL_CMD_ACF = 0x08, /* Auto Configure */ + HIL_CMDID_ACF = 0x07, /* Auto Configure bits with incremented ID */ + HIL_CMD_POL = 0x10, /* Poll */ + HIL_CMDCT_POL = 0x0f, /* Poll command bits with item count */ + HIL_CMD_RPL = 0x20, /* RePoll */ + HIL_CMDCT_RPL = 0x0f, /* RePoll command bits with item count */ + HIL_CMD_RNM = 0x30, /* Report Name */ + HIL_CMD_RST = 0x31, /* Report Status */ + HIL_CMD_EXD = 0x32, /* Extended Describe */ + HIL_CMD_RSC = 0x33, /* Report Security Code */ + + /* 0x34 to 0x3c reserved for future use */ + + HIL_CMD_DKA = 0x3d, /* Disable Keyswitch Autorepeat */ + HIL_CMD_EK1 = 0x3e, /* Enable Keyswitch Autorepeat 1 */ + HIL_CMD_EK2 = 0x3f, /* Enable Keyswitch Autorepeat 2 */ + HIL_CMD_PR1 = 0x40, /* Prompt1 */ + HIL_CMD_PR2 = 0x41, /* Prompt2 */ + HIL_CMD_PR3 = 0x42, /* Prompt3 */ + HIL_CMD_PR4 = 0x43, /* Prompt4 */ + HIL_CMD_PR5 = 0x44, /* Prompt5 */ + HIL_CMD_PR6 = 0x45, /* Prompt6 */ + HIL_CMD_PR7 = 0x46, /* Prompt7 */ + HIL_CMD_PRM = 0x47, /* Prompt (General Purpose) */ + HIL_CMD_AK1 = 0x48, /* Acknowlege1 */ + HIL_CMD_AK2 = 0x49, /* Acknowlege2 */ + HIL_CMD_AK3 = 0x4a, /* Acknowlege3 */ + HIL_CMD_AK4 = 0x4b, /* Acknowlege4 */ + HIL_CMD_AK5 = 0x4c, /* Acknowlege5 */ + HIL_CMD_AK6 = 0x4d, /* Acknowlege6 */ + HIL_CMD_AK7 = 0x4e, /* Acknowlege7 */ + HIL_CMD_ACK = 0x4f, /* Acknowlege (General Purpose) */ + + /* 0x50 to 0x78 reserved for future use */ + /* 0x80 to 0xEF device-specific commands */ + /* 0xf0 to 0xf9 reserved for future use */ + + HIL_CMD_RIO = 0xfa, /* Register I/O Error */ + HIL_CMD_SHR = 0xfb, /* System Hard Reset */ + HIL_CMD_TER = 0xfc, /* Transmission Error */ + HIL_CMD_CAE = 0xfd, /* Configuration Address Error */ + HIL_CMD_DHR = 0xfe, /* Device Hard Reset */ + + /* 0xff is prohibited from use. */ +}; + + +/* + * Response "records" to HIL commands + */ + +/* Device ID byte + */ +#define HIL_IDD_DID_TYPE_MASK 0xe0 /* Primary type bits */ +#define HIL_IDD_DID_TYPE_KB_INTEGRAL 0xa0 /* Integral keyboard */ +#define HIL_IDD_DID_TYPE_KB_ITF 0xc0 /* ITD keyboard */ +#define HIL_IDD_DID_TYPE_KB_RSVD 0xe0 /* Reserved keyboard type */ +#define HIL_IDD_DID_TYPE_KB_LANG_MASK 0x1f /* Keyboard locale bits */ +#define HIL_IDD_DID_KBLANG_USE_ESD 0x00 /* Use ESD Locale instead */ +#define HIL_IDD_DID_TYPE_ABS 0x80 /* Absolute Positioners */ +#define HIL_IDD_DID_ABS_RSVD1_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD1 0x98 +#define HIL_IDD_DID_ABS_TABLET_MASK 0xf8 /* Tablets and digitizers */ +#define HIL_IDD_DID_ABS_TABLET 0x90 +#define HIL_IDD_DID_ABS_TSCREEN_MASK 0xfc /* Touch screens */ +#define HIL_IDD_DID_ABS_TSCREEN 0x8c +#define HIL_IDD_DID_ABS_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD2 0x88 +#define HIL_IDD_DID_ABS_RSVD3_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD3 0x80 +#define HIL_IDD_DID_TYPE_REL 0x60 /* Relative Positioners */ +#define HIL_IDD_DID_REL_RSVD1_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_REL_RSVD1 0x70 +#define HIL_IDD_DID_REL_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_REL_RSVD2 0x6c +#define HIL_IDD_DID_REL_MOUSE_MASK 0xfc /* Mouse */ +#define HIL_IDD_DID_REL_MOUSE 0x68 +#define HIL_IDD_DID_REL_QUAD_MASK 0xf8 /* Other Quadrature Devices */ +#define HIL_IDD_DID_REL_QUAD 0x60 +#define HIL_IDD_DID_TYPE_CHAR 0x40 /* Character Entry */ +#define HIL_IDD_DID_CHAR_BARCODE_MASK 0xfc /* Barcode Reader */ +#define HIL_IDD_DID_CHAR_BARCODE 0x5c +#define HIL_IDD_DID_CHAR_RSVD1_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD1 0x58 +#define HIL_IDD_DID_CHAR_RSVD2_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD2 0x50 +#define HIL_IDD_DID_CHAR_RSVD3_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD3 0x40 +#define HIL_IDD_DID_TYPE_OTHER 0x20 /* Miscellaneous */ +#define HIL_IDD_DID_OTHER_RSVD1_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD1 0x30 +#define HIL_IDD_DID_OTHER_BARCODE_MASK 0xfc /* Tone Generator */ +#define HIL_IDD_DID_OTHER_BARCODE 0x2c +#define HIL_IDD_DID_OTHER_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD2 0x28 +#define HIL_IDD_DID_OTHER_RSVD3_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD3 0x20 +#define HIL_IDD_DID_TYPE_KEYPAD 0x00 /* Vectra Keyboard */ + +/* IDD record header + */ +#define HIL_IDD_HEADER_AXSET_MASK 0x03 /* Number of axis in a set */ +#define HIL_IDD_HEADER_RSC 0x04 /* Supports RSC command */ +#define HIL_IDD_HEADER_EXD 0x08 /* Supports EXD command */ +#define HIL_IDD_HEADER_IOD 0x10 /* IOD byte to follow */ +#define HIL_IDD_HEADER_16BIT 0x20 /* 16 (vs. 8) bit resolution */ +#define HIL_IDD_HEADER_ABS 0x40 /* Reports Absolute Position */ +#define HIL_IDD_HEADER_2X_AXIS 0x80 /* Two sets of 1-3 axis */ + +/* I/O Descriptor + */ +#define HIL_IDD_IOD_NBUTTON_MASK 0x07 /* Number of buttons */ +#define HIL_IDD_IOD_PROXIMITY 0x08 /* Proximity in/out events */ +#define HIL_IDD_IOD_PROMPT_MASK 0x70 /* Number of prompts/acks */ +#define HIL_IDD_IOD_PROMPT_SHIFT 4 +#define HIL_IDD_IOD_PROMPT 0x80 /* Generic prompt/ack */ + +#define HIL_IDD_NUM_AXES_PER_SET(header_packet) \ +((header_packet) & HIL_IDD_HEADER_AXSET_MASK) + +#define HIL_IDD_NUM_AXSETS(header_packet) \ +(2 - !((header_packet) & HIL_IDD_HEADER_2X_AXIS)) + +#define HIL_IDD_LEN(header_packet) \ +((4 - !(header_packet & HIL_IDD_HEADER_IOD) - \ + 2 * !(HIL_IDD_NUM_AXES_PER_SET(header_packet))) + \ + 2 * HIL_IDD_NUM_AXES_PER_SET(header_packet) * \ + !!((header_packet) & HIL_IDD_HEADER_ABS)) + +/* The following HIL_IDD_* macros assume you have an array of + * packets and/or unpacked 8-bit data in the order that they + * were received. + */ + +#define HIL_IDD_AXIS_COUNTS_PER_M(header_ptr) \ +(!(HIL_IDD_NUM_AXSETS(*(header_ptr))) ? -1 : \ +(((*(header_ptr + 1) & HIL_PKT_DATA_MASK) + \ + ((*(header_ptr + 2) & HIL_PKT_DATA_MASK)) << 8) \ +* ((*(header_ptr) & HIL_IDD_HEADER_16BIT) ? 100 : 1))) + +#define HIL_IDD_AXIS_MAX(header_ptr, __axnum) \ +((!(*(header_ptr) & HIL_IDD_HEADER_ABS) || \ + (HIL_IDD_NUM_AXES_PER_SET(*(header_ptr)) <= __axnum)) ? 0 : \ + ((HIL_PKT_DATA_MASK & *((header_ptr) + 3 + 2 * __axnum)) + \ + ((HIL_PKT_DATA_MASK & *((header_ptr) + 4 + 2 * __axnum)) << 8))) + +#define HIL_IDD_IOD(header_ptr) \ +(*(header_ptr + HIL_IDD_LEN((*header_ptr)) - 1)) + +#define HIL_IDD_HAS_GEN_PROMPT(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) && \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROMPT)) + +#define HIL_IDD_HAS_GEN_PROXIMITY(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) && \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROXIMITY)) + +#define HIL_IDD_NUM_BUTTONS(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) ? \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NBUTTON_MASK) : 0) + +#define HIL_IDD_NUM_PROMPTS(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) ? \ + ((HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NPROMPT_MASK) \ + >> HIL_IDD_IOD_PROMPT_SHIFT) : 0) + +/* The response to HIL EXD commands -- the "extended describe record" */ +#define HIL_EXD_HEADER_WRG 0x03 /* Supports type2 WRG */ +#define HIL_EXD_HEADER_WRG_TYPE1 0x01 /* Supports type1 WRG */ +#define HIL_EXD_HEADER_WRG_TYPE2 0x02 /* Supports type2 WRG */ +#define HIL_EXD_HEADER_RRG 0x04 /* Supports RRG command */ +#define HIL_EXD_HEADER_RNM 0x10 /* Supports RNM command */ +#define HIL_EXD_HEADER_RST 0x20 /* Supports RST command */ +#define HIL_EXD_HEADER_LOCALE 0x40 /* Contains locale code */ + +#define HIL_EXD_NUM_RRG(header_ptr) \ +((*header_ptr & HIL_EXD_HEADER_RRG) ? \ + (*(header_ptr + 1) & HIL_PKT_DATA_MASK) : 0) + +#define HIL_EXD_NUM_WWG(header_ptr) \ +((*header_ptr & HIL_EXD_HEADER_WRG) ? \ + (*(header_ptr + 2 - !(*header_ptr & HIL_EXD_HEADER_RRG)) & \ + HIL_PKT_DATA_MASK) : 0) + +#define HIL_EXD_LEN(header_ptr) \ +(!!(*header_ptr & HIL_EXD_HEADER_RRG) + \ + !!(*header_ptr & HIL_EXD_HEADER_WRG) + \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE) + \ + 2 * !!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) + 1) + +#define HIL_EXD_LOCALE(header_ptr) \ +(!(*header_ptr & HIL_EXD_HEADER_LOCALE) ? -1 : \ + (*(header_ptr + HIL_EXD_LEN(header_ptr) - 1) & HIL_PKT_DATA_MASK)) + +#define HIL_EXD_WRG_TYPE2_LEN(header_ptr) \ +(!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) ? -1 : \ + (*(header_ptr + HIL_EXD_LEN(header_ptr) - 2 - \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) + \ + ((*(header_ptr + HIL_EXD_LEN(header_ptr) - 1 - \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) << 8)) + +/* Device locale codes. */ + +/* Last defined locale code. Everything above this is "Reserved", + and note that this same table applies to the Device ID Byte where + keyboards may have a nationality code which is only 5 bits. */ +#define HIL_LOCALE_MAX 0x1f + +/* Map to hopefully useful strings. I was trying to make these look + like locale.aliases strings do; maybe that isn't the right table to + emulate. In either case, I didn't have much to work on. */ +#define HIL_LOCALE_MAP \ +"", /* 0x00 Reserved */ \ +"", /* 0x01 Reserved */ \ +"", /* 0x02 Reserved */ \ +"swiss.french", /* 0x03 Swiss/French */ \ +"portuguese", /* 0x04 Portuguese */ \ +"arabic", /* 0x05 Arabic */ \ +"hebrew", /* 0x06 Hebrew */ \ +"english.canadian", /* 0x07 Canadian English */ \ +"turkish", /* 0x08 Turkish */ \ +"greek", /* 0x09 Greek */ \ +"thai", /* 0x0a Thai (Thailand) */ \ +"italian", /* 0x0b Italian */ \ +"korean", /* 0x0c Hangul (Korea) */ \ +"dutch", /* 0x0d Dutch */ \ +"swedish", /* 0x0e Swedish */ \ +"german", /* 0x0f German */ \ +"chinese", /* 0x10 Chinese-PRC */ \ +"chinese", /* 0x11 Chinese-ROC */ \ +"swiss.french", /* 0x12 Swiss/French II */ \ +"spanish", /* 0x13 Spanish */ \ +"swiss.german", /* 0x14 Swiss/German II */ \ +"flemish", /* 0x15 Belgian (Flemish) */ \ +"finnish", /* 0x16 Finnish */ \ +"english.uk", /* 0x17 United Kingdom */ \ +"french.canadian", /* 0x18 French/Canadian */ \ +"swiss.german", /* 0x19 Swiss/German */ \ +"norwegian", /* 0x1a Norwegian */ \ +"french", /* 0x1b French */ \ +"danish", /* 0x1c Danish */ \ +"japanese", /* 0x1d Katakana */ \ +"spanish", /* 0x1e Latin American/Spanish*/\ +"english.us" /* 0x1f United States */ \ + + +/* HIL keycodes */ +#define HIL_KEYCODES_SET1_TBLSIZE 128 +#define HIL_KEYCODES_SET1 \ + KEY_5, KEY_RESERVED, KEY_RIGHTALT, KEY_LEFTALT, \ + KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_LEFTCTRL, KEY_SYSRQ, \ + KEY_KP4, KEY_KP8, KEY_KP5, KEY_KP9, \ + KEY_KP6, KEY_KP7, KEY_KPCOMMA, KEY_KPENTER, \ + KEY_KP1, KEY_KPSLASH, KEY_KP2, KEY_KPPLUS, \ + KEY_KP3, KEY_KPASTERISK, KEY_KP0, KEY_KPMINUS, \ + KEY_B, KEY_V, KEY_C, KEY_X, \ + KEY_Z, KEY_RESERVED, KEY_RESERVED, KEY_ESC, \ + KEY_6, KEY_F10, KEY_3, KEY_F11, \ + KEY_KPDOT, KEY_F9, KEY_TAB /*KP*/, KEY_F12, \ + KEY_H, KEY_G, KEY_F, KEY_D, \ + KEY_S, KEY_A, KEY_RESERVED, KEY_CAPSLOCK, \ + KEY_U, KEY_Y, KEY_T, KEY_R, \ + KEY_E, KEY_W, KEY_Q, KEY_TAB, \ + KEY_7, KEY_6, KEY_5, KEY_4, \ + KEY_3, KEY_2, KEY_1, KEY_GRAVE, \ + KEY_F13, KEY_F14, KEY_F15, KEY_F16, \ + KEY_F17, KEY_F18, KEY_F19, KEY_F20, \ + KEY_MENU, KEY_F4, KEY_F3, KEY_F2, \ + KEY_F1, KEY_VOLUMEUP, KEY_STOP, KEY_SENDFILE, \ + KEY_SYSRQ, KEY_F5, KEY_F6, KEY_F7, \ + KEY_F8, KEY_VOLUMEDOWN, KEY_DEL_EOL, KEY_DEL_EOS, \ + KEY_8, KEY_9, KEY_0, KEY_MINUS, \ + KEY_EQUAL, KEY_BACKSPACE, KEY_INS_LINE, KEY_DEL_LINE, \ + KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, \ + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_INSERT, KEY_DELETE, \ + KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, \ + KEY_APOSTROPHE, KEY_ENTER, KEY_HOME, KEY_PAGEUP, \ + KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, \ + KEY_BACKSLASH, KEY_SELECT, KEY_102ND, KEY_PAGEDOWN, \ + KEY_N, KEY_SPACE, KEY_NEXT, KEY_RESERVED, \ + KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT + + +#define HIL_KEYCODES_SET3_TBLSIZE 128 +#define HIL_KEYCODES_SET3 \ + KEY_RESERVED, KEY_ESC, KEY_1, KEY_2, \ + KEY_3, KEY_4, KEY_5, KEY_6, \ + KEY_7, KEY_8, KEY_9, KEY_0, \ + KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, \ + KEY_Q, KEY_W, KEY_E, KEY_R, \ + KEY_T, KEY_Y, KEY_U, KEY_I, \ + KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, \ + KEY_ENTER, KEY_LEFTCTRL, KEY_A, KEY_S, \ + KEY_D, KEY_F, KEY_G, KEY_H, \ + KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, \ + KEY_APOSTROPHE,KEY_GRAVE, KEY_LEFTSHIFT, KEY_BACKSLASH, \ + KEY_Z, KEY_X, KEY_C, KEY_V, \ + KEY_B, KEY_N, KEY_M, KEY_COMMA, \ + KEY_DOT, KEY_SLASH, KEY_RIGHTSHIFT, KEY_KPASTERISK, \ + KEY_LEFTALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1, \ + KEY_F2, KEY_F3, KEY_F4, KEY_F5, \ + KEY_F6, KEY_F7, KEY_F8, KEY_F9, \ + KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_KP7, \ + KEY_KP8, KEY_KP9, KEY_KPMINUS, KEY_KP4, \ + KEY_KP5, KEY_KP6, KEY_KPPLUS, KEY_KP1, \ + KEY_KP2, KEY_KP3, KEY_KP0, KEY_KPDOT, \ + KEY_SYSRQ, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, \ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, \ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, \ + KEY_UP, KEY_LEFT, KEY_DOWN, KEY_RIGHT, \ + KEY_HOME, KEY_PAGEUP, KEY_END, KEY_PAGEDOWN, \ + KEY_INSERT, KEY_DELETE, KEY_102ND, KEY_RESERVED, \ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, \ + KEY_F1, KEY_F2, KEY_F3, KEY_F4, \ + KEY_F5, KEY_F6, KEY_F7, KEY_F8, \ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, \ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED + + +/* Response to POL command, the "poll record header" */ + +#define HIL_POL_NUM_AXES_MASK 0x03 /* Number of axis reported */ +#define HIL_POL_CTS 0x04 /* Device ready to receive data */ +#define HIL_POL_STATUS_PENDING 0x08 /* Device has status to report */ +#define HIL_POL_CHARTYPE_MASK 0x70 /* Type of character data to follow */ +#define HIL_POL_CHARTYPE_NONE 0x00 /* No character data to follow */ +#define HIL_POL_CHARTYPE_RSVD1 0x10 /* Reserved Set 1 */ +#define HIL_POL_CHARTYPE_ASCII 0x20 /* U.S. ASCII */ +#define HIL_POL_CHARTYPE_BINARY 0x30 /* Binary data */ +#define HIL_POL_CHARTYPE_SET1 0x40 /* Keycode Set 1 */ +#define HIL_POL_CHARTYPE_RSVD2 0x50 /* Reserved Set 2 */ +#define HIL_POL_CHARTYPE_SET2 0x60 /* Keycode Set 2 */ +#define HIL_POL_CHARTYPE_SET3 0x70 /* Keycode Set 3 */ +#define HIL_POL_AXIS_ALT 0x80 /* Data is from axis set 2 */ + + +#endif /* _HIL_H_ */ diff --git a/include/linux/hil_mlc.h b/include/linux/hil_mlc.h new file mode 100644 index 000000000000..8df29ca48a13 --- /dev/null +++ b/include/linux/hil_mlc.h @@ -0,0 +1,168 @@ +/* + * HP Human Interface Loop Master Link Controller driver. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + */ + +#include +#include +#include +#include +#include +#include + +typedef struct hil_mlc hil_mlc; + +/* The HIL has a complicated state engine. + * We define the structure of nodes in the state engine here. + */ +enum hilse_act { + /* HILSE_OUT prepares to receive input if the next node + * is an IN or EXPECT, and then sends the given packet. + */ + HILSE_OUT = 0, + + /* HILSE_CTS checks if the loop is busy. */ + HILSE_CTS, + + /* HILSE_OUT_LAST sends the given command packet to + * the last configured/running device on the loop. + */ + HILSE_OUT_LAST, + + /* HILSE_OUT_DISC sends the given command packet to + * the next device past the last configured/running one. + */ + HILSE_OUT_DISC, + + /* HILSE_FUNC runs a callback function with given arguments. + * a positive return value causes the "ugly" branch to be taken. + */ + HILSE_FUNC, + + /* HILSE_IN simply expects any non-errored packet to arrive + * within arg usecs. + */ + HILSE_IN = 0x100, + + /* HILSE_EXPECT expects a particular packet to arrive + * within arg usecs, any other packet is considered an error. + */ + HILSE_EXPECT, + + /* HILSE_EXPECT_LAST as above but dev field should be last + * discovered/operational device. + */ + HILSE_EXPECT_LAST, + + /* HILSE_EXPECT_LAST as above but dev field should be first + * undiscovered/inoperational device. + */ + HILSE_EXPECT_DISC +}; + +typedef int (hilse_func) (hil_mlc *mlc, int arg); +struct hilse_node { + enum hilse_act act; /* How to process this node */ + union { + hilse_func *func; /* Function to call if HILSE_FUNC */ + hil_packet packet; /* Packet to send or to compare */ + } object; + int arg; /* Timeout in usec or parm for func */ + int good; /* Node to jump to on success */ + int bad; /* Node to jump to on error */ + int ugly; /* Node to jump to on timeout */ +}; + +/* Methods for back-end drivers, e.g. hp_sdc_mlc */ +typedef int (hil_mlc_cts) (hil_mlc *mlc); +typedef void (hil_mlc_out) (hil_mlc *mlc); +typedef int (hil_mlc_in) (hil_mlc *mlc, suseconds_t timeout); + +struct hil_mlc_devinfo { + uint8_t idd[16]; /* Device ID Byte and Describe Record */ + uint8_t rsc[16]; /* Security Code Header and Record */ + uint8_t exd[16]; /* Extended Describe Record */ + uint8_t rnm[16]; /* Device name as returned by RNM command */ +}; + +struct hil_mlc_serio_map { + hil_mlc *mlc; + int di_revmap; + int didx; +}; + +/* How many (possibly old/detached) devices the we try to keep track of */ +#define HIL_MLC_DEVMEM 16 + +struct hil_mlc { + struct list_head list; /* hil_mlc is organized as linked list */ + + rwlock_t lock; + + void *priv; /* Data specific to a particular type of MLC */ + + int seidx; /* Current node in state engine */ + int istarted, ostarted; + + hil_mlc_cts *cts; + struct semaphore csem; /* Raised when loop idle */ + + hil_mlc_out *out; + struct semaphore osem; /* Raised when outpacket dispatched */ + hil_packet opacket; + + hil_mlc_in *in; + struct semaphore isem; /* Raised when a packet arrives */ + hil_packet ipacket[16]; + hil_packet imatch; + int icount; + struct timeval instart; + suseconds_t intimeout; + + int ddi; /* Last operational device id */ + int lcv; /* LCV to throttle loops */ + struct timeval lcv_tv; /* Time loop was started */ + + int di_map[7]; /* Maps below items to live devs */ + struct hil_mlc_devinfo di[HIL_MLC_DEVMEM]; + struct serio *serio[HIL_MLC_DEVMEM]; + struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM]; + hil_packet serio_opacket[HIL_MLC_DEVMEM]; + int serio_oidx[HIL_MLC_DEVMEM]; + struct hil_mlc_devinfo di_scratch; /* Temporary area */ + + int opercnt; + + struct tasklet_struct *tasklet; +}; + +int hil_mlc_register(hil_mlc *mlc); +int hil_mlc_unregister(hil_mlc *mlc); diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h new file mode 100644 index 000000000000..debd71515312 --- /dev/null +++ b/include/linux/hp_sdc.h @@ -0,0 +1,300 @@ +/* + * HP i8042 System Device Controller -- header + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + * System Device Controller Microprocessor Firmware Theory of Operation + * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 + * + */ + +#ifndef _LINUX_HP_SDC_H +#define _LINUX_HP_SDC_H + +#include +#include +#include +#include +#if defined(__hppa__) +#include +#endif + + +/* No 4X status reads take longer than this (in usec). + */ +#define HP_SDC_MAX_REG_DELAY 20000 + +typedef void (hp_sdc_irqhook) (int irq, void *dev_id, + uint8_t status, uint8_t data); + +int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback); +int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback); +int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback); + +typedef struct { + int actidx; /* Start of act. Acts are atomic WRT I/O to SDC */ + int idx; /* Index within the act */ + int endidx; /* transaction is over and done if idx == endidx */ + uint8_t *seq; /* commands/data for the transaction */ + union { + hp_sdc_irqhook *irqhook; /* Callback, isr or tasklet context */ + struct semaphore *semaphore; /* Semaphore to sleep on. */ + } act; +} hp_sdc_transaction; +int hp_sdc_enqueue_transaction(hp_sdc_transaction *this); +int hp_sdc_dequeue_transaction(hp_sdc_transaction *this); + +/* The HP_SDC_ACT* values are peculiar to this driver. + * Nuance: never HP_SDC_ACT_DATAIN | HP_SDC_ACT_DEALLOC, use another + * act to perform the dealloc. + */ +#define HP_SDC_ACT_PRECMD 0x01 /* Send a command first */ +#define HP_SDC_ACT_DATAREG 0x02 /* Set data registers */ +#define HP_SDC_ACT_DATAOUT 0x04 /* Send data bytes */ +#define HP_SDC_ACT_POSTCMD 0x08 /* Send command after */ +#define HP_SDC_ACT_DATAIN 0x10 /* Collect data after */ +#define HP_SDC_ACT_DURING 0x1f +#define HP_SDC_ACT_SEMAPHORE 0x20 /* Raise semaphore after */ +#define HP_SDC_ACT_CALLBACK 0x40 /* Pass data to IRQ handler */ +#define HP_SDC_ACT_DEALLOC 0x80 /* Destroy transaction after */ +#define HP_SDC_ACT_AFTER 0xe0 +#define HP_SDC_ACT_DEAD 0x60 /* Act timed out. */ + +/* Rest of the flags are straightforward representation of the SDC interface */ +#define HP_SDC_STATUS_IBF 0x02 /* Input buffer full */ + +#define HP_SDC_STATUS_IRQMASK 0xf0 /* Bits containing "level 1" irq */ +#define HP_SDC_STATUS_PERIODIC 0x10 /* Periodic 10ms timer */ +#define HP_SDC_STATUS_USERTIMER 0x20 /* "Special purpose" timer */ +#define HP_SDC_STATUS_TIMER 0x30 /* Both PERIODIC and USERTIMER */ +#define HP_SDC_STATUS_REG 0x40 /* Data from an i8042 register */ +#define HP_SDC_STATUS_HILCMD 0x50 /* Command from HIL MLC */ +#define HP_SDC_STATUS_HILDATA 0x60 /* Data from HIL MLC */ +#define HP_SDC_STATUS_PUP 0x70 /* Sucessful power-up self test */ +#define HP_SDC_STATUS_KCOOKED 0x80 /* Key from cooked kbd */ +#define HP_SDC_STATUS_KRPG 0xc0 /* Key from Repeat Gen */ +#define HP_SDC_STATUS_KMOD_SUP 0x10 /* Shift key is up */ +#define HP_SDC_STATUS_KMOD_CUP 0x20 /* Control key is up */ + +#define HP_SDC_NMISTATUS_FHS 0x40 /* NMI is a fast handshake irq */ + +/* Internal i8042 registers (there are more, but they are not too useful). */ + +#define HP_SDC_USE 0x02 /* Resource usage (including OB bit) */ +#define HP_SDC_IM 0x04 /* Interrupt mask */ +#define HP_SDC_CFG 0x11 /* Configuration register */ +#define HP_SDC_KBLANGUAGE 0x12 /* Keyboard language */ + +#define HP_SDC_D0 0x70 /* General purpose data buffer 0 */ +#define HP_SDC_D1 0x71 /* General purpose data buffer 1 */ +#define HP_SDC_D2 0x72 /* General purpose data buffer 2 */ +#define HP_SDC_D3 0x73 /* General purpose data buffer 3 */ +#define HP_SDC_VT1 0x74 /* Timer for voice 1 */ +#define HP_SDC_VT2 0x75 /* Timer for voice 2 */ +#define HP_SDC_VT3 0x76 /* Timer for voice 3 */ +#define HP_SDC_VT4 0x77 /* Timer for voice 4 */ +#define HP_SDC_KBN 0x78 /* Which HIL devs are Nimitz */ +#define HP_SDC_KBC 0x79 /* Which HIL devs are cooked kbds */ +#define HP_SDC_LPS 0x7a /* i8042's view of HIL status */ +#define HP_SDC_LPC 0x7b /* i8042's view of HIL "control" */ +#define HP_SDC_RSV 0x7c /* Reserved "for testing" */ +#define HP_SDC_LPR 0x7d /* i8042 count of HIL reconfigs */ +#define HP_SDC_XTD 0x7e /* "Extended Configuration" register */ +#define HP_SDC_STR 0x7f /* i8042 self-test result */ + +/* Bitfields for above registers */ +#define HP_SDC_USE_LOOP 0x04 /* Command is currently on the loop. */ + +#define HP_SDC_IM_MASK 0x1f /* these bits not part of cmd/status */ +#define HP_SDC_IM_FH 0x10 /* Mask the fast handshake irq */ +#define HP_SDC_IM_PT 0x08 /* Mask the periodic timer irq */ +#define HP_SDC_IM_TIMERS 0x04 /* Mask the MT/DT/CT irq */ +#define HP_SDC_IM_RESET 0x02 /* Mask the reset key irq */ +#define HP_SDC_IM_HIL 0x01 /* Mask the HIL MLC irq */ + +#define HP_SDC_CFG_ROLLOVER 0x08 /* WTF is "N-key rollover"? */ +#define HP_SDC_CFG_KBD 0x10 /* There is a keyboard */ +#define HP_SDC_CFG_NEW 0x20 /* Supports/uses HIL MLC */ +#define HP_SDC_CFG_KBD_OLD 0x03 /* keyboard code for non-HIL */ +#define HP_SDC_CFG_KBD_NEW 0x07 /* keyboard code from HIL autoconfig */ +#define HP_SDC_CFG_REV 0x40 /* Code revision bit */ +#define HP_SDC_CFG_IDPROM 0x80 /* IDPROM present in kbd (not HIL) */ + +#define HP_SDC_LPS_NDEV 0x07 /* # devices autoconfigured on HIL */ +#define HP_SDC_LPS_ACSUCC 0x08 /* loop autoconfigured successfully */ +#define HP_SDC_LPS_ACFAIL 0x80 /* last loop autoconfigure failed */ + +#define HP_SDC_LPC_APE_IPF 0x01 /* HIL MLC APE/IPF (autopoll) set */ +#define HP_SDC_LPC_ARCONERR 0x02 /* i8042 autoreconfigs loop on err */ +#define HP_SDC_LPC_ARCQUIET 0x03 /* i8042 doesn't report autoreconfigs*/ +#define HP_SDC_LPC_COOK 0x10 /* i8042 cooks devices in _KBN */ +#define HP_SDC_LPC_RC 0x80 /* causes autoreconfig */ + +#define HP_SDC_XTD_REV 0x07 /* contains revision code */ +#define HP_SDC_XTD_REV_STRINGS(val, str) \ +switch (val) { \ + case 0x1: str = "1820-3712"; break; \ + case 0x2: str = "1820-4379"; break; \ + case 0x3: str = "1820-4784"; break; \ + default: str = "unknown"; \ +}; +#define HP_SDC_XTD_BEEPER 0x08 /* TI SN76494 beeper available */ +#define HP_SDC_XTD_BBRTC 0x20 /* OKI MSM-58321 BBRTC present */ + +#define HP_SDC_CMD_LOAD_RT 0x31 /* Load real time (from 8042) */ +#define HP_SDC_CMD_LOAD_FHS 0x36 /* Load the fast handshake timer */ +#define HP_SDC_CMD_LOAD_MT 0x38 /* Load the match timer */ +#define HP_SDC_CMD_LOAD_DT 0x3B /* Load the delay timer */ +#define HP_SDC_CMD_LOAD_CT 0x3E /* Load the cycle timer */ + +#define HP_SDC_CMD_SET_IM 0x40 /* 010xxxxx == set irq mask */ + +/* The documents provided do not explicitly state that all registers betweem + * 0x01 and 0x1f inclusive can be read by sending their register index as a + * command, but this is implied and appears to be the case. + */ +#define HP_SDC_CMD_READ_RAM 0x00 /* Load from i8042 RAM (autoinc) */ +#define HP_SDC_CMD_READ_USE 0x02 /* Undocumented! Load from usage reg */ +#define HP_SDC_CMD_READ_IM 0x04 /* Load current interrupt mask */ +#define HP_SDC_CMD_READ_KCC 0x11 /* Load primary kbd config code */ +#define HP_SDC_CMD_READ_KLC 0x12 /* Load primary kbd language code */ +#define HP_SDC_CMD_READ_T1 0x13 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T2 0x14 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T3 0x15 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T4 0x16 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T5 0x17 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_D0 0xf0 /* Load from i8042 RAM location 0x70 */ +#define HP_SDC_CMD_READ_D1 0xf1 /* Load from i8042 RAM location 0x71 */ +#define HP_SDC_CMD_READ_D2 0xf2 /* Load from i8042 RAM location 0x72 */ +#define HP_SDC_CMD_READ_D3 0xf3 /* Load from i8042 RAM location 0x73 */ +#define HP_SDC_CMD_READ_VT1 0xf4 /* Load from i8042 RAM location 0x74 */ +#define HP_SDC_CMD_READ_VT2 0xf5 /* Load from i8042 RAM location 0x75 */ +#define HP_SDC_CMD_READ_VT3 0xf6 /* Load from i8042 RAM location 0x76 */ +#define HP_SDC_CMD_READ_VT4 0xf7 /* Load from i8042 RAM location 0x77 */ +#define HP_SDC_CMD_READ_KBN 0xf8 /* Load from i8042 RAM location 0x78 */ +#define HP_SDC_CMD_READ_KBC 0xf9 /* Load from i8042 RAM location 0x79 */ +#define HP_SDC_CMD_READ_LPS 0xfa /* Load from i8042 RAM location 0x7a */ +#define HP_SDC_CMD_READ_LPC 0xfb /* Load from i8042 RAM location 0x7b */ +#define HP_SDC_CMD_READ_RSV 0xfc /* Load from i8042 RAM location 0x7c */ +#define HP_SDC_CMD_READ_LPR 0xfd /* Load from i8042 RAM location 0x7d */ +#define HP_SDC_CMD_READ_XTD 0xfe /* Load from i8042 RAM location 0x7e */ +#define HP_SDC_CMD_READ_STR 0xff /* Load from i8042 RAM location 0x7f */ + +#define HP_SDC_CMD_SET_ARD 0xA0 /* Set emulated autorepeat delay */ +#define HP_SDC_CMD_SET_ARR 0xA2 /* Set emulated autorepeat rate */ +#define HP_SDC_CMD_SET_BELL 0xA3 /* Set voice 3 params for "beep" cmd */ +#define HP_SDC_CMD_SET_RPGR 0xA6 /* Set "RPG" irq rate (doesn't work) */ +#define HP_SDC_CMD_SET_RTMS 0xAD /* Set the RTC time (milliseconds) */ +#define HP_SDC_CMD_SET_RTD 0xAF /* Set the RTC time (days) */ +#define HP_SDC_CMD_SET_FHS 0xB2 /* Set fast handshake timer */ +#define HP_SDC_CMD_SET_MT 0xB4 /* Set match timer */ +#define HP_SDC_CMD_SET_DT 0xB7 /* Set delay timer */ +#define HP_SDC_CMD_SET_CT 0xBA /* Set cycle timer */ +#define HP_SDC_CMD_SET_RAMP 0xC1 /* Reset READ_RAM autoinc counter */ +#define HP_SDC_CMD_SET_D0 0xe0 /* Load to i8042 RAM location 0x70 */ +#define HP_SDC_CMD_SET_D1 0xe1 /* Load to i8042 RAM location 0x71 */ +#define HP_SDC_CMD_SET_D2 0xe2 /* Load to i8042 RAM location 0x72 */ +#define HP_SDC_CMD_SET_D3 0xe3 /* Load to i8042 RAM location 0x73 */ +#define HP_SDC_CMD_SET_VT1 0xe4 /* Load to i8042 RAM location 0x74 */ +#define HP_SDC_CMD_SET_VT2 0xe5 /* Load to i8042 RAM location 0x75 */ +#define HP_SDC_CMD_SET_VT3 0xe6 /* Load to i8042 RAM location 0x76 */ +#define HP_SDC_CMD_SET_VT4 0xe7 /* Load to i8042 RAM location 0x77 */ +#define HP_SDC_CMD_SET_KBN 0xe8 /* Load to i8042 RAM location 0x78 */ +#define HP_SDC_CMD_SET_KBC 0xe9 /* Load to i8042 RAM location 0x79 */ +#define HP_SDC_CMD_SET_LPS 0xea /* Load to i8042 RAM location 0x7a */ +#define HP_SDC_CMD_SET_LPC 0xeb /* Load to i8042 RAM location 0x7b */ +#define HP_SDC_CMD_SET_RSV 0xec /* Load to i8042 RAM location 0x7c */ +#define HP_SDC_CMD_SET_LPR 0xed /* Load to i8042 RAM location 0x7d */ +#define HP_SDC_CMD_SET_XTD 0xee /* Load to i8042 RAM location 0x7e */ +#define HP_SDC_CMD_SET_STR 0xef /* Load to i8042 RAM location 0x7f */ + +#define HP_SDC_CMD_DO_RTCW 0xc2 /* i8042 RAM 0x70 --> RTC */ +#define HP_SDC_CMD_DO_RTCR 0xc3 /* RTC[0x70 0:3] --> irq/status/data */ +#define HP_SDC_CMD_DO_BEEP 0xc4 /* i8042 RAM 0x70-74 --> beeper,VT3 */ +#define HP_SDC_CMD_DO_HIL 0xc5 /* i8042 RAM 0x70-73 --> + HIL MLC R0,R1 i8042 HIL watchdog */ + +/* Values used to (de)mangle input/output to/from the HIL MLC */ +#define HP_SDC_DATA 0x40 /* Data from an 8042 register */ +#define HP_SDC_HIL_CMD 0x50 /* Data from HIL MLC R1/8042 */ +#define HP_SDC_HIL_R1MASK 0x0f /* Contents of HIL MLC R1 0:3 */ +#define HP_SDC_HIL_AUTO 0x10 /* Set if POL results from i8042 */ +#define HP_SDC_HIL_ISERR 0x80 /* Has meaning as in next 4 values */ +#define HP_SDC_HIL_RC_DONE 0x80 /* i8042 auto-configured loop */ +#define HP_SDC_HIL_ERR 0x81 /* HIL MLC R2 had a bit set */ +#define HP_SDC_HIL_TO 0x82 /* i8042 HIL watchdog expired */ +#define HP_SDC_HIL_RC 0x84 /* i8042 is auto-configuring loop */ +#define HP_SDC_HIL_DAT 0x60 /* Data from HIL MLC R0 */ + + +typedef struct { + rwlock_t ibf_lock; + rwlock_t lock; /* user/tasklet lock */ + rwlock_t rtq_lock; /* isr/tasklet lock */ + rwlock_t hook_lock; /* isr/user lock for handler add/del */ + + unsigned int irq, nmi; /* Our IRQ lines */ + unsigned long base_io, status_io, data_io; /* Our IO ports */ + + uint8_t im; /* Interrupt mask */ + int set_im; /* Interrupt mask needs to be set. */ + + int ibf; /* Last known status of IBF flag */ + uint8_t wi; /* current i8042 write index */ + uint8_t r7[4]; /* current i8042[0x70 - 0x74] values */ + uint8_t r11, r7e; /* Values from version/revision regs */ + + hp_sdc_irqhook *timer, *reg, *hil, *pup, *cooked; + +#define HP_SDC_QUEUE_LEN 16 + hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ + + int rcurr, rqty; /* Current read transact in process */ + struct timeval rtv; /* Time when current read started */ + int wcurr; /* Current write transact in process */ + + int dev_err; /* carries status from registration */ +#if defined(__hppa__) + struct parisc_device *dev; +#elif defined(__mc68000__) + void *dev; +#else +#error No support for device registration on this arch yet. +#endif + + struct timer_list kicker; /* Keeps below task alive */ + struct tasklet_struct task; + +} hp_i8042_sdc; + +#endif /* _LINUX_HP_SDC_H */ diff --git a/include/linux/input.h b/include/linux/input.h index e8c296ff6257..d7836311ada9 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -644,6 +644,7 @@ struct input_absinfo { #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 +#define BUS_GSC 0x1A /* * Values describing the status of an effect From 27678201333e1b9a9a7fc8e685d858132956113e Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Oct 2005 23:11:03 -0400 Subject: [PATCH 0624/1939] [PARISC] defconfig updates defconfig updates from Kyle McMartin, Grant Grundler, and Matthew Wilcox. Signed-off-by: Kyle McMartin --- arch/parisc/configs/712_defconfig | 456 +++++++++++-------- arch/parisc/configs/a500_defconfig | 551 +++++++++++++--------- arch/parisc/configs/b180_defconfig | 309 ++++++++----- arch/parisc/configs/c3000_defconfig | 678 ++++++++++++++++++---------- arch/parisc/defconfig | 656 +++++++++++++++++++-------- 5 files changed, 1725 insertions(+), 925 deletions(-) diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig index 6efaa9293eef..3e013f55df64 100644 --- a/arch/parisc/configs/712_defconfig +++ b/arch/parisc/configs/712_defconfig @@ -1,12 +1,16 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-pa5 -# Wed Jan 5 13:20:32 2005 +# Linux kernel version: 2.6.14-rc5-pa1 +# Fri Oct 21 23:04:34 2005 # CONFIG_PARISC=y CONFIG_MMU=y CONFIG_STACK_GROWSUP=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -15,35 +19,40 @@ CONFIG_EXPERIMENTAL=y # CONFIG_CLEAN_COMPILE is not set CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=16 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,9 +74,18 @@ CONFIG_PA7100LC=y # CONFIG_PA7300LC is not set # CONFIG_PA8X00 is not set CONFIG_PA11=y -# CONFIG_64BIT is not set # CONFIG_SMP is not set -# CONFIG_DISCONTIGMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +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_PREEMPT is not set # CONFIG_HPUX is not set @@ -81,8 +99,6 @@ CONFIG_GSC_LASI=y # CONFIG_GSC_WAX is not set # CONFIG_EISA is not set # CONFIG_PCI is not set -CONFIG_CHASSIS_LCD_LED=y -# CONFIG_PDC_CHASSIS is not set # # PCCARD (PCMCIA/CardBus) support @@ -90,12 +106,15 @@ CONFIG_CHASSIS_LCD_LED=y # CONFIG_PCCARD is not set # -# PC-card bridges +# PCI Hotplug Support # # -# PCI Hotplug Support +# PA-RISC specific drivers # +CONFIG_CHASSIS_LCD_LED=y +# CONFIG_PDC_CHASSIS is not set +CONFIG_PDC_STABLE=y # # Executable file formats @@ -104,137 +123,7 @@ CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m # -# Device Drivers -# - -# -# Generic Driver Options -# -# CONFIG_STANDALONE is not set -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -CONFIG_FW_LOADER=y -# CONFIG_DEBUG_DRIVER is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_PC_CML1=m -# CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_SUPERIO is not set -CONFIG_PARPORT_GSC=y -# CONFIG_PARPORT_OTHER is not set -# CONFIG_PARPORT_1284 is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_CRYPTOLOOP=y -# CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=6144 -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -CONFIG_SCSI=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -# CONFIG_CHR_DEV_OSST is not set -CONFIG_BLK_DEV_SR=y -# CONFIG_BLK_DEV_SR_VENDOR is not set -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI Transport Attributes -# -CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_SCSI_FC_ATTRS is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set -CONFIG_SCSI_LASI700=y -CONFIG_53C700_MEM_MAPPED=y -CONFIG_53C700_LE_ON_BE=y -# CONFIG_SCSI_ZALON is not set -CONFIG_SCSI_DEBUG=m - -# -# Multi-device support (RAID and LVM) -# -CONFIG_MD=y -CONFIG_BLK_DEV_MD=m -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -# CONFIG_MD_RAID10 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_RAID6 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_MD_FAULTY is not set -# CONFIG_BLK_DEV_DM is not set - -# -# Fusion MPT device support -# - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# - -# -# Networking support +# Networking # CONFIG_NET=y @@ -243,12 +132,14 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK_DEV=y CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m CONFIG_NET_KEY=m 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 @@ -262,8 +153,10 @@ CONFIG_INET_AH=m CONFIG_INET_ESP=m # CONFIG_INET_IPCOMP is not set CONFIG_INET_TUNNEL=m -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set +CONFIG_INET_DIAG=m +CONFIG_INET_TCP_DIAG=m +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y # # IP: Virtual Server Configuration @@ -272,6 +165,7 @@ CONFIG_IP_TCPDIAG=y # CONFIG_IPV6 is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_NETLINK is not set # # IP: Netfilter Configuration @@ -279,11 +173,14 @@ CONFIG_NETFILTER=y CONFIG_IP_NF_CONNTRACK=m # CONFIG_IP_NF_CT_ACCT is not set CONFIG_IP_NF_CONNTRACK_MARK=y +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set CONFIG_IP_NF_CT_PROTO_SCTP=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_NETBIOS_NS is not set CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m +# CONFIG_IP_NF_PPTP is not set CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_LIMIT=m @@ -307,21 +204,23 @@ CONFIG_IP_NF_MATCH_OWNER=m # CONFIG_IP_NF_MATCH_ADDRTYPE is not set # CONFIG_IP_NF_MATCH_REALM is not set CONFIG_IP_NF_MATCH_SCTP=m +# CONFIG_IP_NF_MATCH_DCCP is not set CONFIG_IP_NF_MATCH_COMMENT=m CONFIG_IP_NF_MATCH_CONNMARK=m CONFIG_IP_NF_MATCH_HASHLIMIT=m +# CONFIG_IP_NF_MATCH_STRING is not set CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_TARGET_NFQUEUE is not set CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_SAME=m -# CONFIG_IP_NF_NAT_LOCAL is not set CONFIG_IP_NF_NAT_SNMP_BASIC=m CONFIG_IP_NF_NAT_IRC=m CONFIG_IP_NF_NAT_FTP=m @@ -333,6 +232,7 @@ CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_CLASSIFY=m +# CONFIG_IP_NF_TARGET_TTL is not set CONFIG_IP_NF_TARGET_CONNMARK=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_RAW=m @@ -340,10 +240,11 @@ CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -CONFIG_XFRM=y -CONFIG_XFRM_USER=m + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set # # SCTP Configuration (EXPERIMENTAL) @@ -362,10 +263,6 @@ CONFIG_LLC2=m # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# # CONFIG_NET_SCHED is not set # CONFIG_NET_CLS_ROUTE is not set @@ -373,17 +270,162 @@ CONFIG_LLC2=m # Network testing # CONFIG_NET_PKTGEN=m -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +# 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=y +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_GSC=y +# CONFIG_PARPORT_1284 is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=6144 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_ATA_OVER_ETH=m + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +CONFIG_SCSI_LASI700=y +CONFIG_53C700_LE_ON_BE=y +# CONFIG_SCSI_ZALON is not set +CONFIG_SCSI_DEBUG=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_RAID6 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BLK_DEV_DM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Network device support +# CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m # CONFIG_EQUALIZER is not set CONFIG_TUN=m -# CONFIG_ETHERTAP is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set # # Ethernet (10 or 100Mbit) @@ -391,6 +433,7 @@ CONFIG_TUN=m CONFIG_NET_ETHERNET=y CONFIG_MII=m CONFIG_LASI_82596=y +# CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) @@ -414,6 +457,7 @@ CONFIG_NET_RADIO=y # # CONFIG_STRIP is not set # CONFIG_ATMEL is not set +# CONFIG_HOSTAP is not set # # Wan interfaces @@ -431,6 +475,8 @@ CONFIG_PPPOE=m # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -459,19 +505,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_PARKBD is not set -CONFIG_SERIO_GSCPS2=y -CONFIG_HP_SDC=y -CONFIG_HIL_MLC=y -# CONFIG_SERIO_RAW is not set - # # Input Device Drivers # @@ -483,6 +516,7 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_HIL_OLD=y # CONFIG_KEYBOARD_HIL is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y @@ -493,6 +527,19 @@ CONFIG_MOUSE_HIL=m # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_GSCPS2=y +CONFIG_HP_SDC=y +CONFIG_HIL_MLC=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + # # Character devices # @@ -511,7 +558,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -546,11 +592,13 @@ CONFIG_GEN_RTC_X=y # # Ftape, the floppy tape device driver # -# CONFIG_AGP is not set -# CONFIG_DRM is not set CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=256 +# +# TPM devices +# + # # I2C support # @@ -561,10 +609,20 @@ CONFIG_MAX_RAW_DEVS=256 # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -579,28 +637,36 @@ CONFIG_MAX_RAW_DEVS=256 # Graphics support # CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SOFT_CURSOR=y +# CONFIG_FB_MACMODES is not set CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_STI=y +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # -CONFIG_STI_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=128 CONFIG_DUMMY_CONSOLE_ROWS=48 -CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_STI_CONSOLE=y CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y # CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set # CONFIG_FONT_MINI_4x6 is not set # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set # # Logo configuration @@ -610,6 +676,7 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_LOGO_LINUX_CLUT224 is not set CONFIG_LOGO_PARISC_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -656,10 +723,6 @@ CONFIG_SND_HARMONY=y # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - # # USB Gadget Support # @@ -670,11 +733,21 @@ CONFIG_SND_HARMONY=y # # CONFIG_MMC is not set +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + # # 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 is not set CONFIG_JBD=y @@ -682,20 +755,24 @@ CONFIG_JBD=y # CONFIG_REISERFS_FS is not set CONFIG_JFS_FS=m # CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set CONFIG_FS_POSIX_ACL=y CONFIG_XFS_FS=m -# CONFIG_XFS_RT is not set +CONFIG_XFS_EXPORT=y # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT 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=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -722,14 +799,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -CONFIG_TMPFS_XATTR=y -# CONFIG_TMPFS_SECURITY is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -754,16 +828,19 @@ CONFIG_UFS_FS=m # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y CONFIG_NFS_DIRECTIO=y CONFIG_NFSD=m CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y @@ -778,6 +855,7 @@ CONFIG_CIFS=m # 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 @@ -838,13 +916,19 @@ CONFIG_OPROFILE=m # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # 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_IOREMAP is not set +# CONFIG_DEBUG_FS is not set # # Security options @@ -865,6 +949,7 @@ CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -881,10 +966,15 @@ CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m +# +# Hardware crypto devices +# + # # Library routines # CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=m diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig index 30fc03ed0cfb..955ef5084f3e 100644 --- a/arch/parisc/configs/a500_defconfig +++ b/arch/parisc/configs/a500_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4-pa1 -# Wed Feb 16 11:32:49 2005 +# Linux kernel version: 2.6.14-rc5-pa1 +# Fri Oct 21 23:04:54 2005 # CONFIG_PARISC=y CONFIG_MMU=y @@ -10,6 +10,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -19,26 +20,32 @@ CONFIG_EXPERIMENTAL=y CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=16 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -48,6 +55,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -74,7 +82,19 @@ CONFIG_PREFETCH=y CONFIG_64BIT=y CONFIG_SMP=y CONFIG_HOTPLUG_CPU=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set # CONFIG_PREEMPT is not set CONFIG_COMPAT=y CONFIG_NR_CPUS=8 @@ -85,7 +105,7 @@ CONFIG_NR_CPUS=8 # CONFIG_GSC is not set CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set CONFIG_PCI_LBA=y CONFIG_IOSAPIC=y CONFIG_IOMMU_SBA=y @@ -96,6 +116,8 @@ CONFIG_IOMMU_SBA=y CONFIG_PCCARD=m # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=m +# CONFIG_PCMCIA_LOAD_CIS is not set +CONFIG_PCMCIA_IOCTL=y CONFIG_CARDBUS=y # @@ -104,7 +126,6 @@ CONFIG_CARDBUS=y CONFIG_YENTA=m CONFIG_PD6729=m CONFIG_I82092=m -CONFIG_TCIC=m CONFIG_PCCARD_NONSTATIC=m # @@ -126,6 +147,203 @@ CONFIG_PDC_STABLE=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +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 is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_IPCOMP is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_NETLINK is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +CONFIG_IP_NF_CONNTRACK_MARK=y +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +CONFIG_IP_NF_CT_PROTO_SCTP=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +# CONFIG_IP_NF_PPTP is not set +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +CONFIG_IP_NF_MATCH_SCTP=m +# CONFIG_IP_NF_MATCH_DCCP is not set +CONFIG_IP_NF_MATCH_COMMENT=m +CONFIG_IP_NF_MATCH_CONNMARK=m +CONFIG_IP_NF_MATCH_HASHLIMIT=m +# CONFIG_IP_NF_MATCH_STRING is not set +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_TARGET_NFQUEUE is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_TARGET_CONNMARK=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +# CONFIG_IP6_NF_MATCH_LIMIT is not set +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +# CONFIG_IP6_NF_MATCH_MULTIPORT is not set +# CONFIG_IP6_NF_MATCH_OWNER is not set +# CONFIG_IP6_NF_MATCH_MARK is not set +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +# CONFIG_IP6_NF_TARGET_NFQUEUE is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_TARGET_MARK is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_RAW=m + +# +# DCCP Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP_CCID3 is not set + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +CONFIG_LLC2=m +# 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 +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + # # Device Drivers # @@ -138,6 +356,11 @@ CONFIG_BINFMT_ELF=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -169,7 +392,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=6144 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -189,6 +411,7 @@ CONFIG_IOSCHED_CFQ=y # # SCSI device support # +CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -201,6 +424,7 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -215,6 +439,7 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=m CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m # # SCSI low-level drivers @@ -229,14 +454,12 @@ CONFIG_SCSI_ISCSI_ATTRS=m # CONFIG_SCSI_ADVANSYS is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set @@ -246,8 +469,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set CONFIG_SCSI_QLOGIC_FC=m # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set @@ -258,7 +479,9 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA22XX is not set CONFIG_SCSI_QLA2300=m CONFIG_SCSI_QLA2322=m -CONFIG_SCSI_QLA6312=m +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set CONFIG_SCSI_DEBUG=m @@ -288,8 +511,11 @@ CONFIG_MD_RAID1=y # # Fusion MPT device support # -CONFIG_FUSION=m -CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +# CONFIG_FUSION_SAS is not set +CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_CTL=m # @@ -303,159 +529,24 @@ CONFIG_FUSION_CTL=m # CONFIG_I2O is not set # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_NETLINK_DEV=y -CONFIG_UNIX=y -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -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 is not set -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -# CONFIG_INET_IPCOMP is not set -CONFIG_INET_TUNNEL=m -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# IP: Virtual Server Configuration -# -# CONFIG_IP_VS is not set -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set - -# -# IP: Netfilter Configuration -# -CONFIG_IP_NF_CONNTRACK=m -# CONFIG_IP_NF_CT_ACCT is not set -CONFIG_IP_NF_CONNTRACK_MARK=y -CONFIG_IP_NF_CT_PROTO_SCTP=m -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -CONFIG_IP_NF_TFTP=m -CONFIG_IP_NF_AMANDA=m -CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -# CONFIG_IP_NF_MATCH_ADDRTYPE is not set -# CONFIG_IP_NF_MATCH_REALM is not set -CONFIG_IP_NF_MATCH_SCTP=m -CONFIG_IP_NF_MATCH_COMMENT=m -CONFIG_IP_NF_MATCH_CONNMARK=m -CONFIG_IP_NF_MATCH_HASHLIMIT=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_MARK=m -CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_CONNMARK=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_XFRM=y -CONFIG_XFRM_USER=m - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -CONFIG_LLC=m -CONFIG_LLC2=m -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -CONFIG_NET_PKTGEN=m -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m # CONFIG_EQUALIZER is not set CONFIG_TUN=m -# CONFIG_ETHERTAP is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -463,6 +554,7 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=m # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=m CONFIG_TYPHOON=m @@ -479,6 +571,7 @@ CONFIG_TULIP_MMIO=y # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set CONFIG_PCMCIA_XIRCOM=m # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_HP100=m @@ -489,48 +582,43 @@ CONFIG_PCNET32=m # CONFIG_B44 is not set # CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set -CONFIG_EEPRO100=m +# CONFIG_EEPRO100 is not set CONFIG_E100=m -CONFIG_E100_NAPI=y # CONFIG_FEALNX is not set -CONFIG_NATSEMI=m +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_8139CP is not set -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set -CONFIG_EPIC100=m +# CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y +# CONFIG_VIA_RHINE is not set # # Ethernet (1000 Mbit) # CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y -CONFIG_DL2K=m +# CONFIG_DL2K is not set CONFIG_E1000=m CONFIG_E1000_NAPI=y # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=m +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) # -CONFIG_IXGB=m -CONFIG_IXGB_NAPI=y -CONFIG_S2IO=m -CONFIG_S2IO_NAPI=y -# CONFIG_2BUFF_MODE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set # # Token Ring devices @@ -560,6 +648,7 @@ CONFIG_PCMCIA_RAYCS=m CONFIG_HERMES=m CONFIG_PLX_HERMES=m CONFIG_TMD_HERMES=m +# CONFIG_NORTEL_HERMES is not set CONFIG_PCI_HERMES=m # CONFIG_ATMEL is not set @@ -567,6 +656,7 @@ CONFIG_PCI_HERMES=m # Wireless 802.11b Pcmcia/Cardbus cards support # CONFIG_PCMCIA_HERMES=m +# CONFIG_PCMCIA_SPECTRUM is not set CONFIG_AIRO_CS=m CONFIG_PCMCIA_WL3501=m @@ -574,6 +664,7 @@ CONFIG_PCMCIA_WL3501=m # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support # # CONFIG_PRISM54 is not set +# CONFIG_HOSTAP is not set CONFIG_NET_WIRELESS=y # @@ -607,6 +698,8 @@ CONFIG_PPP_BSDCOMP=m # CONFIG_NET_FC 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 @@ -632,13 +725,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -# CONFIG_SERIO is not set - # # Input Device Drivers # @@ -648,6 +734,12 @@ CONFIG_SOUND_GAMEPORT=y # 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 # @@ -667,7 +759,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -677,6 +768,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_PDC_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set @@ -707,6 +799,11 @@ CONFIG_GEN_RTC_X=y CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=256 +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + # # I2C support # @@ -717,10 +814,20 @@ CONFIG_MAX_RAW_DEVS=256 # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -742,6 +849,7 @@ CONFIG_MAX_RAW_DEVS=256 CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 +# CONFIG_STI_CONSOLE is not set # # Sound @@ -751,13 +859,9 @@ CONFIG_DUMMY_CONSOLE_ROWS=64 # # USB support # -# CONFIG_USB is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# +# CONFIG_USB is not set # # USB Gadget Support @@ -772,17 +876,18 @@ CONFIG_USB_ARCH_HAS_OHCI=y # # InfiniBand support # -CONFIG_INFINIBAND=m -CONFIG_INFINIBAND_MTHCA=m -# CONFIG_INFINIBAND_MTHCA_DEBUG is not set -CONFIG_INFINIBAND_IPOIB=m -# CONFIG_INFINIBAND_IPOIB_DEBUG is not set +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# # # 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 is not set CONFIG_JBD=y @@ -794,22 +899,20 @@ CONFIG_JFS_FS=m # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# CONFIG_XFS_FS=m CONFIG_XFS_EXPORT=y -# CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT 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=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -836,13 +939,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -867,15 +968,18 @@ CONFIG_UFS_FS=m # CONFIG_NFS_FS=m CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y CONFIG_NFS_DIRECTIO=y CONFIG_NFSD=m CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m @@ -890,6 +994,7 @@ CONFIG_CIFS=m # 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 @@ -906,15 +1011,15 @@ CONFIG_NLS_CODEPAGE_437=m # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m +# CONFIG_NLS_CODEPAGE_852 is not set # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set # CONFIG_NLS_CODEPAGE_860 is not set # CONFIG_NLS_CODEPAGE_861 is not set # CONFIG_NLS_CODEPAGE_862 is not set -CONFIG_NLS_CODEPAGE_863=m +# CONFIG_NLS_CODEPAGE_863 is not set # CONFIG_NLS_CODEPAGE_864 is not set -CONFIG_NLS_CODEPAGE_865=m +# CONFIG_NLS_CODEPAGE_865 is not set # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_936 is not set @@ -926,10 +1031,10 @@ CONFIG_NLS_CODEPAGE_865=m # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set # CONFIG_NLS_ISO8859_5 is not set # CONFIG_NLS_ISO8859_6 is not set # CONFIG_NLS_ISO8859_7 is not set @@ -950,11 +1055,15 @@ CONFIG_OPROFILE=m # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # 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_IOREMAP is not set @@ -974,25 +1083,26 @@ CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_ANUBIS=m +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m +# CONFIG_CRYPTO_MICHAEL_MIC is not set CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m @@ -1004,6 +1114,7 @@ CONFIG_CRYPTO_TEST=m # Library routines # CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=m diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig index 46c9511f3229..8819e7e6ae3f 100644 --- a/arch/parisc/configs/b180_defconfig +++ b/arch/parisc/configs/b180_defconfig @@ -1,12 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-pa5 -# Wed Jan 5 13:35:54 2005 +# Linux kernel version: 2.6.14-rc5-pa1 +# Fri Oct 21 23:06:10 2005 # CONFIG_PARISC=y CONFIG_MMU=y CONFIG_STACK_GROWSUP=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y # # Code maturity level options @@ -14,33 +17,39 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_EXPERIMENTAL is not set CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=16 # CONFIG_HOTPLUG is not set CONFIG_KOBJECT_UEVENT=y -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -60,8 +69,14 @@ CONFIG_PA7100LC=y # CONFIG_PA7300LC is not set # CONFIG_PA8X00 is not set CONFIG_PA11=y -# CONFIG_64BIT is not set # CONFIG_SMP is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set # CONFIG_PREEMPT is not set # CONFIG_HPUX is not set @@ -78,11 +93,25 @@ CONFIG_EISA_NAMES=y CONFIG_ISA=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set CONFIG_GSC_DINO=y # CONFIG_PCI_LBA is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# PA-RISC specific drivers +# CONFIG_CHASSIS_LCD_LED=y # CONFIG_PDC_CHASSIS is not set +CONFIG_PDC_STABLE=y # # Executable file formats @@ -90,6 +119,64 @@ CONFIG_CHASSIS_LCD_LED=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_NETFILTER 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_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 # @@ -99,8 +186,14 @@ CONFIG_BINFMT_ELF=y # CONFIG_STANDALONE=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set +# 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) # @@ -111,10 +204,8 @@ CONFIG_STANDALONE=y # CONFIG_PARPORT=y CONFIG_PARPORT_PC=y -CONFIG_PARPORT_PC_CML1=y # CONFIG_PARPORT_SERIAL is not set CONFIG_PARPORT_GSC=y -# CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set # @@ -125,19 +216,17 @@ CONFIG_PARPORT_GSC=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE 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_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_INITRAMFS_SOURCE="" CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 # CONFIG_CDROM_PKTCDVD_WCACHE is not set @@ -149,6 +238,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +CONFIG_ATA_OVER_ETH=y # # ATA/ATAPI/MFM/RLL support @@ -158,6 +248,7 @@ CONFIG_IOSCHED_CFQ=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -170,6 +261,7 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -183,16 +275,16 @@ CONFIG_CHR_DEV_SG=y # CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set -# CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set @@ -202,14 +294,11 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_IN2000 is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_IPS is not set @@ -219,7 +308,6 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set CONFIG_SCSI_LASI700=y -CONFIG_53C700_MEM_MAPPED=y CONFIG_53C700_LE_ON_BE=y CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 @@ -231,7 +319,6 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=y @@ -240,12 +327,12 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set @@ -263,6 +350,7 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_MD_RAID5=y +CONFIG_MD_RAID6=y # CONFIG_MD_MULTIPATH is not set # CONFIG_MD_FAULTY is not set # CONFIG_BLK_DEV_DM is not set @@ -271,6 +359,9 @@ CONFIG_MD_RAID5=y # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support @@ -283,58 +374,8 @@ CONFIG_MD_RAID5=y # CONFIG_I2O is not set # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_NETLINK_DEV=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_NETFILTER 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 - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -346,6 +387,11 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -354,8 +400,8 @@ CONFIG_NET_ETHERNET=y # CONFIG_LASI_82596 is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set @@ -369,6 +415,7 @@ CONFIG_TULIP=y # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set @@ -384,12 +431,15 @@ CONFIG_TULIP=y # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_R8169 is not set +# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -413,12 +463,12 @@ CONFIG_NET_RADIO=y # # Wireless 802.11b ISA/PCI cards support # -# CONFIG_AIRO is not set # CONFIG_HERMES is not set # # Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support # +# CONFIG_HOSTAP is not set CONFIG_NET_WIRELESS=y # @@ -435,6 +485,8 @@ CONFIG_PPP=y # CONFIG_PPP_BSDCOMP is not set # CONFIG_SLIP is not set # CONFIG_NET_FC is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -463,24 +515,13 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_PARKBD is not set -CONFIG_SERIO_GSCPS2=y -# CONFIG_HP_SDC is not set -# CONFIG_SERIO_PCIPS2 is not set -# CONFIG_SERIO_RAW is not set - # # Input Device Drivers # CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y +# CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set @@ -488,7 +529,7 @@ CONFIG_INPUT_KEYBOARD=y # CONFIG_KEYBOARD_HIL_OLD is not set # CONFIG_KEYBOARD_HIL is not set CONFIG_INPUT_MOUSE=y -# CONFIG_MOUSE_PS2 is not set +CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set # CONFIG_MOUSE_INPORT is not set # CONFIG_MOUSE_LOGIBM is not set @@ -501,6 +542,19 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_UINPUT is not set # CONFIG_HP_SDC_RTC is not set +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_GSCPS2=y +# CONFIG_HP_SDC is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + # # Character devices # @@ -519,8 +573,11 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +# CONFIG_SERIAL_8250_HUB6 is not set # # Non-8250 serial port support @@ -529,6 +586,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_PDC_CONSOLE is not set 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 @@ -555,10 +613,13 @@ CONFIG_GEN_RTC=y # # Ftape, the floppy tape device driver # -# CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set +# +# TPM devices +# + # # I2C support # @@ -569,10 +630,20 @@ CONFIG_GEN_RTC=y # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -587,6 +658,11 @@ CONFIG_GEN_RTC=y # Graphics support # CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SOFT_CURSOR=y +# CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set # CONFIG_FB_CIRRUS is not set @@ -595,6 +671,7 @@ CONFIG_FB=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y +# CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set @@ -606,18 +683,19 @@ CONFIG_FB_STI=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # -# CONFIG_MDA_CONSOLE is not set -CONFIG_STI_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 -CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_STI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -630,6 +708,7 @@ CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y CONFIG_LOGO_PARISC_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -639,13 +718,9 @@ CONFIG_LOGO_PARISC_CLUT224=y # # USB support # -# CONFIG_USB is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# +# CONFIG_USB is not set # # USB Gadget Support @@ -657,24 +732,37 @@ CONFIG_USB_ARCH_HAS_OHCI=y # # CONFIG_MMC is not set +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + # # 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 is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # 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_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=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -697,11 +785,10 @@ CONFIG_JOLIET=y CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -719,15 +806,19 @@ CONFIG_RAMFS=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_TCP=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y -# CONFIG_SMB_FS is not set +CONFIG_SMB_FS=y +# CONFIG_SMB_NLS_DEFAULT is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -785,13 +876,19 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # 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_IOREMAP is not set +# CONFIG_DEBUG_FS is not set # # Security options @@ -815,6 +912,7 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set @@ -831,9 +929,14 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_TEST is not set +# +# Hardware crypto devices +# + # # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig index 67aca6ccc9b0..9d86b6b1ebd1 100644 --- a/arch/parisc/configs/c3000_defconfig +++ b/arch/parisc/configs/c3000_defconfig @@ -1,12 +1,16 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-pa5 -# Wed Jan 5 13:26:49 2005 +# Linux kernel version: 2.6.14-rc5-pa1 +# Fri Oct 21 23:06:31 2005 # CONFIG_PARISC=y CONFIG_MMU=y CONFIG_STACK_GROWSUP=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -15,26 +19,31 @@ CONFIG_EXPERIMENTAL=y # CONFIG_CLEAN_COMPILE is not set CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=16 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +53,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -66,10 +76,19 @@ CONFIG_KMOD=y CONFIG_PA8X00=y CONFIG_PA20=y CONFIG_PREFETCH=y -# CONFIG_PARISC64 is not set # CONFIG_64BIT is not set # CONFIG_SMP is not set -# CONFIG_DISCONTIGMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +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_PREEMPT is not set # CONFIG_HPUX is not set @@ -79,34 +98,215 @@ CONFIG_PREFETCH=y # CONFIG_GSC is not set CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set CONFIG_PCI_LBA=y CONFIG_IOSAPIC=y CONFIG_IOMMU_SBA=y -CONFIG_SUPERIO=y -CONFIG_CHASSIS_LCD_LED=y -# CONFIG_PDC_CHASSIS is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PC-card bridges -# - # # PCI Hotplug Support # # CONFIG_HOTPLUG_PCI is not set +# +# PA-RISC specific drivers +# +CONFIG_SUPERIO=y +CONFIG_CHASSIS_LCD_LED=y +# CONFIG_PDC_CHASSIS is not set +CONFIG_PDC_STABLE=y + # # Executable file formats # CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +# CONFIG_NETFILTER_NETLINK is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +# CONFIG_IP_NF_PPTP is not set +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +# CONFIG_IP_NF_MATCH_DCCP is not set +# CONFIG_IP_NF_MATCH_COMMENT is not set +# CONFIG_IP_NF_MATCH_HASHLIMIT is not set +# CONFIG_IP_NF_MATCH_STRING is not set +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_TARGET_NFQUEUE is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +# CONFIG_IP6_NF_MATCH_LIMIT is not set +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_MULTIPORT is not set +CONFIG_IP6_NF_MATCH_OWNER=m +# CONFIG_IP6_NF_MATCH_MARK is not set +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +# CONFIG_IP6_NF_MATCH_AHESP is not set +CONFIG_IP6_NF_MATCH_LENGTH=m +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +# CONFIG_IP6_NF_TARGET_NFQUEUE is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_TARGET_MARK is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_RAW is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + # # Device Drivers # @@ -119,6 +319,11 @@ CONFIG_BINFMT_ELF=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -141,14 +346,14 @@ CONFIG_FW_LOADER=y # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -158,6 +363,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set # # ATA/ATAPI/MFM/RLL support @@ -201,6 +407,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # 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=y # CONFIG_BLK_DEV_PDC202XX_OLD is not set # CONFIG_BLK_DEV_PDC202XX_NEW is not set @@ -218,6 +425,7 @@ CONFIG_BLK_DEV_IDEDMA=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -230,6 +438,7 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -242,7 +451,9 @@ CONFIG_SCSI_MULTI_LUN=y # SCSI Transport Attributes # CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI_FC_ATTRS=m +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -258,25 +469,26 @@ CONFIG_SCSI_FC_ATTRS=m # CONFIG_SCSI_ADVANSYS is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_AHCI is not set # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=m +# CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set CONFIG_SCSI_SATA_PROMISE=m +# CONFIG_SCSI_SATA_QSTOR is not set # CONFIG_SCSI_SATA_SX4 is not set CONFIG_SCSI_SATA_SIL=m # CONFIG_SCSI_SATA_SIS is not set # CONFIG_SCSI_SATA_ULI is not set CONFIG_SCSI_SATA_VIA=m # CONFIG_SCSI_SATA_VITESSE is not set -# CONFIG_SCSI_BUSLOGIC is not set +CONFIG_SCSI_SATA_INTEL_COMBINED=y # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set @@ -286,20 +498,17 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=m -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -CONFIG_SCSI_QLOGIC_1280=m -# CONFIG_SCSI_QLOGIC_1280_1040 is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA21XX is not set # CONFIG_SCSI_QLA22XX is not set -CONFIG_SCSI_QLA2300=m -CONFIG_SCSI_QLA2322=m -CONFIG_SCSI_QLA6312=m -CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set @@ -316,19 +525,24 @@ CONFIG_MD_RAID1=y # CONFIG_MD_RAID10 is not set # CONFIG_MD_RAID5 is not set # CONFIG_MD_RAID6 is not set -CONFIG_MD_MULTIPATH=y +# CONFIG_MD_MULTIPATH is not set # CONFIG_MD_FAULTY is not set -CONFIG_BLK_DEV_DM=y -# CONFIG_DM_CRYPT is not set -# CONFIG_DM_SNAPSHOT is not set -# CONFIG_DM_MIRROR is not set -# CONFIG_DM_ZERO is not set +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_EMC is not set # # Fusion MPT device support # -CONFIG_FUSION=m -CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_CTL=m # @@ -342,164 +556,32 @@ CONFIG_FUSION_CTL=m # CONFIG_I2O is not set # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_NETLINK_DEV=y -CONFIG_UNIX=y -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# IP: Virtual Server Configuration -# -# CONFIG_IP_VS is not set -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y - -# -# IP: Netfilter Configuration -# -CONFIG_IP_NF_CONNTRACK=m -# CONFIG_IP_NF_CT_ACCT is not set -# CONFIG_IP_NF_CONNTRACK_MARK is not set -# CONFIG_IP_NF_CT_PROTO_SCTP is not set -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -CONFIG_IP_NF_TFTP=m -CONFIG_IP_NF_AMANDA=m -CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -# CONFIG_IP_NF_MATCH_ADDRTYPE is not set -# CONFIG_IP_NF_MATCH_REALM is not set -# CONFIG_IP_NF_MATCH_SCTP is not set -# CONFIG_IP_NF_MATCH_COMMENT is not set -# CONFIG_IP_NF_MATCH_HASHLIMIT is not set -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_MARK=m -CONFIG_IP_NF_TARGET_CLASSIFY=m -# CONFIG_IP_NF_RAW is not set -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP_NF_COMPAT_IPCHAINS=m -CONFIG_IP_NF_COMPAT_IPFWADM=m -CONFIG_XFRM=y -CONFIG_XFRM_USER=m - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -CONFIG_LLC=m -CONFIG_LLC2=m -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m # CONFIG_EQUALIZER is not set CONFIG_TUN=m -# CONFIG_ETHERTAP is not set # # ARCnet devices # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=m -CONFIG_HAPPYMEAL=m +# CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # @@ -514,28 +596,22 @@ CONFIG_TULIP_MMIO=y # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y -CONFIG_PCNET32=m +# CONFIG_PCNET32 is not set # CONFIG_AMD8111_ETH is not set -CONFIG_ADAPTEC_STARFIRE=m -# CONFIG_ADAPTEC_STARFIRE_NAPI is not set -CONFIG_B44=m +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set # CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set -CONFIG_EEPRO100=m -# CONFIG_EEPRO100_PIO is not set +# CONFIG_EEPRO100 is not set CONFIG_E100=m -# CONFIG_E100_NAPI is not set # CONFIG_FEALNX is not set -CONFIG_NATSEMI=m +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_8139CP is not set -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -554,15 +630,18 @@ CONFIG_E1000=m # 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_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=m +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) # -CONFIG_IXGB=y -CONFIG_IXGB_NAPI=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set # CONFIG_S2IO is not set # @@ -593,6 +672,8 @@ CONFIG_PPPOE=m # CONFIG_NET_FC 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 @@ -621,16 +702,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1200 # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=m -CONFIG_SERIO_SERPORT=m -# CONFIG_SERIO_PCIPS2 is not set -# CONFIG_SERIO_RAW is not set - # # Input Device Drivers # @@ -648,6 +719,16 @@ CONFIG_INPUT_MOUSE=y # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set +# +# Hardware I/O ports +# +CONFIG_SERIO=m +CONFIG_SERIO_SERPORT=m +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=m +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + # # Character devices # @@ -666,7 +747,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -676,6 +756,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_PDC_CONSOLE is not set 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 @@ -698,11 +779,15 @@ CONFIG_GEN_RTC_X=y # # Ftape, the floppy tape device driver # -# CONFIG_AGP is not set # CONFIG_DRM is not set CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=256 +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + # # I2C support # @@ -713,10 +798,20 @@ CONFIG_MAX_RAW_DEVS=256 # # CONFIG_W1 is not set +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -731,6 +826,11 @@ CONFIG_MAX_RAW_DEVS=256 # Graphics support # CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SOFT_CURSOR=y +# CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set # CONFIG_FB_CIRRUS is not set @@ -739,6 +839,7 @@ CONFIG_FB=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y +# CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set @@ -751,18 +852,20 @@ CONFIG_FB_STI=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set # CONFIG_FB_PM3 is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # -CONFIG_STI_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 -CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_STI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -775,6 +878,7 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_LOGO_LINUX_CLUT224 is not set CONFIG_LOGO_PARISC_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -784,7 +888,78 @@ CONFIG_SOUND=y # # Advanced Linux Sound Architecture # -# CONFIG_SND is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_SEQUENCER=y +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_AC97_BUS=y + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +CONFIG_SND_AD1889=y +# CONFIG_SND_AD1889_OPL3 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set # # Open Sound System @@ -794,6 +969,8 @@ CONFIG_SOUND=y # # USB support # +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB=y CONFIG_USB_DEBUG=y @@ -804,23 +981,23 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG is not set -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y # # USB Host Controller Drivers # # CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_UHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set CONFIG_USB_PRINTER=m @@ -829,12 +1006,11 @@ CONFIG_USB_PRINTER=m # CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_RW_DETECT is not set -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set CONFIG_USB_STORAGE_DPCM=y -CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_USBAT=y CONFIG_USB_STORAGE_SDDR09=y CONFIG_USB_STORAGE_SDDR55=y CONFIG_USB_STORAGE_JUMPSHOT=y @@ -846,21 +1022,25 @@ CONFIG_USB_HID=y CONFIG_USB_HIDINPUT=y # CONFIG_HID_FF is not set CONFIG_USB_HIDDEV=y -CONFIG_USB_AIPTEK=m -CONFIG_USB_WACOM=m -CONFIG_USB_KBTAB=m +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices # CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m -CONFIG_USB_HPUSBSCSI=m # # USB Multimedia devices @@ -879,6 +1059,7 @@ CONFIG_USB_HPUSBSCSI=m # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +# CONFIG_USB_MON is not set # # USB port drivers @@ -894,7 +1075,6 @@ CONFIG_USB_HPUSBSCSI=m # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set CONFIG_USB_LEGOTOWER=m @@ -903,10 +1083,12 @@ CONFIG_USB_LEGOTOWER=m # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_LD is not set # CONFIG_USB_TEST is not set # -# USB ATM/DSL drivers +# USB DSL modem support # # @@ -919,28 +1101,42 @@ CONFIG_USB_LEGOTOWER=m # # CONFIG_MMC is not set +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + # # 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 is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set CONFIG_XFS_FS=m -# CONFIG_XFS_RT is not set +CONFIG_XFS_EXPORT=y # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT 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=y +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -966,13 +1162,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -996,16 +1190,19 @@ CONFIG_RAMFS=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -1014,6 +1211,7 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -1074,13 +1272,19 @@ CONFIG_OPROFILE=m # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # 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_IOREMAP is not set +# CONFIG_DEBUG_FS is not set # # Security options @@ -1092,21 +1296,22 @@ CONFIG_MAGIC_SYSRQ=y # Cryptographic options # CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_HMAC is not set CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m +# CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set # CONFIG_CRYPTO_KHAZAD is not set @@ -1116,10 +1321,15 @@ CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_TEST=m +# +# Hardware crypto devices +# + # # Library routines # CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=m diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig index fdae21c503d7..f38a4620d24f 100644 --- a/arch/parisc/defconfig +++ b/arch/parisc/defconfig @@ -1,38 +1,56 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.14-rc5-pa1 +# Fri Oct 21 23:01:33 2005 # CONFIG_PARISC=y CONFIG_MMU=y CONFIG_STACK_GROWSUP=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_AUDIT is not set # CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -45,10 +63,21 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_PA7000=y # CONFIG_PA7100LC is not set # CONFIG_PA7200 is not set +# CONFIG_PA7300LC is not set # CONFIG_PA8X00 is not set CONFIG_PA11=y -# CONFIG_64BIT is not set # CONFIG_SMP is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +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_PREEMPT is not set # CONFIG_HPUX is not set @@ -65,14 +94,29 @@ CONFIG_EISA_NAMES=y # CONFIG_ISA is not set CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set CONFIG_GSC_DINO=y CONFIG_PCI_LBA=y CONFIG_IOSAPIC=y CONFIG_IOMMU_SBA=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# PA-RISC specific drivers +# CONFIG_SUPERIO=y CONFIG_CHASSIS_LCD_LED=y CONFIG_PDC_CHASSIS=y +CONFIG_PDC_STABLE=y # # Executable file formats @@ -80,6 +124,80 @@ CONFIG_PDC_CHASSIS=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_IPV6_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 +# 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 +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 # @@ -87,8 +205,16 @@ CONFIG_BINFMT_ELF=y # # 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) # @@ -99,12 +225,10 @@ CONFIG_BINFMT_ELF=y # CONFIG_PARPORT=y CONFIG_PARPORT_PC=y -CONFIG_PARPORT_PC_CML1=y # CONFIG_PARPORT_SERIAL is not set # CONFIG_PARPORT_PC_FIFO is not set # CONFIG_PARPORT_PC_SUPERIO is not set CONFIG_PARPORT_GSC=y -# CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set # @@ -114,18 +238,31 @@ CONFIG_PARPORT_GSC=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_PARIDE 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=y # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set # # ATA/ATAPI/MFM/RLL support @@ -135,6 +272,7 @@ CONFIG_BLK_DEV_INITRD=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -147,53 +285,59 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + # # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_PPA is not set # CONFIG_SCSI_IMM is not set CONFIG_SCSI_LASI700=y -CONFIG_53C700_MEM_MAPPED=y CONFIG_53C700_LE_ON_BE=y CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set CONFIG_SCSI_ZALON=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=y @@ -202,7 +346,8 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -217,15 +362,20 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=y # CONFIG_MD_RAID6 is not set # CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set # CONFIG_BLK_DEV_DM is not set # # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support @@ -238,80 +388,23 @@ CONFIG_MD_RAID5=y # CONFIG_I2O is not set # -# Macintosh device drivers +# Network device support # - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_NETLINK_DEV=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -CONFIG_IPV6_SCTP__=y -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q 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 -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # ARCnet devices # # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set # # Ethernet (10 or 100Mbit) @@ -321,6 +414,7 @@ CONFIG_NET_ETHERNET=y CONFIG_LASI_82596=y # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_NET_VENDOR_SMC is not set @@ -336,6 +430,7 @@ CONFIG_TULIP=y # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set # CONFIG_DEPCA is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y @@ -361,30 +456,37 @@ CONFIG_NET_PCI=y # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_ACENIC is not set -CONFIG_DL2K=y +CONFIG_ACENIC=y +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_DL2K is not set # CONFIG_E1000 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_SK98LIN is not set -# CONFIG_TIGON3 is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_TIGON3=y +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set # # Wireless LAN (non-hamradio) @@ -399,38 +501,30 @@ CONFIG_NET_RADIO=y # # Wireless 802.11b ISA/PCI cards support # -CONFIG_AIRO=y # CONFIG_HERMES is not set # CONFIG_ATMEL is not set -CONFIG_NET_WIRELESS=y # -# Token Ring devices +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support # -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set +# CONFIG_PRISM54 is not set +# CONFIG_HOSTAP is not set +CONFIG_NET_WIRELESS=y # # Wan interfaces # # CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC 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 @@ -460,10 +554,56 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_HIL_OLD=y +CONFIG_KEYBOARD_HIL=y +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_HIL is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_DB9 is not set +# CONFIG_JOYSTICK_GAMECON is not set +# CONFIG_JOYSTICK_TURBOGRAFX is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_UINPUT is not set +CONFIG_HP_SDC_RTC=y + +# +# Hardware I/O ports # -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y CONFIG_SERIO=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_PARKBD is not set @@ -471,38 +611,8 @@ CONFIG_SERIO_GSCPS2=y CONFIG_HP_SDC=y CONFIG_HIL_MLC=y # CONFIG_SERIO_PCIPS2 is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ATKBD is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -CONFIG_KEYBOARD_HIL=y -CONFIG_INPUT_MOUSE=y -# CONFIG_MOUSE_PS2 is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_HIL is not set -CONFIG_INPUT_JOYSTICK=y -# CONFIG_JOYSTICK_IFORCE is not set -# CONFIG_JOYSTICK_WARRIOR is not set -# CONFIG_JOYSTICK_MAGELLAN is not set -# CONFIG_JOYSTICK_SPACEORB is not set -# CONFIG_JOYSTICK_SPACEBALL is not set -# CONFIG_JOYSTICK_STINGER is not set -# CONFIG_JOYSTICK_TWIDDLER is not set -# CONFIG_JOYSTICK_DB9 is not set -# CONFIG_JOYSTICK_GAMECON is not set -# CONFIG_JOYSTICK_TURBOGRAFX is not set -# CONFIG_INPUT_JOYDUMP is not set -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_GUNZE is not set -CONFIG_INPUT_MISC=y -# CONFIG_INPUT_PCSPKR is not set -# CONFIG_INPUT_UINPUT is not set -CONFIG_HP_SDC_RTC=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set # # Character devices @@ -522,16 +632,16 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # # Non-8250 serial port support # -# CONFIG_SERIAL_MUX is not set -# CONFIG_PDC_CONSOLE is not set +CONFIG_SERIAL_MUX=y +CONFIG_SERIAL_MUX_CONSOLE=y 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 @@ -540,12 +650,6 @@ CONFIG_PRINTER=y # CONFIG_PPDEV is not set # CONFIG_TIPAR is not set -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set - # # IPMI # @@ -555,7 +659,6 @@ CONFIG_PRINTER=y # 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 @@ -565,20 +668,39 @@ CONFIG_GEN_RTC=y # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + # # I2C support # # CONFIG_I2C 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_HWMON_DEBUG_CHIP is not set + # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -593,34 +715,45 @@ CONFIG_GEN_RTC=y # Graphics support # CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SOFT_CURSOR=y +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y +# CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_ATY is not set +# CONFIG_FB_SAVAGE is not set # CONFIG_FB_SIS is not set # CONFIG_FB_NEOMAGIC is not set # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # -# CONFIG_MDA_CONSOLE is not set -CONFIG_STI_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 -CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y +CONFIG_STI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -629,6 +762,7 @@ CONFIG_FONT_8x16=y # Logo configuration # # CONFIG_LOGO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -638,17 +772,94 @@ CONFIG_SOUND=y # # Advanced Linux Sound Architecture # -# CONFIG_SND is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_SEQUENCER=y +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_AC97_BUS=y + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +CONFIG_SND_AD1889=y +# CONFIG_SND_AD1889_OPL3 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# GSC devices +# +CONFIG_SND_HARMONY=y # # Open Sound System # # CONFIG_SOUND_PRIME is not set -# CONFIG_SOUND_HARMONY is not set # # USB support # +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB=y CONFIG_USB_DEBUG=y @@ -658,26 +869,36 @@ CONFIG_USB_DEBUG=y # CONFIG_USB_DEVICEFS is not set # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set # # USB Host Controller Drivers # CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # CONFIG_USB_STORAGE is not set # -# USB Human Interface Devices (HID) +# USB Input Devices # # CONFIG_USB_HID is not set @@ -688,16 +909,23 @@ CONFIG_USB_OHCI_HCD=y # CONFIG_USB_MOUSE is not set # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices # # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set # # USB Multimedia devices @@ -709,13 +937,15 @@ CONFIG_USB_OHCI_HCD=y # # -# USB Network adaptors +# USB Network Adapters # # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +# CONFIG_USB_ZD1201 is not set +CONFIG_USB_MON=y # # USB port drivers @@ -732,35 +962,63 @@ CONFIG_USB_OHCI_HCD=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETKIT is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set + +# +# USB DSL modem support +# # # USB Gadget Support # # CONFIG_USB_GADGET is not set +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + # # 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 is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # 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_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 @@ -773,7 +1031,8 @@ CONFIG_JOLIET=y # # DOS/FAT/NT Filesystems # -# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_NTFS_FS is not set # @@ -781,11 +1040,11 @@ CONFIG_JOLIET=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -809,23 +1068,28 @@ CONFIG_RAMFS=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set CONFIG_NFSD_TCP=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set +# 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 @@ -861,6 +1125,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -885,17 +1150,24 @@ CONFIG_OPROFILE=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_RWLOCK is not set -CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_IOREMAP is not set +# CONFIG_DEBUG_FS is not set # # Security options # +# CONFIG_KEYS is not set # CONFIG_SECURITY is not set # @@ -909,6 +1181,8 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_SHA1 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set @@ -916,11 +1190,23 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_TEST is not set +# +# Hardware crypto devices +# + # # Library routines # +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set From 6958ae318bb1af5e0b77968384700fb184fb8893 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Oct 2005 23:11:27 -0400 Subject: [PATCH 0625/1939] [PARISC] Update MAINTAINERS and CREDITS Add Kyle McMartin and Thibaut Varene as maintainers for ALSA ad1889 driver. Add myself to CREDITS. Signed-off-by: Kyle McMartin --- CREDITS | 6 ++++++ MAINTAINERS | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/CREDITS b/CREDITS index a347520bef2d..5b1edf3a38a2 100644 --- a/CREDITS +++ b/CREDITS @@ -2247,6 +2247,12 @@ S: 249 Nichols Avenue S: Syracuse, New York 13206 S: USA +N: Kyle McMartin +E: kyle@parisc-linux.org +D: Linux/PARISC hacker +D: AD1889 sound driver +S: Ottawa, Canada + N: Dirk Melchers E: dirk@merlin.nbg.sub.org D: 8 bit XT hard disk driver for OMTI5520 diff --git a/MAINTAINERS b/MAINTAINERS index 767fb610963e..248b93b32fc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -197,6 +197,15 @@ M: Thorsten Knabe W: http://linux.thorsten-knabe.de S: Maintained +AD1889 SOUND DRIVER +P: Kyle McMartin +M: kyle@parisc-linux.org +P: Thibaut Varene +M: T-Bone@parisc-linux.org +W: http://wiki.parisc-linux.org/AD1889 +L: parisc-linux@lists.parisc-linux.org +S: Maintained + ADM1025 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org From 2d5a2ae52d8863275e2d26398bc010249ea709d1 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 22 Oct 2005 00:14:31 -0400 Subject: [PATCH 0626/1939] drivers/block/sx8: several minor changes * Newer hardware doesn't corrupt data when the queue depth is greater than one. Rather than force the user to recompile with a greater queue depth, make it a module parameter. * update copyright date * add MODULE_VERSION() * trim trailing whitespace * move CARM_SG_BOUNDARY to a separate enum, since its unsigned long * bump to version 1.0 --- drivers/block/sx8.c | 50 +++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index d57007b92f77..b5f612679a31 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1,7 +1,7 @@ /* * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware * - * Copyright 2004 Red Hat, Inc. + * Copyright 2004-2005 Red Hat, Inc. * * Author/maintainer: Jeff Garzik * @@ -31,10 +31,6 @@ #include #include -MODULE_AUTHOR("Jeff Garzik"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Promise SATA SX8 block driver"); - #if 0 #define CARM_DEBUG #define CARM_VERBOSE_DEBUG @@ -45,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver"); #undef CARM_NDEBUG #define DRV_NAME "sx8" -#define DRV_VERSION "0.8" +#define DRV_VERSION "1.0" #define PFX DRV_NAME ": " +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SATA SX8 block driver"); +MODULE_VERSION(DRV_VERSION); + +/* + * SX8 hardware has a single message queue for all ATA ports. + * When this driver was written, the hardware (firmware?) would + * corrupt data eventually, if more than one request was outstanding. + * As one can imagine, having 8 ports bottlenecking on a single + * command hurts performance. + * + * Based on user reports, later versions of the hardware (firmware?) + * seem to be able to survive with more than one command queued. + * + * Therefore, we default to the safe option -- 1 command -- but + * allow the user to increase this. + * + * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ), + * but problems seem to occur when you exceed ~30, even on newer hardware. + */ +static int max_queue = 1; +module_param(max_queue, int, 0444); +MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)"); + + #define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) /* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ @@ -90,12 +112,10 @@ enum { /* command message queue limits */ CARM_MAX_REQ = 64, /* max command msgs per host */ - CARM_MAX_Q = 1, /* one command at a time */ CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ /* S/G limits, host-wide and per-request */ CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ - CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ @@ -181,6 +201,10 @@ enum { FL_DYN_MAJOR = (1 << 17), }; +enum { + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ +}; + enum scatter_gather_types { SGT_32BIT = 0, SGT_64BIT = 1, @@ -448,7 +472,7 @@ static inline int carm_lookup_bucket(u32 msg_size) for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) if (msg_size <= msg_sizes[i]) return i; - + return -ENOENT; } @@ -509,7 +533,7 @@ static struct carm_request *carm_get_request(struct carm_host *host) if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) return NULL; - for (i = 0; i < CARM_MAX_Q; i++) + for (i = 0; i < max_queue; i++) if ((host->msg_alloc & (1ULL << i)) == 0) { struct carm_request *crq = &host->req[i]; crq->port = NULL; @@ -521,14 +545,14 @@ static struct carm_request *carm_get_request(struct carm_host *host) assert(host->n_msgs <= CARM_MAX_REQ); return crq; } - + DPRINTK("no request available, returning NULL\n"); return NULL; } static int carm_put_request(struct carm_host *host, struct carm_request *crq) { - assert(crq->tag < CARM_MAX_Q); + assert(crq->tag < max_queue); if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) return -EINVAL; /* tried to clear a tag that was not active */ @@ -791,7 +815,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, int is_ok) { carm_end_request_queued(host, crq, is_ok); - if (CARM_MAX_Q == 1) + if (max_queue == 1) carm_round_robin(host); else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && (host->hw_sg_used <= CARM_SG_LOW_WATER)) { From cf482935c6abe5245e481213c6e6df808c976f56 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 22 Oct 2005 00:19:33 -0400 Subject: [PATCH 0627/1939] libata: turn on block layer clustering --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 0e214f8c8f9f..634b5aa0a615 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -91,7 +91,7 @@ enum { ATA_SHT_EMULATED = 1, ATA_SHT_CMD_PER_LUN = 1, ATA_SHT_THIS_ID = -1, - ATA_SHT_USE_CLUSTERING = 0, + ATA_SHT_USE_CLUSTERING = 1, /* struct ata_device stuff */ ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ From 5c8c56ebdfb290e4feaac406518903f58714d874 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 14:42:51 +1000 Subject: [PATCH 0628/1939] powerpc: Move agp_special_page export to where it is defined ... instead of exporting it in arch/*/kernel/ppc_ksyms.c. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ppc_ksyms.c | 4 ---- arch/powerpc/mm/init_32.c | 1 + arch/ppc/kernel/ppc_ksyms.c | 4 ---- arch/ppc/mm/init.c | 1 + 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 40c9e67e1b28..254bf9c0b5bb 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -274,10 +274,6 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ extern long *intercept_table; EXPORT_SYMBOL(intercept_table); #endif /* CONFIG_PPC_STD_MMU_32 */ -#ifdef CONFIG_PPC_PMAC -extern unsigned long agp_special_page; -EXPORT_SYMBOL(agp_special_page); -#endif #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) EXPORT_SYMBOL(__mtdcr); EXPORT_SYMBOL(__mfdcr); diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index caeb02ee72c5..aa6a5440cec1 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -69,6 +69,7 @@ unsigned long ppc_memoffset = PAGE_OFFSET; int boot_mapsize; #ifdef CONFIG_PPC_PMAC unsigned long agp_special_page; +EXPORT_SYMBOL(agp_special_page); #endif #ifdef CONFIG_HIGHMEM diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index f4373fb9181f..dcc83440f203 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -323,10 +323,6 @@ extern long *intercept_table; EXPORT_SYMBOL(intercept_table); #endif /* CONFIG_PPC_STD_MMU */ EXPORT_SYMBOL(cur_cpu_spec); -#ifdef CONFIG_PPC_PMAC -extern unsigned long agp_special_page; -EXPORT_SYMBOL(agp_special_page); -#endif #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) EXPORT_SYMBOL(__mtdcr); EXPORT_SYMBOL(__mfdcr); diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 5e9ef23b4671..db94efd25369 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -69,6 +69,7 @@ int init_bootmem_done; int boot_mapsize; #ifdef CONFIG_PPC_PMAC unsigned long agp_special_page; +EXPORT_SYMBOL(agp_special_page); #endif extern char _end[]; From e2b5530698cbe8148577b24097eaefcd835ac9ca Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 14:46:33 +1000 Subject: [PATCH 0629/1939] ppc64: Fix delivery of RT signals to 32-bit processes. An error in merging led to 32-bit processes getting the wrong link register value on entry to RT signal handlers, and the wrong stack chain as well. This fixes it. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/signal_32.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 1c4eac4c808f..92452b2db26a 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -821,7 +821,7 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, goto badframe; regs->link = (unsigned long) frame->tramp; } - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) + if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe; regs->gpr[1] = newsp; regs->gpr[3] = sig; @@ -829,7 +829,6 @@ 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; - regs->link = (unsigned long) frame->tramp; regs->trap = 0; #ifdef CONFIG_PPC64 regs->result = 0; From a5b518ed314bfd25ea5e433ce09f8b27080023db Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 14:55:23 +1000 Subject: [PATCH 0630/1939] ppc64/powerpc: Fix time initialization on SMP systems This moves smp_space_timers from arch/ppc64/kernel/smp.c to arch/powerpc/kernel/time.c and makes it initialize last_jiffy[] instead of paca[].next_jiffy_update_tb, since last_jiffy[] is now what the time code uses. It also declares smp_space_timers in include/asm-powerpc/time.h and gets rid of an ifdef in div128_by_32. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 14 +------------- arch/ppc64/kernel/smp.c | 15 --------------- include/asm-powerpc/time.h | 8 +++++--- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 3e722370113b..b635c7de6698 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -458,7 +458,7 @@ void wakeup_decrementer(void) per_cpu(last_jiffy, i) = tb_last_stamp; } -#ifdef CONFIG_SMPxxx +#ifdef CONFIG_SMP void __init smp_space_timers(unsigned int max_cpus) { int i; @@ -948,16 +948,6 @@ void div128_by_32(u64 dividend_high, u64 dividend_low, w = a / divisor; ra = ((u64)(a - (w * divisor)) << 32) + b; -#ifdef CONFIG_PPC64 - x = ra / divisor; - rb = ((ra - (x * divisor)) << 32) + c; - - y = rb / divisor; - rc = ((rb - (y * divisor)) << 32) + d; - - z = rc / divisor; -#else - /* for 32-bit, use do_div from div64.h */ rb = ((u64) do_div(ra, divisor) << 32) + c; x = ra; @@ -966,10 +956,8 @@ void div128_by_32(u64 dividend_high, u64 dividend_low, do_div(rc, divisor); z = rc; -#endif dr->result_high = ((u64)w << 32) + x; dr->result_low = ((u64)y << 32) + z; } - diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 192e3239fadc..017c12919832 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -105,21 +105,6 @@ void __devinit smp_generic_kick_cpu(int nr) #endif /* CONFIG_MPIC */ -static void __init smp_space_timers(unsigned int max_cpus) -{ - int i; - unsigned long offset = tb_ticks_per_jiffy / max_cpus; - unsigned long previous_tb = paca[boot_cpuid].next_jiffy_update_tb; - - for_each_cpu(i) { - if (i != boot_cpuid) { - paca[i].next_jiffy_update_tb = - previous_tb + offset; - previous_tb = paca[i].next_jiffy_update_tb; - } - } -} - void smp_message_recv(int msg, struct pt_regs *regs) { switch(msg) { diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index f8ef186c81e4..99bfe3281768 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -196,9 +196,11 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp) extern u64 mulhdu(u64, u64); #endif -unsigned mulhwu_scale_factor(unsigned, unsigned); -void div128_by_32(u64 dividend_high, u64 dividend_low, - unsigned divisor, struct div_result *dr); +extern void smp_space_timers(unsigned int); + +extern unsigned mulhwu_scale_factor(unsigned, unsigned); +extern void div128_by_32(u64 dividend_high, u64 dividend_low, + unsigned divisor, struct div_result *dr); /* Used to store Processor Utilization register (purr) values */ From f7abbc190b0edec34627d5348ba1d5fa5577da77 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 15:03:21 +1000 Subject: [PATCH 0631/1939] ppc64: Add a `primary' argument to pci_process_bridge_OF_ranges ... for consistency with ppc32 and to make the powermac merge easier. Also make it use just a single resource in the host bridge for multiple consecutive elements of the ranges property. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/maple_pci.c | 2 +- arch/ppc64/kernel/pci.c | 38 +++++++++++++++++++++++++++------- arch/ppc64/kernel/rtas_pci.c | 4 ++-- include/asm-ppc64/pci-bridge.h | 2 +- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index b901470f55cc..633324b5e61b 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -359,7 +359,7 @@ static int __init add_bridge(struct device_node *dev) /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev); + pci_process_bridge_OF_ranges(hose, dev, primary); pci_setup_phb_io(hose, primary); /* Fixup "bus-range" OF property */ diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index feec06bbafc3..b2fb6746f00b 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -880,9 +880,9 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, } void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev) + struct device_node *dev, int prim) { - unsigned int *ranges; + unsigned int *ranges, pci_space; unsigned long size; int rlen = 0; int memno = 0; @@ -905,16 +905,39 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, ranges = (unsigned int *) get_property(dev, "ranges", &rlen); while ((rlen -= np * sizeof(unsigned int)) >= 0) { res = NULL; - pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; + pci_space = ranges[0]; + pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2]; cpu_phys_addr = ranges[3]; - if (na == 2) - cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; + if (na >= 2) + cpu_phys_addr = (cpu_phys_addr << 32) | ranges[4]; - size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; + size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4]; + ranges += np; if (size == 0) continue; - switch ((ranges[0] >> 24) & 0x3) { + + /* Now consume following elements while they are contiguous */ + while (rlen >= np * sizeof(unsigned int)) { + unsigned long addr, phys; + + if (ranges[0] != pci_space) + break; + addr = ((unsigned long)ranges[1] << 32) | ranges[2]; + phys = ranges[3]; + if (na >= 2) + phys = (phys << 32) | ranges[4]; + if (addr != pci_addr + size || + phys != cpu_phys_addr + size) + break; + + size += ((unsigned long)ranges[na+3] << 32) + | ranges[na+4]; + ranges += np; + rlen -= np * sizeof(unsigned int); + } + + switch ((pci_space >> 24) & 0x3) { case 1: /* I/O space */ hose->io_base_phys = cpu_phys_addr; hose->pci_io_size = size; @@ -948,7 +971,6 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, res->sibling = NULL; res->child = NULL; } - ranges += np; } } diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 20361bcd8cfb..3ad15c90fbbd 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -400,7 +400,7 @@ unsigned long __init find_and_init_phbs(void) if (!phb) continue; - pci_process_bridge_OF_ranges(phb, node); + pci_process_bridge_OF_ranges(phb, node, 0); pci_setup_phb_io(phb, index == 0); #ifdef CONFIG_PPC_PSERIES if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { @@ -450,7 +450,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) if (!phb) return NULL; - pci_process_bridge_OF_ranges(phb, dn); + pci_process_bridge_OF_ranges(phb, dn, primary); pci_setup_phb_io_dynamic(phb, primary); of_node_put(root); diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 7d8ecb507a3d..60cf8c838af0 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -123,7 +123,7 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus) } extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev); + struct device_node *dev, int primary); extern int pcibios_remove_root_bus(struct pci_controller *phb); From 7bbaa75452c77cbaa016b987765c5d6c8b744587 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 22 Oct 2005 01:33:18 -0400 Subject: [PATCH 0632/1939] drivers/block/sx8: kill unused variable --- drivers/block/sx8.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index b5f612679a31..1ded3b433459 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -242,7 +242,6 @@ static const char *state_name[] = { struct carm_port { unsigned int port_no; - unsigned int n_queued; struct gendisk *disk; struct carm_host *host; From 529294d59fdc77bf15f00f2308bbeb73e03e7042 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 15:36:52 +1000 Subject: [PATCH 0633/1939] ppc64: Rearrange btext initialization for consistency with ppc32 Moved init_boot_display from arch/ppc64/kernel/pmac_setup.c to arch/ppc64/kernel/btext.c and declared it in asm-ppc64/btext.h. Call it from init_early rather than pmac_init_early. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/btext.c | 42 +++++++++++++++++++++++++++++ arch/ppc64/kernel/pmac_setup.c | 49 ---------------------------------- arch/ppc64/kernel/setup.c | 4 +++ include/asm-ppc64/btext.h | 1 + 4 files changed, 47 insertions(+), 49 deletions(-) diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c index b6fbfbe9032d..506a37885c5c 100644 --- a/arch/ppc64/kernel/btext.c +++ b/arch/ppc64/kernel/btext.c @@ -18,6 +18,7 @@ #include #include #include +#include #undef NO_SCROLL @@ -131,6 +132,47 @@ int btext_initialize(struct device_node *np) return 0; } +static void btext_putc(unsigned char c) +{ + btext_drawchar(c); +} + +void __init init_boot_display(void) +{ + char *name; + struct device_node *np = NULL; + int rc = -ENODEV; + + printk("trying to initialize btext ...\n"); + + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name != NULL) { + np = of_find_node_by_path(name); + if (np != NULL) { + if (strcmp(np->type, "display") != 0) { + printk("boot stdout isn't a display !\n"); + of_node_put(np); + np = NULL; + } + } + } + if (np) + rc = btext_initialize(np); + if (rc) { + for (np = NULL; (np = of_find_node_by_type(np, "display"));) { + if (get_property(np, "linux,opened", NULL)) { + printk("trying %s ...\n", np->full_name); + rc = btext_initialize(np); + printk("result: %d\n", rc); + } + if (rc == 0) + break; + } + } + if (rc == 0 && udbg_putc == NULL) + udbg_putc = btext_putc; +} + /* Calc the base address of a given point (x,y) */ static unsigned char * calc_base(int x, int y) diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index c059805d8cce..c3ea73df937d 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -274,48 +274,6 @@ static void pmac_halt(void) pmac_power_off(); } -#ifdef CONFIG_BOOTX_TEXT -static void btext_putc(unsigned char c) -{ - btext_drawchar(c); -} - -static void __init init_boot_display(void) -{ - char *name; - struct device_node *np = NULL; - int rc = -ENODEV; - - printk("trying to initialize btext ...\n"); - - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name != NULL) { - np = of_find_node_by_path(name); - if (np != NULL) { - if (strcmp(np->type, "display") != 0) { - printk("boot stdout isn't a display !\n"); - of_node_put(np); - np = NULL; - } - } - } - if (np) - rc = btext_initialize(np); - if (rc == 0) - return; - - for (np = NULL; (np = of_find_node_by_type(np, "display"));) { - if (get_property(np, "linux,opened", NULL)) { - printk("trying %s ...\n", np->full_name); - rc = btext_initialize(np); - printk("result: %d\n", rc); - } - if (rc == 0) - return; - } -} -#endif /* CONFIG_BOOTX_TEXT */ - /* * Early initialization. */ @@ -333,13 +291,6 @@ static void __init pmac_init_early(void) sccdbg = 1; udbg_init_scc(NULL); } -#ifdef CONFIG_BOOTX_TEXT - else { - init_boot_display(); - - udbg_putc = btext_putc; - } -#endif /* CONFIG_BOOTX_TEXT */ /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index b7885028fcf1..44ee6ebe9a60 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -585,6 +585,10 @@ void __init setup_system(void) */ finish_device_tree(); +#ifdef CONFIG_BOOTX_TEXT + init_boot_display(); +#endif + /* * Initialize xmon */ diff --git a/include/asm-ppc64/btext.h b/include/asm-ppc64/btext.h index 67aef0cc72c0..71cce36bc630 100644 --- a/include/asm-ppc64/btext.h +++ b/include/asm-ppc64/btext.h @@ -15,6 +15,7 @@ extern int boot_text_mapped; extern int btext_initialize(struct device_node *np); extern void map_boot_text(void); +extern void init_boot_display(void); extern void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch); From ef1a12817aebc313049d226f96eee86e4bcc94a3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 15:55:58 +1000 Subject: [PATCH 0634/1939] ppc64: Simplify secondary CPU startup on powermacs ... for consistency with ppc32, and because this way is neater. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/head.S | 25 +++++++++++-------------- arch/ppc64/kernel/pmac_smp.c | 21 ++++----------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 15c5f0c48043..f58af9c246cb 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1556,20 +1556,17 @@ copy_to_here: .section ".text"; .align 2 ; - .globl pmac_secondary_start_1 -pmac_secondary_start_1: - li r24, 1 - b .pmac_secondary_start - - .globl pmac_secondary_start_2 -pmac_secondary_start_2: - li r24, 2 - b .pmac_secondary_start - - .globl pmac_secondary_start_3 -pmac_secondary_start_3: - li r24, 3 - b .pmac_secondary_start + .globl __secondary_start_pmac_0 +__secondary_start_pmac_0: + /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ + li r24,0 + b 1f + li r24,1 + b 1f + li r24,2 + b 1f + li r24,3 +1: _GLOBAL(pmac_secondary_start) /* turn on 64-bit mode */ diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index 3a1683f5b07f..83c2f8dc1ec6 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -59,9 +59,7 @@ #define DBG(fmt...) #endif -extern void pmac_secondary_start_1(void); -extern void pmac_secondary_start_2(void); -extern void pmac_secondary_start_3(void); +extern void __secondary_start_pmac_0(void); extern struct smp_ops_t *smp_ops; @@ -236,7 +234,7 @@ static int __init smp_core99_probe(void) static void __init smp_core99_kick_cpu(int nr) { - int save_vector, j; + unsigned int save_vector, j; unsigned long new_vector; unsigned long flags; volatile unsigned int *vector @@ -253,20 +251,9 @@ static void __init smp_core99_kick_cpu(int nr) save_vector = *vector; /* Setup fake reset vector that does - * b .pmac_secondary_start - KERNELBASE + * b __secondary_start_pmac_0 + nr*8 - KERNELBASE */ - switch(nr) { - case 1: - new_vector = (unsigned long)pmac_secondary_start_1; - break; - case 2: - new_vector = (unsigned long)pmac_secondary_start_2; - break; - case 3: - default: - new_vector = (unsigned long)pmac_secondary_start_3; - break; - } + new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; *vector = 0x48000002 + (new_vector - KERNELBASE); /* flush data cache and inval instruction cache */ From b6ba92819dc1304a4e5a0bf06b297c657b58168a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 15:57:55 +1000 Subject: [PATCH 0635/1939] powerpc: Make set_rtc_time() return error code from lower-level function Previously it ignored the return value from ppc_md.set_rtc_time, but in fact the functions that that can point to do return a useful error code, so return it from set_rtc_time(). Signed-off-by: Paul Mackerras --- include/asm-powerpc/rtc.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/asm-powerpc/rtc.h b/include/asm-powerpc/rtc.h index d38f2a077db2..f5802926b6c0 100644 --- a/include/asm-powerpc/rtc.h +++ b/include/asm-powerpc/rtc.h @@ -52,10 +52,8 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) /* Set the current date and time in the real time clock. */ static inline int set_rtc_time(struct rtc_time *time) { - if (ppc_md.get_rtc_time) { - ppc_md.set_rtc_time(time); - return 0; - } + if (ppc_md.set_rtc_time) + return ppc_md.set_rtc_time(time); return -EINVAL; } From 35499c0195e46f479cf6ac16ad8d3f394b5fcc10 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 16:02:39 +1000 Subject: [PATCH 0636/1939] powerpc: Merge in 64-bit powermac support. This brings in a lot of changes from arch/ppc64/kernel/pmac_*.c to arch/powerpc/platforms/powermac/*.c and makes various minor tweaks elsewhere. On the powermac we now initialize ppc_md by copying the whole pmac_md structure into it, which required some changes in the ordering of initializations of individual fields of it. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/head_64.S | 25 +- arch/powerpc/kernel/prom_init.c | 4 +- arch/powerpc/kernel/setup_32.c | 7 +- arch/powerpc/platforms/Makefile | 2 +- arch/powerpc/platforms/powermac/Makefile | 6 +- arch/powerpc/platforms/powermac/feature.c | 5 +- arch/powerpc/platforms/powermac/nvram.c | 183 +++++--- arch/powerpc/platforms/powermac/pci.c | 476 ++++++++----------- arch/powerpc/platforms/powermac/pic.c | 2 +- arch/powerpc/platforms/powermac/pmac.h | 4 +- arch/powerpc/platforms/powermac/setup.c | 462 +++++++++++++------ arch/powerpc/platforms/powermac/smp.c | 532 ++++++++++++++-------- arch/powerpc/platforms/powermac/time.c | 280 +++++++----- include/asm-powerpc/machdep.h | 6 +- include/asm-ppc64/system.h | 2 + include/asm-ppc64/udbg.h | 3 + 17 files changed, 1163 insertions(+), 837 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index e70f7049cc6f..27f122e1f849 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -290,6 +290,7 @@ config PPC_PMAC config PPC_PMAC64 bool depends on PPC_PMAC && POWER4 + select U3_DART default y config PPC_PREP diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 72b0d26e41d4..147215a0d6c0 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1501,20 +1501,17 @@ copy_to_here: .section ".text"; .align 2 ; - .globl pmac_secondary_start_1 -pmac_secondary_start_1: - li r24, 1 - b .pmac_secondary_start - - .globl pmac_secondary_start_2 -pmac_secondary_start_2: - li r24, 2 - b .pmac_secondary_start - - .globl pmac_secondary_start_3 -pmac_secondary_start_3: - li r24, 3 - b .pmac_secondary_start + .globl __secondary_start_pmac_0 +__secondary_start_pmac_0: + /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ + li r24,0 + b 1f + li r24,1 + b 1f + li r24,2 + b 1f + li r24,3 +1: _GLOBAL(pmac_secondary_start) /* turn on 64-bit mode */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 9b1baaa9eda0..095659d51b4b 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -772,7 +772,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp) } r = *p++; #ifdef CONFIG_PPC64 - if (s) { + if (s > 1) { r <<= 32; r |= *(p++); } @@ -2059,7 +2059,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, reloc_got2(-offset); #endif - __start(hdr, 0, 0); + __start(hdr, KERNELBASE + offset, 0); return 0; } diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index b9269c038af3..2d7fdeb581d1 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -464,14 +464,11 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys) strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); #endif /* CONFIG_CMDLINE */ + platform_init(); + #ifdef CONFIG_6xx ppc_md.power_save = ppc6xx_idle; #endif -#ifdef CONFIG_POWER4 - ppc_md.power_save = power4_idle; -#endif - - platform_init(); if (ppc_md.progress) ppc_md.progress("id mach(): done", 0x200); diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index da744d5e52fd..9b54e805b8aa 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,4 +1,4 @@ -ifeq ($(CONFIG_PPC32),y) +ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_PMAC) += powermac/ endif obj-$(CONFIG_4xx) += 4xx/ diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 74712ede16df..4369676f1d54 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,8 +1,8 @@ -obj-$(CONFIG_PPC_PMAC) += pic.o setup.o time.o feature.o pci.o \ +obj-y += pic.o setup.o time.o feature.o pci.o \ sleep.o low_i2c.o cache.o obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o -ifeq ($(CONFIG_PPC_PMAC),y) obj-$(CONFIG_NVRAM) += nvram.o +# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff +obj-$(CONFIG_PPC64) += nvram.o obj-$(CONFIG_SMP) += smp.o -endif diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 243a24fd025a..10f1d942c661 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2960,7 +2960,6 @@ static void dump_HT_speeds(char *name, u32 cfg, u32 frq) void __init pmac_check_ht_link(void) { -#if 0 /* Disabled for now */ u32 ufreq, freq, ucfg, cfg; struct device_node *pcix_node; u8 px_bus, px_devfn; @@ -2991,10 +2990,8 @@ void __init pmac_check_ht_link(void) early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); dump_HT_speeds("PCI-X HT Downlink", cfg, freq); -#endif } - -#endif /* CONFIG_POWER4 */ +#endif /* 0 */ /* * Early video resume hook diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 8c9b008c7226..4042e2f06ee0 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -47,7 +47,8 @@ /* On Core99, nvram is either a sharp, a micron or an AMD flash */ #define SM_FLASH_STATUS_DONE 0x80 -#define SM_FLASH_STATUS_ERR 0x38 +#define SM_FLASH_STATUS_ERR 0x38 + #define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 #define SM_FLASH_CMD_ERASE_SETUP 0x20 #define SM_FLASH_CMD_RESET 0xff @@ -75,11 +76,11 @@ struct core99_header { * Read and write the non-volatile RAM on PowerMacs and CHRP machines. */ static int nvram_naddrs; -static volatile unsigned char *nvram_addr; static volatile unsigned char *nvram_data; -static int nvram_mult, is_core_99; +static int is_core_99; static int core99_bank = 0; static int nvram_partitions[3]; +// XXX Turn that into a sem static DEFINE_SPINLOCK(nv_lock); extern int pmac_newworld; @@ -105,6 +106,52 @@ static void core99_nvram_write_byte(int addr, unsigned char val) nvram_image[addr] = val; } +static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index) +{ + int i; + + if (nvram_image == NULL) + return -ENODEV; + if (*index > NVRAM_SIZE) + return 0; + + i = *index; + if (i + count > NVRAM_SIZE) + count = NVRAM_SIZE - i; + + memcpy(buf, &nvram_image[i], count); + *index = i + count; + return count; +} + +static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index) +{ + int i; + + if (nvram_image == NULL) + return -ENODEV; + if (*index > NVRAM_SIZE) + return 0; + + i = *index; + if (i + count > NVRAM_SIZE) + count = NVRAM_SIZE - i; + + memcpy(&nvram_image[i], buf, count); + *index = i + count; + return count; +} + +static ssize_t core99_nvram_size(void) +{ + if (nvram_image == NULL) + return -ENODEV; + return NVRAM_SIZE; +} + +#ifdef CONFIG_PPC32 +static volatile unsigned char *nvram_addr; +static int nvram_mult; static unsigned char direct_nvram_read_byte(int addr) { @@ -181,7 +228,7 @@ static void pmu_nvram_write_byte(int addr, unsigned char val) } #endif /* CONFIG_ADB_PMU */ - +#endif /* CONFIG_PPC32 */ static u8 chrp_checksum(struct chrp_header* hdr) { @@ -249,7 +296,7 @@ static int sm_erase_bank(int bank) timeout = 0; do { if (++timeout > 1000000) { - printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); + printk(KERN_ERR "nvram: Sharp/Micron flash erase timeout !\n"); break; } out_8(base, SM_FLASH_CMD_READ_STATUS); @@ -411,7 +458,7 @@ static void __init lookup_partitions(void) buffer[16] = 0; do { for (i=0;i<16;i++) - buffer[i] = nvram_read_byte(offset+i); + buffer[i] = ppc_md.nvram_read_val(offset+i); if (!strcmp(hdr->name, "common")) nvram_partitions[pmac_nvram_OF] = offset + 0x10; if (!strcmp(hdr->name, "APL,MacOS75")) { @@ -467,65 +514,76 @@ static void core99_nvram_sync(void) #endif } -void __init pmac_nvram_init(void) +static int __init core99_nvram_setup(struct device_node *dp) +{ + int i; + u32 gen_bank0, gen_bank1; + + if (nvram_naddrs < 1) { + printk(KERN_ERR "nvram: no address\n"); + return -EINVAL; + } + nvram_image = alloc_bootmem(NVRAM_SIZE); + if (nvram_image == NULL) { + printk(KERN_ERR "nvram: can't allocate ram image\n"); + return -ENOMEM; + } + nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); + nvram_naddrs = 1; /* Make sure we get the correct case */ + + DBG("nvram: Checking bank 0...\n"); + + gen_bank0 = core99_check((u8 *)nvram_data); + gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); + core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; + + DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); + DBG("nvram: Active bank is: %d\n", core99_bank); + + for (i=0; in_addrs; is_core_99 = device_is_compatible(dp, "nvram,flash"); - if (is_core_99) { - int i; - u32 gen_bank0, gen_bank1; - - if (nvram_naddrs < 1) { - printk(KERN_ERR "nvram: no address\n"); - return; - } - nvram_image = alloc_bootmem(NVRAM_SIZE); - if (nvram_image == NULL) { - printk(KERN_ERR "nvram: can't allocate ram image\n"); - return; - } - nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); - nvram_naddrs = 1; /* Make sure we get the correct case */ - - DBG("nvram: Checking bank 0...\n"); - - gen_bank0 = core99_check((u8 *)nvram_data); - gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); - core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; - - DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); - DBG("nvram: Active bank is: %d\n", core99_bank); - - for (i=0; iaddrs[0].address + isa_mem_base, dp->addrs[0].size); nvram_mult = 1; @@ -547,11 +605,14 @@ void __init pmac_nvram_init(void) ppc_md.nvram_read_val = pmu_nvram_read_byte; ppc_md.nvram_write_val = pmu_nvram_write_byte; #endif /* CONFIG_ADB_PMU */ - } else { - printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", - nvram_naddrs); + } +#endif + else { + printk(KERN_ERR "Incompatible type of NVRAM\n"); + return -ENXIO; } lookup_partitions(); + return err; } int pmac_get_partition(int partition) @@ -561,9 +622,9 @@ int pmac_get_partition(int partition) u8 pmac_xpram_read(int xpaddr) { - int offset = nvram_partitions[pmac_nvram_XPRAM]; + int offset = pmac_get_partition(pmac_nvram_XPRAM); - if (offset < 0) + if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) return 0xff; return ppc_md.nvram_read_val(xpaddr + offset); @@ -571,9 +632,9 @@ u8 pmac_xpram_read(int xpaddr) void pmac_xpram_write(int xpaddr, u8 data) { - int offset = nvram_partitions[pmac_nvram_XPRAM]; + int offset = pmac_get_partition(pmac_nvram_XPRAM); - if (offset < 0) + if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) return; ppc_md.nvram_write_val(xpaddr + offset, data); diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 34dfe1e9706f..ebe22a2267d2 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -37,14 +37,14 @@ #endif static int add_bridge(struct device_node *dev); -extern void pmac_check_ht_link(void); /* XXX Could be per-controller, but I don't think we risk anything by * assuming we won't have both UniNorth and Bandit */ static int has_uninorth; -#ifdef CONFIG_POWER4 +#ifdef CONFIG_PPC64 static struct pci_controller *u3_agp; -#endif /* CONFIG_POWER4 */ +static struct pci_controller *u3_ht; +#endif /* CONFIG_PPC64 */ extern u8 pci_cache_line_size; extern int pcibios_assign_bus_offset; @@ -229,6 +229,7 @@ static struct pci_ops macrisc_pci_ops = macrisc_write_config }; +#ifdef CONFIG_PPC32 /* * Verify that a specific (bus, dev_fn) exists on chaos */ @@ -282,7 +283,19 @@ static struct pci_ops chaos_pci_ops = chaos_write_config }; -#ifdef CONFIG_POWER4 +static void __init setup_chaos(struct pci_controller *hose, + struct reg_property *addr) +{ + /* assume a `chaos' bridge */ + hose->ops = &chaos_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); +} +#else +#define setup_chaos(hose, addr) +#endif /* CONFIG_PPC32 */ + +#ifdef CONFIG_PPC64 /* * These versions of U3 HyperTransport config space access ops do not * implement self-view of the HT host yet @@ -445,8 +458,9 @@ static struct pci_ops u3_ht_pci_ops = u3_ht_read_config, u3_ht_write_config }; -#endif /* CONFIG_POWER4 */ +#endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC32 /* * For a bandit bridge, turn on cache coherency if necessary. * N.B. we could clean this up using the hose ops directly. @@ -487,7 +501,6 @@ static void __init init_bandit(struct pci_controller *bp) printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); } - /* * Tweak the PCI-PCI bridge chip on the blue & white G3s. */ @@ -539,7 +552,7 @@ static void __init fixup_nec_usb2(void) struct pci_controller *hose; u32 data, *prop; u8 bus, devfn; - + prop = (u32 *)get_property(nec, "vendor-id", NULL); if (prop == NULL) continue; @@ -605,8 +618,27 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) (void)in_le32(bp->cfg_data); } -static int __init -setup_uninorth(struct pci_controller* hose, struct reg_property* addr) +void __init setup_grackle(struct pci_controller *hose) +{ + setup_indirect_pci(hose, 0xfec00000, 0xfee00000); + if (machine_is_compatible("AAPL,PowerBook1998")) + grackle_set_loop_snoop(hose, 1); +#if 0 /* Disabled for now, HW problems ??? */ + grackle_set_stg(hose, 1); +#endif +} + +static void __init setup_bandit(struct pci_controller *hose, + struct reg_property *addr) +{ + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + init_bandit(hose); +} + +static int __init setup_uninorth(struct pci_controller *hose, + struct reg_property *addr) { pci_assign_all_buses = 1; has_uninorth = 1; @@ -616,31 +648,14 @@ setup_uninorth(struct pci_controller* hose, struct reg_property* addr) /* We "know" that the bridge at f2000000 has the PCI slots. */ return addr->address == 0xf2000000; } +#endif -static void __init -setup_bandit(struct pci_controller* hose, struct reg_property* addr) -{ - hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); - init_bandit(hose); -} - -static void __init -setup_chaos(struct pci_controller* hose, struct reg_property* addr) -{ - /* assume a `chaos' bridge */ - hose->ops = &chaos_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); -} - -#ifdef CONFIG_POWER4 +#ifdef CONFIG_PPC64 static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_buses to the + * on AGP, we'll have to move pci_assign_all_busses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * We hard code the address because of the different size of @@ -679,8 +694,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * then read its configuration register (if any). */ hose->io_base_phys = 0xf4000000; - hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); - isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; + hose->pci_io_size = 0x00400000; hose->io_resource.name = np->full_name; hose->io_resource.start = 0; hose->io_resource.end = 0x003fffff; @@ -693,6 +707,8 @@ static void __init setup_u3_ht(struct pci_controller* hose) hose->mem_resources[0].end = 0xefffffff; hose->mem_resources[0].flags = IORESOURCE_MEM; + u3_ht = hose; + if (u3_agp == NULL) { DBG("U3 has no AGP, using full resource range\n"); return; @@ -730,7 +746,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) printk(KERN_WARNING "Running out of resources for /ht host !\n"); hose->mem_resources[cur].end = res->start - 1; continue; - } + } cur++; DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); @@ -742,126 +758,17 @@ static void __init setup_u3_ht(struct pci_controller* hose) } } -#endif /* CONFIG_POWER4 */ - -void __init -setup_grackle(struct pci_controller *hose) +/* XXX this needs to be converged between ppc32 and ppc64... */ +static struct pci_controller * __init pcibios_alloc_controller(void) { - setup_indirect_pci(hose, 0xfec00000, 0xfee00000); - if (machine_is_compatible("AAPL,PowerBook1998")) - grackle_set_loop_snoop(hose, 1); -#if 0 /* Disabled for now, HW problems ??? */ - grackle_set_stg(hose, 1); -#endif + struct pci_controller *hose; + + hose = alloc_bootmem(sizeof(struct pci_controller)); + if (hose) + pci_setup_pci_controller(hose); + return hose; } - -static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - static unsigned int static_lc_ranges[2024]; - unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; - unsigned int size; - int rlen = 0, orig_rlen; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - - np = na + 5; - - /* First we try to merge ranges to fix a problem with some pmacs - * that can have more than 3 ranges, fortunately using contiguous - * addresses -- BenH - */ - dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - if (!dt_ranges) - return; - /* lc_ranges = alloc_bootmem(rlen);*/ - lc_ranges = static_lc_ranges; - if (!lc_ranges) - return; /* what can we do here ? */ - memcpy(lc_ranges, dt_ranges, rlen); - orig_rlen = rlen; - - /* Let's work on a copy of the "ranges" property instead of damaging - * the device-tree image in memory - */ - ranges = lc_ranges; - prev = NULL; - while ((rlen -= np * sizeof(unsigned int)) >= 0) { - if (prev) { - if (prev[0] == ranges[0] && prev[1] == ranges[1] && - (prev[2] + prev[na+4]) == ranges[2] && - (prev[na+2] + prev[na+4]) == ranges[na+2]) { - prev[na+4] += ranges[na+4]; - ranges[0] = 0; - ranges += np; - continue; - } - } - prev = ranges; - ranges += np; - } - - /* - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (size depending on dev->n_addr_cells) - * cells 4+5 or 5+6: the size of the range - */ - ranges = lc_ranges; - rlen = orig_rlen; - while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { - res = NULL; - size = ranges[na+4]; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[na+2]; - /* limit I/O space to 16MB */ - if (size > 0x01000000) - size = 0x01000000; - hose->io_base_virt = ioremap(ranges[na+2], size); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[na+4] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ -#if 0 - if (primary) - isa_mem_base = ranges[na+2]; #endif - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[na+2] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[na+2]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} /* * We assume that if we have a G3 powermac, we have one bridge called @@ -872,70 +779,78 @@ static int __init add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; +#ifdef CONFIG_PPC32 struct reg_property *addr; - char* disp_name; +#endif + char *disp_name; int *bus_range; int primary = 1; DBG("Adding PCI host bridge %s\n", dev->full_name); - addr = (struct reg_property *) get_property(dev, "reg", &len); - if (addr == NULL || len < sizeof(*addr)) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - return -ENODEV; - } - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } +#ifdef CONFIG_PPC32 + /* XXX fix this */ + addr = (struct reg_property *) get_property(dev, "reg", &len); + if (addr == NULL || len < sizeof(*addr)) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + return -ENODEV; + } +#endif + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } - hose = pcibios_alloc_controller(); - if (!hose) - return -ENOMEM; - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose = pcibios_alloc_controller(); + if (!hose) + return -ENOMEM; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; disp_name = NULL; #ifdef CONFIG_POWER4 - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose, addr); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose, addr); - disp_name = "U3-HT"; - primary = 1; - } else -#endif /* CONFIG_POWER4 */ + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); +#else if (device_is_compatible(dev, "uni-north")) { - primary = setup_uninorth(hose, addr); - disp_name = "UniNorth"; + primary = setup_uninorth(hose, addr); + disp_name = "UniNorth"; } else if (strcmp(dev->name, "pci") == 0) { - /* XXX assume this is a mpc106 (grackle) */ - setup_grackle(hose); - disp_name = "Grackle (MPC106)"; - } else if (strcmp(dev->name, "bandit") == 0) { - setup_bandit(hose, addr); - disp_name = "Bandit"; - } else if (strcmp(dev->name, "chaos") == 0) { - setup_chaos(hose, addr); - disp_name = "Chaos"; - primary = 0; - } - printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", - disp_name, addr->address, hose->first_busno, hose->last_busno); - DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", - hose, hose->cfg_addr, hose->cfg_data); + /* XXX assume this is a mpc106 (grackle) */ + setup_grackle(hose); + disp_name = "Grackle (MPC106)"; + } else if (strcmp(dev->name, "bandit") == 0) { + setup_bandit(hose, addr); + disp_name = "Bandit"; + } else if (strcmp(dev->name, "chaos") == 0) { + setup_chaos(hose, addr); + disp_name = "Chaos"; + primary = 0; + } + printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", + disp_name, addr->address, hose->first_busno, hose->last_busno); +#endif + DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", + hose, hose->cfg_addr, hose->cfg_data); - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev, primary); + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev, primary); - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } @@ -968,14 +883,28 @@ pmac_pcibios_fixup(void) pcibios_fixup_OF_interrupts(); } -void __init pmac_find_bridges(void) +#ifdef CONFIG_PPC64 +static void __init pmac_fixup_phb_resources(void) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", + hose->global_number, + hose->io_resource.start, hose->io_resource.end); + } +} +#endif + +void __init pmac_pci_init(void) { struct device_node *np, *root; struct device_node *ht = NULL; root = of_find_node_by_path("/"); if (root == NULL) { - printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + printk(KERN_CRIT "pmac_pci_init: can't find root " + "of device tree\n"); return; } for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { @@ -994,22 +923,66 @@ void __init pmac_find_bridges(void) } of_node_put(root); +#ifdef CONFIG_PPC64 /* Probe HT last as it relies on the agp resources to be already * setup */ if (ht && add_bridge(ht) != 0) of_node_put(ht); + /* + * We need to call pci_setup_phb_io for the HT bridge first + * so it gets the I/O port numbers starting at 0, and we + * need to call it for the AGP bridge after that so it gets + * small positive I/O port numbers. + */ + if (u3_ht) + pci_setup_phb_io(u3_ht, 1); + if (u3_agp) + pci_setup_phb_io(u3_agp, 0); + + /* + * On ppc64, fixup the IO resources on our host bridges as + * the common code does it only for children of the host bridges + */ + pmac_fixup_phb_resources(); + + /* Setup the linkage between OF nodes and PHBs */ + pci_devs_phb_init(); + + /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We + * assume there is no P2P bridge on the AGP bus, which should be a + * safe assumptions hopefully. + */ + if (u3_agp) { + struct device_node *np = u3_agp->arch_data; + PCI_DN(np)->busno = 0xf0; + for (np = np->child; np; np = np->sibling) + PCI_DN(np)->busno = 0xf0; + } + + /* map in PCI I/O space */ + phbs_remap_io(); + + /* pmac_check_ht_link(); */ + + /* 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(); - + /* We are still having some issues with the Xserve G4, enabling * some offset between bus number and domains for now when we * assign all busses should help for now */ if (pci_assign_all_buses) pcibios_assign_bus_offset = 0x10; - +#endif } int @@ -1037,7 +1010,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) uninorth_child = node->parent && device_is_compatible(node->parent, "uni-north"); - + /* Firewire & GMAC were disabled after PCI probe, the driver is * claiming them, we must re-enable them now. */ @@ -1057,7 +1030,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) if (updatecfg) { u16 cmd; - + /* * Make sure PCI is correctly configured * @@ -1069,10 +1042,12 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) * register the device. */ pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; - pci_write_config_word(dev, PCI_COMMAND, cmd); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER + | PCI_COMMAND_INVALIDATE; + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + L1_CACHE_BYTES >> 2); } return 0; @@ -1081,8 +1056,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) /* We power down some devices after they have been probed. They'll * be powered back on later on */ -void __init -pmac_pcibios_after_init(void) +void __init pmac_pcibios_after_init(void) { struct device_node* nd; @@ -1125,84 +1099,6 @@ pmac_pcibios_after_init(void) } } -#ifdef CONFIG_PPC64 -static void __init pmac_fixup_phb_resources(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - hose->io_resource.start += offset; - hose->io_resource.end += offset; - printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", - hose->global_number, - hose->io_resource.start, hose->io_resource.end); - } -} - -void __init pmac_pci_init(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - /* Probe root PCI hosts, that is on U3 the AGP host and the - * HyperTransport host. That one is actually "kept" around - * and actually added last as it's resource management relies - * on the AGP resources to have been setup first - */ - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); - return; - } - for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) - continue; - if (strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Now setup the HyperTransport host if we found any - */ - if (ht && add_bridge(ht) != 0) - of_node_put(ht); - - /* Fixup the IO resources on our host bridges as the common code - * does it only for childs of the host bridges - */ - pmac_fixup_phb_resources(); - - /* Setup the linkage between OF nodes and PHBs */ - pci_devs_phb_init(); - - /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We - * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. - */ - if (u3_agp) { - struct device_node *np = u3_agp->arch_data; - PCI_DN(np)->busno = 0xf0; - for (np = np->child; np; np = np->sibling) - PCI_DN(np)->busno = 0xf0; - } - - pmac_check_ht_link(); - - /* Tell pci.c to not use the common resource allocation mecanism */ - pci_probe_only = 1; - - /* Allow all IO */ - io_page_mask = -1; -} -#endif - #ifdef CONFIG_PPC32 void pmac_pci_fixup_cardbus(struct pci_dev* dev) { @@ -1217,7 +1113,7 @@ void pmac_pci_fixup_cardbus(struct pci_dev* dev) if (dev->device == PCI_DEVICE_ID_TI_1130 || dev->device == PCI_DEVICE_ID_TI_1131) { u8 val; - /* Enable PCI interrupt */ + /* Enable PCI interrupt */ if (pci_read_config_byte(dev, 0x91, &val) == 0) pci_write_config_byte(dev, 0x91, val | 0x30); /* Disable ISA interrupt mode */ diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 58017d18db70..0eca17df239e 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -430,7 +430,6 @@ void __init pmac_pic_init(void) printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", (unsigned int)irqctrler->addrs[0].address); - ppc_md.get_irq = mpic_get_irq; pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); prom_get_irq_senses(senses, 0, 128); @@ -483,6 +482,7 @@ void __init pmac_pic_init(void) * a Grand Central nor an OHare, then it's an Heathrow * (or Paddington). */ + ppc_md.get_irq = pmac_get_irq; if (find_devices("gc")) level_mask[0] = GC_LEVEL_MASK; else if (find_devices("ohare")) { diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 0a9ba704865e..2ad25e13423e 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -19,7 +19,7 @@ extern int pmac_set_rtc_time(struct rtc_time *); extern void pmac_read_rtc_time(void); extern void pmac_calibrate_decr(void); extern void pmac_pcibios_fixup(void); -extern void pmac_find_bridges(void); +extern void pmac_pci_init(void); extern unsigned long pmac_ide_get_base(int index); extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq); @@ -41,7 +41,7 @@ extern unsigned long pmac_ide_get_base(int index); extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq); -extern void pmac_nvram_init(void); +extern int pmac_nvram_init(void); extern struct hw_interrupt_type pmac_pic; diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 0bad53fa36ef..da0cb165dfc6 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -1,11 +1,11 @@ /* - * arch/ppc/platforms/setup.c + * Powermac setup and early boot code plus other random bits. * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Adapted for Power Macintosh by Paul Mackerras - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * Copyright (C) 1996 Paul Mackerras (paulus@samba.org) * * Derived from "arch/alpha/kernel/setup.c" * Copyright (C) 1995 Linus Torvalds @@ -65,13 +65,16 @@ #include #include #include -#include #include #include #include #include #include #include +#include +#include +#include +#include #include "pmac.h" @@ -88,16 +91,24 @@ int pmac_newworld = 1; static int current_root_goodness = -1; extern int pmac_newworld; +extern struct machdep_calls pmac_md; #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ -extern void zs_kgdb_hook(int tty_num); -static void ohare_init(void); -#ifdef CONFIG_BOOTX_TEXT -static void pmac_progress(char *s, unsigned short hex); +#ifdef CONFIG_PPC64 +#include +int sccdbg; #endif +extern void zs_kgdb_hook(int tty_num); + sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; +EXPORT_SYMBOL(sys_ctrler); + +#ifdef CONFIG_PMAC_SMU +unsigned long smu_cmdbuf_abs; +EXPORT_SYMBOL(smu_cmdbuf_abs); +#endif #ifdef CONFIG_SMP extern struct smp_ops_t psurge_smp_ops; @@ -191,44 +202,69 @@ static void pmac_show_percpuinfo(struct seq_file *m, int i) return; } #endif /* CONFIG_CPU_FREQ_PMAC */ +#ifdef CONFIG_PPC32 of_show_percpuinfo(m, i); +#endif } +#ifndef CONFIG_ADB_CUDA +int find_via_cuda(void) +{ + if (!find_devices("via-cuda")) + return 0; + printk("WARNING ! Your machine is CUDA-based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); + return 0; +} +#endif + +#ifndef CONFIG_ADB_PMU +int find_via_pmu(void) +{ + if (!find_devices("via-pmu")) + return 0; + printk("WARNING ! Your machine is PMU-based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); + return; +} +#endif + +#ifndef CONFIG_PMAC_SMU +int smu_init(void) +{ + /* should check and warn if SMU is present */ + return 0; +} +#endif + +#ifdef CONFIG_PPC32 static volatile u32 *sysctrl_regs; -void __init -pmac_setup_arch(void) +static void __init ohare_init(void) { - struct device_node *cpu; - int *fp; - unsigned long pvr; - - pvr = PVR_VER(mfspr(SPRN_PVR)); - - /* Set loops_per_jiffy to a half-way reasonable value, - for use until calibrate_delay gets called. */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (int *) get_property(cpu, "clock-frequency", NULL); - if (fp != 0) { - if (pvr == 4 || pvr >= 8) - /* 604, G3, G4 etc. */ - loops_per_jiffy = *fp / HZ; - else - /* 601, 603, etc. */ - loops_per_jiffy = *fp / (2*HZ); - } else - loops_per_jiffy = 50000000 / HZ; - } - /* this area has the CPU identification register and some registers used by smp boards */ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); - ohare_init(); - /* Lookup PCI hosts */ - pmac_find_bridges(); + /* + * Turn on the L2 cache. + * We assume that we have a PSX memory controller iff + * we have an ohare I/O controller. + */ + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + if(has_l2cache) + printk(KERN_INFO "Level 2 cache enabled\n"); + } + } +} +static void __init l2cr_init(void) +{ /* Checks "l2cr-value" property in the registry */ if (cpu_has_feature(CPU_FTR_L2CR)) { struct device_node *np = find_devices("cpus"); @@ -247,68 +283,90 @@ pmac_setup_arch(void) } if (ppc_override_l2cr) - printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", - ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) + printk(KERN_INFO "L2CR overridden (0x%x), " + "backside cache is %s\n", + ppc_override_l2cr_value, + (ppc_override_l2cr_value & 0x80000000) ? "enabled" : "disabled"); +} +#endif + +void __init pmac_setup_arch(void) +{ + struct device_node *cpu; + int *fp; + unsigned long pvr; + + pvr = PVR_VER(mfspr(SPRN_PVR)); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = 50000000 / HZ; + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != NULL) { + fp = (int *) get_property(cpu, "clock-frequency", NULL); + if (fp != NULL) { + if (pvr >= 0x30 && pvr < 0x80) + /* PPC970 etc. */ + loops_per_jiffy = *fp / (3 * HZ); + else if (pvr == 4 || pvr >= 8) + /* 604, G3, G4 etc. */ + loops_per_jiffy = *fp / HZ; + else + /* 601, 603, etc. */ + loops_per_jiffy = *fp / (2 * HZ); + } + of_node_put(cpu); + } + + /* Lookup PCI hosts */ + pmac_pci_init(); + +#ifdef CONFIG_PPC32 + ohare_init(); + l2cr_init(); +#endif /* CONFIG_PPC32 */ + +#ifdef CONFIG_PPC64 + /* Probe motherboard chipset */ + /* this is done earlier in setup_arch for 32-bit */ + pmac_feature_init(); + + /* We can NAP */ + powersave_nap = 1; + printk(KERN_INFO "Using native/NAP idle loop\n"); +#endif #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif -#ifdef CONFIG_ADB_CUDA find_via_cuda(); -#else - if (find_devices("via-cuda")) { - printk("WARNING ! Your machine is Cuda based but your kernel\n"); - printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); - } -#endif -#ifdef CONFIG_ADB_PMU find_via_pmu(); -#else - if (find_devices("via-pmu")) { - printk("WARNING ! Your machine is PMU based but your kernel\n"); - printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); - } -#endif + smu_init(); + #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif + +#ifdef CONFIG_PPC32 #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) ROOT_DEV = Root_RAM0; else #endif ROOT_DEV = DEFAULT_ROOT_DEVICE; +#endif #ifdef CONFIG_SMP /* Check for Core99 */ if (find_devices("uni-n") || find_devices("u3")) smp_ops = &core99_smp_ops; +#ifdef CONFIG_PPC32 else smp_ops = &psurge_smp_ops; +#endif #endif /* CONFIG_SMP */ - - pci_create_OF_bus_map(); -} - -static void __init ohare_init(void) -{ - /* - * Turn on the L2 cache. - * We assume that we have a PSX memory controller iff - * we have an ohare I/O controller. - */ - if (find_devices("ohare") != NULL) { - if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { - if (sysctrl_regs[4] & 0x10) - sysctrl_regs[4] |= 0x04000020; - else - sysctrl_regs[4] |= 0x04000000; - if(has_l2cache) - printk(KERN_INFO "Level 2 cache enabled\n"); - } - } } char *bootpath; @@ -319,8 +377,7 @@ int boot_part; extern dev_t boot_dev; #ifdef CONFIG_SCSI -void __init -note_scsi_host(struct device_node *node, void *host) +void __init note_scsi_host(struct device_node *node, void *host) { int l; char *p; @@ -351,8 +408,7 @@ EXPORT_SYMBOL(note_scsi_host); #endif #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init -find_ide_boot(void) +static dev_t __init find_ide_boot(void) { char *p; int n; @@ -369,15 +425,13 @@ find_ide_boot(void) } #endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ -static void __init -find_boot_device(void) +static void __init find_boot_device(void) { #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) boot_dev = find_ide_boot(); #endif } -static int initializing = 1; /* TODO: Merge the suspend-to-ram with the common code !!! * currently, this is a stub implementation for suspend-to-disk * only @@ -428,6 +482,8 @@ static struct pm_ops pmac_pm_ops = { #endif /* CONFIG_SOFTWARE_SUSPEND */ +static int initializing = 1; + static int pmac_late_init(void) { initializing = 0; @@ -440,8 +496,7 @@ static int pmac_late_init(void) late_initcall(pmac_late_init); /* can't be __init - can be called whenever a disk is first accessed */ -void -note_bootable_part(dev_t dev, int part, int goodness) +void note_bootable_part(dev_t dev, int part, int goodness) { static int found_boot = 0; char *p; @@ -466,52 +521,68 @@ note_bootable_part(dev_t dev, int part, int goodness) } } -static void -pmac_restart(char *cmd) +#ifdef CONFIG_ADB_CUDA +static void cuda_restart(void) { -#ifdef CONFIG_ADB_CUDA struct adb_request req; -#endif /* CONFIG_ADB_CUDA */ + cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); + for (;;) + cuda_poll(); +} + +static void cuda_shutdown(void) +{ + struct adb_request req; + + cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); + for (;;) + cuda_poll(); +} + +#else +#define cuda_restart() +#define cuda_shutdown() +#endif + +#ifndef CONFIG_ADB_PMU +#define pmu_restart() +#define pmu_shutdown() +#endif + +#ifndef CONFIG_PMAC_SMU +#define smu_restart() +#define smu_shutdown() +#endif + +static void pmac_restart(char *cmd) +{ switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_RESET_SYSTEM); - for (;;) - cuda_poll(); + cuda_restart(); break; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: pmu_restart(); break; -#endif /* CONFIG_ADB_PMU */ + case SYS_CTRLER_SMU: + smu_restart(); + break; default: ; } } -static void -pmac_power_off(void) +static void pmac_power_off(void) { -#ifdef CONFIG_ADB_CUDA - struct adb_request req; -#endif /* CONFIG_ADB_CUDA */ - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_POWERDOWN); - for (;;) - cuda_poll(); + cuda_shutdown(); break; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: pmu_shutdown(); break; -#endif /* CONFIG_ADB_PMU */ + case SYS_CTRLER_SMU: + smu_shutdown(); + break; default: ; } } @@ -522,37 +593,17 @@ pmac_halt(void) pmac_power_off(); } +#ifdef CONFIG_PPC32 void __init pmac_init(void) { - /* isa_io_base gets set in pmac_find_bridges */ + /* isa_io_base gets set in pmac_pci_init */ isa_mem_base = PMAC_ISA_MEM_BASE; pci_dram_offset = PMAC_PCI_DRAM_OFFSET; ISA_DMA_THRESHOLD = ~0L; DMA_MODE_READ = 1; DMA_MODE_WRITE = 2; - ppc_md.setup_arch = pmac_setup_arch; - ppc_md.show_cpuinfo = pmac_show_cpuinfo; - ppc_md.show_percpuinfo = pmac_show_percpuinfo; - ppc_md.init_IRQ = pmac_pic_init; - ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ - - ppc_md.pcibios_fixup = pmac_pcibios_fixup; - ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; - ppc_md.pcibios_after_init = pmac_pcibios_after_init; - ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; - - ppc_md.restart = pmac_restart; - ppc_md.power_off = pmac_power_off; - ppc_md.halt = pmac_halt; - - ppc_md.time_init = pmac_time_init; - ppc_md.set_rtc_time = pmac_set_rtc_time; - ppc_md.get_rtc_time = pmac_get_rtc_time; - ppc_md.get_boot_time = pmac_get_boot_time; - ppc_md.calibrate_decr = pmac_calibrate_decr; - - ppc_md.feature_call = pmac_do_feature_call; + ppc_md = pmac_md; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) #ifdef CONFIG_BLK_DEV_IDE_PMAC @@ -561,27 +612,62 @@ void __init pmac_init(void) #endif /* CONFIG_BLK_DEV_IDE_PMAC */ #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ -#ifdef CONFIG_BOOTX_TEXT - ppc_md.progress = pmac_progress; -#endif /* CONFIG_BOOTX_TEXT */ - if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); } +#endif -#ifdef CONFIG_BOOTX_TEXT -static void __init -pmac_progress(char *s, unsigned short hex) +/* + * Early initialization. + */ +static void __init pmac_init_early(void) { +#ifdef CONFIG_PPC64 + /* Initialize hash table, from now on, we can take hash faults + * and call ioremap + */ + hpte_init_native(); + + /* Init SCC */ + if (strstr(cmd_line, "sccdbg")) { + sccdbg = 1; + udbg_init_scc(NULL); + } + + /* Setup interrupt mapping options */ + ppc64_interrupt_controller = IC_OPEN_PIC; + + iommu_init_early_u3(); +#endif +} + +static void __init pmac_progress(char *s, unsigned short hex) +{ +#ifdef CONFIG_PPC64 + if (sccdbg) { + udbg_puts(s); + udbg_puts("\n"); + return; + } +#endif +#ifdef CONFIG_BOOTX_TEXT if (boot_text_mapped) { btext_drawstring(s); btext_drawchar('\n'); } -} #endif /* CONFIG_BOOTX_TEXT */ +} -static int __init -pmac_declare_of_platform_devices(void) +/* + * pmac has no legacy IO, anything calling this function has to + * fail or bad things will happen + */ +static int pmac_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + +static int __init pmac_declare_of_platform_devices(void) { struct device_node *np; @@ -594,6 +680,13 @@ pmac_declare_of_platform_devices(void) break; } } + np = find_devices("valkyrie"); + if (np) + of_platform_device_create(np, "valkyrie", NULL); + np = find_devices("platinum"); + if (np) + of_platform_device_create(np, "platinum", NULL); + np = find_devices("u3"); if (np) { for (np = np->child; np != NULL; np = np->sibling) @@ -603,15 +696,92 @@ pmac_declare_of_platform_devices(void) break; } } - - np = find_devices("valkyrie"); - if (np) - of_platform_device_create(np, "valkyrie", NULL); - np = find_devices("platinum"); - if (np) - of_platform_device_create(np, "platinum", NULL); + np = of_find_node_by_type(NULL, "smu"); + if (np) { + of_platform_device_create(np, "smu", NULL); + of_node_put(np); + } return 0; } device_initcall(pmac_declare_of_platform_devices); + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init pmac_probe(int platform) +{ +#ifdef CONFIG_PPC64 + if (platform != PLATFORM_POWERMAC) + return 0; + + /* + * On U3, the DART (iommu) must be allocated now since it + * has an impact on htab_initialize (due to the large page it + * occupies having to be broken up so the DART itself is not + * part of the cacheable linar mapping + */ + alloc_u3_dart_table(); +#endif + +#ifdef CONFIG_PMAC_SMU + /* + * SMU based G5s need some memory below 2Gb, at least the current + * driver needs that. We have to allocate it now. We allocate 4k + * (1 small page) for now. + */ + smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); +#endif /* CONFIG_PMAC_SMU */ + + return 1; +} + +#ifdef CONFIG_PPC64 +static int pmac_probe_mode(struct pci_bus *bus) +{ + struct device_node *node = bus->sysdata; + + /* We need to use normal PCI probing for the AGP bus, + since the device for the AGP bridge isn't in the tree. */ + if (bus->self == NULL && device_is_compatible(node, "u3-agp")) + return PCI_PROBE_NORMAL; + + return PCI_PROBE_DEVTREE; +} +#endif + +struct machdep_calls __initdata pmac_md = { +#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) + .cpu_die = generic_mach_cpu_die, +#endif + .probe = pmac_probe, + .setup_arch = pmac_setup_arch, + .init_early = pmac_init_early, + .show_cpuinfo = pmac_show_cpuinfo, + .show_percpuinfo = pmac_show_percpuinfo, + .init_IRQ = pmac_pic_init, + .get_irq = mpic_get_irq, /* changed later */ + .pcibios_fixup = pmac_pcibios_fixup, + .restart = pmac_restart, + .power_off = pmac_power_off, + .halt = pmac_halt, + .time_init = pmac_time_init, + .get_boot_time = pmac_get_boot_time, + .set_rtc_time = pmac_set_rtc_time, + .get_rtc_time = pmac_get_rtc_time, + .calibrate_decr = pmac_calibrate_decr, + .feature_call = pmac_do_feature_call, + .check_legacy_ioport = pmac_check_legacy_ioport, + .progress = pmac_progress, +#ifdef CONFIG_PPC64 + .pci_probe_mode = pmac_probe_mode, + .idle_loop = native_idle, + .enable_pmcs = power4_enable_pmcs, +#endif +#ifdef CONFIG_PPC32 + .pcibios_enable_device_hook = pmac_pci_enable_device_hook, + .pcibios_after_init = pmac_pcibios_after_init, + .phys_mem_access_prot = pci_phys_mem_access_prot, +#endif +}; diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index ccaa0534d60f..e1f9443cc872 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -44,20 +44,33 @@ #include #include #include -#include #include #include #include #include #include #include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +extern void __secondary_start_pmac_0(void); + +#ifdef CONFIG_PPC32 + +/* Sync flag for HW tb sync */ +static volatile int sec_tb_reset = 0; /* * Powersurge (old powermac SMP) support. */ -extern void __secondary_start_pmac_0(void); - /* Addresses for powersurge registers */ #define HAMMERHEAD_BASE 0xf8000000 #define HHEAD_CONFIG 0x90 @@ -106,47 +119,6 @@ static volatile u32 __iomem *psurge_start; /* what sort of powersurge board we have */ static int psurge_type = PSURGE_NONE; -/* L2 and L3 cache settings to pass from CPU0 to CPU1 */ -volatile static long int core99_l2_cache; -volatile static long int core99_l3_cache; - -/* Timebase freeze GPIO */ -static unsigned int core99_tb_gpio; - -/* Sync flag for HW tb sync */ -static volatile int sec_tb_reset = 0; -static unsigned int pri_tb_hi, pri_tb_lo; -static unsigned int pri_tb_stamp; - -static void __devinit core99_init_caches(int cpu) -{ - if (!cpu_has_feature(CPU_FTR_L2CR)) - return; - - if (cpu == 0) { - core99_l2_cache = _get_L2CR(); - printk("CPU0: L2CR is %lx\n", core99_l2_cache); - } else { - printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); - _set_L2CR(0); - _set_L2CR(core99_l2_cache); - printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); - } - - if (!cpu_has_feature(CPU_FTR_L3CR)) - return; - - if (cpu == 0){ - core99_l3_cache = _get_L3CR(); - printk("CPU0: L3CR is %lx\n", core99_l3_cache); - } else { - printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); - _set_L3CR(0); - _set_L3CR(core99_l3_cache); - printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); - } -} - /* * Set and clear IPIs for powersurge. */ @@ -436,65 +408,346 @@ void __init smp_psurge_give_timebase(void) /* Dummy implementation */ } -static int __init smp_core99_probe(void) +/* PowerSurge-style Macs */ +struct smp_ops_t psurge_smp_ops = { + .message_pass = smp_psurge_message_pass, + .probe = smp_psurge_probe, + .kick_cpu = smp_psurge_kick_cpu, + .setup_cpu = smp_psurge_setup_cpu, + .give_timebase = smp_psurge_give_timebase, + .take_timebase = smp_psurge_take_timebase, +}; +#endif /* CONFIG_PPC32 - actually powersurge support */ + +#ifdef CONFIG_PPC64 +/* + * G5s enable/disable the timebase via an i2c-connected clock chip. + */ +static struct device_node *pmac_tb_clock_chip_host; +static u8 pmac_tb_pulsar_addr; +static void (*pmac_tb_freeze)(int freeze); +static DEFINE_SPINLOCK(timebase_lock); +static unsigned long timebase; + +static void smp_core99_cypress_tb_freeze(int freeze) { -#ifdef CONFIG_6xx - extern int powersave_nap; -#endif - struct device_node *cpus, *firstcpu; - int i, ncpus = 0, boot_cpu = -1; - u32 *tbprop = NULL; + u8 data; + int rc; - if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - cpus = firstcpu = find_type_devices("cpu"); - while(cpus != NULL) { - u32 *regprop = (u32 *)get_property(cpus, "reg", NULL); - char *stateprop = (char *)get_property(cpus, "state", NULL); - if (regprop != NULL && stateprop != NULL && - !strncmp(stateprop, "running", 7)) - boot_cpu = *regprop; - ++ncpus; - cpus = cpus->next; + /* Strangely, the device-tree says address is 0xd2, but darwin + * accesses 0xd0 ... + */ + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, + 0xd0 | pmac_low_i2c_read, + 0x81, &data, 1); + if (rc != 0) + goto bail; + + data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); + + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, + 0xd0 | pmac_low_i2c_write, + 0x81, &data, 1); + + bail: + if (rc != 0) { + printk("Cypress Timebase %s rc: %d\n", + freeze ? "freeze" : "unfreeze", rc); + panic("Timebase freeze failed !\n"); } - if (boot_cpu == -1) - printk(KERN_WARNING "Couldn't detect boot CPU !\n"); - if (boot_cpu != 0) - printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu); +} - if (machine_is_compatible("MacRISC4")) { - extern struct smp_ops_t core99_smp_ops; - core99_smp_ops.take_timebase = smp_generic_take_timebase; - core99_smp_ops.give_timebase = smp_generic_give_timebase; +static void smp_core99_pulsar_tb_freeze(int freeze) +{ + u8 data; + int rc; + + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, + pmac_tb_pulsar_addr | pmac_low_i2c_read, + 0x2e, &data, 1); + if (rc != 0) + goto bail; + + data = (data & 0x88) | (freeze ? 0x11 : 0x22); + + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, + pmac_tb_pulsar_addr | pmac_low_i2c_write, + 0x2e, &data, 1); + bail: + if (rc != 0) { + printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", + freeze ? "freeze" : "unfreeze", rc); + panic("Timebase freeze failed !\n"); + } +} + + +static void smp_core99_give_timebase(void) +{ + /* Open i2c bus for synchronous access */ + if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) + panic("Can't open i2c for TB sync !\n"); + + spin_lock(&timebase_lock); + (*pmac_tb_freeze)(1); + mb(); + timebase = get_tb(); + spin_unlock(&timebase_lock); + + while (timebase) + barrier(); + + spin_lock(&timebase_lock); + (*pmac_tb_freeze)(0); + spin_unlock(&timebase_lock); + + /* Close i2c bus */ + pmac_low_i2c_close(pmac_tb_clock_chip_host); +} + + +static void __devinit smp_core99_take_timebase(void) +{ + while (!timebase) + barrier(); + spin_lock(&timebase_lock); + set_tb(timebase >> 32, timebase & 0xffffffff); + timebase = 0; + spin_unlock(&timebase_lock); +} + +static void __init smp_core99_setup(int ncpus) +{ + struct device_node *cc = NULL; + struct device_node *p; + u32 *reg; + int ok; + + /* HW sync only on these platforms */ + if (!machine_is_compatible("PowerMac7,2") && + !machine_is_compatible("PowerMac7,3") && + !machine_is_compatible("RackMac3,1")) + return; + + /* Look for the clock chip */ + while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { + p = of_get_parent(cc); + ok = p && device_is_compatible(p, "uni-n-i2c"); + of_node_put(p); + if (!ok) + continue; + + reg = (u32 *)get_property(cc, "reg", NULL); + if (reg == NULL) + continue; + + switch (*reg) { + case 0xd2: + if (device_is_compatible(cc, "pulsar-legacy-slewing")) { + pmac_tb_freeze = smp_core99_pulsar_tb_freeze; + pmac_tb_pulsar_addr = 0xd2; + printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + } else if (device_is_compatible(cc, "cy28508")) { + pmac_tb_freeze = smp_core99_cypress_tb_freeze; + printk(KERN_INFO "Timebase clock is Cypress chip\n"); + } + break; + case 0xd4: + pmac_tb_freeze = smp_core99_pulsar_tb_freeze; + pmac_tb_pulsar_addr = 0xd4; + printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + break; + } + if (pmac_tb_freeze != NULL) { + pmac_tb_clock_chip_host = of_get_parent(cc); + of_node_put(cc); + break; + } + } + if (pmac_tb_freeze == NULL) { + smp_ops->give_timebase = smp_generic_give_timebase; + smp_ops->take_timebase = smp_generic_take_timebase; + } +} + +/* nothing to do here, caches are already set up by service processor */ +static inline void __devinit core99_init_caches(int cpu) +{ +} + +#else /* CONFIG_PPC64 */ + +/* + * SMP G4 powermacs use a GPIO to enable/disable the timebase. + */ + +static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ + +static unsigned int pri_tb_hi, pri_tb_lo; +static unsigned int pri_tb_stamp; + +/* not __init, called in sleep/wakeup code */ +void smp_core99_give_timebase(void) +{ + unsigned long flags; + unsigned int t; + + /* wait for the secondary to be in take_timebase */ + for (t = 100000; t > 0 && !sec_tb_reset; --t) + udelay(10); + if (!sec_tb_reset) { + printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); + return; + } + + /* freeze the timebase and read it */ + /* disable interrupts so the timebase is disabled for the + shortest possible time */ + local_irq_save(flags); + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + mb(); + pri_tb_hi = get_tbu(); + pri_tb_lo = get_tbl(); + pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); + mb(); + + /* tell the secondary we're ready */ + sec_tb_reset = 2; + mb(); + + /* wait for the secondary to have taken it */ + for (t = 100000; t > 0 && sec_tb_reset; --t) + udelay(10); + if (sec_tb_reset) + printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); + else + smp_tb_synchronized = 1; + + /* Now, restart the timebase by leaving the GPIO to an open collector */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + local_irq_restore(flags); +} + +/* not __init, called in sleep/wakeup code */ +void smp_core99_take_timebase(void) +{ + unsigned long flags; + + /* tell the primary we're here */ + sec_tb_reset = 1; + mb(); + + /* wait for the primary to set pri_tb_hi/lo */ + while (sec_tb_reset < 2) + mb(); + + /* set our stuff the same as the primary */ + local_irq_save(flags); + set_dec(1); + set_tb(pri_tb_hi, pri_tb_lo); + last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; + mb(); + + /* tell the primary we're done */ + sec_tb_reset = 0; + mb(); + local_irq_restore(flags); +} + +/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ +volatile static long int core99_l2_cache; +volatile static long int core99_l3_cache; + +static void __devinit core99_init_caches(int cpu) +{ + if (!cpu_has_feature(CPU_FTR_L2CR)) + return; + + if (cpu == 0) { + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); } else { - if (firstcpu != NULL) - tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL); + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(0); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } + + if (!cpu_has_feature(CPU_FTR_L3CR)) + return; + + if (cpu == 0){ + core99_l3_cache = _get_L3CR(); + printk("CPU0: L3CR is %lx\n", core99_l3_cache); + } else { + printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); + _set_L3CR(0); + _set_L3CR(core99_l3_cache); + printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); + } +} + +static void __init smp_core99_setup(int ncpus) +{ + struct device_node *cpu; + u32 *tbprop = NULL; + int i; + + core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != NULL) { + tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL); if (tbprop) core99_tb_gpio = *tbprop; - else - core99_tb_gpio = KL_GPIO_TB_ENABLE; + of_node_put(cpu); } - if (ncpus > 1) { - mpic_request_ipis(); - for (i = 1; i < ncpus; ++i) - smp_hw_index[i] = i; -#ifdef CONFIG_6xx - powersave_nap = 0; + /* XXX should get this from reg properties */ + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; + powersave_nap = 0; +} #endif - core99_init_caches(0); - } + +static int __init smp_core99_probe(void) +{ + struct device_node *cpus; + int ncpus = 0; + + if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); + + /* Count CPUs in the device-tree */ + for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;) + ++ncpus; + + printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus); + + /* Nothing more to do if less than 2 of them */ + if (ncpus <= 1) + return 1; + + smp_core99_setup(ncpus); + mpic_request_ipis(); + core99_init_caches(0); return ncpus; } static void __devinit smp_core99_kick_cpu(int nr) { - unsigned long save_vector, new_vector; + unsigned int save_vector; + unsigned long new_vector; unsigned long flags; + volatile unsigned int *vector + = ((volatile unsigned int *)(KERNELBASE+0x100)); - volatile unsigned long *vector - = ((volatile unsigned long *)(KERNELBASE+0x100)); if (nr < 0 || nr > 3) return; if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); @@ -556,113 +809,10 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) } } -/* not __init, called in sleep/wakeup code */ -void smp_core99_take_timebase(void) -{ - unsigned long flags; - /* tell the primary we're here */ - sec_tb_reset = 1; - mb(); - - /* wait for the primary to set pri_tb_hi/lo */ - while (sec_tb_reset < 2) - mb(); - - /* set our stuff the same as the primary */ - local_irq_save(flags); - set_dec(1); - set_tb(pri_tb_hi, pri_tb_lo); - last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; - mb(); - - /* tell the primary we're done */ - sec_tb_reset = 0; - mb(); - local_irq_restore(flags); -} - -/* not __init, called in sleep/wakeup code */ -void smp_core99_give_timebase(void) -{ - unsigned long flags; - unsigned int t; - - /* wait for the secondary to be in take_timebase */ - for (t = 100000; t > 0 && !sec_tb_reset; --t) - udelay(10); - if (!sec_tb_reset) { - printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); - return; - } - - /* freeze the timebase and read it */ - /* disable interrupts so the timebase is disabled for the - shortest possible time */ - local_irq_save(flags); - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); - pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); - mb(); - pri_tb_hi = get_tbu(); - pri_tb_lo = get_tbl(); - pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); - mb(); - - /* tell the secondary we're ready */ - sec_tb_reset = 2; - mb(); - - /* wait for the secondary to have taken it */ - for (t = 100000; t > 0 && sec_tb_reset; --t) - udelay(10); - if (sec_tb_reset) - printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); - else - smp_tb_synchronized = 1; - - /* Now, restart the timebase by leaving the GPIO to an open collector */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); - pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); - local_irq_restore(flags); -} - -void smp_core99_message_pass(int target, int msg) -{ - cpumask_t mask = CPU_MASK_ALL; - /* make sure we're sending something that translates to an IPI */ - if (msg > 0x3) { - printk("SMP %d: smp_message_pass: unknown msg %d\n", - smp_processor_id(), msg); - return; - } - switch (target) { - case MSG_ALL: - mpic_send_ipi(msg, cpus_addr(mask)[0]); - break; - case MSG_ALL_BUT_SELF: - cpu_clear(smp_processor_id(), mask); - mpic_send_ipi(msg, cpus_addr(mask)[0]); - break; - default: - mpic_send_ipi(msg, 1 << target); - break; - } -} - - -/* PowerSurge-style Macs */ -struct smp_ops_t psurge_smp_ops = { - .message_pass = smp_psurge_message_pass, - .probe = smp_psurge_probe, - .kick_cpu = smp_psurge_kick_cpu, - .setup_cpu = smp_psurge_setup_cpu, - .give_timebase = smp_psurge_give_timebase, - .take_timebase = smp_psurge_take_timebase, -}; - -/* Core99 Macs (dual G4s) */ +/* Core99 Macs (dual G4s and G5s) */ struct smp_ops_t core99_smp_ops = { - .message_pass = smp_core99_message_pass, + .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu, @@ -670,7 +820,7 @@ struct smp_ops_t core99_smp_ops = { .take_timebase = smp_core99_take_timebase, }; -#ifdef CONFIG_HOTPLUG_CPU +#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) int __cpu_disable(void) { @@ -685,7 +835,7 @@ int __cpu_disable(void) return 0; } -extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */ +extern void low_cpu_die(void) __attribute__((noreturn)); /* in sleep.S */ static int cpu_dead[NR_CPUS]; void cpu_die(void) diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index a6d2d231d5a0..82982bf6453c 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -33,6 +33,7 @@ #include #include #include +#include #undef DEBUG @@ -68,8 +69,8 @@ long __init pmac_time_init(void) { -#ifdef CONFIG_NVRAM s32 delta = 0; +#ifdef CONFIG_NVRAM int dst; delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; @@ -80,110 +81,181 @@ long __init pmac_time_init(void) dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - return delta; -#else - return 0; #endif + return delta; } +static void to_rtc_time(unsigned long now, struct rtc_time *tm) +{ + to_tm(now, tm); + tm->tm_year -= 1900; + tm->tm_mon -= 1; +} + +static unsigned long from_rtc_time(struct rtc_time *tm) +{ + return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +} + +#ifdef CONFIG_ADB_CUDA +static unsigned long cuda_get_time(void) +{ + struct adb_request req; + unsigned long now; + + if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if (req.reply_len != 7) + printk(KERN_ERR "cuda_get_time: got %d byte reply\n", + req.reply_len); + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + if (now < RTC_OFFSET) + return 0; + return now - RTC_OFFSET; +} + +#define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm)) + +static int cuda_set_rtc_time(struct rtc_time *tm) +{ + unsigned int nowtime; + struct adb_request req; + + nowtime = from_rtc_time(tm) + RTC_OFFSET; + if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, + nowtime >> 24, nowtime >> 16, nowtime >> 8, + nowtime) < 0) + return -ENXIO; + while (!req.complete) + cuda_poll(); + if ((req.reply_len != 3) && (req.reply_len != 7)) + printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n", + req.reply_len); + return 0; +} + +#else +#define cuda_get_time() 0 +#define cuda_get_rtc_time(tm) +#define cuda_set_rtc_time(tm) 0 +#endif + +#ifdef CONFIG_ADB_PMU +static unsigned long pmu_get_time(void) +{ + struct adb_request req; + unsigned long now; + + if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) + return 0; + pmu_wait_complete(&req); + if (req.reply_len != 4) + printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n", + req.reply_len); + now = (req.reply[0] << 24) + (req.reply[1] << 16) + + (req.reply[2] << 8) + req.reply[3]; + if (now < RTC_OFFSET) + return 0; + return now - RTC_OFFSET; +} + +#define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm)) + +static int pmu_set_rtc_time(struct rtc_time *tm) +{ + unsigned int nowtime; + struct adb_request req; + + nowtime = from_rtc_time(tm) + RTC_OFFSET; + if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, + nowtime >> 16, nowtime >> 8, nowtime) < 0) + return -ENXIO; + pmu_wait_complete(&req); + if (req.reply_len != 0) + printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n", + req.reply_len); + return 0; +} + +#else +#define pmu_get_time() 0 +#define pmu_get_rtc_time(tm) +#define pmu_set_rtc_time(tm) 0 +#endif + +#ifdef CONFIG_PMAC_SMU +static unsigned long smu_get_time(void) +{ + struct rtc_time tm; + + if (smu_get_rtc_time(&tm, 1)) + return 0; + return from_rtc_time(&tm); +} + +#else +#define smu_get_time() 0 +#define smu_get_rtc_time(tm, spin) +#define smu_set_rtc_time(tm, spin) 0 +#endif + unsigned long pmac_get_boot_time(void) { -#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) - struct adb_request req; - unsigned long now; -#endif - - /* Get the time from the RTC */ + /* Get the time from the RTC, used only at boot time */ switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: - if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) - return 0; - while (!req.complete) - cuda_poll(); - if (req.reply_len != 7) - printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", - req.reply_len); - now = (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6]; - return now - RTC_OFFSET; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU + return cuda_get_time(); case SYS_CTRLER_PMU: - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return 0; - while (!req.complete) - pmu_poll(); - if (req.reply_len != 4) - printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", - req.reply_len); - now = (req.reply[0] << 24) + (req.reply[1] << 16) - + (req.reply[2] << 8) + req.reply[3]; - return now - RTC_OFFSET; -#endif /* CONFIG_ADB_PMU */ - default: ; - } - return 0; -} - -void pmac_get_rtc_time(struct rtc_time *tm) -{ - unsigned long now; - - now = pmac_get_boot_time(); - to_tm(now, tm); - tm->tm_year -= 1900; - tm->tm_mon -= 1; /* month is 0-based */ -} - -int pmac_set_rtc_time(struct rtc_time *tm) -{ - unsigned long nowtime; -#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) - struct adb_request req; -#endif - - nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - nowtime += RTC_OFFSET; - - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA - case SYS_CTRLER_CUDA: - if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, - nowtime >> 24, nowtime >> 16, nowtime >> 8, - nowtime) < 0) - return 0; - while (!req.complete) - cuda_poll(); - if ((req.reply_len != 3) && (req.reply_len != 7)) - printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", - req.reply_len); - return 1; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, - nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) - return 0; - while (!req.complete) - pmu_poll(); - if (req.reply_len != 0) - printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", - req.reply_len); - return 1; -#endif /* CONFIG_ADB_PMU */ + return pmu_get_time(); + case SYS_CTRLER_SMU: + return smu_get_time(); default: return 0; } } +void pmac_get_rtc_time(struct rtc_time *tm) +{ + /* Get the time from the RTC, used only at boot time */ + switch (sys_ctrler) { + case SYS_CTRLER_CUDA: + cuda_get_rtc_time(tm); + break; + case SYS_CTRLER_PMU: + pmu_get_rtc_time(tm); + break; + case SYS_CTRLER_SMU: + smu_get_rtc_time(tm, 1); + break; + default: + ; + } +} + +int pmac_set_rtc_time(struct rtc_time *tm) +{ + switch (sys_ctrler) { + case SYS_CTRLER_CUDA: + return cuda_set_rtc_time(tm); + case SYS_CTRLER_PMU: + return pmu_set_rtc_time(tm); + case SYS_CTRLER_SMU: + return smu_set_rtc_time(tm, 1); + default: + return -ENODEV; + } +} + +#ifdef CONFIG_PPC32 /* * Calibrate the decrementer register using VIA timer 1. * This is used both on powermacs and CHRP machines. */ -int __init -via_calibrate_decr(void) +int __init via_calibrate_decr(void) { struct device_node *vias; volatile unsigned char __iomem *via; @@ -217,15 +289,12 @@ via_calibrate_decr(void) dend = get_dec(); ppc_tb_freq = (dstart - dend) * 100 / 6; - tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); - - printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n", - tb_ticks_per_jiffy, dstart - dend); iounmap(via); return 1; } +#endif #ifdef CONFIG_PM /* @@ -262,19 +331,17 @@ static struct pmu_sleep_notifier time_sleep_notifier = { /* * Query the OF and get the decr frequency. - * This was taken from the pmac time_init() when merging the prep/pmac - * time functions. */ -void __init -pmac_calibrate_decr(void) +void __init pmac_calibrate_decr(void) { - struct device_node *cpu; - unsigned int freq, *fp; - #ifdef CONFIG_PM + /* XXX why here? */ pmu_register_sleep_notifier(&time_sleep_notifier); #endif /* CONFIG_PM */ + generic_calibrate_decr(); + +#ifdef CONFIG_PPC32 /* We assume MacRISC2 machines have correct device-tree * calibration. That's better since the VIA itself seems * to be slightly off. --BenH @@ -293,18 +360,5 @@ pmac_calibrate_decr(void) if (machine_is_compatible("PowerMac3,5")) if (via_calibrate_decr()) return; - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = find_type_devices("cpu"); - if (cpu == 0) - panic("can't find cpu node in time_init"); - fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); - if (fp == 0) - panic("can't get cpu timebase frequency"); - freq = *fp; - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - ppc_tb_freq = freq; +#endif } diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 8a0969b6243c..b3a93b476d97 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -119,6 +119,8 @@ struct machdep_calls { /* Interface for platform error logging */ void (*log_error)(char *buf, unsigned int err_type, int fatal); + unsigned char (*nvram_read_val)(int addr); + void (*nvram_write_val)(int addr, unsigned char val); ssize_t (*nvram_write)(char *buf, size_t count, loff_t *index); ssize_t (*nvram_read)(char *buf, size_t count, loff_t *index); ssize_t (*nvram_size)(void); @@ -165,15 +167,11 @@ struct machdep_calls { unsigned long heartbeat_reset; unsigned long heartbeat_count; - unsigned long (*find_end_of_memory)(void); void (*setup_io_mappings)(void); void (*early_serial_map)(void); void (*kgdb_map_scc)(void); - unsigned char (*nvram_read_val)(int addr); - void (*nvram_write_val)(int addr, unsigned char val); - /* * optional PCI "hooks" */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index d1e00933354c..2e17ef7dbeb4 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -148,6 +148,8 @@ struct thread_struct; extern struct task_struct * _switch(struct thread_struct *prev, struct thread_struct *next); +extern int powersave_nap; /* set if nap mode can be used in idle loop */ + /* * Atomic exchange * diff --git a/include/asm-ppc64/udbg.h b/include/asm-ppc64/udbg.h index c786604aef02..8192fb8541cc 100644 --- a/include/asm-ppc64/udbg.h +++ b/include/asm-ppc64/udbg.h @@ -28,4 +28,7 @@ extern unsigned long udbg_ifdebug(unsigned long flags); extern void __init ppcdbg_initialize(void); extern void udbg_init_uart(void __iomem *comport, unsigned int speed); + +struct device_node; +extern void udbg_init_scc(struct device_node *np); #endif From 834289447542b7ec55c0847486616d4d53ddf891 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Oct 2005 16:06:27 +1000 Subject: [PATCH 0637/1939] ppc64: Use arch/powerpc/platforms/powermac for powermac build. This switches the ARCH=ppc64 build to use arch/powerpc/platforms/powermac instead of arch/ppc64/kernel/pmac*, and deletes the latter set of files. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Makefile | 4 + arch/ppc64/kernel/Makefile | 10 +- arch/ppc64/kernel/pmac.h | 31 -- arch/ppc64/kernel/pmac_feature.c | 767 ------------------------------ arch/ppc64/kernel/pmac_low_i2c.c | 523 -------------------- arch/ppc64/kernel/pmac_nvram.c | 493 ------------------- arch/ppc64/kernel/pmac_pci.c | 793 ------------------------------- arch/ppc64/kernel/pmac_setup.c | 476 ------------------- arch/ppc64/kernel/pmac_smp.c | 316 ------------ arch/ppc64/kernel/pmac_time.c | 174 ------- 10 files changed, 6 insertions(+), 3581 deletions(-) delete mode 100644 arch/ppc64/kernel/pmac.h delete mode 100644 arch/ppc64/kernel/pmac_feature.c delete mode 100644 arch/ppc64/kernel/pmac_low_i2c.c delete mode 100644 arch/ppc64/kernel/pmac_nvram.c delete mode 100644 arch/ppc64/kernel/pmac_pci.c delete mode 100644 arch/ppc64/kernel/pmac_setup.c delete mode 100644 arch/ppc64/kernel/pmac_smp.c delete mode 100644 arch/ppc64/kernel/pmac_time.c diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 9b54e805b8aa..509622da5408 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,5 +1,9 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_PMAC) += powermac/ +else +ifeq ($(CONFIG_PPC64),y) +obj-$(CONFIG_PPC_PMAC) += powermac/ +endif endif obj-$(CONFIG_4xx) += 4xx/ obj-$(CONFIG_85xx) += 85xx/ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 6c02a79955c7..424dd250cd87 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -56,11 +56,7 @@ obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o -ifneq ($(CONFIG_PPC_MERGE),y) -obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ - pmac_time.o pmac_nvram.o pmac_low_i2c.o \ - udbg_scc.o -endif +obj-$(CONFIG_PPC_PMAC) += udbg_scc.o obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ udbg_16550.o @@ -68,9 +64,7 @@ obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP -ifneq ($(CONFIG_PPC_MERGE),y) -obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o -endif +obj-$(CONFIG_PPC_PMAC) += smp-tbsync.o obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o endif diff --git a/arch/ppc64/kernel/pmac.h b/arch/ppc64/kernel/pmac.h deleted file mode 100644 index fa59f2a5c722..000000000000 --- a/arch/ppc64/kernel/pmac.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __PMAC_H__ -#define __PMAC_H__ - -#include -#include - -/* - * Declaration for the various functions exported by the - * pmac_* files. Mostly for use by pmac_setup - */ - -extern unsigned long pmac_get_boot_time(void); -extern void pmac_get_rtc_time(struct rtc_time *tm); -extern int pmac_set_rtc_time(struct rtc_time *tm); -extern void pmac_read_rtc_time(void); -extern void pmac_calibrate_decr(void); - -extern void pmac_pcibios_fixup(void); -extern void pmac_pci_init(void); -extern void pmac_setup_pci_dma(void); -extern void pmac_check_ht_link(void); - -extern void pmac_setup_smp(void); - -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); - -extern void pmac_nvram_init(void); - -#endif /* __PMAC_H__ */ diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c deleted file mode 100644 index 26075f11db77..000000000000 --- a/arch/ppc64/kernel/pmac_feature.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * arch/ppc/platforms/pmac_feature.c - * - * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * 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. - * - * TODO: - * - * - Replace mdelay with some schedule loop if possible - * - Shorten some obfuscated delays on some routines (like modem - * power) - * - Refcount some clocks (see darwin) - * - Split split split... - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG_FEATURE - -#ifdef DEBUG_FEATURE -#define DBG(fmt...) printk(KERN_DEBUG fmt) -#else -#define DBG(fmt...) -#endif - -/* - * We use a single global lock to protect accesses. Each driver has - * to take care of its own locking - */ -static DEFINE_SPINLOCK(feature_lock); - -#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); -#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); - - -/* - * Instance of some macio stuffs - */ -struct macio_chip macio_chips[MAX_MACIO_CHIPS] ; - -struct macio_chip* macio_find(struct device_node* child, int type) -{ - while(child) { - int i; - - for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) - if (child == macio_chips[i].of_node && - (!type || macio_chips[i].type == type)) - return &macio_chips[i]; - child = child->parent; - } - return NULL; -} -EXPORT_SYMBOL_GPL(macio_find); - -static const char* macio_names[] = -{ - "Unknown", - "Grand Central", - "OHare", - "OHareII", - "Heathrow", - "Gatwick", - "Paddington", - "Keylargo", - "Pangea", - "Intrepid", - "K2" -}; - - - -/* - * Uninorth reg. access. Note that Uni-N regs are big endian - */ - -#define UN_REG(r) (uninorth_base + ((r) >> 2)) -#define UN_IN(r) (in_be32(UN_REG(r))) -#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) -#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) -#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) - -static struct device_node* uninorth_node; -static u32* uninorth_base; -static u32 uninorth_rev; -static void *u3_ht; - -extern struct device_node *k2_skiplist[2]; - -/* - * For each motherboard family, we have a table of functions pointers - * that handle the various features. - */ - -typedef long (*feature_call)(struct device_node* node, long param, long value); - -struct feature_table_entry { - unsigned int selector; - feature_call function; -}; - -struct pmac_mb_def -{ - const char* model_string; - const char* model_name; - int model_id; - struct feature_table_entry* features; - unsigned long board_flags; -}; -static struct pmac_mb_def pmac_mb; - -/* - * Here are the chip specific feature functions - */ - - -static long g5_read_gpio(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - - return MACIO_IN8(param); -} - - -static long g5_write_gpio(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - - MACIO_OUT8(param, (u8)(value & 0xff)); - return 0; -} - -static long g5_gmac_enable(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (node == NULL) - return -ENODEV; - - LOCK(flags); - if (value) { - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); - mb(); - k2_skiplist[0] = NULL; - } else { - k2_skiplist[0] = node; - mb(); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); - } - - UNLOCK(flags); - mdelay(1); - - return 0; -} - -static long g5_fw_enable(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (node == NULL) - return -ENODEV; - - LOCK(flags); - if (value) { - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); - mb(); - k2_skiplist[1] = NULL; - } else { - k2_skiplist[1] = node; - mb(); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); - } - - UNLOCK(flags); - mdelay(1); - - return 0; -} - -static long g5_mpic_enable(struct device_node* node, long param, long value) -{ - unsigned long flags; - - if (node->parent == NULL || strcmp(node->parent->name, "u3")) - return 0; - - LOCK(flags); - UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); - UNLOCK(flags); - - return 0; -} - -static long g5_eth_phy_reset(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - struct device_node *phy; - int need_reset; - - /* - * We must not reset the combo PHYs, only the BCM5221 found in - * the iMac G5. - */ - phy = of_get_next_child(node, NULL); - if (!phy) - return -ENODEV; - need_reset = device_is_compatible(phy, "B5221"); - of_node_put(phy); - if (!need_reset) - return 0; - - /* PHY reset is GPIO 29, not in device-tree unfortunately */ - MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - /* Thankfully, this is now always called at a time when we can - * schedule by sungem. - */ - msleep(10); - MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0); - - return 0; -} - -static long g5_i2s_enable(struct device_node *node, long param, long value) -{ - /* Very crude implementation for now */ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (value == 0) - return 0; /* don't disable yet */ - - LOCK(flags); - MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | - KL3_I2S0_CLK18_ENABLE); - udelay(10); - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | - K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); - udelay(10); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); - UNLOCK(flags); - udelay(10); - - return 0; -} - - -#ifdef CONFIG_SMP -static long g5_reset_cpu(struct device_node* node, long param, long value) -{ - unsigned int reset_io = 0; - unsigned long flags; - struct macio_chip* macio; - struct device_node* np; - - macio = &macio_chips[0]; - if (macio->type != macio_keylargo2) - return -ENODEV; - - np = find_path_device("/cpus"); - if (np == NULL) - return -ENODEV; - for (np = np->child; np != NULL; np = np->sibling) { - u32* num = (u32 *)get_property(np, "reg", NULL); - u32* rst = (u32 *)get_property(np, "soft-reset", NULL); - if (num == NULL || rst == NULL) - continue; - if (param == *num) { - reset_io = *rst; - break; - } - } - if (np == NULL || reset_io == 0) - return -ENODEV; - - LOCK(flags); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)MACIO_IN8(reset_io); - udelay(1); - MACIO_OUT8(reset_io, 0); - (void)MACIO_IN8(reset_io); - UNLOCK(flags); - - return 0; -} -#endif /* CONFIG_SMP */ - -/* - * This can be called from pmac_smp so isn't static - * - * This takes the second CPU off the bus on dual CPU machines - * running UP - */ -void g5_phy_disable_cpu1(void) -{ - UN_OUT(U3_API_PHY_CONFIG_1, 0); -} - -static long generic_get_mb_info(struct device_node* node, long param, long value) -{ - switch(param) { - case PMAC_MB_INFO_MODEL: - return pmac_mb.model_id; - case PMAC_MB_INFO_FLAGS: - return pmac_mb.board_flags; - case PMAC_MB_INFO_NAME: - /* hack hack hack... but should work */ - *((const char **)value) = pmac_mb.model_name; - return 0; - } - return -EINVAL; -} - - -/* - * Table definitions - */ - -/* Used on any machine - */ -static struct feature_table_entry any_features[] = { - { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, - { 0, NULL } -}; - -/* G5 features - */ -static struct feature_table_entry g5_features[] = { - { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, - { PMAC_FTR_1394_ENABLE, g5_fw_enable }, - { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, - { PMAC_FTR_READ_GPIO, g5_read_gpio }, - { PMAC_FTR_WRITE_GPIO, g5_write_gpio }, - { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset }, - { PMAC_FTR_SOUND_CHIP_ENABLE, g5_i2s_enable }, -#ifdef CONFIG_SMP - { PMAC_FTR_RESET_CPU, g5_reset_cpu }, -#endif /* CONFIG_SMP */ - { 0, NULL } -}; - -static struct pmac_mb_def pmac_mb_defs[] = { - { "PowerMac7,2", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5, g5_features, - 0, - }, - { "PowerMac7,3", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5, g5_features, - 0, - }, - { "PowerMac8,1", "iMac G5", - PMAC_TYPE_IMAC_G5, g5_features, - 0, - }, - { "PowerMac9,1", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5_U3L, g5_features, - 0, - }, - { "RackMac3,1", "XServe G5", - PMAC_TYPE_XSERVE_G5, g5_features, - 0, - }, -}; - -/* - * The toplevel feature_call callback - */ -long pmac_do_feature_call(unsigned int selector, ...) -{ - struct device_node* node; - long param, value; - int i; - feature_call func = NULL; - va_list args; - - if (pmac_mb.features) - for (i=0; pmac_mb.features[i].function; i++) - if (pmac_mb.features[i].selector == selector) { - func = pmac_mb.features[i].function; - break; - } - if (!func) - for (i=0; any_features[i].function; i++) - if (any_features[i].selector == selector) { - func = any_features[i].function; - break; - } - if (!func) - return -ENODEV; - - va_start(args, selector); - node = (struct device_node*)va_arg(args, void*); - param = va_arg(args, long); - value = va_arg(args, long); - va_end(args); - - return func(node, param, value); -} - -static int __init probe_motherboard(void) -{ - int i; - struct macio_chip* macio = &macio_chips[0]; - const char* model = NULL; - struct device_node *dt; - - /* Lookup known motherboard type in device-tree. First try an - * exact match on the "model" property, then try a "compatible" - * match is none is found. - */ - dt = find_devices("device-tree"); - if (dt != NULL) - model = (const char *) get_property(dt, "model", NULL); - for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { - if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { - pmac_mb = pmac_mb_defs[i]; - goto found; - } - } - for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { - if (machine_is_compatible(pmac_mb_defs[i].model_string)) { - pmac_mb = pmac_mb_defs[i]; - goto found; - } - } - - /* Fallback to selection depending on mac-io chip type */ - switch(macio->type) { - case macio_keylargo2: - pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; - pmac_mb.model_name = "Unknown K2-based"; - pmac_mb.features = g5_features; - - default: - return -ENODEV; - } -found: - /* Check for "mobile" machine */ - if (model && (strncmp(model, "PowerBook", 9) == 0 - || strncmp(model, "iBook", 5) == 0)) - pmac_mb.board_flags |= PMAC_MB_MOBILE; - - - printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); - return 0; -} - -/* Initialize the Core99 UniNorth host bridge and memory controller - */ -static void __init probe_uninorth(void) -{ - uninorth_node = of_find_node_by_name(NULL, "u3"); - if (uninorth_node && uninorth_node->n_addrs > 0) { - /* Small hack until I figure out if parsing in prom.c is correct. I should - * get rid of those pre-parsed junk anyway - */ - unsigned long address = uninorth_node->addrs[0].address; - uninorth_base = ioremap(address, 0x40000); - uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); - } else - uninorth_node = NULL; - - if (!uninorth_node) - return; - - printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n", - uninorth_rev); - printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); - -} - -static void __init probe_one_macio(const char* name, const char* compat, int type) -{ - struct device_node* node; - int i; - volatile u32* base; - u32* revp; - - node = find_devices(name); - if (!node || !node->n_addrs) - return; - if (compat) - do { - if (device_is_compatible(node, compat)) - break; - node = node->next; - } while (node); - if (!node) - return; - for(i=0; i= MAX_MACIO_CHIPS) { - printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); - printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); - return; - } - base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); - if (!base) { - printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); - return; - } - if (type == macio_keylargo) { - u32* did = (u32 *)get_property(node, "device-id", NULL); - if (*did == 0x00000025) - type = macio_pangea; - if (*did == 0x0000003e) - type = macio_intrepid; - } - macio_chips[i].of_node = node; - macio_chips[i].type = type; - macio_chips[i].base = base; - macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; - macio_chips[i].name = macio_names[type]; - revp = (u32 *)get_property(node, "revision-id", NULL); - if (revp) - macio_chips[i].rev = *revp; - printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", - macio_names[type], macio_chips[i].rev, macio_chips[i].base); -} - -static int __init -probe_macios(void) -{ - probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); - - macio_chips[0].lbus.index = 0; - macio_chips[1].lbus.index = 1; - - return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; -} - -static void __init -set_initial_features(void) -{ - struct device_node *np; - - if (macio_chips[0].type == macio_keylargo2) { -#ifndef CONFIG_SMP - /* On SMP machines running UP, we have the second CPU eating - * bus cycles. We need to take it off the bus. This is done - * from pmac_smp for SMP kernels running on one CPU - */ - np = of_find_node_by_type(NULL, "cpu"); - if (np != NULL) - np = of_find_node_by_type(np, "cpu"); - if (np != NULL) { - g5_phy_disable_cpu1(); - of_node_put(np); - } -#endif /* CONFIG_SMP */ - /* Enable GMAC for now for PCI probing. It will be disabled - * later on after PCI probe - */ - np = of_find_node_by_name(NULL, "ethernet"); - while(np) { - if (device_is_compatible(np, "K2-GMAC")) - g5_gmac_enable(np, 0, 1); - np = of_find_node_by_name(np, "ethernet"); - } - - /* Enable FW before PCI probe. Will be disabled later on - * Note: We should have a batter way to check that we are - * dealing with uninorth internal cell and not a PCI cell - * on the external PCI. The code below works though. - */ - np = of_find_node_by_name(NULL, "firewire"); - while(np) { - if (device_is_compatible(np, "pci106b,5811")) { - macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; - g5_fw_enable(np, 0, 1); - } - np = of_find_node_by_name(np, "firewire"); - } - } -} - -void __init -pmac_feature_init(void) -{ - /* Detect the UniNorth memory controller */ - probe_uninorth(); - - /* Probe mac-io controllers */ - if (probe_macios()) { - printk(KERN_WARNING "No mac-io chip found\n"); - return; - } - - /* Setup low-level i2c stuffs */ - pmac_init_low_i2c(); - - /* Probe machine type */ - if (probe_motherboard()) - printk(KERN_WARNING "Unknown PowerMac !\n"); - - /* Set some initial features (turn off some chips that will - * be later turned on) - */ - set_initial_features(); -} - -int __init pmac_feature_late_init(void) -{ -#if 0 - struct device_node* np; - - /* Request some resources late */ - if (uninorth_node) - request_OF_resource(uninorth_node, 0, NULL); - np = find_devices("hammerhead"); - if (np) - request_OF_resource(np, 0, NULL); - np = find_devices("interrupt-controller"); - if (np) - request_OF_resource(np, 0, NULL); -#endif - return 0; -} - -device_initcall(pmac_feature_late_init); - -#if 0 -static void dump_HT_speeds(char *name, u32 cfg, u32 frq) -{ - int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; - int bits[8] = { 8,16,0,32,2,4,0,0 }; - int freq = (frq >> 8) & 0xf; - - if (freqs[freq] == 0) - printk("%s: Unknown HT link frequency %x\n", name, freq); - else - printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", - name, freqs[freq], - bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); -} -#endif - -void __init pmac_check_ht_link(void) -{ -#if 0 /* Disabled for now */ - u32 ufreq, freq, ucfg, cfg; - struct device_node *pcix_node; - struct pci_dn *pdn; - u8 px_bus, px_devfn; - struct pci_controller *px_hose; - - (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); - ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); - ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); - dump_HT_speeds("U3 HyperTransport", cfg, freq); - - pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); - if (pcix_node == NULL) { - printk("No PCI-X bridge found\n"); - return; - } - pdn = pcix_node->data; - px_hose = pdn->phb; - px_bus = pdn->busno; - px_devfn = pdn->devfn; - - early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); - dump_HT_speeds("PCI-X HT Uplink", cfg, freq); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); - dump_HT_speeds("PCI-X HT Downlink", cfg, freq); -#endif -} - -/* - * Early video resume hook - */ - -static void (*pmac_early_vresume_proc)(void *data); -static void *pmac_early_vresume_data; - -void pmac_set_early_video_resume(void (*proc)(void *data), void *data) -{ - if (_machine != _MACH_Pmac) - return; - preempt_disable(); - pmac_early_vresume_proc = proc; - pmac_early_vresume_data = data; - preempt_enable(); -} -EXPORT_SYMBOL(pmac_set_early_video_resume); - - -/* - * AGP related suspend/resume code - */ - -static struct pci_dev *pmac_agp_bridge; -static int (*pmac_agp_suspend)(struct pci_dev *bridge); -static int (*pmac_agp_resume)(struct pci_dev *bridge); - -void pmac_register_agp_pm(struct pci_dev *bridge, - int (*suspend)(struct pci_dev *bridge), - int (*resume)(struct pci_dev *bridge)) -{ - if (suspend || resume) { - pmac_agp_bridge = bridge; - pmac_agp_suspend = suspend; - pmac_agp_resume = resume; - return; - } - if (bridge != pmac_agp_bridge) - return; - pmac_agp_suspend = pmac_agp_resume = NULL; - return; -} -EXPORT_SYMBOL(pmac_register_agp_pm); - -void pmac_suspend_agp_for_card(struct pci_dev *dev) -{ - if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) - return; - if (pmac_agp_bridge->bus != dev->bus) - return; - pmac_agp_suspend(pmac_agp_bridge); -} -EXPORT_SYMBOL(pmac_suspend_agp_for_card); - -void pmac_resume_agp_for_card(struct pci_dev *dev) -{ - if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) - return; - if (pmac_agp_bridge->bus != dev->bus) - return; - pmac_agp_resume(pmac_agp_bridge); -} -EXPORT_SYMBOL(pmac_resume_agp_for_card); diff --git a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c deleted file mode 100644 index f3f39e8e337a..000000000000 --- a/arch/ppc64/kernel/pmac_low_i2c.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * arch/ppc/platforms/pmac_low_i2c.c - * - * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * 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 file contains some low-level i2c access routines that - * need to be used by various bits of the PowerMac platform code - * at times where the real asynchronous & interrupt driven driver - * cannot be used. The API borrows some semantics from the darwin - * driver in order to ease the implementation of the platform - * properties parser - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_LOW_I2C_HOST 4 - -#ifdef DEBUG -#define DBG(x...) do {\ - printk(KERN_DEBUG "KW:" x); \ - } while(0) -#else -#define DBG(x...) -#endif - -struct low_i2c_host; - -typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); - -struct low_i2c_host -{ - struct device_node *np; /* OF device node */ - struct semaphore mutex; /* Access mutex for use by i2c-keywest */ - low_i2c_func_t func; /* Access function */ - unsigned int is_open : 1; /* Poor man's access control */ - int mode; /* Current mode */ - int channel; /* Current channel */ - int num_channels; /* Number of channels */ - void __iomem *base; /* For keywest-i2c, base address */ - int bsteps; /* And register stepping */ - int speed; /* And speed */ -}; - -static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; - -/* No locking is necessary on allocation, we are running way before - * anything can race with us - */ -static struct low_i2c_host *find_low_i2c_host(struct device_node *np) -{ - int i; - - for (i = 0; i < MAX_LOW_I2C_HOST; i++) - if (low_i2c_hosts[i].np == np) - return &low_i2c_hosts[i]; - return NULL; -} - -/* - * - * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) - * - */ - -/* - * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, - * should be moved somewhere in include/asm-ppc/ - */ -/* Register indices */ -typedef enum { - reg_mode = 0, - reg_control, - reg_status, - reg_isr, - reg_ier, - reg_addr, - reg_subaddr, - reg_data -} reg_t; - - -/* Mode register */ -#define KW_I2C_MODE_100KHZ 0x00 -#define KW_I2C_MODE_50KHZ 0x01 -#define KW_I2C_MODE_25KHZ 0x02 -#define KW_I2C_MODE_DUMB 0x00 -#define KW_I2C_MODE_STANDARD 0x04 -#define KW_I2C_MODE_STANDARDSUB 0x08 -#define KW_I2C_MODE_COMBINED 0x0C -#define KW_I2C_MODE_MODE_MASK 0x0C -#define KW_I2C_MODE_CHAN_MASK 0xF0 - -/* Control register */ -#define KW_I2C_CTL_AAK 0x01 -#define KW_I2C_CTL_XADDR 0x02 -#define KW_I2C_CTL_STOP 0x04 -#define KW_I2C_CTL_START 0x08 - -/* Status register */ -#define KW_I2C_STAT_BUSY 0x01 -#define KW_I2C_STAT_LAST_AAK 0x02 -#define KW_I2C_STAT_LAST_RW 0x04 -#define KW_I2C_STAT_SDA 0x08 -#define KW_I2C_STAT_SCL 0x10 - -/* IER & ISR registers */ -#define KW_I2C_IRQ_DATA 0x01 -#define KW_I2C_IRQ_ADDR 0x02 -#define KW_I2C_IRQ_STOP 0x04 -#define KW_I2C_IRQ_START 0x08 -#define KW_I2C_IRQ_MASK 0x0F - -/* State machine states */ -enum { - state_idle, - state_addr, - state_read, - state_write, - state_stop, - state_dead -}; - -#define WRONG_STATE(name) do {\ - printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ - name, __kw_state_names[state], isr); \ - } while(0) - -static const char *__kw_state_names[] = { - "state_idle", - "state_addr", - "state_read", - "state_write", - "state_stop", - "state_dead" -}; - -static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) -{ - return readb(host->base + (((unsigned int)reg) << host->bsteps)); -} - -static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) -{ - writeb(val, host->base + (((unsigned)reg) << host->bsteps)); - (void)__kw_read_reg(host, reg_subaddr); -} - -#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) -#define kw_read_reg(reg) __kw_read_reg(host, reg) - - -/* Don't schedule, the g5 fan controller is too - * timing sensitive - */ -static u8 kw_wait_interrupt(struct low_i2c_host* host) -{ - int i, j; - u8 isr; - - for (i = 0; i < 100000; i++) { - isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; - if (isr != 0) - return isr; - - /* This code is used with the timebase frozen, we cannot rely - * on udelay ! For now, just use a bogus loop - */ - for (j = 1; j < 10000; j++) - mb(); - } - return isr; -} - -static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) -{ - u8 ack; - - DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); - - if (isr == 0) { - if (state != state_stop) { - DBG("KW: Timeout !\n"); - *rc = -EIO; - goto stop; - } - if (state == state_stop) { - ack = kw_read_reg(reg_status); - if (!(ack & KW_I2C_STAT_BUSY)) { - state = state_idle; - kw_write_reg(reg_ier, 0x00); - } - } - return state; - } - - if (isr & KW_I2C_IRQ_ADDR) { - ack = kw_read_reg(reg_status); - if (state != state_addr) { - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); - WRONG_STATE("KW_I2C_IRQ_ADDR"); - *rc = -EIO; - goto stop; - } - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - *rc = -ENODEV; - DBG("KW: NAK on address\n"); - return state_stop; - } else { - if (rw) { - state = state_read; - if (*len > 1) - kw_write_reg(reg_control, KW_I2C_CTL_AAK); - } else { - state = state_write; - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; - } - } - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); - } - - if (isr & KW_I2C_IRQ_DATA) { - if (state == state_read) { - **data = kw_read_reg(reg_data); - (*data)++; (*len)--; - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - if ((*len) == 0) - state = state_stop; - else if ((*len) == 1) - kw_write_reg(reg_control, 0); - } else if (state == state_write) { - ack = kw_read_reg(reg_status); - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - DBG("KW: nack on data write\n"); - *rc = -EIO; - goto stop; - } else if (*len) { - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; - } else { - kw_write_reg(reg_control, KW_I2C_CTL_STOP); - state = state_stop; - *rc = 0; - } - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - } else { - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - WRONG_STATE("KW_I2C_IRQ_DATA"); - if (state != state_stop) { - *rc = -EIO; - goto stop; - } - } - } - - if (isr & KW_I2C_IRQ_STOP) { - kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); - if (state != state_stop) { - WRONG_STATE("KW_I2C_IRQ_STOP"); - *rc = -EIO; - } - return state_idle; - } - - if (isr & KW_I2C_IRQ_START) - kw_write_reg(reg_isr, KW_I2C_IRQ_START); - - return state; - - stop: - kw_write_reg(reg_control, KW_I2C_CTL_STOP); - return state_stop; -} - -static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) -{ - u8 mode_reg = host->speed; - int state = state_addr; - int rc = 0; - - /* Setup mode & subaddress if any */ - switch(host->mode) { - case pmac_low_i2c_mode_dumb: - printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); - return -EINVAL; - case pmac_low_i2c_mode_std: - mode_reg |= KW_I2C_MODE_STANDARD; - break; - case pmac_low_i2c_mode_stdsub: - mode_reg |= KW_I2C_MODE_STANDARDSUB; - break; - case pmac_low_i2c_mode_combined: - mode_reg |= KW_I2C_MODE_COMBINED; - break; - } - - /* Setup channel & clear pending irqs */ - kw_write_reg(reg_isr, kw_read_reg(reg_isr)); - kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); - kw_write_reg(reg_status, 0); - - /* Set up address and r/w bit */ - kw_write_reg(reg_addr, addr); - - /* Set up the sub address */ - if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB - || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) - kw_write_reg(reg_subaddr, subaddr); - - /* Start sending address & disable interrupt*/ - kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); - kw_write_reg(reg_control, KW_I2C_CTL_XADDR); - - /* State machine, to turn into an interrupt handler */ - while(state != state_idle) { - u8 isr = kw_wait_interrupt(host); - state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); - } - - return rc; -} - -static void keywest_low_i2c_add(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(NULL); - u32 *psteps, *prate, steps, aoffset = 0; - struct device_node *parent; - - if (host == NULL) { - printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", - np->full_name); - return; - } - memset(host, 0, sizeof(*host)); - - init_MUTEX(&host->mutex); - host->np = of_node_get(np); - psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); - steps = psteps ? (*psteps) : 0x10; - for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) - steps >>= 1; - parent = of_get_parent(np); - host->num_channels = 1; - if (parent && parent->name[0] == 'u') { - host->num_channels = 2; - aoffset = 3; - } - /* Select interface rate */ - host->speed = KW_I2C_MODE_100KHZ; - prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); - if (prate) switch(*prate) { - case 100: - host->speed = KW_I2C_MODE_100KHZ; - break; - case 50: - host->speed = KW_I2C_MODE_50KHZ; - break; - case 25: - host->speed = KW_I2C_MODE_25KHZ; - break; - } - - host->mode = pmac_low_i2c_mode_std; - host->base = ioremap(np->addrs[0].address + aoffset, - np->addrs[0].size); - host->func = keywest_low_i2c_func; -} - -/* - * - * PMU implementation - * - */ - - -#ifdef CONFIG_ADB_PMU - -static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) -{ - // TODO - return -ENODEV; -} - -static void pmu_low_i2c_add(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(NULL); - - if (host == NULL) { - printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", - np->full_name); - return; - } - memset(host, 0, sizeof(*host)); - - init_MUTEX(&host->mutex); - host->np = of_node_get(np); - host->num_channels = 3; - host->mode = pmac_low_i2c_mode_std; - host->func = pmu_low_i2c_func; -} - -#endif /* CONFIG_ADB_PMU */ - -void __init pmac_init_low_i2c(void) -{ - struct device_node *np; - - /* Probe keywest-i2c busses */ - np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); - while(np) { - keywest_low_i2c_add(np); - np = of_find_compatible_node(np, "i2c", "keywest-i2c"); - } - -#ifdef CONFIG_ADB_PMU - /* Probe PMU busses */ - np = of_find_node_by_name(NULL, "via-pmu"); - if (np) - pmu_low_i2c_add(np); -#endif /* CONFIG_ADB_PMU */ - - /* TODO: Add CUDA support as well */ -} - -int pmac_low_i2c_lock(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - down(&host->mutex); - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_lock); - -int pmac_low_i2c_unlock(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - up(&host->mutex); - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_unlock); - - -int pmac_low_i2c_open(struct device_node *np, int channel) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - - if (channel >= host->num_channels) - return -EINVAL; - - down(&host->mutex); - host->is_open = 1; - host->channel = channel; - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_open); - -int pmac_low_i2c_close(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - - host->is_open = 0; - up(&host->mutex); - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_close); - -int pmac_low_i2c_setmode(struct device_node *np, int mode) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); - host->mode = mode; - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_setmode); - -int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); - - return host->func(host, addrdir, subaddr, data, len); -} -EXPORT_SYMBOL(pmac_low_i2c_xfer); - diff --git a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c deleted file mode 100644 index 5fe9785ad7d8..000000000000 --- a/arch/ppc64/kernel/pmac_nvram.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * arch/ppc/platforms/pmac_nvram.c - * - * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * - * 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. - * - * Todo: - add support for the OF persistent properties - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ - -#define CORE99_SIGNATURE 0x5a -#define CORE99_ADLER_START 0x14 - -/* On Core99, nvram is either a sharp, a micron or an AMD flash */ -#define SM_FLASH_STATUS_DONE 0x80 -#define SM_FLASH_STATUS_ERR 0x38 - -#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 -#define SM_FLASH_CMD_ERASE_SETUP 0x20 -#define SM_FLASH_CMD_RESET 0xff -#define SM_FLASH_CMD_WRITE_SETUP 0x40 -#define SM_FLASH_CMD_CLEAR_STATUS 0x50 -#define SM_FLASH_CMD_READ_STATUS 0x70 - -/* CHRP NVRAM header */ -struct chrp_header { - u8 signature; - u8 cksum; - u16 len; - char name[12]; - u8 data[0]; -}; - -struct core99_header { - struct chrp_header hdr; - u32 adler; - u32 generation; - u32 reserved[2]; -}; - -/* - * Read and write the non-volatile RAM on PowerMacs and CHRP machines. - */ -static volatile unsigned char *nvram_data; -static int core99_bank = 0; -// XXX Turn that into a sem -static DEFINE_SPINLOCK(nv_lock); - -extern int system_running; - -static int (*core99_write_bank)(int bank, u8* datas); -static int (*core99_erase_bank)(int bank); - -static char *nvram_image; - - -static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index) -{ - int i; - - if (nvram_image == NULL) - return -ENODEV; - if (*index > NVRAM_SIZE) - return 0; - - i = *index; - if (i + count > NVRAM_SIZE) - count = NVRAM_SIZE - i; - - memcpy(buf, &nvram_image[i], count); - *index = i + count; - return count; -} - -static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index) -{ - int i; - - if (nvram_image == NULL) - return -ENODEV; - if (*index > NVRAM_SIZE) - return 0; - - i = *index; - if (i + count > NVRAM_SIZE) - count = NVRAM_SIZE - i; - - memcpy(&nvram_image[i], buf, count); - *index = i + count; - return count; -} - -static ssize_t core99_nvram_size(void) -{ - if (nvram_image == NULL) - return -ENODEV; - return NVRAM_SIZE; -} - -static u8 chrp_checksum(struct chrp_header* hdr) -{ - u8 *ptr; - u16 sum = hdr->signature; - for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) - sum += *ptr; - while (sum > 0xFF) - sum = (sum & 0xFF) + (sum>>8); - return sum; -} - -static u32 core99_calc_adler(u8 *buffer) -{ - int cnt; - u32 low, high; - - buffer += CORE99_ADLER_START; - low = 1; - high = 0; - for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { - if ((cnt % 5000) == 0) { - high %= 65521UL; - high %= 65521UL; - } - low += buffer[cnt]; - high += low; - } - low %= 65521UL; - high %= 65521UL; - - return (high << 16) | low; -} - -static u32 core99_check(u8* datas) -{ - struct core99_header* hdr99 = (struct core99_header*)datas; - - if (hdr99->hdr.signature != CORE99_SIGNATURE) { - DBG("Invalid signature\n"); - return 0; - } - if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { - DBG("Invalid checksum\n"); - return 0; - } - if (hdr99->adler != core99_calc_adler(datas)) { - DBG("Invalid adler\n"); - return 0; - } - return hdr99->generation; -} - -static int sm_erase_bank(int bank) -{ - int stat, i; - unsigned long timeout; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); - - out_8(base, SM_FLASH_CMD_ERASE_SETUP); - out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); - timeout = 0; - do { - if (++timeout > 1000000) { - printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); - break; - } - out_8(base, SM_FLASH_CMD_READ_STATUS); - stat = in_8(base); - } while (!(stat & SM_FLASH_STATUS_DONE)); - - out_8(base, SM_FLASH_CMD_CLEAR_STATUS); - out_8(base, SM_FLASH_CMD_RESET); - - for (i=0; i 1000000) { - printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); - break; - } - out_8(base, SM_FLASH_CMD_READ_STATUS); - stat = in_8(base); - } while (!(stat & SM_FLASH_STATUS_DONE)); - if (!(stat & SM_FLASH_STATUS_DONE)) - break; - } - out_8(base, SM_FLASH_CMD_CLEAR_STATUS); - out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i 1000000) { - printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); - break; - } - stat = in_8(base) ^ in_8(base); - } while (stat != 0); - - /* Reset */ - out_8(base, 0xf0); - udelay(1); - - for (i=0; i 1000000) { - printk(KERN_ERR "nvram: AMD flash write timeout !\n"); - break; - } - stat = in_8(base) ^ in_8(base); - } while (stat != 0); - if (stat != 0) - break; - } - - /* Reset */ - out_8(base, 0xf0); - udelay(1); - - for (i=0; igeneration++; - hdr99->hdr.signature = CORE99_SIGNATURE; - hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); - hdr99->adler = core99_calc_adler(nvram_image); - core99_bank = core99_bank ? 0 : 1; - if (core99_erase_bank) - if (core99_erase_bank(core99_bank)) { - printk("nvram: Error erasing bank %d\n", core99_bank); - goto bail; - } - if (core99_write_bank) - if (core99_write_bank(core99_bank, nvram_image)) - printk("nvram: Error writing bank %d\n", core99_bank); - bail: - spin_unlock_irqrestore(&nv_lock, flags); -} - -int __init pmac_nvram_init(void) -{ - struct device_node *dp; - u32 gen_bank0, gen_bank1; - int i; - - dp = find_devices("nvram"); - if (dp == NULL) { - printk(KERN_ERR "Can't find NVRAM device\n"); - return -ENODEV; - } - if (!device_is_compatible(dp, "nvram,flash")) { - printk(KERN_ERR "Incompatible type of NVRAM\n"); - return -ENXIO; - } - - nvram_image = alloc_bootmem(NVRAM_SIZE); - if (nvram_image == NULL) { - printk(KERN_ERR "nvram: can't allocate ram image\n"); - return -ENOMEM; - } - nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); - - DBG("nvram: Checking bank 0...\n"); - - gen_bank0 = core99_check((u8 *)nvram_data); - gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); - core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; - - DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); - DBG("nvram: Active bank is: %d\n", core99_bank); - - for (i=0; iindex; -} - -u8 pmac_xpram_read(int xpaddr) -{ - int offset = pmac_get_partition(pmac_nvram_XPRAM); - loff_t index; - u8 buf; - ssize_t count; - - if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) - return 0xff; - index = offset + xpaddr; - - count = ppc_md.nvram_read(&buf, 1, &index); - if (count != 1) - return 0xff; - return buf; -} - -void pmac_xpram_write(int xpaddr, u8 data) -{ - int offset = pmac_get_partition(pmac_nvram_XPRAM); - loff_t index; - u8 buf; - - if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) - return; - index = offset + xpaddr; - buf = data; - - ppc_md.nvram_write(&buf, 1, &index); -} - -EXPORT_SYMBOL(pmac_get_partition); -EXPORT_SYMBOL(pmac_xpram_read); -EXPORT_SYMBOL(pmac_xpram_write); diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c deleted file mode 100644 index 7a81c8275940..000000000000 --- a/arch/ppc64/kernel/pmac_pci.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Support for PCI bridges found on Power Macintoshes. - * At present the "bandit" and "chaos" bridges are supported. - * Fortunately you access configuration space in the same - * way with either bridge. - * - * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) - * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) - * - * 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 "pmac.h" - -#define DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* XXX Could be per-controller, but I don't think we risk anything by - * assuming we won't have both UniNorth and Bandit */ -static int has_uninorth; -static struct pci_controller *u3_agp; -struct device_node *k2_skiplist[2]; - -static int __init fixup_one_level_bus_range(struct device_node *node, int higher) -{ - for (; node != 0;node = node->sibling) { - int * bus_range; - unsigned int *class_code; - int len; - - /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = (unsigned int *) get_property(node, "class-code", NULL); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - bus_range = (int *) get_property(node, "bus-range", &len); - if (bus_range != NULL && len > 2 * sizeof(int)) { - if (bus_range[1] > higher) - higher = bus_range[1]; - } - higher = fixup_one_level_bus_range(node->child, higher); - } - return higher; -} - -/* This routine fixes the "bus-range" property of all bridges in the - * system since they tend to have their "last" member wrong on macs - * - * Note that the bus numbers manipulated here are OF bus numbers, they - * are not Linux bus numbers. - */ -static void __init fixup_bus_range(struct device_node *bridge) -{ - int * bus_range; - int len; - - /* Lookup the "bus-range" property for the hose */ - bus_range = (int *) get_property(bridge, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - bridge->full_name); - return; - } - bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); -} - -/* - * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers. - * - * The "Bandit" version is present in all early PCI PowerMacs, - * and up to the first ones using Grackle. Some machines may - * have 2 bandit controllers (2 PCI busses). - * - * "Chaos" is used in some "Bandit"-type machines as a bridge - * for the separate display bus. It is accessed the same - * way as bandit, but cannot be probed for devices. It therefore - * has its own config access functions. - * - * The "UniNorth" version is present in all Core99 machines - * (iBook, G4, new IMacs, and all the recent Apple machines). - * It contains 3 controllers in one ASIC. - * - * The U3 is the bridge used on G5 machines. It contains on - * AGP bus which is dealt with the old UniNorth access routines - * and an HyperTransport bus which uses its own set of access - * functions. - */ - -#define MACRISC_CFA0(devfn, off) \ - ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ - | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ - | (((unsigned long)(off)) & 0xFCUL)) - -#define MACRISC_CFA1(bus, devfn, off) \ - ((((unsigned long)(bus)) << 16) \ - |(((unsigned long)(devfn)) << 8) \ - |(((unsigned long)(off)) & 0xFCUL) \ - |1UL) - -static unsigned long macrisc_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) { - if (dev_fn < (11 << 3)) - return 0; - caddr = MACRISC_CFA0(dev_fn, offset); - } else - caddr = MACRISC_CFA1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while (in_le32(hose->cfg_addr) != caddr); - - offset &= has_uninorth ? 0x07 : 0x03; - return ((unsigned long)hose->cfg_data) + offset; -} - -static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops macrisc_pci_ops = -{ - macrisc_read_config, - macrisc_write_config -}; - -/* - * These versions of U3 HyperTransport config space access ops do not - * implement self-view of the HT host yet - */ - -/* - * This function deals with some "special cases" devices. - * - * 0 -> No special case - * 1 -> Skip the device but act as if the access was successfull - * (return 0xff's on reads, eventually, cache config space - * accesses in a later version) - * -1 -> Hide the device (unsuccessful acess) - */ -static int u3_ht_skip_device(struct pci_controller *hose, - struct pci_bus *bus, unsigned int devfn) -{ - struct device_node *busdn, *dn; - int i; - - /* We only allow config cycles to devices that are in OF device-tree - * as we are apparently having some weird things going on with some - * revs of K2 on recent G5s - */ - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = hose->arch_data; - for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->data && PCI_DN(dn)->devfn == devfn) - break; - if (dn == NULL) - return -1; - - /* - * When a device in K2 is powered down, we die on config - * cycle accesses. Fix that here. - */ - for (i=0; i<2; i++) - if (k2_skiplist[i] == dn) - return 1; - - return 0; -} - -#define U3_HT_CFA0(devfn, off) \ - ((((unsigned long)devfn) << 8) | offset) -#define U3_HT_CFA1(bus, devfn, off) \ - (U3_HT_CFA0(devfn, off) \ - + (((unsigned long)bus) << 16) \ - + 0x01000000UL) - -static unsigned long u3_ht_cfg_access(struct pci_controller* hose, - u8 bus, u8 devfn, u8 offset) -{ - if (bus == hose->first_busno) { - /* For now, we don't self probe U3 HT bridge */ - if (PCI_SLOT(devfn) == 0) - return 0; - return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); - } else - return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); -} - -static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (u3_ht_skip_device(hose, bus, devfn)) { - case 0: - break; - case 1: - switch (len) { - case 1: - *val = 0xff; break; - case 2: - *val = 0xffff; break; - default: - *val = 0xfffffffful; break; - } - return PCIBIOS_SUCCESSFUL; - default: - return PCIBIOS_DEVICE_NOT_FOUND; - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (u3_ht_skip_device(hose, bus, devfn)) { - case 0: - break; - case 1: - return PCIBIOS_SUCCESSFUL; - default: - return PCIBIOS_DEVICE_NOT_FOUND; - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_ht_pci_ops = -{ - u3_ht_read_config, - u3_ht_write_config -}; - -static void __init setup_u3_agp(struct pci_controller* hose) -{ - /* On G5, we move AGP up to high bus number so we don't need - * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_buses to the - * pci_controller structure so we enable it for AGP and not for - * HT childs. - * We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->first_busno = 0xf0; - hose->last_busno = 0xff; - has_uninorth = 1; - hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); - hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - - u3_agp = hose; -} - -static void __init setup_u3_ht(struct pci_controller* hose) -{ - struct device_node *np = (struct device_node *)hose->arch_data; - int i, cur; - - hose->ops = &u3_ht_pci_ops; - - /* We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); - - /* - * /ht node doesn't expose a "ranges" property, so we "remove" regions that - * have been allocated to AGP. So far, this version of the code doesn't assign - * any of the 0xfxxxxxxx "fine" memory regions to /ht. - * We need to fix that sooner or later by either parsing all child "ranges" - * properties or figuring out the U3 address space decoding logic and - * then read it's configuration register (if any). - */ - hose->io_base_phys = 0xf4000000; - hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); - isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; - hose->io_resource.name = np->full_name; - hose->io_resource.start = 0; - hose->io_resource.end = 0x003fffff; - hose->io_resource.flags = IORESOURCE_IO; - hose->pci_mem_offset = 0; - hose->first_busno = 0; - hose->last_busno = 0xef; - hose->mem_resources[0].name = np->full_name; - hose->mem_resources[0].start = 0x80000000; - hose->mem_resources[0].end = 0xefffffff; - hose->mem_resources[0].flags = IORESOURCE_MEM; - - if (u3_agp == NULL) { - DBG("U3 has no AGP, using full resource range\n"); - return; - } - - /* We "remove" the AGP resources from the resources allocated to HT, that - * is we create "holes". However, that code does assumptions that so far - * happen to be true (cross fingers...), typically that resources in the - * AGP node are properly ordered - */ - cur = 0; - for (i=0; i<3; i++) { - struct resource *res = &u3_agp->mem_resources[i]; - if (res->flags != IORESOURCE_MEM) - continue; - /* We don't care about "fine" resources */ - if (res->start >= 0xf0000000) - continue; - /* Check if it's just a matter of "shrinking" us in one direction */ - if (hose->mem_resources[cur].start == res->start) { - DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", - cur, hose->mem_resources[cur].start, res->end + 1); - hose->mem_resources[cur].start = res->end + 1; - continue; - } - if (hose->mem_resources[cur].end == res->end) { - DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", - cur, hose->mem_resources[cur].end, res->start - 1); - hose->mem_resources[cur].end = res->start - 1; - continue; - } - /* No, it's not the case, we need a hole */ - if (cur == 2) { - /* not enough resources for a hole, we drop part of the range */ - printk(KERN_WARNING "Running out of resources for /ht host !\n"); - hose->mem_resources[cur].end = res->start - 1; - continue; - } - cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", - cur-1, res->start - 1, cur, res->end + 1); - hose->mem_resources[cur].name = np->full_name; - hose->mem_resources[cur].flags = IORESOURCE_MEM; - hose->mem_resources[cur].start = res->end + 1; - hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; - hose->mem_resources[cur-1].end = res->start - 1; - } -} - -static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - static unsigned int static_lc_ranges[2024]; - unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; - unsigned int size; - int rlen = 0, orig_rlen; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - - np = na + 5; - - /* First we try to merge ranges to fix a problem with some pmacs - * that can have more than 3 ranges, fortunately using contiguous - * addresses -- BenH - */ - dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - if (!dt_ranges) - return; - /* lc_ranges = alloc_bootmem(rlen);*/ - lc_ranges = static_lc_ranges; - if (!lc_ranges) - return; /* what can we do here ? */ - memcpy(lc_ranges, dt_ranges, rlen); - orig_rlen = rlen; - - /* Let's work on a copy of the "ranges" property instead of damaging - * the device-tree image in memory - */ - ranges = lc_ranges; - prev = NULL; - while ((rlen -= np * sizeof(unsigned int)) >= 0) { - if (prev) { - if (prev[0] == ranges[0] && prev[1] == ranges[1] && - (prev[2] + prev[na+4]) == ranges[2] && - (prev[na+2] + prev[na+4]) == ranges[na+2]) { - prev[na+4] += ranges[na+4]; - ranges[0] = 0; - ranges += np; - continue; - } - } - prev = ranges; - ranges += np; - } - - /* - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (size depending on dev->n_addr_cells) - * cells 4+5 or 5+6: the size of the range - */ - ranges = lc_ranges; - rlen = orig_rlen; - while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { - res = NULL; - size = ranges[na+4]; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[na+2]; - /* limit I/O space to 16MB */ - if (size > 0x01000000) - size = 0x01000000; - hose->io_base_virt = ioremap(ranges[na+2], size); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[na+4] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ -#if 0 - if (primary) - isa_mem_base = ranges[na+2]; -#endif - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[na+2] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[na+2]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - -/* - * We assume that if we have a G3 powermac, we have one bridge called - * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, - * if we have one or more bandit or chaos bridges, we don't have a MPC106. - */ -static int __init add_bridge(struct device_node *dev) -{ - int len; - struct pci_controller *hose; - char* disp_name; - int *bus_range; - int primary = 1; - struct property *of_prop; - - DBG("Adding PCI host bridge %s\n", dev->full_name); - - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } - - hose = alloc_bootmem(sizeof(struct pci_controller)); - if (hose == NULL) - return -ENOMEM; - pci_setup_pci_controller(hose); - - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - of_prop = alloc_bootmem(sizeof(struct property) + - sizeof(hose->global_number)); - if (of_prop) { - memset(of_prop, 0, sizeof(struct property)); - of_prop->name = "linux,pci-domain"; - of_prop->length = sizeof(hose->global_number); - of_prop->value = (unsigned char *)&of_prop[1]; - memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number)); - prom_add_property(dev, of_prop); - } - - disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pmac_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); - - return 0; -} - -/* - * We use our own read_irq_line here because PCI_INTERRUPT_PIN is - * crap on some of Apple ASICs. We unconditionally use the Open Firmware - * interrupt number as this is always right. - */ -static int pmac_pci_read_irq_line(struct pci_dev *pci_dev) -{ - struct device_node *node; - - node = pci_device_to_OF_node(pci_dev); - if (node == NULL) - return -1; - if (node->n_intrs == 0) - return -1; - pci_dev->irq = node->intrs[0].line; - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); - - return 0; -} - -void __init pmac_pcibios_fixup(void) -{ - struct pci_dev *dev = NULL; - - for_each_pci_dev(dev) - pmac_pci_read_irq_line(dev); -} - -static void __init pmac_fixup_phb_resources(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - hose->io_resource.start += offset; - hose->io_resource.end += offset; - printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", - hose->global_number, - hose->io_resource.start, hose->io_resource.end); - } -} - -void __init pmac_pci_init(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - /* Probe root PCI hosts, that is on U3 the AGP host and the - * HyperTransport host. That one is actually "kept" around - * and actually added last as it's resource management relies - * on the AGP resources to have been setup first - */ - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); - return; - } - for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) - continue; - if (strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Now setup the HyperTransport host if we found any - */ - if (ht && add_bridge(ht) != 0) - of_node_put(ht); - - /* Fixup the IO resources on our host bridges as the common code - * does it only for childs of the host bridges - */ - pmac_fixup_phb_resources(); - - /* Setup the linkage between OF nodes and PHBs */ - pci_devs_phb_init(); - - /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We - * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. - */ - if (u3_agp) { - struct device_node *np = u3_agp->arch_data; - PCI_DN(np)->busno = 0xf0; - for (np = np->child; np; np = np->sibling) - PCI_DN(np)->busno = 0xf0; - } - - pmac_check_ht_link(); - - /* Tell pci.c to not use the common resource allocation mecanism */ - pci_probe_only = 1; - - /* Allow all IO */ - io_page_mask = -1; -} - -/* - * Disable second function on K2-SATA, it's broken - * and disable IO BARs on first one - */ -static void fixup_k2_sata(struct pci_dev* dev) -{ - int i; - u16 cmd; - - if (PCI_FUNC(dev->devfn) > 0) { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(dev, PCI_COMMAND, cmd); - for (i = 0; i < 6; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); - } - } else { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_IO; - pci_write_config_word(dev, PCI_COMMAND, cmd); - for (i = 0; i < 5; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); - diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c deleted file mode 100644 index c3ea73df937d..000000000000 --- a/arch/ppc64/kernel/pmac_setup.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * arch/ppc/platforms/setup.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Adapted for Power Macintosh by Paul Mackerras - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * - * Derived from "arch/alpha/kernel/setup.c" - * Copyright (C) 1995 Linus Torvalds - * - * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) - * - * 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. - * - */ - -/* - * bootup setup stuff.. - */ - -#undef DEBUG - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pmac.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -static int current_root_goodness = -1; -#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ - -extern int powersave_nap; -int sccdbg; - -sys_ctrler_t sys_ctrler; -EXPORT_SYMBOL(sys_ctrler); - -#ifdef CONFIG_PMAC_SMU -unsigned long smu_cmdbuf_abs; -EXPORT_SYMBOL(smu_cmdbuf_abs); -#endif - -extern void udbg_init_scc(struct device_node *np); - -static void pmac_show_cpuinfo(struct seq_file *m) -{ - struct device_node *np; - char *pp; - int plen; - char* mbname; - int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, - PMAC_MB_INFO_MODEL, 0); - unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, - PMAC_MB_INFO_FLAGS, 0); - - if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, - (long)&mbname) != 0) - mbname = "Unknown"; - - /* find motherboard type */ - seq_printf(m, "machine\t\t: "); - np = find_devices("device-tree"); - if (np != NULL) { - pp = (char *) get_property(np, "model", NULL); - if (pp != NULL) - seq_printf(m, "%s\n", pp); - else - seq_printf(m, "PowerMac\n"); - pp = (char *) get_property(np, "compatible", &plen); - if (pp != NULL) { - seq_printf(m, "motherboard\t:"); - while (plen > 0) { - int l = strlen(pp) + 1; - seq_printf(m, " %s", pp); - plen -= l; - pp += l; - } - seq_printf(m, "\n"); - } - } else - seq_printf(m, "PowerMac\n"); - - /* print parsed model */ - seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); - seq_printf(m, "pmac flags\t: %08x\n", mbflags); - - /* Indicate newworld */ - seq_printf(m, "pmac-generation\t: NewWorld\n"); -} - - -static void __init pmac_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - /* Probe motherboard chipset */ - pmac_feature_init(); -#if 0 - /* Lock-enable the SCC channel used for debug */ - if (sccdbg) { - np = of_find_node_by_name(NULL, "escc"); - if (np) - pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, - PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); - } -#endif - /* We can NAP */ - powersave_nap = 1; - -#ifdef CONFIG_ADB_PMU - /* Initialize the PMU if any */ - find_via_pmu(); -#endif -#ifdef CONFIG_PMAC_SMU - /* Initialize the SMU if any */ - smu_init(); -#endif - - /* Init NVRAM access */ - pmac_nvram_init(); - - /* Setup SMP callback */ -#ifdef CONFIG_SMP - pmac_setup_smp(); -#endif - - /* Lookup PCI hosts */ - pmac_pci_init(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - printk(KERN_INFO "Using native/NAP idle loop\n"); -} - -#ifdef CONFIG_SCSI -void note_scsi_host(struct device_node *node, void *host) -{ - /* Obsolete */ -} -#endif - - -static int initializing = 1; - -static int pmac_late_init(void) -{ - initializing = 0; - return 0; -} - -late_initcall(pmac_late_init); - -/* can't be __init - can be called whenever a disk is first accessed */ -void note_bootable_part(dev_t dev, int part, int goodness) -{ - extern dev_t boot_dev; - char *p; - - if (!initializing) - return; - if ((goodness <= current_root_goodness) && - ROOT_DEV != DEFAULT_ROOT_DEVICE) - return; - p = strstr(saved_command_line, "root="); - if (p != NULL && (p == saved_command_line || p[-1] == ' ')) - return; - - if (!boot_dev || dev == boot_dev) { - ROOT_DEV = dev + part; - boot_dev = 0; - current_root_goodness = goodness; - } -} - -static void pmac_restart(char *cmd) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_restart(); - break; -#endif - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_restart(); - break; -#endif - default: - ; - } -} - -static void pmac_power_off(void) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_shutdown(); - break; -#endif -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_shutdown(); - break; -#endif - default: - ; - } -} - -static void pmac_halt(void) -{ - pmac_power_off(); -} - -/* - * Early initialization. - */ -static void __init pmac_init_early(void) -{ - DBG(" -> pmac_init_early\n"); - - /* Initialize hash table, from now on, we can take hash faults - * and call ioremap - */ - hpte_init_native(); - - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); - } - - /* Setup interrupt mapping options */ - ppc64_interrupt_controller = IC_OPEN_PIC; - - iommu_init_early_u3(); - - DBG(" <- pmac_init_early\n"); -} - -static int pmac_u3_cascade(struct pt_regs *regs, void *data) -{ - return mpic_get_one_irq((struct mpic *)data, regs); -} - -static __init void pmac_init_IRQ(void) -{ - struct device_node *irqctrler = NULL; - struct device_node *irqctrler2 = NULL; - struct device_node *np = NULL; - struct mpic *mpic1, *mpic2; - - /* We first try to detect Apple's new Core99 chipset, since mac-io - * is quite different on those machines and contains an IBM MPIC2. - */ - while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { - struct device_node *parent = of_get_parent(np); - if (parent && !strcmp(parent->name, "u3")) - irqctrler2 = of_node_get(np); - else - irqctrler = of_node_get(np); - of_node_put(parent); - } - if (irqctrler != NULL && irqctrler->n_addrs > 0) { - unsigned char senses[128]; - - printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", - (unsigned int)irqctrler->addrs[0].address); - - prom_get_irq_senses(senses, 0, 128); - mpic1 = mpic_alloc(irqctrler->addrs[0].address, - MPIC_PRIMARY | MPIC_WANTS_RESET, - 0, 0, 128, 256, senses, 128, " K2-MPIC "); - BUG_ON(mpic1 == NULL); - mpic_init(mpic1); - - if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && - irqctrler2->n_addrs > 0) { - printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", - (u32)irqctrler2->addrs[0].address, - irqctrler2->intrs[0].line); - - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); - prom_get_irq_senses(senses, 128, 128 + 128); - - /* We don't need to set MPIC_BROKEN_U3 here since we don't have - * hypertransport interrupts routed to it - */ - mpic2 = mpic_alloc(irqctrler2->addrs[0].address, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, - 0, 128, 128, 0, senses, 128, " U3-MPIC "); - BUG_ON(mpic2 == NULL); - mpic_init(mpic2); - mpic_setup_cascade(irqctrler2->intrs[0].line, - pmac_u3_cascade, mpic2); - } - } - of_node_put(irqctrler); - of_node_put(irqctrler2); -} - -static void __init pmac_progress(char *s, unsigned short hex) -{ - if (sccdbg) { - udbg_puts(s); - udbg_puts("\n"); - } -#ifdef CONFIG_BOOTX_TEXT - else if (boot_text_mapped) { - btext_drawstring(s); - btext_drawstring("\n"); - } -#endif /* CONFIG_BOOTX_TEXT */ -} - -/* - * pmac has no legacy IO, anything calling this function has to - * fail or bad things will happen - */ -static int pmac_check_legacy_ioport(unsigned int baseport) -{ - return -ENODEV; -} - -static int __init pmac_declare_of_platform_devices(void) -{ - struct device_node *np, *npp; - - npp = of_find_node_by_name(NULL, "u3"); - if (npp) { - for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { - if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c", NULL); - of_node_put(np); - break; - } - } - of_node_put(npp); - } - npp = of_find_node_by_type(NULL, "smu"); - if (npp) { - of_platform_device_create(npp, "smu", NULL); - of_node_put(npp); - } - - return 0; -} - -device_initcall(pmac_declare_of_platform_devices); - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init pmac_probe(int platform) -{ - if (platform != PLATFORM_POWERMAC) - return 0; - /* - * On U3, the DART (iommu) must be allocated now since it - * has an impact on htab_initialize (due to the large page it - * occupies having to be broken up so the DART itself is not - * part of the cacheable linar mapping - */ - alloc_u3_dart_table(); - -#ifdef CONFIG_PMAC_SMU - /* - * SMU based G5s need some memory below 2Gb, at least the current - * driver needs that. We have to allocate it now. We allocate 4k - * (1 small page) for now. - */ - smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); -#endif /* CONFIG_PMAC_SMU */ - - return 1; -} - -static int pmac_probe_mode(struct pci_bus *bus) -{ - struct device_node *node = bus->sysdata; - - /* We need to use normal PCI probing for the AGP bus, - since the device for the AGP bridge isn't in the tree. */ - if (bus->self == NULL && device_is_compatible(node, "u3-agp")) - return PCI_PROBE_NORMAL; - - return PCI_PROBE_DEVTREE; -} - -struct machdep_calls __initdata pmac_md = { -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = generic_mach_cpu_die, -#endif - .probe = pmac_probe, - .setup_arch = pmac_setup_arch, - .init_early = pmac_init_early, - .show_cpuinfo = pmac_show_cpuinfo, - .init_IRQ = pmac_init_IRQ, - .get_irq = mpic_get_irq, - .pcibios_fixup = pmac_pcibios_fixup, - .pci_probe_mode = pmac_probe_mode, - .restart = pmac_restart, - .power_off = pmac_power_off, - .halt = pmac_halt, - .get_boot_time = pmac_get_boot_time, - .set_rtc_time = pmac_set_rtc_time, - .get_rtc_time = pmac_get_rtc_time, - .calibrate_decr = pmac_calibrate_decr, - .feature_call = pmac_do_feature_call, - .progress = pmac_progress, - .check_legacy_ioport = pmac_check_legacy_ioport, - .idle_loop = native_idle, - .enable_pmcs = power4_enable_pmcs, -}; diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c deleted file mode 100644 index 83c2f8dc1ec6..000000000000 --- a/arch/ppc64/kernel/pmac_smp.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * SMP support for power macintosh. - * - * We support both the old "powersurge" SMP architecture - * and the current Core99 (G4 PowerMac) machines. - * - * Note that we don't support the very first rev. of - * Apple/DayStar 2 CPUs board, the one with the funky - * watchdog. Hopefully, none of these should be there except - * maybe internally to Apple. I should probably still add some - * code to detect this card though and disable SMP. --BenH. - * - * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) - * and Ben Herrenschmidt . - * - * Support for DayStar quad CPU cards - * Copyright (C) XLR8, Inc. 1994-2000 - * - * 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. - */ - -#undef DEBUG - -#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 - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -extern void __secondary_start_pmac_0(void); - -extern struct smp_ops_t *smp_ops; - -static void (*pmac_tb_freeze)(int freeze); -static struct device_node *pmac_tb_clock_chip_host; -static u8 pmac_tb_pulsar_addr; -static DEFINE_SPINLOCK(timebase_lock); -static unsigned long timebase; - -static void smp_core99_cypress_tb_freeze(int freeze) -{ - u8 data; - int rc; - - /* Strangely, the device-tree says address is 0xd2, but darwin - * accesses 0xd0 ... - */ - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_read, - 0x81, &data, 1); - if (rc != 0) - goto bail; - - data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_write, - 0x81, &data, 1); - - bail: - if (rc != 0) { - printk("Cypress Timebase %s rc: %d\n", - freeze ? "freeze" : "unfreeze", rc); - panic("Timebase freeze failed !\n"); - } -} - -static void smp_core99_pulsar_tb_freeze(int freeze) -{ - u8 data; - int rc; - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_read, - 0x2e, &data, 1); - if (rc != 0) - goto bail; - - data = (data & 0x88) | (freeze ? 0x11 : 0x22); - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_write, - 0x2e, &data, 1); - bail: - if (rc != 0) { - printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", - freeze ? "freeze" : "unfreeze", rc); - panic("Timebase freeze failed !\n"); - } -} - - -static void smp_core99_give_timebase(void) -{ - /* Open i2c bus for synchronous access */ - if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) - panic("Can't open i2c for TB sync !\n"); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(1); - mb(); - timebase = get_tb(); - spin_unlock(&timebase_lock); - - while (timebase) - barrier(); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(0); - spin_unlock(&timebase_lock); - - /* Close i2c bus */ - pmac_low_i2c_close(pmac_tb_clock_chip_host); -} - - -static void __devinit smp_core99_take_timebase(void) -{ - while (!timebase) - barrier(); - spin_lock(&timebase_lock); - set_tb(timebase >> 32, timebase & 0xffffffff); - timebase = 0; - spin_unlock(&timebase_lock); -} - - -static int __init smp_core99_probe(void) -{ - struct device_node *cpus; - struct device_node *cc; - int ncpus = 0; - - /* Maybe use systemconfiguration here ? */ - if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - - /* Count CPUs in the device-tree */ - for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;) - ++ncpus; - - printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus); - - /* Nothing more to do if less than 2 of them */ - if (ncpus <= 1) - return 1; - - /* HW sync only on these platforms */ - if (!machine_is_compatible("PowerMac7,2") && - !machine_is_compatible("PowerMac7,3") && - !machine_is_compatible("RackMac3,1")) - goto nohwsync; - - /* Look for the clock chip */ - for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { - struct device_node *p = of_get_parent(cc); - u32 *reg; - int ok; - ok = p && device_is_compatible(p, "uni-n-i2c"); - if (!ok) - goto next; - reg = (u32 *)get_property(cc, "reg", NULL); - if (reg == NULL) - goto next; - switch (*reg) { - case 0xd2: - if (device_is_compatible(cc, "pulsar-legacy-slewing")) { - pmac_tb_freeze = smp_core99_pulsar_tb_freeze; - pmac_tb_pulsar_addr = 0xd2; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); - } else if (device_is_compatible(cc, "cy28508")) { - pmac_tb_freeze = smp_core99_cypress_tb_freeze; - printk(KERN_INFO "Timebase clock is Cypress chip\n"); - } - break; - case 0xd4: - pmac_tb_freeze = smp_core99_pulsar_tb_freeze; - pmac_tb_pulsar_addr = 0xd4; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); - break; - } - if (pmac_tb_freeze != NULL) { - pmac_tb_clock_chip_host = p; - smp_ops->give_timebase = smp_core99_give_timebase; - smp_ops->take_timebase = smp_core99_take_timebase; - of_node_put(cc); - of_node_put(p); - break; - } - next: - of_node_put(p); - } - - nohwsync: - mpic_request_ipis(); - - return ncpus; -} - -static void __init smp_core99_kick_cpu(int nr) -{ - unsigned int save_vector, j; - unsigned long new_vector; - unsigned long flags; - volatile unsigned int *vector - = ((volatile unsigned int *)(KERNELBASE+0x100)); - - if (nr < 1 || nr > 3) - return; - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); - - local_irq_save(flags); - local_irq_disable(); - - /* Save reset vector */ - save_vector = *vector; - - /* Setup fake reset vector that does - * b __secondary_start_pmac_0 + nr*8 - KERNELBASE - */ - new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; - *vector = 0x48000002 + (new_vector - KERNELBASE); - - /* flush data cache and inval instruction cache */ - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - /* Put some life in our friend */ - pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); - paca[nr].cpu_start = 1; - - /* FIXME: We wait a bit for the CPU to take the exception, I should - * instead wait for the entry code to set something for me. Well, - * ideally, all that crap will be done in prom.c and the CPU left - * in a RAM-based wait loop like CHRP. - */ - for (j = 1; j < 1000000; j++) - mb(); - - /* Restore our exception vector */ - *vector = save_vector; - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - local_irq_restore(flags); - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); -} - -static void __init smp_core99_setup_cpu(int cpu_nr) -{ - /* Setup MPIC */ - mpic_setup_this_cpu(); - - if (cpu_nr == 0) { - extern void g5_phy_disable_cpu1(void); - - /* If we didn't start the second CPU, we must take - * it off the bus - */ - if (num_online_cpus() < 2) - g5_phy_disable_cpu1(); - if (ppc_md.progress) ppc_md.progress("smp_core99_setup_cpu 0 done", 0x349); - } -} - -struct smp_ops_t core99_smp_ops = { - .message_pass = smp_mpic_message_pass, - .probe = smp_core99_probe, - .kick_cpu = smp_core99_kick_cpu, - .setup_cpu = smp_core99_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, -}; - -void __init pmac_setup_smp(void) -{ - smp_ops = &core99_smp_ops; -#ifdef CONFIG_HOTPLUG_CPU - smp_ops->cpu_enable = generic_cpu_enable; - smp_ops->cpu_disable = generic_cpu_disable; - smp_ops->cpu_die = generic_cpu_die; -#endif -} diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c deleted file mode 100644 index 928bf213ec4e..000000000000 --- a/arch/ppc64/kernel/pmac_time.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Support for periodic interrupts (100 per second) and for getting - * the current time from the RTC on Power Macintoshes. - * - * We use the decrementer register for our periodic interrupts. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - * Copyright (C) 2003-2005 Benjamin Herrenschmidt. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* Apparently the RTC stores seconds since 1 Jan 1904 */ -#define RTC_OFFSET 2082844800 - -/* - * Calibrate the decrementer frequency with the VIA timer 1. - */ -#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ - -extern struct timezone sys_tz; -extern void to_tm(int tim, struct rtc_time * tm); - -void pmac_get_rtc_time(struct rtc_time *tm) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: { - /* TODO: Move that to a function in the PMU driver */ - struct adb_request req; - unsigned int now; - - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return; - pmu_wait_complete(&req); - if (req.reply_len != 4) - printk(KERN_ERR "pmac_get_rtc_time: PMU returned a %d" - " bytes reply\n", req.reply_len); - now = (req.reply[0] << 24) + (req.reply[1] << 16) - + (req.reply[2] << 8) + req.reply[3]; - DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET)); - now -= RTC_OFFSET; - - to_tm(now, tm); - tm->tm_year -= 1900; - tm->tm_mon -= 1; - - DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); - break; - } -#endif /* CONFIG_ADB_PMU */ - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_get_rtc_time(tm, 1); - break; -#endif /* CONFIG_PMAC_SMU */ - default: - ; - } -} - -int pmac_set_rtc_time(struct rtc_time *tm) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: { - /* TODO: Move that to a function in the PMU driver */ - struct adb_request req; - unsigned int nowtime; - - DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d," - " %d:%02d:%02d\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, - tm->tm_sec); - - DBG("-> %u -> %u\n", (int)nowtime, - (int)(nowtime + RTC_OFFSET)); - nowtime += RTC_OFFSET; - - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, - nowtime >> 24, nowtime >> 16, - nowtime >> 8, nowtime) < 0) - return -ENXIO; - pmu_wait_complete(&req); - if (req.reply_len != 0) - printk(KERN_ERR "pmac_set_rtc_time: PMU returned a %d" - " bytes reply\n", req.reply_len); - return 0; - } -#endif /* CONFIG_ADB_PMU */ - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - return smu_set_rtc_time(tm, 1); -#endif /* CONFIG_PMAC_SMU */ - default: - return -ENODEV; - } -} - -unsigned long __init pmac_get_boot_time(void) -{ - struct rtc_time tm; - - pmac_get_rtc_time(&tm); - return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); -} - -/* - * Query the OF and get the decr frequency. - * FIXME: merge this with generic_calibrate_decr - */ -void __init pmac_calibrate_decr(void) -{ - struct device_node *cpu; - unsigned int *fp; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = find_type_devices("cpu"); - if (cpu == 0) - panic("can't find cpu node in time_init"); - fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); - if (fp == 0) - panic("can't get cpu timebase frequency"); - ppc_tb_freq = *fp; - - fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL); - if (fp == 0) - panic("can't get cpu processor frequency"); - ppc_proc_freq = *fp; -} - From c8e0ca683dfea7242ff29814561dfe761945e5b3 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 22 Oct 2005 09:43:29 -0700 Subject: [PATCH 0638/1939] [IB] mthca: Always re-arm EQs in mthca_tavor_interrupt() We should always re-arm an event queue's interrupt in mthca_tavor_interrupt() if the corresponding bit is set in the event cause register (ECR), even if we didn't find any entries in the EQ. If we don't, then there's a window where we miss an EQ entry and then get stuck because we don't get another EQ event. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_eq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index c81fa8e975ef..8dfafda5ed24 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -396,20 +396,21 @@ static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); ecr = readl(dev->eq_regs.tavor.ecr_base + 4); - if (ecr) { - writel(ecr, dev->eq_regs.tavor.ecr_base + - MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + if (!ecr) + return IRQ_NONE; - for (i = 0; i < MTHCA_NUM_EQ; ++i) - if (ecr & dev->eq_table.eq[i].eqn_mask && - mthca_eq_int(dev, &dev->eq_table.eq[i])) { + writel(ecr, dev->eq_regs.tavor.ecr_base + + MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (ecr & dev->eq_table.eq[i].eqn_mask) { + if (mthca_eq_int(dev, &dev->eq_table.eq[i])) tavor_set_eq_ci(dev, &dev->eq_table.eq[i], dev->eq_table.eq[i].cons_index); - tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); - } - } + tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); + } - return IRQ_RETVAL(ecr); + return IRQ_HANDLED; } static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr, From 057ace5e79da9ebf2aa82833cfea825533ac06fb Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 22 Oct 2005 14:27:05 -0400 Subject: [PATCH 0639/1939] libata: const-ification bombing run Enforce access rules where appropriate. If the compiler is smart enough, this may buy us an optimization or two as a side effect. --- drivers/scsi/ahci.c | 2 +- drivers/scsi/ata_piix.c | 4 +-- drivers/scsi/libata-core.c | 68 ++++++++++++++++++------------------- drivers/scsi/libata-scsi.c | 24 ++++++------- drivers/scsi/libata.h | 2 +- drivers/scsi/pdc_adma.c | 2 +- drivers/scsi/sata_mv.c | 2 +- drivers/scsi/sata_nv.c | 2 +- drivers/scsi/sata_promise.c | 12 +++---- drivers/scsi/sata_qstor.c | 2 +- drivers/scsi/sata_sil.c | 2 +- drivers/scsi/sata_sil24.c | 2 +- drivers/scsi/sata_sis.c | 2 +- drivers/scsi/sata_svw.c | 4 +-- drivers/scsi/sata_sx4.c | 10 +++--- drivers/scsi/sata_uli.c | 2 +- drivers/scsi/sata_via.c | 2 +- drivers/scsi/sata_vsc.c | 4 +-- include/linux/ata.h | 6 ++-- include/linux/libata.h | 32 ++++++++--------- 20 files changed, 93 insertions(+), 93 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index cfa22e4ee547..fe8187d6f58b 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -216,7 +216,7 @@ static Scsi_Host_Template ahci_sht = { .ordered_flush = 1, }; -static struct ata_port_operations ahci_ops = { +static const struct ata_port_operations ahci_ops = { .port_disable = ata_port_disable, .check_status = ahci_check_status, diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index d71cef767cec..be021478f416 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -147,7 +147,7 @@ static Scsi_Host_Template piix_sht = { .ordered_flush = 1, }; -static struct ata_port_operations piix_pata_ops = { +static const struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, @@ -177,7 +177,7 @@ static struct ata_port_operations piix_pata_ops = { .host_stop = ata_host_stop, }; -static struct ata_port_operations piix_sata_ops = { +static const struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9269fd9b814f..d55f12dacfcb 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -67,9 +67,9 @@ static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift); static int fgb(u32 bitmap); -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); static void __ata_qc_complete(struct ata_queued_cmd *qc); @@ -97,7 +97,7 @@ MODULE_VERSION(DRV_VERSION); * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -155,7 +155,7 @@ static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) * Inherited from caller. */ -static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -224,7 +224,7 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * Inherited from caller. */ -void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_tf_load_mmio(ap, tf); @@ -244,7 +244,7 @@ void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -265,7 +265,7 @@ static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -285,7 +285,7 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_exec_command_mmio(ap, tf); @@ -305,7 +305,7 @@ void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) +static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf) { unsigned long flags; @@ -328,7 +328,7 @@ static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); @@ -348,7 +348,7 @@ static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); ap->ops->exec_command(ap, tf); @@ -558,7 +558,7 @@ u8 ata_chk_err(struct ata_port *ap) * Inherited from caller. */ -void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp) { fis[0] = 0x27; /* Register - Host to Device FIS */ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, @@ -599,7 +599,7 @@ void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) * Inherited from caller. */ -void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) +void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) { tf->command = fis[2]; /* status */ tf->feature = fis[3]; /* error */ @@ -845,7 +845,7 @@ static unsigned int ata_devchk(struct ata_port *ap, * the event of failure. */ -unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -937,7 +937,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) * caller. */ -void ata_dev_id_string(u16 *id, unsigned char *s, +void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len) { unsigned int c; @@ -1054,7 +1054,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, * caller. */ -static inline void ata_dump_id(struct ata_device *dev) +static inline void ata_dump_id(const struct ata_device *dev) { DPRINTK("49==0x%04x " "53==0x%04x " @@ -1089,7 +1089,7 @@ static inline void ata_dump_id(struct ata_device *dev) * FIXME: pre IDE drive timing (do we care ?). */ -static unsigned int ata_pio_modes(struct ata_device *adev) +static unsigned int ata_pio_modes(const struct ata_device *adev) { u16 modes; @@ -1352,7 +1352,7 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) } -static inline u8 ata_dev_knobble(struct ata_port *ap) +static inline u8 ata_dev_knobble(const struct ata_port *ap) { return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id))); } @@ -1684,7 +1684,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, return 0; } -static struct { +static const struct { unsigned int shift; u8 base; } xfer_mode_classes[] = { @@ -2093,7 +2093,8 @@ void ata_bus_reset(struct ata_port *ap) DPRINTK("EXIT\n"); } -static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev) +static void ata_pr_blacklisted(const struct ata_port *ap, + const struct ata_device *dev) { printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n", ap->id, dev->devno); @@ -2131,7 +2132,7 @@ static const char * ata_dma_blacklist [] = { "_NEC DV5800A", }; -static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) +static int ata_dma_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; char *s; @@ -2156,9 +2157,9 @@ static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) return 0; } -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift) { - struct ata_device *master, *slave; + const struct ata_device *master, *slave; unsigned int mask; master = &ap->device[0]; @@ -2170,14 +2171,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->udma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2187,14 +2188,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->mwdma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2258,7 +2259,7 @@ static int fgb(u32 bitmap) * Zero on success, negative on error. */ -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out) { @@ -4144,7 +4145,7 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, struct ata_host_set *host_set, - struct ata_probe_ent *ent, unsigned int port_no) + const struct ata_probe_ent *ent, unsigned int port_no) { unsigned int i; @@ -4203,7 +4204,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, * */ -static struct ata_port * ata_host_add(struct ata_probe_ent *ent, +static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, struct ata_host_set *host_set, unsigned int port_no) { @@ -4251,7 +4252,7 @@ static struct ata_port * ata_host_add(struct ata_probe_ent *ent, * */ -int ata_device_add(struct ata_probe_ent *ent) +int ata_device_add(const struct ata_probe_ent *ent) { unsigned int count = 0, i; struct device *dev = ent->dev; @@ -4470,7 +4471,7 @@ void ata_std_ports(struct ata_ioports *ioaddr) } static struct ata_probe_ent * -ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port) +ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; @@ -4570,7 +4571,6 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, stru if (!probe_ent) return NULL; - probe_ent->legacy_mode = 1; probe_ent->n_ports = 1; probe_ent->hard_port_no = port_num; @@ -4783,7 +4783,7 @@ void ata_pci_remove_one (struct pci_dev *pdev) } /* move to PCI subsystem */ -int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits) +int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) { unsigned long tmp = 0; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 90bf22204668..58858886d751 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -44,9 +44,9 @@ #include "libata.h" -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); +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, struct scsi_device *scsidev); +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, @@ -418,7 +418,7 @@ int ata_scsi_error(struct Scsi_Host *host) */ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, - u8 *scsicmd) + const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; @@ -485,7 +485,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; @@ -512,7 +512,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * @plen: the transfer length */ -static void scsi_6_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; @@ -539,7 +539,7 @@ static void scsi_6_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) * @plen: the transfer length */ -static void scsi_10_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; @@ -569,7 +569,7 @@ static void scsi_10_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) * @plen: the transfer length */ -static void scsi_16_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; @@ -608,7 +608,7 @@ static void scsi_16_lba_len(u8 *scsicmd, u64 *plba, u32 *plen) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; @@ -734,7 +734,7 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; @@ -1688,7 +1688,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * Zero on success, non-zero on failure. */ -static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; @@ -1757,7 +1757,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) */ static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev; @@ -1914,7 +1914,7 @@ void ata_scsi_simulate(u16 *id, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; - u8 *scsicmd = cmd->cmnd; + const u8 *scsicmd = cmd->cmnd; args.id = id; args.cmd = cmd; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 67d752ca8ae2..3d60190584ba 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -48,7 +48,7 @@ extern int ata_qc_issue(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); -extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 53b8db4be1a9..9820f272f889 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -158,7 +158,7 @@ static Scsi_Host_Template adma_ata_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations adma_ata_ops = { +static const struct ata_port_operations adma_ata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 9b6213928f7a..422e0b6f603a 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -290,7 +290,7 @@ static Scsi_Host_Template mv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations mv_ops = { +static const struct ata_port_operations mv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 8866530bc491..1a56d6c79ddd 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -238,7 +238,7 @@ static Scsi_Host_Template nv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations nv_ops = { +static const struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 9bf8cbd29901..eee93b0016df 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -87,8 +87,8 @@ static void pdc_port_stop(struct ata_port *ap); static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_sata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); @@ -113,7 +113,7 @@ static Scsi_Host_Template pdc_ata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_sata_ops = { +static const struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -136,7 +136,7 @@ static struct ata_port_operations pdc_sata_ops = { .host_stop = ata_pci_host_stop, }; -static struct ata_port_operations pdc_pata_ops = { +static const struct ata_port_operations pdc_pata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -546,7 +546,7 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -554,7 +554,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index e1c1dae27c52..250dafa6bc36 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -147,7 +147,7 @@ static Scsi_Host_Template qs_ata_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations qs_ata_ops = { +static const struct ata_port_operations qs_ata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index f6f0184e1ac8..3a056173fb95 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -150,7 +150,7 @@ static Scsi_Host_Template sil_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sil_ops = { +static const struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 19857814d69f..32d730bd5bb6 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -275,7 +275,7 @@ static Scsi_Host_Template sil24_sht = { .ordered_flush = 1, /* NCQ not supported yet */ }; -static struct ata_port_operations sil24_ops = { +static const struct ata_port_operations sil24_ops = { .port_disable = ata_port_disable, .check_status = sil24_check_status, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 0761a3234fcf..057f7b98b6c4 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -102,7 +102,7 @@ static Scsi_Host_Template sis_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sis_ops = { +static const struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index d89d968bedac..e0f9570bc6dd 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -102,7 +102,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, } -static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -297,7 +297,7 @@ static Scsi_Host_Template k2_sata_sht = { }; -static struct ata_port_operations k2_sata_ops = { +static const struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index d6d350a0b5e9..af08f4f650c1 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -157,8 +157,8 @@ static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); @@ -196,7 +196,7 @@ static Scsi_Host_Template pdc_sata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_20621_ops = { +static const struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -899,7 +899,7 @@ static void pdc_eng_timeout(struct ata_port *ap) DPRINTK("EXIT\n"); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -907,7 +907,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 9c06f2abe7f7..d68dc7d3422c 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -90,7 +90,7 @@ static Scsi_Host_Template uli_sht = { .ordered_flush = 1, }; -static struct ata_port_operations uli_ops = { +static const struct ata_port_operations uli_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 565872479b9a..80e291a909a9 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -109,7 +109,7 @@ static Scsi_Host_Template svia_sht = { .ordered_flush = 1, }; -static struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 877b9fda3965..5af05fdf8544 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -115,7 +115,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) } -static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -231,7 +231,7 @@ static Scsi_Host_Template vsc_sata_sht = { }; -static struct ata_port_operations vsc_sata_ops = { +static const struct ata_port_operations vsc_sata_ops = { .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, diff --git a/include/linux/ata.h b/include/linux/ata.h index 33276d1d05d2..d2873b732bb1 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -261,7 +261,7 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) -static inline int ata_id_current_chs_valid(u16 *id) +static inline int ata_id_current_chs_valid(const u16 *id) { /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command has not been issued to the device then the values of @@ -273,7 +273,7 @@ static inline int ata_id_current_chs_valid(u16 *id) id[56]; /* sectors in current translation */ } -static inline int atapi_cdb_len(u16 *dev_id) +static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; switch (tmp) { @@ -283,7 +283,7 @@ static inline int atapi_cdb_len(u16 *dev_id) } } -static inline int is_atapi_taskfile(struct ata_taskfile *tf) +static inline int is_atapi_taskfile(const struct ata_taskfile *tf) { return (tf->protocol == ATA_PROT_ATAPI) || (tf->protocol == ATA_PROT_ATAPI_NODATA) || diff --git a/include/linux/libata.h b/include/linux/libata.h index 634b5aa0a615..00a8a5738858 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -202,7 +202,7 @@ struct ata_ioports { struct ata_probe_ent { struct list_head node; struct device *dev; - struct ata_port_operations *port_ops; + const struct ata_port_operations *port_ops; Scsi_Host_Template *sht; struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; @@ -225,7 +225,7 @@ struct ata_host_set { void __iomem *mmio_base; unsigned int n_ports; void *private_data; - struct ata_port_operations *ops; + const struct ata_port_operations *ops; struct ata_port * ports[0]; }; @@ -294,7 +294,7 @@ struct ata_device { struct ata_port { struct Scsi_Host *host; /* our co-allocated scsi host */ - struct ata_port_operations *ops; + const struct ata_port_operations *ops; unsigned long flags; /* ATA_FLAG_xxx */ unsigned int id; /* unique id req'd by scsi midlyr */ unsigned int port_no; /* unique port #; from zero */ @@ -341,10 +341,10 @@ struct ata_port_operations { void (*set_piomode) (struct ata_port *, struct ata_device *); void (*set_dmamode) (struct ata_port *, struct ata_device *); - void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); + void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); - void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); + void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); u8 (*check_status)(struct ata_port *ap); u8 (*check_altstatus)(struct ata_port *ap); u8 (*check_err)(struct ata_port *ap); @@ -385,7 +385,7 @@ struct ata_port_info { unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; - struct ata_port_operations *port_ops; + const struct ata_port_operations *port_ops; }; struct ata_timing { @@ -413,7 +413,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i unsigned int n_ports); extern void ata_pci_remove_one (struct pci_dev *pdev); #endif /* CONFIG_PCI */ -extern int ata_device_add(struct ata_probe_ent *ent); +extern int ata_device_add(const struct ata_probe_ent *ent); extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(Scsi_Host_Template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); @@ -426,16 +426,16 @@ extern int ata_ratelimit(void); /* * Default driver ops implementations */ -extern void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp); -extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf); +extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp); +extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf); extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); 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 u8 ata_chk_err(struct ata_port *ap); -extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); 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); @@ -446,8 +446,8 @@ extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen); extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem); -extern unsigned int ata_dev_classify(struct ata_taskfile *tf); -extern void ata_dev_id_string(u16 *id, unsigned char *s, +extern unsigned int ata_dev_classify(const struct ata_taskfile *tf); +extern void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_dev_config(struct ata_port *ap, unsigned int i); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); @@ -502,7 +502,7 @@ struct pci_bits { extern void ata_pci_host_stop (struct ata_host_set *host_set); extern struct ata_probe_ent * ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask); -extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); +extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); #endif /* CONFIG_PCI */ @@ -512,7 +512,7 @@ static inline unsigned int ata_tag_valid(unsigned int tag) return (tag < ATA_MAX_QUEUE) ? 1 : 0; } -static inline unsigned int ata_dev_present(struct ata_device *dev) +static inline unsigned int ata_dev_present(const struct ata_device *dev) { return ((dev->class == ATA_DEV_ATA) || (dev->class == ATA_DEV_ATAPI)); @@ -711,7 +711,7 @@ 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(struct ata_device *dev) +static inline int ata_try_flush_cache(const struct ata_device *dev) { return ata_id_wcache_enabled(dev->id) || ata_id_has_flush(dev->id) || From c98d80edc827277c28f88d662a7d6e9affa7e12f Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 22 Oct 2005 13:39:21 +0300 Subject: [PATCH 0640/1939] [SK_BUFF]: ipvs_property field must be copied IPVS used flag NFC_IPVS_PROPERTY in nfcache but as now nfcache was removed the new flag 'ipvs_property' still needs to be copied. This patch should be included in 2.6.14. Further comments from Harald Welte: Sorry, seems like the bug was introduced by me. Signed-off-by: Julian Anastasov Signed-off-by: Harald Welte Signed-off-by: Arnaldo Carvalho de Melo --- net/core/skbuff.c | 6 ++++++ net/ipv4/ip_output.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index af9b1516e21f..02cd4cde2112 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -410,6 +410,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) C(nfct); nf_conntrack_get(skb->nfct); C(nfctinfo); +#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) + C(ipvs_property); +#endif #ifdef CONFIG_BRIDGE_NETFILTER C(nf_bridge); nf_bridge_get(skb->nf_bridge); @@ -467,6 +470,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->nfct = old->nfct; nf_conntrack_get(old->nfct); new->nfctinfo = old->nfctinfo; +#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) + new->ipvs_property = old->ipvs_property; +#endif #ifdef CONFIG_BRIDGE_NETFILTER new->nf_bridge = old->nf_bridge; nf_bridge_get(old->nf_bridge); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 3f1a263e1249..1ad5202e556b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -391,6 +391,9 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->nfct = from->nfct; nf_conntrack_get(to->nfct); to->nfctinfo = from->nfctinfo; +#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) + to->ipvs_property = from->ipvs_property; +#endif #ifdef CONFIG_BRIDGE_NETFILTER nf_bridge_put(to->nf_bridge); to->nf_bridge = from->nf_bridge; From 4595f251058609d97a5d792de08c34a7956af816 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 14 Oct 2005 21:29:56 +0100 Subject: [PATCH 0641/1939] [AX.25]: Fix signed char bug On architectures where the char type defaults to unsigned some of the arithmetic in the AX.25 stack to fail, resulting in some packets being dropped on receive. Credits for tracking this down and the original patch to Bob Brose N0QBJ . Signed-off-by: Ralf Baechle DL5RB Signed-off-by: Arnaldo Carvalho de Melo --- include/net/ax25.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ax25.h b/include/net/ax25.h index 9dbcd9e51c00..30bb4a893237 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -171,7 +171,7 @@ typedef struct { ax25_address calls[AX25_MAX_DIGIS]; unsigned char repeated[AX25_MAX_DIGIS]; unsigned char ndigi; - char lastrepeat; + signed char lastrepeat; } ax25_digi; typedef struct ax25_route { From d475f3f47a0427dfee483cecf9a7e9109e991423 Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Fri, 21 Oct 2005 22:06:15 +0400 Subject: [PATCH 0642/1939] [PATCH] alpha: additional smp barriers As stated in Documentation/atomic_ops.txt, atomic functions returning values must have the memory barriers both before and after the operation. Thanks to DaveM for pointing that out. Signed-off-by: Ivan Kokshaysky Signed-off-by: Linus Torvalds --- include/asm-alpha/atomic.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h index 1b383e3cb68c..0b40bad00289 100644 --- a/include/asm-alpha/atomic.h +++ b/include/asm-alpha/atomic.h @@ -100,18 +100,19 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v) static __inline__ long atomic_add_return(int i, atomic_t * v) { long temp, result; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%1\n" " addl %0,%3,%2\n" " addl %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,2f\n" - " mb\n" ".subsection 2\n" "2: br 1b\n" ".previous" :"=&r" (temp), "=m" (v->counter), "=&r" (result) :"Ir" (i), "m" (v->counter) : "memory"); + smp_mb(); return result; } @@ -120,54 +121,57 @@ static __inline__ long atomic_add_return(int i, atomic_t * v) static __inline__ long atomic64_add_return(long i, atomic64_t * v) { long temp, result; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%1\n" " addq %0,%3,%2\n" " addq %0,%3,%0\n" " stq_c %0,%1\n" " beq %0,2f\n" - " mb\n" ".subsection 2\n" "2: br 1b\n" ".previous" :"=&r" (temp), "=m" (v->counter), "=&r" (result) :"Ir" (i), "m" (v->counter) : "memory"); + smp_mb(); return result; } static __inline__ long atomic_sub_return(int i, atomic_t * v) { long temp, result; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%1\n" " subl %0,%3,%2\n" " subl %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,2f\n" - " mb\n" ".subsection 2\n" "2: br 1b\n" ".previous" :"=&r" (temp), "=m" (v->counter), "=&r" (result) :"Ir" (i), "m" (v->counter) : "memory"); + smp_mb(); return result; } static __inline__ long atomic64_sub_return(long i, atomic64_t * v) { long temp, result; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%1\n" " subq %0,%3,%2\n" " subq %0,%3,%0\n" " stq_c %0,%1\n" " beq %0,2f\n" - " mb\n" ".subsection 2\n" "2: br 1b\n" ".previous" :"=&r" (temp), "=m" (v->counter), "=&r" (result) :"Ir" (i), "m" (v->counter) : "memory"); + smp_mb(); return result; } From 203755029e063066ecc4cf5eee1110ab946c2d88 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 23 Oct 2005 16:11:39 +1000 Subject: [PATCH 0643/1939] [NEIGH] Print stack trace in neigh_add_timer Stack traces are very helpful in determining the exact nature of a bug. So let's print a stack trace when the timer is added twice. Signed-off-by: Herbert Xu --- net/core/neighbour.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4128fc76ac3a..766caa0dd930 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -732,6 +732,7 @@ static inline void neigh_add_timer(struct neighbour *n, unsigned long when) if (unlikely(mod_timer(&n->timer, when))) { printk("NEIGH: BUG, double timer add, state is %x\n", n->nud_state); + dump_stack(); } } From 6fb9974f49f7a6032118c5b6caa6e08e7097913e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 23 Oct 2005 16:37:48 +1000 Subject: [PATCH 0644/1939] [NEIGH] Fix add_timer race in neigh_add_timer neigh_add_timer cannot use add_timer unconditionally. The reason is that by the time it has obtained the write lock someone else (e.g., neigh_update) could have already added a new timer. So it should only use mod_timer and deal with its return value accordingly. This bug would have led to rare neighbour cache entry leaks. Signed-off-by: Herbert Xu --- net/core/neighbour.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 766caa0dd930..37d8d8c29522 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -816,10 +816,10 @@ static void neigh_timer_handler(unsigned long arg) } if (neigh->nud_state & NUD_IN_TIMER) { - neigh_hold(neigh); if (time_before(next, jiffies + HZ/2)) next = jiffies + HZ/2; - neigh_add_timer(neigh, next); + if (!mod_timer(&neigh->timer, next)) + neigh_hold(neigh); } if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { struct sk_buff *skb = skb_peek(&neigh->arp_queue); From 96c44507601d64f29b8ccc867637292e326c7019 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 23 Oct 2005 17:14:56 +1000 Subject: [PATCH 0645/1939] powerpc: Fix time code for 601 processors The 601 doesn't have the timebase register; instead it has an RTCL register that counts nanoseconds and wraps at 1000000000, and an RTCU register that counts seconds. This makes the necessary changes for the merged time code to use the RTCL/U registers when the kernel is running on a 601. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 79 +++++++++++++++++++++++++++----------- include/asm-powerpc/time.h | 14 ++++++- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index b635c7de6698..ad501d62aa6e 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -126,6 +126,16 @@ unsigned long ppc_tb_freq; #define boot_cpuid 0 #endif +u64 tb_last_jiffy __cacheline_aligned_in_smp; +unsigned long tb_last_stamp; + +/* + * Note that on ppc32 this only stores the bottom 32 bits of + * the timebase value, but that's enough to tell when a jiffy + * has passed. + */ +DEFINE_PER_CPU(unsigned long, last_jiffy); + static __inline__ void timer_check_rtc(void) { /* @@ -191,6 +201,26 @@ static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val) void do_gettimeofday(struct timeval *tv) { + if (__USE_RTC()) { + /* do this the old way */ + unsigned long flags, seq; + unsigned int sec, nsec, usec, lost; + + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + sec = xtime.tv_sec; + nsec = xtime.tv_nsec + tb_ticks_since(tb_last_stamp); + lost = jiffies - wall_jiffies; + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + usec = nsec / 1000 + lost * (1000000 / HZ); + while (usec >= 1000000) { + usec -= 1000000; + ++sec; + } + tv->tv_sec = sec; + tv->tv_usec = usec; + return; + } __do_gettimeofday(tv, get_tb()); } @@ -272,6 +302,8 @@ static __inline__ void timer_recalc_offset(u64 cur_tb) unsigned long offset; u64 new_stamp_xsec; + if (__USE_RTC()) + return; offset = cur_tb - do_gtod.varp->tb_orig_stamp; if ((offset & 0x80000000u) == 0) return; @@ -357,15 +389,6 @@ static void iSeries_tb_recal(void) * call will not be needed) */ -u64 tb_last_stamp __cacheline_aligned_in_smp; - -/* - * Note that on ppc32 this only stores the bottom 32 bits of - * the timebase value, but that's enough to tell when a jiffy - * has passed. - */ -DEFINE_PER_CPU(unsigned long, last_jiffy); - /* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. @@ -415,10 +438,11 @@ void timer_interrupt(struct pt_regs * regs) continue; write_seqlock(&xtime_lock); - tb_last_stamp += tb_ticks_per_jiffy; - timer_recalc_offset(tb_last_stamp); + tb_last_jiffy += tb_ticks_per_jiffy; + tb_last_stamp = per_cpu(last_jiffy, cpu); + timer_recalc_offset(tb_last_jiffy); do_timer(regs); - timer_sync_xtime(tb_last_stamp); + timer_sync_xtime(tb_last_jiffy); timer_check_rtc(); write_sequnlock(&xtime_lock); if (adjusting_time && (time_adjust == 0)) @@ -453,7 +477,7 @@ void wakeup_decrementer(void) * We don't expect this to be called on a machine with a 601, * so using get_tbl is fine. */ - tb_last_stamp = get_tb(); + tb_last_stamp = tb_last_jiffy = get_tb(); for_each_cpu(i) per_cpu(last_jiffy, i) = tb_last_stamp; } @@ -483,6 +507,8 @@ void __init smp_space_timers(unsigned int max_cpus) */ unsigned long long sched_clock(void) { + if (__USE_RTC()) + return get_rtc(); return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; } @@ -534,7 +560,7 @@ int do_settimeofday(struct timespec *tv) new_xsec = (u64)new_nsec * XSEC_PER_SEC; do_div(new_xsec, NSEC_PER_SEC); new_xsec += (u64)new_sec * XSEC_PER_SEC; - update_gtod(tb_last_stamp, new_xsec, do_gtod.varp->tb_to_xs); + update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); #ifdef CONFIG_PPC64 systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; @@ -616,12 +642,20 @@ void __init time_init(void) if (ppc_md.time_init != NULL) timezone_offset = ppc_md.time_init(); - ppc_md.calibrate_decr(); - - printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", - ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); - printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", - ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); + if (__USE_RTC()) { + /* 601 processor: dec counts down by 128 every 128ns */ + ppc_tb_freq = 1000000000; + tb_last_stamp = get_rtcl(); + tb_last_jiffy = tb_last_stamp; + } else { + /* Normal PowerPC with timebase register */ + ppc_md.calibrate_decr(); + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); + printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", + ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); + tb_last_stamp = tb_last_jiffy = get_tb(); + } tb_ticks_per_jiffy = ppc_tb_freq / HZ; tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; @@ -661,17 +695,16 @@ void __init time_init(void) write_seqlock_irqsave(&xtime_lock, flags); xtime.tv_sec = tm; xtime.tv_nsec = 0; - tb_last_stamp = get_tb(); do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; - do_gtod.varp->tb_orig_stamp = tb_last_stamp; + do_gtod.varp->tb_orig_stamp = tb_last_jiffy; __get_cpu_var(last_jiffy) = tb_last_stamp; do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC; do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; do_gtod.tb_to_us = tb_to_us; #ifdef CONFIG_PPC64 - systemcfg->tb_orig_stamp = tb_last_stamp; + systemcfg->tb_orig_stamp = tb_last_jiffy; systemcfg->tb_update_count = 0; systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index 99bfe3281768..410e795f7d43 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -30,7 +30,8 @@ extern unsigned long tb_ticks_per_usec; extern unsigned long tb_ticks_per_sec; extern u64 tb_to_xs; extern unsigned tb_to_us; -extern u64 tb_last_stamp; +extern unsigned long tb_last_stamp; +extern u64 tb_last_jiffy; DECLARE_PER_CPU(unsigned long, last_jiffy); @@ -113,6 +114,17 @@ static inline unsigned int get_rtcl(void) return rtcl; } +static inline u64 get_rtc(void) +{ + unsigned int hi, lo, hi2; + + do { + asm volatile("mfrtcu %0; mfrtcl %1; mfrtcu %2" + : "=r" (hi), "=r" (lo), "=r" (hi2)); + } while (hi2 != hi); + return (u64)hi * 1000000000 + lo; +} + #ifdef CONFIG_PPC64 static inline u64 get_tb(void) { From 49636bb12892786e4a7b207b37ca7b0c5ca1cae0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 23 Oct 2005 17:18:00 +1000 Subject: [PATCH 0646/1939] [NEIGH] Fix timer leak in neigh_changeaddr neigh_changeaddr attempts to delete neighbour timers without setting nud_state. This doesn't work because the timer may have already fired when we acquire the write lock in neigh_changeaddr. The result is that the timer may keep firing for quite a while until the entry reaches NEIGH_FAILED. It should be setting the nud_state straight away so that if the timer has already fired it can simply exit once we relinquish the lock. In fact, this whole function is simply duplicating the logic in neigh_ifdown which in turn is already doing the right thing when it comes to deleting timers and setting nud_state. So all we have to do is take that code out and put it into a common function and make both neigh_changeaddr and neigh_ifdown call it. Signed-off-by: Herbert Xu --- net/core/neighbour.c | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 37d8d8c29522..1dcf7fa1f0fe 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -175,39 +175,10 @@ static void pneigh_queue_purge(struct sk_buff_head *list) } } -void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) +static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) { int i; - write_lock_bh(&tbl->lock); - - for (i=0; i <= tbl->hash_mask; i++) { - struct neighbour *n, **np; - - np = &tbl->hash_buckets[i]; - while ((n = *np) != NULL) { - if (dev && n->dev != dev) { - np = &n->next; - continue; - } - *np = n->next; - write_lock_bh(&n->lock); - n->dead = 1; - neigh_del_timer(n); - write_unlock_bh(&n->lock); - neigh_release(n); - } - } - - write_unlock_bh(&tbl->lock); -} - -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) -{ - int i; - - write_lock_bh(&tbl->lock); - for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np = &tbl->hash_buckets[i]; @@ -243,7 +214,19 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) neigh_release(n); } } +} +void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) +{ + write_lock_bh(&tbl->lock); + neigh_flush_dev(tbl, dev); + write_unlock_bh(&tbl->lock); +} + +int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) +{ + write_lock_bh(&tbl->lock); + neigh_flush_dev(tbl, dev); pneigh_ifdown(tbl, dev); write_unlock_bh(&tbl->lock); From a575b807172ca7d8850e6e979c8e83d4258e8c43 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 23 Oct 2005 17:23:21 +1000 Subject: [PATCH 0647/1939] powerpc: Run on old powermacs. Old powermacs have a number of differences from current machines: - there is no interrupt tree in the device tree, just interrupt or AAPL,interrupt properties - the chosen node in the device tree is called /chosen@0 - the OF claim method doesn't map the memory, so we have to do an explicit map call as well - there is no /chosen/cpu property on SMP machines - the NVRAM isn't structured as a set of partitions. This adapts the merged powermac support code to cope with these issues. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 36 +++++++++- arch/powerpc/kernel/prom_init.c | 87 ++++++++++++++++++------- arch/powerpc/platforms/powermac/setup.c | 10 ++- 3 files changed, 106 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index c8d288457b4c..69f69c38fd27 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -309,6 +309,37 @@ static int __devinit finish_node_interrupts(struct device_node *np, unsigned int *irq, virq; struct device_node *ic; + if (num_interrupt_controllers == 0) { + /* + * Old machines just have a list of interrupt numbers + * and no interrupt-controller nodes. + */ + ints = (unsigned int *) get_property(np, "AAPL,interrupts", + &intlen); + /* XXX old interpret_pci_props looked in parent too */ + /* XXX old interpret_macio_props looked for interrupts + before AAPL,interrupts */ + if (ints == NULL) + ints = (unsigned int *) get_property(np, "interrupts", + &intlen); + if (ints == NULL) + return 0; + + np->n_intrs = intlen / sizeof(unsigned int); + np->intrs = prom_alloc(np->n_intrs * sizeof(np->intrs[0]), + mem_start); + if (!np->intrs) + return -ENOMEM; + if (measure_only) + return 0; + + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *ints++; + np->intrs[i].sense = 1; + } + return 0; + } + ints = (unsigned int *) get_property(np, "interrupts", &intlen); if (ints == NULL) return 0; @@ -1024,6 +1055,8 @@ void __init unflatten_device_tree(void) /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); + if (of_chosen == NULL) + of_chosen = of_find_node_by_path("/chosen@0"); /* Retreive command line */ if (of_chosen != NULL) { @@ -1123,7 +1156,8 @@ static int __init early_init_dt_scan_chosen(unsigned long node, DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - if (depth != 1 || strcmp(uname, "chosen") != 0) + if (depth != 1 || + (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) return 0; /* get platform type */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 095659d51b4b..18d266d8935d 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -132,6 +132,7 @@ struct prom_t { ihandle chosen; int cpu; ihandle stdout; + ihandle mmumap; }; struct mem_map_entry { @@ -274,14 +275,6 @@ static int __init call_prom_ret(const char *service, int nargs, int nret, } -static unsigned int __init prom_claim(unsigned long virt, unsigned long size, - unsigned long align) -{ - return (unsigned int)call_prom("claim", 3, 1, - (prom_arg_t)virt, (prom_arg_t)size, - (prom_arg_t)align); -} - static void __init prom_print(const char *msg) { const char *p, *q; @@ -363,6 +356,21 @@ static void __init prom_printf(const char *format, ...) } +static unsigned int __init prom_claim(unsigned long virt, unsigned long size, + unsigned long align) +{ + int ret; + struct prom_t *_prom = &RELOC(prom); + + ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, + (prom_arg_t)align); + if (ret != -1 && _prom->mmumap != 0) + /* old pmacs need us to map as well */ + call_prom("call-method", 6, 1, + ADDR("map"), _prom->mmumap, 0, size, virt, virt); + return ret; +} + static void __init __attribute__((noreturn)) prom_panic(const char *reason) { #ifdef CONFIG_PPC64 @@ -1323,8 +1331,38 @@ static void __init prom_init_client_services(unsigned long pp) _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); if (!PHANDLE_VALID(_prom->root)) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ + + _prom->mmumap = 0; } +#ifdef CONFIG_PPC32 +/* + * For really old powermacs, we need to map things we claim. + * For that, we need the ihandle of the mmu. + */ +static void __init prom_find_mmu(void) +{ + struct prom_t *_prom = &RELOC(prom); + phandle oprom; + char version[64]; + + oprom = call_prom("finddevice", 1, 1, ADDR("/openprom")); + if (!PHANDLE_VALID(oprom)) + return; + if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) + return; + version[sizeof(version) - 1] = 0; + prom_printf("OF version is '%s'\n", version); + /* XXX might need to add other versions here */ + if (strcmp(version, "Open Firmware, 1.0.5") != 0) + return; + prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, + sizeof(_prom->mmumap)); +} +#else +#define prom_find_mmu() +#endif + static void __init prom_init_stdout(void) { struct prom_t *_prom = &RELOC(prom); @@ -1379,7 +1417,7 @@ static int __init prom_find_machine_type(void) if (sl == 0) break; if (strstr(p, RELOC("Power Macintosh")) || - strstr(p, RELOC("MacRISC4"))) + strstr(p, RELOC("MacRISC"))) return PLATFORM_POWERMAC; #ifdef CONFIG_PPC64 if (strstr(p, RELOC("Momentum,Maple"))) @@ -1618,22 +1656,17 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, namep[l] = '\0'; /* Fixup an Apple bug where they have bogus \0 chars in the - * middle of the path in some properties + * middle of the path in some properties, and extract + * the unit name (everything after the last '/'). */ - for (p = namep, ep = namep + l; p < ep; p++) - if (*p == '\0') { - memmove(p, p+1, ep - p); - ep--; l--; p--; - } - - /* now try to extract the unit name in that mess */ - for (p = namep, lp = NULL; *p; p++) + for (lp = p = namep, ep = namep + l; p < ep; p++) { if (*p == '/') - lp = p + 1; - if (lp != NULL) - memmove(namep, lp, strlen(lp) + 1); - *mem_start = _ALIGN(((unsigned long) namep) + - strlen(namep) + 1, 4); + lp = namep; + else if (*p != 0) + *lp++ = *p; + } + *lp = 0; + *mem_start = _ALIGN((unsigned long)lp + 1, 4); } /* get it again for debugging */ @@ -1858,8 +1891,9 @@ static void __init prom_find_boot_cpu(void) ihandle prom_cpu; phandle cpu_pkg; + _prom->cpu = 0; if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) - prom_panic("cannot find boot cpu"); + return; cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); @@ -1933,6 +1967,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_init_stdout(); + /* + * See if this OF is old enough that we need to do explicit maps + */ + prom_find_mmu(); + /* * Check for an initrd */ diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 50f5dd787900..908e4921bac4 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -225,7 +225,7 @@ int find_via_pmu(void) return 0; printk("WARNING ! Your machine is PMU-based but your kernel\n"); printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); - return; + return 0; } #endif @@ -293,7 +293,7 @@ static void __init l2cr_init(void) void __init pmac_setup_arch(void) { - struct device_node *cpu; + struct device_node *cpu, *ic; int *fp; unsigned long pvr; @@ -319,6 +319,12 @@ void __init pmac_setup_arch(void) of_node_put(cpu); } + /* See if newworld or oldworld */ + ic = of_find_node_by_name(NULL, "interrupt-controller"); + pmac_newworld = (ic != NULL); + if (ic) + of_node_put(ic); + /* Lookup PCI hosts */ pmac_pci_init(); From 85e568ea5843d455a0bcb682ad2c71abb50bdb80 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 23 Oct 2005 17:26:32 +1000 Subject: [PATCH 0648/1939] powerpc: Make coff boot wrapper load the kernel at 8M Previously it claimed 7MB starting at the 9M point and loaded the kernel there. That meant that prom_init put the flattened device tree above 16M. On the 601 that caused the early device tree scan to fail, since only 16MB are mapped with BATs on the 601. Moving this down to 8MB allows prom_init to put the flattened device tree between 15M and 16M, so it works on the 601. Signed-off-by: Paul Mackerras --- arch/ppc/boot/openfirmware/coffmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c index 04ba9d57e110..2da8855e2be0 100644 --- a/arch/ppc/boot/openfirmware/coffmain.c +++ b/arch/ppc/boot/openfirmware/coffmain.c @@ -38,7 +38,7 @@ static char heap[SCRATCH_SIZE]; static unsigned long ram_start = 0; static unsigned long ram_end = 0x1000000; -static unsigned long prog_start = 0x900000; +static unsigned long prog_start = 0x800000; static unsigned long prog_size = 0x700000; typedef void (*kernel_start_t)(int, int, void *); From e80eda94d3eaf1d12cfc97878eff77cd679dabc9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 23 Oct 2005 10:02:50 -0700 Subject: [PATCH 0649/1939] Posix timers: limit number of timers firing at once Bursty timers aren't good for anybody, very much including latency for other programs when we trigger lots of timers in interrupt context. So set a random limit, after which we'll handle the rest on the next timer tick. Noted by Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 7a51a5597c33..d30b304a3384 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -961,14 +961,16 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) static void check_thread_timers(struct task_struct *tsk, struct list_head *firing) { + int maxfire; struct list_head *timers = tsk->cpu_timers; + maxfire = 20; tsk->it_prof_expires = cputime_zero; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (cputime_lt(prof_ticks(tsk), t->expires.cpu)) { + if (!--maxfire || cputime_lt(prof_ticks(tsk), t->expires.cpu)) { tsk->it_prof_expires = t->expires.cpu; break; } @@ -977,12 +979,13 @@ static void check_thread_timers(struct task_struct *tsk, } ++timers; + maxfire = 20; tsk->it_virt_expires = cputime_zero; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (cputime_lt(virt_ticks(tsk), t->expires.cpu)) { + if (!--maxfire || cputime_lt(virt_ticks(tsk), t->expires.cpu)) { tsk->it_virt_expires = t->expires.cpu; break; } @@ -991,12 +994,13 @@ static void check_thread_timers(struct task_struct *tsk, } ++timers; + maxfire = 20; tsk->it_sched_expires = 0; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (tsk->sched_time < t->expires.sched) { + if (!--maxfire || tsk->sched_time < t->expires.sched) { tsk->it_sched_expires = t->expires.sched; break; } @@ -1013,6 +1017,7 @@ static void check_thread_timers(struct task_struct *tsk, static void check_process_timers(struct task_struct *tsk, struct list_head *firing) { + int maxfire; struct signal_struct *const sig = tsk->signal; cputime_t utime, stime, ptime, virt_expires, prof_expires; unsigned long long sched_time, sched_expires; @@ -1045,12 +1050,13 @@ static void check_process_timers(struct task_struct *tsk, } while (t != tsk); ptime = cputime_add(utime, stime); + maxfire = 20; prof_expires = cputime_zero; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (cputime_lt(ptime, t->expires.cpu)) { + if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) { prof_expires = t->expires.cpu; break; } @@ -1059,12 +1065,13 @@ static void check_process_timers(struct task_struct *tsk, } ++timers; + maxfire = 20; virt_expires = cputime_zero; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (cputime_lt(utime, t->expires.cpu)) { + if (!--maxfire || cputime_lt(utime, t->expires.cpu)) { virt_expires = t->expires.cpu; break; } @@ -1073,12 +1080,13 @@ static void check_process_timers(struct task_struct *tsk, } ++timers; + maxfire = 20; sched_expires = 0; while (!list_empty(timers)) { struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list, entry); - if (sched_time < t->expires.sched) { + if (!--maxfire || sched_time < t->expires.sched) { sched_expires = t->expires.sched; break; } From 4196c3af25d98204216a5d6c37ad2cb303a1f2bf Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 23 Oct 2005 16:31:16 -0700 Subject: [PATCH 0650/1939] cardbus: limit IO windows to 256 bytes That's what we've always historically done, and bigger windows seem to confuse some cardbus bridges. Or something. Alan reports that this makes the ThinkPad 600x series work properly again: the 4kB IO window for some reason made IDE DMA not work, which makes IDE painfully slow even if it works after DMA timeouts. Signed-off-by: Linus Torvalds --- drivers/pci/setup-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 657be948baf7..28ce3a7ee434 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -40,7 +40,7 @@ * FIXME: IO should be max 256 bytes. However, since we may * have a P2P bridge below a cardbus bridge, we need 4K. */ -#define CARDBUS_IO_SIZE (4*1024) +#define CARDBUS_IO_SIZE (256) #define CARDBUS_MEM_SIZE (32*1024*1024) static void __devinit From a991304496bdaec09f497d1eb5d9dcf2f94b7d5d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 23 Oct 2005 12:57:11 -0700 Subject: [PATCH 0651/1939] [PATCH] kernel-parameters cleanup Fix typos & trailing whitespace. Add blank lines in a few places. Remove "AM53C974=" option: driver does not exist. Restrict to < 80 columns in most places (but don't split formatted command-line arguments). Add a few option arguments for completeness. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 492 +++++++++++++++------------- 1 file changed, 258 insertions(+), 234 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7086f0a90d14..971589a9752d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -17,7 +17,7 @@ are specified on the kernel command line with the module name plus usbcore.blinkenlights=1 -The text in square brackets at the beginning of the description state the +The text in square brackets at the beginning of the description states the restrictions on the kernel for the said kernel parameter to be valid. The restrictions referred to are that the relevant option is valid if: @@ -27,8 +27,8 @@ restrictions referred to are that the relevant option is valid if: APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. CD Appropriate CD support is enabled. - DEVFS devfs support is enabled. - DRM Direct Rendering Management support is enabled. + DEVFS devfs support is enabled. + DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. @@ -71,7 +71,7 @@ restrictions referred to are that the relevant option is valid if: SERIAL Serial support is enabled. SMP The kernel is an SMP kernel. SPARC Sparc architecture is enabled. - SWSUSP Software suspension is enabled. + SWSUSP Software suspend is enabled. TS Appropriate touchscreen support is enabled. USB USB support is enabled. USBHID USB Human Interface Device support is enabled. @@ -105,13 +105,13 @@ running once the system is up. See header of drivers/scsi/53c7xx.c. See also Documentation/scsi/ncr53c7xx.txt. - acpi= [HW,ACPI] Advanced Configuration and Power Interface - Format: { force | off | ht | strict } + acpi= [HW,ACPI] Advanced Configuration and Power Interface + Format: { force | off | ht | strict | noirq } force -- enable ACPI if default was off off -- disable ACPI if default was on noirq -- do not use ACPI for IRQ routing ht -- run only enough ACPI to enable Hyper Threading - strict -- Be less tolerant of platforms that are not + strict -- Be less tolerant of platforms that are not strictly ACPI specification compliant. See also Documentation/pm.txt, pci=noacpi @@ -119,20 +119,23 @@ running once the system is up. acpi_sleep= [HW,ACPI] Sleep options Format: { s3_bios, s3_mode } See Documentation/power/video.txt - + acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode - Format: { level | edge | high | low } + Format: { level | edge | high | low } - acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs - default in APIC mode + acpi_irq_balance [HW,ACPI] + ACPI will balance active IRQs + default in APIC mode - acpi_irq_nobalance [HW,ACPI] ACPI will not move active IRQs (default) - default in PIC mode + acpi_irq_nobalance [HW,ACPI] + ACPI will not move active IRQs (default) + default in PIC mode - acpi_irq_pci= [HW,ACPI] If irq_balance, Clear listed IRQs for use by PCI + acpi_irq_pci= [HW,ACPI] If irq_balance, clear listed IRQs for + use by PCI Format: ,... - acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA + acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA Format: ,... acpi_osi= [HW,ACPI] empty param disables _OSI @@ -145,14 +148,14 @@ running once the system is up. acpi_dbg_layer= [HW,ACPI] Format: - Each bit of the indicates an acpi debug layer, + Each bit of the indicates an ACPI debug layer, 1: enable, 0: disable. It is useful for boot time debugging. After system has booted up, it can be set via /proc/acpi/debug_layer. acpi_dbg_level= [HW,ACPI] Format: - Each bit of the indicates an acpi debug level, + Each bit of the indicates an ACPI debug level, 1: enable, 0: disable. It is useful for boot time debugging. After system has booted up, it can be set via /proc/acpi/debug_level. @@ -161,12 +164,13 @@ running once the system is up. acpi_generic_hotkey [HW,ACPI] Allow consolidated generic hotkey driver to - over-ride platform specific driver. + override platform specific driver. See also Documentation/acpi-hotkey.txt. enable_timer_pin_1 [i386,x86-64] Enable PIN 1 of APIC timer - Can be useful to work around chipset bugs (in particular on some ATI chipsets) + Can be useful to work around chipset bugs + (in particular on some ATI chipsets). The kernel tries to set a reasonable default. disable_timer_pin_1 [i386,x86-64] @@ -182,7 +186,7 @@ running once the system is up. adlib= [HW,OSS] Format: - + advansys= [HW,SCSI] See header of drivers/scsi/advansys.c. @@ -192,7 +196,7 @@ running once the system is up. aedsp16= [HW,OSS] Audio Excel DSP 16 Format: ,,,,, See also header of sound/oss/aedsp16.c. - + aha152x= [HW,SCSI] See Documentation/scsi/aha152x.txt. @@ -205,10 +209,6 @@ running once the system is up. aic79xx= [HW,SCSI] See Documentation/scsi/aic79xx.txt. - AM53C974= [HW,SCSI] - Format: ,,, - See also header of drivers/scsi/AM53C974.c. - amijoy.map= [HW,JOY] Amiga joystick support Map of devices attached to JOY0DAT and JOY1DAT Format: , @@ -219,23 +219,24 @@ running once the system is up. connected to one of 16 gameports Format: ,,.. - apc= [HW,SPARC] Power management functions (SPARCstation-4/5 + deriv.) + apc= [HW,SPARC] + Power management functions (SPARCstation-4/5 + deriv.) Format: noidle Disable APC CPU standby support. SPARCstation-Fox does not play well with APC CPU idle - disable it if you have APC and your system crashes randomly. - apic= [APIC,i386] Change the output verbosity whilst booting + apic= [APIC,i386] Change the output verbosity whilst booting Format: { quiet (default) | verbose | debug } Change the amount of debugging information output when initialising the APIC and IO-APIC components. - + apm= [APM] Advanced Power Management See header of arch/i386/kernel/apm.c. applicom= [HW] Format: , - + arcrimi= [HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards Format: ,, @@ -250,38 +251,40 @@ running once the system is up. atkbd.reset= [HW] Reset keyboard during initialization - atkbd.set= [HW] Select keyboard code set - Format: (2 = AT (default) 3 = PS/2) + atkbd.set= [HW] Select keyboard code set + Format: (2 = AT (default), 3 = PS/2) atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar keyboards atkbd.softraw= [HW] Choose between synthetic and real raw mode Format: (0 = real, 1 = synthetic (default)) - - atkbd.softrepeat= - [HW] Use software keyboard repeat + + atkbd.softrepeat= [HW] + Use software keyboard repeat autotest [IA64] awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth Format: ,, - + aztcd= [HW,CD] Aztech CD268 CDROM driver Format: ,0x79 (?) baycom_epp= [HW,AX25] Format: , - + baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem Format: , See header of drivers/net/hamradio/baycom_par.c. - baycom_ser_fdx= [HW,AX25] BayCom Serial Port AX.25 Modem (Full Duplex Mode) + baycom_ser_fdx= [HW,AX25] + BayCom Serial Port AX.25 Modem (Full Duplex Mode) Format: ,,[,] See header of drivers/net/hamradio/baycom_ser_fdx.c. - baycom_ser_hdx= [HW,AX25] BayCom Serial Port AX.25 Modem (Half Duplex Mode) + baycom_ser_hdx= [HW,AX25] + BayCom Serial Port AX.25 Modem (Half Duplex Mode) Format: ,, See header of drivers/net/hamradio/baycom_ser_hdx.c. @@ -292,7 +295,8 @@ running once the system is up. blkmtd_count= bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) - bttv.radio= Most important insmod options are available as kernel args too. + bttv.radio= Most important insmod options are available as + kernel args too. bttv.pll= See Documentation/video4linux/bttv/Insmod-options bttv.tuner= and Documentation/video4linux/bttv/CARDLIST @@ -318,15 +322,17 @@ running once the system is up. checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text. - 0 -- check protection applied by kernel (includes any implied execute protection). + 0 -- check protection applied by kernel (includes + any implied execute protection). 1 -- check protection requested by application. Default value is set via a kernel config option. - Value can be changed at runtime via /selinux/checkreqprot. - - clock= [BUGS=IA-32, HW] gettimeofday timesource override. + Value can be changed at runtime via + /selinux/checkreqprot. + + clock= [BUGS=IA-32,HW] gettimeofday timesource override. Forces specified timesource (if avaliable) to be used - when calculating gettimeofday(). If specicified timesource - is not avalible, it defaults to PIT. + when calculating gettimeofday(). If specicified + timesource is not avalible, it defaults to PIT. Format: { pit | tsc | cyclone | pmtmr } hpet= [IA-32,HPET] option to disable HPET and use PIT. @@ -336,17 +342,19 @@ running once the system is up. Format: { auto | [,][] } com20020= [HW,NET] ARCnet - COM20020 chipset - Format: [,[,[,[,[,]]]]] + Format: + [,[,[,[,[,]]]]] com90io= [HW,NET] ARCnet - COM90xx chipset (IO-mapped buffers) Format: [,] - com90xx= [HW,NET] ARCnet - COM90xx chipset (memory-mapped buffers) + com90xx= [HW,NET] + ARCnet - COM90xx chipset (memory-mapped buffers) Format: [,[,]] condev= [HW,S390] console device conmode= - + console= [KNL] Output console device and options. tty Use the virtual console device . @@ -367,7 +375,8 @@ running once the system is up. options are the same as for ttyS, above. cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver - Format: ,,,[,] + Format: + ,,,[,] cpia_pp= [HW,PPT] Format: { parport | auto | none } @@ -384,10 +393,10 @@ running once the system is up. cs89x0_media= [HW,NET] Format: { rj45 | aui | bnc } - + cyclades= [HW,SERIAL] Cyclades multi-serial port adapter. - - dasd= [HW,NET] + + dasd= [HW,NET] See header of drivers/s390/block/dasd_devmap.c. db9.dev[2|3]= [HW,JOY] Multisystem joystick support via parallel port @@ -406,7 +415,7 @@ running once the system is up. dhash_entries= [KNL] Set number of hash buckets for dentry cache. - + digi= [HW,SERIAL] IO parameters + enable/disable command. @@ -424,11 +433,11 @@ running once the system is up. dtc3181e= [HW,SCSI] - earlyprintk= [IA-32, X86-64] + earlyprintk= [IA-32,X86-64] earlyprintk=vga earlyprintk=serial[,ttySn[,baudrate]] - Append ,keep to not disable it when the real console + Append ",keep" to not disable it when the real console takes over. Only vga or serial at a time, not both. @@ -451,7 +460,7 @@ running once the system is up. Format: {"of[f]" | "sk[ipmbr]"} See comment in arch/i386/boot/edd.S - eicon= [HW,ISDN] + eicon= [HW,ISDN] Format: ,, eisa_irq_edge= [PARISC,HW] @@ -462,12 +471,13 @@ running once the system is up. arch/i386/kernel/cpu/cpufreq/elanfreq.c. elevator= [IOSCHED] - Format: {"as"|"cfq"|"deadline"|"noop"} - See Documentation/block/as-iosched.txt - and Documentation/block/deadline-iosched.txt for details. + Format: {"as" | "cfq" | "deadline" | "noop"} + See Documentation/block/as-iosched.txt and + Documentation/block/deadline-iosched.txt for details. + elfcorehdr= [IA-32] - Specifies physical address of start of kernel core image - elf header. + Specifies physical address of start of kernel core + image elf header. See Documentation/kdump.txt for details. enforcing [SELINUX] Set initial enforcing status. @@ -485,7 +495,7 @@ running once the system is up. es1371= [HW,OSS] Format: ,[,[]] See also header of sound/oss/es1371.c. - + ether= [HW,NET] Ethernet cards parameters This option is obsoleted by the "netdev=" option, which has equivalent usage. See its documentation for details. @@ -526,12 +536,13 @@ running once the system is up. gus= [HW,OSS] Format: ,,, - + gvp11= [HW,SCSI] hashdist= [KNL,NUMA] Large hashes allocated during boot are distributed across NUMA nodes. Defaults on for IA-64, off otherwise. + Format: 0 | 1 (for off | on) hcl= [IA-64] SGI's Hardware Graph compatibility layer @@ -595,13 +606,13 @@ running once the system is up. ide?= [HW] (E)IDE subsystem Format: ide?=noprobe or chipset specific parameters. See Documentation/ide.txt. - + idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed See Documentation/ide.txt. idle= [HW] Format: idle=poll or idle=halt - + ihash_entries= [KNL] Set number of hash buckets for inode cache. @@ -649,7 +660,7 @@ running once the system is up. firmware running. isapnp= [ISAPNP] - Format: , , , + Format: ,,, isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler. Format: ,..., @@ -661,32 +672,33 @@ running once the system is up. "number of CPUs in system - 1". This option is the preferred way to isolate CPUs. The - alternative - manually setting the CPU mask of all tasks - in the system can cause problems and suboptimal load - balancer performance. + alternative -- manually setting the CPU mask of all + tasks in the system -- can cause problems and + suboptimal load balancer performance. isp16= [HW,CD] Format: ,,, - iucv= [HW,NET] + iucv= [HW,NET] js= [HW,JOY] Analog joystick See Documentation/input/joystick.txt. keepinitrd [HW,ARM] - kstack=N [IA-32, X86-64] Print N words from the kernel stack + kstack=N [IA-32,X86-64] Print N words from the kernel stack in oops dumps. l2cr= [PPC] - lapic [IA-32,APIC] Enable the local APIC even if BIOS disabled it. + lapic [IA-32,APIC] Enable the local APIC even if BIOS + disabled it. lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip Format: addr:,irq: - llsc*= [IA64] - See function print_params() in arch/ia64/sn/kernel/llsc4.c. + llsc*= [IA64] See function print_params() in + arch/ia64/sn/kernel/llsc4.c. load_ramdisk= [RAM] List of ramdisks to load from floppy See Documentation/ramdisk.txt. @@ -713,8 +725,9 @@ running once the system is up. 7 (KERN_DEBUG) debug-level messages log_buf_len=n Sets the size of the printk ring buffer, in bytes. - Format is n, nk, nM. n must be a power of two. The - default is set in kernel config. + Format: { n | nk | nM } + n must be a power of two. The default size + is set in the kernel config file. lp=0 [LP] Specify parallel ports to use, e.g, lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses @@ -750,23 +763,23 @@ running once the system is up. ltpc= [NET] Format: ,, - mac5380= [HW,SCSI] - Format: ,,,, + mac5380= [HW,SCSI] Format: + ,,,, - mac53c9x= [HW,SCSI] - Format: ,,,,,,, + mac53c9x= [HW,SCSI] Format: + ,,,,,,, - machvec= [IA64] - Force the use of a particular machine-vector (machvec) in a generic - kernel. Example: machvec=hpzx1_swiotlb + machvec= [IA64] Force the use of a particular machine-vector + (machvec) in a generic kernel. + Example: machvec=hpzx1_swiotlb - mad16= [HW,OSS] - Format: ,,,,,, + mad16= [HW,OSS] Format: + ,,,,,, maui= [HW,OSS] Format: , - - max_loop= [LOOP] Maximum number of loopback devices that can + + max_loop= [LOOP] Maximum number of loopback devices that can be mounted Format: <1-256> @@ -776,11 +789,11 @@ running once the system is up. max_addr=[KMG] [KNL,BOOT,ia64] All physical memory greater than or equal to this physical address is ignored. - max_luns= [SCSI] Maximum number of LUNs to probe + max_luns= [SCSI] Maximum number of LUNs to probe. Should be between 1 and 2^32-1. max_report_luns= - [SCSI] Maximum number of LUNs received + [SCSI] Maximum number of LUNs received. Should be between 1 and 16384. mca-pentium [BUGS=IA-32] @@ -796,11 +809,11 @@ running once the system is up. md= [HW] RAID subsystems devices and level See Documentation/md.txt. - + mdacon= [MDA] Format: , Specifies range of consoles to be captured by the MDA. - + mem=nn[KMG] [KNL,BOOT] Force usage of a specific amount of memory Amount of memory to be used when the kernel is not able to see the whole system memory or for test. @@ -851,15 +864,15 @@ running once the system is up. MTD_Partition= [MTD] Format: ,,, - MTD_Region= [MTD] - Format: ,[,,,,] + MTD_Region= [MTD] Format: + ,[,,,,] mtdparts= [MTD] See drivers/mtd/cmdline.c. mtouchusb.raw_coordinates= - [HW] Make the MicroTouch USB driver use raw coordinates ('y', default) - or cooked coordinates ('n') + [HW] Make the MicroTouch USB driver use raw coordinates + ('y', default) or cooked coordinates ('n') n2= [NET] SDL Inc. RISCom/N2 synchronous serial card @@ -880,7 +893,9 @@ running once the system is up. Format: ,,,, Note that mem_start is often overloaded to mean something different and driver-specific. - + This usage is only documented in each driver source + file if at all. + nfsaddrs= [NFS] See Documentation/nfsroot.txt. @@ -893,8 +908,8 @@ running once the system is up. emulation library even if a 387 maths coprocessor is present. - noalign [KNL,ARM] - + noalign [KNL,ARM] + noapic [SMP,APIC] Tells the kernel to not make use of any IOAPICs that may be present in the system. @@ -905,19 +920,19 @@ running once the system is up. on "Classic" PPC cores. nocache [ARM] - + nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects. noexec [IA-64] - noexec [IA-32, X86-64] + noexec [IA-32,X86-64] noexec=on: enable non-executable mappings (default) noexec=off: disable nn-executable mappings nofxsr [BUGS=IA-32] nohlt [BUGS=ARM] - + no-hlt [BUGS=IA-32] Tells the kernel that the hlt instruction doesn't work correctly and not to use it. @@ -948,8 +963,9 @@ running once the system is up. noresidual [PPC] Don't use residual data on PReP machines. - noresume [SWSUSP] Disables resume and restore original swap space. - + noresume [SWSUSP] Disables resume and restores original swap + space. + no-scroll [VGA] Disables scrollback. This is required for the Braillex ib80-piezo Braille reader made by F.H. Papenmeier (Germany). @@ -965,16 +981,16 @@ running once the system is up. nousb [USB] Disable the USB subsystem nowb [ARM] - + opl3= [HW,OSS] Format: opl3sa= [HW,OSS] Format: ,,,,, - opl3sa2= [HW,OSS] - Format: ,,,,,,,[,,,,,,,,,[,, parkbd.mode= [HW] Parallel port keyboard adapter mode of operation, 0 for XT, 1 for AT (default is AT). - Format: + Format: - parport=0 [HW,PPT] Specify parallel ports. 0 disables. - parport=auto Use 'auto' to force the driver to use - parport=0xBBB[,IRQ[,DMA]] any IRQ/DMA settings detected (the - default is to ignore detected IRQ/DMA - settings because of possible - conflicts). You can specify the base - address, IRQ, and DMA settings; IRQ and - DMA should be numbers, or 'auto' (for - using detected settings on that - particular port), or 'nofifo' (to avoid - using a FIFO even if it is detected). - Parallel ports are assigned in the - order they are specified on the command - line, starting with parport0. + parport= [HW,PPT] Specify parallel ports. 0 disables. + Format: { 0 | auto | 0xBBB[,IRQ[,DMA]] } + Use 'auto' to force the driver to use any + IRQ/DMA settings detected (the default is to + ignore detected IRQ/DMA settings because of + possible conflicts). You can specify the base + address, IRQ, and DMA settings; IRQ and DMA + should be numbers, or 'auto' (for using detected + settings on that particular port), or 'nofifo' + (to avoid using a FIFO even if it is detected). + Parallel ports are assigned in the order they + are specified on the command line, starting + with parport0. - parport_init_mode= - [HW,PPT] Configure VIA parallel port to - operate in specific mode. This is - necessary on Pegasos computer where - firmware has no options for setting up - parallel port mode and sets it to - spp. Currently this function knows - 686a and 8231 chips. + parport_init_mode= [HW,PPT] + Configure VIA parallel port to operate in + a specific mode. This is necessary on Pegasos + computer where firmware has no options for setting + up parallel port mode and sets it to spp. + Currently this function knows 686a and 8231 chips. Format: [spp|ps2|epp|ecp|ecpepp] - pas2= [HW,OSS] - Format: ,,,,,,, - + pas2= [HW,OSS] Format: + ,,,,,,, + pas16= [HW,SCSI] See header of drivers/scsi/pas16.c. @@ -1032,64 +1045,67 @@ running once the system is up. See header of drivers/block/paride/pcd.c. See also Documentation/paride.txt. - pci=option[,option...] [PCI] various PCI subsystem options: - off [IA-32] don't probe for the PCI bus - bios [IA-32] force use of PCI BIOS, don't access - the hardware directly. Use this if your machine - has a non-standard PCI host bridge. - nobios [IA-32] disallow use of PCI BIOS, only direct - hardware access methods are allowed. Use this - if you experience crashes upon bootup and you - suspect they are caused by the BIOS. - conf1 [IA-32] Force use of PCI Configuration Mechanism 1. - conf2 [IA-32] Force use of PCI Configuration Mechanism 2. - nosort [IA-32] Don't sort PCI devices according to - order given by the PCI BIOS. This sorting is done - to get a device order compatible with older kernels. - biosirq [IA-32] Use PCI BIOS calls to get the interrupt - routing table. These calls are known to be buggy - on several machines and they hang the machine when used, - but on other computers it's the only way to get the - interrupt routing table. Try this option if the kernel - is unable to allocate IRQs or discover secondary PCI - buses on your motherboard. - rom [IA-32] Assign address space to expansion ROMs. - Use with caution as certain devices share address - decoders between ROMs and other resources. - irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned - automatically to PCI devices. You can make the kernel - exclude IRQs of your ISA cards this way. + pci=option[,option...] [PCI] various PCI subsystem options: + off [IA-32] don't probe for the PCI bus + bios [IA-32] force use of PCI BIOS, don't access + the hardware directly. Use this if your machine + has a non-standard PCI host bridge. + nobios [IA-32] disallow use of PCI BIOS, only direct + hardware access methods are allowed. Use this + if you experience crashes upon bootup and you + suspect they are caused by the BIOS. + conf1 [IA-32] Force use of PCI Configuration + Mechanism 1. + conf2 [IA-32] Force use of PCI Configuration + Mechanism 2. + nosort [IA-32] Don't sort PCI devices according to + order given by the PCI BIOS. This sorting is + done to get a device order compatible with + older kernels. + biosirq [IA-32] Use PCI BIOS calls to get the interrupt + routing table. These calls are known to be buggy + on several machines and they hang the machine + when used, but on other computers it's the only + way to get the interrupt routing table. Try + this option if the kernel is unable to allocate + IRQs or discover secondary PCI buses on your + motherboard. + rom [IA-32] Assign address space to expansion ROMs. + Use with caution as certain devices share + address decoders between ROMs and other + resources. + irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be + assigned automatically to PCI devices. You can + make the kernel exclude IRQs of your ISA cards + this way. pirqaddr=0xAAAAA [IA-32] Specify the physical address - of the PIRQ table (normally generated - by the BIOS) if it is outside the - F0000h-100000h range. - lastbus=N [IA-32] Scan all buses till bus #N. Can be useful - if the kernel is unable to find your secondary buses - and you want to tell it explicitly which ones they are. - assign-busses [IA-32] Always assign all PCI bus - numbers ourselves, overriding - whatever the firmware may have - done. - usepirqmask [IA-32] Honor the possible IRQ mask - stored in the BIOS $PIR table. This is - needed on some systems with broken - BIOSes, notably some HP Pavilion N5400 - and Omnibook XE3 notebooks. This will - have no effect if ACPI IRQ routing is - enabled. - noacpi [IA-32] Do not use ACPI for IRQ routing - or for PCI scanning. - routeirq Do IRQ routing for all PCI devices. - This is normally done in pci_enable_device(), - so this option is a temporary workaround - for broken drivers that don't call it. - - firmware [ARM] Do not re-enumerate the bus but - instead just use the configuration - from the bootloader. This is currently - used on IXP2000 systems where the - bus has to be configured a certain way - for adjunct CPUs. + of the PIRQ table (normally generated + by the BIOS) if it is outside the + F0000h-100000h range. + lastbus=N [IA-32] Scan all buses thru bus #N. Can be + useful if the kernel is unable to find your + secondary buses and you want to tell it + explicitly which ones they are. + assign-busses [IA-32] Always assign all PCI bus + numbers ourselves, overriding + whatever the firmware may have done. + usepirqmask [IA-32] Honor the possible IRQ mask stored + in the BIOS $PIR table. This is needed on + some systems with broken BIOSes, notably + some HP Pavilion N5400 and Omnibook XE3 + notebooks. This will have no effect if ACPI + IRQ routing is enabled. + noacpi [IA-32] Do not use ACPI for IRQ routing + or for PCI scanning. + routeirq Do IRQ routing for all PCI devices. + This is normally done in pci_enable_device(), + so this option is a temporary workaround + for broken drivers that don't call it. + firmware [ARM] Do not re-enumerate the bus but instead + just use the configuration from the + bootloader. This is currently used on + IXP2000 systems where the bus has to be + configured a certain way for adjunct CPUs. pcmv= [HW,PCMCIA] BadgePAD 4 @@ -1127,19 +1143,20 @@ running once the system is up. [ISAPNP] Exclude DMAs for the autoconfiguration pnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration - Ranges are in pairs (I/O port base and size). + Ranges are in pairs (I/O port base and size). pnp_reserve_mem= - [ISAPNP] Exclude memory regions for the autoconfiguration + [ISAPNP] Exclude memory regions for the + autoconfiguration. Ranges are in pairs (memory base and size). profile= [KNL] Enable kernel profiling via /proc/profile - { schedule | } - (param: schedule - profile schedule points} - (param: profile step/bucket size as a power of 2 for - statistical time based profiling) + Format: [schedule,] + Param: "schedule" - profile schedule points. + Param: - step/bucket size as a power of 2 for + statistical time based profiling. - processor.max_cstate= [HW, ACPI] + processor.max_cstate= [HW,ACPI] Limit processor to maximum C-state max_cstate=9 overrides any DMI blacklist limit. @@ -1147,27 +1164,28 @@ running once the system is up. before loading. See Documentation/ramdisk.txt. - psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to - probe for (bare|imps|exps|lifebook|any). + psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to + probe for; one of (bare|imps|exps|lifebook|any). psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports per second. - psmouse.resetafter= - [HW,MOUSE] Try to reset the device after so many bad packets + psmouse.resetafter= [HW,MOUSE] + Try to reset the device after so many bad packets (0 = never). psmouse.resolution= [HW,MOUSE] Set desired mouse resolution, in dpi. psmouse.smartscroll= - [HW,MOUSE] Controls Logitech smartscroll autorepeat, + [HW,MOUSE] Controls Logitech smartscroll autorepeat. 0 = disabled, 1 = enabled (default). pss= [HW,OSS] Personal Sound System (ECHO ESC614) - Format: ,,,,, + Format: + ,,,,, pt. [PARIDE] See Documentation/paride.txt. quiet= [KNL] Disable log messages - + r128= [HW,DRM] raid= [HW,RAID] @@ -1176,10 +1194,9 @@ running once the system is up. ramdisk= [RAM] Sizes of RAM disks in kilobytes [deprecated] See Documentation/ramdisk.txt. - ramdisk_blocksize= - [RAM] + ramdisk_blocksize= [RAM] See Documentation/ramdisk.txt. - + ramdisk_size= [RAM] Sizes of RAM disks in kilobytes New name for the ramdisk parameter. See Documentation/ramdisk.txt. @@ -1195,7 +1212,8 @@ running once the system is up. reserve= [KNL,BUGS] Force the kernel to ignore some iomem area - resume= [SWSUSP] Specify the partition device for software suspension + resume= [SWSUSP] + Specify the partition device for software suspend rhash_entries= [KNL,NET] Set number of hash buckets for route cache @@ -1225,7 +1243,7 @@ running once the system is up. Format: ,,, sbni= [NET] Granch SBNI12 leased line adapter - + sbpcd= [HW,CD] Soundblaster CD adapter Format: , See a comment before function sbpcd_setup() in @@ -1258,21 +1276,20 @@ running once the system is up. serialnumber [BUGS=IA-32] - sg_def_reserved_size= - [SCSI] - + sg_def_reserved_size= [SCSI] + sgalaxy= [HW,OSS] Format: ,,,, shapers= [NET] Maximal number of shapers. - + sim710= [SCSI,HW] See header of drivers/scsi/sim710.c. simeth= [IA-64] simscsi= - + sjcd= [HW,CD] Format: ,, See header of drivers/cdrom/sjcd.c. @@ -1403,10 +1420,10 @@ running once the system is up. snd-wavefront= [HW,ALSA] snd-ymfpci= [HW,ALSA] - + sonicvibes= [HW,OSS] Format: - + sonycd535= [HW,CD] Format: [,] @@ -1423,7 +1440,7 @@ running once the system is up. sscape= [HW,OSS] Format: ,,,, - + st= [HW,SCSI] SCSI tape parameters (buffers, etc.) See Documentation/scsi/st.txt. @@ -1446,7 +1463,7 @@ running once the system is up. stram_swap= [HW,M68k] swiotlb= [IA-64] Number of I/O TLB slabs - + switches= [HW,M68k] sym53c416= [HW,SCSI] @@ -1479,14 +1496,16 @@ running once the system is up. tp720= [HW,PS2] trix= [HW,OSS] MediaTrix AudioTrix Pro - Format: ,,,,,,,, - + Format: + ,,,,,,,, + tsdev.xres= [TS] Horizontal screen resolution. tsdev.yres= [TS] Vertical screen resolution. - turbografx.map[2|3]= - [HW,JOY] TurboGraFX parallel port interface - Format: ,,,,,,, + turbografx.map[2|3]= [HW,JOY] + TurboGraFX parallel port interface + Format: + ,,,,,,, See also Documentation/input/joystick-parport.txt u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter @@ -1502,17 +1521,18 @@ running once the system is up. usbhid.mousepoll= [USBHID] The interval which mice are to be polled at. - + video= [FB] Frame buffer configuration See Documentation/fb/modedb.txt. vga= [BOOT,IA-32] Select a particular video mode - See Documentation/i386/boot.txt and Documentation/svga.txt. + See Documentation/i386/boot.txt and + Documentation/svga.txt. Use vga=ask for menu. This is actually a boot loader parameter; the value is passed to the kernel using a special protocol. - vmalloc=nn[KMG] [KNL,BOOT] forces the vmalloc area to have an exact + vmalloc=nn[KMG] [KNL,BOOT] Forces the vmalloc area to have an exact size of . This can be used to increase the minimum size (128MB on x86). It can also be used to decrease the size and leave more room for directly @@ -1520,11 +1540,11 @@ running once the system is up. vmhalt= [KNL,S390] - vmpoff= [KNL,S390] - + vmpoff= [KNL,S390] + waveartist= [HW,OSS] Format: ,,, - + wd33c93= [HW,SCSI] See header of drivers/scsi/wd33c93.c. @@ -1538,21 +1558,25 @@ running once the system is up. xd_geo= See header of drivers/block/xd.c. xirc2ps_cs= [NET,PCMCIA] - Format: ,,,,,[,[,[,]]] - + Format: + ,,,,,[,[,[,]]] +______________________________________________________________________ Changelog: +2000-06-?? Mr. Unknown The last known update (for 2.4.0) - the changelog was not kept before. - 2000-06-?? Mr. Unknown +2002-11-24 Petr Baudis + Randy Dunlap Update for 2.5.49, description for most of the options introduced, references to other documentation (C files, READMEs, ..), added S390, PPC, SPARC, MTD, ALSA and OSS category. Minor corrections and reformatting. - 2002-11-24 Petr Baudis - Randy Dunlap + +2005-10-19 Randy Dunlap + Lots of typos, whitespace, some reformatting. TODO: From 8766ce41018a0cb80fbe0ce7dbf747f357c752da Mon Sep 17 00:00:00 2001 From: Kostik Belousov Date: Sun, 23 Oct 2005 12:57:13 -0700 Subject: [PATCH 0652/1939] [PATCH] aio syscalls are not checked by lsm Another case of missing call to security_file_permission: aio functions (namely, io_submit) does not check credentials with security modules. Below is the simple patch to the problem. It seems that it is enough to check for rights at the request submission time. Signed-off-by: Kostik Belousov Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/aio.c b/fs/aio.c index 9fe7216457d8..edfca5b75535 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1397,6 +1397,9 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf, kiocb->ki_left))) break; + ret = security_file_permission(file, MAY_READ); + if (unlikely(ret)) + break; ret = -EINVAL; if (file->f_op->aio_read) kiocb->ki_retry = aio_pread; @@ -1409,6 +1412,9 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf, kiocb->ki_left))) break; + ret = security_file_permission(file, MAY_WRITE); + if (unlikely(ret)) + break; ret = -EINVAL; if (file->f_op->aio_write) kiocb->ki_retry = aio_pwrite; From 282c1f5eba150d0b156ffa9e6b064f1d92f8315f Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Sun, 23 Oct 2005 12:57:15 -0700 Subject: [PATCH 0653/1939] [PATCH] selinux: Fix NULL deref in policydb_destroy This patch fixes a possible NULL dereference in policydb_destroy, where p->type_attr_map can be NULL if policydb_destroy is called to clean up a partially loaded policy upon an error during policy load. Please apply. Signed-off-by: Stephen Smalley Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/ss/policydb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 0a758323a9cf..8e6262d12aa9 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -650,8 +650,10 @@ void policydb_destroy(struct policydb *p) } if (lrt) kfree(lrt); - for (i = 0; i < p->p_types.nprim; i++) - ebitmap_destroy(&p->type_attr_map[i]); + if (p->type_attr_map) { + for (i = 0; i < p->p_types.nprim; i++) + ebitmap_destroy(&p->type_attr_map[i]); + } kfree(p->type_attr_map); return; From 20c19e4179884d7e843314071e2dfb1ea7b0afcd Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Sun, 23 Oct 2005 12:57:16 -0700 Subject: [PATCH 0654/1939] [PATCH] SELinux: handle sel_make_bools() failure in selinuxfs This patch fixes error handling in sel_make_bools(), where currently we'd get a memory leak via security_get_bools() and try to kfree() the wrong pointer if called again. Signed-off-by: James Morris Acked-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/selinuxfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 8eb140dd2e4b..a45cc971e735 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -879,7 +879,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, if (sscanf(page, "%d", &new_value) != 1) goto out; - if (new_value) { + if (new_value && bool_pending_values) { security_set_bools(bool_num, bool_pending_values); } @@ -952,6 +952,7 @@ static int sel_make_bools(void) /* remove any existing files */ kfree(bool_pending_values); + bool_pending_values = NULL; sel_remove_bools(dir); @@ -1002,6 +1003,7 @@ static int sel_make_bools(void) } return ret; err: + kfree(values); d_genocide(dir); ret = -ENOMEM; goto out; From c0fef676bbd75e711711ed3ff5bebb7bfd1bdb00 Mon Sep 17 00:00:00 2001 From: Mike Krufky Date: Sun, 23 Oct 2005 12:57:17 -0700 Subject: [PATCH 0655/1939] [PATCH] Kconfig: saa7134-dvb should not select cx22702 On 2005-05-01, Gerd Knorr sent in a patch to add cx22702 to cx88-dvb: [PATCH] dvb: cx22702 frontend driver update http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9990d744bea7d28e83c420e2c9d524c7a8a2d136 ...but as we can see, the Kconfig portion of his patch was incorrectly applied to saa7134-dvb instead of cx88-dvb. On 2005-06-24, Adrian bunk fixed cx88-dvb: [PATCH] VIDEO_CX88_DVB must select DVB_CX22702 http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d6988588e13616587aa879c2e0bd7cd811705e5d ...but we never removed the original patch from Gerd. This patch sets things straight: saa7134-dvb should not select cx22702 Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 93570355819a..bbb989df4cf0 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -262,7 +262,6 @@ config VIDEO_SAA7134_DVB depends on VIDEO_SAA7134 && DVB_CORE select VIDEO_BUF_DVB select DVB_MT352 - select DVB_CX22702 select DVB_TDA1004X ---help--- This adds support for DVB cards based on the From 8d3b35914aa54232b27e6a2b57d84092aadc5e86 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 23 Oct 2005 12:57:18 -0700 Subject: [PATCH 0656/1939] [PATCH] inotify/idr leak fix Fix a bug which was reported and diagnosed by Stefan Jones IDR trees include a cache of idr_layer objects. There's no way to destroy this cache, so when we discard an overall idr tree we end up leaking some memory. Add and use idr_destroy() for this. v9fs and infiniband also need to use idr_destroy() to avoid leaks. Or, we make the cache global, like radix_tree_preload(). Which is probably better. Later. Cc: Eric Van Hensbergen Cc: Roland Dreier Cc: Robert Love Cc: John McCutchan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inotify.c | 1 + include/linux/idr.h | 1 + lib/idr.c | 13 +++++++++++++ 3 files changed, 15 insertions(+) diff --git a/fs/inotify.c b/fs/inotify.c index a37e9fb1da58..9fbaebfdf40b 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -176,6 +176,7 @@ static inline void put_inotify_dev(struct inotify_device *dev) if (atomic_dec_and_test(&dev->count)) { atomic_dec(&dev->user->inotify_devs); free_uid(dev->user); + idr_destroy(&dev->idr); kfree(dev); } } diff --git a/include/linux/idr.h b/include/linux/idr.h index ca3b7e462576..3d5de45f961b 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -75,4 +75,5 @@ int idr_pre_get(struct idr *idp, unsigned gfp_mask); int idr_get_new(struct idr *idp, void *ptr, int *id); int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); void idr_remove(struct idr *idp, int id); +void idr_destroy(struct idr *idp); void idr_init(struct idr *idp); diff --git a/lib/idr.c b/lib/idr.c index 6415d053e2bf..d4df21debc4d 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -345,6 +345,19 @@ void idr_remove(struct idr *idp, int id) } EXPORT_SYMBOL(idr_remove); +/** + * idr_destroy - release all cached layers within an idr tree + * idp: idr handle + */ +void idr_destroy(struct idr *idp) +{ + while (idp->id_free_cnt) { + struct idr_layer *p = alloc_layer(idp); + kmem_cache_free(idr_layer_cache, p); + } +} +EXPORT_SYMBOL(idr_destroy); + /** * idr_find - return pointer for given id * @idp: idr handle From 75eeec2f3fd9e8a16777219ebf1bf8395845faa7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sun, 23 Oct 2005 12:57:19 -0700 Subject: [PATCH 0657/1939] [PATCH] ib: mthca: Always re-arm EQs in mthca_tavor_interrupt() We should always re-arm an event queue's interrupt in mthca_tavor_interrupt() if the corresponding bit is set in the event cause register (ECR), even if we didn't find any entries in the EQ. If we don't, then there's a window where we miss an EQ entry and then get stuck because we don't get another EQ event. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_eq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index c81fa8e975ef..8dfafda5ed24 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -396,20 +396,21 @@ static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); ecr = readl(dev->eq_regs.tavor.ecr_base + 4); - if (ecr) { - writel(ecr, dev->eq_regs.tavor.ecr_base + - MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + if (!ecr) + return IRQ_NONE; - for (i = 0; i < MTHCA_NUM_EQ; ++i) - if (ecr & dev->eq_table.eq[i].eqn_mask && - mthca_eq_int(dev, &dev->eq_table.eq[i])) { + writel(ecr, dev->eq_regs.tavor.ecr_base + + MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (ecr & dev->eq_table.eq[i].eqn_mask) { + if (mthca_eq_int(dev, &dev->eq_table.eq[i])) tavor_set_eq_ci(dev, &dev->eq_table.eq[i], dev->eq_table.eq[i].cons_index); - tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); - } - } + tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); + } - return IRQ_RETVAL(ecr); + return IRQ_HANDLED; } static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr, From 580460194e0e647d95cb5a2b66fdd7497b197f92 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 14:22:37 +1000 Subject: [PATCH 0658/1939] powerpc: Merge arch/ppc64/kernel/vio.c into arch/powerpc/kernel/vio.c Merge arch/ppc64/kernel/vio.c into arch/powerpc/kernel/vio.c, update the Makefiles to make it work, and make ARCH=ppc64 still work. Michael's version put vio.c in arch/powerpc/sysedv but after consolting Paulus, this one puts it in arch/powerpc/kernel. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 1 + arch/{ppc64 => powerpc}/kernel/vio.c | 0 arch/ppc64/kernel/Makefile | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename arch/{ppc64 => powerpc}/kernel/vio.c (100%) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 6b0f176265e3..f5d8038fed52 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o +obj-$(CONFIG_IBMVIO) += vio.o ifeq ($(CONFIG_PPC_MERGE),y) diff --git a/arch/ppc64/kernel/vio.c b/arch/powerpc/kernel/vio.c similarity index 100% rename from arch/ppc64/kernel/vio.c rename to arch/powerpc/kernel/vio.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 424dd250cd87..ce5c99db431f 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -53,7 +53,6 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o endif obj-$(CONFIG_HVCS) += hvcserver.o -obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_PPC_PMAC) += udbg_scc.o From f38d87f566195d78bd70538d5c774758f2d926d3 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 14:32:35 +1000 Subject: [PATCH 0659/1939] powerpc: Move include/asm-ppc64/vio.h to include/asm-powerpc/vio.h Move include/asm-ppc64/vio.h to include/asm-powerpc/vio.h, that's it. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- include/{asm-ppc64 => asm-powerpc}/vio.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/vio.h (84%) diff --git a/include/asm-ppc64/vio.h b/include/asm-powerpc/vio.h similarity index 84% rename from include/asm-ppc64/vio.h rename to include/asm-powerpc/vio.h index 03f1b95f433b..f10f72f24fde 100644 --- a/include/asm-ppc64/vio.h +++ b/include/asm-powerpc/vio.h @@ -1,18 +1,18 @@ /* * IBM PowerPC Virtual I/O Infrastructure Support. * - * Copyright (c) 2003 IBM Corp. - * Dave Engebretsen engebret@us.ibm.com - * Santiago Leon santil@us.ibm.com + * Copyright (c) 2003 IBM Corp. + * Dave Engebretsen engebret@us.ibm.com + * Santiago Leon santil@us.ibm.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 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_VIO_H -#define _ASM_VIO_H +#ifndef _ASM_POWERPC_VIO_H +#define _ASM_POWERPC_VIO_H #include #include @@ -103,4 +103,4 @@ static inline struct vio_dev *to_vio_dev(struct device *dev) return container_of(dev, struct vio_dev, dev); } -#endif /* _ASM_VIO_H */ +#endif /* _ASM_POWERPC_VIO_H */ From 6fdf5392caa4c3cba65add0a4beec9f5eb96b723 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 14:53:21 +1000 Subject: [PATCH 0660/1939] powerpc: don't duplicate name between vio_driver and device_driver Just set the name field directly in the device_driver structure contained in the vio_driver struct. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/vio.c | 3 +-- drivers/block/viodasd.c | 6 ++++-- drivers/cdrom/viocd.c | 6 ++++-- drivers/char/hvc_vio.c | 2 +- drivers/char/hvcs.c | 4 +++- drivers/char/viotape.c | 6 ++++-- drivers/net/ibmveth.c | 10 ++++++---- drivers/net/iseries_veth.c | 6 ++++-- drivers/scsi/ibmvscsi/ibmvscsi.c | 6 ++++-- include/asm-powerpc/vio.h | 1 - 10 files changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 0e555b7a6587..3aec492ec767 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -76,10 +76,9 @@ static int vio_bus_remove(struct device *dev) int vio_register_driver(struct vio_driver *viodrv) { printk(KERN_DEBUG "%s: driver %s registering\n", __FUNCTION__, - viodrv->name); + viodrv->driver.name); /* fill in 'struct driver' fields */ - viodrv->driver.name = viodrv->name; viodrv->driver.bus = &vio_bus_type; viodrv->driver.probe = vio_bus_probe; viodrv->driver.remove = vio_bus_remove; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index e46ecd23b3ac..ea72faa83436 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -781,10 +781,12 @@ static struct vio_device_id viodasd_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, viodasd_device_table); static struct vio_driver viodasd_driver = { - .name = "viodasd", .id_table = viodasd_device_table, .probe = viodasd_probe, - .remove = viodasd_remove + .remove = viodasd_remove, + .driver = { + .name = "viodasd", + } }; /* diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 0829db58462f..255d24ad704b 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -739,10 +739,12 @@ static struct vio_device_id viocd_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, viocd_device_table); static struct vio_driver viocd_driver = { - .name = "viocd", .id_table = viocd_device_table, .probe = viocd_probe, - .remove = viocd_remove + .remove = viocd_remove, + .driver = { + .name = "viocd", + } }; static int __init viocd_init(void) diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 78d681dc35a8..f5212eb2b41d 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -95,11 +95,11 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev) } static struct vio_driver hvc_vio_driver = { - .name = hvc_driver_name, .id_table = hvc_driver_table, .probe = hvc_vio_probe, .remove = hvc_vio_remove, .driver = { + .name = hvc_driver_name, .owner = THIS_MODULE, } }; diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index f47f009f9259..8486298c011f 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -720,10 +720,12 @@ static int __devexit hvcs_remove(struct vio_dev *dev) }; static struct vio_driver hvcs_vio_driver = { - .name = hvcs_driver_name, .id_table = hvcs_driver_table, .probe = hvcs_probe, .remove = hvcs_remove, + .driver = { + .name = hvcs_driver_name, + } }; /* Only called from hvcs_get_pi please */ diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 0aff45fac2e6..8fc1115c4b69 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -996,10 +996,12 @@ static struct vio_device_id viotape_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, viotape_device_table); static struct vio_driver viotape_driver = { - .name = "viotape", .id_table = viotape_device_table, .probe = viotape_probe, - .remove = viotape_remove + .remove = viotape_remove, + .driver = { + .name = "viotape", + } }; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index a2c4dd4fb221..fcf6f2c76300 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1150,10 +1150,12 @@ static struct vio_device_id ibmveth_device_table[] __devinitdata= { MODULE_DEVICE_TABLE(vio, ibmveth_device_table); static struct vio_driver ibmveth_driver = { - .name = (char *)ibmveth_driver_name, - .id_table = ibmveth_device_table, - .probe = ibmveth_probe, - .remove = ibmveth_remove + .id_table = ibmveth_device_table, + .probe = ibmveth_probe, + .remove = ibmveth_remove, + .driver = { + .name = ibmveth_driver_name, + } }; static int __init ibmveth_module_init(void) diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index db3bc2f6f0fa..33613fe9556c 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1648,10 +1648,12 @@ static struct vio_device_id veth_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, veth_device_table); static struct vio_driver veth_driver = { - .name = DRV_NAME, .id_table = veth_device_table, .probe = veth_probe, - .remove = veth_remove + .remove = veth_remove, + .driver = { + .name = DRV_NAME, + } }; /* diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index ff25210b00ba..965e5373538c 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1546,10 +1546,12 @@ static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table); static struct vio_driver ibmvscsi_driver = { - .name = "ibmvscsi", .id_table = ibmvscsi_device_table, .probe = ibmvscsi_probe, - .remove = ibmvscsi_remove + .remove = ibmvscsi_remove, + .driver = { + .name = "ibmvscsi", + } }; int __init ibmvscsi_module_init(void) diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index f10f72f24fde..104c58501d0c 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -55,7 +55,6 @@ struct vio_dev { struct vio_driver { struct list_head node; - char *name; const struct vio_device_id *id_table; int (*probe)(struct vio_dev *dev, const struct vio_device_id *id); int (*remove)(struct vio_dev *dev); From 7c7eb28481a038c3859a0efcf38ac5b642aca212 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 15:21:52 +1000 Subject: [PATCH 0661/1939] powerpc: iseries: Fix a bogus comment A comment in lpevents.c refers to code that's actually in HvCallEvent.h. The code in HvCallEvent.h is pretty obvious, so just remove the comment altogether. Signed-off-by: Michael Ellerman Acked-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/lpevents.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index f8b4155b0481..54c7753dbe05 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -184,11 +184,7 @@ void setup_hvlpevent_queue(void) { void *eventStack; - /* - * Allocate a page for the Event Stack. The Hypervisor needs the - * absolute real address, so we subtract out the KERNELBASE and add - * in the absolute real address of the kernel load area. - */ + /* Allocate a page for the Event Stack. */ eventStack = alloc_bootmem_pages(LpEventStackSize); memset(eventStack, 0, LpEventStackSize); From 915124d8114ec8c3825b10a39151bf9e851593bb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 15:12:22 +1000 Subject: [PATCH 0662/1939] powerpc: set the driver.owner field for all vio drivers Signed-off-by: Stephen Rothwell --- drivers/block/viodasd.c | 3 ++- drivers/cdrom/viocd.c | 3 ++- drivers/char/hvcs.c | 1 + drivers/char/viotape.c | 3 ++- drivers/net/ibmveth.c | 2 +- drivers/net/iseries_veth.c | 1 + drivers/scsi/ibmvscsi/ibmvscsi.c | 3 ++- 7 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index ea72faa83436..709f809f79f1 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -778,14 +778,15 @@ static struct vio_device_id viodasd_device_table[] __devinitdata = { { "viodasd", "" }, { "", "" } }; - MODULE_DEVICE_TABLE(vio, viodasd_device_table); + static struct vio_driver viodasd_driver = { .id_table = viodasd_device_table, .probe = viodasd_probe, .remove = viodasd_remove, .driver = { .name = "viodasd", + .owner = THIS_MODULE, } }; diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 255d24ad704b..36f31d202223 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -736,14 +736,15 @@ static struct vio_device_id viocd_device_table[] __devinitdata = { { "viocd", "" }, { "", "" } }; - MODULE_DEVICE_TABLE(vio, viocd_device_table); + static struct vio_driver viocd_driver = { .id_table = viocd_device_table, .probe = viocd_probe, .remove = viocd_remove, .driver = { .name = "viocd", + .owner = THIS_MODULE, } }; diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8486298c011f..53dc77c760fc 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -725,6 +725,7 @@ static struct vio_driver hvcs_vio_driver = { .remove = hvcs_remove, .driver = { .name = hvcs_driver_name, + .owner = THIS_MODULE, } }; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 8fc1115c4b69..d92a05645007 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -993,14 +993,15 @@ static struct vio_device_id viotape_device_table[] __devinitdata = { { "viotape", "" }, { "", "" } }; - MODULE_DEVICE_TABLE(vio, viotape_device_table); + static struct vio_driver viotape_driver = { .id_table = viotape_device_table, .probe = viotape_probe, .remove = viotape_remove, .driver = { .name = "viotape", + .owner = THIS_MODULE, } }; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index fcf6f2c76300..f5dc632452f1 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1146,7 +1146,6 @@ static struct vio_device_id ibmveth_device_table[] __devinitdata= { { "network", "IBM,l-lan"}, { "", "" } }; - MODULE_DEVICE_TABLE(vio, ibmveth_device_table); static struct vio_driver ibmveth_driver = { @@ -1155,6 +1154,7 @@ static struct vio_driver ibmveth_driver = { .remove = ibmveth_remove, .driver = { .name = ibmveth_driver_name, + .owner = THIS_MODULE, } }; diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 33613fe9556c..f5ea39ff1017 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1653,6 +1653,7 @@ static struct vio_driver veth_driver = { .remove = veth_remove, .driver = { .name = DRV_NAME, + .owner = THIS_MODULE, } }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 965e5373538c..822b9fa706f3 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1543,14 +1543,15 @@ static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { {"vscsi", "IBM,v-scsi"}, { "", "" } }; - MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table); + static struct vio_driver ibmvscsi_driver = { .id_table = ibmvscsi_device_table, .probe = ibmvscsi_probe, .remove = ibmvscsi_remove, .driver = { .name = "ibmvscsi", + .owner = THIS_MODULE, } }; From 340601043df518d6f4f82da285c60c785ac8a716 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 24 Oct 2005 17:40:23 +1000 Subject: [PATCH 0663/1939] powerpc: Add a shutdown member to vio_driver Add a shutdown member to struct vio_driver. We also need vio_bus_shutdown() which converts from struct device to struct vio_dev and knows how to extract the struct vio_driver. Original patch adjusted for different location of vio.c. Signed-off-by: Michael Ellerman Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/vio.c | 11 +++++++++++ include/asm-powerpc/vio.h | 1 + 2 files changed, 12 insertions(+) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 3aec492ec767..97082a4203ad 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -69,6 +69,16 @@ static int vio_bus_remove(struct device *dev) return 1; } +/* convert from struct device to struct vio_dev and pass to driver. */ +static void vio_bus_shutdown(struct device *dev) +{ + struct vio_dev *viodev = to_vio_dev(dev); + struct vio_driver *viodrv = to_vio_driver(dev->driver); + + if (viodrv->shutdown) + viodrv->shutdown(viodev); +} + /** * vio_register_driver: - Register a new vio driver * @drv: The vio_driver structure to be registered. @@ -82,6 +92,7 @@ int vio_register_driver(struct vio_driver *viodrv) viodrv->driver.bus = &vio_bus_type; viodrv->driver.probe = vio_bus_probe; viodrv->driver.remove = vio_bus_remove; + viodrv->driver.shutdown = vio_bus_shutdown; return driver_register(&viodrv->driver); } diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 104c58501d0c..e0ccf108277c 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -58,6 +58,7 @@ struct vio_driver { const struct vio_device_id *id_table; int (*probe)(struct vio_dev *dev, const struct vio_device_id *id); int (*remove)(struct vio_dev *dev); + void (*shutdown)(struct vio_dev *dev); unsigned long driver_data; struct device_driver driver; }; From d04bd1fb60252f30f4f41a56613ade48df130588 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Mon, 24 Oct 2005 08:41:24 +0100 Subject: [PATCH 0664/1939] NTFS: Use %z for size_t to fix compilation warnings. (Andrew Morton) Signed-off-by: Andrew Morton Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 3 ++- fs/ntfs/file.c | 4 ++-- fs/ntfs/super.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index bc6ec16ad1f8..2a76b1fbbfc0 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -75,7 +75,8 @@ ToDo/Notes: for highly fragmented files, i.e. ones whose data attribute is split across multiple extents. When such a case is encountered, EOPNOTSUPP is returned. - - $EA attributes can be both resident non-resident. + - $EA attributes can be both resident and non-resident. + - Use %z for size_t to fix compilation warnings. (Andrew Morton) 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index a142bf3ba1a5..cdedc84e1372 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -531,7 +531,7 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ni = NTFS_I(vi); vol = ni->vol; ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " - "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%x.", + "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", vi->i_ino, ni->type, pages[0]->index, nr_pages, (long long)pos, bytes); blocksize_bits = vi->i_blkbits; @@ -1693,7 +1693,7 @@ static int ntfs_commit_pages_after_write(struct page **pages, vi = page->mapping->host; ni = NTFS_I(vi); ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " - "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%x.", + "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", vi->i_ino, ni->type, page->index, nr_pages, (long long)pos, bytes); if (NInoNonResident(ni)) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 453d0d51ea4b..6c16db9e1a8a 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1447,7 +1447,7 @@ static BOOL load_and_init_usnjrnl(ntfs_volume *vol) if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) { ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max " "attribute (size is 0x%llx but should be at " - "least 0x%x bytes).", i_size_read(tmp_ino), + "least 0x%zx bytes).", i_size_read(tmp_ino), sizeof(USN_HEADER)); return FALSE; } From dda65b941f992ab10fda3d9f09539c68206b7114 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Mon, 24 Oct 2005 08:57:59 +0100 Subject: [PATCH 0665/1939] NTFS: Fix compilation warnings with gcc-4.0.2 on SUSE 10.0. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 1 + fs/ntfs/attrib.c | 2 +- fs/ntfs/file.c | 23 ++++++++--------------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 2a76b1fbbfc0..dea742405161 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -77,6 +77,7 @@ ToDo/Notes: EOPNOTSUPP is returned. - $EA attributes can be both resident and non-resident. - Use %z for size_t to fix compilation warnings. (Andrew Morton) + - Fix compilation warnings with gcc-4.0.2 on SUSE 10.0. 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index df2e2091f936..eda056bac256 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -91,7 +91,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx) struct page *put_this_page = NULL; int err = 0; BOOL ctx_is_temporary, ctx_needs_reset; - ntfs_attr_search_ctx old_ctx; + ntfs_attr_search_ctx old_ctx = { NULL, }; ntfs_debug("Mapping runlist part containing vcn 0x%llx.", (unsigned long long)vcn); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index cdedc84e1372..cf3e6ced2d01 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -78,12 +78,8 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) * Extend the initialized size of an attribute described by the ntfs inode @ni * to @new_init_size bytes. This involves zeroing any non-sparse space between * the old initialized size and @new_init_size both in the page cache and on - * disk (if relevant complete pages are zeroed in the page cache then these may - * simply be marked dirty for later writeout). There is one caveat and that is - * that if any uptodate page cache pages between the old initialized size and - * the smaller of @new_init_size and the file size (vfs inode->i_size) are in - * memory, these need to be marked dirty without being zeroed since they could - * be non-zero due to mmap() based writes. + * disk (if relevant complete pages are already uptodate in the page cache then + * these are simply marked dirty). * * As a side-effect, the file size (vfs inode->i_size) may be incremented as, * in the resident attribute case, it is tied to the initialized size and, in @@ -98,10 +94,10 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) * with new data via mmap() based writes, so we cannot just zero it. And since * POSIX specifies that the behaviour of resizing a file whilst it is mmap()ped * is unspecified, we choose not to do zeroing and thus we do not need to touch - * the page at all. For a more detailed explanation see ntfs_truncate() which - * is in fs/ntfs/inode.c. + * the page at all. For a more detailed explanation see ntfs_truncate() in + * fs/ntfs/inode.c. * - * @cached_page and @lru_pvec are just optimisations for dealing with multiple + * @cached_page and @lru_pvec are just optimizations for dealing with multiple * pages. * * Return 0 on success and -errno on error. In the case that an error is @@ -110,9 +106,8 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) * this is the case, the necessary zeroing will also have happened and that all * metadata is self-consistent. * - * Locking: This function locks the mft record of the base ntfs inode and - * maintains the lock throughout execution of the function. This is required - * so that the initialized size of the attribute can be modified safely. + * Locking: i_sem on the vfs inode corrseponsind to the ntfs inode @ni must be + * held by the caller. */ static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size, struct page **cached_page, struct pagevec *lru_pvec) @@ -1836,7 +1831,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, VCN last_vcn; LCN lcn; unsigned long flags; - size_t bytes, iov_ofs; + size_t bytes, iov_ofs = 0; /* Offset in the current iovec. */ ssize_t status, written; unsigned nr_pages; int err; @@ -1988,8 +1983,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, last_vcn = -1; if (likely(nr_segs == 1)) buf = iov->iov_base; - else - iov_ofs = 0; /* Offset in the current iovec. */ do { VCN vcn; pgoff_t idx, start_idx; From c9c2009a4e915db17f32701d1f0535b400e61b58 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Mon, 24 Oct 2005 09:00:51 +0100 Subject: [PATCH 0666/1939] NTFS: Document extended attribute ($EA) NEED_EA flag. (Based on libntfs patch by Yura Pakhuchiy.) Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 2 ++ fs/ntfs/layout.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index dea742405161..50a7749cfca1 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -78,6 +78,8 @@ ToDo/Notes: - $EA attributes can be both resident and non-resident. - Use %z for size_t to fix compilation warnings. (Andrew Morton) - Fix compilation warnings with gcc-4.0.2 on SUSE 10.0. + - Document extended attribute ($EA) NEED_EA flag. (Based on libntfs + patch by Yura Pakhuchiy.) 2.1.24 - Lots of bug fixes and support more clean journal states. diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 71b25dab8199..f5678d5d7919 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -2374,7 +2374,9 @@ typedef struct { * Extended attribute flags (8-bit). */ enum { - NEED_EA = 0x80 + NEED_EA = 0x80 /* If set the file to which the EA belongs + cannot be interpreted without understanding + the associates extended attributes. */ } __attribute__ ((__packed__)); typedef u8 EA_FLAGS; From 108150ea78003044e41150c75259447b2c0953b6 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 23 Oct 2005 20:25:39 +0400 Subject: [PATCH 0667/1939] [PATCH] posix-timers: fix cleanup_timers() and run_posix_cpu_timers() races 1. cleanup_timers() sets timer->task = NULL under tasklist + ->sighand locks. That means that this code in posix_cpu_timer_del() and posix_cpu_timer_set() lock_timer(timer); if (timer->task == NULL) return; read_lock(tasklist); put_task_struct(timer->task) is racy. With this patch timer->task modified and accounted only under timer->it_lock. Sadly, this means that dead task_struct won't be freed until timer deleted or armed. 2. run_posix_cpu_timers() collects expired timers into local list under tasklist + ->sighand again. That means that posix_cpu_timer_del() should check timer->it.cpu.firing under these locks too. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index d30b304a3384..30ab39a27736 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -380,14 +380,9 @@ int posix_cpu_timer_create(struct k_itimer *new_timer) int posix_cpu_timer_del(struct k_itimer *timer) { struct task_struct *p = timer->it.cpu.task; + int ret = 0; - if (timer->it.cpu.firing) - return TIMER_RETRY; - - if (unlikely(p == NULL)) - return 0; - - if (!list_empty(&timer->it.cpu.entry)) { + if (likely(p != NULL)) { read_lock(&tasklist_lock); if (unlikely(p->signal == NULL)) { /* @@ -396,18 +391,20 @@ int posix_cpu_timer_del(struct k_itimer *timer) */ BUG_ON(!list_empty(&timer->it.cpu.entry)); } else { - /* - * Take us off the task's timer list. - */ spin_lock(&p->sighand->siglock); - list_del(&timer->it.cpu.entry); + if (timer->it.cpu.firing) + ret = TIMER_RETRY; + else + list_del(&timer->it.cpu.entry); spin_unlock(&p->sighand->siglock); } read_unlock(&tasklist_lock); - } - put_task_struct(p); - return 0; + if (!ret) + put_task_struct(p); + } + + return ret; } /* @@ -424,8 +421,6 @@ static void cleanup_timers(struct list_head *head, cputime_t ptime = cputime_add(utime, stime); list_for_each_entry_safe(timer, next, head, entry) { - put_task_struct(timer->task); - timer->task = NULL; list_del_init(&timer->entry); if (cputime_lt(timer->expires.cpu, ptime)) { timer->expires.cpu = cputime_zero; @@ -437,8 +432,6 @@ static void cleanup_timers(struct list_head *head, ++head; list_for_each_entry_safe(timer, next, head, entry) { - put_task_struct(timer->task); - timer->task = NULL; list_del_init(&timer->entry); if (cputime_lt(timer->expires.cpu, utime)) { timer->expires.cpu = cputime_zero; @@ -450,8 +443,6 @@ static void cleanup_timers(struct list_head *head, ++head; list_for_each_entry_safe(timer, next, head, entry) { - put_task_struct(timer->task); - timer->task = NULL; list_del_init(&timer->entry); if (timer->expires.sched < sched_time) { timer->expires.sched = 0; From 3de463c7d9d58f8cf3395268230cb20a4c15bffa Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 24 Oct 2005 14:34:03 +0400 Subject: [PATCH 0668/1939] [PATCH] posix-timers: remove false BUG_ON() from run_posix_cpu_timers() do_exit() clears ->it_##clock##_expires, but nothing prevents another cpu to attach the timer to exiting process after that. After exit_notify() does 'write_unlock_irq(&tasklist_lock)' and before do_exit() calls 'schedule() local timer interrupt can find tsk->exit_state != 0. If that state was EXIT_DEAD (or another cpu does sys_wait4) interrupted task has ->signal == NULL. At this moment exiting task has no pending cpu timers, they were cleaned up in __exit_signal()->posix_cpu_timers_exit{,_group}(), so we can just return from irq. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/exit.c | 8 -------- kernel/posix-cpu-timers.c | 36 ++++++++++++++++++------------------ 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 3b25b182d2be..4897977a1f4b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -825,14 +825,6 @@ fastcall NORET_TYPE void do_exit(long code) tsk->flags |= PF_EXITING; - /* - * Make sure we don't try to process any timer firings - * while we are already exiting. - */ - tsk->it_virt_expires = cputime_zero; - tsk->it_prof_expires = cputime_zero; - tsk->it_sched_expires = 0; - if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 30ab39a27736..ccb04683bf18 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1285,30 +1285,30 @@ void run_posix_cpu_timers(struct task_struct *tsk) #undef UNEXPIRED - BUG_ON(tsk->exit_state); - /* * Double-check with locks held. */ read_lock(&tasklist_lock); - spin_lock(&tsk->sighand->siglock); + if (likely(tsk->signal != NULL)) { + spin_lock(&tsk->sighand->siglock); - /* - * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] - * all the timers that are firing, and put them on the firing list. - */ - check_thread_timers(tsk, &firing); - check_process_timers(tsk, &firing); + /* + * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] + * all the timers that are firing, and put them on the firing list. + */ + check_thread_timers(tsk, &firing); + check_process_timers(tsk, &firing); - /* - * We must release these locks before taking any timer's lock. - * There is a potential race with timer deletion here, as the - * siglock now protects our private firing list. We have set - * the firing flag in each timer, so that a deletion attempt - * that gets the timer lock before we do will give it up and - * spin until we've taken care of that timer below. - */ - spin_unlock(&tsk->sighand->siglock); + /* + * We must release these locks before taking any timer's lock. + * There is a potential race with timer deletion here, as the + * siglock now protects our private firing list. We have set + * the firing flag in each timer, so that a deletion attempt + * that gets the timer lock before we do will give it up and + * spin until we've taken care of that timer below. + */ + spin_unlock(&tsk->sighand->siglock); + } read_unlock(&tasklist_lock); /* From ca531a0a5e01e5122f67cb6aca8fcbfc70e18e0b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 24 Oct 2005 14:36:28 +0400 Subject: [PATCH 0669/1939] [PATCH] posix-timers: exit path cleanup No need to rebalance when task exited Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index ccb04683bf18..92a038064628 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -486,6 +486,9 @@ static void process_timer_rebalance(struct task_struct *p, struct task_struct *t = p; unsigned int nthreads = atomic_read(&p->signal->live); + if (!nthreads) + return; + switch (clock_idx) { default: BUG(); @@ -1160,6 +1163,9 @@ static void check_process_timers(struct task_struct *tsk, unsigned long long sched_left, sched; const unsigned int nthreads = atomic_read(&sig->live); + if (!nthreads) + return; + prof_left = cputime_sub(prof_expires, utime); prof_left = cputime_sub(prof_left, stime); prof_left = cputime_div(prof_left, nthreads); From a69ac4a78d8bd9e1ec478bd7297d4f047fcd44a8 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 24 Oct 2005 18:29:58 +0400 Subject: [PATCH 0670/1939] [PATCH] posix-timers: fix posix_cpu_timer_set() vs run_posix_cpu_timers() race This might be harmless, but looks like a race from code inspection (I was unable to trigger it). I must admit, I don't understand why we can't return TIMER_RETRY after 'spin_unlock(&p->sighand->siglock)' without doing bump_cpu_timer(), but this is what original code does. posix_cpu_timer_set: read_lock(&tasklist_lock); spin_lock(&p->sighand->siglock); list_del_init(&timer->it.cpu.entry); spin_unlock(&p->sighand->siglock); We are probaly deleting the timer from run_posix_cpu_timers's 'firing' local list_head while run_posix_cpu_timers() does list_for_each_safe. Various bad things can happen, for example we can just delete this timer so that list_for_each() will not notice it and run_posix_cpu_timers() will not reset '->firing' flag. In that case, .... if (timer->it.cpu.firing) { read_unlock(&tasklist_lock); timer->it.cpu.firing = -1; return TIMER_RETRY; } sys_timer_settime() goes to 'retry:', calls posix_cpu_timer_set() again, it returns TIMER_RETRY ... Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 92a038064628..b15462b17a58 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -730,9 +730,15 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, * Disarm any old timer after extracting its expiry time. */ BUG_ON(!irqs_disabled()); + + ret = 0; spin_lock(&p->sighand->siglock); old_expires = timer->it.cpu.expires; - list_del_init(&timer->it.cpu.entry); + if (unlikely(timer->it.cpu.firing)) { + timer->it.cpu.firing = -1; + ret = TIMER_RETRY; + } else + list_del_init(&timer->it.cpu.entry); spin_unlock(&p->sighand->siglock); /* @@ -780,7 +786,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, } } - if (unlikely(timer->it.cpu.firing)) { + if (unlikely(ret)) { /* * We are colliding with the timer actually firing. * Punt after filling in the timer's old value, and @@ -788,8 +794,6 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, * it as an overrun (thanks to bump_cpu_timer above). */ read_unlock(&tasklist_lock); - timer->it.cpu.firing = -1; - ret = TIMER_RETRY; goto out; } From 10ded9493ec4a566977ed68b65158eba280e61e5 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 24 Oct 2005 17:49:34 +0200 Subject: [PATCH 0671/1939] [PATCH] uml: fix compile failure for TT mode Without this patch, uml compile fails with: LD .tmp_vmlinux1 arch/um/kernel/built-in.o: In function `config_gdb_cb': arch/um/kernel/tt/gdb.c:129: undefined reference to `TASK_EXTERN_PID' Tested on i386, but fix needed on x86_64 too AFAICS. Signed-off-by: Miklos Szeredi Signed-off-by: Linus Torvalds --- arch/um/include/sysdep-i386/thread.h | 2 +- arch/um/include/sysdep-x86_64/thread.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/include/sysdep-i386/thread.h b/arch/um/include/sysdep-i386/thread.h index e2bd6bae8b8a..243fed44d780 100644 --- a/arch/um/include/sysdep-i386/thread.h +++ b/arch/um/include/sysdep-i386/thread.h @@ -4,7 +4,7 @@ #include #define TASK_DEBUGREGS(task) ((unsigned long *) &(((char *) (task))[HOST_TASK_DEBUGREGS])) -#ifdef CONFIG_MODE_TT +#ifdef UML_CONFIG_MODE_TT #define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) #endif diff --git a/arch/um/include/sysdep-x86_64/thread.h b/arch/um/include/sysdep-x86_64/thread.h index 6a76a7f3683f..cbef3e1697f4 100644 --- a/arch/um/include/sysdep-x86_64/thread.h +++ b/arch/um/include/sysdep-x86_64/thread.h @@ -3,7 +3,7 @@ #include -#ifdef CONFIG_MODE_TT +#ifdef UML_CONFIG_MODE_TT #define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) #endif From d5c5d8fe32a4b9b14363c6031061e98e26da59a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Oct 2005 18:16:50 +0200 Subject: [PATCH 0672/1939] [PATCH] ALSA: Fix Oops of suspend/resume with generic drivers The patch fixes Oops from sound drivers using generic platform device but have no suspend/resume callbacks. Signed-off-by: Takashi Iwai Signed-off-by: Linus Torvalds --- sound/core/init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index a5702014a704..c72a79115cca 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -828,7 +828,8 @@ static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; - card->pm_suspend(card, PMSG_SUSPEND); + if (card->pm_suspend) + card->pm_suspend(card, PMSG_SUSPEND); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -843,7 +844,8 @@ static int snd_generic_resume(struct device *dev, u32 level) card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D0) return 0; - card->pm_resume(card); + if (card->pm_suspend) + card->pm_resume(card); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } From 5d7edb3c1a01310725d86f0d83fb3be45685dc82 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 24 Oct 2005 10:53:25 -0700 Subject: [PATCH 0673/1939] [IB] Add idr_destroy() calls on module unload Add idr_destroy() calls to the module_exit() functions of the four IB driver modules that use idrs, so we don't leak idr_layer_cache objects when these modules are unloaded. Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 1 + drivers/infiniband/core/sa_query.c | 1 + drivers/infiniband/core/ucm.c | 1 + drivers/infiniband/core/uverbs_main.c | 7 +++++++ 4 files changed, 10 insertions(+) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 54db6d4831f1..151ef83cc14f 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3323,6 +3323,7 @@ static void __exit ib_cm_cleanup(void) flush_workqueue(cm.wq); destroy_workqueue(cm.wq); ib_unregister_client(&cm_client); + idr_destroy(&cm.local_id_table); } module_init(ib_cm_init); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 262618210c1c..e215cf0478d6 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -975,6 +975,7 @@ static int __init ib_sa_init(void) static void __exit ib_sa_cleanup(void) { ib_unregister_client(&sa_client); + idr_destroy(&query_idr); } module_init(ib_sa_init); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index d0f0b0a2edd3..5a6ba4030d44 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1320,6 +1320,7 @@ static void __exit ib_ucm_cleanup(void) class_destroy(ib_ucm_class); cdev_del(&ib_ucm_cdev); unregister_chrdev_region(IB_UCM_DEV, 1); + idr_destroy(&ctx_id_table); } module_init(ib_ucm_init); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 12511808de21..add45f7faa5b 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -762,6 +762,13 @@ static void __exit ib_uverbs_cleanup(void) unregister_filesystem(&uverbs_event_fs); class_unregister(&uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + idr_destroy(&ib_uverbs_pd_idr); + idr_destroy(&ib_uverbs_mr_idr); + idr_destroy(&ib_uverbs_mw_idr); + idr_destroy(&ib_uverbs_ah_idr); + idr_destroy(&ib_uverbs_cq_idr); + idr_destroy(&ib_uverbs_qp_idr); + idr_destroy(&ib_uverbs_srq_idr); } module_init(ib_uverbs_init); From ae7971a7706384ca373fb7e212fe195698e6c5a1 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Mon, 24 Oct 2005 12:33:56 -0700 Subject: [PATCH 0674/1939] [IB] CM: Fix initialization of QP attributes for UC QPs. Fix cm_init_qp_init_attr(), cm_init_qp_rtr_attr() and cm_init_qp_rts_attr() so that they correctly handle the differences between UC and RC QPs. This fixes problems with setting up UC QPs through the CM. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 38 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 3fe6f4754fa8..389fecbaf662 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -135,6 +135,7 @@ struct cm_id_private { __be64 tid; __be32 local_qpn; __be32 remote_qpn; + enum ib_qp_type qp_type; __be32 sq_psn; __be32 rq_psn; int timeout_ms; @@ -926,6 +927,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, cm_id_priv->responder_resources = param->responder_resources; cm_id_priv->retry_count = param->retry_count; cm_id_priv->path_mtu = param->primary_path->mtu; + cm_id_priv->qp_type = param->qp_type; ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg); if (ret) @@ -1320,6 +1322,7 @@ static int cm_req_handler(struct cm_work *work) cm_req_get_primary_local_ack_timeout(req_msg); cm_id_priv->retry_count = cm_req_get_retry_count(req_msg); cm_id_priv->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); + cm_id_priv->qp_type = cm_req_get_qp_type(req_msg); cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id); cm_process_work(cm_id_priv, work); @@ -3079,10 +3082,10 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, case IB_CM_ESTABLISHED: *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT; - qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; + qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_WRITE; if (cm_id_priv->responder_resources) - qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_WRITE | - IB_ACCESS_REMOTE_READ; + qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ; qp_attr->pkey_index = cm_id_priv->av.pkey_index; qp_attr->port_num = cm_id_priv->av.port->port_num; ret = 0; @@ -3112,14 +3115,18 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, case IB_CM_MRA_REP_RCVD: case IB_CM_ESTABLISHED: *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | - IB_QP_DEST_QPN | IB_QP_RQ_PSN | - IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER; + IB_QP_DEST_QPN | IB_QP_RQ_PSN; qp_attr->ah_attr = cm_id_priv->av.ah_attr; qp_attr->path_mtu = cm_id_priv->path_mtu; qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); - qp_attr->max_dest_rd_atomic = cm_id_priv->responder_resources; - qp_attr->min_rnr_timer = 0; + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_MIN_RNR_TIMER; + qp_attr->max_dest_rd_atomic = + cm_id_priv->responder_resources; + qp_attr->min_rnr_timer = 0; + } if (cm_id_priv->alt_av.ah_attr.dlid) { *qp_attr_mask |= IB_QP_ALT_PATH; qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; @@ -3148,14 +3155,17 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: case IB_CM_ESTABLISHED: - *qp_attr_mask = IB_QP_STATE | IB_QP_TIMEOUT | IB_QP_RETRY_CNT | - IB_QP_RNR_RETRY | IB_QP_SQ_PSN | - IB_QP_MAX_QP_RD_ATOMIC; - qp_attr->timeout = cm_id_priv->local_ack_timeout; - qp_attr->retry_cnt = cm_id_priv->retry_count; - qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; + *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); - qp_attr->max_rd_atomic = cm_id_priv->initiator_depth; + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC; + qp_attr->timeout = cm_id_priv->local_ack_timeout; + qp_attr->retry_cnt = cm_id_priv->retry_count; + qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; + qp_attr->max_rd_atomic = cm_id_priv->initiator_depth; + } if (cm_id_priv->alt_av.ah_attr.dlid) { *qp_attr_mask |= IB_QP_PATH_MIG_STATE; qp_attr->path_mig_state = IB_MIG_REARM; From c14e2cfc18659c6ca67c2e10417c432eb978d976 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 24 Oct 2005 21:46:21 +0100 Subject: [PATCH 0675/1939] [PATCH] Return the line length via sysfs for fbdev This small patch returns the stride/line length of the framebuffer via sysfs. Signed-off-by: James Simmons Signed-off-by: Linus Torvalds --- drivers/video/fbsysfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 1147b899f007..007c8e9b2b39 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -242,6 +242,13 @@ static ssize_t show_virtual(struct class_device *class_device, char *buf) fb_info->var.yres_virtual); } +static ssize_t show_stride(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length); +} + /* Format for cmap is "%02x%c%4x%4x%4x\n" */ /* %02x entry %c transp %4x red %4x blue %4x green \n */ /* 256 rows at 16 chars equals 4096, the normal page size */ @@ -432,6 +439,7 @@ static struct class_device_attribute class_device_attrs[] = { __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan), __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(stride, S_IRUGO, show_stride, NULL), }; int fb_init_class_device(struct fb_info *fb_info) From add7b58e7558dd2894f3c17ca8574099fcba5c15 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 24 Oct 2005 22:11:57 +0100 Subject: [PATCH 0676/1939] [SERIAL] support the Exsys EX-4055 4S four-port card Tested by Wolfgang Denk with this device: 00:0f.0 Network controller: PLX Technology, Inc. PCI <-> IOBus Bridge (rev 01) Subsystem: Exsys EX-4055 4S(16C550) RS-232 Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- SERR- Signed-off-by: Russell King --- drivers/serial/8250_pci.c | 25 ++++++++++++++++++++++++- include/linux/pci_ids.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 0e21f583690e..5da61ebbac88 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -226,8 +226,10 @@ static int __devinit pci_plx9050_init(struct pci_dev *dev) } irq_config = 0x41; - if (dev->vendor == PCI_VENDOR_ID_PANACOM) + if (dev->vendor == PCI_VENDOR_ID_PANACOM || + dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) { irq_config = 0x43; + } if ((dev->vendor == PCI_VENDOR_ID_PLX) && (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { /* @@ -661,6 +663,15 @@ static struct pci_serial_quirk pci_serial_quirks[] = { /* * PLX */ + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9050, + .subvendor = PCI_SUBVENDOR_ID_EXSYS, + .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, @@ -927,6 +938,7 @@ enum pci_board_num_t { pbn_panacom, pbn_panacom2, pbn_panacom4, + pbn_exsys_4055, pbn_plx_romulus, pbn_oxsemi, pbn_intel_i960, @@ -1292,6 +1304,13 @@ static struct pciserial_board pci_boards[] __devinitdata = { .reg_shift = 7, }, + [pbn_exsys_4055] = { + .flags = FL_BASE2, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + /* I think this entry is broken - the first_offset looks wrong --rmk */ [pbn_plx_romulus] = { .flags = FL_BASE2, @@ -1853,6 +1872,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, pbn_b2_8_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_EXSYS, + PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0, + pbn_exsys_4055 }, /* * Megawolf Romulus PCI Serial Card, from Mike Hudson * (Exoray@isys.ca) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f74ed9462475..ca0691c319ab 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2696,6 +2696,7 @@ #define PCI_SUBVENDOR_ID_EXSYS 0xd84d #define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 +#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 #define PCI_VENDOR_ID_TIGERJET 0xe159 #define PCI_DEVICE_ID_TIGERJET_300 0x0001 From 551f8f0e87becb415c522adccab524a7a05ca83a Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Mon, 24 Oct 2005 22:16:38 +0100 Subject: [PATCH 0677/1939] [SERIAL] new hp diva console port Add the new ID 0x132a and configure the new PCI Diva console port. This device supports only 1 single console UART. Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/serial/8250_pci.c | 1 + include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 5da61ebbac88..5c3c03932d6d 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -152,6 +152,7 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev) rc = 4; break; case PCI_DEVICE_ID_HP_DIVA_POWERBAR: + case PCI_DEVICE_ID_HP_DIVA_HURRICANE: rc = 1; break; } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ca0691c319ab..71834f05504f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -723,6 +723,7 @@ #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 #define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 +#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a #define PCI_DEVICE_ID_HP_CISS 0x3210 #define PCI_DEVICE_ID_HP_CISSA 0x3220 #define PCI_DEVICE_ID_HP_CISSB 0x3222 From c34e152a494c0de8d920b70163d95235a51f4120 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 24 Oct 2005 22:30:10 +0100 Subject: [PATCH 0678/1939] [ARM] fix sharp zaurus c-3000 compile failure without CONFIG_FB_PXA This fixes compile problem when CONFIG_FB_PXA is not set. LD .tmp_vmlinux1 arch/arm/mach-pxa/built-in.o(.text+0x1d74): In function `spitz_get_hsync_len': : undefined reference to `pxafb_get_hsync_time' make: *** [.tmp_vmlinux1] Error 1 3.46user 0.46system 5.10 (0m5.106s) elapsed 77.01%CPU Signed-off-by: Pavel Machek Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/corgi_lcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index 850538fadece..370df113dc06 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c @@ -488,6 +488,7 @@ static int is_pxafb_device(struct device * dev, void * data) unsigned long spitz_get_hsync_len(void) { +#ifdef CONFIG_FB_PXA if (!spitz_pxafb_dev) { spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device); if (!spitz_pxafb_dev) @@ -496,6 +497,7 @@ unsigned long spitz_get_hsync_len(void) if (!get_hsync_time) get_hsync_time = symbol_get(pxafb_get_hsync_time); if (!get_hsync_time) +#endif return 0; return pxafb_get_hsync_time(spitz_pxafb_dev); From 6f0ef4fa57b9ba27d7b1c330bad041f1665501fe Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 25 Oct 2005 01:44:30 -0400 Subject: [PATCH 0679/1939] [PATCH] libata kernel-doc fixes Correct some function names in kernel-doc. Add some kernel-doc descriptions. Fix some typos. Remove a few blank lines. Signed-off-by: Randy Dunlap Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index d55f12dacfcb..dcd3b5553cc8 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -87,7 +87,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /** - * ata_tf_load - send taskfile registers to host controller + * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -2701,13 +2701,13 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) /** * ata_pio_poll - - * @ap: + * @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) @@ -2748,8 +2748,8 @@ static unsigned long ata_pio_poll(struct ata_port *ap) } /** - * ata_pio_complete - - * @ap: + * ata_pio_complete - check if drive is busy or idle + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2801,7 +2801,7 @@ static int ata_pio_complete (struct ata_port *ap) /** - * swap_buf_le16 - + * swap_buf_le16 - swap halves of 16-words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. * @@ -2810,6 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap) * vice-versa. * * LOCKING: + * Inherited from caller. */ void swap_buf_le16(u16 *buf, unsigned int buf_words) { @@ -2832,7 +2833,6 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * * LOCKING: * Inherited from caller. - * */ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2878,7 +2878,6 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2918,7 +2917,6 @@ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -3071,7 +3069,6 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) * * LOCKING: * Inherited from caller. - * */ static void atapi_pio_bytes(struct ata_queued_cmd *qc) @@ -3107,8 +3104,8 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) } /** - * ata_pio_sector - - * @ap: + * ata_pio_block - start PIO on a block + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -3120,7 +3117,7 @@ static void ata_pio_block(struct ata_port *ap) u8 status; /* - * This is purely hueristic. This is a fast path. + * 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 @@ -3440,7 +3437,6 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_free(struct ata_queued_cmd *qc) { @@ -3460,7 +3456,6 @@ void ata_qc_free(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) @@ -3954,7 +3949,6 @@ inline unsigned int ata_host_intr (struct ata_port *ap, * * RETURNS: * IRQ_NONE or IRQ_HANDLED. - * */ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) @@ -4066,6 +4060,7 @@ static void atapi_packet_task(void *_data) * May be used as the port_start() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ int ata_port_start (struct ata_port *ap) @@ -4091,6 +4086,7 @@ int ata_port_start (struct ata_port *ap) * May be used as the port_stop() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ void ata_port_stop (struct ata_port *ap) @@ -4113,6 +4109,7 @@ void ata_host_stop (struct ata_host_set *host_set) * @do_unregister: 1 if we fully unregister, 0 to just stop the port * * LOCKING: + * Inherited from caller. */ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) @@ -4140,7 +4137,6 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) * * LOCKING: * Inherited from caller. - * */ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, @@ -4201,7 +4197,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, * * RETURNS: * New ata_port on success, for NULL on error. - * */ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, @@ -4249,7 +4244,6 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, * * RETURNS: * Number of ports registered. Zero on error (no ports registered). - * */ int ata_device_add(const struct ata_probe_ent *ent) @@ -4381,7 +4375,6 @@ int ata_device_add(const struct ata_probe_ent *ent) * Inherited from calling layer (may sleep). */ - void ata_host_set_remove(struct ata_host_set *host_set) { struct ata_port *ap; @@ -4614,7 +4607,6 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, stru * * RETURNS: * Zero on success, negative on errno-based value on error. - * */ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, @@ -4762,7 +4754,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, * @pdev: PCI device that was removed * * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occured. + * hot-unplug or module unload event has occurred. * Handle this by unregistering all objects associated * with this PCI device. Free those objects. Then finally * release PCI resources and disable device. From 0db9ae4a79381a5a3d272ccb51851c48c4bcbb6d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 24 Oct 2005 23:05:58 -0700 Subject: [PATCH 0680/1939] [PATCH] alpha: atomic dependency fix My alpha build is exploding because asm/atomic.h now needs smb_mb(), which is over in the (not included) system.h. I fear what will happen if I include system.h into atomic.h, so let's put the barriers into their own header file. Cc: Richard Henderson Cc: Ivan Kokshaysky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-alpha/atomic.h | 2 ++ include/asm-alpha/barrier.h | 34 ++++++++++++++++++++++++++++++++++ include/asm-alpha/system.h | 31 +------------------------------ 3 files changed, 37 insertions(+), 30 deletions(-) create mode 100644 include/asm-alpha/barrier.h diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h index 0b40bad00289..20ac3d95ecd9 100644 --- a/include/asm-alpha/atomic.h +++ b/include/asm-alpha/atomic.h @@ -1,6 +1,8 @@ #ifndef _ALPHA_ATOMIC_H #define _ALPHA_ATOMIC_H +#include + /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc... diff --git a/include/asm-alpha/barrier.h b/include/asm-alpha/barrier.h new file mode 100644 index 000000000000..229c83fe77cb --- /dev/null +++ b/include/asm-alpha/barrier.h @@ -0,0 +1,34 @@ +#ifndef __BARRIER_H +#define __BARRIER_H + +#define mb() \ +__asm__ __volatile__("mb": : :"memory") + +#define rmb() \ +__asm__ __volatile__("mb": : :"memory") + +#define wmb() \ +__asm__ __volatile__("wmb": : :"memory") + +#define read_barrier_depends() \ +__asm__ __volatile__("mb": : :"memory") + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() barrier() +#endif + +#define set_mb(var, value) \ +do { var = value; mb(); } while (0) + +#define set_wmb(var, value) \ +do { var = value; wmb(); } while (0) + +#endif /* __BARRIER_H */ diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index bdb4d66418f1..050e86d12891 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * System defines.. Note that this is included both from .c and .S @@ -139,36 +140,6 @@ extern void halt(void) __attribute__((noreturn)); struct task_struct; extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct*); -#define mb() \ -__asm__ __volatile__("mb": : :"memory") - -#define rmb() \ -__asm__ __volatile__("mb": : :"memory") - -#define wmb() \ -__asm__ __volatile__("wmb": : :"memory") - -#define read_barrier_depends() \ -__asm__ __volatile__("mb": : :"memory") - -#ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() -#else -#define smp_mb() barrier() -#define smp_rmb() barrier() -#define smp_wmb() barrier() -#define smp_read_barrier_depends() barrier() -#endif - -#define set_mb(var, value) \ -do { var = value; mb(); } while (0) - -#define set_wmb(var, value) \ -do { var = value; wmb(); } while (0) - #define imb() \ __asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory") From 34816ad98efe4d47ffd858a0345321f9d85d9420 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Tue, 25 Oct 2005 10:51:39 -0700 Subject: [PATCH 0681/1939] [IB] Fix MAD layer DMA mappings to avoid touching data buffer once mapped The MAD layer was violating the DMA API by touching data buffers used for sends after the DMA mapping was done. This causes problems on non-cache-coherent architectures, because the device doing DMA won't see updates to the payload buffers that exist only in the CPU cache. Fix this by having all MAD consumers use ib_create_send_mad() to allocate their send buffers, and moving the DMA mapping into the MAD layer so it can be done just before calling send (and after any modifications of the send buffer by the MAD layer). Tested on a non-cache-coherent PowerPC 440SPe system. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/agent.c | 299 +++++++----------------- drivers/infiniband/core/agent.h | 13 +- drivers/infiniband/core/agent_priv.h | 62 ----- drivers/infiniband/core/cm.c | 137 ++++------- drivers/infiniband/core/mad.c | 282 ++++++++++------------ drivers/infiniband/core/mad_priv.h | 8 +- drivers/infiniband/core/mad_rmpp.c | 87 ++++--- drivers/infiniband/core/mad_rmpp.h | 2 + drivers/infiniband/core/sa_query.c | 239 +++++++++---------- drivers/infiniband/core/smi.h | 2 + drivers/infiniband/core/user_mad.c | 47 ++-- drivers/infiniband/hw/mthca/mthca_mad.c | 72 +----- include/rdma/ib_mad.h | 66 +++--- include/rdma/ib_verbs.h | 3 - 14 files changed, 475 insertions(+), 844 deletions(-) delete mode 100644 drivers/infiniband/core/agent_priv.h diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 5ac86f566dc0..0c3c6952faae 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c @@ -37,58 +37,41 @@ * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ */ -#include - -#include - -#include - -#include "smi.h" -#include "agent_priv.h" -#include "mad_priv.h" #include "agent.h" +#include "smi.h" -spinlock_t ib_agent_port_list_lock; +#define SPFX "ib_agent: " + +struct ib_agent_port_private { + struct list_head port_list; + struct ib_mad_agent *agent[2]; +}; + +static DEFINE_SPINLOCK(ib_agent_port_list_lock); static LIST_HEAD(ib_agent_port_list); -/* - * Caller must hold ib_agent_port_list_lock - */ -static inline struct ib_agent_port_private * -__ib_get_agent_port(struct ib_device *device, int port_num, - struct ib_mad_agent *mad_agent) +static struct ib_agent_port_private * +__ib_get_agent_port(struct ib_device *device, int port_num) { struct ib_agent_port_private *entry; - BUG_ON(!(!!device ^ !!mad_agent)); /* Exactly one MUST be (!NULL) */ - - if (device) { - list_for_each_entry(entry, &ib_agent_port_list, port_list) { - if (entry->smp_agent->device == device && - entry->port_num == port_num) - return entry; - } - } else { - list_for_each_entry(entry, &ib_agent_port_list, port_list) { - if ((entry->smp_agent == mad_agent) || - (entry->perf_mgmt_agent == mad_agent)) - return entry; - } + list_for_each_entry(entry, &ib_agent_port_list, port_list) { + if (entry->agent[0]->device == device && + entry->agent[0]->port_num == port_num) + return entry; } return NULL; } -static inline struct ib_agent_port_private * -ib_get_agent_port(struct ib_device *device, int port_num, - struct ib_mad_agent *mad_agent) +static struct ib_agent_port_private * +ib_get_agent_port(struct ib_device *device, int port_num) { struct ib_agent_port_private *entry; unsigned long flags; spin_lock_irqsave(&ib_agent_port_list_lock, flags); - entry = __ib_get_agent_port(device, port_num, mad_agent); + entry = __ib_get_agent_port(device, port_num); spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); - return entry; } @@ -100,192 +83,76 @@ int smi_check_local_dr_smp(struct ib_smp *smp, if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) return 1; - port_priv = ib_get_agent_port(device, port_num, NULL); + + port_priv = ib_get_agent_port(device, port_num); if (!port_priv) { printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d " - "not open\n", - device->name, port_num); + "not open\n", device->name, port_num); return 1; } - return smi_check_local_smp(port_priv->smp_agent, smp); + return smi_check_local_smp(port_priv->agent[0], smp); } -static int agent_mad_send(struct ib_mad_agent *mad_agent, - struct ib_agent_port_private *port_priv, - struct ib_mad_private *mad_priv, - struct ib_grh *grh, - struct ib_wc *wc) -{ - struct ib_agent_send_wr *agent_send_wr; - struct ib_sge gather_list; - struct ib_send_wr send_wr; - struct ib_send_wr *bad_send_wr; - struct ib_ah_attr ah_attr; - unsigned long flags; - int ret = 1; - - agent_send_wr = kmalloc(sizeof(*agent_send_wr), GFP_KERNEL); - if (!agent_send_wr) - goto out; - agent_send_wr->mad = mad_priv; - - gather_list.addr = dma_map_single(mad_agent->device->dma_device, - &mad_priv->mad, - sizeof(mad_priv->mad), - DMA_TO_DEVICE); - gather_list.length = sizeof(mad_priv->mad); - gather_list.lkey = mad_agent->mr->lkey; - - send_wr.next = NULL; - send_wr.opcode = IB_WR_SEND; - send_wr.sg_list = &gather_list; - send_wr.num_sge = 1; - send_wr.wr.ud.remote_qpn = wc->src_qp; /* DQPN */ - send_wr.wr.ud.timeout_ms = 0; - send_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED; - - ah_attr.dlid = wc->slid; - ah_attr.port_num = mad_agent->port_num; - ah_attr.src_path_bits = wc->dlid_path_bits; - ah_attr.sl = wc->sl; - ah_attr.static_rate = 0; - ah_attr.ah_flags = 0; /* No GRH */ - if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { - if (wc->wc_flags & IB_WC_GRH) { - ah_attr.ah_flags = IB_AH_GRH; - /* Should sgid be looked up ? */ - ah_attr.grh.sgid_index = 0; - ah_attr.grh.hop_limit = grh->hop_limit; - ah_attr.grh.flow_label = be32_to_cpu( - grh->version_tclass_flow) & 0xfffff; - ah_attr.grh.traffic_class = (be32_to_cpu( - grh->version_tclass_flow) >> 20) & 0xff; - memcpy(ah_attr.grh.dgid.raw, - grh->sgid.raw, - sizeof(ah_attr.grh.dgid)); - } - } - - agent_send_wr->ah = ib_create_ah(mad_agent->qp->pd, &ah_attr); - if (IS_ERR(agent_send_wr->ah)) { - printk(KERN_ERR SPFX "No memory for address handle\n"); - kfree(agent_send_wr); - goto out; - } - - send_wr.wr.ud.ah = agent_send_wr->ah; - if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { - send_wr.wr.ud.pkey_index = wc->pkey_index; - send_wr.wr.ud.remote_qkey = IB_QP1_QKEY; - } else { /* for SMPs */ - send_wr.wr.ud.pkey_index = 0; - send_wr.wr.ud.remote_qkey = 0; - } - send_wr.wr.ud.mad_hdr = &mad_priv->mad.mad.mad_hdr; - send_wr.wr_id = (unsigned long)agent_send_wr; - - pci_unmap_addr_set(agent_send_wr, mapping, gather_list.addr); - - /* Send */ - spin_lock_irqsave(&port_priv->send_list_lock, flags); - if (ib_post_send_mad(mad_agent, &send_wr, &bad_send_wr)) { - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(agent_send_wr, mapping), - sizeof(mad_priv->mad), - DMA_TO_DEVICE); - ib_destroy_ah(agent_send_wr->ah); - kfree(agent_send_wr); - } else { - list_add_tail(&agent_send_wr->send_list, - &port_priv->send_posted_list); - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - ret = 0; - } - -out: - return ret; -} - -int agent_send(struct ib_mad_private *mad, - struct ib_grh *grh, - struct ib_wc *wc, - struct ib_device *device, - int port_num) +int agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn) { struct ib_agent_port_private *port_priv; - struct ib_mad_agent *mad_agent; + struct ib_mad_agent *agent; + struct ib_mad_send_buf *send_buf; + struct ib_ah *ah; + int ret; - port_priv = ib_get_agent_port(device, port_num, NULL); + port_priv = ib_get_agent_port(device, port_num); if (!port_priv) { - printk(KERN_DEBUG SPFX "agent_send %s port %d not open\n", - device->name, port_num); - return 1; + printk(KERN_ERR SPFX "Unable to find port agent\n"); + return -ENODEV; } - /* Get mad agent based on mgmt_class in MAD */ - switch (mad->mad.mad.mad_hdr.mgmt_class) { - case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: - case IB_MGMT_CLASS_SUBN_LID_ROUTED: - mad_agent = port_priv->smp_agent; - break; - case IB_MGMT_CLASS_PERF_MGMT: - mad_agent = port_priv->perf_mgmt_agent; - break; - default: - return 1; + agent = port_priv->agent[qpn]; + ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + printk(KERN_ERR SPFX "ib_create_ah_from_wc error:%d\n", ret); + return ret; } - return agent_mad_send(mad_agent, port_priv, mad, grh, wc); + send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, + IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_KERNEL); + if (IS_ERR(send_buf)) { + ret = PTR_ERR(send_buf); + printk(KERN_ERR SPFX "ib_create_send_mad error:%d\n", ret); + goto err1; + } + + memcpy(send_buf->mad, mad, sizeof *mad); + send_buf->ah = ah; + if ((ret = ib_post_send_mad(send_buf, NULL))) { + printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret); + goto err2; + } + return 0; +err2: + ib_free_send_mad(send_buf); +err1: + ib_destroy_ah(ah); + return ret; } static void agent_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_agent_port_private *port_priv; - struct ib_agent_send_wr *agent_send_wr; - unsigned long flags; - - /* Find matching MAD agent */ - port_priv = ib_get_agent_port(NULL, 0, mad_agent); - if (!port_priv) { - printk(KERN_ERR SPFX "agent_send_handler: no matching MAD " - "agent %p\n", mad_agent); - return; - } - - agent_send_wr = (struct ib_agent_send_wr *)(unsigned long)mad_send_wc->wr_id; - spin_lock_irqsave(&port_priv->send_list_lock, flags); - /* Remove completed send from posted send MAD list */ - list_del(&agent_send_wr->send_list); - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - - dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(agent_send_wr, mapping), - sizeof(agent_send_wr->mad->mad), - DMA_TO_DEVICE); - - ib_destroy_ah(agent_send_wr->ah); - - /* Release allocated memory */ - kmem_cache_free(ib_mad_cache, agent_send_wr->mad); - kfree(agent_send_wr); + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); } int ib_agent_port_open(struct ib_device *device, int port_num) { - int ret; struct ib_agent_port_private *port_priv; unsigned long flags; - - /* First, check if port already open for SMI */ - port_priv = ib_get_agent_port(device, port_num, NULL); - if (port_priv) { - printk(KERN_DEBUG SPFX "%s port %d already open\n", - device->name, port_num); - return 0; - } + int ret; /* Create new device info */ port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); @@ -294,32 +161,25 @@ int ib_agent_port_open(struct ib_device *device, int port_num) ret = -ENOMEM; goto error1; } - memset(port_priv, 0, sizeof *port_priv); - port_priv->port_num = port_num; - spin_lock_init(&port_priv->send_list_lock); - INIT_LIST_HEAD(&port_priv->send_posted_list); - /* Obtain send only MAD agent for SM class (SMI QP) */ - port_priv->smp_agent = ib_register_mad_agent(device, port_num, - IB_QPT_SMI, - NULL, 0, + /* Obtain send only MAD agent for SMI QP */ + port_priv->agent[0] = ib_register_mad_agent(device, port_num, + IB_QPT_SMI, NULL, 0, &agent_send_handler, - NULL, NULL); - - if (IS_ERR(port_priv->smp_agent)) { - ret = PTR_ERR(port_priv->smp_agent); + NULL, NULL); + if (IS_ERR(port_priv->agent[0])) { + ret = PTR_ERR(port_priv->agent[0]); goto error2; } - /* Obtain send only MAD agent for PerfMgmt class (GSI QP) */ - port_priv->perf_mgmt_agent = ib_register_mad_agent(device, port_num, - IB_QPT_GSI, - NULL, 0, - &agent_send_handler, - NULL, NULL); - if (IS_ERR(port_priv->perf_mgmt_agent)) { - ret = PTR_ERR(port_priv->perf_mgmt_agent); + /* Obtain send only MAD agent for GSI QP */ + port_priv->agent[1] = ib_register_mad_agent(device, port_num, + IB_QPT_GSI, NULL, 0, + &agent_send_handler, + NULL, NULL); + if (IS_ERR(port_priv->agent[1])) { + ret = PTR_ERR(port_priv->agent[1]); goto error3; } @@ -330,7 +190,7 @@ int ib_agent_port_open(struct ib_device *device, int port_num) return 0; error3: - ib_unregister_mad_agent(port_priv->smp_agent); + ib_unregister_mad_agent(port_priv->agent[0]); error2: kfree(port_priv); error1: @@ -343,7 +203,7 @@ int ib_agent_port_close(struct ib_device *device, int port_num) unsigned long flags; spin_lock_irqsave(&ib_agent_port_list_lock, flags); - port_priv = __ib_get_agent_port(device, port_num, NULL); + port_priv = __ib_get_agent_port(device, port_num); if (port_priv == NULL) { spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); printk(KERN_ERR SPFX "Port %d not found\n", port_num); @@ -352,9 +212,8 @@ int ib_agent_port_close(struct ib_device *device, int port_num) list_del(&port_priv->port_list); spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); - ib_unregister_mad_agent(port_priv->perf_mgmt_agent); - ib_unregister_mad_agent(port_priv->smp_agent); + ib_unregister_mad_agent(port_priv->agent[1]); + ib_unregister_mad_agent(port_priv->agent[0]); kfree(port_priv); - return 0; } diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h index d9426842254a..c5f3cfec942a 100644 --- a/drivers/infiniband/core/agent.h +++ b/drivers/infiniband/core/agent.h @@ -39,17 +39,14 @@ #ifndef __AGENT_H_ #define __AGENT_H_ -extern spinlock_t ib_agent_port_list_lock; +#include -extern int ib_agent_port_open(struct ib_device *device, - int port_num); +extern int ib_agent_port_open(struct ib_device *device, int port_num); extern int ib_agent_port_close(struct ib_device *device, int port_num); -extern int agent_send(struct ib_mad_private *mad, - struct ib_grh *grh, - struct ib_wc *wc, - struct ib_device *device, - int port_num); +extern int agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn); #endif /* __AGENT_H_ */ diff --git a/drivers/infiniband/core/agent_priv.h b/drivers/infiniband/core/agent_priv.h deleted file mode 100644 index 2ec6d7f1b7d0..000000000000 --- a/drivers/infiniband/core/agent_priv.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. - * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * $Id: agent_priv.h 1640 2005-01-24 22:39:02Z halr $ - */ - -#ifndef __IB_AGENT_PRIV_H__ -#define __IB_AGENT_PRIV_H__ - -#include - -#define SPFX "ib_agent: " - -struct ib_agent_send_wr { - struct list_head send_list; - struct ib_ah *ah; - struct ib_mad_private *mad; - DECLARE_PCI_UNMAP_ADDR(mapping) -}; - -struct ib_agent_port_private { - struct list_head port_list; - struct list_head send_posted_list; - spinlock_t send_list_lock; - int port_num; - struct ib_mad_agent *smp_agent; /* SM class */ - struct ib_mad_agent *perf_mgmt_agent; /* PerfMgmt class */ -}; - -#endif /* __IB_AGENT_PRIV_H__ */ diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 389fecbaf662..580c3a2bb102 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -176,8 +176,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, cm_id_priv->av.pkey_index, - ah, 0, sizeof(struct ib_mad_hdr), - sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); if (IS_ERR(m)) { ib_destroy_ah(ah); @@ -185,7 +184,8 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, } /* Timeout set by caller if response is expected. */ - m->send_wr.wr.ud.retries = cm_id_priv->max_cm_retries; + m->ah = ah; + m->retries = cm_id_priv->max_cm_retries; atomic_inc(&cm_id_priv->refcount); m->context[0] = cm_id_priv; @@ -206,20 +206,20 @@ static int cm_alloc_response_msg(struct cm_port *port, return PTR_ERR(ah); m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, - ah, 0, sizeof(struct ib_mad_hdr), - sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); if (IS_ERR(m)) { ib_destroy_ah(ah); return PTR_ERR(m); } + m->ah = ah; *msg = m; return 0; } static void cm_free_msg(struct ib_mad_send_buf *msg) { - ib_destroy_ah(msg->send_wr.wr.ud.ah); + ib_destroy_ah(msg->ah); if (msg->context[0]) cm_deref_id(msg->context[0]); ib_free_send_mad(msg); @@ -678,8 +678,7 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id) break; case IB_CM_SIDR_REQ_SENT: cm_id->state = IB_CM_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; case IB_CM_SIDR_REQ_RCVD: @@ -690,8 +689,7 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id) case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* Fall through */ case IB_CM_REQ_RCVD: case IB_CM_MRA_REQ_SENT: @@ -708,8 +706,7 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id) ib_send_cm_dreq(cm_id, NULL, 0); goto retest; case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); cm_enter_timewait(cm_id_priv); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; @@ -883,7 +880,6 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param) { struct cm_id_private *cm_id_priv; - struct ib_send_wr *bad_send_wr; struct cm_req_msg *req_msg; unsigned long flags; int ret; @@ -936,7 +932,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad; cm_format_req(req_msg, cm_id_priv, param); cm_id_priv->tid = req_msg->hdr.tid; - cm_id_priv->msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms; cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT; cm_id_priv->local_qpn = cm_req_get_local_qpn(req_msg); @@ -945,8 +941,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, cm_req_get_primary_local_ack_timeout(req_msg); spin_lock_irqsave(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &cm_id_priv->msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(cm_id_priv->msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); goto error2; @@ -969,7 +964,6 @@ static int cm_issue_rej(struct cm_port *port, void *ari, u8 ari_length) { struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; struct cm_rej_msg *rej_msg, *rcv_msg; int ret; @@ -992,7 +986,7 @@ static int cm_issue_rej(struct cm_port *port, memcpy(rej_msg->ari, ari, ari_length); } - ret = ib_post_send_mad(port->mad_agent, &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) cm_free_msg(msg); @@ -1172,7 +1166,6 @@ static void cm_dup_req_handler(struct cm_work *work, struct cm_id_private *cm_id_priv) { struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1201,8 +1194,7 @@ static void cm_dup_req_handler(struct cm_work *work, } spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto free; return; @@ -1367,7 +1359,6 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; struct cm_rep_msg *rep_msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1389,11 +1380,10 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, rep_msg = (struct cm_rep_msg *) msg->mad; cm_format_rep(rep_msg, cm_id_priv, param); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1431,7 +1421,6 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; void *data; int ret; @@ -1458,8 +1447,7 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id, cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1504,7 +1492,6 @@ static void cm_dup_rep_handler(struct cm_work *work) struct cm_id_private *cm_id_priv; struct cm_rep_msg *rep_msg; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1532,8 +1519,7 @@ static void cm_dup_rep_handler(struct cm_work *work) goto unlock; spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto free; goto deref; @@ -1601,8 +1587,7 @@ static int cm_rep_handler(struct cm_work *work) /* todo: handle peer_to_peer */ - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1636,8 +1621,7 @@ static int cm_establish_handler(struct cm_work *work) goto out; } - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1676,8 +1660,7 @@ static int cm_rtu_handler(struct cm_work *work) } cm_id_priv->id.state = IB_CM_ESTABLISHED; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1714,7 +1697,6 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1736,11 +1718,10 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id, cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { cm_enter_timewait(cm_id_priv); spin_unlock_irqrestore(&cm_id_priv->lock, flags); @@ -1774,7 +1755,6 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; void *data; int ret; @@ -1804,8 +1784,7 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id, cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1822,7 +1801,6 @@ static int cm_dreq_handler(struct cm_work *work) struct cm_id_private *cm_id_priv; struct cm_dreq_msg *dreq_msg; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1841,8 +1819,7 @@ static int cm_dreq_handler(struct cm_work *work) switch (cm_id_priv->id.state) { case IB_CM_REP_SENT: case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); break; case IB_CM_ESTABLISHED: case IB_CM_MRA_REP_RCVD: @@ -1856,8 +1833,7 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv->private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); - if (ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr)) + if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; default: @@ -1904,8 +1880,7 @@ static int cm_drep_handler(struct cm_work *work) } cm_enter_timewait(cm_id_priv); - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1930,7 +1905,6 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1974,8 +1948,7 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, if (ret) goto out; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) cm_free_msg(msg); @@ -2051,8 +2024,7 @@ static int cm_rej_handler(struct cm_work *work) case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* fall through */ case IB_CM_REQ_RCVD: case IB_CM_MRA_REQ_SENT: @@ -2062,8 +2034,7 @@ static int cm_rej_handler(struct cm_work *work) cm_reset_to_idle(cm_id_priv); break; case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* fall through */ case IB_CM_REP_RCVD: case IB_CM_MRA_REP_SENT: @@ -2098,7 +2069,6 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; void *data; unsigned long flags; int ret; @@ -2122,8 +2092,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_REQ, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->state = IB_CM_MRA_REQ_SENT; @@ -2136,8 +2105,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_REP, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->state = IB_CM_MRA_REP_SENT; @@ -2150,8 +2118,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_OTHER, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->lap_state = IB_CM_MRA_LAP_SENT; @@ -2213,14 +2180,14 @@ static int cm_mra_handler(struct cm_work *work) case IB_CM_REQ_SENT: if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD; break; case IB_CM_REP_SENT: if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REP || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.state = IB_CM_MRA_REP_RCVD; break; @@ -2228,7 +2195,7 @@ static int cm_mra_handler(struct cm_work *work) if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || cm_id_priv->id.lap_state != IB_CM_LAP_SENT || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; break; @@ -2291,7 +2258,6 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2312,11 +2278,10 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id, cm_format_lap((struct cm_lap_msg *) msg->mad, cm_id_priv, alternate_path, private_data, private_data_len); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_ESTABLISHED; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2360,7 +2325,6 @@ static int cm_lap_handler(struct cm_work *work) struct cm_lap_msg *lap_msg; struct ib_cm_lap_event_param *param; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2394,8 +2358,7 @@ static int cm_lap_handler(struct cm_work *work) cm_id_priv->private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); - if (ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr)) + if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; default: @@ -2451,7 +2414,6 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2474,8 +2436,7 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id, cm_format_apr((struct cm_apr_msg *) msg->mad, cm_id_priv, status, info, info_length, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2514,8 +2475,7 @@ static int cm_apr_handler(struct cm_work *work) goto out; } cm_id_priv->id.lap_state = IB_CM_LAP_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); cm_id_priv->msg = NULL; ret = atomic_inc_and_test(&cm_id_priv->work_count); @@ -2590,7 +2550,6 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2613,13 +2572,12 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv, param); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT; spin_lock_irqsave(&cm_id_priv->lock, flags); if (cm_id->state == IB_CM_IDLE) - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); else ret = -EINVAL; @@ -2733,7 +2691,6 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2755,8 +2712,7 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv, param); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2809,8 +2765,7 @@ static int cm_sidr_rep_handler(struct cm_work *work) goto out; } cm_id_priv->id.state = IB_CM_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_format_sidr_rep_event(work); @@ -2878,9 +2833,7 @@ static void cm_process_send_error(struct ib_mad_send_buf *msg, static void cm_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_mad_send_buf *msg; - - msg = (struct ib_mad_send_buf *)(unsigned long)mad_send_wc->wr_id; + struct ib_mad_send_buf *msg = mad_send_wc->send_buf; switch (mad_send_wc->status) { case IB_WC_SUCCESS: diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index af302e830561..88f9f8c9eacc 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -579,7 +579,7 @@ static void dequeue_mad(struct ib_mad_list_head *mad_list) } static void snoop_send(struct ib_mad_qp_info *qp_info, - struct ib_send_wr *send_wr, + struct ib_mad_send_buf *send_buf, struct ib_mad_send_wc *mad_send_wc, int mad_snoop_flags) { @@ -597,7 +597,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, atomic_inc(&mad_snoop_priv->refcount); spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, - send_wr, mad_send_wc); + send_buf, mad_send_wc); if (atomic_dec_and_test(&mad_snoop_priv->refcount)) wake_up(&mad_snoop_priv->wait); spin_lock_irqsave(&qp_info->snoop_lock, flags); @@ -654,10 +654,10 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, * Return < 0 if error */ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, - struct ib_smp *smp, - struct ib_send_wr *send_wr) + struct ib_mad_send_wr_private *mad_send_wr) { int ret; + struct ib_smp *smp = mad_send_wr->send_buf.mad; unsigned long flags; struct ib_mad_local_private *local; struct ib_mad_private *mad_priv; @@ -666,6 +666,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, struct ib_device *device = mad_agent_priv->agent.device; u8 port_num = mad_agent_priv->agent.port_num; struct ib_wc mad_wc; + struct ib_send_wr *send_wr = &mad_send_wr->send_wr; if (!smi_handle_dr_smp_send(smp, device->node_type, port_num)) { ret = -EINVAL; @@ -745,13 +746,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, goto out; } - local->send_wr = *send_wr; - local->send_wr.sg_list = local->sg_list; - memcpy(local->sg_list, send_wr->sg_list, - sizeof *send_wr->sg_list * send_wr->num_sge); - local->send_wr.next = NULL; - local->tid = send_wr->wr.ud.mad_hdr->tid; - local->wr_id = send_wr->wr_id; + local->mad_send_wr = mad_send_wr; /* Reference MAD agent until send side of local completion handled */ atomic_inc(&mad_agent_priv->refcount); /* Queue local completion to local list */ @@ -781,17 +776,17 @@ static int get_buf_length(int hdr_len, int data_len) struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, u32 remote_qpn, u16 pkey_index, - struct ib_ah *ah, int rmpp_active, + int rmpp_active, int hdr_len, int data_len, gfp_t gfp_mask) { struct ib_mad_agent_private *mad_agent_priv; - struct ib_mad_send_buf *send_buf; + struct ib_mad_send_wr_private *mad_send_wr; int buf_size; void *buf; - mad_agent_priv = container_of(mad_agent, - struct ib_mad_agent_private, agent); + mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, + agent); buf_size = get_buf_length(hdr_len, data_len); if ((!mad_agent->rmpp_version && @@ -799,45 +794,40 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, (!rmpp_active && buf_size > sizeof(struct ib_mad))) return ERR_PTR(-EINVAL); - buf = kmalloc(sizeof *send_buf + buf_size, gfp_mask); + buf = kmalloc(sizeof *mad_send_wr + buf_size, gfp_mask); if (!buf) return ERR_PTR(-ENOMEM); - memset(buf, 0, sizeof *send_buf + buf_size); + memset(buf, 0, sizeof *mad_send_wr + buf_size); - send_buf = buf + buf_size; - send_buf->mad = buf; + mad_send_wr = buf + buf_size; + mad_send_wr->send_buf.mad = buf; - send_buf->sge.addr = dma_map_single(mad_agent->device->dma_device, - buf, buf_size, DMA_TO_DEVICE); - pci_unmap_addr_set(send_buf, mapping, send_buf->sge.addr); - send_buf->sge.length = buf_size; - send_buf->sge.lkey = mad_agent->mr->lkey; + mad_send_wr->mad_agent_priv = mad_agent_priv; + mad_send_wr->sg_list[0].length = buf_size; + mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; - send_buf->send_wr.wr_id = (unsigned long) send_buf; - send_buf->send_wr.sg_list = &send_buf->sge; - send_buf->send_wr.num_sge = 1; - send_buf->send_wr.opcode = IB_WR_SEND; - send_buf->send_wr.send_flags = IB_SEND_SIGNALED; - send_buf->send_wr.wr.ud.ah = ah; - send_buf->send_wr.wr.ud.mad_hdr = &send_buf->mad->mad_hdr; - send_buf->send_wr.wr.ud.remote_qpn = remote_qpn; - send_buf->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; - send_buf->send_wr.wr.ud.pkey_index = pkey_index; + mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; + mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; + mad_send_wr->send_wr.num_sge = 1; + mad_send_wr->send_wr.opcode = IB_WR_SEND; + mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; + mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; + mad_send_wr->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; + mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; if (rmpp_active) { - struct ib_rmpp_mad *rmpp_mad; - rmpp_mad = (struct ib_rmpp_mad *)send_buf->mad; + struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad; rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len - - offsetof(struct ib_rmpp_mad, data) + data_len); + IB_MGMT_RMPP_HDR + data_len); rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version; rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); } - send_buf->mad_agent = mad_agent; + mad_send_wr->send_buf.mad_agent = mad_agent; atomic_inc(&mad_agent_priv->refcount); - return send_buf; + return &mad_send_wr->send_buf; } EXPORT_SYMBOL(ib_create_send_mad); @@ -847,10 +837,6 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf) mad_agent_priv = container_of(send_buf->mad_agent, struct ib_mad_agent_private, agent); - - dma_unmap_single(send_buf->mad_agent->device->dma_device, - pci_unmap_addr(send_buf, mapping), - send_buf->sge.length, DMA_TO_DEVICE); kfree(send_buf->mad); if (atomic_dec_and_test(&mad_agent_priv->refcount)) @@ -861,8 +847,10 @@ EXPORT_SYMBOL(ib_free_send_mad); int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) { struct ib_mad_qp_info *qp_info; - struct ib_send_wr *bad_send_wr; struct list_head *list; + struct ib_send_wr *bad_send_wr; + struct ib_mad_agent *mad_agent; + struct ib_sge *sge; unsigned long flags; int ret; @@ -871,10 +859,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) mad_send_wr->send_wr.wr_id = (unsigned long)&mad_send_wr->mad_list; mad_send_wr->mad_list.mad_queue = &qp_info->send_queue; + mad_agent = mad_send_wr->send_buf.mad_agent; + sge = mad_send_wr->sg_list; + sge->addr = dma_map_single(mad_agent->device->dma_device, + mad_send_wr->send_buf.mad, sge->length, + DMA_TO_DEVICE); + pci_unmap_addr_set(mad_send_wr, mapping, sge->addr); + spin_lock_irqsave(&qp_info->send_queue.lock, flags); if (qp_info->send_queue.count < qp_info->send_queue.max_active) { - ret = ib_post_send(mad_send_wr->mad_agent_priv->agent.qp, - &mad_send_wr->send_wr, &bad_send_wr); + ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr, + &bad_send_wr); list = &qp_info->send_queue.list; } else { ret = 0; @@ -886,6 +881,11 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) list_add_tail(&mad_send_wr->mad_list.list, list); } spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); + if (ret) + dma_unmap_single(mad_agent->device->dma_device, + pci_unmap_addr(mad_send_wr, mapping), + sge->length, DMA_TO_DEVICE); + return ret; } @@ -893,45 +893,28 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated * with the registered client */ -int ib_post_send_mad(struct ib_mad_agent *mad_agent, - struct ib_send_wr *send_wr, - struct ib_send_wr **bad_send_wr) +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf) { - int ret = -EINVAL; struct ib_mad_agent_private *mad_agent_priv; - - /* Validate supplied parameters */ - if (!bad_send_wr) - goto error1; - - if (!mad_agent || !send_wr) - goto error2; - - if (!mad_agent->send_handler) - goto error2; - - mad_agent_priv = container_of(mad_agent, - struct ib_mad_agent_private, - agent); + struct ib_mad_send_buf *next_send_buf; + struct ib_mad_send_wr_private *mad_send_wr; + unsigned long flags; + int ret = -EINVAL; /* Walk list of send WRs and post each on send list */ - while (send_wr) { - unsigned long flags; - struct ib_send_wr *next_send_wr; - struct ib_mad_send_wr_private *mad_send_wr; - struct ib_smp *smp; + for (; send_buf; send_buf = next_send_buf) { - /* Validate more parameters */ - if (send_wr->num_sge > IB_MAD_SEND_REQ_MAX_SG) - goto error2; + mad_send_wr = container_of(send_buf, + struct ib_mad_send_wr_private, + send_buf); + mad_agent_priv = mad_send_wr->mad_agent_priv; - if (send_wr->wr.ud.timeout_ms && !mad_agent->recv_handler) - goto error2; - - if (!send_wr->wr.ud.mad_hdr) { - printk(KERN_ERR PFX "MAD header must be supplied " - "in WR %p\n", send_wr); - goto error2; + if (!send_buf->mad_agent->send_handler || + (send_buf->timeout_ms && + !send_buf->mad_agent->recv_handler)) { + ret = -EINVAL; + goto error; } /* @@ -939,40 +922,24 @@ int ib_post_send_mad(struct ib_mad_agent *mad_agent, * current one completes, and the user modifies the work * request associated with the completion */ - next_send_wr = (struct ib_send_wr *)send_wr->next; + next_send_buf = send_buf->next; + mad_send_wr->send_wr.wr.ud.ah = send_buf->ah; - smp = (struct ib_smp *)send_wr->wr.ud.mad_hdr; - if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - ret = handle_outgoing_dr_smp(mad_agent_priv, smp, - send_wr); + if (((struct ib_mad_hdr *) send_buf->mad)->mgmt_class == + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + ret = handle_outgoing_dr_smp(mad_agent_priv, + mad_send_wr); if (ret < 0) /* error */ - goto error2; + goto error; else if (ret == 1) /* locally consumed */ - goto next; + continue; } - /* Allocate MAD send WR tracking structure */ - mad_send_wr = kmalloc(sizeof *mad_send_wr, GFP_ATOMIC); - if (!mad_send_wr) { - printk(KERN_ERR PFX "No memory for " - "ib_mad_send_wr_private\n"); - ret = -ENOMEM; - goto error2; - } - memset(mad_send_wr, 0, sizeof *mad_send_wr); - - mad_send_wr->send_wr = *send_wr; - mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; - memcpy(mad_send_wr->sg_list, send_wr->sg_list, - sizeof *send_wr->sg_list * send_wr->num_sge); - mad_send_wr->wr_id = send_wr->wr_id; - mad_send_wr->tid = send_wr->wr.ud.mad_hdr->tid; - mad_send_wr->mad_agent_priv = mad_agent_priv; + mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid; /* Timeout will be updated after send completes */ - mad_send_wr->timeout = msecs_to_jiffies(send_wr->wr. - ud.timeout_ms); - mad_send_wr->retries = mad_send_wr->send_wr.wr.ud.retries; - /* One reference for each work request to QP + response */ + mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms); + mad_send_wr->retries = send_buf->retries; + /* Reference for work request to QP + response */ mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); mad_send_wr->status = IB_WC_SUCCESS; @@ -995,16 +962,13 @@ int ib_post_send_mad(struct ib_mad_agent *mad_agent, list_del(&mad_send_wr->agent_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); atomic_dec(&mad_agent_priv->refcount); - goto error2; + goto error; } -next: - send_wr = next_send_wr; } return 0; - -error2: - *bad_send_wr = send_wr; -error1: +error: + if (bad_send_buf) + *bad_send_buf = send_buf; return ret; } EXPORT_SYMBOL(ib_post_send_mad); @@ -1447,8 +1411,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv, * of MAD. */ hi_tid = be64_to_cpu(mad->mad_hdr.tid) >> 32; - list_for_each_entry(entry, &port_priv->agent_list, - agent_list) { + list_for_each_entry(entry, &port_priv->agent_list, agent_list) { if (entry->agent.hi_tid == hi_tid) { mad_agent = entry; break; @@ -1571,8 +1534,7 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) */ list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, agent_list) { - if (is_data_mad(mad_agent_priv, - mad_send_wr->send_wr.wr.ud.mad_hdr) && + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && mad_send_wr->tid == tid && mad_send_wr->timeout) { /* Verify request has not been canceled */ return (mad_send_wr->status == IB_WC_SUCCESS) ? @@ -1628,14 +1590,14 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, spin_unlock_irqrestore(&mad_agent_priv->lock, flags); /* Defined behavior is to complete response before request */ - mad_recv_wc->wc->wr_id = mad_send_wr->wr_id; + mad_recv_wc->wc->wr_id = (unsigned long) &mad_send_wr->send_buf; mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, mad_recv_wc); atomic_dec(&mad_agent_priv->refcount); mad_send_wc.status = IB_WC_SUCCESS; mad_send_wc.vendor_err = 0; - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); } else { mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, @@ -1728,11 +1690,11 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, if (ret & IB_MAD_RESULT_CONSUMED) goto out; if (ret & IB_MAD_RESULT_REPLY) { - /* Send response */ - if (!agent_send(response, &recv->grh, wc, - port_priv->device, - port_priv->port_num)) - response = NULL; + agent_send_response(&response->mad.mad, + &recv->grh, wc, + port_priv->device, + port_priv->port_num, + qp_info->qp->qp_num); goto out; } } @@ -1866,15 +1828,15 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, if (mad_send_wr->status != IB_WC_SUCCESS ) mad_send_wc->status = mad_send_wr->status; - if (ret != IB_RMPP_RESULT_INTERNAL) + if (ret == IB_RMPP_RESULT_INTERNAL) + ib_rmpp_send_handler(mad_send_wc); + else mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, mad_send_wc); /* Release reference on agent taken when sending */ if (atomic_dec_and_test(&mad_agent_priv->refcount)) wake_up(&mad_agent_priv->wait); - - kfree(mad_send_wr); return; done: spin_unlock_irqrestore(&mad_agent_priv->lock, flags); @@ -1888,6 +1850,7 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, struct ib_mad_qp_info *qp_info; struct ib_mad_queue *send_queue; struct ib_send_wr *bad_send_wr; + struct ib_mad_send_wc mad_send_wc; unsigned long flags; int ret; @@ -1898,6 +1861,9 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, qp_info = send_queue->qp_info; retry: + dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, + pci_unmap_addr(mad_send_wr, mapping), + mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); queued_send_wr = NULL; spin_lock_irqsave(&send_queue->lock, flags); list_del(&mad_list->list); @@ -1914,17 +1880,17 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, } spin_unlock_irqrestore(&send_queue->lock, flags); - /* Restore client wr_id in WC and complete send */ - wc->wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + mad_send_wc.status = wc->status; + mad_send_wc.vendor_err = wc->vendor_err; if (atomic_read(&qp_info->snoop_count)) - snoop_send(qp_info, &mad_send_wr->send_wr, - (struct ib_mad_send_wc *)wc, + snoop_send(qp_info, &mad_send_wr->send_buf, &mad_send_wc, IB_MAD_SNOOP_SEND_COMPLETIONS); - ib_mad_complete_send_wr(mad_send_wr, (struct ib_mad_send_wc *)wc); + ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); if (queued_send_wr) { ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr, - &bad_send_wr); + &bad_send_wr); if (ret) { printk(KERN_ERR PFX "ib_post_send failed: %d\n", ret); mad_send_wr = queued_send_wr; @@ -2066,38 +2032,37 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, &cancel_list, agent_list) { - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + list_del(&mad_send_wr->agent_list); mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); - - list_del(&mad_send_wr->agent_list); - kfree(mad_send_wr); atomic_dec(&mad_agent_priv->refcount); } } static struct ib_mad_send_wr_private* -find_send_by_wr_id(struct ib_mad_agent_private *mad_agent_priv, u64 wr_id) +find_send_wr(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_send_buf *send_buf) { struct ib_mad_send_wr_private *mad_send_wr; list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, agent_list) { - if (mad_send_wr->wr_id == wr_id) + if (&mad_send_wr->send_buf == send_buf) return mad_send_wr; } list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, agent_list) { - if (is_data_mad(mad_agent_priv, - mad_send_wr->send_wr.wr.ud.mad_hdr) && - mad_send_wr->wr_id == wr_id) + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && + &mad_send_wr->send_buf == send_buf) return mad_send_wr; } return NULL; } -int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_send_wr_private *mad_send_wr; @@ -2107,7 +2072,7 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, agent); spin_lock_irqsave(&mad_agent_priv->lock, flags); - mad_send_wr = find_send_by_wr_id(mad_agent_priv, wr_id); + mad_send_wr = find_send_wr(mad_agent_priv, send_buf); if (!mad_send_wr || mad_send_wr->status != IB_WC_SUCCESS) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); return -EINVAL; @@ -2119,7 +2084,7 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) mad_send_wr->refcount -= (mad_send_wr->timeout > 0); } - mad_send_wr->send_wr.wr.ud.timeout_ms = timeout_ms; + mad_send_wr->send_buf.timeout_ms = timeout_ms; if (active) mad_send_wr->timeout = msecs_to_jiffies(timeout_ms); else @@ -2130,9 +2095,10 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) } EXPORT_SYMBOL(ib_modify_mad); -void ib_cancel_mad(struct ib_mad_agent *mad_agent, u64 wr_id) +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf) { - ib_modify_mad(mad_agent, wr_id, 0); + ib_modify_mad(mad_agent, send_buf, 0); } EXPORT_SYMBOL(ib_cancel_mad); @@ -2166,10 +2132,9 @@ static void local_completions(void *data) * Defined behavior is to complete response * before request */ - build_smp_wc(local->wr_id, + build_smp_wc((unsigned long) local->mad_send_wr, be16_to_cpu(IB_LID_PERMISSIVE), - 0 /* pkey index */, - recv_mad_agent->agent.port_num, &wc); + 0, recv_mad_agent->agent.port_num, &wc); local->mad_priv->header.recv_wc.wc = &wc; local->mad_priv->header.recv_wc.mad_len = @@ -2196,11 +2161,11 @@ static void local_completions(void *data) /* Complete send */ mad_send_wc.status = IB_WC_SUCCESS; mad_send_wc.vendor_err = 0; - mad_send_wc.wr_id = local->wr_id; + mad_send_wc.send_buf = &local->mad_send_wr->send_buf; if (atomic_read(&mad_agent_priv->qp_info->snoop_count)) - snoop_send(mad_agent_priv->qp_info, &local->send_wr, - &mad_send_wc, - IB_MAD_SNOOP_SEND_COMPLETIONS); + snoop_send(mad_agent_priv->qp_info, + &local->mad_send_wr->send_buf, + &mad_send_wc, IB_MAD_SNOOP_SEND_COMPLETIONS); mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); @@ -2221,8 +2186,7 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) if (!mad_send_wr->retries--) return -ETIMEDOUT; - mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_wr. - wr.ud.timeout_ms); + mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); if (mad_send_wr->mad_agent_priv->agent.rmpp_version) { ret = ib_retry_rmpp(mad_send_wr); @@ -2285,11 +2249,10 @@ static void timeout_sends(void *data) mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR; else mad_send_wc.status = mad_send_wr->status; - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); - kfree(mad_send_wr); atomic_dec(&mad_agent_priv->refcount); spin_lock_irqsave(&mad_agent_priv->lock, flags); } @@ -2761,7 +2724,6 @@ static int __init ib_mad_init_module(void) int ret; spin_lock_init(&ib_mad_port_list_lock); - spin_lock_init(&ib_agent_port_list_lock); ib_mad_cache = kmem_cache_create("ib_mad", sizeof(struct ib_mad_private), diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index f1ba794e0daa..570f78682af3 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -118,9 +118,10 @@ struct ib_mad_send_wr_private { struct ib_mad_list_head mad_list; struct list_head agent_list; struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_buf send_buf; + DECLARE_PCI_UNMAP_ADDR(mapping) struct ib_send_wr send_wr; struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; - u64 wr_id; /* client WR ID */ __be64 tid; unsigned long timeout; int retries; @@ -141,10 +142,7 @@ struct ib_mad_local_private { struct list_head completion_list; struct ib_mad_private *mad_priv; struct ib_mad_agent_private *recv_mad_agent; - struct ib_send_wr send_wr; - struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; - u64 wr_id; /* client WR ID */ - __be64 tid; + struct ib_mad_send_wr_private *mad_send_wr; }; struct ib_mad_mgmt_method_table { diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index e23836d0e21b..ba112cd5f93c 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -103,12 +103,12 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent) static int data_offset(u8 mgmt_class) { if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) - return offsetof(struct ib_sa_mad, data); + return IB_MGMT_SA_HDR; else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) - return offsetof(struct ib_vendor_mad, data); + return IB_MGMT_VENDOR_HDR; else - return offsetof(struct ib_rmpp_mad, data); + return IB_MGMT_RMPP_HDR; } static void format_ack(struct ib_rmpp_mad *ack, @@ -135,21 +135,18 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, struct ib_mad_recv_wc *recv_wc) { struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; - int hdr_len, ret; + int ret; - hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr); msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, - recv_wc->wc->pkey_index, rmpp_recv->ah, 1, - hdr_len, sizeof(struct ib_rmpp_mad) - hdr_len, - GFP_KERNEL); + recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR, + IB_MGMT_RMPP_DATA, GFP_KERNEL); if (!msg) return; - format_ack((struct ib_rmpp_mad *) msg->mad, - (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); - ret = ib_post_send_mad(&rmpp_recv->agent->agent, &msg->send_wr, - &bad_send_wr); + format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, + rmpp_recv); + msg->ah = rmpp_recv->ah; + ret = ib_post_send_mad(msg, NULL); if (ret) ib_free_send_mad(msg); } @@ -160,30 +157,31 @@ static int alloc_response_msg(struct ib_mad_agent *agent, { struct ib_mad_send_buf *m; struct ib_ah *ah; - int hdr_len; ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, recv_wc->recv_buf.grh, agent->port_num); if (IS_ERR(ah)) return PTR_ERR(ah); - hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr); m = ib_create_send_mad(agent, recv_wc->wc->src_qp, - recv_wc->wc->pkey_index, ah, 1, hdr_len, - sizeof(struct ib_rmpp_mad) - hdr_len, - GFP_KERNEL); + recv_wc->wc->pkey_index, 1, + IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, GFP_KERNEL); if (IS_ERR(m)) { ib_destroy_ah(ah); return PTR_ERR(m); } + m->ah = ah; *msg = m; return 0; } -static void free_msg(struct ib_mad_send_buf *msg) +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc) { - ib_destroy_ah(msg->send_wr.wr.ud.ah); - ib_free_send_mad(msg); + struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad; + + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_ACK) + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); } static void nack_recv(struct ib_mad_agent_private *agent, @@ -191,14 +189,13 @@ static void nack_recv(struct ib_mad_agent_private *agent, { struct ib_mad_send_buf *msg; struct ib_rmpp_mad *rmpp_mad; - struct ib_send_wr *bad_send_wr; int ret; ret = alloc_response_msg(&agent->agent, recv_wc, &msg); if (ret) return; - rmpp_mad = (struct ib_rmpp_mad *) msg->mad; + rmpp_mad = msg->mad; memcpy(rmpp_mad, recv_wc->recv_buf.mad, data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class)); @@ -210,9 +207,11 @@ static void nack_recv(struct ib_mad_agent_private *agent, rmpp_mad->rmpp_hdr.seg_num = 0; rmpp_mad->rmpp_hdr.paylen_newwin = 0; - ret = ib_post_send_mad(&agent->agent, &msg->send_wr, &bad_send_wr); - if (ret) - free_msg(msg); + ret = ib_post_send_mad(msg, NULL); + if (ret) { + ib_destroy_ah(msg->ah); + ib_free_send_mad(msg); + } } static void recv_timeout_handler(void *data) @@ -585,7 +584,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) int timeout; u32 paylen; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num); @@ -612,7 +611,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) } /* 2 seconds for an ACK until we can find the packet lifetime */ - timeout = mad_send_wr->send_wr.wr.ud.timeout_ms; + timeout = mad_send_wr->send_buf.timeout_ms; if (!timeout || timeout > 2000) mad_send_wr->timeout = msecs_to_jiffies(2000); mad_send_wr->seg_num++; @@ -640,7 +639,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, wc.status = IB_WC_REM_ABORT_ERR; wc.vendor_err = rmpp_status; - wc.wr_id = mad_send_wr->wr_id; + wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &wc); return; out: @@ -694,12 +693,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, if (seg_num > mad_send_wr->last_ack) { mad_send_wr->last_ack = seg_num; - mad_send_wr->retries = mad_send_wr->send_wr.wr.ud.retries; + mad_send_wr->retries = mad_send_wr->send_buf.retries; } mad_send_wr->newwin = newwin; if (mad_send_wr->last_ack == mad_send_wr->total_seg) { /* If no response is expected, the ACK completes the send */ - if (!mad_send_wr->send_wr.wr.ud.timeout_ms) { + if (!mad_send_wr->send_buf.timeout_ms) { struct ib_mad_send_wc wc; ib_mark_mad_done(mad_send_wr); @@ -707,13 +706,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, wc.status = IB_WC_SUCCESS; wc.vendor_err = 0; - wc.wr_id = mad_send_wr->wr_id; + wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &wc); return; } if (mad_send_wr->refcount == 1) - ib_reset_mad_timeout(mad_send_wr, mad_send_wr-> - send_wr.wr.ud.timeout_ms); + ib_reset_mad_timeout(mad_send_wr, + mad_send_wr->send_buf.timeout_ms); } else if (mad_send_wr->refcount == 1 && mad_send_wr->seg_num < mad_send_wr->newwin && mad_send_wr->seg_num <= mad_send_wr->total_seg) { @@ -842,7 +841,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) struct ib_rmpp_mad *rmpp_mad; int i, total_len, ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; @@ -863,7 +862,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) / (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset); - mad_send_wr->pad = total_len - offsetof(struct ib_rmpp_mad, data) - + mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); /* We need to wait for the final ACK even if there isn't a response */ @@ -878,23 +877,15 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, struct ib_mad_send_wc *mad_send_wc) { struct ib_rmpp_mad *rmpp_mad; - struct ib_mad_send_buf *msg; int ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ - if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) { - msg = (struct ib_mad_send_buf *) (unsigned long) - mad_send_wc->wr_id; - if (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_ACK) - ib_free_send_mad(msg); - else - free_msg(msg); + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) return IB_RMPP_RESULT_INTERNAL; /* ACK, STOP, or ABORT */ - } if (mad_send_wc->status != IB_WC_SUCCESS || mad_send_wr->status != IB_WC_SUCCESS) @@ -905,7 +896,7 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, if (mad_send_wr->last_ack == mad_send_wr->total_seg) { mad_send_wr->timeout = - msecs_to_jiffies(mad_send_wr->send_wr.wr.ud.timeout_ms); + msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); return IB_RMPP_RESULT_PROCESSED; /* Send done */ } @@ -926,7 +917,7 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr) struct ib_rmpp_mad *rmpp_mad; int ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ diff --git a/drivers/infiniband/core/mad_rmpp.h b/drivers/infiniband/core/mad_rmpp.h index c4924dfb8e75..f0616fd22494 100644 --- a/drivers/infiniband/core/mad_rmpp.h +++ b/drivers/infiniband/core/mad_rmpp.h @@ -51,6 +51,8 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, struct ib_mad_send_wc *mad_send_wc); +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc); + void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent); int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 0e5ef97f7637..89ce9dc210d4 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -73,11 +73,10 @@ struct ib_sa_device { struct ib_sa_query { void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *); void (*release)(struct ib_sa_query *); - struct ib_sa_port *port; - struct ib_sa_mad *mad; - struct ib_sa_sm_ah *sm_ah; - DECLARE_PCI_UNMAP_ADDR(mapping) - int id; + struct ib_sa_port *port; + struct ib_mad_send_buf *mad_buf; + struct ib_sa_sm_ah *sm_ah; + int id; }; struct ib_sa_service_query { @@ -426,6 +425,7 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) { unsigned long flags; struct ib_mad_agent *agent; + struct ib_mad_send_buf *mad_buf; spin_lock_irqsave(&idr_lock, flags); if (idr_find(&query_idr, id) != query) { @@ -433,9 +433,10 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) return; } agent = query->port->agent; + mad_buf = query->mad_buf; spin_unlock_irqrestore(&idr_lock, flags); - ib_cancel_mad(agent, id); + ib_cancel_mad(agent, mad_buf); } EXPORT_SYMBOL(ib_sa_cancel_query); @@ -457,71 +458,46 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) static int send_mad(struct ib_sa_query *query, int timeout_ms) { - struct ib_sa_port *port = query->port; unsigned long flags; - int ret; - struct ib_sge gather_list; - struct ib_send_wr *bad_wr, wr = { - .opcode = IB_WR_SEND, - .sg_list = &gather_list, - .num_sge = 1, - .send_flags = IB_SEND_SIGNALED, - .wr = { - .ud = { - .mad_hdr = &query->mad->mad_hdr, - .remote_qpn = 1, - .remote_qkey = IB_QP1_QKEY, - .timeout_ms = timeout_ms, - } - } - }; + int ret, id; retry: if (!idr_pre_get(&query_idr, GFP_ATOMIC)) return -ENOMEM; spin_lock_irqsave(&idr_lock, flags); - ret = idr_get_new(&query_idr, query, &query->id); + ret = idr_get_new(&query_idr, query, &id); spin_unlock_irqrestore(&idr_lock, flags); if (ret == -EAGAIN) goto retry; if (ret) return ret; - wr.wr_id = query->id; + query->mad_buf->timeout_ms = timeout_ms; + query->mad_buf->context[0] = query; + query->id = id; - spin_lock_irqsave(&port->ah_lock, flags); - kref_get(&port->sm_ah->ref); - query->sm_ah = port->sm_ah; - wr.wr.ud.ah = port->sm_ah->ah; - spin_unlock_irqrestore(&port->ah_lock, flags); + spin_lock_irqsave(&query->port->ah_lock, flags); + kref_get(&query->port->sm_ah->ref); + query->sm_ah = query->port->sm_ah; + spin_unlock_irqrestore(&query->port->ah_lock, flags); - gather_list.addr = dma_map_single(port->agent->device->dma_device, - query->mad, - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - gather_list.length = sizeof (struct ib_sa_mad); - gather_list.lkey = port->agent->mr->lkey; - pci_unmap_addr_set(query, mapping, gather_list.addr); + query->mad_buf->ah = query->sm_ah->ah; - ret = ib_post_send_mad(port->agent, &wr, &bad_wr); + ret = ib_post_send_mad(query->mad_buf, NULL); if (ret) { - dma_unmap_single(port->agent->device->dma_device, - pci_unmap_addr(query, mapping), - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - kref_put(&query->sm_ah->ref, free_sm_ah); spin_lock_irqsave(&idr_lock, flags); - idr_remove(&query_idr, query->id); + idr_remove(&query_idr, id); spin_unlock_irqrestore(&idr_lock, flags); + + kref_put(&query->sm_ah->ref, free_sm_ah); } /* * It's not safe to dereference query any more, because the * send may already have completed and freed the query in - * another context. So use wr.wr_id, which has a copy of the - * query's id. + * another context. */ - return ret ? ret : wr.wr_id; + return ret ? ret : id; } static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, @@ -543,7 +519,6 @@ static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_path_query, sa_query)); } @@ -585,6 +560,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); struct ib_sa_port *port; struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; if (!sa_dev) @@ -596,37 +572,45 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; - query->sa_query.release = ib_sa_path_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; - query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; + query->sa_query.release = ib_sa_path_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = IB_MGMT_METHOD_GET; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); + mad->sa_hdr.comp_mask = comp_mask; - ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), - rec, query->sa_query.mad->data); + ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; return ret; + +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); + return ret; } EXPORT_SYMBOL(ib_sa_path_rec_get); @@ -649,7 +633,6 @@ static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_service_query, sa_query)); } @@ -693,6 +676,7 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); struct ib_sa_port *port; struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; if (!sa_dev) @@ -709,38 +693,46 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; - query->sa_query.release = ib_sa_service_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = method; - query->sa_query.mad->mad_hdr.attr_id = - cpu_to_be16(IB_SA_ATTR_SERVICE_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; + query->sa_query.release = ib_sa_service_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC); + mad->sa_hdr.comp_mask = comp_mask; ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), - rec, query->sa_query.mad->data); + rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; return ret; + +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); + return ret; } EXPORT_SYMBOL(ib_sa_service_rec_query); @@ -763,7 +755,6 @@ static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query)); } @@ -782,6 +773,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); struct ib_sa_port *port; struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; if (!sa_dev) @@ -793,53 +785,55 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; - query->sa_query.release = ib_sa_mcmember_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = method; - query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; + query->sa_query.release = ib_sa_mcmember_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); + mad->sa_hdr.comp_mask = comp_mask; ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), - rec, query->sa_query.mad->data); + rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; return ret; + +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); + return ret; } EXPORT_SYMBOL(ib_sa_mcmember_rec_query); static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_sa_query *query; + struct ib_sa_query *query = mad_send_wc->send_buf->context[0]; unsigned long flags; - spin_lock_irqsave(&idr_lock, flags); - query = idr_find(&query_idr, mad_send_wc->wr_id); - spin_unlock_irqrestore(&idr_lock, flags); - - if (!query) - return; - if (query->callback) switch (mad_send_wc->status) { case IB_WC_SUCCESS: @@ -856,30 +850,25 @@ static void send_handler(struct ib_mad_agent *agent, break; } - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(query, mapping), - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - kref_put(&query->sm_ah->ref, free_sm_ah); - - query->release(query); - spin_lock_irqsave(&idr_lock, flags); - idr_remove(&query_idr, mad_send_wc->wr_id); + idr_remove(&query_idr, query->id); spin_unlock_irqrestore(&idr_lock, flags); + + ib_free_send_mad(mad_send_wc->send_buf); + kref_put(&query->sm_ah->ref, free_sm_ah); + query->release(query); } static void recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_recv_wc *mad_recv_wc) { struct ib_sa_query *query; - unsigned long flags; + struct ib_mad_send_buf *mad_buf; - spin_lock_irqsave(&idr_lock, flags); - query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); - spin_unlock_irqrestore(&idr_lock, flags); + mad_buf = (void *) (unsigned long) mad_recv_wc->wc->wr_id; + query = mad_buf->context[0]; - if (query && query->callback) { + if (query->callback) { if (mad_recv_wc->wc->status == IB_WC_SUCCESS) query->callback(query, mad_recv_wc->recv_buf.mad->mad_hdr.status ? diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h index db25503a0736..2b3c40198f81 100644 --- a/drivers/infiniband/core/smi.h +++ b/drivers/infiniband/core/smi.h @@ -39,6 +39,8 @@ #ifndef __SMI_H_ #define __SMI_H_ +#include + int smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, int port_num, diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index fd200c064a2e..fc5519a3de99 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -96,7 +96,6 @@ struct ib_umad_file { }; struct ib_umad_packet { - struct ib_ah *ah; struct ib_mad_send_buf *msg; struct list_head list; int length; @@ -139,10 +138,10 @@ static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *send_wc) { struct ib_umad_file *file = agent->context; - struct ib_umad_packet *timeout, *packet = - (void *) (unsigned long) send_wc->wr_id; + struct ib_umad_packet *timeout; + struct ib_umad_packet *packet = send_wc->send_buf->context[0]; - ib_destroy_ah(packet->msg->send_wr.wr.ud.ah); + ib_destroy_ah(packet->msg->ah); ib_free_send_mad(packet->msg); if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { @@ -268,11 +267,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, struct ib_umad_packet *packet; struct ib_mad_agent *agent; struct ib_ah_attr ah_attr; - struct ib_send_wr *bad_wr; + struct ib_ah *ah; struct ib_rmpp_mad *rmpp_mad; u8 method; __be64 *tid; - int ret, length, hdr_len, data_len, rmpp_hdr_size; + int ret, length, hdr_len, rmpp_hdr_size; int rmpp_active = 0; if (count < sizeof (struct ib_user_mad)) @@ -321,9 +320,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class; } - packet->ah = ib_create_ah(agent->qp->pd, &ah_attr); - if (IS_ERR(packet->ah)) { - ret = PTR_ERR(packet->ah); + ah = ib_create_ah(agent->qp->pd, &ah_attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); goto err_up; } @@ -337,12 +336,10 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, /* Validate that the management class can support RMPP */ if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { - hdr_len = offsetof(struct ib_sa_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_SA_HDR; } else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && (rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) { - hdr_len = offsetof(struct ib_vendor_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_VENDOR_HDR; } else { ret = -EINVAL; goto err_ah; @@ -353,25 +350,23 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ret = -EINVAL; goto err_ah; } - hdr_len = offsetof(struct ib_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_MAD_HDR; } packet->msg = ib_create_send_mad(agent, be32_to_cpu(packet->mad.hdr.qpn), - 0, packet->ah, rmpp_active, - hdr_len, data_len, + 0, rmpp_active, + hdr_len, length - hdr_len, GFP_KERNEL); if (IS_ERR(packet->msg)) { ret = PTR_ERR(packet->msg); goto err_ah; } - packet->msg->send_wr.wr.ud.timeout_ms = packet->mad.hdr.timeout_ms; - packet->msg->send_wr.wr.ud.retries = packet->mad.hdr.retries; - - /* Override send WR WRID initialized in ib_create_send_mad */ - packet->msg->send_wr.wr_id = (unsigned long) packet; + packet->msg->ah = ah; + packet->msg->timeout_ms = packet->mad.hdr.timeout_ms; + packet->msg->retries = packet->mad.hdr.retries; + packet->msg->context[0] = packet; if (!rmpp_active) { /* Copy message from user into send buffer */ @@ -403,17 +398,17 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, * transaction ID matches the agent being used to send the * MAD. */ - method = packet->msg->mad->mad_hdr.method; + method = ((struct ib_mad_hdr *) packet->msg)->method; if (!(method & IB_MGMT_METHOD_RESP) && method != IB_MGMT_METHOD_TRAP_REPRESS && method != IB_MGMT_METHOD_SEND) { - tid = &packet->msg->mad->mad_hdr.tid; + tid = &((struct ib_mad_hdr *) packet->msg)->tid; *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | (be64_to_cpup(tid) & 0xffffffff)); } - ret = ib_post_send_mad(agent, &packet->msg->send_wr, &bad_wr); + ret = ib_post_send_mad(packet->msg, NULL); if (ret) goto err_msg; @@ -425,7 +420,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ib_free_send_mad(packet->msg); err_ah: - ib_destroy_ah(packet->ah); + ib_destroy_ah(ah); err_up: up_read(&file->agent_mutex); diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 9804174f7f3c..8561b297a19b 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c @@ -46,11 +46,6 @@ enum { MTHCA_VENDOR_CLASS2 = 0xa }; -struct mthca_trap_mad { - struct ib_mad *mad; - DECLARE_PCI_UNMAP_ADDR(mapping) -}; - static void update_sm_ah(struct mthca_dev *dev, u8 port_num, u16 lid, u8 sl) { @@ -116,49 +111,14 @@ static void forward_trap(struct mthca_dev *dev, struct ib_mad *mad) { int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; - struct mthca_trap_mad *tmad; - struct ib_sge gather_list; - struct ib_send_wr *bad_wr, wr = { - .opcode = IB_WR_SEND, - .sg_list = &gather_list, - .num_sge = 1, - .send_flags = IB_SEND_SIGNALED, - .wr = { - .ud = { - .remote_qpn = qpn, - .remote_qkey = qpn ? IB_QP1_QKEY : 0, - .timeout_ms = 0 - } - } - }; + struct ib_mad_send_buf *send_buf; struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; int ret; unsigned long flags; if (agent) { - tmad = kmalloc(sizeof *tmad, GFP_KERNEL); - if (!tmad) - return; - - tmad->mad = kmalloc(sizeof *tmad->mad, GFP_KERNEL); - if (!tmad->mad) { - kfree(tmad); - return; - } - - memcpy(tmad->mad, mad, sizeof *mad); - - wr.wr.ud.mad_hdr = &tmad->mad->mad_hdr; - wr.wr_id = (unsigned long) tmad; - - gather_list.addr = dma_map_single(agent->device->dma_device, - tmad->mad, - sizeof *tmad->mad, - DMA_TO_DEVICE); - gather_list.length = sizeof *tmad->mad; - gather_list.lkey = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey; - pci_unmap_addr_set(tmad, mapping, gather_list.addr); - + send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, + IB_MGMT_MAD_DATA, GFP_ATOMIC); /* * We rely here on the fact that MLX QPs don't use the * address handle after the send is posted (this is @@ -166,21 +126,15 @@ static void forward_trap(struct mthca_dev *dev, * it's OK for our devices). */ spin_lock_irqsave(&dev->sm_lock, flags); - wr.wr.ud.ah = dev->sm_ah[port_num - 1]; - if (wr.wr.ud.ah) - ret = ib_post_send_mad(agent, &wr, &bad_wr); + memcpy(send_buf->mad, mad, sizeof *mad); + if ((send_buf->ah = dev->sm_ah[port_num - 1])) + ret = ib_post_send_mad(send_buf, NULL); else ret = -EINVAL; spin_unlock_irqrestore(&dev->sm_lock, flags); - if (ret) { - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(tmad, mapping), - sizeof *tmad->mad, - DMA_TO_DEVICE); - kfree(tmad->mad); - kfree(tmad); - } + if (ret) + ib_free_send_mad(send_buf); } } @@ -267,15 +221,7 @@ int mthca_process_mad(struct ib_device *ibdev, static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) { - struct mthca_trap_mad *tmad = - (void *) (unsigned long) mad_send_wc->wr_id; - - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(tmad, mapping), - sizeof *tmad->mad, - DMA_TO_DEVICE); - kfree(tmad->mad); - kfree(tmad); + ib_free_send_mad(mad_send_wc->send_buf); } int mthca_create_agents(struct mthca_dev *dev) diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 4172e6841e3d..2c133506742b 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -109,10 +109,14 @@ #define IB_QP_SET_QKEY 0x80000000 enum { + IB_MGMT_MAD_HDR = 24, IB_MGMT_MAD_DATA = 232, + IB_MGMT_RMPP_HDR = 36, IB_MGMT_RMPP_DATA = 220, + IB_MGMT_VENDOR_HDR = 40, IB_MGMT_VENDOR_DATA = 216, - IB_MGMT_SA_DATA = 200 + IB_MGMT_SA_HDR = 56, + IB_MGMT_SA_DATA = 200, }; struct ib_mad_hdr { @@ -203,26 +207,25 @@ struct ib_class_port_info /** * ib_mad_send_buf - MAD data buffer and work request for sends. - * @mad: References an allocated MAD data buffer. The size of the data - * buffer is specified in the @send_wr.length field. - * @mapping: DMA mapping information. + * @next: A pointer used to chain together MADs for posting. + * @mad: References an allocated MAD data buffer. * @mad_agent: MAD agent that allocated the buffer. + * @ah: The address handle to use when sending the MAD. * @context: User-controlled context fields. - * @send_wr: An initialized work request structure used when sending the MAD. - * The wr_id field of the work request is initialized to reference this - * data structure. - * @sge: A scatter-gather list referenced by the work request. + * @timeout_ms: Time to wait for a response. + * @retries: Number of times to retry a request for a response. * * Users are responsible for initializing the MAD buffer itself, with the * exception of specifying the payload length field in any RMPP MAD. */ struct ib_mad_send_buf { - struct ib_mad *mad; - DECLARE_PCI_UNMAP_ADDR(mapping) + struct ib_mad_send_buf *next; + void *mad; struct ib_mad_agent *mad_agent; + struct ib_ah *ah; void *context[2]; - struct ib_send_wr send_wr; - struct ib_sge sge; + int timeout_ms; + int retries; }; /** @@ -287,7 +290,7 @@ typedef void (*ib_mad_send_handler)(struct ib_mad_agent *mad_agent, * or @mad_send_wc. */ typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent, - struct ib_send_wr *send_wr, + struct ib_mad_send_buf *send_buf, struct ib_mad_send_wc *mad_send_wc); /** @@ -334,13 +337,13 @@ struct ib_mad_agent { /** * ib_mad_send_wc - MAD send completion information. - * @wr_id: Work request identifier associated with the send MAD request. + * @send_buf: Send MAD data buffer associated with the send MAD request. * @status: Completion status. * @vendor_err: Optional vendor error information returned with a failed * request. */ struct ib_mad_send_wc { - u64 wr_id; + struct ib_mad_send_buf *send_buf; enum ib_wc_status status; u32 vendor_err; }; @@ -366,7 +369,7 @@ struct ib_mad_recv_buf { * @rmpp_list: Specifies a list of RMPP reassembled received MAD buffers. * @mad_len: The length of the received MAD, without duplicated headers. * - * For received response, the wr_id field of the wc is set to the wr_id + * For received response, the wr_id contains a pointer to the ib_mad_send_buf * for the corresponding send request. */ struct ib_mad_recv_wc { @@ -463,9 +466,9 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent); /** * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated * with the registered client. - * @mad_agent: Specifies the associated registration to post the send to. - * @send_wr: Specifies the information needed to send the MAD(s). - * @bad_send_wr: Specifies the MAD on which an error was encountered. + * @send_buf: Specifies the information needed to send the MAD(s). + * @bad_send_buf: Specifies the MAD on which an error was encountered. This + * parameter is optional if only a single MAD is posted. * * Sent MADs are not guaranteed to complete in the order that they were posted. * @@ -479,9 +482,8 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent); * defined data being transferred. The paylen_newwin field should be * specified in network-byte order. */ -int ib_post_send_mad(struct ib_mad_agent *mad_agent, - struct ib_send_wr *send_wr, - struct ib_send_wr **bad_send_wr); +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf); /** * ib_coalesce_recv_mad - Coalesces received MAD data into a single buffer. @@ -507,23 +509,25 @@ void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc); /** * ib_cancel_mad - Cancels an outstanding send MAD operation. * @mad_agent: Specifies the registration associated with sent MAD. - * @wr_id: Indicates the work request identifier of the MAD to cancel. + * @send_buf: Indicates the MAD to cancel. * * MADs will be returned to the user through the corresponding * ib_mad_send_handler. */ -void ib_cancel_mad(struct ib_mad_agent *mad_agent, u64 wr_id); +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf); /** * ib_modify_mad - Modifies an outstanding send MAD operation. * @mad_agent: Specifies the registration associated with sent MAD. - * @wr_id: Indicates the work request identifier of the MAD to modify. + * @send_buf: Indicates the MAD to modify. * @timeout_ms: New timeout value for sent MAD. * * This call will reset the timeout value for a sent MAD to the specified * value. */ -int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms); +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms); /** * ib_redirect_mad_qp - Registers a QP for MAD services. @@ -572,7 +576,6 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent, * @remote_qpn: Specifies the QPN of the receiving node. * @pkey_index: Specifies which PKey the MAD will be sent using. This field * is valid only if the remote_qpn is QP 1. - * @ah: References the address handle used to transfer to the remote node. * @rmpp_active: Indicates if the send will enable RMPP. * @hdr_len: Indicates the size of the data header of the MAD. This length * should include the common MAD header, RMPP header, plus any class @@ -582,11 +585,10 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent, * additional padding that may be necessary. * @gfp_mask: GFP mask used for the memory allocation. * - * This is a helper routine that may be used to allocate a MAD. Users are - * not required to allocate outbound MADs using this call. The returned - * MAD send buffer will reference a data buffer usable for sending a MAD, along + * This routine allocates a MAD for sending. The returned MAD send buffer + * will reference a data buffer usable for sending a MAD, along * with an initialized work request structure. Users may modify the returned - * MAD data buffer or work request before posting the send. + * MAD data buffer before posting the send. * * The returned data buffer will be cleared. Users are responsible for * initializing the common MAD and any class specific headers. If @rmpp_active @@ -594,7 +596,7 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent, */ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, u32 remote_qpn, u16 pkey_index, - struct ib_ah *ah, int rmpp_active, + int rmpp_active, int hdr_len, int data_len, gfp_t gfp_mask); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index a5a963cb5676..f72d46d54e0a 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -595,11 +595,8 @@ struct ib_send_wr { } atomic; struct { struct ib_ah *ah; - struct ib_mad_hdr *mad_hdr; u32 remote_qpn; u32 remote_qkey; - int timeout_ms; /* valid for MADs only */ - int retries; /* valid for MADs only */ u16 pkey_index; /* valid for GSI only */ u8 port_num; /* valid for DR SMPs on switch only */ } ud; From 547e3090738b04be650770b64265835dbb6ddf92 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 25 Oct 2005 10:57:32 -0700 Subject: [PATCH 0682/1939] [IB] mthca: correct modify QP attribute masks for UC The UC transport does not support RDMA reads or atomic operations, so we shouldn't require or even allow the consumer to set attributes relating to these operations for UC QPs. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 2ee0a2b0fd4b..62ff091505da 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -338,8 +338,7 @@ static const struct { [UC] = (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | - IB_QP_RQ_PSN | - IB_QP_MAX_DEST_RD_ATOMIC), + IB_QP_RQ_PSN), [RC] = (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | @@ -368,8 +367,7 @@ static const struct { .trans = MTHCA_TRANS_RTR2RTS, .req_param = { [UD] = IB_QP_SQ_PSN, - [UC] = (IB_QP_SQ_PSN | - IB_QP_MAX_QP_RD_ATOMIC), + [UC] = IB_QP_SQ_PSN, [RC] = (IB_QP_TIMEOUT | IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | @@ -446,8 +444,6 @@ static const struct { [UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), [UC] = (IB_QP_AV | - IB_QP_MAX_QP_RD_ATOMIC | - IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | @@ -478,7 +474,7 @@ static const struct { .opt_param = { [UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), - [UC] = (IB_QP_CUR_STATE), + [UC] = IB_QP_CUR_STATE, [RC] = (IB_QP_CUR_STATE | IB_QP_MIN_RNR_TIMER), [MLX] = (IB_QP_CUR_STATE | From 444d1d9bb5b724f03344c9317bc01d54a9b39073 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 25 Oct 2005 11:00:56 -0700 Subject: [PATCH 0683/1939] [PATCH] qlogic lockup fix If qla2x00_probe_one()'s call to qla2x00_iospace_config() fails, we call qla2x00_free_device() to clean up. But because ha->dpc_pid hasn't been set yet, qla2x00_free_device() tries to stop a kernel thread which hasn't started yet. It does wait_for_completion() against an uninitialised completion struct and the kernel hangs up. Fix it by initialising ha->dpc_pid a bit earlier. Cc: Andrew Vasquez Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/qla2xxx/qla_os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8982978c42fd..7aec93f9d423 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1325,6 +1325,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->brd_info = brd_info; sprintf(ha->host_str, "%s_%ld", ha->brd_info->drv_name, ha->host_no); + ha->dpc_pid = -1; + /* Configure PCI I/O space */ ret = qla2x00_iospace_config(ha); if (ret) @@ -1448,7 +1450,6 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) */ spin_lock_init(&ha->mbx_reg_lock); - ha->dpc_pid = -1; init_completion(&ha->dpc_inited); init_completion(&ha->dpc_exited); From b6a7e1ecef66b9ecd1eed31f46ba0248d6d7e957 Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Thu, 20 Oct 2005 12:31:19 +1000 Subject: [PATCH 0684/1939] [IA64] Allow simulator to use bigger disks The simscsi code at present overflows an int if it's given a large disk image. The attached patch increases the possible size to 128G. While it's unlikely that anyone will want to use SKI with such a large drive, the same framework is currently being used for various virtualisation experiments. Signed-off-by: Peter Chubb Signed-off-by: Tony Luck --- arch/ia64/hp/sim/simscsi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index a18983a3c934..a3fe97531134 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -205,10 +205,11 @@ simscsi_get_disk_size (int fd) char buf[512]; /* - * This is a bit kludgey: the simulator doesn't provide a direct way of determining - * the disk size, so we do a binary search, assuming a maximum disk size of 4GB. + * This is a bit kludgey: the simulator doesn't provide a + * direct way of determining the disk size, so we do a binary + * search, assuming a maximum disk size of 128GB. */ - for (bit = (4UL << 30)/512; bit != 0; bit >>= 1) { + for (bit = (128UL << 30)/512; bit != 0; bit >>= 1) { req.addr = __pa(&buf); req.len = sizeof(buf); ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ); @@ -225,8 +226,10 @@ simscsi_readwrite10 (struct scsi_cmnd *sc, int mode) { unsigned long offset; - offset = ( (sc->cmnd[2] << 24) | (sc->cmnd[3] << 16) - | (sc->cmnd[4] << 8) | (sc->cmnd[5] << 0))*512; + offset = (((unsigned long)sc->cmnd[2] << 24) + | ((unsigned long)sc->cmnd[3] << 16) + | ((unsigned long)sc->cmnd[4] << 8) + | ((unsigned long)sc->cmnd[5] << 0))*512UL; if (sc->use_sg > 0) simscsi_sg_readwrite(sc, mode, offset); else From ce6e71ad4866dad366be135b024b776c00ec9ec8 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Tue, 4 Oct 2005 16:35:31 -0700 Subject: [PATCH 0685/1939] [IA64] fix siblings field value in /proc/cpuinfo Fix the "siblings" field value in /proc/cpuinfo so that it now shows the number of siblings as seen by OS, instead of what is available from hardware perspective. Signed-off-by: Suresh Siddha Signed-off-by: Tony Luck --- arch/ia64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 1f5c26dbe705..0ca6ef103952 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -526,7 +526,7 @@ show_cpuinfo (struct seq_file *m, void *v) c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); #ifdef CONFIG_SMP - seq_printf(m, "siblings : %u\n", c->num_log); + seq_printf(m, "siblings : %u\n", cpus_weight(cpu_core_map[cpunum])); if (c->threads_per_core > 1 || c->cores_per_socket > 1) seq_printf(m, "physical id: %u\n" From 9c184a073bfd650cc791956d6ca79725bb682716 Mon Sep 17 00:00:00 2001 From: "H. J. Lu" Date: Fri, 7 Oct 2005 11:01:19 -0700 Subject: [PATCH 0686/1939] [IA64] Fix 2.6 kernel for the new ia64 assembler The new ia64 assembler uses slot 1 for the offset of a long (2-slot) instruction and the old assembler uses slot 2. The 2.6 kernel assumes slot 2 and won't boot when the new assembler is used: http://sources.redhat.com/bugzilla/show_bug.cgi?id=1433 This patch will work with either slot 1 or 2. Patch provided by H.J. Lu Signed-off-by: Tony Luck --- arch/ia64/kernel/patch.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c index 367804a605fa..6a4ac7d70b35 100644 --- a/arch/ia64/kernel/patch.c +++ b/arch/ia64/kernel/patch.c @@ -64,22 +64,30 @@ ia64_patch (u64 insn_addr, u64 mask, u64 val) void ia64_patch_imm64 (u64 insn_addr, u64 val) { - ia64_patch(insn_addr, + /* The assembler may generate offset pointing to either slot 1 + or slot 2 for a long (2-slot) instruction, occupying slots 1 + and 2. */ + insn_addr &= -16UL; + ia64_patch(insn_addr + 2, 0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1ffffffffffUL, val >> 22); + ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); } void ia64_patch_imm60 (u64 insn_addr, u64 val) { - ia64_patch(insn_addr, + /* The assembler may generate offset pointing to either slot 1 + or slot 2 for a long (2-slot) instruction, occupying slots 1 + and 2. */ + insn_addr &= -16UL; + ia64_patch(insn_addr + 2, 0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); - ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); + ia64_patch(insn_addr + 1, 0x1fffffffffcUL, val >> 18); } /* From dc565b525d4b7091a3abb6616d210c8a896a11d7 Mon Sep 17 00:00:00 2001 From: "hawkes@sgi.com" Date: Mon, 10 Oct 2005 08:43:26 -0700 Subject: [PATCH 0687/1939] [IA64] wider use of for_each_cpu_mask() in arch/ia64 In arch/ia64 change the explicit use of for-loops and NR_CPUS into the general for_each_cpu() or for_each_online_cpu() constructs, as appropriate. This widens the scope of potential future optimizations of the general constructs, as well as takes advantage of the existing optimizations of first_cpu() and next_cpu(). Signed-off-by: John Hawkes Signed-off-by: Tony Luck --- arch/ia64/kernel/irq.c | 12 ++++++------ arch/ia64/kernel/module.c | 6 +++--- arch/ia64/kernel/smp.c | 10 +++++----- arch/ia64/kernel/smpboot.c | 6 +++--- arch/ia64/mm/tlb.c | 5 +++-- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 205d98028261..d33244c32759 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -57,9 +57,9 @@ int show_interrupts(struct seq_file *p, void *v) if (i == 0) { seq_printf(p, " "); - for (j=0; jtypename); seq_printf(p, " %s", action->name); diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index f1aca7cffd12..7a2f0a798d12 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -947,8 +947,8 @@ void percpu_modcopy (void *pcpudst, const void *src, unsigned long size) { unsigned int i; - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) - memcpy(pcpudst + __per_cpu_offset[i], src, size); + for_each_cpu(i) { + memcpy(pcpudst + __per_cpu_offset[i], src, size); + } } #endif /* CONFIG_SMP */ diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 0166a9847095..657ac99a451c 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -185,8 +185,8 @@ send_IPI_allbutself (int op) { unsigned int i; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_online(i) && i != smp_processor_id()) + for_each_online_cpu(i) { + if (i != smp_processor_id()) send_IPI_single(i, op); } } @@ -199,9 +199,9 @@ send_IPI_all (int op) { int i; - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i)) - send_IPI_single(i, op); + for_each_online_cpu(i) { + send_IPI_single(i, op); + } } /* diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 7d72c0d872b3..400a48987124 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -694,9 +694,9 @@ smp_cpus_done (unsigned int dummy) * Allow the user to impress friends. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online(cpu)) - bogosum += cpu_data(cpu)->loops_per_jiffy; + for_each_online_cpu(cpu) { + bogosum += cpu_data(cpu)->loops_per_jiffy; + } printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n", (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 464557e4ed82..987fb754d6ad 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -77,9 +77,10 @@ wrap_mmu_context (struct mm_struct *mm) /* can't call flush_tlb_all() here because of race condition with O(1) scheduler [EF] */ { int cpu = get_cpu(); /* prevent preemption/migration */ - for (i = 0; i < NR_CPUS; ++i) - if (cpu_online(i) && (i != cpu)) + for_each_online_cpu(i) { + if (i != cpu) per_cpu(ia64_need_tlb_flush, i) = 1; + } put_cpu(); } local_flush_tlb_all(); From ddf6d0a00cbb4ad6d4fb4200cc911bb9389174c1 Mon Sep 17 00:00:00 2001 From: "hawkes@sgi.com" Date: Thu, 13 Oct 2005 12:01:18 -0700 Subject: [PATCH 0688/1939] [IA64] another place to use for_each_cpu_mask() in arch/ia64 In arch/ia64 change the explicit use of a for-loop using NR_CPUS into the general for_each_online_cpu() construct. This widens the scope of potential future optimizations of the general constructs, as well as takes advantage of the existing optimizations of first_cpu() and next_cpu(), which is advantageous when the true CPU count is much smaller than NR_CPUS. Signed-off-by: John Hawkes Signed-off-by: Tony Luck --- arch/ia64/kernel/mca.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index d0a5106fba24..52c47da17246 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -508,9 +508,7 @@ ia64_mca_wakeup_all(void) int cpu; /* Clear the Rendez checkin flag for all cpus */ - for(cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; + for_each_online_cpu(cpu) { if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) ia64_mca_wakeup(cpu); } From 7cc656efb560cda66b5ed48444cad7556ea4fe99 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 25 Oct 2005 15:13:54 -0700 Subject: [PATCH 0689/1939] [IB] simplify mad_rmpp.c:alloc_response_msg() Change alloc_response_msg() in mad_rmpp.c to return the struct it allocates directly (or an error code a la ERR_PTR), rather than returning a status and passing the struct back in a pointer param. This simplifies the code and gets rid of warnings like drivers/infiniband/core/mad_rmpp.c: In function nack_recv: drivers/infiniband/core/mad_rmpp.c:192: warning: msg may be used uninitialized in this function with newer versions of gcc. Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad_rmpp.c | 31 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index ba112cd5f93c..3249e1d8c07b 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -151,28 +151,27 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, ib_free_send_mad(msg); } -static int alloc_response_msg(struct ib_mad_agent *agent, - struct ib_mad_recv_wc *recv_wc, - struct ib_mad_send_buf **msg) +static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent, + struct ib_mad_recv_wc *recv_wc) { - struct ib_mad_send_buf *m; + struct ib_mad_send_buf *msg; struct ib_ah *ah; ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, recv_wc->recv_buf.grh, agent->port_num); if (IS_ERR(ah)) - return PTR_ERR(ah); + return (void *) ah; - m = ib_create_send_mad(agent, recv_wc->wc->src_qp, - recv_wc->wc->pkey_index, 1, - IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, GFP_KERNEL); - if (IS_ERR(m)) { + msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, + recv_wc->wc->pkey_index, 1, + IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, + GFP_KERNEL); + if (IS_ERR(msg)) ib_destroy_ah(ah); - return PTR_ERR(m); - } - m->ah = ah; - *msg = m; - return 0; + else + msg->ah = ah; + + return msg; } void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc) @@ -191,8 +190,8 @@ static void nack_recv(struct ib_mad_agent_private *agent, struct ib_rmpp_mad *rmpp_mad; int ret; - ret = alloc_response_msg(&agent->agent, recv_wc, &msg); - if (ret) + msg = alloc_response_msg(&agent->agent, recv_wc); + if (IS_ERR(msg)) return; rmpp_mad = msg->mad; From 4ea6a8046bb49d43c950898f0cb4e1994ef6c89d Mon Sep 17 00:00:00 2001 From: Yan Zheng Date: Mon, 24 Oct 2005 19:55:23 +0800 Subject: [PATCH 0690/1939] [IPV6]: Fix refcnt of struct ip6_flowlabel Signed-off-by: Yan Zheng Acked-by: YOSHIFUJI Hideaki Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv6/ip6_flowlabel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index f841bde30c18..bbbe80cdaf72 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -483,7 +483,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) goto done; } fl1 = sfl->fl; - atomic_inc(&fl->users); + atomic_inc(&fl1->users); break; } } From e54af724c1ae3530c95135157776c9be65cdb747 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 25 Oct 2005 14:07:43 -0500 Subject: [PATCH 0691/1939] [IA64-SGI] fixes for XPC disengage and open/close protocol This patch addresses a few issues with the open/close protocol that were revealed by the newly added disengage functionality combined with more extensive testing. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/xpc.h | 21 ++-- arch/ia64/sn/kernel/xpc_channel.c | 117 ++++++++++++++------- arch/ia64/sn/kernel/xpc_main.c | 152 ++++++++++++++++++++-------- arch/ia64/sn/kernel/xpc_partition.c | 8 +- include/asm-ia64/sn/xp.h | 6 +- 5 files changed, 211 insertions(+), 93 deletions(-) diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h index 565822ab3d08..ae51d7b4c42e 100644 --- a/arch/ia64/sn/kernel/xpc.h +++ b/arch/ia64/sn/kernel/xpc.h @@ -417,6 +417,9 @@ struct xpc_channel { atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ + u8 delayed_IPI_flags; /* IPI flags received, but delayed */ + /* action until channel disconnected */ + /* queue of msg senders who want to be notified when msg received */ atomic_t n_to_notify; /* #of msg senders to notify */ @@ -478,7 +481,8 @@ struct xpc_channel { #define XPC_C_DISCONNECTED 0x00002000 /* channel is disconnected */ #define XPC_C_DISCONNECTING 0x00004000 /* channel is being disconnected */ -#define XPC_C_WDISCONNECT 0x00008000 /* waiting for channel disconnect */ +#define XPC_C_DISCONNECTCALLOUT 0x00008000 /* chan disconnected callout made */ +#define XPC_C_WDISCONNECT 0x00010000 /* waiting for channel disconnect */ @@ -508,13 +512,13 @@ struct xpc_partition { int reason_line; /* line# deactivation initiated from */ int reactivate_nasid; /* nasid in partition to reactivate */ - unsigned long disengage_request_timeout; /* timeout in XPC_TICKS */ + unsigned long disengage_request_timeout; /* timeout in jiffies */ struct timer_list disengage_request_timer; /* XPC infrastructure referencing and teardown control */ - volatile u8 setup_state; /* infrastructure setup state */ + volatile u8 setup_state; /* infrastructure setup state */ wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ atomic_t references; /* #of references to infrastructure */ @@ -604,7 +608,7 @@ struct xpc_partition { /* number of seconds to wait for other partitions to disengage */ -#define XPC_DISENGAGE_REQUEST_TIMELIMIT 90 +#define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 /* interval in seconds to print 'waiting disengagement' messages */ #define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 @@ -618,20 +622,18 @@ struct xpc_partition { extern struct xpc_registration xpc_registrations[]; -/* >>> found in xpc_main.c only */ +/* found in xpc_main.c */ extern struct device *xpc_part; extern struct device *xpc_chan; +extern int xpc_disengage_request_timelimit; extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *); extern void xpc_dropped_IPI_check(struct xpc_partition *); +extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int); extern void xpc_disconnect_wait(int); -/* found in xpc_main.c and efi-xpc.c */ -extern void xpc_activate_partition(struct xpc_partition *); - - /* found in xpc_partition.c */ extern int xpc_exiting; extern struct xpc_vars *xpc_vars; @@ -1077,6 +1079,7 @@ xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, /* given an AMO variable and a channel#, get its associated IPI flags */ #define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) +#define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) #define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0f) #define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & 0x1010101010101010) diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index 195ac1b8e262..abf4fc2a87bb 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c @@ -792,11 +792,20 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) "reason=%d\n", ch->number, ch->partid, ch->reason); } - /* wake the thread that is waiting for this channel to disconnect */ if (ch->flags & XPC_C_WDISCONNECT) { spin_unlock_irqrestore(&ch->lock, *irq_flags); up(&ch->wdisconnect_sema); spin_lock_irqsave(&ch->lock, *irq_flags); + + } else if (ch->delayed_IPI_flags) { + if (part->act_state != XPC_P_DEACTIVATING) { + /* time to take action on any delayed IPI flags */ + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, + ch->delayed_IPI_flags); + spin_unlock(&part->IPI_lock); + } + ch->delayed_IPI_flags = 0; } } @@ -818,6 +827,19 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, spin_lock_irqsave(&ch->lock, irq_flags); +again: + + if ((ch->flags & XPC_C_DISCONNECTED) && + (ch->flags & XPC_C_WDISCONNECT)) { + /* + * Delay processing IPI flags until thread waiting disconnect + * has had a chance to see that the channel is disconnected. + */ + ch->delayed_IPI_flags |= IPI_flags; + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + if (IPI_flags & XPC_IPI_CLOSEREQUEST) { @@ -843,14 +865,22 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, /* both sides have finished disconnecting */ xpc_process_disconnect(ch, &irq_flags); + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); + goto again; } if (ch->flags & XPC_C_DISCONNECTED) { - // >>> explain this section - if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { - DBUG_ON(part->act_state != - XPC_P_DEACTIVATING); + if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, + ch_number) & XPC_IPI_OPENREQUEST)) { + + DBUG_ON(ch->delayed_IPI_flags != 0); + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch_number, + XPC_IPI_CLOSEREQUEST); + spin_unlock(&part->IPI_lock); + } spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -880,9 +910,13 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, } XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); - } else { - xpc_process_disconnect(ch, &irq_flags); + + DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; } + + xpc_process_disconnect(ch, &irq_flags); } @@ -898,7 +932,20 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, } DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); - DBUG_ON(!(ch->flags & XPC_C_RCLOSEREQUEST)); + + if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { + if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) + & XPC_IPI_CLOSEREQUEST)) { + + DBUG_ON(ch->delayed_IPI_flags != 0); + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch_number, XPC_IPI_CLOSEREPLY); + spin_unlock(&part->IPI_lock); + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } ch->flags |= XPC_C_RCLOSEREPLY; @@ -916,8 +963,14 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, "channel=%d\n", args->msg_size, args->local_nentries, ch->partid, ch->number); - if ((ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) || - part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_DEACTIVATING || + (ch->flags & XPC_C_ROPENREQUEST)) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { + ch->delayed_IPI_flags |= XPC_IPI_OPENREQUEST; spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -931,8 +984,11 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, * msg_size = size of channel's messages in bytes * local_nentries = remote partition's local_nentries */ - DBUG_ON(args->msg_size == 0); - DBUG_ON(args->local_nentries == 0); + if (args->msg_size == 0 || args->local_nentries == 0) { + /* assume OPENREQUEST was delayed by mistake */ + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING); ch->remote_nentries = args->local_nentries; @@ -970,7 +1026,13 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, spin_unlock_irqrestore(&ch->lock, irq_flags); return; } - DBUG_ON(!(ch->flags & XPC_C_OPENREQUEST)); + if (!(ch->flags & XPC_C_OPENREQUEST)) { + XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError, + &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST)); DBUG_ON(ch->flags & XPC_C_CONNECTED); @@ -1024,8 +1086,8 @@ xpc_connect_channel(struct xpc_channel *ch) struct xpc_registration *registration = &xpc_registrations[ch->number]; - if (down_interruptible(®istration->sema) != 0) { - return xpcInterrupted; + if (down_trylock(®istration->sema) != 0) { + return xpcRetry; } if (!XPC_CHANNEL_REGISTERED(ch->number)) { @@ -1445,19 +1507,11 @@ xpc_initiate_connect(int ch_number) if (xpc_part_ref(part)) { ch = &part->channels[ch_number]; - if (!(ch->flags & XPC_C_DISCONNECTING)) { - DBUG_ON(ch->flags & XPC_C_OPENREQUEST); - DBUG_ON(ch->flags & XPC_C_CONNECTED); - DBUG_ON(ch->flags & XPC_C_SETUP); - - /* - * Initiate the establishment of a connection - * on the newly registered channel to the - * remote partition. - */ - xpc_wakeup_channel_mgr(part); - } - + /* + * Initiate the establishment of a connection on the + * newly registered channel to the remote partition. + */ + xpc_wakeup_channel_mgr(part); xpc_part_deref(part); } } @@ -1467,9 +1521,6 @@ xpc_initiate_connect(int ch_number) void xpc_connected_callout(struct xpc_channel *ch) { - unsigned long irq_flags; - - /* let the registerer know that a connection has been established */ if (ch->func != NULL) { @@ -1482,10 +1533,6 @@ xpc_connected_callout(struct xpc_channel *ch) dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, " "partid=%d, channel=%d\n", ch->partid, ch->number); } - - spin_lock_irqsave(&ch->lock, irq_flags); - ch->flags |= XPC_C_CONNECTCALLOUT; - spin_unlock_irqrestore(&ch->lock, irq_flags); } diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index feece200b3c3..db349c6d4c58 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c @@ -91,6 +91,10 @@ static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL; static int xpc_hb_check_min_interval = 10; static int xpc_hb_check_max_interval = 120; +int xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT; +static int xpc_disengage_request_min_timelimit = 0; +static int xpc_disengage_request_max_timelimit = 120; + static ctl_table xpc_sys_xpc_hb_dir[] = { { 1, @@ -129,6 +133,19 @@ static ctl_table xpc_sys_xpc_dir[] = { 0555, xpc_sys_xpc_hb_dir }, + { + 2, + "disengage_request_timelimit", + &xpc_disengage_request_timelimit, + sizeof(int), + 0644, + NULL, + &proc_dointvec_minmax, + &sysctl_intvec, + NULL, + &xpc_disengage_request_min_timelimit, + &xpc_disengage_request_max_timelimit + }, {0} }; static ctl_table xpc_sys_dir[] = { @@ -153,11 +170,11 @@ static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); static unsigned long xpc_hb_check_timeout; -/* used as an indication of when the xpc_hb_checker thread is inactive */ -static DECLARE_MUTEX_LOCKED(xpc_hb_checker_inactive); +/* notification that the xpc_hb_checker thread has exited */ +static DECLARE_MUTEX_LOCKED(xpc_hb_checker_exited); -/* used as an indication of when the xpc_discovery thread is inactive */ -static DECLARE_MUTEX_LOCKED(xpc_discovery_inactive); +/* notification that the xpc_discovery thread has exited */ +static DECLARE_MUTEX_LOCKED(xpc_discovery_exited); static struct timer_list xpc_hb_timer; @@ -181,7 +198,7 @@ xpc_timeout_partition_disengage_request(unsigned long data) struct xpc_partition *part = (struct xpc_partition *) data; - DBUG_ON(XPC_TICKS < part->disengage_request_timeout); + DBUG_ON(jiffies < part->disengage_request_timeout); (void) xpc_partition_disengaged(part); @@ -292,8 +309,8 @@ xpc_hb_checker(void *ignore) dev_dbg(xpc_part, "heartbeat checker is exiting\n"); - /* mark this thread as inactive */ - up(&xpc_hb_checker_inactive); + /* mark this thread as having exited */ + up(&xpc_hb_checker_exited); return 0; } @@ -312,8 +329,8 @@ xpc_initiate_discovery(void *ignore) dev_dbg(xpc_part, "discovery thread is exiting\n"); - /* mark this thread as inactive */ - up(&xpc_discovery_inactive); + /* mark this thread as having exited */ + up(&xpc_discovery_exited); return 0; } @@ -703,6 +720,7 @@ xpc_daemonize_kthread(void *args) struct xpc_partition *part = &xpc_partitions[partid]; struct xpc_channel *ch; int n_needed; + unsigned long irq_flags; daemonize("xpc%02dc%d", partid, ch_number); @@ -713,11 +731,14 @@ xpc_daemonize_kthread(void *args) ch = &part->channels[ch_number]; if (!(ch->flags & XPC_C_DISCONNECTING)) { - DBUG_ON(!(ch->flags & XPC_C_CONNECTED)); /* let registerer know that connection has been established */ - if (atomic_read(&ch->kthreads_assigned) == 1) { + spin_lock_irqsave(&ch->lock, irq_flags); + if (!(ch->flags & XPC_C_CONNECTCALLOUT)) { + ch->flags |= XPC_C_CONNECTCALLOUT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + xpc_connected_callout(ch); /* @@ -732,14 +753,23 @@ xpc_daemonize_kthread(void *args) !(ch->flags & XPC_C_DISCONNECTING)) { xpc_activate_kthreads(ch, n_needed); } + } else { + spin_unlock_irqrestore(&ch->lock, irq_flags); } xpc_kthread_waitmsgs(part, ch); } if (atomic_dec_return(&ch->kthreads_assigned) == 0) { - if (ch->flags & XPC_C_CONNECTCALLOUT) { + spin_lock_irqsave(&ch->lock, irq_flags); + if ((ch->flags & XPC_C_CONNECTCALLOUT) && + !(ch->flags & XPC_C_DISCONNECTCALLOUT)) { + ch->flags |= XPC_C_DISCONNECTCALLOUT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + xpc_disconnecting_callout(ch); + } else { + spin_unlock_irqrestore(&ch->lock, irq_flags); } if (atomic_dec_return(&part->nchannels_engaged) == 0) { xpc_mark_partition_disengaged(part); @@ -780,9 +810,29 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) while (needed-- > 0) { + + /* + * The following is done on behalf of the newly created + * kthread. That kthread is responsible for doing the + * counterpart to the following before it exits. + */ + (void) xpc_part_ref(part); + xpc_msgqueue_ref(ch); + if (atomic_inc_return(&ch->kthreads_assigned) == 1 && + atomic_inc_return(&part->nchannels_engaged) == 1) { + xpc_mark_partition_engaged(part); + } + pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0); if (pid < 0) { /* the fork failed */ + if (atomic_dec_return(&ch->kthreads_assigned) == 0 && + atomic_dec_return(&part->nchannels_engaged) == 0) { + xpc_mark_partition_disengaged(part); + xpc_IPI_send_disengage(part); + } + xpc_msgqueue_deref(ch); + xpc_part_deref(part); if (atomic_read(&ch->kthreads_assigned) < ch->kthreads_idle_limit) { @@ -802,18 +852,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) break; } - /* - * The following is done on behalf of the newly created - * kthread. That kthread is responsible for doing the - * counterpart to the following before it exits. - */ - (void) xpc_part_ref(part); - xpc_msgqueue_ref(ch); - if (atomic_inc_return(&ch->kthreads_assigned) == 1) { - if (atomic_inc_return(&part->nchannels_engaged) == 1) { - xpc_mark_partition_engaged(part); - } - } ch->kthreads_created++; // >>> temporary debug only!!! } } @@ -826,26 +864,49 @@ xpc_disconnect_wait(int ch_number) partid_t partid; struct xpc_partition *part; struct xpc_channel *ch; + int wakeup_channel_mgr; /* now wait for all callouts to the caller's function to cease */ for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - if (xpc_part_ref(part)) { - ch = &part->channels[ch_number]; - - if (ch->flags & XPC_C_WDISCONNECT) { - if (!(ch->flags & XPC_C_DISCONNECTED)) { - (void) down(&ch->wdisconnect_sema); - } - spin_lock_irqsave(&ch->lock, irq_flags); - ch->flags &= ~XPC_C_WDISCONNECT; - spin_unlock_irqrestore(&ch->lock, irq_flags); - } - - xpc_part_deref(part); + if (!xpc_part_ref(part)) { + continue; } + + ch = &part->channels[ch_number]; + + if (!(ch->flags & XPC_C_WDISCONNECT)) { + xpc_part_deref(part); + continue; + } + + (void) down(&ch->wdisconnect_sema); + + spin_lock_irqsave(&ch->lock, irq_flags); + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); + wakeup_channel_mgr = 0; + + if (ch->delayed_IPI_flags) { + if (part->act_state != XPC_P_DEACTIVATING) { + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch->number, ch->delayed_IPI_flags); + spin_unlock(&part->IPI_lock); + wakeup_channel_mgr = 1; + } + ch->delayed_IPI_flags = 0; + } + + ch->flags &= ~XPC_C_WDISCONNECT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + if (wakeup_channel_mgr) { + xpc_wakeup_channel_mgr(part); + } + + xpc_part_deref(part); } } @@ -873,11 +934,11 @@ xpc_do_exit(enum xpc_retval reason) /* ignore all incoming interrupts */ free_irq(SGI_XPC_ACTIVATE, NULL); - /* wait for the discovery thread to mark itself inactive */ - down(&xpc_discovery_inactive); + /* wait for the discovery thread to exit */ + down(&xpc_discovery_exited); - /* wait for the heartbeat checker thread to mark itself inactive */ - down(&xpc_hb_checker_inactive); + /* wait for the heartbeat checker thread to exit */ + down(&xpc_hb_checker_exited); /* sleep for a 1/3 of a second or so */ @@ -893,6 +954,7 @@ xpc_do_exit(enum xpc_retval reason) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; + if (xpc_partition_disengaged(part) && part->act_state == XPC_P_INACTIVE) { continue; @@ -930,7 +992,7 @@ xpc_do_exit(enum xpc_retval reason) /* now it's time to eliminate our heartbeat */ del_timer_sync(&xpc_hb_timer); - DBUG_ON(xpc_vars->heartbeating_to_mask == 0); + DBUG_ON(xpc_vars->heartbeating_to_mask != 0); /* take ourselves off of the reboot_notifier_list */ (void) unregister_reboot_notifier(&xpc_reboot_notifier); @@ -1134,7 +1196,7 @@ xpc_init(void) dev_err(xpc_part, "failed while forking discovery thread\n"); /* mark this new thread as a non-starter */ - up(&xpc_discovery_inactive); + up(&xpc_discovery_exited); xpc_do_exit(xpcUnloading); return -EBUSY; @@ -1172,3 +1234,7 @@ module_param(xpc_hb_check_interval, int, 0); MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " "heartbeat checks."); +module_param(xpc_disengage_request_timelimit, int, 0); +MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " + "for disengage request to complete."); + diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 79a0fc4c860c..958488f55699 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -578,7 +578,7 @@ xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, /* - * Prior code has determine the nasid which generated an IPI. Inspect + * Prior code has determined the nasid which generated an IPI. Inspect * that nasid to determine if its partition needs to be activated or * deactivated. * @@ -942,14 +942,14 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, /* set a timelimit on the disengage request */ part->disengage_request_timeout = jiffies + - (XPC_DISENGAGE_REQUEST_TIMELIMIT * HZ); + (xpc_disengage_request_timelimit * HZ); part->disengage_request_timer.expires = part->disengage_request_timeout; add_timer(&part->disengage_request_timer); } - dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid, - reason); + dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", + XPC_PARTID(part), reason); xpc_partition_going_down(part, reason); } diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h index f3052a54932b..30312be31206 100644 --- a/include/asm-ia64/sn/xp.h +++ b/include/asm-ia64/sn/xp.h @@ -225,7 +225,9 @@ enum xpc_retval { xpcDisconnecting, /* 49: channel disconnecting (closing) */ - xpcUnknownReason /* 50: unknown reason -- must be last in list */ + xpcOpenCloseError, /* 50: channel open/close protocol error */ + + xpcUnknownReason /* 51: unknown reason -- must be last in list */ }; @@ -350,7 +352,7 @@ typedef void (*xpc_notify_func)(enum xpc_retval reason, partid_t partid, * * The 'func' field points to the function to call when aynchronous * notification is required for such events as: a connection established/lost, - * or an incomming message received, or an error condition encountered. A + * or an incoming message received, or an error condition encountered. A * non-NULL 'func' field indicates that there is an active registration for * the channel. */ From 5ac660ee1334b401450280cd282113b2c18398f5 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Sun, 23 Oct 2005 10:31:45 +0200 Subject: [PATCH 0692/1939] [TR]: Preserve RIF flag even for 2 byte RIF fields. Signed-off-by: Jochen Friedrich Signed-off-by: Arnaldo Carvalho de Melo --- net/802/tr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/802/tr.c b/net/802/tr.c index 1eaa3d19d8bf..afd8385c0c9c 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -340,9 +340,10 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) unsigned int hash, rii_p = 0; unsigned long flags; struct rif_cache *entry; - + unsigned char saddr0; spin_lock_irqsave(&rif_lock, flags); + saddr0 = trh->saddr[0]; /* * Firstly see if the entry exists @@ -395,7 +396,6 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); entry->local_ring = 0; - trh->saddr[0]|=TR_RII; /* put the routing indicator back for tcpdump */ } else { @@ -422,6 +422,7 @@ printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", } entry->last_used=jiffies; } + trh->saddr[0]=saddr0; /* put the routing indicator back for tcpdump */ spin_unlock_irqrestore(&rif_lock, flags); } From 4b38fcd4858204cb3667eb7b3aca48ffb1002f05 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 25 Oct 2005 14:09:51 -0500 Subject: [PATCH 0693/1939] [IA64-SGI] XPC changes to support more than 2k nasids XPC needs to be changed to support up to 16k nasids on an SGI Altix system. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/xpc.h | 77 +++++++++++---- arch/ia64/sn/kernel/xpc_main.c | 8 +- arch/ia64/sn/kernel/xpc_partition.c | 140 ++++++++++++++++------------ 3 files changed, 141 insertions(+), 84 deletions(-) diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h index ae51d7b4c42e..33df1b3758b6 100644 --- a/arch/ia64/sn/kernel/xpc.h +++ b/arch/ia64/sn/kernel/xpc.h @@ -68,29 +68,58 @@ /* - * Reserved Page provided by SAL. + * the reserved page * - * SAL provides one page per partition of reserved memory. When SAL - * initialization is complete, SAL_signature, SAL_version, partid, - * part_nasids, and mach_nasids are set. + * SAL reserves one page of memory per partition for XPC. Though a full page + * in length (16384 bytes), its starting address is not page aligned, but it + * is cacheline aligned. The reserved page consists of the following: + * + * reserved page header + * + * The first cacheline of the reserved page contains the header + * (struct xpc_rsvd_page). Before SAL initialization has completed, + * SAL has set up the following fields of the reserved page header: + * SAL_signature, SAL_version, partid, and nasids_size. The other + * fields are set up by XPC. (xpc_rsvd_page points to the local + * partition's reserved page.) + * + * part_nasids mask + * mach_nasids mask + * + * SAL also sets up two bitmaps (or masks), one that reflects the actual + * nasids in this partition (part_nasids), and the other that reflects + * the actual nasids in the entire machine (mach_nasids). We're only + * interested in the even numbered nasids (which contain the processors + * and/or memory), so we only need half as many bits to represent the + * nasids. The part_nasids mask is located starting at the first cacheline + * following the reserved page header. The mach_nasids mask follows right + * after the part_nasids mask. The size in bytes of each mask is reflected + * by the reserved page header field 'nasids_size'. (Local partition's + * mask pointers are xpc_part_nasids and xpc_mach_nasids.) + * + * vars + * vars part + * + * Immediately following the mach_nasids mask are the XPC variables + * required by other partitions. First are those that are generic to all + * partitions (vars), followed on the next available cacheline by those + * which are partition specific (vars part). These are setup by XPC. + * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) * * Note: Until vars_pa is set, the partition XPC code has not been initialized. */ struct xpc_rsvd_page { - u64 SAL_signature; /* SAL unique signature */ - u64 SAL_version; /* SAL specified version */ - u8 partid; /* partition ID from SAL */ + u64 SAL_signature; /* SAL: unique signature */ + u64 SAL_version; /* SAL: version */ + u8 partid; /* SAL: partition ID */ u8 version; - u8 pad[6]; /* pad to u64 align */ + u8 pad1[6]; /* align to next u64 in cacheline */ volatile u64 vars_pa; - struct timespec stamp; /* time when reserved page was initialized */ - u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; - u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; + struct timespec stamp; /* time when reserved page was setup by XPC */ + u64 pad2[9]; /* align to last u64 in cacheline */ + u64 nasids_size; /* SAL: size of each nasid mask in bytes */ }; -#define XPC_RSVD_PAGE_ALIGNED_SIZE \ - (L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))) - #define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ #define XPC_SUPPORTS_RP_STAMP(_version) \ @@ -142,8 +171,6 @@ struct xpc_vars { AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ }; -#define XPC_VARS_ALIGNED_SIZE (L1_CACHE_ALIGN(sizeof(struct xpc_vars))) - #define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ @@ -184,7 +211,7 @@ xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) /* * The AMOs page consists of a number of AMO variables which are divided into * four groups, The first two groups are used to identify an IRQ's sender. - * These two groups consist of 64 and 16 AMO variables respectively. The last + * These two groups consist of 64 and 128 AMO variables respectively. The last * two groups, consisting of just one AMO variable each, are used to identify * the remote partitions that are currently engaged (from the viewpoint of * the XPC running on the remote partition). @@ -233,6 +260,16 @@ struct xpc_vars_part { #define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ +/* the reserved page sizes and offsets */ + +#define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)) +#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars)) + +#define XPC_RP_PART_NASIDS(_rp) (u64 *) ((u8 *) _rp + XPC_RP_HEADER_SIZE) +#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) +#define XPC_RP_VARS(_rp) ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words) +#define XPC_RP_VARS_PART(_rp) (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE) + /* * Functions registered by add_timer() or called by kernel_thread() only @@ -1147,9 +1184,9 @@ xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) * cacheable mapping for the entire region. This will prevent speculative * reading of cached copies of our lines from being issued which will cause * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * (XP_MAX_PARTITIONS) AMO variables for message notification and an - * additional 16 (XP_NASID_MASK_WORDS) AMO variables for partition activation - * and 2 AMO variables for partition deactivation. + * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an + * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition + * activation and 2 AMO variables for partition deactivation. */ static inline AMO_t * xpc_IPI_init(int index) diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index db349c6d4c58..38f2c699192c 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c @@ -1049,11 +1049,11 @@ xpc_init(void) /* * xpc_remote_copy_buffer is used as a temporary buffer for bte_copy'ng - * both a partition's reserved page and its XPC variables. Its size was - * based on the size of a reserved page. So we need to ensure that the - * XPC variables will fit as well. + * various portions of a partition's reserved page. Its size is based + * on the size of the reserved page header and part_nasids mask. So we + * need to ensure that the other items will fit as well. */ - if (XPC_VARS_ALIGNED_SIZE > XPC_RSVD_PAGE_ALIGNED_SIZE) { + if (XPC_RP_VARS_SIZE > XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES) { dev_err(xpc_part, "xpc_remote_copy_buffer is not big enough\n"); return -EPERM; } diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 958488f55699..6bb1091f2a4d 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -47,13 +47,16 @@ static u64 xpc_sh2_IPI_access3; u64 xpc_prot_vec[MAX_COMPACT_NODES]; -/* this partition's reserved page */ +/* this partition's reserved page pointers */ struct xpc_rsvd_page *xpc_rsvd_page; - -/* this partition's XPC variables (within the reserved page) */ +static u64 *xpc_part_nasids; +static u64 *xpc_mach_nasids; struct xpc_vars *xpc_vars; struct xpc_vars_part *xpc_vars_part; +static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ +static int xp_nasid_mask_words; /* actual size in words of nasid mask */ + /* * For performance reasons, each entry of xpc_partitions[] is cacheline @@ -65,15 +68,16 @@ struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; /* - * Generic buffer used to store a local copy of the remote partitions - * reserved page or XPC variables. + * Generic buffer used to store a local copy of portions of a remote + * partition's reserved page (either its header and part_nasids mask, + * or its vars). * * xpc_discovery runs only once and is a seperate thread that is * very likely going to be processing in parallel with receiving * interrupts. */ -char ____cacheline_aligned - xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE]; +char ____cacheline_aligned xpc_remote_copy_buffer[XPC_RP_HEADER_SIZE + + XP_NASID_MASK_BYTES]; /* @@ -136,7 +140,7 @@ xpc_rsvd_page_init(void) { struct xpc_rsvd_page *rp; AMO_t *amos_page; - u64 rp_pa, next_cl, nasid_array = 0; + u64 rp_pa, nasid_array = 0; int i, ret; @@ -144,7 +148,8 @@ xpc_rsvd_page_init(void) rp_pa = xpc_get_rsvd_page_pa(cnodeid_to_nasid(0), (u64) xpc_remote_copy_buffer, - XPC_RSVD_PAGE_ALIGNED_SIZE); + XPC_RP_HEADER_SIZE + + L1_CACHE_BYTES); if (rp_pa == 0) { dev_err(xpc_part, "SAL failed to locate the reserved page\n"); return NULL; @@ -159,12 +164,19 @@ xpc_rsvd_page_init(void) rp->version = XPC_RP_VERSION; - /* - * Place the XPC variables on the cache line following the - * reserved page structure. - */ - next_cl = (u64) rp + XPC_RSVD_PAGE_ALIGNED_SIZE; - xpc_vars = (struct xpc_vars *) next_cl; + /* establish the actual sizes of the nasid masks */ + if (rp->SAL_version == 1) { + /* SAL_version 1 didn't set the nasids_size field */ + rp->nasids_size = 128; + } + xp_nasid_mask_bytes = rp->nasids_size; + xp_nasid_mask_words = xp_nasid_mask_bytes / 8; + + /* setup the pointers to the various items in the reserved page */ + xpc_part_nasids = XPC_RP_PART_NASIDS(rp); + xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); + xpc_vars = XPC_RP_VARS(rp); + xpc_vars_part = XPC_RP_VARS_PART(rp); /* * Before clearing xpc_vars, see if a page of AMOs had been previously @@ -216,26 +228,23 @@ xpc_rsvd_page_init(void) amos_page = (AMO_t *) TO_AMO((u64) amos_page); } + /* clear xpc_vars */ memset(xpc_vars, 0, sizeof(struct xpc_vars)); - /* - * Place the XPC per partition specific variables on the cache line - * following the XPC variables structure. - */ - next_cl += XPC_VARS_ALIGNED_SIZE; - memset((u64 *) next_cl, 0, sizeof(struct xpc_vars_part) * - XP_MAX_PARTITIONS); - xpc_vars_part = (struct xpc_vars_part *) next_cl; - xpc_vars->vars_part_pa = __pa(next_cl); - xpc_vars->version = XPC_V_VERSION; xpc_vars->act_nasid = cpuid_to_nasid(0); xpc_vars->act_phys_cpuid = cpu_physical_id(0); + xpc_vars->vars_part_pa = __pa(xpc_vars_part); + xpc_vars->amos_page_pa = ia64_tpa((u64) amos_page); xpc_vars->amos_page = amos_page; /* save for next load of XPC */ + /* clear xpc_vars_part */ + memset((u64 *) xpc_vars_part, 0, sizeof(struct xpc_vars_part) * + XP_MAX_PARTITIONS); + /* initialize the activate IRQ related AMO variables */ - for (i = 0; i < XP_NASID_MASK_WORDS; i++) { + for (i = 0; i < xp_nasid_mask_words; i++) { (void) xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); } @@ -243,10 +252,7 @@ xpc_rsvd_page_init(void) (void) xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); (void) xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); - /* export AMO page's physical address to other partitions */ - xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page); - - /* timestamp of when reserved page was initialized */ + /* timestamp of when reserved page was setup by XPC */ rp->stamp = CURRENT_TIME; /* @@ -406,7 +412,7 @@ xpc_check_remote_hb(void) /* pull the remote_hb cache line */ bres = xp_bte_copy(part->remote_vars_pa, ia64_tpa((u64) remote_vars), - XPC_VARS_ALIGNED_SIZE, + XPC_RP_VARS_SIZE, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { XPC_DEACTIVATE_PARTITION(part, @@ -434,10 +440,11 @@ xpc_check_remote_hb(void) /* - * Get a copy of the remote partition's rsvd page. + * Get a copy of a portion of the remote partition's rsvd page. * * remote_rp points to a buffer that is cacheline aligned for BTE copies and - * assumed to be of size XPC_RSVD_PAGE_ALIGNED_SIZE. + * is large enough to contain a copy of their reserved page header and + * part_nasids mask. */ static enum xpc_retval xpc_get_remote_rp(int nasid, u64 *discovered_nasids, @@ -449,16 +456,17 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* get the reserved page's physical address */ *remote_rp_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp, - XPC_RSVD_PAGE_ALIGNED_SIZE); + XPC_RP_HEADER_SIZE + + xp_nasid_mask_bytes); if (*remote_rp_pa == 0) { return xpcNoRsvdPageAddr; } - /* pull over the reserved page structure */ + /* pull over the reserved page header and part_nasids mask */ bres = xp_bte_copy(*remote_rp_pa, ia64_tpa((u64) remote_rp), - XPC_RSVD_PAGE_ALIGNED_SIZE, + XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { return xpc_map_bte_errors(bres); @@ -466,8 +474,11 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, if (discovered_nasids != NULL) { - for (i = 0; i < XP_NASID_MASK_WORDS; i++) { - discovered_nasids[i] |= remote_rp->part_nasids[i]; + u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); + + + for (i = 0; i < xp_nasid_mask_words; i++) { + discovered_nasids[i] |= remote_part_nasids[i]; } } @@ -494,10 +505,10 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* - * Get a copy of the remote partition's XPC variables. + * Get a copy of the remote partition's XPC variables from the reserved page. * * remote_vars points to a buffer that is cacheline aligned for BTE copies and - * assumed to be of size XPC_VARS_ALIGNED_SIZE. + * assumed to be of size XPC_RP_VARS_SIZE. */ static enum xpc_retval xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) @@ -513,7 +524,7 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) /* pull over the cross partition variables */ bres = xp_bte_copy(remote_vars_pa, ia64_tpa((u64) remote_vars), - XPC_VARS_ALIGNED_SIZE, + XPC_RP_VARS_SIZE, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { return xpc_map_bte_errors(bres); @@ -778,14 +789,13 @@ xpc_identify_act_IRQ_sender(void) u64 nasid; /* remote nasid */ int n_IRQs_detected = 0; AMO_t *act_amos; - struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page; act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; /* scan through act AMO variable looking for non-zero entries */ - for (word = 0; word < XP_NASID_MASK_WORDS; word++) { + for (word = 0; word < xp_nasid_mask_words; word++) { if (xpc_exiting) { break; @@ -807,7 +817,7 @@ xpc_identify_act_IRQ_sender(void) * remote nasid in our reserved pages machine mask. * This is used in the event of module reload. */ - rp->mach_nasids[word] |= nasid_mask; + xpc_mach_nasids[word] |= nasid_mask; /* locate the nasid(s) which sent interrupts */ @@ -992,6 +1002,7 @@ xpc_discovery(void) u64 remote_rp_pa; u64 remote_vars_pa; int region; + int region_size; int max_regions; int nasid; struct xpc_rsvd_page *rp; @@ -1001,7 +1012,8 @@ xpc_discovery(void) enum xpc_retval ret; - remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RSVD_PAGE_ALIGNED_SIZE, + remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + + xp_nasid_mask_bytes, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) { return; @@ -1009,13 +1021,13 @@ xpc_discovery(void) remote_vars = (struct xpc_vars *) remote_rp; - discovered_nasids = kmalloc(sizeof(u64) * XP_NASID_MASK_WORDS, + discovered_nasids = kmalloc(sizeof(u64) * xp_nasid_mask_words, GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); return; } - memset(discovered_nasids, 0, sizeof(u64) * XP_NASID_MASK_WORDS); + memset(discovered_nasids, 0, sizeof(u64) * xp_nasid_mask_words); rp = (struct xpc_rsvd_page *) xpc_rsvd_page; @@ -1024,11 +1036,19 @@ xpc_discovery(void) * nodes that can comprise an access protection grouping. The access * protection is in regards to memory, IOI and IPI. */ -//>>> move the next two #defines into either include/asm-ia64/sn/arch.h or -//>>> include/asm-ia64/sn/addrs.h -#define SH1_MAX_REGIONS 64 -#define SH2_MAX_REGIONS 256 - max_regions = is_shub2() ? SH2_MAX_REGIONS : SH1_MAX_REGIONS; + max_regions = 64; + region_size = sn_region_size; + + switch (region_size) { + case 128: + max_regions *= 2; + case 64: + max_regions *= 2; + case 32: + max_regions *= 2; + region_size = 16; + DBUG_ON(!is_shub2()); + } for (region = 0; region < max_regions; region++) { @@ -1038,8 +1058,8 @@ xpc_discovery(void) dev_dbg(xpc_part, "searching region %d\n", region); - for (nasid = (region * sn_region_size * 2); - nasid < ((region + 1) * sn_region_size * 2); + for (nasid = (region * region_size * 2); + nasid < ((region + 1) * region_size * 2); nasid += 2) { if ((volatile int) xpc_exiting) { @@ -1049,14 +1069,14 @@ xpc_discovery(void) dev_dbg(xpc_part, "checking nasid %d\n", nasid); - if (XPC_NASID_IN_ARRAY(nasid, rp->part_nasids)) { + if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { dev_dbg(xpc_part, "PROM indicates Nasid %d is " "part of the local partition; skipping " "region\n", nasid); break; } - if (!(XPC_NASID_IN_ARRAY(nasid, rp->mach_nasids))) { + if (!(XPC_NASID_IN_ARRAY(nasid, xpc_mach_nasids))) { dev_dbg(xpc_part, "PROM indicates Nasid %d was " "not on Numa-Link network at reset\n", nasid); @@ -1178,12 +1198,12 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask) return xpcPartitionDown; } - part_nasid_pa = part->remote_rp_pa + - (u64) &((struct xpc_rsvd_page *) 0)->part_nasids; + memset(nasid_mask, 0, XP_NASID_MASK_BYTES); + + part_nasid_pa = (u64) XPC_RP_PART_NASIDS(part->remote_rp_pa); bte_res = xp_bte_copy(part_nasid_pa, ia64_tpa((u64) nasid_mask), - L1_CACHE_ALIGN(XP_NASID_MASK_BYTES), - (BTE_NOTIFY | BTE_WACQUIRE), NULL); + xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL); return xpc_map_bte_errors(bte_res); } From 279290294662d4a35d209fb7d7c46523cfa3d63d Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 25 Oct 2005 14:11:53 -0500 Subject: [PATCH 0694/1939] [IA64-SGI] cleanup the way XPC locates the reserved page Eliminate the passing in of a scratch buffer used for locating the reserved page setup for XPC. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/xpc_partition.c | 39 +++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 6bb1091f2a4d..ce5a37ff4388 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -85,13 +85,16 @@ char ____cacheline_aligned xpc_remote_copy_buffer[XPC_RP_HEADER_SIZE + * for that nasid. This function returns 0 on any error. */ static u64 -xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size) +xpc_get_rsvd_page_pa(int nasid) { bte_result_t bte_res; s64 status; u64 cookie = 0; u64 rp_pa = nasid; /* seed with nasid */ u64 len = 0; + u64 buf = buf; + u64 buf_len = 0; + void *buf_base = NULL; while (1) { @@ -107,13 +110,22 @@ xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size) break; } - if (len > buf_size) { - dev_err(xpc_part, "len (=0x%016lx) > buf_size\n", len); - status = SALRET_ERROR; - break; + if (L1_CACHE_ALIGN(len) > buf_len) { + if (buf_base != NULL) { + kfree(buf_base); + } + buf_len = L1_CACHE_ALIGN(len); + buf = (u64) xpc_kmalloc_cacheline_aligned(buf_len, + GFP_KERNEL, &buf_base); + if (buf_base == NULL) { + dev_err(xpc_part, "unable to kmalloc " + "len=0x%016lx\n", buf_len); + status = SALRET_ERROR; + break; + } } - bte_res = xp_bte_copy(rp_pa, ia64_tpa(buf), buf_size, + bte_res = xp_bte_copy(rp_pa, ia64_tpa(buf), buf_len, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bte_res != BTE_SUCCESS) { dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res); @@ -122,6 +134,10 @@ xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size) } } + if (buf_base != NULL) { + kfree(buf_base); + } + if (status != SALRET_OK) { rp_pa = 0; } @@ -146,10 +162,9 @@ xpc_rsvd_page_init(void) /* get the local reserved page's address */ - rp_pa = xpc_get_rsvd_page_pa(cnodeid_to_nasid(0), - (u64) xpc_remote_copy_buffer, - XPC_RP_HEADER_SIZE + - L1_CACHE_BYTES); + preempt_disable(); + rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id())); + preempt_enable(); if (rp_pa == 0) { dev_err(xpc_part, "SAL failed to locate the reserved page\n"); return NULL; @@ -455,9 +470,7 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* get the reserved page's physical address */ - *remote_rp_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp, - XPC_RP_HEADER_SIZE + - xp_nasid_mask_bytes); + *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); if (*remote_rp_pa == 0) { return xpcNoRsvdPageAddr; } From 5ed688a7162ff8d28d7cf98b34a1f825e4c2c2ac Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Sun, 23 Oct 2005 10:33:52 +0200 Subject: [PATCH 0695/1939] [LLC]: Strip RIF flag from source MAC address Signed-off-by: Jochen Friedrich Signed-off-by: Arnaldo Carvalho de Melo --- include/net/llc_pdu.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h index f45c37d89cf7..c7a959428b4f 100644 --- a/include/net/llc_pdu.h +++ b/include/net/llc_pdu.h @@ -254,8 +254,10 @@ static inline void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) { if (skb->protocol == ntohs(ETH_P_802_2)) memcpy(sa, eth_hdr(skb)->h_source, ETH_ALEN); - else if (skb->protocol == ntohs(ETH_P_TR_802_2)) + else if (skb->protocol == ntohs(ETH_P_TR_802_2)) { memcpy(sa, tr_hdr(skb)->saddr, ETH_ALEN); + *sa &= 0x7F; + } } /** From e7f98dbbb89b68b23a5115708412a820a713fbf1 Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Tue, 25 Oct 2005 17:34:19 -0500 Subject: [PATCH 0696/1939] [IA64-SGI] fix bte_copy() calling get_nasid() while preemptible bte_copy() calls calls get_nasid(), which will get flagged if preemption if enabled. raw_smp_processor_id() is used instead. It is OK if we migrate off node. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/bte.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 45854c637e9c..d71f4de44f79 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -87,7 +87,7 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) unsigned long irq_flags; unsigned long itc_end = 0; int nasid_to_try[MAX_NODES_TO_TRY]; - int my_nasid = get_nasid(); + int my_nasid = cpuid_to_nasid(raw_smp_processor_id()); int bte_if_index, nasid_index; int bte_first, btes_per_node = BTES_PER_NODE; From 900e0143a575406146ac531fcb91790f166ce52f Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Tue, 11 Oct 2005 08:22:33 +0100 Subject: [PATCH 0697/1939] [DECNET]: Remove some redundant ifdeffed code Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/decnet/af_decnet.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 1186dc44cdff..3f25cadccddd 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -719,22 +719,9 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (saddr->sdn_flags & ~SDF_WILD) return -EINVAL; -#if 1 if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))) return -EACCES; -#else - /* - * Maybe put the default actions in the default security ops for - * dn_prot_sock ? Would be nice if the capable call would go there - * too. - */ - if (security_dn_prot_sock(saddr) && - !capable(CAP_NET_BIND_SERVICE) || - saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD)) - return -EACCES; -#endif - if (!(saddr->sdn_flags & SDF_WILD)) { if (dn_ntohs(saddr->sdn_nodeaddrl)) { From 670c02c2bfd2c8a305a90f5285409a7b0a8fd630 Mon Sep 17 00:00:00 2001 From: John Hawkes Date: Thu, 13 Oct 2005 09:30:31 -0700 Subject: [PATCH 0698/1939] [NET]: Wider use of for_each_*cpu() In 'net' change the explicit use of for-loops and NR_CPUS into the general for_each_cpu() or for_each_online_cpu() constructs, as appropriate. This widens the scope of potential future optimizations of the general constructs, as well as takes advantage of the existing optimizations of first_cpu() and next_cpu(), which is advantageous when the true CPU count is much smaller than NR_CPUS. Signed-off-by: John Hawkes Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/core/neighbour.c | 5 +---- net/core/pktgen.c | 5 +---- net/ipv4/icmp.c | 5 +---- net/ipv4/proc.c | 4 +--- net/ipv6/icmp.c | 9 ++------- net/ipv6/proc.c | 4 +--- net/sctp/proc.c | 4 +--- 7 files changed, 8 insertions(+), 28 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 1dcf7fa1f0fe..e68700f950a5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1625,12 +1625,9 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, memset(&ndst, 0, sizeof(ndst)); - for (cpu = 0; cpu < NR_CPUS; cpu++) { + for_each_cpu(cpu) { struct neigh_statistics *st; - if (!cpu_possible(cpu)) - continue; - st = per_cpu_ptr(tbl->stats, cpu); ndst.ndts_allocs += st->allocs; ndst.ndts_destroys += st->destroys; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 5f043d346694..00116d8b3b28 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3065,12 +3065,9 @@ static int __init pg_init(void) /* Register us to receive netdevice events */ register_netdevice_notifier(&pktgen_notifier_block); - for (cpu = 0; cpu < NR_CPUS ; cpu++) { + for_each_online_cpu(cpu) { char buf[30]; - if (!cpu_online(cpu)) - continue; - sprintf(buf, "kpktgend_%i", cpu); pktgen_create_thread(buf, cpu); } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 90dca711ac9f..175e093ec564 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1108,12 +1108,9 @@ void __init icmp_init(struct net_proto_family *ops) struct inet_sock *inet; int i; - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu(i) { int err; - if (!cpu_possible(i)) - continue; - err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &per_cpu(__icmp_socket, i)); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index f7943ba1f43c..a65e508fbd40 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -90,9 +90,7 @@ fold_field(void *mib[], int offt) unsigned long res = 0; int i; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; + for_each_cpu(i) { res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt); res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index b7185fb3377c..23e540365a14 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -700,10 +700,7 @@ int __init icmpv6_init(struct net_proto_family *ops) struct sock *sk; int err, i, j; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; - + for_each_cpu(i) { err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &per_cpu(__icmpv6_socket, i)); if (err < 0) { @@ -749,9 +746,7 @@ void icmpv6_cleanup(void) { int i; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; + for_each_cpu(i) { sock_release(per_cpu(__icmpv6_socket, i)); } inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 334a5967831e..50a13e75d70e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -140,9 +140,7 @@ fold_field(void *mib[], int offt) unsigned long res = 0; int i; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; + for_each_cpu(i) { res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt); res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt); } diff --git a/net/sctp/proc.c b/net/sctp/proc.c index b74f7772b576..6e4dc28874d7 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -69,9 +69,7 @@ fold_field(void *mib[], int nr) unsigned long res = 0; int i; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; + for_each_cpu(i) { res += *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) + sizeof (unsigned long) * nr)); From b7c8921bf1a8a9c1907b1eeb029d3f167be226f3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Oct 2005 15:26:34 -0700 Subject: [PATCH 0699/1939] [PKTGEN]: Sleeping function called under lock pktgen is calling kmalloc GFP_KERNEL and vmalloc with lock held. The simplest fix is to turn the lock into a semaphore, since the thread lock is only used for admin control from user context. Signed-off-by: Stephen Hemminger Signed-off-by: Robert Olsson Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/core/pktgen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 00116d8b3b28..8a90bf79261a 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -177,8 +177,8 @@ #define T_REMDEV (1<<3) /* Remove all devs */ /* Locks */ -#define thread_lock() spin_lock(&_thread_lock) -#define thread_unlock() spin_unlock(&_thread_lock) +#define thread_lock() down(&pktgen_sem) +#define thread_unlock() up(&pktgen_sem) /* If lock -- can be removed after some work */ #define if_lock(t) spin_lock(&(t->if_lock)); @@ -503,7 +503,7 @@ static int pg_delay_d = 0; static int pg_clone_skb_d = 0; static int debug = 0; -static DEFINE_SPINLOCK(_thread_lock); +static DECLARE_MUTEX(pktgen_sem); static struct pktgen_thread *pktgen_threads = NULL; static char module_fname[128]; From 2845b63b504b051a9cb4d78bed8b3594451a1f6f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Oct 2005 15:29:48 -0700 Subject: [PATCH 0700/1939] [PKTGEN]: Use kzalloc These are cleanup patches for pktgen that can go in 2.6.15 Can use kzalloc in a couple of places. Signed-off-by: Stephen Hemminger Signed-off-by: Robert Olsson Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/core/pktgen.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8a90bf79261a..b597ef1771f4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2869,12 +2869,10 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) if( (pkt_dev = __pktgen_NN_threads(ifname, FIND)) == NULL) { - pkt_dev = kmalloc(sizeof(struct pktgen_dev), GFP_KERNEL); + pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); if (!pkt_dev) return -ENOMEM; - memset(pkt_dev, 0, sizeof(struct pktgen_dev)); - pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state)); if (pkt_dev->flows == NULL) { kfree(pkt_dev); @@ -2958,13 +2956,12 @@ static int pktgen_create_thread(const char* name, int cpu) return -EINVAL; } - t = (struct pktgen_thread*)(kmalloc(sizeof(struct pktgen_thread), GFP_KERNEL)); + t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); if (!t) { printk("pktgen: ERROR: out of memory, can't create new thread.\n"); return -ENOMEM; } - memset(t, 0, sizeof(struct pktgen_thread)); strcpy(t->name, name); spin_lock_init(&t->if_lock); t->cpu = cpu; From b4099fab75d5e3eae8d207c0d7159e2f3348686e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Oct 2005 15:32:22 -0700 Subject: [PATCH 0701/1939] [PKTGEN]: Spelling and white space Fix some cosmetic issues. Indentation, spelling errors, and some whitespace. Signed-off-by: Stephen Hemminger Signed-off-by: Robert Olsson Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/core/pktgen.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b597ef1771f4..ad053c8cb7fc 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -75,7 +75,7 @@ * By design there should only be *one* "controlling" process. In practice * multiple write accesses gives unpredictable result. Understood by "write" * to /proc gives result code thats should be read be the "writer". - * For pratical use this should be no problem. + * For practical use this should be no problem. * * Note when adding devices to a specific CPU there good idea to also assign * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. @@ -96,7 +96,7 @@ * New xmit() return, do_div and misc clean up by Stephen Hemminger * 040923 * - * Rany Dunlap fixed u64 printk compiler waring + * Randy Dunlap fixed u64 printk compiler waring * * Remove FCS from BW calculation. Lennert Buytenhek * New time handling. Lennert Buytenhek 041213 @@ -244,7 +244,7 @@ struct pktgen_dev { __u32 seq_num; int clone_skb; /* Use multiple SKBs during packet gen. If this number - * is greater than 1, then that many coppies of the same + * is greater than 1, then that many copies of the same * packet will be sent before a new packet is allocated. * For instance, if you want to send 1024 identical packets * before creating a new packet, set clone_skb to 1024. @@ -396,7 +396,7 @@ static inline s64 divremdi3(s64 x, s64 y, int type) /* End of hacks to deal with 64-bit math on x86 */ -/** Convert to miliseconds */ +/** Convert to milliseconds */ static inline __u64 tv_to_ms(const struct timeval* tv) { __u64 ms = tv->tv_usec / 1000; @@ -425,7 +425,7 @@ static inline __u64 pg_div64(__u64 n, __u64 base) { __u64 tmp = n; /* - * How do we know if the architectrure we are running on + * How do we know if the architecture we are running on * supports division with 64 bit base? * */ @@ -544,12 +544,12 @@ static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, len = strlen(data); if(len > count) { - len =-EFAULT; + len = -EFAULT; goto out; } if (copy_to_user(buf, data, len)) { - len =-EFAULT; + len = -EFAULT; goto out; } @@ -578,7 +578,7 @@ static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf, goto out; } if (copy_from_user(data, buf, count)) { - err =-EFAULT; + err = -EFAULT; goto out_free; } data[count-1] = 0; /* Make string */ @@ -1702,7 +1702,7 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) start = now = getCurUs(); printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now)); while (now < spin_until_us) { - /* TODO: optimise sleeping behavior */ + /* TODO: optimize sleeping behavior */ if (spin_until_us - now > jiffies_to_usecs(1)+1) schedule_timeout_interruptible(1); else if (spin_until_us - now > 100) { @@ -2361,7 +2361,7 @@ static void pktgen_stop_all_threads_ifs(void) pktgen_stop(t); t = t->next; } - thread_unlock(); + thread_unlock(); } static int thread_is_running(struct pktgen_thread *t ) @@ -2555,7 +2555,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t) if (strlen(t->fname)) remove_proc_entry(t->fname, NULL); - thread_lock(); + thread_lock(); if (tmp == t) pktgen_threads = tmp->next; @@ -2929,7 +2929,7 @@ static struct pktgen_thread *pktgen_find_thread(const char* name) { struct pktgen_thread *t = NULL; - thread_lock(); + thread_lock(); t = pktgen_threads; while (t) { From d50a6b56f0f239cf061630c85add121dc3555339 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Oct 2005 15:42:33 -0700 Subject: [PATCH 0702/1939] [PKTGEN]: proc interface revision The code to handle the /proc interface can be cleaned up in several places: * use seq_file for read * don't need to remember all the filenames separately * use for_online_cpu's * don't vmalloc a buffer for small command from user. Committer note: This patch clashed with John Hawkes's "[NET]: Wider use of for_each_*cpu()", so I fixed it up manually. Signed-off-by: Stephen Hemminger Signed-off-by: Robert Olsson Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/core/pktgen.c | 472 +++++++++++++++++++++------------------------- 1 file changed, 215 insertions(+), 257 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index ad053c8cb7fc..7fc3e9e28c34 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -137,6 +137,7 @@ #include #include #include +#include #include #include #include @@ -151,7 +152,7 @@ #include -#define VERSION "pktgen v2.62: Packet Generator for packet performance testing.\n" +#define VERSION "pktgen v2.63: Packet Generator for packet performance testing.\n" /* #define PG_DEBUG(a) a */ #define PG_DEBUG(a) @@ -186,7 +187,9 @@ /* Used to help with determining the pkts on receive */ #define PKTGEN_MAGIC 0xbe9be955 -#define PG_PROC_DIR "net/pktgen" +#define PG_PROC_DIR "pktgen" +#define PGCTRL "pgctrl" +static struct proc_dir_entry *pg_proc_dir = NULL; #define MAX_CFLOWS 65536 @@ -202,11 +205,8 @@ struct pktgen_dev { * Try to keep frequent/infrequent used vars. separated. */ - char ifname[32]; - struct proc_dir_entry *proc_ent; + char ifname[IFNAMSIZ]; char result[512]; - /* proc file names */ - char fname[80]; struct pktgen_thread* pg_thread; /* the owner */ struct pktgen_dev *next; /* Used for chaining in the thread's run-queue */ @@ -330,8 +330,6 @@ struct pktgen_thread { struct pktgen_dev *if_list; /* All device here */ struct pktgen_thread* next; char name[32]; - char fname[128]; /* name of proc file */ - struct proc_dir_entry *proc_ent; char result[512]; u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ @@ -473,16 +471,6 @@ static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b) static char version[] __initdata = VERSION; -static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, size_t count, loff_t *ppos); -static ssize_t proc_pgctrl_write(struct file* file, const char __user * buf, size_t count, loff_t *ppos); -static int proc_if_read(char *buf , char **start, off_t offset, int len, int *eof, void *data); - -static int proc_thread_read(char *buf , char **start, off_t offset, int len, int *eof, void *data); -static int proc_if_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data); -static int proc_thread_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data); -static int create_proc_dir(void); -static int remove_proc_dir(void); - static int pktgen_remove_device(struct pktgen_thread* t, struct pktgen_dev *i); static int pktgen_add_device(struct pktgen_thread* t, const char* ifname); static struct pktgen_thread* pktgen_find_thread(const char* name); @@ -506,80 +494,38 @@ static int debug = 0; static DECLARE_MUTEX(pktgen_sem); static struct pktgen_thread *pktgen_threads = NULL; -static char module_fname[128]; -static struct proc_dir_entry *module_proc_ent = NULL; - static struct notifier_block pktgen_notifier_block = { .notifier_call = pktgen_device_event, }; -static struct file_operations pktgen_fops = { - .read = proc_pgctrl_read, - .write = proc_pgctrl_write, - /* .ioctl = pktgen_ioctl, later maybe */ -}; - /* * /proc handling functions * */ -static struct proc_dir_entry *pg_proc_dir = NULL; -static int proc_pgctrl_read_eof=0; - -static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, - size_t count, loff_t *ppos) +static int pgctrl_show(struct seq_file *seq, void *v) { - char data[200]; - int len = 0; - - if(proc_pgctrl_read_eof) { - proc_pgctrl_read_eof=0; - len = 0; - goto out; - } - - sprintf(data, "%s", VERSION); - - len = strlen(data); - - if(len > count) { - len = -EFAULT; - goto out; - } - - if (copy_to_user(buf, data, len)) { - len = -EFAULT; - goto out; - } - - *ppos += len; - proc_pgctrl_read_eof=1; /* EOF next call */ - - out: - return len; + seq_puts(seq, VERSION); + return 0; } -static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf, - size_t count, loff_t *ppos) +static ssize_t pgctrl_write(struct file* file,const char __user * buf, + size_t count, loff_t *ppos) { - char *data = NULL; int err = 0; + char data[128]; if (!capable(CAP_NET_ADMIN)){ err = -EPERM; goto out; } - data = (void*)vmalloc ((unsigned int)count); + if (count > sizeof(data)) + count = sizeof(data); - if(!data) { - err = -ENOMEM; - goto out; - } if (copy_from_user(data, buf, count)) { err = -EFAULT; - goto out_free; + goto out; } data[count-1] = 0; /* Make string */ @@ -594,31 +540,40 @@ static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf, err = count; - out_free: - vfree (data); out: return err; } -static int proc_if_read(char *buf , char **start, off_t offset, - int len, int *eof, void *data) +static int pgctrl_open(struct inode *inode, struct file *file) +{ + return single_open(file, pgctrl_show, PDE(inode)->data); +} + +static struct file_operations pktgen_fops = { + .owner = THIS_MODULE, + .open = pgctrl_open, + .read = seq_read, + .llseek = seq_lseek, + .write = pgctrl_write, + .release = single_release, +}; + +static int pktgen_if_show(struct seq_file *seq, void *v) { - char *p; int i; - struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data); + struct pktgen_dev *pkt_dev = seq->private; __u64 sa; __u64 stopped; __u64 now = getCurUs(); - p = buf; - p += sprintf(p, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", - (unsigned long long) pkt_dev->count, - pkt_dev->min_pkt_size, pkt_dev->max_pkt_size); + seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", + (unsigned long long) pkt_dev->count, + pkt_dev->min_pkt_size, pkt_dev->max_pkt_size); - p += sprintf(p, " frags: %d delay: %u clone_skb: %d ifname: %s\n", - pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname); + seq_printf(seq, " frags: %d delay: %u clone_skb: %d ifname: %s\n", + pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname); - p += sprintf(p, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); + seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); if(pkt_dev->flags & F_IPV6) { @@ -626,19 +581,19 @@ static int proc_if_read(char *buf , char **start, off_t offset, fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); - p += sprintf(p, " saddr: %s min_saddr: %s max_saddr: %s\n", b1, b2, b3); + seq_printf(seq, " saddr: %s min_saddr: %s max_saddr: %s\n", b1, b2, b3); fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); - p += sprintf(p, " daddr: %s min_daddr: %s max_daddr: %s\n", b1, b2, b3); + seq_printf(seq, " daddr: %s min_daddr: %s max_daddr: %s\n", b1, b2, b3); } else - p += sprintf(p, " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", - pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max); + seq_printf(seq," dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", + pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max); - p += sprintf(p, " src_mac: "); + seq_puts(seq, " src_mac: "); if ((pkt_dev->src_mac[0] == 0) && (pkt_dev->src_mac[1] == 0) && @@ -648,89 +603,89 @@ static int proc_if_read(char *buf , char **start, off_t offset, (pkt_dev->src_mac[5] == 0)) for (i = 0; i < 6; i++) - p += sprintf(p, "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? " " : ":"); + seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? " " : ":"); else for (i = 0; i < 6; i++) - p += sprintf(p, "%02X%s", pkt_dev->src_mac[i], i == 5 ? " " : ":"); + seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], i == 5 ? " " : ":"); - p += sprintf(p, "dst_mac: "); + seq_printf(seq, "dst_mac: "); for (i = 0; i < 6; i++) - p += sprintf(p, "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":"); + seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":"); - p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", - pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min, - pkt_dev->udp_dst_max); + seq_printf(seq, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", + pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min, + pkt_dev->udp_dst_max); - p += sprintf(p, " src_mac_count: %d dst_mac_count: %d \n Flags: ", - pkt_dev->src_mac_count, pkt_dev->dst_mac_count); + seq_printf(seq, " src_mac_count: %d dst_mac_count: %d \n Flags: ", + pkt_dev->src_mac_count, pkt_dev->dst_mac_count); if (pkt_dev->flags & F_IPV6) - p += sprintf(p, "IPV6 "); + seq_printf(seq, "IPV6 "); if (pkt_dev->flags & F_IPSRC_RND) - p += sprintf(p, "IPSRC_RND "); + seq_printf(seq, "IPSRC_RND "); if (pkt_dev->flags & F_IPDST_RND) - p += sprintf(p, "IPDST_RND "); + seq_printf(seq, "IPDST_RND "); if (pkt_dev->flags & F_TXSIZE_RND) - p += sprintf(p, "TXSIZE_RND "); + seq_printf(seq, "TXSIZE_RND "); if (pkt_dev->flags & F_UDPSRC_RND) - p += sprintf(p, "UDPSRC_RND "); + seq_printf(seq, "UDPSRC_RND "); if (pkt_dev->flags & F_UDPDST_RND) - p += sprintf(p, "UDPDST_RND "); + seq_printf(seq, "UDPDST_RND "); if (pkt_dev->flags & F_MACSRC_RND) - p += sprintf(p, "MACSRC_RND "); + seq_printf(seq, "MACSRC_RND "); if (pkt_dev->flags & F_MACDST_RND) - p += sprintf(p, "MACDST_RND "); + seq_printf(seq, "MACDST_RND "); - p += sprintf(p, "\n"); + seq_puts(seq, "\n"); sa = pkt_dev->started_at; stopped = pkt_dev->stopped_at; if (pkt_dev->running) stopped = now; /* not really stopped, more like last-running-at */ - p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", - (unsigned long long) pkt_dev->sofar, - (unsigned long long) pkt_dev->errors, - (unsigned long long) sa, - (unsigned long long) stopped, - (unsigned long long) pkt_dev->idle_acc); + seq_printf(seq, "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", + (unsigned long long) pkt_dev->sofar, + (unsigned long long) pkt_dev->errors, + (unsigned long long) sa, + (unsigned long long) stopped, + (unsigned long long) pkt_dev->idle_acc); - p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", - pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, pkt_dev->cur_src_mac_offset); + seq_printf(seq, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", + pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, + pkt_dev->cur_src_mac_offset); if(pkt_dev->flags & F_IPV6) { char b1[128], b2[128]; fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); - p += sprintf(p, " cur_saddr: %s cur_daddr: %s\n", b2, b1); + seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); } else - p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x\n", - pkt_dev->cur_saddr, pkt_dev->cur_daddr); + seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", + pkt_dev->cur_saddr, pkt_dev->cur_daddr); - p += sprintf(p, " cur_udp_dst: %d cur_udp_src: %d\n", - pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); + seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", + pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); - p += sprintf(p, " flows: %u\n", pkt_dev->nflows); + seq_printf(seq, " flows: %u\n", pkt_dev->nflows); if (pkt_dev->result[0]) - p += sprintf(p, "Result: %s\n", pkt_dev->result); + seq_printf(seq, "Result: %s\n", pkt_dev->result); else - p += sprintf(p, "Result: Idle\n"); - *eof = 1; + seq_printf(seq, "Result: Idle\n"); - return p - buf; + return 0; } @@ -802,13 +757,14 @@ static int strn_len(const char __user *user_buffer, unsigned int maxlen) return i; } -static int proc_if_write(struct file *file, const char __user *user_buffer, - unsigned long count, void *data) +static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer, + size_t count, loff_t *offset) { + struct seq_file *seq = (struct seq_file *) file->private_data; + struct pktgen_dev *pkt_dev = seq->private; int i = 0, max, len; char name[16], valstr[32]; unsigned long value = 0; - struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data); char* pg_result = NULL; int tmp = 0; char buf[128]; @@ -849,7 +805,8 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, if (copy_from_user(tb, user_buffer, count)) return -EFAULT; tb[count] = 0; - printk("pktgen: %s,%lu buffer -:%s:-\n", name, count, tb); + printk("pktgen: %s,%lu buffer -:%s:-\n", name, + (unsigned long) count, tb); } if (!strcmp(name, "min_pkt_size")) { @@ -1335,92 +1292,98 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return -EINVAL; } -static int proc_thread_read(char *buf , char **start, off_t offset, - int len, int *eof, void *data) +static int pktgen_if_open(struct inode *inode, struct file *file) { - char *p; - struct pktgen_thread *t = (struct pktgen_thread*)(data); + return single_open(file, pktgen_if_show, PDE(inode)->data); +} + +static struct file_operations pktgen_if_fops = { + .owner = THIS_MODULE, + .open = pktgen_if_open, + .read = seq_read, + .llseek = seq_lseek, + .write = pktgen_if_write, + .release = single_release, +}; + +static int pktgen_thread_show(struct seq_file *seq, void *v) +{ + struct pktgen_thread *t = seq->private; struct pktgen_dev *pkt_dev = NULL; + BUG_ON(!t); - if (!t) { - printk("pktgen: ERROR: could not find thread in proc_thread_read\n"); - return -EINVAL; - } - - p = buf; - p += sprintf(p, "Name: %s max_before_softirq: %d\n", + seq_printf(seq, "Name: %s max_before_softirq: %d\n", t->name, t->max_before_softirq); - p += sprintf(p, "Running: "); + seq_printf(seq, "Running: "); if_lock(t); for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) if(pkt_dev->running) - p += sprintf(p, "%s ", pkt_dev->ifname); + seq_printf(seq, "%s ", pkt_dev->ifname); - p += sprintf(p, "\nStopped: "); + seq_printf(seq, "\nStopped: "); for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) if(!pkt_dev->running) - p += sprintf(p, "%s ", pkt_dev->ifname); + seq_printf(seq, "%s ", pkt_dev->ifname); if (t->result[0]) - p += sprintf(p, "\nResult: %s\n", t->result); + seq_printf(seq, "\nResult: %s\n", t->result); else - p += sprintf(p, "\nResult: NA\n"); - - *eof = 1; + seq_printf(seq, "\nResult: NA\n"); if_unlock(t); - return p - buf; + return 0; } -static int proc_thread_write(struct file *file, const char __user *user_buffer, - unsigned long count, void *data) +static ssize_t pktgen_thread_write(struct file *file, + const char __user *user_buffer, + size_t count, loff_t *offset) { + struct seq_file *seq = (struct seq_file *) file->private_data; + struct pktgen_thread *t = seq->private; int i = 0, max, len, ret; char name[40]; - struct pktgen_thread *t; char *pg_result; unsigned long value = 0; - + if (count < 1) { // sprintf(pg_result, "Wrong command format"); return -EINVAL; } - + max = count - i; len = count_trail_chars(&user_buffer[i], max); - if (len < 0) - return len; - + if (len < 0) + return len; + i += len; - + /* Read variable name */ len = strn_len(&user_buffer[i], sizeof(name) - 1); - if (len < 0) - return len; + if (len < 0) + return len; memset(name, 0, sizeof(name)); if (copy_from_user(name, &user_buffer[i], len)) return -EFAULT; i += len; - + max = count -i; len = count_trail_chars(&user_buffer[i], max); - if (len < 0) - return len; - + if (len < 0) + return len; + i += len; - if (debug) - printk("pktgen: t=%s, count=%lu\n", name, count); - + if (debug) + printk("pktgen: t=%s, count=%lu\n", name, + (unsigned long) count); - t = (struct pktgen_thread*)(data); if(!t) { printk("pktgen: ERROR: No thread\n"); ret = -EINVAL; @@ -1474,21 +1437,19 @@ static int proc_thread_write(struct file *file, const char __user *user_buffer, return ret; } -static int create_proc_dir(void) +static int pktgen_thread_open(struct inode *inode, struct file *file) { - pg_proc_dir = proc_mkdir(PG_PROC_DIR, NULL); - - if (!pg_proc_dir) - return -ENODEV; - - return 0; + return single_open(file, pktgen_thread_show, PDE(inode)->data); } -static int remove_proc_dir(void) -{ - remove_proc_entry(PG_PROC_DIR, NULL); - return 0; -} +static struct file_operations pktgen_thread_fops = { + .owner = THIS_MODULE, + .open = pktgen_thread_open, + .read = seq_read, + .llseek = seq_lseek, + .write = pktgen_thread_write, + .release = single_release, +}; /* Think find or remove for NN */ static struct pktgen_dev *__pktgen_NN_threads(const char* ifname, int remove) @@ -2552,8 +2513,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t) struct pktgen_thread *tmp = pktgen_threads; - if (strlen(t->fname)) - remove_proc_entry(t->fname, NULL); + remove_proc_entry(t->name, pg_proc_dir); thread_lock(); @@ -2825,7 +2785,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char* i if_lock(t); for(pkt_dev=t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) { - if (strcmp(pkt_dev->ifname, ifname) == 0) { + if (strncmp(pkt_dev->ifname, ifname, IFNAMSIZ) == 0) { break; } } @@ -2864,65 +2824,63 @@ static int add_dev_to_thread(struct pktgen_thread *t, struct pktgen_dev *pkt_dev static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) { struct pktgen_dev *pkt_dev; + struct proc_dir_entry *pe; /* We don't allow a device to be on several threads */ - if( (pkt_dev = __pktgen_NN_threads(ifname, FIND)) == NULL) { - - pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); - if (!pkt_dev) - return -ENOMEM; - - pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state)); - if (pkt_dev->flows == NULL) { - kfree(pkt_dev); - return -ENOMEM; - } - memset(pkt_dev->flows, 0, MAX_CFLOWS*sizeof(struct flow_state)); - - pkt_dev->min_pkt_size = ETH_ZLEN; - pkt_dev->max_pkt_size = ETH_ZLEN; - pkt_dev->nfrags = 0; - pkt_dev->clone_skb = pg_clone_skb_d; - pkt_dev->delay_us = pg_delay_d / 1000; - pkt_dev->delay_ns = pg_delay_d % 1000; - pkt_dev->count = pg_count_d; - pkt_dev->sofar = 0; - pkt_dev->udp_src_min = 9; /* sink port */ - pkt_dev->udp_src_max = 9; - pkt_dev->udp_dst_min = 9; - pkt_dev->udp_dst_max = 9; - - strncpy(pkt_dev->ifname, ifname, 31); - sprintf(pkt_dev->fname, "%s/%s", PG_PROC_DIR, ifname); - - if (! pktgen_setup_dev(pkt_dev)) { - printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); - if (pkt_dev->flows) - vfree(pkt_dev->flows); - kfree(pkt_dev); - return -ENODEV; - } - - pkt_dev->proc_ent = create_proc_entry(pkt_dev->fname, 0600, NULL); - if (!pkt_dev->proc_ent) { - printk("pktgen: cannot create %s procfs entry.\n", pkt_dev->fname); - if (pkt_dev->flows) - vfree(pkt_dev->flows); - kfree(pkt_dev); - return -EINVAL; - } - pkt_dev->proc_ent->read_proc = proc_if_read; - pkt_dev->proc_ent->write_proc = proc_if_write; - pkt_dev->proc_ent->data = (void*)(pkt_dev); - pkt_dev->proc_ent->owner = THIS_MODULE; - - return add_dev_to_thread(t, pkt_dev); - } - else { + pkt_dev = __pktgen_NN_threads(ifname, FIND); + if (pkt_dev) { printk("pktgen: ERROR: interface already used.\n"); return -EBUSY; } + + pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); + if (!pkt_dev) + return -ENOMEM; + + pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state)); + if (pkt_dev->flows == NULL) { + kfree(pkt_dev); + return -ENOMEM; + } + memset(pkt_dev->flows, 0, MAX_CFLOWS*sizeof(struct flow_state)); + + pkt_dev->min_pkt_size = ETH_ZLEN; + pkt_dev->max_pkt_size = ETH_ZLEN; + pkt_dev->nfrags = 0; + pkt_dev->clone_skb = pg_clone_skb_d; + pkt_dev->delay_us = pg_delay_d / 1000; + pkt_dev->delay_ns = pg_delay_d % 1000; + pkt_dev->count = pg_count_d; + pkt_dev->sofar = 0; + pkt_dev->udp_src_min = 9; /* sink port */ + pkt_dev->udp_src_max = 9; + pkt_dev->udp_dst_min = 9; + pkt_dev->udp_dst_max = 9; + + strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); + + if (! pktgen_setup_dev(pkt_dev)) { + printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); + if (pkt_dev->flows) + vfree(pkt_dev->flows); + kfree(pkt_dev); + return -ENODEV; + } + + pe = create_proc_entry(ifname, 0600, pg_proc_dir); + if (!pe) { + printk("pktgen: cannot create %s/%s procfs entry.\n", + PG_PROC_DIR, ifname); + if (pkt_dev->flows) + vfree(pkt_dev->flows); + kfree(pkt_dev); + return -EINVAL; + } + pe->proc_fops = &pktgen_if_fops; + pe->data = pkt_dev; + + return add_dev_to_thread(t, pkt_dev); } static struct pktgen_thread *pktgen_find_thread(const char* name) @@ -2945,6 +2903,7 @@ static struct pktgen_thread *pktgen_find_thread(const char* name) static int pktgen_create_thread(const char* name, int cpu) { struct pktgen_thread *t = NULL; + struct proc_dir_entry *pe; if (strlen(name) > 31) { printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n"); @@ -2966,17 +2925,16 @@ static int pktgen_create_thread(const char* name, int cpu) spin_lock_init(&t->if_lock); t->cpu = cpu; - sprintf(t->fname, "%s/%s", PG_PROC_DIR, t->name); - t->proc_ent = create_proc_entry(t->fname, 0600, NULL); - if (!t->proc_ent) { - printk("pktgen: cannot create %s procfs entry.\n", t->fname); + pe = create_proc_entry(t->name, 0600, pg_proc_dir); + if (!pe) { + printk("pktgen: cannot create %s/%s procfs entry.\n", + PG_PROC_DIR, t->name); kfree(t); return -EINVAL; } - t->proc_ent->read_proc = proc_thread_read; - t->proc_ent->write_proc = proc_thread_write; - t->proc_ent->data = (void*)(t); - t->proc_ent->owner = THIS_MODULE; + + pe->proc_fops = &pktgen_thread_fops; + pe->data = t; t->next = pktgen_threads; pktgen_threads = t; @@ -3031,8 +2989,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_ /* Clean up proc file system */ - if (strlen(pkt_dev->fname)) - remove_proc_entry(pkt_dev->fname, NULL); + remove_proc_entry(pkt_dev->ifname, pg_proc_dir); if (pkt_dev->flows) vfree(pkt_dev->flows); @@ -3043,21 +3000,24 @@ static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_ static int __init pg_init(void) { int cpu; + struct proc_dir_entry *pe; + printk(version); - module_fname[0] = 0; + pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net); + if (!pg_proc_dir) + return -ENODEV; + pg_proc_dir->owner = THIS_MODULE; - create_proc_dir(); - - sprintf(module_fname, "%s/pgctrl", PG_PROC_DIR); - module_proc_ent = create_proc_entry(module_fname, 0600, NULL); - if (!module_proc_ent) { - printk("pktgen: ERROR: cannot create %s procfs entry.\n", module_fname); + pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir); + if (pe == NULL) { + printk("pktgen: ERROR: cannot create %s procfs entry.\n", PGCTRL); + proc_net_remove(PG_PROC_DIR); return -EINVAL; } - module_proc_ent->proc_fops = &pktgen_fops; - module_proc_ent->data = NULL; + pe->proc_fops = &pktgen_fops; + pe->data = NULL; /* Register us to receive netdevice events */ register_netdevice_notifier(&pktgen_notifier_block); @@ -3089,10 +3049,8 @@ static void __exit pg_cleanup(void) unregister_netdevice_notifier(&pktgen_notifier_block); /* Clean up proc file system */ - - remove_proc_entry(module_fname, NULL); - - remove_proc_dir(); + remove_proc_entry(PGCTRL, pg_proc_dir); + proc_net_remove(PG_PROC_DIR); } From eed75f191d8318a2b144da8aae9774e1cfcae492 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 16 Oct 2005 14:22:59 +0200 Subject: [PATCH 0703/1939] [NETFILTER] ip_conntrack: Make "hashsize" conntrack parameter writable It's fairly simple to resize the hash table, but currently you need to remove and reinsert the module. That's bad (we lose connection state). Harald has even offered to write a daemon which sets this based on load. Signed-off-by: Rusty Russell Signed-off-by: Harald Welte Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/netfilter/ip_conntrack_core.c | 132 ++++++++++++++++++------- 1 file changed, 95 insertions(+), 37 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 07a80b56e8dc..422ab68ee7fb 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -50,7 +50,7 @@ #include #include -#define IP_CONNTRACK_VERSION "2.3" +#define IP_CONNTRACK_VERSION "2.4" #if 0 #define DEBUGP printk @@ -148,16 +148,20 @@ DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); static int ip_conntrack_hash_rnd_initted; static unsigned int ip_conntrack_hash_rnd; -static u_int32_t -hash_conntrack(const struct ip_conntrack_tuple *tuple) +static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple, + unsigned int size, unsigned int rnd) { -#if 0 - dump_tuple(tuple); -#endif return (jhash_3words(tuple->src.ip, (tuple->dst.ip ^ tuple->dst.protonum), (tuple->src.u.all | (tuple->dst.u.all << 16)), - ip_conntrack_hash_rnd) % ip_conntrack_htable_size); + rnd) % size); +} + +static u_int32_t +hash_conntrack(const struct ip_conntrack_tuple *tuple) +{ + return __hash_conntrack(tuple, ip_conntrack_htable_size, + ip_conntrack_hash_rnd); } int @@ -1341,14 +1345,13 @@ static int kill_all(struct ip_conntrack *i, void *data) return 1; } -static void free_conntrack_hash(void) +static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size) { - if (ip_conntrack_vmalloc) - vfree(ip_conntrack_hash); + if (vmalloced) + vfree(hash); else - free_pages((unsigned long)ip_conntrack_hash, - get_order(sizeof(struct list_head) - * ip_conntrack_htable_size)); + free_pages((unsigned long)hash, + get_order(sizeof(struct list_head) * size)); } void ip_conntrack_flush() @@ -1378,12 +1381,83 @@ void ip_conntrack_cleanup(void) ip_conntrack_flush(); kmem_cache_destroy(ip_conntrack_cachep); kmem_cache_destroy(ip_conntrack_expect_cachep); - free_conntrack_hash(); + free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc, + ip_conntrack_htable_size); nf_unregister_sockopt(&so_getorigdst); } -static int hashsize; -module_param(hashsize, int, 0400); +static struct list_head *alloc_hashtable(int size, int *vmalloced) +{ + struct list_head *hash; + unsigned int i; + + *vmalloced = 0; + hash = (void*)__get_free_pages(GFP_KERNEL, + get_order(sizeof(struct list_head) + * size)); + if (!hash) { + *vmalloced = 1; + printk(KERN_WARNING"ip_conntrack: falling back to vmalloc.\n"); + hash = vmalloc(sizeof(struct list_head) * size); + } + + if (hash) + for (i = 0; i < size; i++) + INIT_LIST_HEAD(&hash[i]); + + return hash; +} + +int set_hashsize(const char *val, struct kernel_param *kp) +{ + int i, bucket, hashsize, vmalloced; + int old_vmalloced, old_size; + int rnd; + struct list_head *hash, *old_hash; + struct ip_conntrack_tuple_hash *h; + + /* On boot, we can set this without any fancy locking. */ + if (!ip_conntrack_htable_size) + return param_set_int(val, kp); + + hashsize = simple_strtol(val, NULL, 0); + if (!hashsize) + return -EINVAL; + + hash = alloc_hashtable(hashsize, &vmalloced); + if (!hash) + return -ENOMEM; + + /* We have to rehash for the new table anyway, so we also can + * use a new random seed */ + get_random_bytes(&rnd, 4); + + write_lock_bh(&ip_conntrack_lock); + for (i = 0; i < ip_conntrack_htable_size; i++) { + while (!list_empty(&ip_conntrack_hash[i])) { + h = list_entry(ip_conntrack_hash[i].next, + struct ip_conntrack_tuple_hash, list); + list_del(&h->list); + bucket = __hash_conntrack(&h->tuple, hashsize, rnd); + list_add_tail(&h->list, &hash[bucket]); + } + } + old_size = ip_conntrack_htable_size; + old_vmalloced = ip_conntrack_vmalloc; + old_hash = ip_conntrack_hash; + + ip_conntrack_htable_size = hashsize; + ip_conntrack_vmalloc = vmalloced; + ip_conntrack_hash = hash; + ip_conntrack_hash_rnd = rnd; + write_unlock_bh(&ip_conntrack_lock); + + free_conntrack_hash(old_hash, old_vmalloced, old_size); + return 0; +} + +module_param_call(hashsize, set_hashsize, param_get_uint, + &ip_conntrack_htable_size, 0600); int __init ip_conntrack_init(void) { @@ -1392,9 +1466,7 @@ int __init ip_conntrack_init(void) /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ - if (hashsize) { - ip_conntrack_htable_size = hashsize; - } else { + if (!ip_conntrack_htable_size) { ip_conntrack_htable_size = (((num_physpages << PAGE_SHIFT) / 16384) / sizeof(struct list_head)); @@ -1416,20 +1488,8 @@ int __init ip_conntrack_init(void) return ret; } - /* AK: the hash table is twice as big than needed because it - uses list_head. it would be much nicer to caches to use a - single pointer list head here. */ - ip_conntrack_vmalloc = 0; - ip_conntrack_hash - =(void*)__get_free_pages(GFP_KERNEL, - get_order(sizeof(struct list_head) - *ip_conntrack_htable_size)); - if (!ip_conntrack_hash) { - ip_conntrack_vmalloc = 1; - printk(KERN_WARNING "ip_conntrack: falling back to vmalloc.\n"); - ip_conntrack_hash = vmalloc(sizeof(struct list_head) - * ip_conntrack_htable_size); - } + ip_conntrack_hash = alloc_hashtable(ip_conntrack_htable_size, + &ip_conntrack_vmalloc); if (!ip_conntrack_hash) { printk(KERN_ERR "Unable to create ip_conntrack_hash\n"); goto err_unreg_sockopt; @@ -1461,9 +1521,6 @@ int __init ip_conntrack_init(void) ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp; write_unlock_bh(&ip_conntrack_lock); - for (i = 0; i < ip_conntrack_htable_size; i++) - INIT_LIST_HEAD(&ip_conntrack_hash[i]); - /* For use by ipt_REJECT */ ip_ct_attach = ip_conntrack_attach; @@ -1478,7 +1535,8 @@ int __init ip_conntrack_init(void) err_free_conntrack_slab: kmem_cache_destroy(ip_conntrack_cachep); err_free_hash: - free_conntrack_hash(); + free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc, + ip_conntrack_htable_size); err_unreg_sockopt: nf_unregister_sockopt(&so_getorigdst); From 1371e37da299d4df6267ad0ddf010435782c28e9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 15 Oct 2005 09:42:39 +1000 Subject: [PATCH 0704/1939] [IPV4]: Kill redundant rcu_dereference on fa_info This patch kills a redundant rcu_dereference on fa->fa_info in fib_trie.c. As this dereference directly follows a list_for_each_entry_rcu line, we have already taken a read barrier with respect to getting an entry from the list. This read barrier guarantees that all values read out of fa are valid. In particular, the contents of structure pointed to by fa->fa_info is initialised before fa->fa_info is actually set (see fn_trie_insert); the setting of fa->fa_info itself is further separated with a write barrier from the insertion of fa into the list. Therefore by taking a read barrier after obtaining fa from the list (which is given by list_for_each_entry_rcu), we can be sure that fa->fa_info contains a valid pointer, as well as the fact that the data pointed to by fa->fa_info is itself valid. Signed-off-by: Herbert Xu Acked-by: Paul E. McKenney Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/fib_trie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 0093ea08c7f5..66247f38b371 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2404,7 +2404,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) prefix = htonl(l->key); list_for_each_entry_rcu(fa, &li->falh, fa_list) { - const struct fib_info *fi = rcu_dereference(fa->fa_info); + const struct fib_info *fi = fa->fa_info; unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); if (fa->fa_type == RTN_BROADCAST From 80b30c1023dbd795faf948dee0cfb3b270b56d47 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 15 Oct 2005 10:58:30 +1000 Subject: [PATCH 0705/1939] [IPSEC]: Kill obsolete get_mss function Now that we've switched over to storing MTUs in the xfrm_dst entries, we no longer need the dst's get_mss methods. This patch gets rid of them. It also documents the fact that our MTU calculation is not optimal for ESP. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- include/net/dst.h | 1 - net/xfrm/xfrm_policy.c | 43 ------------------------------------------ net/xfrm/xfrm_state.c | 6 ++++++ 3 files changed, 6 insertions(+), 44 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 4a056a682435..6c196a5baf24 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -94,7 +94,6 @@ struct dst_ops struct dst_entry * (*negative_advice)(struct dst_entry *); void (*link_failure)(struct sk_buff *); void (*update_pmtu)(struct dst_entry *dst, u32 mtu); - int (*get_mss)(struct dst_entry *dst, u32 mtu); int entry_size; atomic_t entries; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cbb0ba34a600..0db9e57013fd 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1192,46 +1192,6 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) EXPORT_SYMBOL(xfrm_bundle_ok); -/* Well... that's _TASK_. We need to scan through transformation - * list and figure out what mss tcp should generate in order to - * final datagram fit to mtu. Mama mia... :-) - * - * Apparently, some easy way exists, but we used to choose the most - * bizarre ones. :-) So, raising Kalashnikov... tra-ta-ta. - * - * Consider this function as something like dark humour. :-) - */ -static int xfrm_get_mss(struct dst_entry *dst, u32 mtu) -{ - int res = mtu - dst->header_len; - - for (;;) { - struct dst_entry *d = dst; - int m = res; - - do { - struct xfrm_state *x = d->xfrm; - if (x) { - spin_lock_bh(&x->lock); - if (x->km.state == XFRM_STATE_VALID && - x->type && x->type->get_max_size) - m = x->type->get_max_size(d->xfrm, m); - else - m += x->props.header_len; - spin_unlock_bh(&x->lock); - } - } while ((d = d->child) != NULL); - - if (m <= mtu) - break; - res -= (m - mtu); - if (res < 88) - return mtu; - } - - return res + dst->header_len; -} - int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) { int err = 0; @@ -1252,8 +1212,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) dst_ops->negative_advice = xfrm_negative_advice; if (likely(dst_ops->link_failure == NULL)) dst_ops->link_failure = xfrm_link_failure; - if (likely(dst_ops->get_mss == NULL)) - dst_ops->get_mss = xfrm_get_mss; if (likely(afinfo->garbage_collect == NULL)) afinfo->garbage_collect = __xfrm_garbage_collect; xfrm_policy_afinfo[afinfo->family] = afinfo; @@ -1281,7 +1239,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) dst_ops->check = NULL; dst_ops->negative_advice = NULL; dst_ops->link_failure = NULL; - dst_ops->get_mss = NULL; afinfo->garbage_collect = NULL; } } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9d206c282cf1..8b9a4747417d 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1026,6 +1026,12 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x) } EXPORT_SYMBOL(xfrm_state_delete_tunnel); +/* + * This function is NOT optimal. For example, with ESP it will give an + * MTU that's usually two bytes short of being optimal. However, it will + * usually give an answer that's a multiple of 4 provided the input is + * also a multiple of 4. + */ int xfrm_state_mtu(struct xfrm_state *x, int mtu) { int res = mtu; From ea7ce406490cb248f44f510f7c0bcc357184640a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Thu, 13 Oct 2005 11:43:05 -0700 Subject: [PATCH 0706/1939] [NETLINK]: Remove dead code in af_netlink.c Remove the variable nlk & call to nlk_sk as it does not have any side effect. Signed-off-by: Jayachandran C. Acked-by: James Morris Signed-off-by: Arnaldo Carvalho de Melo --- net/netlink/af_netlink.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 678c3f2c0d0b..eab4942ac97d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -740,11 +740,8 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) { - struct netlink_sock *nlk; int len = skb->len; - nlk = nlk_sk(sk); - skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, len); sock_put(sk); From 0d0d2bba97cb091218ea0bcb3d8debcc7bf48397 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Thu, 13 Oct 2005 11:43:02 -0700 Subject: [PATCH 0707/1939] [IPV4]: Remove dead code from ip_output.c skb_prev is assigned from skb, which cannot be NULL. This patch removes the unnecessary NULL check. Signed-off-by: Jayachandran C. Acked-by: James Morris Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/ip_output.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1ad5202e556b..87e350069abb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1023,10 +1023,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, int alloclen; skb_prev = skb; - if (skb_prev) - fraggap = skb_prev->len - maxfraglen; - else - fraggap = 0; + fraggap = skb_prev->len - maxfraglen; alloclen = fragheaderlen + hh_len + fraggap + 15; skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); From c83c24861882758b9731e8550225cd1e52a4cd1c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 18 Oct 2005 22:07:41 -0700 Subject: [PATCH 0708/1939] [SK_BUFF] kernel-doc: fix skbuff warnings Add kernel-doc to skbuff.h, skbuff.c to eliminate kernel-doc warnings. Signed-off-by: Randy Dunlap Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/skbuff.h | 3 ++- net/core/skbuff.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8f5d9e7f8734..b756935da9c8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -171,7 +171,6 @@ enum { * struct sk_buff - socket buffer * @next: Next buffer in list * @prev: Previous buffer in list - * @list: List we are on * @sk: Socket we are owned by * @tstamp: Time we arrived * @dev: Device we arrived on/are leaving by @@ -190,6 +189,7 @@ enum { * @cloned: Head may be cloned (check refcnt to be sure) * @nohdr: Payload reference only, must not modify header * @pkt_type: Packet class + * @fclone: skbuff clone status * @ip_summed: Driver fed us an IP checksum * @priority: Packet queueing priority * @users: User count - see {datagram,tcp}.c @@ -202,6 +202,7 @@ enum { * @destructor: Destruct function * @nfmark: Can be used for communication between hooks * @nfct: Associated connection, if any + * @ipvs_property: skbuff is owned by ipvs * @nfctinfo: Relationship of this skb to the connection * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @tc_index: Traffic control index diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 02cd4cde2112..ef9d46b91eb9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -122,6 +122,8 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here) * __alloc_skb - allocate a network buffer * @size: size to allocate * @gfp_mask: allocation mask + * @fclone: allocate from fclone cache instead of head cache + * and allocate a cloned (child) skb * * Allocate a new &sk_buff. The returned buffer has no headroom and a * tail room of size bytes. The object has a reference count of one. From 95df1c04ab3f7ca617774930df62c0893a188c2c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 21:39:33 +0100 Subject: [PATCH 0709/1939] [AX.25]: Use constant instead of magic number Signed-off-by: Ralf Baechle DL5RB Signed-off-by: Arnaldo Carvalho de Melo --- net/rose/rose_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index e556d92c0bc4..b18fe5043019 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -727,7 +727,7 @@ int rose_rt_ioctl(unsigned int cmd, void __user *arg) } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; - if (rose_route.ndigis > 8) /* No more than 8 digipeats */ + if (rose_route.ndigis > AX25_MAX_DIGIS) return -EINVAL; err = rose_add_node(&rose_route, dev); dev_put(dev); From dcab5e1eeccf5e226c771ecc013631cde157435f Mon Sep 17 00:00:00 2001 From: David Engel Date: Fri, 21 Oct 2005 22:09:16 -0500 Subject: [PATCH 0710/1939] [IPV4]: Fix setting broadcast for SIOCSIFNETMASK Fix setting of the broadcast address when the netmask is set via SIOCSIFNETMASK in Linux 2.6. The code wanted the old value of ifa->ifa_mask but used it after it had already been overwritten with the new value. Signed-off-by: David Engel Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/devinet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 74f2207e131a..4ec4b2ca6ab1 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -715,6 +715,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) break; ret = 0; if (ifa->ifa_mask != sin->sin_addr.s_addr) { + u32 old_mask = ifa->ifa_mask; inet_del_ifa(in_dev, ifap, 0); ifa->ifa_mask = sin->sin_addr.s_addr; ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); @@ -728,7 +729,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) if ((dev->flags & IFF_BROADCAST) && (ifa->ifa_prefixlen < 31) && (ifa->ifa_broadcast == - (ifa->ifa_local|~ifa->ifa_mask))) { + (ifa->ifa_local|~old_mask))) { ifa->ifa_broadcast = (ifa->ifa_local | ~sin->sin_addr.s_addr); } From 6693e74a16ef563960764bd963f1048392135c3c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 25 Oct 2005 20:40:09 -0700 Subject: [PATCH 0711/1939] PCI: be more verbose about resource quirks When reserving an PCI quirk, note that in the kernel bootup messages. Also, parse the strange PIIX4 device resources - they should get their own PCI resource quirks, but for now just print out what it finds to verify that the code does the right thing. Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 101 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a6a630a950d0..7992bc8cc6a4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -241,7 +241,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M ); -static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr) +static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, + unsigned size, int nr, const char *name) { region &= ~(size-1); if (region) { @@ -259,6 +260,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsi pcibios_bus_to_resource(dev, res, &bus_region); pci_claim_resource(dev, nr); + printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); } } @@ -291,25 +293,98 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) u16 region; pci_read_config_word(dev, 0xE0, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI"); pci_read_config_word(dev, 0xE2, ®ion); - quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); + quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi ); +static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) +{ + u32 devres; + u32 mask, size, base; + + pci_read_config_dword(dev, port, &devres); + if ((devres & enable) != enable) + return; + mask = (devres >> 16) & 15; + base = devres & 0xffff; + size = 16; + for (;;) { + unsigned bit = size >> 1; + if ((bit & mask) == bit) + break; + size = bit; + } + /* + * For now we only print it out. Eventually we'll want to + * reserve it (at least if it's in the 0x1000+ range), but + * let's get enough confirmation reports first. + */ + base &= -size; + printk("%s PIO at %04x-%04x\n", name, base, base + size - 1); +} + +static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) +{ + u32 devres; + u32 mask, size, base; + + pci_read_config_dword(dev, port, &devres); + if ((devres & enable) != enable) + return; + base = devres & 0xffff0000; + mask = (devres & 0x3f) << 16; + size = 128 << 16; + for (;;) { + unsigned bit = size >> 1; + if ((bit & mask) == bit) + break; + size = bit; + } + /* + * For now we only print it out. Eventually we'll want to + * reserve it, but let's get enough confirmation reports first. + */ + base &= -size; + printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1); +} + /* * PIIX4 ACPI: Two IO regions pointed to by longwords at * 0x40 (64 bytes of ACPI registers) * 0x90 (32 bytes of SMB registers) + * and a few strange programmable PIIX4 device resources. */ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) { - u32 region; + u32 region, res_a; pci_read_config_dword(dev, 0x40, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI"); pci_read_config_dword(dev, 0x90, ®ion); - quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1); + quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB"); + + /* Device resource A has enables for some of the other ones */ + pci_read_config_dword(dev, 0x5c, &res_a); + + piix4_io_quirk(dev, "PIIX4 devres B", 0x60, 3 << 21); + piix4_io_quirk(dev, "PIIX4 devres C", 0x64, 3 << 21); + + /* Device resource D is just bitfields for static resources */ + + /* Device 12 enabled? */ + if (res_a & (1 << 29)) { + piix4_io_quirk(dev, "PIIX4 devres E", 0x68, 1 << 20); + piix4_mem_quirk(dev, "PIIX4 devres F", 0x6c, 1 << 7); + } + /* Device 13 enabled? */ + if (res_a & (1 << 30)) { + piix4_io_quirk(dev, "PIIX4 devres G", 0x70, 1 << 20); + piix4_mem_quirk(dev, "PIIX4 devres H", 0x74, 1 << 7); + } + piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20); + piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi ); @@ -323,10 +398,10 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) u32 region; pci_read_config_dword(dev, 0x40, ®ion); - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES); + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH4 ACPI/GPIO/TCO"); pci_read_config_dword(dev, 0x58, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi ); @@ -352,7 +427,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) if (rev & 0x10) { pci_read_config_dword(dev, 0x48, ®ion); region &= PCI_BASE_ADDRESS_IO_MASK; - quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES); + quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi ); @@ -372,11 +447,11 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) pci_read_config_word(dev, 0x70, &hm); hm &= PCI_BASE_ADDRESS_IO_MASK; - quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1); + quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c868 HW-mon"); pci_read_config_dword(dev, 0x90, &smb); smb &= PCI_BASE_ADDRESS_IO_MASK; - quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); + quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c868 SMB"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi ); @@ -391,11 +466,11 @@ static void __devinit quirk_vt8235_acpi(struct pci_dev *dev) pci_read_config_word(dev, 0x88, &pm); pm &= PCI_BASE_ADDRESS_IO_MASK; - quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES); + quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM"); pci_read_config_word(dev, 0xd0, &smb); smb &= PCI_BASE_ADDRESS_IO_MASK; - quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1); + quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1, "vt8235 SMB"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi); From ac9c18974f7d08cdedfb1e9599faa8c851c7cef9 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Wed, 26 Oct 2005 00:51:24 -0400 Subject: [PATCH 0712/1939] [netdrvr forcedeth] scatter gather and segmentation offload support also: - eliminate use of pointless get_nvpriv() wrapper, and use netdev_priv() directly. - use NETDEV_TX_xxx return codes --- drivers/net/forcedeth.c | 257 ++++++++++++++++++++++++++-------------- 1 file changed, 166 insertions(+), 91 deletions(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index e5f480203675..22aec6ed80f5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -96,6 +96,7 @@ * 0.42: 06 Aug 2005: Fix lack of link speed initialization * in the second (and later) nv_open call * 0.43: 10 Aug 2005: Add support for tx checksum. + * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -107,7 +108,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.43" +#define FORCEDETH_VERSION "0.44" #define DRV_NAME "forcedeth" #include @@ -340,6 +341,8 @@ typedef union _ring_type { /* error and valid are the same for both */ #define NV_TX2_ERROR (1<<30) #define NV_TX2_VALID (1<<31) +#define NV_TX2_TSO (1<<28) +#define NV_TX2_TSO_SHIFT 14 #define NV_TX2_CHECKSUM_L3 (1<<27) #define NV_TX2_CHECKSUM_L4 (1<<26) @@ -542,7 +545,7 @@ static inline struct fe_priv *get_nvpriv(struct net_device *dev) static inline u8 __iomem *get_hwbase(struct net_device *dev) { - return get_nvpriv(dev)->base; + return ((struct fe_priv *)netdev_priv(dev))->base; } static inline void pci_push(u8 __iomem *base) @@ -631,7 +634,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) static int phy_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 miicontrol; unsigned int tries = 0; @@ -734,7 +737,7 @@ static int phy_init(struct net_device *dev) static void nv_start_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); @@ -790,7 +793,7 @@ static void nv_stop_tx(struct net_device *dev) static void nv_txrx_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); @@ -809,7 +812,7 @@ static void nv_txrx_reset(struct net_device *dev) */ static struct net_device_stats *nv_get_stats(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); /* It seems that the nic always generates interrupts and doesn't * accumulate errors internally. Thus the current values in np->stats @@ -825,7 +828,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) */ static int nv_alloc_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unsigned int refill_rx = np->refill_rx; int nr; @@ -869,7 +872,7 @@ static int nv_alloc_rx(struct net_device *dev) static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); disable_irq(dev->irq); if (nv_alloc_rx(dev)) { @@ -883,7 +886,7 @@ static void nv_do_rx_refill(unsigned long data) static void nv_init_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->cur_rx = RX_RING; @@ -897,15 +900,17 @@ static void nv_init_rx(struct net_device *dev) static void nv_init_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; + np->tx_skbuff[i] = NULL; + } } static int nv_init_ring(struct net_device *dev) @@ -915,21 +920,44 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx(dev); } +static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) +{ + struct fe_priv *np = netdev_priv(dev); + struct sk_buff *skb = np->tx_skbuff[skbnr]; + unsigned int j, entry, fragments; + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", + dev->name, skbnr, np->tx_skbuff[skbnr]); + + entry = skbnr; + if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { + for (j = fragments; j >= 1; j--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; + pci_unmap_page(np->pci_dev, np->tx_dma[entry], + frag->size, + PCI_DMA_TODEVICE); + entry = (entry - 1) % TX_RING; + } + } + pci_unmap_single(np->pci_dev, np->tx_dma[entry], + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + np->tx_skbuff[skbnr] = NULL; +} + static void nv_drain_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int i; + struct fe_priv *np = netdev_priv(dev); + unsigned int i; + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; + nv_release_txskb(dev, i); np->stats.tx_dropped++; } } @@ -937,7 +965,7 @@ static void nv_drain_tx(struct net_device *dev) static void nv_drain_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; for (i = 0; i < RX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) @@ -967,29 +995,69 @@ static void drain_ring(struct net_device *dev) */ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int nr = np->next_tx % TX_RING; - u32 tx_checksum = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); - - np->tx_skbuff[nr] = skb; - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, - PCI_DMA_TODEVICE); - - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - else { - np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - } + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int nr = (np->next_tx + fragments) % TX_RING; + unsigned int i; spin_lock_irq(&np->lock); - wmb(); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum); + + if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { + spin_unlock_irq(&np->lock); + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + np->tx_skbuff[nr] = skb; + + if (fragments) { + dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); + /* setup descriptors in reverse order */ + for (i = fragments; i >= 1; i--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } + + nr = (nr - 1) % TX_RING; + + if (np->desc_ver == DESC_VER_1) + tx_flags_extra &= ~NV_TX_LASTPACKET; + else + tx_flags_extra &= ~NV_TX2_LASTPACKET; + } + } + +#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); else - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission\n", - dev->name, np->next_tx); +#endif + tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, + PCI_DMA_TODEVICE); + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } + + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -1000,15 +1068,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx++; + np->next_tx += 1 + fragments; dev->trans_start = jiffies; - if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) - netif_stop_queue(dev); spin_unlock_irq(&np->lock); writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); - return 0; + return NETDEV_TX_OK; } /* @@ -1018,9 +1084,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static void nv_tx_done(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; - int i; + unsigned int i; + struct sk_buff *skb; while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; @@ -1035,35 +1102,38 @@ static void nv_tx_done(struct net_device *dev) if (Flags & NV_TX_VALID) break; if (np->desc_ver == DESC_VER_1) { - if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (Flags & NV_TX_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (Flags & NV_TX_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } else { - if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (Flags & NV_TX2_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX2_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX2_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (Flags & NV_TX2_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX2_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -1076,7 +1146,7 @@ static void nv_tx_done(struct net_device *dev) */ static void nv_tx_timeout(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, @@ -1209,7 +1279,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen) static void nv_rx_process(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; for (;;) { @@ -1364,7 +1434,7 @@ static void set_bufsize(struct net_device *dev) */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int old_mtu; if (new_mtu < 64 || new_mtu > np->pkt_limit) @@ -1449,7 +1519,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev) */ static int nv_set_mac_address(struct net_device *dev, void *addr) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); struct sockaddr *macaddr = (struct sockaddr*)addr; if(!is_valid_ether_addr(macaddr->sa_data)) @@ -1484,7 +1554,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) */ static void nv_set_multicast(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; @@ -1544,7 +1614,7 @@ static void nv_set_multicast(struct net_device *dev) static int nv_update_linkspeed(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int adv, lpa; int newls = np->linkspeed; @@ -1714,7 +1784,7 @@ static void nv_link_irq(struct net_device *dev) static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 events; int i; @@ -1786,7 +1856,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); disable_irq(dev->irq); @@ -1810,7 +1880,7 @@ static void nv_poll_controller(struct net_device *dev) static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); strcpy(info->driver, "forcedeth"); strcpy(info->version, FORCEDETH_VERSION); strcpy(info->bus_info, pci_name(np->pci_dev)); @@ -1818,7 +1888,7 @@ static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); wolinfo->supported = WAKE_MAGIC; spin_lock_irq(&np->lock); @@ -1829,7 +1899,7 @@ static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); spin_lock_irq(&np->lock); @@ -2030,7 +2100,7 @@ static int nv_get_regs_len(struct net_device *dev) static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 *rbuf = buf; int i; @@ -2044,7 +2114,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void static int nv_nway_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int ret; spin_lock_irq(&np->lock); @@ -2079,7 +2149,7 @@ static struct ethtool_ops ops = { static int nv_open(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int ret, oom, i; @@ -2215,7 +2285,7 @@ static int nv_open(struct net_device *dev) static int nv_close(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base; spin_lock_irq(&np->lock); @@ -2271,7 +2341,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!dev) goto out; - np = get_nvpriv(dev); + np = netdev_priv(dev); np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -2323,6 +2393,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); + } else { + dev->features |= NETIF_F_HIGHDMA; } np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { @@ -2341,8 +2413,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_CHECKSUM) { np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_HW_CSUM; - } + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; +#ifdef NETIF_F_TSO + dev->features |= NETIF_F_TSO; +#endif + } err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); @@ -2422,9 +2497,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->wolenabled = 0; if (np->desc_ver == DESC_VER_1) { - np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; + np->tx_flags = NV_TX_VALID; } else { - np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; + np->tx_flags = NV_TX2_VALID; } np->irqmask = NVREG_IRQMASK_WANTED; if (id->driver_data & DEV_NEED_TIMERIRQ) @@ -2513,7 +2588,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unregister_netdev(dev); From 077783f87708b24054452e5c07685ead2c28b1eb Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Mon, 24 Oct 2005 10:27:46 -0500 Subject: [PATCH 0713/1939] [PATCH] ieee80211 build fix James Ketrenos wrote: > [3/4] Use the tx_headroom and reserve requested space. This patch introduced a compile problem; patch below corrects this. Fixed compilation error due to not passing tx_headroom in ieee80211_tx_frame. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index fb4509032402..95ccbadbf55b 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -541,7 +541,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC); + txb = ieee80211_alloc_txb(1, len, ieee->tx_headroom, GFP_ATOMIC); if (unlikely(!txb)) { printk(KERN_WARNING "%s: Could not allocate TXB\n", ieee->dev->name); From d2e615125762459fd2bb9f0c91881509a0b9c31b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 20 Oct 2005 11:43:33 -0500 Subject: [PATCH 0714/1939] [PATCH] powerpc: Make sure we have an RTC before trying to adjust it Its valid for ppc_md.set_rtc_time to be NULL. We need to check that its non-NULL before trying to update the RTC. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index ad501d62aa6e..82f2cabb4f47 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -154,7 +154,7 @@ static __inline__ void timer_check_rtc(void) * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ - if (ntp_synced() && + if (ppc_md.set_rtc_time && ntp_synced() && xtime.tv_sec - last_rtc_update >= 659 && abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ && jiffies - wall_jiffies == 1) { From 60dda2565bbf31bbe662fd143a41c861b7a190cf Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 20 Oct 2005 11:44:03 -0500 Subject: [PATCH 0715/1939] [PATCH] powerpc: some prom.c cleanups On !CONFIG_PPC_MULTIPLATFORM _machine is defined as 0. This is ok, but we can't assign a value to _machine then. We may not have CONFIG_PCI available, so only build in support for find_parent_pci_resource(), request_OF_resource(), release_OF_resource() if PCI is enabled. This is probably not the long term fix but works out for now. Make reg_property64 contain 64-bit elements on a 32-bit machine. Mark the deprecated prom.c functions as __deprecated. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 4 ++++ include/asm-powerpc/prom.h | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 69f69c38fd27..8d0c78cbc0bc 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1167,8 +1167,10 @@ static int __init early_init_dt_scan_chosen(unsigned long node, #ifdef CONFIG_PPC64 systemcfg->platform = *prop; #else +#ifdef CONFIG_PPC_MULTIPLATFORM _machine = *prop; #endif +#endif #ifdef CONFIG_PPC64 /* check if iommu is forced on or off */ @@ -2005,6 +2007,7 @@ bus_space_to_resource_flags(unsigned int bus_space) } } +#ifdef CONFIG_PCI static struct resource *find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) { @@ -2157,3 +2160,4 @@ int release_OF_resource(struct device_node *node, int index) return 0; } EXPORT_SYMBOL(release_OF_resource); +#endif /* CONFIG_PCI */ diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 8a21791c7cae..49d2c7455f8e 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -104,8 +104,8 @@ struct reg_property32 { }; struct reg_property64 { - unsigned long address; - unsigned long size; + u64 address; + u64 size; }; struct property { @@ -155,12 +155,12 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e /* OBSOLETE: Old style node lookup */ -extern struct device_node *find_devices(const char *name); -extern struct device_node *find_type_devices(const char *type); -extern struct device_node *find_path_device(const char *path); -extern struct device_node *find_compatible_devices(const char *type, +extern __deprecated struct device_node *find_devices(const char *name); +extern __deprecated struct device_node *find_type_devices(const char *type); +extern __deprecated struct device_node *find_path_device(const char *path); +extern __deprecated struct device_node *find_compatible_devices(const char *type, const char *compat); -extern struct device_node *find_all_nodes(void); +extern __deprecated struct device_node *find_all_nodes(void); /* New style node lookup */ extern struct device_node *of_find_node_by_name(struct device_node *from, From d95bbcb3a344b3eb84b45d162c0a20348f0af37f Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 20 Oct 2005 11:44:46 -0500 Subject: [PATCH 0716/1939] [PATCH] powerpc: merge include/asm-ppc*/checksum.h into include/asm-powerpc/checksum.h Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/checksum.h | 47 ++++++-- include/asm-ppc/checksum.h | 107 ------------------ 2 files changed, 36 insertions(+), 118 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/checksum.h (77%) delete mode 100644 include/asm-ppc/checksum.h diff --git a/include/asm-ppc64/checksum.h b/include/asm-powerpc/checksum.h similarity index 77% rename from include/asm-ppc64/checksum.h rename to include/asm-powerpc/checksum.h index d22d4469de43..d8354d8a49ce 100644 --- a/include/asm-ppc64/checksum.h +++ b/include/asm-powerpc/checksum.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_CHECKSUM_H -#define _PPC64_CHECKSUM_H +#ifndef _ASM_POWERPC_CHECKSUM_H +#define _ASM_POWERPC_CHECKSUM_H /* * This program is free software; you can redistribute it and/or @@ -41,8 +41,14 @@ extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); /* - * the same as csum_partial, but copies from src to dst while it - * checksums + * Computes the checksum of a memory block at src, length len, + * and adds in "sum" (32-bit), while copying the block to dst. + * If an access exception occurs on src or dst, it stores -EFAULT + * to *src_err or *dst_err respectively (if that pointer is not + * NULL), and, for an error on src, zeroes the rest of dst. + * + * Like csum_partial, this must be called with even lengths, + * except for the last fragment. */ extern unsigned int csum_partial_copy_generic(const char *src, char *dst, int len, unsigned int sum, @@ -51,12 +57,18 @@ extern unsigned int csum_partial_copy_generic(const char *src, char *dst, * the same as csum_partial, but copies from src to dst while it * checksums. */ - unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum); +#define csum_partial_copy_from_user(src, dst, len, sum, errp) \ + csum_partial_copy_generic((src), (dst), (len), (sum), (errp), NULL) + +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL) + + /* * turns a 32-bit partial checksum (e.g. from csum_partial) into a * 1's complement 16-bit checksum. @@ -83,12 +95,7 @@ static inline unsigned short ip_compute_csum(unsigned char * buff, int len) return csum_fold(csum_partial(buff, len, 0)); } -#define csum_partial_copy_from_user(src, dst, len, sum, errp) \ - csum_partial_copy_generic((src), (dst), (len), (sum), (errp), NULL) - -#define csum_partial_copy_nocheck(src, dst, len, sum) \ - csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL) - +#ifdef __powerpc64__ static inline u32 csum_tcpudp_nofold(u32 saddr, u32 daddr, unsigned short len, @@ -103,5 +110,23 @@ static inline u32 csum_tcpudp_nofold(u32 saddr, s += (s >> 32); return (u32) s; } +#else +static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + __asm__("\n\ + addc %0,%0,%1 \n\ + adde %0,%0,%2 \n\ + adde %0,%0,%3 \n\ + addze %0,%0 \n\ + " + : "=r" (sum) + : "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum)); + return sum; +} #endif +#endif diff --git a/include/asm-ppc/checksum.h b/include/asm-ppc/checksum.h deleted file mode 100644 index cf953a92c7ab..000000000000 --- a/include/asm-ppc/checksum.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _PPC_CHECKSUM_H -#define _PPC_CHECKSUM_H - - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -extern unsigned int csum_partial(const unsigned char * buff, int len, - unsigned int sum); - -/* - * Computes the checksum of a memory block at src, length len, - * and adds in "sum" (32-bit), while copying the block to dst. - * If an access exception occurs on src or dst, it stores -EFAULT - * to *src_err or *dst_err respectively (if that pointer is not - * NULL), and, for an error on src, zeroes the rest of dst. - * - * Like csum_partial, this must be called with even lengths, - * except for the last fragment. - */ -extern unsigned int csum_partial_copy_generic(const char *src, char *dst, - int len, unsigned int sum, - int *src_err, int *dst_err); - -#define csum_partial_copy_from_user(src, dst, len, sum, errp) \ - csum_partial_copy_generic((__force void *)(src), (dst), (len), (sum), (errp), NULL) - -/* FIXME: this needs to be written to really do no check -- Cort */ -#define csum_partial_copy_nocheck(src, dst, len, sum) \ - csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL) - -/* - * turns a 32-bit partial checksum (e.g. from csum_partial) into a - * 1's complement 16-bit checksum. - */ -static inline unsigned int csum_fold(unsigned int sum) -{ - unsigned int tmp; - - /* swap the two 16-bit halves of sum */ - __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum)); - /* if there is a carry from adding the two 16-bit halves, - it will carry from the lower half into the upper half, - giving us the correct sum in the upper half. */ - sum = ~(sum + tmp) >> 16; - return sum; -} - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ -static inline unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - return csum_fold(csum_partial(buff, len, 0)); -} - -/* - * FIXME: I swiped this one from the sparc and made minor modifications. - * It may not be correct. -- Cort - */ -static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - __asm__("\n\ - addc %0,%0,%1 \n\ - adde %0,%0,%2 \n\ - adde %0,%0,%3 \n\ - addze %0,%0 \n\ - " - : "=r" (sum) - : "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum)); - return sum; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. ihl is the number - * of 32-bit words and is always >= 5. - */ -extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl); - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -extern unsigned short csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum); - -#endif -#endif /* __KERNEL__ */ From bfbac4973687ae32df528f2811483f92b943f251 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Fri, 21 Oct 2005 16:16:58 -0500 Subject: [PATCH 0717/1939] [PATCH] powerpc: Fix types.h Powerpc: Fix types.h I noticed that Paul had already pulled the version of types.h that is missing the config.h include into the merge tree - this patch adds it back in. Signed-off-by: Becky Bruce Signed-off-by: Paul Mackerras --- include/asm-powerpc/types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-powerpc/types.h b/include/asm-powerpc/types.h index 7d803cb547bb..f70cd3fb32d9 100644 --- a/include/asm-powerpc/types.h +++ b/include/asm-powerpc/types.h @@ -64,6 +64,8 @@ typedef struct { #ifndef __ASSEMBLY__ +#include + typedef signed char s8; typedef unsigned char u8; From ab590ccb428f874bb8f9cec1265cc1f9cb38b601 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Mon, 24 Oct 2005 14:50:46 -0500 Subject: [PATCH 0718/1939] [PATCH] ppc: Fix m82xx_pci build A recent patch updated the name of pci_assign_all_busses to pci_assign_all_buses. This instance of its use wasn't corrected by the original patch to use the new name. Builds cleanly on ads8272. Signed-off-by: Becky Bruce Signed-off-by: Paul Mackerras --- arch/ppc/syslib/m82xx_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c index 5cce123789f1..1d1c3956c1ae 100644 --- a/arch/ppc/syslib/m82xx_pci.c +++ b/arch/ppc/syslib/m82xx_pci.c @@ -306,7 +306,7 @@ void __init pq2_find_bridges(void) struct pci_controller * hose; int host_bridge; - pci_assign_all_busses = 1; + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); From 0fd6f717948083d480f38e97f62cc116faf0e534 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 25 Oct 2005 23:02:59 -0500 Subject: [PATCH 0719/1939] [PATCH] powerpc: Add support for Book-E timer config to generic_calibrate_decr We need to initialize some control SPRS for timers on Book-E before we start taking decrementer interrupts. Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 82f2cabb4f47..9f264c2f02c3 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -610,6 +610,17 @@ void __init generic_calibrate_decr(void) ppc_proc_freq = *fp; } } +#ifdef CONFIG_BOOKE + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +#endif if (!node_found) printk(KERN_ERR "WARNING: Estimating processor frequency " "(not found)\n"); From 6d7f58b04d824843f7539a132e1ad8220bbe589a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 25 Oct 2005 23:57:33 -0500 Subject: [PATCH 0720/1939] [PATCH] powerpc: Some minor cleanups to setup_32.c * Removed of_show_percpuinfo and just report CPU frequency in generic show_cpuinfo code. * Killed OCP and PPC_SYS related code which doesn't belong in the merge tree Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 45 +++++-------------------- arch/powerpc/platforms/powermac/setup.c | 3 -- 2 files changed, 8 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 2d7fdeb581d1..c6a67c65852a 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -39,15 +39,7 @@ #include #include #include -#include - -#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \ - defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \ - defined(CONFIG_PPC_MPC52xx)) - -#if USES_PPC_SYS -#include -#endif +#include #if defined CONFIG_KGDB #include @@ -234,18 +226,19 @@ int show_cpuinfo(struct seq_file *m, void *v) } } + /* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ + seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, + ppc_proc_freq % 1000000); + seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", maj, min, PVR_VER(pvr), PVR_REV(pvr)); seq_printf(m, "bogomips\t: %lu.%02lu\n", lpj / (500000/HZ), (lpj / (5000/HZ)) % 100); -#if USES_PPC_SYS - if (cur_ppc_sys_spec->ppc_sys_name) - seq_printf(m, "chipset\t\t: %s\n", - cur_ppc_sys_spec->ppc_sys_name); -#endif - #ifdef CONFIG_SMP seq_printf(m, "\n"); #endif @@ -305,28 +298,6 @@ unsigned long __init early_init(unsigned long dt_ptr) } #ifdef CONFIG_PPC_OF -/* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ -int -of_show_percpuinfo(struct seq_file *m, int i) -{ - struct device_node *cpu_node; - u32 *fp; - int s; - - cpu_node = find_type_devices("cpu"); - if (!cpu_node) - return 0; - for (s = 0; s < i && cpu_node->next; s++) - cpu_node = cpu_node->next; - fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL); - if (fp) - seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000); - return 0; -} - void __init intuit_machine_type(void) { diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 908e4921bac4..72cd503d3d33 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -202,9 +202,6 @@ static void pmac_show_percpuinfo(struct seq_file *m, int i) return; } #endif /* CONFIG_CPU_FREQ_PMAC */ -#ifdef CONFIG_PPC32 - of_show_percpuinfo(m, i); -#endif } #ifndef CONFIG_ADB_CUDA From a6f3546ecd00a1566cee6e0d992f4c33c2d28287 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 24 Oct 2005 15:07:26 +1000 Subject: [PATCH 0721/1939] [PATCH] powerpc: Remove duplicate definition of set_tb() Somewhere along the line we got two definitions of set_tb(). They look to be identical although they're not textually identical. So remove the #ifdef CONFIG_PPC64 version, leaving the common version in time.h. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- include/asm-powerpc/reg.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 06a1f0f2db21..68058d72d8da 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -585,13 +585,6 @@ static inline void ppc64_runlatch_off(void) mtspr(SPRN_CTRLT, ctrl); } } - -static inline void set_tb(unsigned int upper, unsigned int lower) -{ - mttbl(0); - mttbu(upper); - mttbl(lower); -} #endif #define __get_SP() ({unsigned long sp; \ From 8c71632f7a13357b7dc5636fca68317f72d3043e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 24 Oct 2005 15:07:27 +1000 Subject: [PATCH 0722/1939] [PATCH] powerpc: Remove trailing \n" in HMT macros GCC 3.3.3 barfs on the trailing \n" in the HMT macros. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- include/asm-powerpc/ppc_asm.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 96367e04fa58..f8ad5df6ebef 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -76,13 +76,13 @@ #define REST_16EVRS(n,s,base) REST_8EVRS(n,s,base); REST_8EVRS(n+8,s,base) #define REST_32EVRS(n,s,base) REST_16EVRS(n,s,base); REST_16EVRS(n+16,s,base) -/* Macros to adjust thread priority for Iseries hardware multithreading */ -#define HMT_VERY_LOW or 31,31,31 # very low priority\n" -#define HMT_LOW or 1,1,1 -#define HMT_MEDIUM_LOW or 6,6,6 # medium low priority\n" -#define HMT_MEDIUM or 2,2,2 -#define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority\n" -#define HMT_HIGH or 3,3,3 +/* Macros to adjust thread priority for hardware multithreading */ +#define HMT_VERY_LOW or 31,31,31 # very low priority +#define HMT_LOW or 1,1,1 +#define HMT_MEDIUM_LOW or 6,6,6 # medium low priority +#define HMT_MEDIUM or 2,2,2 +#define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority +#define HMT_HIGH or 3,3,3 /* handle instructions that older assemblers may not know */ #define RFCI .long 0x4c000066 /* rfci instruction */ From 21f35f28229ad1b017a0ea6cd17c10d6b9ec255f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 24 Oct 2005 15:07:29 +1000 Subject: [PATCH 0723/1939] [PATCH] powerpc: Move firmware.h into include/asm-powerpc Move firmware.h into include/asm-powerpc. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- include/{asm-ppc64 => asm-powerpc}/firmware.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/firmware.h (93%) diff --git a/include/asm-ppc64/firmware.h b/include/asm-powerpc/firmware.h similarity index 93% rename from include/asm-ppc64/firmware.h rename to include/asm-powerpc/firmware.h index 22bb85cf60af..806c142ae9ea 100644 --- a/include/asm-ppc64/firmware.h +++ b/include/asm-powerpc/firmware.h @@ -1,8 +1,4 @@ /* - * include/asm-ppc64/firmware.h - * - * Extracted from include/asm-ppc64/cputable.h - * * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) * * Modifications for ppc64: @@ -13,8 +9,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#ifndef __ASM_PPC_FIRMWARE_H -#define __ASM_PPC_FIRMWARE_H +#ifndef __ASM_POWERPC_FIRMWARE_H +#define __ASM_POWERPC_FIRMWARE_H #ifdef __KERNEL__ @@ -98,4 +94,4 @@ extern firmware_feature_t firmware_features_table[]; #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ -#endif /* __ASM_PPC_FIRMWARE_H */ +#endif /* __ASM_POWERPC_FIRMWARE_H */ From d9953105ce000abcfa988d0c160b2662186f5879 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 24 Oct 2005 15:07:30 +1000 Subject: [PATCH 0724/1939] [PATCH] powerpc: Move ras.c into arch/powerpc/platforms/pseries ras.o is only built for CONFIG_PPC_PSERIES, so move it into arch/powerpc/platforms/pseries. Update Makefiles to suit. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/Makefile | 2 +- .../{ppc64/kernel => powerpc/platforms/pseries}/ras.c | 11 +++++------ arch/ppc64/kernel/Makefile | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) rename arch/{ppc64/kernel => powerpc/platforms/pseries}/ras.c (99%) diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 9ebb34180a10..4c817304fc21 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -1,4 +1,4 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ - setup.o iommu.o + setup.o iommu.o ras.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_IBMVIO) += vio.o diff --git a/arch/ppc64/kernel/ras.c b/arch/powerpc/platforms/pseries/ras.c similarity index 99% rename from arch/ppc64/kernel/ras.c rename to arch/powerpc/platforms/pseries/ras.c index 41b97dc9cc0a..6562ff4b0a82 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -1,17 +1,16 @@ /* - * ras.c * Copyright (C) 2001 Dave Engebretsen 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 @@ -19,7 +18,7 @@ /* Change Activity: * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support. - * End Change Activity + * End Change Activity */ #include @@ -323,7 +322,7 @@ static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err) nonfatal = 1; } - log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal); + log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal); return nonfatal; } diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index ce5c99db431f..cb6ac3d1a06f 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -29,7 +29,7 @@ ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o endif -obj-$(CONFIG_PPC_PSERIES) += rtasd.o ras.o udbg_16550.o +obj-$(CONFIG_PPC_PSERIES) += rtasd.o udbg_16550.o obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ bpa_iic.o spider-pic.o From 25635c71e44111a6bd48f342e144e2fc02d0a314 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 16:36:55 +1000 Subject: [PATCH 0725/1939] ppc: Use the indirect_pci.c from arch/powerpc/sysdev This defines a CONFIG_INDIRECT_PCI symbol to control whether it gets used or not, and fixes the Kconfig to select that symbol for platforms that need it. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 10 ++ arch/powerpc/platforms/embedded6xx/Kconfig | 8 ++ arch/powerpc/sysdev/Makefile | 3 +- arch/ppc/Kconfig | 18 +++ arch/ppc/Makefile | 3 +- arch/ppc/syslib/Makefile | 38 +++--- arch/ppc/syslib/indirect_pci.c | 134 --------------------- 7 files changed, 58 insertions(+), 156 deletions(-) delete mode 100644 arch/ppc/syslib/indirect_pci.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 27f122e1f849..a3451d5bb788 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -280,11 +280,13 @@ config PPC_PSERIES config PPC_CHRP bool " Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM && PPC32 + select PPC_INDIRECT_PCI default y config PPC_PMAC bool " Apple PowerMac based machines" depends on PPC_MULTIPLATFORM + select PPC_INDIRECT_PCI if PPC32 default y config PPC_PMAC64 @@ -296,6 +298,7 @@ config PPC_PMAC64 config PPC_PREP bool " PowerPC Reference Platform (PReP) based machines" depends on PPC_MULTIPLATFORM && PPC32 + select PPC_INDIRECT_PCI default y config PPC_MAPLE @@ -637,6 +640,12 @@ config GENERIC_ISA_DMA depends on PPC64 || POWER4 || 6xx && !CPM2 default y +config PPC_INDIRECT_PCI + bool + depends on PCI + default y if 40x || 44x || 85xx || 83xx + default n + config EISA bool @@ -677,6 +686,7 @@ config PCI_QSPAN config PCI_8260 bool depends on PCI && 8260 + select PPC_INDIRECT_PCI default y config 8260_PCI9 diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 2d755b79d51f..784b41e19465 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -27,6 +27,7 @@ config CHESTNUT config SPRUCE bool "IBM-Spruce" + select PPC_INDIRECT_PCI config HDPU bool "Sky-HDPU" @@ -50,15 +51,19 @@ config LOPEC config MVME5100 bool "Motorola-MVME5100" + select PPC_INDIRECT_PCI config PPLUS bool "Motorola-PowerPlus" + select PPC_INDIRECT_PCI config PRPMC750 bool "Motorola-PrPMC750" + select PPC_INDIRECT_PCI config PRPMC800 bool "Motorola-PrPMC800" + select PPC_INDIRECT_PCI config SANDPOINT bool "Motorola-Sandpoint" @@ -74,6 +79,7 @@ config PAL4 config GEMINI bool "Synergy-Gemini" + select PPC_INDIRECT_PCI depends on BROKEN help Select Gemini if configuring for a Synergy Microsystems' Gemini @@ -226,6 +232,7 @@ config MV64360 # Really MV64360 & MV64460 config MV64X60 bool depends on (GT64260 || MV64360) + select PPC_INDIRECT_PCI default y menu "Set bridge options" @@ -274,6 +281,7 @@ config EPIC_SERIAL_MODE config MPC10X_BRIDGE bool depends on POWERPMC250 || LOPEC || SANDPOINT + select PPC_INDIRECT_PCI default y config MPC10X_OPENPIC diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index c649f03acf68..e66fef652fac 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1,3 +1,2 @@ obj-$(CONFIG_MPIC) += mpic.o -indirectpci-$(CONFIG_PPC_PMAC) = indirect_pci.o -obj-$(CONFIG_PPC32) += $(indirectpci-y) +obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index ed9c9727d75f..e3efaf47d083 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -568,6 +568,7 @@ config CHESTNUT config SPRUCE bool "IBM-Spruce" + select PPC_INDIRECT_PCI config HDPU bool "Sky-HDPU" @@ -591,15 +592,19 @@ config LOPEC config MVME5100 bool "Motorola-MVME5100" + select PPC_INDIRECT_PCI config PPLUS bool "Motorola-PowerPlus" + select PPC_INDIRECT_PCI config PRPMC750 bool "Motorola-PrPMC750" + select PPC_INDIRECT_PCI config PRPMC800 bool "Motorola-PrPMC800" + select PPC_INDIRECT_PCI config SANDPOINT bool "Motorola-Sandpoint" @@ -616,6 +621,7 @@ config PAL4 config GEMINI bool "Synergy-Gemini" depends on BROKEN + select PPC_INDIRECT_PCI help Select Gemini if configuring for a Synergy Microsystems' Gemini series Single Board Computer. More information is available at: @@ -749,11 +755,13 @@ config CPM2 config PPC_CHRP bool " Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM + select PPC_INDIRECT_PCI default y config PPC_PMAC bool " Apple PowerMac based machines" depends on PPC_MULTIPLATFORM + select PPC_INDIRECT_PCI default y config PPC_PMAC64 @@ -764,6 +772,7 @@ config PPC_PMAC64 config PPC_PREP bool " PowerPC Reference Platform (PReP) based machines" depends on PPC_MULTIPLATFORM + select PPC_INDIRECT_PCI default y config PPC_OF @@ -797,6 +806,7 @@ config MV64360 # Really MV64360 & MV64460 config MV64X60 bool depends on (GT64260 || MV64360) + select PPC_INDIRECT_PCI default y menu "Set bridge options" @@ -845,6 +855,7 @@ config EPIC_SERIAL_MODE config MPC10X_BRIDGE bool depends on POWERPMC250 || LOPEC || SANDPOINT + select PPC_INDIRECT_PCI default y config MPC10X_OPENPIC @@ -1139,6 +1150,12 @@ config GENERIC_ISA_DMA depends on POWER3 || POWER4 || 6xx && !CPM2 default y +config PPC_INDIRECT_PCI + bool + depends on PCI + default y if 40x || 44x || 85xx || 83xx + default n + config EISA bool help @@ -1182,6 +1199,7 @@ config PCI_QSPAN config PCI_8260 bool depends on PCI && 8260 + select PPC_INDIRECT_PCI default y config 8260_PCI9 diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index aedc9ae13b2a..121d2347b89f 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -61,7 +61,8 @@ head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o core-y += arch/ppc/kernel/ arch/powerpc/kernel/ \ arch/ppc/platforms/ \ - arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/ + arch/ppc/mm/ arch/ppc/lib/ \ + arch/ppc/syslib/ arch/powerpc/sysdev/ core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index f6a2f1938bfa..5739a19b9ed9 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_GEN_RTC) += todc_time.o obj-$(CONFIG_PPC4xx_DMA) += ppc4xx_dma.o obj-$(CONFIG_PPC4xx_EDMA) += ppc4xx_sgdma.o ifeq ($(CONFIG_40x),y) -obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o ppc405_pci.o +obj-$(CONFIG_PCI) += pci_auto.o ppc405_pci.o endif endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ @@ -40,43 +40,43 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif obj-$(CONFIG_PPC_OF) += prom_init.o prom.o -obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o +obj-$(CONFIG_PPC_PMAC) += open_pic.o obj-$(CONFIG_POWER4) += open_pic2.o -obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o -obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o todc_time.o -obj-$(CONFIG_BAMBOO) += indirect_pci.o pci_auto.o todc_time.o +obj-$(CONFIG_PPC_CHRP) += open_pic.o i8259.o +obj-$(CONFIG_PPC_PREP) += open_pic.o i8259.o todc_time.o +obj-$(CONFIG_BAMBOO) += pci_auto.o todc_time.o obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o -obj-$(CONFIG_EBONY) += indirect_pci.o pci_auto.o todc_time.o +obj-$(CONFIG_EBONY) += pci_auto.o todc_time.o obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o -obj-$(CONFIG_GEMINI) += open_pic.o indirect_pci.o +obj-$(CONFIG_GEMINI) += open_pic.o obj-$(CONFIG_GT64260) += gt64260_pic.o obj-$(CONFIG_LOPEC) += i8259.o pci_auto.o todc_time.o obj-$(CONFIG_HDPU) += pci_auto.o -obj-$(CONFIG_LUAN) += indirect_pci.o pci_auto.o todc_time.o +obj-$(CONFIG_LUAN) += pci_auto.o todc_time.o obj-$(CONFIG_KATANA) += pci_auto.o obj-$(CONFIG_MV64360) += mv64360_pic.o -obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o indirect_pci.o -obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o indirect_pci.o \ +obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o +obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o \ pci_auto.o hawk_common.o obj-$(CONFIG_MVME5100_IPMC761_PRESENT) += i8259.o -obj-$(CONFIG_OCOTEA) += indirect_pci.o pci_auto.o todc_time.o +obj-$(CONFIG_OCOTEA) += pci_auto.o todc_time.o obj-$(CONFIG_PAL4) += cpc700_pic.o obj-$(CONFIG_POWERPMC250) += pci_auto.o obj-$(CONFIG_PPLUS) += hawk_common.o open_pic.o i8259.o \ - indirect_pci.o todc_time.o pci_auto.o -obj-$(CONFIG_PRPMC750) += open_pic.o indirect_pci.o pci_auto.o \ + todc_time.o pci_auto.o +obj-$(CONFIG_PRPMC750) += open_pic.o pci_auto.o \ hawk_common.o obj-$(CONFIG_HARRIER) += harrier.o -obj-$(CONFIG_PRPMC800) += open_pic.o indirect_pci.o pci_auto.o +obj-$(CONFIG_PRPMC800) += open_pic.o pci_auto.o obj-$(CONFIG_RADSTONE_PPC7D) += i8259.o pci_auto.o obj-$(CONFIG_SANDPOINT) += i8259.o pci_auto.o todc_time.o obj-$(CONFIG_SBC82xx) += todc_time.o -obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \ +obj-$(CONFIG_SPRUCE) += cpc700_pic.o pci_auto.o \ todc_time.o obj-$(CONFIG_8260) += m8260_setup.o pq2_devices.o pq2_sys.o \ ppc_sys.o -obj-$(CONFIG_PCI_8260) += m82xx_pci.o indirect_pci.o pci_auto.o +obj-$(CONFIG_PCI_8260) += m82xx_pci.o pci_auto.o obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o ifeq ($(CONFIG_PPC_GEN550),y) @@ -87,7 +87,7 @@ ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y) obj-$(CONFIG_SERIAL_TEXT_DEBUG) += mv64x60_dbg.o endif obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o ppc_sys.o +obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o ppc_sys.o obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o obj-$(CONFIG_40x) += dcr.o obj-$(CONFIG_BOOKE) += dcr.o @@ -95,12 +95,12 @@ obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \ ppc_sys.o i8259.o mpc85xx_sys.o \ mpc85xx_devices.o ifeq ($(CONFIG_85xx),y) -obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o +obj-$(CONFIG_PCI) += pci_auto.o endif obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \ mpc83xx_sys.o mpc83xx_devices.o ifeq ($(CONFIG_83xx),y) -obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o +obj-$(CONFIG_PCI) += pci_auto.o endif obj-$(CONFIG_MPC8548_CDS) += todc_time.o obj-$(CONFIG_MPC8555_CDS) += todc_time.o diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c deleted file mode 100644 index e71488469704..000000000000 --- a/arch/ppc/syslib/indirect_pci.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Support for indirect PCI bridges. - * - * Copyright (C) 1998 Gabriel Paubert. - * - * 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 - -#ifdef CONFIG_PPC_INDIRECT_PCI_BE -#define PCI_CFG_OUT out_be32 -#else -#define PCI_CFG_OUT out_le32 -#endif - -static int -indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - struct pci_controller *hose = bus->sysdata; - volatile void __iomem *cfg_data; - u8 cfg_type = 0; - - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (hose->set_cfg_type) - if (bus->number != hose->first_busno) - cfg_type = 1; - - PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((bus->number - hose->bus_offset) << 16) - | (devfn << 8) | ((offset & 0xfc) | cfg_type))); - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + (offset & 3); - switch (len) { - case 1: - *val = in_8(cfg_data); - break; - case 2: - *val = in_le16(cfg_data); - break; - default: - *val = in_le32(cfg_data); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - struct pci_controller *hose = bus->sysdata; - volatile void __iomem *cfg_data; - u8 cfg_type = 0; - - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (hose->set_cfg_type) - if (bus->number != hose->first_busno) - cfg_type = 1; - - PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((bus->number - hose->bus_offset) << 16) - | (devfn << 8) | ((offset & 0xfc) | cfg_type))); - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + (offset & 3); - switch (len) { - case 1: - out_8(cfg_data, val); - break; - case 2: - out_le16(cfg_data, val); - break; - default: - out_le32(cfg_data, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops indirect_pci_ops = -{ - indirect_read_config, - indirect_write_config -}; - -void __init -setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr, - void __iomem * cfg_data) -{ - hose->cfg_addr = cfg_addr; - hose->cfg_data = cfg_data; - hose->ops = &indirect_pci_ops; -} - -void __init -setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) -{ - unsigned long base = cfg_addr & PAGE_MASK; - void __iomem *mbase, *addr, *data; - - mbase = ioremap(base, PAGE_SIZE); - addr = mbase + (cfg_addr & ~PAGE_MASK); - if ((cfg_data & PAGE_MASK) != base) - mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); - data = mbase + (cfg_data & ~PAGE_MASK); - setup_indirect_pci_nomap(hose, addr, data); -} From f9bd170a87948a9e077149b70fb192c563770fdf Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 16:47:42 +1000 Subject: [PATCH 0726/1939] powerpc: Merge i8259.c into arch/powerpc/sysdev This changes the parameters for i8259_init so that it takes two parameters: a physical address for generating an interrupt acknowledge cycle, and an interrupt number offset. i8259_init now sets the irq_desc[] for its interrupts; all the callers were doing this, and that code is gone now. This also defines a CONFIG_PPC_I8259 symbol to select i8259.o for inclusion, and makes the platforms that need it select that symbol. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 10 ++ arch/powerpc/platforms/embedded6xx/Kconfig | 5 + arch/powerpc/platforms/pseries/setup.c | 19 +- arch/powerpc/sysdev/Makefile | 1 + arch/{ppc/syslib => powerpc/sysdev}/i8259.c | 65 ++++--- arch/ppc/Kconfig | 14 ++ arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 5 +- arch/ppc/platforms/chrp_setup.c | 4 +- arch/ppc/platforms/lopec.c | 6 +- arch/ppc/platforms/mvme5100.c | 6 +- arch/ppc/platforms/pplus.c | 5 +- arch/ppc/platforms/prep_setup.c | 8 +- arch/ppc/platforms/radstone_ppc7d.c | 6 +- arch/ppc/platforms/sandpoint.c | 10 +- arch/ppc/syslib/Makefile | 19 +- arch/ppc64/Kconfig | 5 + arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/i8259.c | 177 ------------------- include/asm-powerpc/i8259.h | 3 +- 19 files changed, 99 insertions(+), 271 deletions(-) rename arch/{ppc/syslib => powerpc/sysdev}/i8259.c (76%) delete mode 100644 arch/ppc64/kernel/i8259.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a3451d5bb788..9f279e0d84f2 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -275,11 +275,13 @@ endchoice config PPC_PSERIES depends on PPC_MULTIPLATFORM && PPC64 bool " IBM pSeries & new (POWER5-based) iSeries" + select PPC_I8259 default y config PPC_CHRP bool " Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM && PPC32 + select PPC_I8259 select PPC_INDIRECT_PCI default y @@ -298,6 +300,7 @@ config PPC_PMAC64 config PPC_PREP bool " PowerPC Reference Platform (PReP) based machines" depends on PPC_MULTIPLATFORM && PPC32 + select PPC_I8259 select PPC_INDIRECT_PCI default y @@ -628,6 +631,7 @@ menu "Bus options" config ISA bool "Support for ISA-bus hardware" depends on PPC_PREP || PPC_CHRP + select PPC_I8259 help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -640,6 +644,11 @@ config GENERIC_ISA_DMA depends on PPC64 || POWER4 || 6xx && !CPM2 default y +config PPC_I8259 + bool + default y if 85xx + default n + config PPC_INDIRECT_PCI bool depends on PCI @@ -679,6 +688,7 @@ config MPC83xx_PCI2 config PCI_QSPAN bool "QSpan PCI" depends on !4xx && !CPM2 && 8xx + select PPC_I8259 help Say Y here if you have a system based on a Motorola 8xx-series embedded processor with a QSPAN PCI interface, otherwise say N. diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 784b41e19465..81250090f98d 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -48,6 +48,7 @@ config EV64260 config LOPEC bool "Motorola-LoPEC" + select PPC_I8259 config MVME5100 bool "Motorola-MVME5100" @@ -55,6 +56,7 @@ config MVME5100 config PPLUS bool "Motorola-PowerPlus" + select PPC_I8259 select PPC_INDIRECT_PCI config PRPMC750 @@ -67,12 +69,14 @@ config PRPMC800 config SANDPOINT bool "Motorola-Sandpoint" + select PPC_I8259 help Select SANDPOINT if configuring for a Motorola Sandpoint X3 (any flavor). config RADSTONE_PPC7D bool "Radstone Technology PPC7D board" + select PPC_I8259 config PAL4 bool "SBS-Palomar4" @@ -307,6 +311,7 @@ config HARRIER_STORE_GATHERING config MVME5100_IPMC761_PRESENT bool "MVME5100 configured with an IPMC761" depends on MVME5100 + select PPC_I8259 config SPRUCE_BAUD_33M bool "Spruce baud clock support" diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 92d18003f152..0fa5beae6d1b 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -87,7 +87,6 @@ extern int pSeries_machine_check_exception(struct pt_regs *regs); static void pseries_shared_idle(void); static void pseries_dedicated_idle(void); -static volatile void __iomem * chrp_int_ack_special; struct mpic *pSeries_mpic; void pSeries_show_cpuinfo(struct seq_file *m) @@ -119,19 +118,11 @@ static void __init fwnmi_init(void) fwnmi_active = 1; } -static int pSeries_irq_cascade(struct pt_regs *regs, void *data) -{ - if (chrp_int_ack_special) - return readb(chrp_int_ack_special); - else - return i8259_irq(regs); -} - static void __init pSeries_init_mpic(void) { unsigned int *addrp; struct device_node *np; - int i; + unsigned long intack = 0; /* All ISUs are setup, complete initialization */ mpic_init(pSeries_mpic); @@ -142,16 +133,14 @@ static void __init pSeries_init_mpic(void) get_property(np, "8259-interrupt-acknowledge", NULL))) printk(KERN_ERR "Cannot find pci to get ack address\n"); else - chrp_int_ack_special = ioremap(addrp[prom_n_addr_cells(np)-1], 1); + intack = addrp[prom_n_addr_cells(np)-1]; of_node_put(np); /* Setup the legacy interrupts & controller */ - for (i = 0; i < NUM_ISA_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - i8259_init(0); + i8259_init(intack, 0); /* Hook cascade to mpic */ - mpic_setup_cascade(NUM_ISA_INTERRUPTS, pSeries_irq_cascade, NULL); + mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); } static void __init pSeries_setup_mpic(void) diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index e66fef652fac..f3c9e61c3910 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_MPIC) += mpic.o obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o +obj-$(CONFIG_PPC_I8259) += i8259.o diff --git a/arch/ppc/syslib/i8259.c b/arch/powerpc/sysdev/i8259.c similarity index 76% rename from arch/ppc/syslib/i8259.c rename to arch/powerpc/sysdev/i8259.c index 5c7908c20e43..90bce6e0c191 100644 --- a/arch/ppc/syslib/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -1,18 +1,26 @@ +/* + * i8259 interrupt controller driver. + * + * 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 -static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */ +static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */ -unsigned char cached_8259[2] = { 0xff, 0xff }; +static unsigned char cached_8259[2] = { 0xff, 0xff }; #define cached_A1 (cached_8259[0]) #define cached_21 (cached_8259[1]) static DEFINE_SPINLOCK(i8259_lock); -int i8259_pic_irq_offset; +static int i8259_pic_irq_offset; /* * Acknowledge the IRQ using either the PCI host bridge's interrupt @@ -20,8 +28,7 @@ int i8259_pic_irq_offset; * which is called. It should be noted that polling is broken on some * IBM and Motorola PReP boxes so we must use the int-ack feature on them. */ -int -i8259_irq(struct pt_regs *regs) +int i8259_irq(struct pt_regs *regs) { int irq; @@ -29,7 +36,7 @@ i8259_irq(struct pt_regs *regs) /* Either int-ack or poll for the IRQ */ if (pci_intack) - irq = *pci_intack; + irq = readb(pci_intack); else { /* Perform an interrupt acknowledge cycle on controller 1. */ outb(0x0C, 0x20); /* prepare for poll */ @@ -59,7 +66,12 @@ i8259_irq(struct pt_regs *regs) } spin_unlock(&i8259_lock); - return irq; + return irq + i8259_pic_irq_offset; +} + +int i8259_irq_cascade(struct pt_regs *regs, void *unused) +{ + return i8259_irq(regs); } static void i8259_mask_and_ack_irq(unsigned int irq_nr) @@ -67,20 +79,18 @@ static void i8259_mask_and_ack_irq(unsigned int irq_nr) unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - + irq_nr -= i8259_pic_irq_offset; if (irq_nr > 7) { cached_A1 |= 1 << (irq_nr-8); - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x20,0xA0); /* Non-specific EOI */ - outb(0x20,0x20); /* Non-specific EOI to cascade */ + inb(0xA1); /* DUMMY */ + outb(cached_A1, 0xA1); + outb(0x20, 0xA0); /* Non-specific EOI */ + outb(0x20, 0x20); /* Non-specific EOI to cascade */ } else { cached_21 |= 1 << irq_nr; - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); /* Non-specific EOI */ + inb(0x21); /* DUMMY */ + outb(cached_21, 0x21); + outb(0x20, 0x20); /* Non-specific EOI */ } spin_unlock_irqrestore(&i8259_lock, flags); } @@ -96,9 +106,8 @@ static void i8259_mask_irq(unsigned int irq_nr) unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) + irq_nr -= i8259_pic_irq_offset; + if (irq_nr < 8) cached_21 |= 1 << irq_nr; else cached_A1 |= 1 << (irq_nr-8); @@ -111,9 +120,8 @@ static void i8259_unmask_irq(unsigned int irq_nr) unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) + irq_nr -= i8259_pic_irq_offset; + if (irq_nr < 8) cached_21 &= ~(1 << irq_nr); else cached_A1 &= ~(1 << (irq_nr-8)); @@ -169,12 +177,14 @@ static struct irqaction i8259_irqaction = { * intack_addr - PCI interrupt acknowledge (real) address which will return * the active irq from the 8259 */ -void __init -i8259_init(long intack_addr) +void __init i8259_init(unsigned long intack_addr, int offset) { unsigned long flags; + int i; spin_lock_irqsave(&i8259_lock, flags); + i8259_pic_irq_offset = offset; + /* init master interrupt controller */ outb(0x11, 0x20); /* Start init sequence */ outb(0x00, 0x21); /* Vector base */ @@ -198,11 +208,14 @@ i8259_init(long intack_addr) spin_unlock_irqrestore(&i8259_lock, flags); /* reserve our resources */ - setup_irq( i8259_pic_irq_offset + 2, &i8259_irqaction); + setup_irq(offset + 2, &i8259_irqaction); request_resource(&ioport_resource, &pic1_iores); request_resource(&ioport_resource, &pic2_iores); request_resource(&ioport_resource, &pic_edgectrl_iores); if (intack_addr != 0) pci_intack = ioremap(intack_addr, 1); + + for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) + irq_desc[offset + i].handler = &i8259_pic; } diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index e3efaf47d083..114b90fdea24 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -589,6 +589,7 @@ config EV64260 config LOPEC bool "Motorola-LoPEC" + select PPC_I8259 config MVME5100 bool "Motorola-MVME5100" @@ -596,6 +597,7 @@ config MVME5100 config PPLUS bool "Motorola-PowerPlus" + select PPC_I8259 select PPC_INDIRECT_PCI config PRPMC750 @@ -608,12 +610,14 @@ config PRPMC800 config SANDPOINT bool "Motorola-Sandpoint" + select PPC_I8259 help Select SANDPOINT if configuring for a Motorola Sandpoint X3 (any flavor). config RADSTONE_PPC7D bool "Radstone Technology PPC7D board" + select PPC_I8259 config PAL4 bool "SBS-Palomar4" @@ -755,6 +759,7 @@ config CPM2 config PPC_CHRP bool " Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM + select PPC_I8259 select PPC_INDIRECT_PCI default y @@ -772,6 +777,7 @@ config PPC_PMAC64 config PPC_PREP bool " PowerPC Reference Platform (PReP) based machines" depends on PPC_MULTIPLATFORM + select PPC_I8259 select PPC_INDIRECT_PCI default y @@ -881,6 +887,7 @@ config HARRIER_STORE_GATHERING config MVME5100_IPMC761_PRESENT bool "MVME5100 configured with an IPMC761" depends on MVME5100 + select PPC_I8259 config SPRUCE_BAUD_33M bool "Spruce baud clock support" @@ -1138,6 +1145,7 @@ menu "Bus options" config ISA bool "Support for ISA-bus hardware" depends on PPC_PREP || PPC_CHRP + select PPC_I8259 help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -1150,6 +1158,11 @@ config GENERIC_ISA_DMA depends on POWER3 || POWER4 || 6xx && !CPM2 default y +config PPC_I8259 + bool + default y if 85xx + default n + config PPC_INDIRECT_PCI bool depends on PCI @@ -1192,6 +1205,7 @@ config MPC83xx_PCI2 config PCI_QSPAN bool "QSpan PCI" depends on !4xx && !CPM2 && 8xx + select PPC_I8259 help Say Y here if you have a system based on a Motorola 8xx-series embedded processor with a QSPAN PCI interface, otherwise say N. diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 9f9039498ae5..eda659916f24 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -173,10 +173,7 @@ mpc85xx_cds_init_IRQ(void) #ifdef CONFIG_PCI openpic_hookup_cascade(PIRQ0A, "82c59 cascade", i8259_irq); - for (i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - i8259_init(0); + i8259_init(0, 0); #endif #ifdef CONFIG_CPM2 diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index 56c53bb3dfd4..dad81ffd4013 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -436,9 +436,7 @@ void __init chrp_init_IRQ(void) i8259_irq); } - for (i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - i8259_init(chrp_int_ack); + i8259_init(chrp_int_ack, 0); #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) /* see if there is a keyboard in the device tree diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c index 800c56a07a97..06d247c23b82 100644 --- a/arch/ppc/platforms/lopec.c +++ b/arch/ppc/platforms/lopec.c @@ -267,15 +267,11 @@ lopec_init_IRQ(void) openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", &i8259_irq); - /* Map i8259 interrupts */ - for(i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - /* * The EPIC allows for a read in the range of 0xFEF00000 -> * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. */ - i8259_init(0xfef00000); + i8259_init(0xfef00000, 0); } static int __init diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c index ce2ce88c8033..108eb182dddc 100644 --- a/arch/ppc/platforms/mvme5100.c +++ b/arch/ppc/platforms/mvme5100.c @@ -223,11 +223,7 @@ mvme5100_init_IRQ(void) openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", &i8259_irq); - /* Map i8259 interrupts. */ - for (i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - i8259_init(0); + i8259_init(0, 0); #else openpic_init(0); #endif diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c index 59eb330b2090..22bd40cfb092 100644 --- a/arch/ppc/platforms/pplus.c +++ b/arch/ppc/platforms/pplus.c @@ -665,10 +665,7 @@ static void __init pplus_init_IRQ(void) ppc_md.get_irq = openpic_get_irq; } - for (i = 0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - i8259_init(0); + i8259_init(0, 0); if (ppc_md.progress) ppc_md.progress("init_irq: exit", 0); diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 9e5637e5f5a9..067d7d53b81e 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -954,11 +954,9 @@ prep_init_IRQ(void) openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", i8259_irq); } - for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) - irq_desc[i].handler = &i8259_pic; if (have_residual_data) { - i8259_init(residual_isapic_addr()); + i8259_init(residual_isapic_addr(), 0); return; } @@ -969,11 +967,11 @@ prep_init_IRQ(void) if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA) && ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN) || (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK))) - i8259_init(0); + i8259_init(0, 0); else /* PCI interrupt ack address given in section 6.1.8 of the * PReP specification. */ - i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR); + i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR, 0); } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 5058568c13ec..6f97911c330d 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -514,13 +514,9 @@ static void __init ppc7d_init_irq(void) int irq; pr_debug("%s\n", __FUNCTION__); - i8259_init(0); + i8259_init(0, 0); mv64360_init_irq(); - /* IRQ 0..15 are handled by the cascaded 8259's of the Ali1535 */ - for (irq = 0; irq < 16; irq++) { - irq_desc[irq].handler = &i8259_pic; - } /* IRQs 5,6,9,10,11,14,15 are level sensitive */ irq_desc[5].status |= IRQ_LEVEL; irq_desc[6].status |= IRQ_LEVEL; diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c index d4c9781989fb..9eeed3572309 100644 --- a/arch/ppc/platforms/sandpoint.c +++ b/arch/ppc/platforms/sandpoint.c @@ -493,19 +493,11 @@ sandpoint_init_IRQ(void) openpic_hookup_cascade(sandpoint_is_x2 ? 17 : NUM_8259_INTERRUPTS, "82c59 cascade", i8259_irq); - /* - * openpic_init() has set up irq_desc[16-31] to be openpic - * interrupts. We need to set irq_desc[0-15] to be i8259 - * interrupts. - */ - for(i=0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - /* * The EPIC allows for a read in the range of 0xFEF00000 -> * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. */ - i8259_init(0xfef00000); + i8259_init(0xfef00000, 0); } static unsigned long __init diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 5739a19b9ed9..e6e6aa4d291e 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -36,14 +36,12 @@ endif endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o -ifeq ($(CONFIG_8xx),y) -obj-$(CONFIG_PCI) += qspan_pci.o i8259.o -endif +obj-$(CONFIG_PCI_QSPAN) += qspan_pci.o obj-$(CONFIG_PPC_OF) += prom_init.o prom.o obj-$(CONFIG_PPC_PMAC) += open_pic.o obj-$(CONFIG_POWER4) += open_pic2.o -obj-$(CONFIG_PPC_CHRP) += open_pic.o i8259.o -obj-$(CONFIG_PPC_PREP) += open_pic.o i8259.o todc_time.o +obj-$(CONFIG_PPC_CHRP) += open_pic.o +obj-$(CONFIG_PPC_PREP) += open_pic.o todc_time.o obj-$(CONFIG_BAMBOO) += pci_auto.o todc_time.o obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o obj-$(CONFIG_EBONY) += pci_auto.o todc_time.o @@ -51,7 +49,7 @@ obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o obj-$(CONFIG_GEMINI) += open_pic.o obj-$(CONFIG_GT64260) += gt64260_pic.o -obj-$(CONFIG_LOPEC) += i8259.o pci_auto.o todc_time.o +obj-$(CONFIG_LOPEC) += pci_auto.o todc_time.o obj-$(CONFIG_HDPU) += pci_auto.o obj-$(CONFIG_LUAN) += pci_auto.o todc_time.o obj-$(CONFIG_KATANA) += pci_auto.o @@ -59,18 +57,17 @@ obj-$(CONFIG_MV64360) += mv64360_pic.o obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o \ pci_auto.o hawk_common.o -obj-$(CONFIG_MVME5100_IPMC761_PRESENT) += i8259.o obj-$(CONFIG_OCOTEA) += pci_auto.o todc_time.o obj-$(CONFIG_PAL4) += cpc700_pic.o obj-$(CONFIG_POWERPMC250) += pci_auto.o -obj-$(CONFIG_PPLUS) += hawk_common.o open_pic.o i8259.o \ +obj-$(CONFIG_PPLUS) += hawk_common.o open_pic.o \ todc_time.o pci_auto.o obj-$(CONFIG_PRPMC750) += open_pic.o pci_auto.o \ hawk_common.o obj-$(CONFIG_HARRIER) += harrier.o obj-$(CONFIG_PRPMC800) += open_pic.o pci_auto.o -obj-$(CONFIG_RADSTONE_PPC7D) += i8259.o pci_auto.o -obj-$(CONFIG_SANDPOINT) += i8259.o pci_auto.o todc_time.o +obj-$(CONFIG_RADSTONE_PPC7D) += pci_auto.o +obj-$(CONFIG_SANDPOINT) += pci_auto.o todc_time.o obj-$(CONFIG_SBC82xx) += todc_time.o obj-$(CONFIG_SPRUCE) += cpc700_pic.o pci_auto.o \ todc_time.o @@ -92,7 +89,7 @@ obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o obj-$(CONFIG_40x) += dcr.o obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \ - ppc_sys.o i8259.o mpc85xx_sys.o \ + ppc_sys.o mpc85xx_sys.o \ mpc85xx_devices.o ifeq ($(CONFIG_85xx),y) obj-$(CONFIG_PCI) += pci_auto.o diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 8cbac7f32092..963f519b7713 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -123,6 +123,11 @@ config MPIC bool default y +config PPC_I8259 + depends on PPC_PSERIES + bool + default y + config BPA_IIC depends on PPC_BPA bool diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index cb6ac3d1a06f..2c541c6652b2 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -24,7 +24,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o endif diff --git a/arch/ppc64/kernel/i8259.c b/arch/ppc64/kernel/i8259.c deleted file mode 100644 index 74dcfd68fc75..000000000000 --- a/arch/ppc64/kernel/i8259.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * c 2001 PPC64 Team, 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 "i8259.h" - -unsigned char cached_8259[2] = { 0xff, 0xff }; -#define cached_A1 (cached_8259[0]) -#define cached_21 (cached_8259[1]) - -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(i8259_lock); - -static int i8259_pic_irq_offset; -static int i8259_present; - -int i8259_irq(int cpu) -{ - int irq; - - spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); - /* - * Perform an interrupt acknowledge cycle on controller 1 - */ - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { - /* - * Interrupt is cascaded so perform interrupt - * acknowledge on controller 2 - */ - outb(0x0C, 0xA0); - irq = (inb(0xA0) & 7) + 8; - } - else if (irq==7) - { - /* - * This may be a spurious interrupt - * - * Read the interrupt status register. If the most - * significant bit is not set then there is no valid - * interrupt - */ - outb(0x0b, 0x20); - if(~inb(0x20)&0x80) { - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return -1; - } - } - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return irq; -} - -static void i8259_mask_and_ack_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - - if (irq_nr > 7) { - cached_A1 |= 1 << (irq_nr-8); - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x20,0xA0); /* Non-specific EOI */ - outb(0x20,0x20); /* Non-specific EOI to cascade */ - } else { - cached_21 |= 1 << irq_nr; - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); /* Non-specific EOI */ - } - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_set_irq_mask(int irq_nr) -{ - outb(cached_A1,0xA1); - outb(cached_21,0x21); -} - -static void i8259_mask_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 |= 1 << irq_nr; - else - cached_A1 |= 1 << (irq_nr-8); - i8259_set_irq_mask(irq_nr); - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_unmask_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 &= ~(1 << irq_nr); - else - cached_A1 &= ~(1 << (irq_nr-8)); - i8259_set_irq_mask(irq_nr); - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_end_irq(unsigned int irq) -{ - if (!(get_irq_desc(irq)->status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - get_irq_desc(irq)->action) - i8259_unmask_irq(irq); -} - -struct hw_interrupt_type i8259_pic = { - .typename = " i8259 ", - .enable = i8259_unmask_irq, - .disable = i8259_mask_irq, - .ack = i8259_mask_and_ack_irq, - .end = i8259_end_irq, -}; - -void __init i8259_init(int offset) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - i8259_pic_irq_offset = offset; - i8259_present = 1; - /* init master interrupt controller */ - outb(0x11, 0x20); /* Start init sequence */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0x21); /* Select 8086 mode */ - outb(0xFF, 0x21); /* Mask all */ - /* init slave interrupt controller */ - outb(0x11, 0xA0); /* Start init sequence */ - outb(0x08, 0xA1); /* Vector base */ - outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0xA1); /* Select 8086 mode */ - outb(0xFF, 0xA1); /* Mask all */ - outb(cached_A1, 0xA1); - outb(cached_21, 0x21); - spin_unlock_irqrestore(&i8259_lock, flags); - -} - -static int i8259_request_cascade(void) -{ - if (!i8259_present) - return -ENODEV; - - request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, - "82c59 secondary cascade", NULL ); - - return 0; -} - -arch_initcall(i8259_request_cascade); diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h index 9521ad47740f..fc4bfee124d7 100644 --- a/include/asm-powerpc/i8259.h +++ b/include/asm-powerpc/i8259.h @@ -5,7 +5,8 @@ extern struct hw_interrupt_type i8259_pic; -extern void i8259_init(long intack_addr); +extern void i8259_init(unsigned long intack_addr, int offset); extern int i8259_irq(struct pt_regs *regs); +extern int i8259_irq_cascade(struct pt_regs *regs, void *unused); #endif /* _ASM_POWERPC_I8259_H */ From 033ef338b6e007dc081c6282a4f2a9dd761f8cd2 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 17:05:24 +1000 Subject: [PATCH 0727/1939] powerpc: Merge rtas.c into arch/powerpc/kernel This splits arch/ppc64/kernel/rtas.c into arch/powerpc/kernel/rtas.c, which contains generic RTAS functions useful on any CHRP platform, and arch/powerpc/platforms/pseries/rtas-fw.[ch], which contain some pSeries-specific firmware flashing bits. The parts of rtas.c that are to do with pSeries-specific error logging are protected by a new CONFIG_RTAS_ERROR_LOGGING symbol. The inclusion of rtas.o is controlled by the CONFIG_PPC_RTAS symbol, and the relevant platforms select that. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 13 ++ arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/asm-offsets.c | 6 +- arch/powerpc/kernel/entry_32.S | 12 +- arch/powerpc/kernel/prom.c | 3 - arch/{ppc64 => powerpc}/kernel/rtas.c | 255 +++++++---------------- arch/powerpc/platforms/pseries/Kconfig | 5 - arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/rtas-fw.c | 138 ++++++++++++ arch/powerpc/platforms/pseries/rtas-fw.h | 3 + arch/powerpc/platforms/pseries/setup.c | 10 +- arch/ppc64/Kconfig | 5 + arch/ppc64/kernel/Makefile | 2 +- 13 files changed, 256 insertions(+), 199 deletions(-) rename arch/{ppc64 => powerpc}/kernel/rtas.c (72%) create mode 100644 arch/powerpc/platforms/pseries/rtas-fw.c create mode 100644 arch/powerpc/platforms/pseries/rtas-fw.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9f279e0d84f2..ce5100cadd34 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -276,6 +276,8 @@ config PPC_PSERIES depends on PPC_MULTIPLATFORM && PPC64 bool " IBM pSeries & new (POWER5-based) iSeries" select PPC_I8259 + select PPC_RTAS + select RTAS_ERROR_LOGGING default y config PPC_CHRP @@ -283,6 +285,7 @@ config PPC_CHRP depends on PPC_MULTIPLATFORM && PPC32 select PPC_I8259 select PPC_INDIRECT_PCI + select PPC_RTAS default y config PPC_PMAC @@ -317,6 +320,7 @@ config PPC_MAPLE config PPC_BPA bool " Broadband Processor Architecture" depends on PPC_MULTIPLATFORM && PPC64 + select PPC_RTAS config PPC_OF bool @@ -338,6 +342,15 @@ config MPIC bool default y +config PPC_RTAS + bool + default n + +config RTAS_ERROR_LOGGING + bool + depends on PPC_RTAS + default n + config MPIC_BROKEN_U3 bool depends on PPC_MAPLE diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5d8038fed52..eaedb7e63315 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o +obj-$(CONFIG_PPC_RTAS) += rtas.o obj-$(CONFIG_IBMVIO) += vio.o ifeq ($(CONFIG_PPC_MERGE),y) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 1c83abd9f37c..710336a9f0fd 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -36,11 +36,11 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include #include -#include #include #include #include @@ -97,7 +97,7 @@ int main(void) DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC32 */ #ifdef CONFIG_PPC64 DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); @@ -142,11 +142,11 @@ int main(void) DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); +#endif /* CONFIG_PPC64 */ /* RTAS */ DEFINE(RTASBASE, offsetof(struct rtas_t, base)); DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); -#endif /* CONFIG_PPC64 */ /* Interrupt register frame */ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 37b4396ca978..960da7bea043 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -954,7 +954,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) * here so it's easy to add arch-specific sections later. * -- Cort */ -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC_RTAS /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -963,14 +963,13 @@ _GLOBAL(enter_rtas) stwu r1,-INT_FRAME_SIZE(r1) mflr r0 stw r0,INT_FRAME_SIZE+4(r1) - lis r4,rtas_data@ha - lwz r4,rtas_data@l(r4) + LOADADDR(r4, rtas) lis r6,1f@ha /* physical return address for rtas */ addi r6,r6,1f@l tophys(r6,r6) tophys(r7,r1) - lis r8,rtas_entry@ha - lwz r8,rtas_entry@l(r8) + lwz r8,RTASENTRY(r4) + lwz r4,RTASBASE(r4) mfmsr r9 stw r9,8(r1) LOAD_MSR_KERNEL(r0,MSR_KERNEL) @@ -978,7 +977,6 @@ _GLOBAL(enter_rtas) MTMSRD(r0) /* don't get trashed */ li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtlr r6 - CLR_TOP32(r7) mtspr SPRN_SPRG2,r7 mtspr SPRN_SRR0,r8 mtspr SPRN_SRR1,r9 @@ -999,4 +997,4 @@ machine_check_in_rtas: twi 31,0,0 /* XXX load up BATs and panic */ -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_RTAS */ diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 8d0c78cbc0bc..16ac15e73b44 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -110,9 +110,6 @@ struct device_node *of_chosen; struct device_node *dflt_interrupt_controller; int num_interrupt_controllers; -u32 rtas_data; -u32 rtas_entry; - /* * Wrapper for allocating memory for various data that needs to be * attached to device nodes as they are processed at boot or when diff --git a/arch/ppc64/kernel/rtas.c b/arch/powerpc/kernel/rtas.c similarity index 72% rename from arch/ppc64/kernel/rtas.c rename to arch/powerpc/kernel/rtas.c index 36adab591bd3..4d22eeeeb91d 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -25,29 +25,29 @@ #include #include #include -#include -#include #include #include +#include +#ifdef CONFIG_PPC64 #include -#include +#endif -struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; - -struct rtas_t rtas = { +struct rtas_t rtas = { .lock = SPIN_LOCK_UNLOCKED }; EXPORT_SYMBOL(rtas); -char rtas_err_buf[RTAS_ERROR_LOG_MAX]; - DEFINE_SPINLOCK(rtas_data_buf_lock); -char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; +char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned; unsigned long rtas_rmo_buf; -void -call_rtas_display_status(unsigned char c) +/* + * call_rtas_display_status and call_rtas_display_status_delay + * are designed only for very early low-level debugging, which + * is why the token is hard-coded to 10. + */ +void call_rtas_display_status(unsigned char c) { struct rtas_args *args = &rtas.args; unsigned long s; @@ -67,8 +67,7 @@ call_rtas_display_status(unsigned char c) spin_unlock_irqrestore(&rtas.lock, s); } -void -call_rtas_display_status_delay(unsigned char c) +void call_rtas_display_status_delay(unsigned char c) { static int pending_newline = 0; /* did last write end with unprinted newline? */ static int width = 16; @@ -92,8 +91,7 @@ call_rtas_display_status_delay(unsigned char c) } } -void -rtas_progress(char *s, unsigned short hex) +void rtas_progress(char *s, unsigned short hex) { struct device_node *root; int width, *p; @@ -209,18 +207,16 @@ rtas_progress(char *s, unsigned short hex) spin_unlock(&progress_lock); } -int -rtas_token(const char *service) +int rtas_token(const char *service) { int *tokp; - if (rtas.dev == NULL) { - PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n"); + if (rtas.dev == NULL) return RTAS_UNKNOWN_SERVICE; - } tokp = (int *) get_property(rtas.dev, service, NULL); return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; } +#ifdef CONFIG_RTAS_ERROR_LOGGING /* * Return the firmware-specified size of the error log buffer * for all rtas calls that require an error buffer argument. @@ -235,31 +231,38 @@ int rtas_get_error_log_max(void) rtas_error_log_max = rtas_token ("rtas-error-log-max"); if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { - printk (KERN_WARNING "RTAS: bad log buffer size %d\n", rtas_error_log_max); + printk (KERN_WARNING "RTAS: bad log buffer size %d\n", + rtas_error_log_max); rtas_error_log_max = RTAS_ERROR_LOG_MAX; } return rtas_error_log_max; } +EXPORT_SYMBOL(rtas_get_error_log_max); +char rtas_err_buf[RTAS_ERROR_LOG_MAX]; +int rtas_last_error_token; + /** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ -static int -__fetch_rtas_last_error(void) +static char *__fetch_rtas_last_error(char *altbuf) { struct rtas_args err_args, save_args; u32 bufsz; + char *buf = NULL; + + if (rtas_last_error_token == -1) + return NULL; bufsz = rtas_get_error_log_max(); - err_args.token = rtas_token("rtas-last-error"); + err_args.token = rtas_last_error_token; err_args.nargs = 2; err_args.nret = 1; - err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); err_args.args[1] = bufsz; err_args.args[2] = 0; @@ -272,23 +275,38 @@ __fetch_rtas_last_error(void) err_args = rtas.args; rtas.args = save_args; - return err_args.args[2]; + /* Log the error in the unlikely case that there was one. */ + if (unlikely(err_args.args[2] == 0)) { + if (altbuf) { + buf = altbuf; + } else { + buf = rtas_err_buf; + if (mem_init_done) + buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); + } + if (buf) + memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); + } + + return buf; } +#define get_errorlog_buffer() kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL) + +#else /* CONFIG_RTAS_ERROR_LOGGING */ +#define __fetch_rtas_last_error(x) NULL +#define get_errorlog_buffer() NULL +#endif + int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; - int i, logit = 0; + int i; unsigned long s; struct rtas_args *rtas_args; - char * buff_copy = NULL; + char *buff_copy = NULL; int ret; - PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); - PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); - PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); - PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); - PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; @@ -301,46 +319,25 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); - for (i = 0; i < nargs; ++i) { + for (i = 0; i < nargs; ++i) rtas_args->args[i] = va_arg(list, rtas_arg_t); - PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); - } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; - PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", - __pa(rtas_args)); enter_rtas(__pa(rtas_args)); - PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) - logit = (__fetch_rtas_last_error() == 0); - - ifppcdebug(PPCDBG_RTAS) { - for(i=0; i < nret ;i++) - udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); - } + buff_copy = __fetch_rtas_last_error(NULL); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; ret = (nret > 0)? rtas_args->rets[0]: 0; - /* Log the error in the unlikely case that there was one. */ - if (unlikely(logit)) { - buff_copy = rtas_err_buf; - if (mem_init_done) { - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); - if (buff_copy) - memcpy(buff_copy, rtas_err_buf, - RTAS_ERROR_LOG_MAX); - } - } - /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas.lock, s); @@ -355,8 +352,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) /* 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). */ -unsigned int -rtas_extended_busy_delay_time(int status) +unsigned int rtas_extended_busy_delay_time(int status) { int order = status - 9900; unsigned long ms; @@ -367,7 +363,7 @@ rtas_extended_busy_delay_time(int status) order = 5; /* bound */ /* Use microseconds for reasonable accuracy */ - for (ms=1; order > 0; order--) + for (ms = 1; order > 0; order--) ms *= 10; return ms; @@ -494,112 +490,23 @@ int rtas_set_indicator(int indicator, int index, int new_value) return rc; } -#define FLASH_BLOCK_LIST_VERSION (1UL) -static void -rtas_flash_firmware(void) +void rtas_restart(char *cmd) { - unsigned long image_size; - struct flash_block_list *f, *next, *flist; - unsigned long rtas_block_list; - int i, status, update_token; - - update_token = rtas_token("ibm,update-flash-64-and-reboot"); - if (update_token == RTAS_UNKNOWN_SERVICE) { - printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); - printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); - return; - } - - /* NOTE: the "first" block list is a global var with no data - * blocks in the kernel data segment. We do this because - * we want to ensure this block_list addr is under 4GB. - */ - rtas_firmware_flash_list.num_blocks = 0; - flist = (struct flash_block_list *)&rtas_firmware_flash_list; - rtas_block_list = virt_to_abs(flist); - if (rtas_block_list >= 4UL*1024*1024*1024) { - printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); - return; - } - - printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); - /* Update the block_list in place. */ - image_size = 0; - for (f = flist; f; f = next) { - /* Translate data addrs to absolute */ - for (i = 0; i < f->num_blocks; i++) { - f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); - image_size += f->blocks[i].length; - } - next = f->next; - /* Don't translate NULL pointer for last entry */ - if (f->next) - f->next = (struct flash_block_list *)virt_to_abs(f->next); - else - f->next = NULL; - /* make num_blocks into the version/length field */ - f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); - } - - printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); - printk(KERN_ALERT "FLASH: performing flash and reboot\n"); - rtas_progress("Flashing \n", 0x0); - rtas_progress("Please Wait... ", 0x0); - printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); - status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); - switch (status) { /* should only get "bad" status */ - case 0: - printk(KERN_ALERT "FLASH: success\n"); - break; - case -1: - printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); - break; - case -3: - printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); - break; - case -4: - printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); - break; - default: - printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); - break; - } -} - -void rtas_flash_bypass_warning(void) -{ - printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); - printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); -} - - -void -rtas_restart(char *cmd) -{ - if (rtas_firmware_flash_list.next) - rtas_flash_firmware(); - printk("RTAS system-reboot returned %d\n", rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); for (;;); } -void -rtas_power_off(void) +void rtas_power_off(void) { - if (rtas_firmware_flash_list.next) - rtas_flash_bypass_warning(); /* allow power on only with power button press */ printk("RTAS power-off returned %d\n", rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); for (;;); } -void -rtas_halt(void) +void rtas_halt(void) { - if (rtas_firmware_flash_list.next) - rtas_flash_bypass_warning(); rtas_power_off(); } @@ -632,9 +539,8 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { struct rtas_args args; unsigned long flags; - char * buff_copy; + char *buff_copy, *errbuf = NULL; int nargs; - int err_rc = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -653,7 +559,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL); + buff_copy = get_errorlog_buffer(); spin_lock_irqsave(&rtas.lock, flags); @@ -665,19 +571,14 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ - if (args.rets[0] == -1) { - err_rc = __fetch_rtas_last_error(); - if ((err_rc == 0) && buff_copy) { - memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); - } - } + if (args.rets[0] == -1) + errbuf = __fetch_rtas_last_error(buff_copy); spin_unlock_irqrestore(&rtas.lock, flags); if (buff_copy) { - if ((args.rets[0] == -1) && (err_rc == 0)) { - log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); - } + if (errbuf) + log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } @@ -690,6 +591,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) return 0; } +#ifdef CONFIG_SMP /* This version can't take the spinlock, because it never returns */ struct rtas_args rtas_stop_self_args = { @@ -714,6 +616,7 @@ void rtas_stop_self(void) panic("Alas, I survived.\n"); } +#endif /* * Call early during boot, before mem init or bootmem, to retreive the RTAS @@ -722,6 +625,8 @@ void rtas_stop_self(void) */ void __init rtas_initialize(void) { + unsigned long rtas_region = RTAS_INSTANTIATE_MAX; + /* Get RTAS dev node and fill up our "rtas" structure with infos * about it. */ @@ -743,26 +648,27 @@ void __init rtas_initialize(void) } else rtas.dev = NULL; } + if (!rtas.dev) + return; + /* If RTAS was found, allocate the RMO buffer for it and look for * the stop-self token if any */ - if (rtas.dev) { - unsigned long rtas_region = RTAS_INSTANTIATE_MAX; - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) - rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); - - rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, - rtas_region); +#ifdef CONFIG_PPC64 + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) + rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); +#endif + rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); #ifdef CONFIG_HOTPLUG_CPU - rtas_stop_self_args.token = rtas_token("stop-self"); + rtas_stop_self_args.token = rtas_token("stop-self"); #endif /* CONFIG_HOTPLUG_CPU */ - } - +#ifdef CONFIG_RTAS_ERROR_LOGGING + rtas_last_error_token = rtas_token("rtas-last-error"); +#endif } -EXPORT_SYMBOL(rtas_firmware_flash_list); EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); @@ -772,4 +678,3 @@ EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); EXPORT_SYMBOL(rtas_set_indicator); -EXPORT_SYMBOL(rtas_get_error_log_max); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 7a3b6fc4d976..2d57f588151d 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -21,11 +21,6 @@ config EEH depends on PPC_PSERIES default y if !EMBEDDED -config PPC_RTAS - bool - depends on PPC_PSERIES || PPC_BPA - default y - config RTAS_PROC bool "Proc interface to RTAS" depends on PPC_RTAS diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 4c817304fc21..d5c160b789e3 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -1,4 +1,4 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ - setup.o iommu.o ras.o + setup.o iommu.o rtas-fw.o ras.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_IBMVIO) += vio.o diff --git a/arch/powerpc/platforms/pseries/rtas-fw.c b/arch/powerpc/platforms/pseries/rtas-fw.c new file mode 100644 index 000000000000..15d81d758ca0 --- /dev/null +++ b/arch/powerpc/platforms/pseries/rtas-fw.c @@ -0,0 +1,138 @@ +/* + * + * Procedures for firmware flash updates on pSeries systems. + * + * Peter Bergner, IBM March 2001. + * Copyright (C) 2001 IBM. + * + * 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 "rtas-fw.h" + +struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; + +#define FLASH_BLOCK_LIST_VERSION (1UL) + +static void rtas_flash_firmware(void) +{ + unsigned long image_size; + struct flash_block_list *f, *next, *flist; + unsigned long rtas_block_list; + int i, status, update_token; + + update_token = rtas_token("ibm,update-flash-64-and-reboot"); + if (update_token == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); + printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); + return; + } + + /* NOTE: the "first" block list is a global var with no data + * blocks in the kernel data segment. We do this because + * we want to ensure this block_list addr is under 4GB. + */ + rtas_firmware_flash_list.num_blocks = 0; + flist = (struct flash_block_list *)&rtas_firmware_flash_list; + rtas_block_list = virt_to_abs(flist); + if (rtas_block_list >= 4UL*1024*1024*1024) { + printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); + return; + } + + printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); + /* Update the block_list in place. */ + image_size = 0; + for (f = flist; f; f = next) { + /* Translate data addrs to absolute */ + for (i = 0; i < f->num_blocks; i++) { + f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); + image_size += f->blocks[i].length; + } + next = f->next; + /* Don't translate NULL pointer for last entry */ + if (f->next) + f->next = (struct flash_block_list *)virt_to_abs(f->next); + else + f->next = NULL; + /* make num_blocks into the version/length field */ + f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); + } + + printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); + printk(KERN_ALERT "FLASH: performing flash and reboot\n"); + rtas_progress("Flashing \n", 0x0); + rtas_progress("Please Wait... ", 0x0); + printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); + status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); + switch (status) { /* should only get "bad" status */ + case 0: + printk(KERN_ALERT "FLASH: success\n"); + break; + case -1: + printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); + break; + case -3: + printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); + break; + case -4: + printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); + break; + default: + printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); + break; + } +} + +void rtas_flash_bypass_warning(void) +{ + printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); + printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); +} + + +void rtas_fw_restart(char *cmd) +{ + if (rtas_firmware_flash_list.next) + rtas_flash_firmware(); + rtas_restart(cmd); +} + +void rtas_fw_power_off(void) +{ + if (rtas_firmware_flash_list.next) + rtas_flash_bypass_warning(); + rtas_power_off(); +} + +void rtas_fw_halt(void) +{ + if (rtas_firmware_flash_list.next) + rtas_flash_bypass_warning(); + rtas_halt(); +} + +EXPORT_SYMBOL(rtas_firmware_flash_list); diff --git a/arch/powerpc/platforms/pseries/rtas-fw.h b/arch/powerpc/platforms/pseries/rtas-fw.h new file mode 100644 index 000000000000..e70fa69974a3 --- /dev/null +++ b/arch/powerpc/platforms/pseries/rtas-fw.h @@ -0,0 +1,3 @@ +void rtas_fw_restart(char *cmd); +void rtas_fw_power_off(void); +void rtas_fw_halt(void); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 0fa5beae6d1b..7e7e556e6b48 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -1,5 +1,5 @@ /* - * linux/arch/ppc/kernel/setup.c + * 64-bit pSeries and RS/6000 setup code. * * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas @@ -67,6 +67,8 @@ #include #include +#include "rtas-fw.h" + #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) #else @@ -589,9 +591,9 @@ struct machdep_calls __initdata pSeries_md = { .pcibios_fixup = pSeries_final_fixup, .pci_probe_mode = pSeries_pci_probe_mode, .irq_bus_setup = pSeries_irq_bus_setup, - .restart = rtas_restart, - .power_off = rtas_power_off, - .halt = rtas_halt, + .restart = rtas_fw_restart, + .power_off = rtas_fw_power_off, + .halt = rtas_fw_halt, .panic = rtas_os_term, .cpu_die = pSeries_mach_cpu_die, .get_boot_time = rtas_get_boot_time, diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 963f519b7713..8cc73cc1b4c4 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -318,6 +318,11 @@ config PPC_RTAS depends on PPC_PSERIES || PPC_BPA default y +config RTAS_ERROR_LOGGING + bool + depends on PPC_RTAS + default y + config RTAS_PROC bool "Proc interface to RTAS" depends on PPC_RTAS diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 2c541c6652b2..83ecefdcfef7 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_MODULES) += module.o ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_MODULES) += ppc_ksyms.o endif -obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o +obj-$(CONFIG_PPC_RTAS) += rtas_pci.o obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_LPARCFG) += lparcfg.o From 03501dab035ab7da5e1373f5e130cfd6346d3f21 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 17:11:18 +1000 Subject: [PATCH 0728/1939] powerpc: Pull common bits of setup_{32,64}.c into setup-common.c This creates a new arch/powerpc/kernel/setup-common.c with various bits that setup_32.c and setup_64.c had in common - functions like machine_shutdown/restart/power_off, show_cpuinfo, set_preferred_console etc. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/ppc_ksyms.c | 2 - arch/powerpc/kernel/setup-common.c | 412 +++++++++++++++++++++++++++++ arch/powerpc/kernel/setup_32.c | 249 +---------------- 4 files changed, 417 insertions(+), 248 deletions(-) create mode 100644 arch/powerpc/kernel/setup-common.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index eaedb7e63315..30101762f7c0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -32,7 +32,7 @@ extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ - prom.o systbl.o traps.o + prom.o systbl.o traps.o setup-common.o obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 254bf9c0b5bb..5f3a12bb8961 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -231,7 +230,6 @@ EXPORT_SYMBOL(screen_info); #endif #ifdef CONFIG_PPC32 -EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c new file mode 100644 index 000000000000..d4f0a4c3b5bc --- /dev/null +++ b/arch/powerpc/kernel/setup-common.c @@ -0,0 +1,412 @@ +/* + * Common boot and setup code for both 32-bit and 64-bit. + * Extracted from arch/powerpc/kernel/setup_64.c. + * + * Copyright (C) 2001 PPC64 Team, 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 +#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 + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * This still seems to be needed... -- paulus + */ +struct screen_info screen_info = { + .orig_x = 0, + .orig_y = 25, + .orig_video_cols = 80, + .orig_video_lines = 25, + .orig_video_isVGA = 1, + .orig_video_points = 16 +}; + +#ifdef __DO_IRQ_CANON +/* XXX should go elsewhere eventually */ +int ppc_do_canonicalize_irqs; +EXPORT_SYMBOL(ppc_do_canonicalize_irqs); +#endif + +/* also used by kexec */ +void machine_shutdown(void) +{ + if (ppc_md.nvram_sync) + ppc_md.nvram_sync(); +} + +void machine_restart(char *cmd) +{ + machine_shutdown(); + ppc_md.restart(cmd); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} + +void machine_power_off(void) +{ + machine_shutdown(); + ppc_md.power_off(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} +/* Used by the G5 thermal driver */ +EXPORT_SYMBOL_GPL(machine_power_off); + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL_GPL(pm_power_off); + +void machine_halt(void) +{ + machine_shutdown(); + ppc_md.halt(); +#ifdef CONFIG_SMP + smp_send_stop(); +#endif + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) ; +} + + +#ifdef CONFIG_TAU +extern u32 cpu_temp(unsigned long cpu); +extern u32 cpu_temp_both(unsigned long cpu); +#endif /* CONFIG_TAU */ + +#ifdef CONFIG_SMP +DEFINE_PER_CPU(unsigned int, pvr); +#endif + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long cpu_id = (unsigned long)v - 1; + unsigned int pvr; + unsigned short maj; + unsigned short min; + + if (cpu_id == NR_CPUS) { +#if defined(CONFIG_SMP) && defined(CONFIG_PPC32) + unsigned long bogosum = 0; + int i; + for (i = 0; i < NR_CPUS; ++i) + if (cpu_online(i)) + bogosum += loops_per_jiffy; + seq_printf(m, "total bogomips\t: %lu.%02lu\n", + bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); +#endif /* CONFIG_SMP && CONFIG_PPC32 */ + seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); + + if (ppc_md.show_cpuinfo != NULL) + ppc_md.show_cpuinfo(m); + + return 0; + } + + /* We only show online cpus: disable preempt (overzealous, I + * knew) to prevent cpu going down. */ + preempt_disable(); + if (!cpu_online(cpu_id)) { + preempt_enable(); + return 0; + } + +#ifdef CONFIG_SMP +#ifdef CONFIG_PPC64 /* XXX for now */ + pvr = per_cpu(pvr, cpu_id); +#else + pvr = cpu_data[cpu_id].pvr; +#endif +#else + pvr = mfspr(SPRN_PVR); +#endif + maj = (pvr >> 8) & 0xFF; + min = pvr & 0xFF; + + seq_printf(m, "processor\t: %lu\n", cpu_id); + seq_printf(m, "cpu\t\t: "); + + if (cur_cpu_spec->pvr_mask) + seq_printf(m, "%s", cur_cpu_spec->cpu_name); + else + seq_printf(m, "unknown (%08x)", pvr); + +#ifdef CONFIG_ALTIVEC + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + seq_printf(m, ", altivec supported"); +#endif /* CONFIG_ALTIVEC */ + + seq_printf(m, "\n"); + +#ifdef CONFIG_TAU + if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { +#ifdef CONFIG_TAU_AVERAGE + /* more straightforward, but potentially misleading */ + seq_printf(m, "temperature \t: %u C (uncalibrated)\n", + cpu_temp(i)); +#else + /* show the actual temp sensor range */ + u32 temp; + temp = cpu_temp_both(i); + seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", + temp & 0xff, temp >> 16); +#endif + } +#endif /* CONFIG_TAU */ + + /* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ + if (ppc_proc_freq) + seq_printf(m, "clock\t\t: %lu.%06luMHz\n", + ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); + + if (ppc_md.show_percpuinfo != NULL) + ppc_md.show_percpuinfo(m, cpu_id); + + /* If we are a Freescale core do a simple check so + * we dont have to keep adding cases in the future */ + if (PVR_VER(pvr) & 0x8000) { + maj = PVR_MAJ(pvr); + min = PVR_MIN(pvr); + } else { + switch (PVR_VER(pvr)) { + case 0x0020: /* 403 family */ + maj = PVR_MAJ(pvr) + 1; + min = PVR_MIN(pvr); + break; + case 0x1008: /* 740P/750P ?? */ + maj = ((pvr >> 8) & 0xFF) - 1; + min = pvr & 0xFF; + break; + default: + maj = (pvr >> 8) & 0xFF; + min = pvr & 0xFF; + break; + } + } + + seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", + maj, min, PVR_VER(pvr), PVR_REV(pvr)); + +#ifdef CONFIG_PPC32 + seq_printf(m, "bogomips\t: %lu.%02lu\n", + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); +#endif + +#ifdef CONFIG_SMP + seq_printf(m, "\n"); +#endif + + preempt_enable(); + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; + + return i <= NR_CPUS ? (void *)(i + 1) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +#ifdef CONFIG_PPC_MULTIPLATFORM +static int __init set_preferred_console(void) +{ + struct device_node *prom_stdout = NULL; + char *name; + u32 *spd; + int offset = 0; + + DBG(" -> set_preferred_console()\n"); + + /* The user has requested a console so this is already set up. */ + if (strstr(saved_command_line, "console=")) { + DBG(" console was specified !\n"); + return -EBUSY; + } + + if (!of_chosen) { + DBG(" of_chosen is NULL !\n"); + return -ENODEV; + } + /* We are getting a weird phandle from OF ... */ + /* ... So use the full path instead */ + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) { + DBG(" no linux,stdout-path !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_path(name); + if (!prom_stdout) { + DBG(" can't find stdout package %s !\n", name); + return -ENODEV; + } + DBG("stdout is %s\n", prom_stdout->full_name); + + name = (char *)get_property(prom_stdout, "name", NULL); + if (!name) { + DBG(" stdout package has no name !\n"); + goto not_found; + } + spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); + + if (0) + ; +#ifdef CONFIG_SERIAL_8250_CONSOLE + else if (strcmp(name, "serial") == 0) { + int i; + u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); + if (i > 8) { + switch (reg[1]) { + case 0x3f8: + offset = 0; + break; + case 0x2f8: + offset = 1; + break; + case 0x898: + offset = 2; + break; + case 0x890: + offset = 3; + break; + default: + /* We dont recognise the serial port */ + goto not_found; + } + } + } +#endif /* CONFIG_SERIAL_8250_CONSOLE */ +#ifdef CONFIG_PPC_PSERIES + else if (strcmp(name, "vty") == 0) { + u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); + char *compat = (char *)get_property(prom_stdout, "compatible", NULL); + + if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { + /* Host Virtual Serial Interface */ + int offset; + switch (reg[0]) { + case 0x30000000: + offset = 0; + break; + case 0x30000001: + offset = 1; + break; + default: + goto not_found; + } + of_node_put(prom_stdout); + DBG("Found hvsi console at offset %d\n", offset); + return add_preferred_console("hvsi", offset, NULL); + } else { + /* pSeries LPAR virtual console */ + of_node_put(prom_stdout); + DBG("Found hvc console\n"); + return add_preferred_console("hvc", 0, NULL); + } + } +#endif /* CONFIG_PPC_PSERIES */ +#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE + else if (strcmp(name, "ch-a") == 0) + offset = 0; + else if (strcmp(name, "ch-b") == 0) + offset = 1; +#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ + else + goto not_found; + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); + + if (spd) { + static char __initdata opt[16]; + sprintf(opt, "%d", *spd); + return add_preferred_console("ttyS", offset, opt); + } else + return add_preferred_console("ttyS", offset, NULL); + + not_found: + DBG("No preferred console found !\n"); + of_node_put(prom_stdout); + return -ENODEV; +} +console_initcall(set_preferred_console); +#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index c6a67c65852a..295d5c77f020 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -41,6 +41,8 @@ #include #include +#define DBG(fmt...) + #if defined CONFIG_KGDB #include #endif @@ -108,168 +110,6 @@ struct screen_info screen_info = { }; #endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */ -void machine_restart(char *cmd) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - ppc_md.restart(cmd); -} - -void machine_power_off(void) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - ppc_md.power_off(); -} - -void machine_halt(void) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - ppc_md.halt(); -} - -void (*pm_power_off)(void) = machine_power_off; - -#ifdef CONFIG_TAU -extern u32 cpu_temp(unsigned long cpu); -extern u32 cpu_temp_both(unsigned long cpu); -#endif /* CONFIG_TAU */ - -int show_cpuinfo(struct seq_file *m, void *v) -{ - int i = (int) v - 1; - unsigned int pvr; - unsigned short maj, min; - unsigned long lpj; - - if (i >= NR_CPUS) { - /* Show summary information */ -#ifdef CONFIG_SMP - unsigned long bogosum = 0; - for (i = 0; i < NR_CPUS; ++i) - if (cpu_online(i)) - bogosum += cpu_data[i].loops_per_jiffy; - seq_printf(m, "total bogomips\t: %lu.%02lu\n", - bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); -#endif /* CONFIG_SMP */ - - if (ppc_md.show_cpuinfo != NULL) - ppc_md.show_cpuinfo(m); - return 0; - } - -#ifdef CONFIG_SMP - if (!cpu_online(i)) - return 0; - pvr = cpu_data[i].pvr; - lpj = cpu_data[i].loops_per_jiffy; -#else - pvr = mfspr(SPRN_PVR); - lpj = loops_per_jiffy; -#endif - - seq_printf(m, "processor\t: %d\n", i); - seq_printf(m, "cpu\t\t: "); - - if (cur_cpu_spec->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec->cpu_name); - else - seq_printf(m, "unknown (%08x)", pvr); -#ifdef CONFIG_ALTIVEC - if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) - seq_printf(m, ", altivec supported"); -#endif - seq_printf(m, "\n"); - -#ifdef CONFIG_TAU - if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { -#ifdef CONFIG_TAU_AVERAGE - /* more straightforward, but potentially misleading */ - seq_printf(m, "temperature \t: %u C (uncalibrated)\n", - cpu_temp(i)); -#else - /* show the actual temp sensor range */ - u32 temp; - temp = cpu_temp_both(i); - seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", - temp & 0xff, temp >> 16); -#endif - } -#endif /* CONFIG_TAU */ - - if (ppc_md.show_percpuinfo != NULL) - ppc_md.show_percpuinfo(m, i); - - /* If we are a Freescale core do a simple check so - * we dont have to keep adding cases in the future */ - if (PVR_VER(pvr) & 0x8000) { - maj = PVR_MAJ(pvr); - min = PVR_MIN(pvr); - } else { - switch (PVR_VER(pvr)) { - case 0x0020: /* 403 family */ - maj = PVR_MAJ(pvr) + 1; - min = PVR_MIN(pvr); - break; - case 0x1008: /* 740P/750P ?? */ - maj = ((pvr >> 8) & 0xFF) - 1; - min = pvr & 0xFF; - break; - default: - maj = (pvr >> 8) & 0xFF; - min = pvr & 0xFF; - break; - } - } - - /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ - seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, - ppc_proc_freq % 1000000); - - seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", - maj, min, PVR_VER(pvr), PVR_REV(pvr)); - - seq_printf(m, "bogomips\t: %lu.%02lu\n", - lpj / (500000/HZ), (lpj / (5000/HZ)) % 100); - -#ifdef CONFIG_SMP - seq_printf(m, "\n"); -#endif - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - int i = *pos; - - return i <= NR_CPUS? (void *) (i + 1): NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - /* * We're called here very early in the boot. We determine the machine * type and call the appropriate low-level setup functions. @@ -297,30 +137,6 @@ unsigned long __init early_init(unsigned long dt_ptr) return KERNELBASE + offset; } -#ifdef CONFIG_PPC_OF -void __init -intuit_machine_type(void) -{ - char *model; - struct device_node *root; - - /* ask the OF info if we're a chrp or pmac */ - root = find_path_device("/"); - if (root != 0) { - /* assume pmac unless proven to be chrp -- Cort */ - _machine = _MACH_Pmac; - model = get_property(root, "device_type", NULL); - if (model && !strncmp("chrp", model, 4)) - _machine = _MACH_chrp; - else { - model = get_property(root, "model", NULL); - if (model && !strncmp(model, "IBM", 3)) - _machine = _MACH_chrp; - } - } -} -#endif - #ifdef CONFIG_PPC_MULTIPLATFORM /* * The PPC_MULTIPLATFORM version of platform_init... @@ -362,64 +178,7 @@ void __init platform_init(void) #endif } } - -#ifdef CONFIG_SERIAL_CORE_CONSOLE -extern char *of_stdout_device; - -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout; - char *name; - int offset = 0; - - if (of_stdout_device == NULL) - return -ENODEV; - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) - return -EBUSY; - - prom_stdout = find_path_device(of_stdout_device); - if (!prom_stdout) - return -ENODEV; - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) - return -ENODEV; - - if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - return -ENODEV; - } - } - } else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; - else - return -ENODEV; - return add_preferred_console("ttyS", offset, NULL); -} -console_initcall(set_preferred_console); -#endif /* CONFIG_SERIAL_CORE_CONSOLE */ -#endif /* CONFIG_PPC_MULTIPLATFORM */ +#endif /* * Find out what kind of machine we're on and save any data we need @@ -545,7 +304,7 @@ void __init setup_arch(char **cmdline_p) init_boot_display(); #endif -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_PPC_PMAC /* This could be called "early setup arch", it must be done * now because xmon need it */ From 830825d6c37a28061c0b6ca538a6411001cf3b2a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 17:16:38 +1000 Subject: [PATCH 0729/1939] powerpc: Pull out MPC106 (grackle) initialization code into its own file This is so that the 32-bit CHRP code can use it. The MPC106 initialization code is now in arch/powerpc/sysdev/grackle.c and is controlled by CONFIG_PPC_MPC106. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 5 +++ arch/powerpc/platforms/powermac/pci.c | 45 +------------------ arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/grackle.c | 64 +++++++++++++++++++++++++++ include/asm-powerpc/grackle.h | 7 +++ 5 files changed, 78 insertions(+), 44 deletions(-) create mode 100644 arch/powerpc/sysdev/grackle.c create mode 100644 include/asm-powerpc/grackle.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index ce5100cadd34..964ded4a757f 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -286,6 +286,7 @@ config PPC_CHRP select PPC_I8259 select PPC_INDIRECT_PCI select PPC_RTAS + select PPC_MPC106 default y config PPC_PMAC @@ -366,6 +367,10 @@ config IBMVIO bool default y +config PPC_MPC106 + bool + default n + source "drivers/cpufreq/Kconfig" config CPU_FREQ_PMAC diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index ebe22a2267d2..8f818d092e2b 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include @@ -584,50 +585,6 @@ static void __init fixup_nec_usb2(void) } } -#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ - | (((o) & ~3) << 24)) - -#define GRACKLE_PICR1_STG 0x00000040 -#define GRACKLE_PICR1_LOOPSNOOP 0x00000010 - -/* N.B. this is called before bridges is initialized, so we can't - use grackle_pcibios_{read,write}_config_dword. */ -static inline void grackle_set_stg(struct pci_controller* bp, int enable) -{ - unsigned int val; - - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - val = in_le32(bp->cfg_data); - val = enable? (val | GRACKLE_PICR1_STG) : - (val & ~GRACKLE_PICR1_STG); - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - out_le32(bp->cfg_data, val); - (void)in_le32(bp->cfg_data); -} - -static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) -{ - unsigned int val; - - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - val = in_le32(bp->cfg_data); - val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : - (val & ~GRACKLE_PICR1_LOOPSNOOP); - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - out_le32(bp->cfg_data, val); - (void)in_le32(bp->cfg_data); -} - -void __init setup_grackle(struct pci_controller *hose) -{ - setup_indirect_pci(hose, 0xfec00000, 0xfee00000); - if (machine_is_compatible("AAPL,PowerBook1998")) - grackle_set_loop_snoop(hose, 1); -#if 0 /* Disabled for now, HW problems ??? */ - grackle_set_stg(hose, 1); -#endif -} - static void __init setup_bandit(struct pci_controller *hose, struct reg_property *addr) { diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index f3c9e61c3910..97119c0ffc72 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_MPIC) += mpic.o obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_I8259) += i8259.o +obj-$(CONFIG_PPC_MPC106) += grackle.o diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c new file mode 100644 index 000000000000..b6ec793a23be --- /dev/null +++ b/arch/powerpc/sysdev/grackle.c @@ -0,0 +1,64 @@ +/* + * Functions for setting up and using a MPC106 northbridge + * Extracted from arch/powerpc/platforms/powermac/pci.c. + * + * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) + * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) + * + * 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 + +#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ + | (((o) & ~3) << 24)) + +#define GRACKLE_PICR1_STG 0x00000040 +#define GRACKLE_PICR1_LOOPSNOOP 0x00000010 + +/* N.B. this is called before bridges is initialized, so we can't + use grackle_pcibios_{read,write}_config_dword. */ +static inline void grackle_set_stg(struct pci_controller* bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_STG) : + (val & ~GRACKLE_PICR1_STG); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : + (val & ~GRACKLE_PICR1_LOOPSNOOP); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +void __init setup_grackle(struct pci_controller *hose) +{ + setup_indirect_pci(hose, 0xfec00000, 0xfee00000); + if (machine_is_compatible("AAPL,PowerBook1998")) + grackle_set_loop_snoop(hose, 1); +#if 0 /* Disabled for now, HW problems ??? */ + grackle_set_stg(hose, 1); +#endif +} diff --git a/include/asm-powerpc/grackle.h b/include/asm-powerpc/grackle.h new file mode 100644 index 000000000000..563c7a5e64c9 --- /dev/null +++ b/include/asm-powerpc/grackle.h @@ -0,0 +1,7 @@ +/* + * Functions for setting up and using a MPC106 northbridge + */ + +#include + +extern void setup_grackle(struct pci_controller *hose); From 6d0124fc06be40deafca043c73a8203c78bbfe45 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 17:19:06 +1000 Subject: [PATCH 0730/1939] powerpc: Fix interrupt-tree parsing The interrupt-tree parsing code wasn't offsetting interrupt numbers by 16 on 32-bit platforms with an i8259 interrupt controller, and it was confused about the encoding of interrupt sense and level (which is different for i8259 and openpic interrupt controllers, just to make things interesting). Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 40 +++++++++++++++++++++++++------------- include/asm-powerpc/irq.h | 2 ++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 16ac15e73b44..ab9b291dda54 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -296,13 +296,28 @@ static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictr return nintrc; } +static unsigned char map_isa_senses[4] = { + IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, + IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE, + IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE, + IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE +}; + +static unsigned char map_mpic_senses[4] = { + IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE, + IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, + /* 2 seems to be used for the 8259 cascade... */ + IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE, + IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE, +}; + static int __devinit finish_node_interrupts(struct device_node *np, unsigned long *mem_start, int measure_only) { unsigned int *ints; int intlen, intrcells, intrcount; - int i, j, n; + int i, j, n, sense; unsigned int *irq, virq; struct device_node *ic; @@ -332,7 +347,8 @@ static int __devinit finish_node_interrupts(struct device_node *np, for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ints++; - np->intrs[i].sense = 1; + np->intrs[i].sense = IRQ_SENSE_LEVEL + | IRQ_POLARITY_NEGATIVE; } return 0; } @@ -359,19 +375,20 @@ static int __devinit finish_node_interrupts(struct device_node *np, /* don't map IRQ numbers under a cascaded 8259 controller */ if (ic && device_is_compatible(ic, "chrp,iic")) { np->intrs[intrcount].line = irq[0]; + sense = (n > 1)? (irq[1] & 3): 3; + np->intrs[intrcount].sense = map_isa_senses[sense]; } else { -#ifdef CONFIG_PPC64 virq = virt_irq_create_mapping(irq[0]); +#ifdef CONFIG_PPC64 if (virq == NO_IRQ) { printk(KERN_CRIT "Could not allocate interrupt" " number for %s\n", np->full_name); continue; } - virq = irq_offset_up(virq); -#else - virq = irq[0]; #endif - np->intrs[intrcount].line = virq; + np->intrs[intrcount].line = irq_offset_up(virq); + sense = (n > 1)? (irq[1] & 3): 1; + np->intrs[intrcount].sense = map_mpic_senses[sense]; } #ifdef CONFIG_PPC64 @@ -386,9 +403,6 @@ static int __devinit finish_node_interrupts(struct device_node *np, break; } #endif - np->intrs[intrcount].sense = 1; - if (n > 1) - np->intrs[intrcount].sense = irq[1]; if (n > 2) { printk("hmmm, got %d intr cells for %s:", n, np->full_name); @@ -1401,15 +1415,13 @@ void __init prom_get_irq_senses(unsigned char *senses, int off, int max) int i, j; /* default to level-triggered */ - memset(senses, 1, max - off); + memset(senses, IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, max - off); for (np = allnodes; np != 0; np = np->allnext) { for (j = 0; j < np->n_intrs; j++) { i = np->intrs[j].line; if (i >= off && i < max) - senses[i-off] = np->intrs[j].sense ? - IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE : - IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE; + senses[i-off] = np->intrs[j].sense; } } } diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 07c2b3fc4c66..c7c3f912a3c2 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -432,6 +432,8 @@ extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; extern atomic_t ppc_n_lost_interrupts; +#define virt_irq_create_mapping(x) (x) + #endif /* From 303d72a0006c65bb8d16199c75a26338ce723811 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 17:22:33 +1000 Subject: [PATCH 0731/1939] powerpc: Don't limit pmac_get_rtc_time to return only positive values If the machine's clock is set to a bogus value, this check resulted in userland waiting effectively forever for the RTC value to change, so remove the check. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/time.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index 82982bf6453c..5947b21a8588 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -113,8 +113,6 @@ static unsigned long cuda_get_time(void) req.reply_len); now = (req.reply[3] << 24) + (req.reply[4] << 16) + (req.reply[5] << 8) + req.reply[6]; - if (now < RTC_OFFSET) - return 0; return now - RTC_OFFSET; } @@ -158,8 +156,6 @@ static unsigned long pmu_get_time(void) req.reply_len); now = (req.reply[0] << 24) + (req.reply[1] << 16) + (req.reply[2] << 8) + req.reply[3]; - if (now < RTC_OFFSET) - return 0; return now - RTC_OFFSET; } From bbd0abda9cc689a54df509aae00000bbb2a1a7d1 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 21:45:56 +1000 Subject: [PATCH 0732/1939] powerpc: Merge 32-bit CHRP support. SMP still needs more work but UP gets as far as starting userspace at least. This uses the 64-bit-style code for spinning up the cpus. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 2 +- arch/powerpc/kernel/head_32.S | 9 +- arch/powerpc/kernel/prom_init.c | 54 +-- arch/powerpc/kernel/setup_32.c | 4 + arch/powerpc/platforms/Makefile | 1 + arch/powerpc/platforms/chrp/Makefile | 3 + arch/powerpc/platforms/chrp/pci.c | 310 +++++++++++++ arch/powerpc/platforms/chrp/pegasos_eth.c | 101 +++++ arch/powerpc/platforms/chrp/setup.c | 523 ++++++++++++++++++++++ arch/powerpc/platforms/chrp/smp.c | 94 ++++ arch/powerpc/platforms/chrp/time.c | 188 ++++++++ arch/powerpc/platforms/powermac/pic.c | 4 - 12 files changed, 1256 insertions(+), 37 deletions(-) create mode 100644 arch/powerpc/platforms/chrp/Makefile create mode 100644 arch/powerpc/platforms/chrp/pci.c create mode 100644 arch/powerpc/platforms/chrp/pegasos_eth.c create mode 100644 arch/powerpc/platforms/chrp/setup.c create mode 100644 arch/powerpc/platforms/chrp/smp.c create mode 100644 arch/powerpc/platforms/chrp/time.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 964ded4a757f..9589d621edc5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -339,7 +339,7 @@ config U3_DART default n config MPIC - depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE + depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP bool default y diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index cd51fe585fcd..f8673f7b2b2d 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -207,7 +207,7 @@ turn_on_mmu: .globl __secondary_hold __secondary_hold: /* tell the master we're here */ - stw r3,4(0) + stw r3,__secondary_hold_acknowledge@l(0) #ifdef CONFIG_SMP 100: lwz r4,0(0) /* wait until we're told to start */ @@ -220,6 +220,13 @@ __secondary_hold: b . #endif /* CONFIG_SMP */ + .globl __secondary_hold_spinloop +__secondary_hold_spinloop: + .long 0 + .globl __secondary_hold_acknowledge +__secondary_hold_acknowledge: + .long -1 + /* * Exception entry code. This code runs with address translation * turned off, i.e. using physical addresses. diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 18d266d8935d..debe9734636e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1155,9 +1155,18 @@ static void __init prom_initialize_tce_table(void) * * -- Cort */ +extern void __secondary_hold(void); +extern unsigned long __secondary_hold_spinloop; +extern unsigned long __secondary_hold_acknowledge; + +/* + * We want to reference the copy of __secondary_hold_* in the + * 0 - 0x100 address range + */ +#define LOW_ADDR(x) (((unsigned long) &(x)) & 0xff) + static void __init prom_hold_cpus(void) { -#ifdef CONFIG_PPC64 unsigned long i; unsigned int reg; phandle node; @@ -1166,20 +1175,18 @@ static void __init prom_hold_cpus(void) unsigned int interrupt_server[MAX_CPU_THREADS]; unsigned int cpu_threads, hw_cpu_num; int propsize; - extern void __secondary_hold(void); - extern unsigned long __secondary_hold_spinloop; - extern unsigned long __secondary_hold_acknowledge; + struct prom_t *_prom = &RELOC(prom); unsigned long *spinloop - = (void *) __pa(&__secondary_hold_spinloop); + = (void *) LOW_ADDR(__secondary_hold_spinloop); unsigned long *acknowledge - = (void *) __pa(&__secondary_hold_acknowledge); + = (void *) LOW_ADDR(__secondary_hold_acknowledge); #ifdef CONFIG_PPC64 + /* __secondary_hold is actually a descriptor, not the text address */ unsigned long secondary_hold = __pa(*PTRRELOC((unsigned long *)__secondary_hold)); #else - unsigned long secondary_hold = __pa(&__secondary_hold); + unsigned long secondary_hold = LOW_ADDR(__secondary_hold); #endif - struct prom_t *_prom = &RELOC(prom); prom_debug("prom_hold_cpus: start...\n"); prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); @@ -1197,9 +1204,8 @@ static void __init prom_hold_cpus(void) *spinloop = 0; #ifdef CONFIG_HMT - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; - } #endif /* look for cpus */ for (node = 0; prom_next_node(&node); ) { @@ -1250,34 +1256,22 @@ static void __init prom_hold_cpus(void) call_prom("start-cpu", 3, 0, node, secondary_hold, reg); - for ( i = 0 ; (i < 100000000) && - (*acknowledge == ((unsigned long)-1)); i++ ) + for (i = 0; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) mb(); - if (*acknowledge == reg) { + if (*acknowledge == reg) prom_printf("done\n"); - /* We have to get every CPU out of OF, - * even if we never start it. */ - if (cpuid >= NR_CPUS) - goto next; - } else { + else prom_printf("failed: %x\n", *acknowledge); - } } #ifdef CONFIG_SMP else prom_printf("%x : boot cpu %x\n", cpuid, reg); -#endif -next: -#ifdef CONFIG_SMP - /* Init paca for secondary threads. They start later. */ - for (i=1; i < cpu_threads; i++) { - cpuid++; - if (cpuid >= NR_CPUS) - continue; - } #endif /* CONFIG_SMP */ - cpuid++; + + /* Reserve cpu #s for secondary threads. They start later. */ + cpuid += cpu_threads; } #ifdef CONFIG_HMT /* Only enable HMT on processors that provide support. */ @@ -1311,7 +1305,6 @@ static void __init prom_hold_cpus(void) ") exceeded: ignoring extras\n"); prom_debug("prom_hold_cpus: end...\n"); -#endif } @@ -1940,7 +1933,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long r6, unsigned long r7) { struct prom_t *_prom; - extern char _stext[]; unsigned long hdr; u32 getprop_rval; unsigned long offset = reloc_offset(); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 295d5c77f020..0cac112ca89d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -56,6 +56,10 @@ extern void power4_idle(void); boot_infos_t *boot_infos; struct ide_machdep_calls ppc_ide_md; +/* XXX should go elsewhere */ +int __irq_offset_value; +EXPORT_SYMBOL(__irq_offset_value); + /* Used with the BI_MEMSIZE bootinfo parameter to store the memory size value reported by the boot loader. */ unsigned long boot_mem_size; diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 509622da5408..01723d491b5d 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -5,6 +5,7 @@ ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_PPC_PMAC) += powermac/ endif endif +obj-$(CONFIG_PPC_CHRP) += chrp/ obj-$(CONFIG_4xx) += 4xx/ obj-$(CONFIG_85xx) += 85xx/ obj-$(CONFIG_PPC_PSERIES) += pseries/ diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile new file mode 100644 index 000000000000..1fde4e68414f --- /dev/null +++ b/arch/powerpc/platforms/chrp/Makefile @@ -0,0 +1,3 @@ +obj-y += setup.o time.o pegasos_eth.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c new file mode 100644 index 000000000000..82c429d487f3 --- /dev/null +++ b/arch/powerpc/platforms/chrp/pci.c @@ -0,0 +1,310 @@ +/* + * CHRP pci routines. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* LongTrail */ +void __iomem *gg2_pci_config_base; + +/* + * The VLSI Golden Gate II has only 512K of PCI configuration space, so we + * limit the bus number to 3 bits + */ + +int gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, + int len, u32 *val) +{ + volatile void __iomem *cfg_data; + struct pci_controller *hose = bus->sysdata; + + if (bus->number > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that off is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); + switch (len) { + case 1: + *val = in_8(cfg_data); + break; + case 2: + *val = in_le16(cfg_data); + break; + default: + *val = in_le32(cfg_data); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, + int len, u32 val) +{ + volatile void __iomem *cfg_data; + struct pci_controller *hose = bus->sysdata; + + if (bus->number > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that off is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); + switch (len) { + case 1: + out_8(cfg_data, val); + break; + case 2: + out_le16(cfg_data, val); + break; + default: + out_le32(cfg_data, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gg2_pci_ops = +{ + gg2_read_config, + gg2_write_config +}; + +/* + * Access functions for PCI config space using RTAS calls. + */ +int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); + int ret = -1; + int rval; + + rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); + *val = ret; + return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; +} + +int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); + int rval; + + rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, + addr, len, val); + return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops rtas_pci_ops = +{ + rtas_read_config, + rtas_write_config +}; + +volatile struct Hydra __iomem *Hydra = NULL; + +int __init +hydra_init(void) +{ + struct device_node *np; + + np = find_devices("mac-io"); + if (np == NULL || np->n_addrs == 0) + return 0; + Hydra = ioremap(np->addrs[0].address, np->addrs[0].size); + printk("Hydra Mac I/O at %lx\n", np->addrs[0].address); + printk("Hydra Feature_Control was %x", + in_le32(&Hydra->Feature_Control)); + out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN | + HYDRA_FC_SCSI_CELL_EN | + HYDRA_FC_SCCA_ENABLE | + HYDRA_FC_SCCB_ENABLE | + HYDRA_FC_ARB_BYPASS | + HYDRA_FC_MPIC_ENABLE | + HYDRA_FC_SLOW_SCC_PCLK | + HYDRA_FC_MPIC_IS_MASTER)); + printk(", now %x\n", in_le32(&Hydra->Feature_Control)); + return 1; +} + +void __init +chrp_pcibios_fixup(void) +{ + struct pci_dev *dev = NULL; + struct device_node *np; + + /* PCI interrupts are controlled by the OpenPIC */ + for_each_pci_dev(dev) { + np = pci_device_to_OF_node(dev); + if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + dev->irq = np->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +#define PRG_CL_RESET_VALID 0x00010000 + +static void __init +setup_python(struct pci_controller *hose, struct device_node *dev) +{ + u32 __iomem *reg; + u32 val; + unsigned long addr = dev->addrs[0].address; + + setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010); + + /* Clear the magic go-slow bit */ + reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40); + val = in_be32(®[12]); + if (val & PRG_CL_RESET_VALID) { + out_be32(®[12], val & ~PRG_CL_RESET_VALID); + in_be32(®[12]); + } + iounmap(reg); +} + +/* Marvell Discovery II based Pegasos 2 */ +static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev) +{ + struct device_node *root = find_path_device("/"); + struct device_node *rtas; + + rtas = of_find_node_by_name (root, "rtas"); + if (rtas) { + hose->ops = &rtas_pci_ops; + } else { + printk ("RTAS supporting Pegasos OF not found, please upgrade" + " your firmware\n"); + } + pci_assign_all_buses = 1; +} + +void __init +chrp_find_bridges(void) +{ + struct device_node *dev; + int *bus_range; + int len, index = -1; + struct pci_controller *hose; + unsigned int *dma; + char *model, *machine; + int is_longtrail = 0, is_mot = 0, is_pegasos = 0; + struct device_node *root = find_path_device("/"); + + /* + * The PCI host bridge nodes on some machines don't have + * properties to adequately identify them, so we have to + * look at what sort of machine this is as well. + */ + machine = get_property(root, "model", NULL); + if (machine != NULL) { + is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; + is_mot = strncmp(machine, "MOT", 3) == 0; + if (strncmp(machine, "Pegasos2", 8) == 0) + is_pegasos = 2; + else if (strncmp(machine, "Pegasos", 7) == 0) + is_pegasos = 1; + } + for (dev = root->child; dev != NULL; dev = dev->sibling) { + if (dev->type == NULL || strcmp(dev->type, "pci") != 0) + continue; + ++index; + /* The GG2 bridge on the LongTrail doesn't have an address */ + if (dev->n_addrs < 1 && !is_longtrail) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + continue; + } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + dev->full_name); + continue; + } + if (bus_range[1] == bus_range[0]) + printk(KERN_INFO "PCI bus %d", bus_range[0]); + else + printk(KERN_INFO "PCI buses %d..%d", + bus_range[0], bus_range[1]); + printk(" controlled by %s", dev->type); + if (dev->n_addrs > 0) + printk(" at %lx", dev->addrs[0].address); + printk("\n"); + + hose = pcibios_alloc_controller(); + if (!hose) { + printk("Can't allocate PCI controller structure for %s\n", + dev->full_name); + continue; + } + hose->arch_data = dev; + hose->first_busno = bus_range[0]; + hose->last_busno = bus_range[1]; + + model = get_property(dev, "model", NULL); + if (model == NULL) + model = ""; + if (device_is_compatible(dev, "IBM,python")) { + setup_python(hose, dev); + } else if (is_mot + || strncmp(model, "Motorola, Grackle", 17) == 0) { + setup_grackle(hose); + } else if (is_longtrail) { + void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000); + hose->ops = &gg2_pci_ops; + hose->cfg_data = p; + gg2_pci_config_base = p; + } else if (is_pegasos == 1) { + setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc); + } else if (is_pegasos == 2) { + setup_peg2(hose, dev); + } else { + printk("No methods for %s (model %s), using RTAS\n", + dev->full_name, model); + hose->ops = &rtas_pci_ops; + } + + pci_process_bridge_OF_ranges(hose, dev, index == 0); + + /* check the first bridge for a property that we can + use to set pci_dram_offset */ + dma = (unsigned int *) + get_property(dev, "ibm,dma-ranges", &len); + if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { + pci_dram_offset = dma[2] - dma[3]; + printk("pci_dram_offset = %lx\n", pci_dram_offset); + } + } + + /* Do not fixup interrupts from OF tree on pegasos */ + if (is_pegasos == 0) + ppc_md.pcibios_fixup = chrp_pcibios_fixup; +} diff --git a/arch/powerpc/platforms/chrp/pegasos_eth.c b/arch/powerpc/platforms/chrp/pegasos_eth.c new file mode 100644 index 000000000000..cad5bfa153b2 --- /dev/null +++ b/arch/powerpc/platforms/chrp/pegasos_eth.c @@ -0,0 +1,101 @@ +/* + * arch/ppc/platforms/chrp_pegasos_eth.c + * + * Copyright (C) 2005 Sven Luther + * Thanks to : + * Dale Farnsworth + * Mark A. Greer + * Nicolas DET + * Benjamin Herrenschmidt + * And anyone else who helped me on this. + */ + +#include +#include +#include +#include +#include +#include + +/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */ +static struct resource mv643xx_eth_shared_resources[] = { + [0] = { + .name = "ethernet shared base", + .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, + .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + + MV643XX_ETH_SHARED_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mv643xx_eth_shared_device = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), + .resource = mv643xx_eth_shared_resources, +}; + +static struct resource mv643xx_eth0_resources[] = { + [0] = { + .name = "eth0 irq", + .start = 9, + .end = 9, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv643xx_eth_platform_data eth0_pd; + +static struct platform_device eth0_device = { + .name = MV643XX_ETH_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth0_resources), + .resource = mv643xx_eth0_resources, + .dev = { + .platform_data = ð0_pd, + }, +}; + +static struct resource mv643xx_eth1_resources[] = { + [0] = { + .name = "eth1 irq", + .start = 9, + .end = 9, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv643xx_eth_platform_data eth1_pd; + +static struct platform_device eth1_device = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(mv643xx_eth1_resources), + .resource = mv643xx_eth1_resources, + .dev = { + .platform_data = ð1_pd, + }, +}; + +static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { + &mv643xx_eth_shared_device, + ð0_device, + ð1_device, +}; + + +int +mv643xx_eth_add_pds(void) +{ + int ret = 0; + static struct pci_device_id pci_marvell_mv64360[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) }, + { } + }; + + if (pci_dev_present(pci_marvell_mv64360)) { + ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs)); + } + return ret; +} +device_initcall(mv643xx_eth_add_pds); diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c new file mode 100644 index 000000000000..5145990e6a01 --- /dev/null +++ b/arch/powerpc/platforms/chrp/setup.c @@ -0,0 +1,523 @@ +/* + * arch/ppc/platforms/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + */ + +/* + * bootup setup stuff.. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +void chrp_get_rtc_time(struct rtc_time *); +int chrp_set_rtc_time(struct rtc_time *); +void chrp_calibrate_decr(void); +long chrp_time_init(void); + +void chrp_find_bridges(void); +void chrp_event_scan(void); +void rtas_indicator_progress(char *, unsigned short); +void btext_progress(char *, unsigned short); + +int _chrp_type; +EXPORT_SYMBOL(_chrp_type); + +struct mpic *chrp_mpic; + +/* + * XXX this should be in xmon.h, but putting it there means xmon.h + * has to include (to get irqreturn_t), which + * causes all sorts of problems. -- paulus + */ +extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); + +extern unsigned long loops_per_jiffy; + +#ifdef CONFIG_SMP +extern struct smp_ops_t chrp_smp_ops; +#endif + +static const char *gg2_memtypes[4] = { + "FPM", "SDRAM", "EDO", "BEDO" +}; +static const char *gg2_cachesizes[4] = { + "256 KB", "512 KB", "1 MB", "Reserved" +}; +static const char *gg2_cachetypes[4] = { + "Asynchronous", "Reserved", "Flow-Through Synchronous", + "Pipelined Synchronous" +}; +static const char *gg2_cachemodes[4] = { + "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" +}; + +void chrp_show_cpuinfo(struct seq_file *m) +{ + int i, sdramen; + unsigned int t; + struct device_node *root; + const char *model = ""; + + root = find_path_device("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); + + /* longtrail (goldengate) stuff */ + if (!strncmp(model, "IBM,LongTrail", 13)) { + /* VLSI VAS96011/12 `Golden Gate 2' */ + /* Memory banks */ + sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) + >>31) & 1; + for (i = 0; i < (sdramen ? 4 : 6); i++) { + t = in_le32(gg2_pci_config_base+ + GG2_PCI_DRAM_BANK0+ + i*4); + if (!(t & 1)) + continue; + switch ((t>>8) & 0x1f) { + case 0x1f: + model = "4 MB"; + break; + case 0x1e: + model = "8 MB"; + break; + case 0x1c: + model = "16 MB"; + break; + case 0x18: + model = "32 MB"; + break; + case 0x10: + model = "64 MB"; + break; + case 0x00: + model = "128 MB"; + break; + default: + model = "Reserved"; + break; + } + seq_printf(m, "memory bank %d\t: %s %s\n", i, model, + gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); + } + /* L2 cache */ + t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL); + seq_printf(m, "board l2\t: %s %s (%s)\n", + gg2_cachesizes[(t>>7) & 3], + gg2_cachetypes[(t>>2) & 3], + gg2_cachemodes[t & 3]); + } +} + +/* + * Fixes for the National Semiconductor PC78308VUL SuperI/O + * + * Some versions of Open Firmware incorrectly initialize the IRQ settings + * for keyboard and mouse + */ +static inline void __init sio_write(u8 val, u8 index) +{ + outb(index, 0x15c); + outb(val, 0x15d); +} + +static inline u8 __init sio_read(u8 index) +{ + outb(index, 0x15c); + return inb(0x15d); +} + +static void __init sio_fixup_irq(const char *name, u8 device, u8 level, + u8 type) +{ + u8 level0, type0, active; + + /* select logical device */ + sio_write(device, 0x07); + active = sio_read(0x30); + level0 = sio_read(0x70); + type0 = sio_read(0x71); + if (level0 != level || type0 != type || !active) { + printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: " + "remapping to level %d, type %d, active\n", + name, level0, type0, !active ? "in" : "", level, type); + sio_write(0x01, 0x30); + sio_write(level, 0x70); + sio_write(type, 0x71); + } +} + +static void __init sio_init(void) +{ + struct device_node *root; + + if ((root = find_path_device("/")) && + !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { + /* logical device 0 (KBC/Keyboard) */ + sio_fixup_irq("keyboard", 0, 1, 2); + /* select logical device 1 (KBC/Mouse) */ + sio_fixup_irq("mouse", 1, 12, 2); + } +} + + +static void __init pegasos_set_l2cr(void) +{ + struct device_node *np; + + /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */ + if (_chrp_type != _CHRP_Pegasos) + return; + + /* Enable L2 cache if needed */ + np = find_type_devices("cpu"); + if (np != NULL) { + unsigned int *l2cr = (unsigned int *) + get_property (np, "l2cr", NULL); + if (l2cr == NULL) { + printk ("Pegasos l2cr : no cpu l2cr property found\n"); + return; + } + if (!((*l2cr) & 0x80000000)) { + printk ("Pegasos l2cr : L2 cache was not active, " + "activating\n"); + _set_L2CR(0); + _set_L2CR((*l2cr) | 0x80000000); + } + } +} + +void __init chrp_setup_arch(void) +{ + struct device_node *root = find_path_device ("/"); + char *machine = NULL; + struct device_node *device; + unsigned int *p = NULL; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + if (root) + machine = get_property(root, "model", NULL); + if (machine && strncmp(machine, "Pegasos", 7) == 0) { + _chrp_type = _CHRP_Pegasos; + } else if (machine && strncmp(machine, "IBM", 3) == 0) { + _chrp_type = _CHRP_IBM; + } else if (machine && strncmp(machine, "MOT", 3) == 0) { + _chrp_type = _CHRP_Motorola; + } else { + /* Let's assume it is an IBM chrp if all else fails */ + _chrp_type = _CHRP_IBM; + } + printk("chrp type = %x\n", _chrp_type); + + rtas_initialize(); + if (rtas_token("display-character") >= 0) + ppc_md.progress = rtas_progress; + +#ifdef CONFIG_BOOTX_TEXT + if (ppc_md.progress == NULL && boot_text_mapped) + ppc_md.progress = btext_progress; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ + + /* On pegasos, enable the L2 cache if not already done by OF */ + pegasos_set_l2cr(); + + /* Lookup PCI host bridges */ + chrp_find_bridges(); + + /* + * Temporary fixes for PCI devices. + * -- Geert + */ + hydra_init(); /* Mac I/O */ + + /* + * Fix the Super I/O configuration + */ + sio_init(); + + /* Get the event scan rate for the rtas so we know how + * often it expects a heartbeat. -- Cort + */ + device = find_devices("rtas"); + if (device) + p = (unsigned int *) get_property + (device, "rtas-event-scan-rate", NULL); + if (p && *p) { + ppc_md.heartbeat = chrp_event_scan; + ppc_md.heartbeat_reset = HZ / (*p * 30) - 1; + ppc_md.heartbeat_count = 1; + printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", + *p, ppc_md.heartbeat_reset); + } + + pci_create_OF_bus_map(); + + /* + * Print the banner, then scroll down so boot progress + * can be printed. -- Cort + */ + if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); +} + +void +chrp_event_scan(void) +{ + unsigned char log[1024]; + int ret = 0; + + /* XXX: we should loop until the hardware says no more error logs -- Cort */ + rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, + __pa(log), 1024); + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +/* + * Finds the open-pic node and sets up the mpic driver. + */ +static void __init chrp_find_openpic(void) +{ + struct device_node *np, *root; + int len, i, j, irq_count; + int isu_size, idu_size; + unsigned int *iranges, *opprop = NULL; + int oplen = 0; + unsigned long opaddr; + int na = 1; + unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; + + np = find_type_devices("open-pic"); + if (np == NULL) + return; + root = find_path_device("/"); + if (root) { + opprop = (unsigned int *) get_property + (root, "platform-open-pic", &oplen); + na = prom_n_addr_cells(root); + } + if (opprop && oplen >= na * sizeof(unsigned int)) { + opaddr = opprop[na-1]; /* assume 32-bit */ + oplen /= na * sizeof(unsigned int); + } else { + if (np->n_addrs == 0) + return; + opaddr = np->addrs[0].address; + oplen = 0; + } + + printk(KERN_INFO "OpenPIC at %lx\n", opaddr); + + irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ + prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4); + + iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); + if (iranges == NULL) + len = 0; /* non-distributed mpic */ + else + len /= 2 * sizeof(unsigned int); + + /* + * The first pair of cells in interrupt-ranges refers to the + * IDU; subsequent pairs refer to the ISUs. + */ + if (oplen < len) { + printk(KERN_ERR "Insufficient addresses for distributed" + " OpenPIC (%d < %d)\n", np->n_addrs, len); + len = oplen; + } + + isu_size = 0; + idu_size = 0; + if (len > 0 && iranges[1] != 0) { + printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n", + iranges[0], iranges[0] + iranges[1] - 1); + idu_size = iranges[1]; + } + if (len > 1) + isu_size = iranges[3]; + + chrp_mpic = mpic_alloc(opaddr, MPIC_PRIMARY, + isu_size, NUM_ISA_INTERRUPTS, irq_count, + NR_IRQS - 4, init_senses, irq_count, + " MPIC "); + if (chrp_mpic == NULL) { + printk(KERN_ERR "Failed to allocate MPIC structure\n"); + return; + } + + j = na - 1; + for (i = 1; i < len; ++i) { + iranges += 2; + j += na; + printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x\n", + iranges[0], iranges[0] + iranges[1] - 1, + opprop[j]); + mpic_assign_isu(chrp_mpic, i - 1, opprop[j]); + } + + mpic_init(chrp_mpic); + mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); +} + +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) +static struct irqaction xmon_irqaction = { + .handler = xmon_irq, + .mask = CPU_MASK_NONE, + .name = "XMON break", +}; +#endif + +void __init chrp_init_IRQ(void) +{ + struct device_node *np; + unsigned long chrp_int_ack = 0; +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) + struct device_node *kbd; +#endif + + for (np = find_devices("pci"); np != NULL; np = np->next) { + unsigned int *addrp = (unsigned int *) + get_property(np, "8259-interrupt-acknowledge", NULL); + + if (addrp == NULL) + continue; + chrp_int_ack = addrp[prom_n_addr_cells(np)-1]; + break; + } + if (np == NULL) + printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n"); + + chrp_find_openpic(); + + i8259_init(chrp_int_ack, 0); + + if (_chrp_type == _CHRP_Pegasos) + ppc_md.get_irq = i8259_irq; + else + ppc_md.get_irq = mpic_get_irq; + +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) + if (kbd->parent && kbd->parent->type + && strcmp(kbd->parent->type, "adb") == 0) + break; + if (kbd) + setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction); +#endif +} + +void __init +chrp_init2(void) +{ + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + + if (ppc_md.progress) + ppc_md.progress(" Have fun! ", 0x7777); +} + +void __init chrp_init(void) +{ + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + isa_io_base = CHRP_ISA_IO_BASE; /* default value */ + ppc_do_canonicalize_irqs = 1; + + /* Assume we have an 8259... */ + __irq_offset_value = NUM_ISA_INTERRUPTS; + + ppc_md.setup_arch = chrp_setup_arch; + ppc_md.show_cpuinfo = chrp_show_cpuinfo; + + ppc_md.init_IRQ = chrp_init_IRQ; + ppc_md.init = chrp_init2; + + ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; + + ppc_md.restart = rtas_restart; + ppc_md.power_off = rtas_power_off; + ppc_md.halt = rtas_halt; + + ppc_md.time_init = chrp_time_init; + ppc_md.set_rtc_time = chrp_set_rtc_time; + ppc_md.get_rtc_time = chrp_get_rtc_time; + ppc_md.calibrate_decr = chrp_calibrate_decr; + +#ifdef CONFIG_SMP + smp_ops = &chrp_smp_ops; +#endif /* CONFIG_SMP */ +} + +#ifdef CONFIG_BOOTX_TEXT +void +btext_progress(char *s, unsigned short hex) +{ + btext_drawstring(s); + btext_drawstring("\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c new file mode 100644 index 000000000000..bf68282670dd --- /dev/null +++ b/arch/powerpc/platforms/chrp/smp.c @@ -0,0 +1,94 @@ +/* + * Smp support for CHRP machines. + * + * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great + * deal of code from the sparc and intel versions. + * + * Copyright (C) 1999 Cort Dougan + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long smp_chrp_cpu_nr; + +static int __init smp_chrp_probe(void) +{ + if (smp_chrp_cpu_nr > 1) + openpic_request_IPIs(); + + return smp_chrp_cpu_nr; +} + +static void __devinit smp_chrp_kick_cpu(int nr) +{ + *(unsigned long *)KERNELBASE = nr; + asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); +} + +static void __devinit smp_chrp_setup_cpu(int cpu_nr) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); +} + +static DEFINE_SPINLOCK(timebase_lock); +static unsigned int timebase_upper = 0, timebase_lower = 0; + +void __devinit smp_chrp_give_timebase(void) +{ + spin_lock(&timebase_lock); + rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL); + timebase_upper = get_tbu(); + timebase_lower = get_tbl(); + spin_unlock(&timebase_lock); + + while (timebase_upper || timebase_lower) + barrier(); + rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL); +} + +void __devinit smp_chrp_take_timebase(void) +{ + while (!(timebase_upper || timebase_lower)) + barrier(); + spin_lock(&timebase_lock); + set_tb(timebase_upper, timebase_lower); + timebase_upper = 0; + timebase_lower = 0; + spin_unlock(&timebase_lock); + printk("CPU %i taken timebase\n", smp_processor_id()); +} + +/* CHRP with openpic */ +struct smp_ops_t chrp_smp_ops = { + .message_pass = smp_openpic_message_pass, + .probe = smp_chrp_probe, + .kick_cpu = smp_chrp_kick_cpu, + .setup_cpu = smp_chrp_setup_cpu, + .give_timebase = smp_chrp_give_timebase, + .take_timebase = smp_chrp_take_timebase, +}; diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c new file mode 100644 index 000000000000..9e53535ddb82 --- /dev/null +++ b/arch/powerpc/platforms/chrp/time.c @@ -0,0 +1,188 @@ +/* + * arch/ppc/platforms/chrp_time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * Adapted for PowerPC (PReP) by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu). + * Copied and modified from arch/i386/kernel/time.c + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern spinlock_t rtc_lock; + +static int nvram_as1 = NVRAM_AS1; +static int nvram_as0 = NVRAM_AS0; +static int nvram_data = NVRAM_DATA; + +long __init chrp_time_init(void) +{ + struct device_node *rtcs; + int base; + + rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); + if (rtcs == NULL) + rtcs = find_compatible_devices("rtc", "ds1385-rtc"); + if (rtcs == NULL || rtcs->addrs == NULL) + return 0; + base = rtcs->addrs[0].address; + nvram_as1 = 0; + nvram_as0 = base; + nvram_data = base + 1; + + return 0; +} + +int chrp_cmos_clock_read(int addr) +{ + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + return (inb(nvram_data)); +} + +void chrp_cmos_clock_write(unsigned long val, int addr) +{ + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + outb(val, nvram_data); + return; +} + +/* + * Set the hardware clock. -- Cort + */ +int chrp_set_rtc_time(struct rtc_time *tmarg) +{ + unsigned char save_control, save_freq_select; + struct rtc_time tm = *tmarg; + + spin_lock(&rtc_lock); + + save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ + + chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ + + chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + tm.tm_year -= 1900; + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + } + chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS); + chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES); + chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS); + chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH); + chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); + chrp_cmos_clock_write(tm.tm_year,RTC_YEAR); + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + chrp_cmos_clock_write(save_control, RTC_CONTROL); + chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); + + spin_unlock(&rtc_lock); + return 0; +} + +void chrp_get_rtc_time(struct rtc_time *tm) +{ + unsigned int year, mon, day, hour, min, sec; + int uip, i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); + sec = chrp_cmos_clock_read(RTC_SECONDS); + min = chrp_cmos_clock_read(RTC_MINUTES); + hour = chrp_cmos_clock_read(RTC_HOURS); + day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); + mon = chrp_cmos_clock_read(RTC_MONTH); + year = chrp_cmos_clock_read(RTC_YEAR); + uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + + if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + tm->tm_sec = sec; + tm->tm_min = min; + tm->tm_hour = hour; + tm->tm_mday = day; + tm->tm_mon = mon; + tm->tm_year = year; +} + + +void __init chrp_calibrate_decr(void) +{ + struct device_node *cpu; + unsigned int freq, *fp; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + freq = 16666000; /* hardcoded default */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (unsigned int *) + get_property(cpu, "timebase-frequency", NULL); + if (fp != 0) + freq = *fp; + } + ppc_tb_freq = freq; +} diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 0eca17df239e..0037a8c8c81f 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -71,10 +71,6 @@ static u32 level_mask[4]; static DEFINE_SPINLOCK(pmac_pic_lock); -/* XXX here for now, should move to arch/powerpc/kernel/irq.c */ -int ppc_do_canonicalize_irqs; -EXPORT_SYMBOL(ppc_do_canonicalize_irqs); - #define GATWICK_IRQ_POOL_SIZE 10 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; From c49888203d7a316cb947bb8a1cf2ae191f28bcd3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 21:52:53 +1000 Subject: [PATCH 0733/1939] powerpc: Fixes to get the Longtrail CHRP a bit further Talk about buggy firmware... the OF on the Longtrail returns 0 from the claim client service rather than -1 when the claim fails. It also has no device_type on the /memory node and blows up if the output buffer for package-to-path is too big. This also fixes a bug with calling alloc_up with align == 0, where we did _ALIGN_UP(alloc_bottom, 0) which will end up as 0. Lastly, we now check the return value (in r3) from calling the prom, and return -1 from call_prom if we get a negative value back. That is supposed to indicate that the requested client service doesn't exist. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 42 ++++++++++++++++++--------- arch/ppc/boot/of1275/claim.c | 1 + arch/ppc/boot/openfirmware/chrpmain.c | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index debe9734636e..2ad9947bd675 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -145,11 +145,11 @@ typedef u32 cell_t; extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); #ifdef CONFIG_PPC64 -extern void enter_prom(struct prom_args *args, unsigned long entry); +extern int enter_prom(struct prom_args *args, unsigned long entry); #else -static inline void enter_prom(struct prom_args *args, unsigned long entry) +static inline int enter_prom(struct prom_args *args, unsigned long entry) { - ((void (*)(struct prom_args *))entry)(args); + return ((int (*)(struct prom_args *))entry)(args); } #endif @@ -241,7 +241,8 @@ static int __init call_prom(const char *service, int nargs, int nret, ...) for (i = 0; i < nret; i++) args.args[nargs+i] = 0; - enter_prom(&args, RELOC(prom_entry)); + if (enter_prom(&args, RELOC(prom_entry)) < 0) + return PROM_ERROR; return (nret > 0) ? args.args[nargs] : 0; } @@ -265,7 +266,8 @@ static int __init call_prom_ret(const char *service, int nargs, int nret, for (i = 0; i < nret; i++) rets[nargs+i] = 0; - enter_prom(&args, RELOC(prom_entry)); + if (enter_prom(&args, RELOC(prom_entry)) < 0) + return PROM_ERROR; if (rets != NULL) for (i = 1; i < nret; ++i) @@ -670,9 +672,11 @@ static void __init prom_send_capabilities(void) */ static unsigned long __init alloc_up(unsigned long size, unsigned long align) { - unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); + unsigned long base = RELOC(alloc_bottom); unsigned long addr = 0; + if (align) + base = _ALIGN_UP(base, align); prom_debug("alloc_up(%x, %x)\n", size, align); if (RELOC(ram_top) == 0) prom_panic("alloc_up() called with mem not initialized\n"); @@ -686,7 +690,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) base = _ALIGN_UP(base + 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if (addr != PROM_ERROR) + if (addr != PROM_ERROR && addr != 0) break; addr = 0; if (align == 0) @@ -746,7 +750,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, base = _ALIGN_DOWN(base - 0x100000, align)) { prom_debug(" trying: 0x%x\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); - if (addr != PROM_ERROR) + if (addr != PROM_ERROR && addr != 0) break; addr = 0; } @@ -852,9 +856,16 @@ static void __init prom_init_mem(void) type[0] = 0; prom_getprop(node, "device_type", type, sizeof(type)); + if (type[0] == 0) { + /* + * CHRP Longtrail machines have no device_type + * on the memory node, so check the name instead... + */ + prom_getprop(node, "name", type, sizeof(type)); + } if (strcmp(type, RELOC("memory"))) continue; - + plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); if (plen > sizeof(regbuf)) { prom_printf("memory node too large for buffer !\n"); @@ -1632,18 +1643,21 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long soff; unsigned char *valp; static char pname[MAX_PROPERTY_NAME]; - int l; + int l, room; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); /* get the node's full name */ namep = (char *)*mem_start; - l = call_prom("package-to-path", 3, 1, node, - namep, *mem_end - *mem_start); + room = *mem_end - *mem_start; + if (room > 255) + room = 255; + l = call_prom("package-to-path", 3, 1, node, namep, room); if (l >= 0) { /* Didn't fit? Get more room. */ - if ((l+1) > (*mem_end - *mem_start)) { - namep = make_room(mem_start, mem_end, l+1, 1); + if (l >= room) { + if (l >= *mem_end - *mem_start) + namep = make_room(mem_start, mem_end, l+1, 1); call_prom("package-to-path", 3, 1, node, namep, l); } namep[l] = '\0'; diff --git a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c index e060292ae2a7..13169a5c4339 100644 --- a/arch/ppc/boot/of1275/claim.c +++ b/arch/ppc/boot/of1275/claim.c @@ -29,6 +29,7 @@ claim(unsigned int virt, unsigned int size, unsigned int align) args.virt = virt; args.size = size; args.align = align; + args.ret = (void *) 0; (*of_prom_entry)(&args); return args.ret; } diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c index effe4a0624b0..245dbd9fc120 100644 --- a/arch/ppc/boot/openfirmware/chrpmain.c +++ b/arch/ppc/boot/openfirmware/chrpmain.c @@ -78,7 +78,7 @@ boot(int a1, int a2, void *prom) begin_avail = avail_high = avail_ram; end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); - gunzip(dst, 0x400000, im, &len); + gunzip(dst, PROG_SIZE - PROG_START, im, &len); printf("done %u bytes\n\r", len); printf("%u bytes of heap consumed, max in use %u\n\r", avail_high - begin_avail, heap_max); From b41fc4f82f6a73b8b2e8f44bd7ef075797d2dacb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 21:53:19 +1000 Subject: [PATCH 0734/1939] power: Update the multiple inclusion protection symbol on machdep.h Signed-off-by: Paul Mackerras --- include/asm-powerpc/machdep.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index b3a93b476d97..706508b1b04b 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_MACHDEP_H -#define _PPC64_MACHDEP_H +#ifndef _ASM_POWERPC_MACHDEP_H +#define _ASM_POWERPC_MACHDEP_H #ifdef __KERNEL__ /* @@ -281,4 +281,4 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal) } #endif /* __KERNEL__ */ -#endif /* _PPC64_MACHDEP_H */ +#endif /* _ASM_POWERPC_MACHDEP_H */ From fa39dc437a41733adaba241fd9036760283a516a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 21:54:21 +1000 Subject: [PATCH 0735/1939] powerpc32: Limit memory to lowmem if !CONFIG_HIGHMEM. This trims off the extra unusable memory from the lmb structure, so we don't try to use it. Signed-off-by: Paul Mackerras --- arch/powerpc/mm/init_32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index aa6a5440cec1..8dd1f7d0e23c 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -154,10 +154,13 @@ void __init MMU_init(void) * in the fixed entries */ adjust_total_lowmem(); #endif /* CONFIG_FSL_BOOKE */ + if (total_lowmem > __max_low_memory) { total_lowmem = __max_low_memory; #ifndef CONFIG_HIGHMEM total_memory = total_lowmem; + lmb_enforce_memory_limit(total_lowmem); + lmb_analyze(); #endif /* CONFIG_HIGHMEM */ } From bd561c79dce9036c9efb17420b6cf8763c8c9de3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 21:55:33 +1000 Subject: [PATCH 0736/1939] powerpc: Fix incorrect timer register addresses in mpic.c We were computing the wrong address for the MPIC timer registers, so when we went to initialize them we would have been hitting some unrelated ioremap... oops. Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 3948e759d41a..105f05341a41 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -358,7 +358,7 @@ static void mpic_enable_irq(unsigned int irq) struct mpic *mpic = mpic_from_irq(irq); unsigned int src = irq - mpic->irq_offset; - DBG("%s: enable_irq: %d (src %d)\n", mpic->name, irq, src); + DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & ~MPIC_VECPRI_MASK); @@ -511,7 +511,7 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, /* Map the global registers */ mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); - mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2); + mpic->tmregs = mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE) >> 2); BUG_ON(mpic->gregs == NULL); /* Reset */ @@ -648,7 +648,6 @@ void __init mpic_init(struct mpic *mpic) continue; irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi; - #endif /* CONFIG_SMP */ } From b6a4ce526a87bd8a99a396ac993240d6d3239852 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 26 Oct 2005 22:54:17 +1000 Subject: [PATCH 0737/1939] powerpc: 32-bit powermac needs the mpc106 code Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9589d621edc5..c71ddc0c191a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -293,6 +293,7 @@ config PPC_PMAC bool " Apple PowerMac based machines" depends on PPC_MULTIPLATFORM select PPC_INDIRECT_PCI if PPC32 + select PPC_MPC106 if PPC32 default y config PPC_PMAC64 From 7edc24c4d1924e79d3853a8d7563bcce73f31e5d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 26 Oct 2005 15:04:21 +0100 Subject: [PATCH 0738/1939] [ARM] 3032/1: sparse: complains about generic_fls() prototype in asm-arm/bitops.h Patch from Ian Campbell Sparse complains about the definition of generic_fls in asm-arm/bitops.h: CHECK /home/icampbell/devel/kernel/2.6/arch/arm/mach-pxa/viper.c include2/asm/bitops.h:350:34: error: marked inline, but without a definition The definition is unnecessary since linux/bitops.h defines generic_fls before including asm/bitops.h and asm/bitops.h should not be included directly. There are still some places where asm/bitops.h is directly included, but I think that code should be fixed. I was a little wary of the patch for this reason but lubbock, mainstone and assabet all build OK and so do my in house boards... ARM is the only arch with the generic_fls prototype in this way. Signed-off-by: Ian Campbell Signed-off-by: Russell King --- include/asm-arm/bitops.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h index aad7aad026b3..e007dd990da5 100644 --- a/include/asm-arm/bitops.h +++ b/include/asm-arm/bitops.h @@ -347,7 +347,6 @@ static inline unsigned long __ffs(unsigned long word) * the clz instruction for much better code efficiency. */ -static __inline__ int generic_fls(int x); #define fls(x) \ ( __builtin_constant_p(x) ? generic_fls(x) : \ ({ int __r; asm("clz\t%0, %1" : "=r"(__r) : "r"(x) : "cc"); 32-__r; }) ) From 91190758d410a5d33c6051ba9ca95baa430256bb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Oct 2005 12:17:46 -0400 Subject: [PATCH 0739/1939] [libata] ata_timing fix --- drivers/scsi/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index dcd3b5553cc8..f53d7b8ac33f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1616,7 +1616,7 @@ static const struct ata_timing* ata_timing_find_mode(unsigned short speed) const struct ata_timing *t; for (t = ata_timing; t->mode != speed; t++) - if (t->mode != 0xFF) + if (t->mode == 0xFF) return NULL; return t; } From 8712e553562bbbed9b3a99370f08e9bc25908a76 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 26 Oct 2005 01:58:58 -0700 Subject: [PATCH 0740/1939] [PATCH] md: make sure mdthreads will always respond to kthread_stop There are still a couple of cases where md threads (the resync/recovery thread) is not interruptible since the change to use kthreads. All places there it tests "signal_pending", it should also test kthread_should_stop, as with this patch. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index e9476075aa13..2a8a5696bf8a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3568,7 +3568,8 @@ static void md_do_sync(mddev_t *mddev) mddev->curr_resync = 2; try_again: - if (signal_pending(current)) { + if (signal_pending(current) || + kthread_should_stop()) { flush_signals(current); set_bit(MD_RECOVERY_INTR, &mddev->recovery); goto skip; @@ -3590,8 +3591,9 @@ static void md_do_sync(mddev_t *mddev) */ continue; prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE); - if (!signal_pending(current) - && mddev2->curr_resync >= mddev->curr_resync) { + if (!signal_pending(current) && + !kthread_should_stop() && + mddev2->curr_resync >= mddev->curr_resync) { printk(KERN_INFO "md: delaying resync of %s" " until %s has finished resync (they" " share one or more physical units)\n", @@ -3697,7 +3699,7 @@ static void md_do_sync(mddev_t *mddev) } - if (signal_pending(current)) { + if (signal_pending(current) || kthread_should_stop()) { /* * got a signal, exit. */ From 1c6fe9465941df04a1ad8f009bd6d95b20072a58 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 26 Oct 2005 01:58:59 -0700 Subject: [PATCH 0741/1939] [PATCH] NUMA: broken per cpu pageset counters The NUMA counters in struct per_cpu_pageset (linux/mmzone.h) are never cleared today. This works ok for CPU 0 on NUMA machines because boot_pageset[] is already zero, but for other CPU:s this results in uninitialized counters. Signed-off-by: Magnus Damm Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index cc1fe2672a31..e1d3d77f4aee 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1750,6 +1750,8 @@ inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch) { struct per_cpu_pages *pcp; + memset(p, 0, sizeof(*p)); + pcp = &p->pcp[0]; /* hot */ pcp->count = 0; pcp->low = 2 * batch; From 958d24df82e021704437da0789c47fcf581e4b85 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 26 Oct 2005 01:59:00 -0700 Subject: [PATCH 0742/1939] [PATCH] ppc64: Fix wrong register mapping in mpic driver The mpic interrupt controller driver (used on G5 and early pSeries among others) has a bug where it doesn't get the right virtual address for the timer registers. It causes the driver to poke at the MMIO space of whatever has been mapped just next to it (ouch !) when initializing and causes boot failures on some IBM machines. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/mpic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c index cc262a05ddb4..5f5bc73754d9 100644 --- a/arch/ppc64/kernel/mpic.c +++ b/arch/ppc64/kernel/mpic.c @@ -506,8 +506,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, mpic->senses_count = senses_count; /* Map the global registers */ - mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); - mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2); + mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x2000); + mpic->tmregs = mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE) >> 2); BUG_ON(mpic->gregs == NULL); /* Reset */ From bb32051532fed727de0d513a9a578b54c0b7ea5a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 26 Oct 2005 01:59:01 -0700 Subject: [PATCH 0743/1939] [PATCH] export cpu_online_map With CONFIG_SMP=n: *** Warning: "cpu_online_map" [drivers/firmware/dcdbas.ko] undefined! due to set_cpus_allowed(). Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sched.c b/kernel/sched.c index 1f31a528fdba..1e5cafdf4e27 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3879,6 +3879,7 @@ EXPORT_SYMBOL(cpu_present_map); #ifndef CONFIG_SMP cpumask_t cpu_online_map = CPU_MASK_ALL; +EXPORT_SYMBOL_GPL(cpu_online_map); cpumask_t cpu_possible_map = CPU_MASK_ALL; #endif From 35848e048f55368f132e28e7f3278ce2d2347f6c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 26 Oct 2005 01:59:01 -0700 Subject: [PATCH 0744/1939] [PATCH] kill massive wireless-related log spam Although this message is having the intended effect of causing wireless driver maintainers to upgrade their code, I never should have merged this patch in its present form. Leading to tons of bug reports and unhappy users. Some wireless apps poll for statistics regularly, which leads to a printk() every single time they ask for stats. That's a little bit _too_ much of a reminder that the driver is using an old API. Change this to printing out the message once, per kernel boot. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/core/wireless.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/core/wireless.c b/net/core/wireless.c index d17f1583ea3e..271ddb35b0b2 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c @@ -455,10 +455,15 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) /* Old location, field to be removed in next WE */ if(dev->get_wireless_stats) { - printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", - dev->name); + static int printed_message; + + if (!printed_message++) + printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", + dev->name); + return dev->get_wireless_stats(dev); } + /* Not found */ return (struct iw_statistics *) NULL; } From 94c1d3184523efa7109472eb393cee6e954c5d75 Mon Sep 17 00:00:00 2001 From: Peter Wainwright Date: Wed, 26 Oct 2005 01:59:02 -0700 Subject: [PATCH 0745/1939] [PATCH] Fix HFS+ to free up the space when a file is deleted. fsck_hfs reveals lots of temporary files accumulating in the hidden directory "\000\000\000HFS+ Private Data". According to the HFS+ documentation these are files which are unlinked while in use. However, there may be a bug in the Linux hfsplus implementation which causes this to happen even when the files are not in use. It looks like the "opencnt" field is never initialized as (I think) it should be in hfsplus_read_inode. This means that a file can appear to be still in use when in fact it has been closed. This patch seems to fix it for me. Signed-off-by: Anton Altaparmakov Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hfsplus/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index fd0f0f050e1d..452fc1fdbd32 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -50,6 +50,7 @@ static void hfsplus_read_inode(struct inode *inode) init_MUTEX(&HFSPLUS_I(inode).extents_lock); HFSPLUS_I(inode).flags = 0; HFSPLUS_I(inode).rsrc_inode = NULL; + atomic_set(&HFSPLUS_I(inode).opencnt, 0); if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) { read_inode: From 4bcde03d41d2264edb4ea3c47cb27da1e2609e48 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 26 Oct 2005 01:59:03 -0700 Subject: [PATCH 0746/1939] [PATCH] svcsock timestamp fix Convert nanoseconds to microseconds correctly. Spotted by Steve Dickson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/svcsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 30ec3efc48a6..691dea4a58e7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -587,7 +587,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) struct timeval tv; tv.tv_sec = xtime.tv_sec; - tv.tv_usec = xtime.tv_nsec * 1000; + tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC; skb_set_timestamp(skb, &tv); /* Don't enable netstamp, sunrpc doesn't need that much accuracy */ From b0917bd912d3708c50e1df1b5e1648d0547108a3 Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Wed, 26 Oct 2005 11:05:25 +0100 Subject: [PATCH 0747/1939] [PATCH] fix radeon_cp_init_ring_buffer() I've seen similar failure on alpha. Obviously, someone forgot to convert sg->handle stuff for PCI gart case. Signed-off-by: Dave Airlie Signed-off-by: Linus Torvalds --- drivers/char/drm/radeon_cp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 6d9080a3ca7e..12ef13ff04ca 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1133,10 +1133,10 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, ring_start = (dev_priv->cp_ring->offset - dev->agp->base + dev_priv->gart_vm_start); - } else + } else #endif ring_start = (dev_priv->cp_ring->offset - - dev->sg->handle + - (unsigned long)dev->sg->virtual + dev_priv->gart_vm_start); RADEON_WRITE( RADEON_CP_RB_BASE, ring_start ); @@ -1164,7 +1164,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; - tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; + tmp_ofs = dev_priv->ring_rptr->offset - + (unsigned long)dev->sg->virtual; page_ofs = tmp_ofs >> PAGE_SHIFT; RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, @@ -1491,8 +1492,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) else #endif dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - - dev->sg->handle - + dev_priv->gart_vm_start); + - (unsigned long)dev->sg->virtual + + dev_priv->gart_vm_start); DRM_DEBUG( "dev_priv->gart_size %d\n", dev_priv->gart_size ); From 70ab81c2ed3d1323e7d6805bf59cbb570dff7937 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 26 Oct 2005 11:23:06 -0700 Subject: [PATCH 0748/1939] posix cpu timers: fix timer ordering Pointed out by Oleg Nesterov, who has been walking over the code forwards and backwards. Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index b15462b17a58..2f86424fa515 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -576,17 +576,15 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now) listpos = head; if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) { list_for_each_entry(next, head, entry) { - if (next->expires.sched > nt->expires.sched) { - listpos = &next->entry; + if (next->expires.sched > nt->expires.sched) break; - } + listpos = &next->entry; } } else { list_for_each_entry(next, head, entry) { - if (cputime_gt(next->expires.cpu, nt->expires.cpu)) { - listpos = &next->entry; + if (cputime_gt(next->expires.cpu, nt->expires.cpu)) break; - } + listpos = &next->entry; } } list_add(&nt->entry, listpos); From 7a4ed937aa44acdeb8c6ba671509dc7b54b09d3a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 26 Oct 2005 20:26:53 +0400 Subject: [PATCH 0749/1939] [PATCH] Fix cpu timers expiration time There's a silly off-by-one error in the code that updates the expiration of posix CPU timers, causing them to not be properly updated when they hit exactly on their expiration time (which should be the normal case). This causes them to then fire immediately again, and only _then_ get properly updated. Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 2f86424fa515..383ba22f0b62 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -91,7 +91,7 @@ static inline union cpu_time_count cpu_time_sub(clockid_t which_clock, * Update expiry time from increment, and increase overrun count, * given the current clock sample. */ -static inline void bump_cpu_timer(struct k_itimer *timer, +static void bump_cpu_timer(struct k_itimer *timer, union cpu_time_count now) { int i; @@ -110,7 +110,7 @@ static inline void bump_cpu_timer(struct k_itimer *timer, for (i = 0; incr < delta - incr; i++) incr = incr << 1; for (; i >= 0; incr >>= 1, i--) { - if (delta <= incr) + if (delta < incr) continue; timer->it.cpu.expires.sched += incr; timer->it_overrun += 1 << i; @@ -128,7 +128,7 @@ static inline void bump_cpu_timer(struct k_itimer *timer, for (i = 0; cputime_lt(incr, cputime_sub(delta, incr)); i++) incr = cputime_add(incr, incr); for (; i >= 0; incr = cputime_halve(incr), i--) { - if (cputime_le(delta, incr)) + if (cputime_lt(delta, incr)) continue; timer->it.cpu.expires.cpu = cputime_add(timer->it.cpu.expires.cpu, incr); From cb4ab974ae0bff3f49086090a1a50373c5edc8f4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 11:08:31 +1000 Subject: [PATCH 0750/1939] powerpc: Remove common stuff from setup_64.c This should have been in commit 03501dab035ab7da5e1373f5e130cfd6346d3f21 but got missed by accident. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_64.c | 270 --------------------------------- 1 file changed, 270 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 0312422881ae..9cdf294e76f6 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -138,23 +138,6 @@ static struct notifier_block ppc64_panic_block = { .priority = INT_MIN /* may not return; must be done last */ }; -/* - * Perhaps we can put the pmac screen_info[] here - * on pmac as well so we don't need the ifdef's. - * Until we get multiple-console support in here - * that is. -- Cort - * Maybe tie it to serial consoles, since this is really what - * these processors use on existing boards. -- Dan - */ -struct screen_info screen_info = { - .orig_x = 0, - .orig_y = 25, - .orig_video_cols = 80, - .orig_video_lines = 25, - .orig_video_isVGA = 1, - .orig_video_points = 16 -}; - #ifdef CONFIG_SMP static int smt_enabled_cmdline; @@ -641,51 +624,6 @@ void __init setup_system(void) DBG(" <- setup_system()\n"); } -/* also used by kexec */ -void machine_shutdown(void) -{ - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); -} - -void machine_restart(char *cmd) -{ - machine_shutdown(); - ppc_md.restart(cmd); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - -void machine_power_off(void) -{ - machine_shutdown(); - ppc_md.power_off(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} -/* Used by the G5 thermal driver */ -EXPORT_SYMBOL_GPL(machine_power_off); - -void machine_halt(void) -{ - machine_shutdown(); - ppc_md.halt(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - static int ppc64_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -693,90 +631,6 @@ static int ppc64_panic_event(struct notifier_block *this, return NOTIFY_DONE; } - -#ifdef CONFIG_SMP -DEFINE_PER_CPU(unsigned int, pvr); -#endif - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long cpu_id = (unsigned long)v - 1; - unsigned int pvr; - unsigned short maj; - unsigned short min; - - if (cpu_id == NR_CPUS) { - seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - - if (ppc_md.show_cpuinfo != NULL) - ppc_md.show_cpuinfo(m); - - return 0; - } - - /* We only show online cpus: disable preempt (overzealous, I - * knew) to prevent cpu going down. */ - preempt_disable(); - if (!cpu_online(cpu_id)) { - preempt_enable(); - return 0; - } - -#ifdef CONFIG_SMP - pvr = per_cpu(pvr, cpu_id); -#else - pvr = mfspr(SPRN_PVR); -#endif - maj = (pvr >> 8) & 0xFF; - min = pvr & 0xFF; - - seq_printf(m, "processor\t: %lu\n", cpu_id); - seq_printf(m, "cpu\t\t: "); - - if (cur_cpu_spec->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec->cpu_name); - else - seq_printf(m, "unknown (%08x)", pvr); - -#ifdef CONFIG_ALTIVEC - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - seq_printf(m, ", altivec supported"); -#endif /* CONFIG_ALTIVEC */ - - seq_printf(m, "\n"); - - /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ - seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, - ppc_proc_freq % 1000000); - - seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); - - preempt_enable(); - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - /* * These three variables are used to save values passed to us by prom_init() * via the device tree. The TCE variables are needed because with a memory_limit @@ -803,130 +657,6 @@ static int __init early_parsemem(char *p) early_param("mem", early_parsemem); #endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_MULTIPLATFORM -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout = NULL; - char *name; - u32 *spd; - int offset = 0; - - DBG(" -> set_preferred_console()\n"); - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) { - DBG(" console was specified !\n"); - return -EBUSY; - } - - if (!of_chosen) { - DBG(" of_chosen is NULL !\n"); - return -ENODEV; - } - /* We are getting a weird phandle from OF ... */ - /* ... So use the full path instead */ - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) { - DBG(" no linux,stdout-path !\n"); - return -ENODEV; - } - prom_stdout = of_find_node_by_path(name); - if (!prom_stdout) { - DBG(" can't find stdout package %s !\n", name); - return -ENODEV; - } - DBG("stdout is %s\n", prom_stdout->full_name); - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) { - DBG(" stdout package has no name !\n"); - goto not_found; - } - spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); - - if (0) - ; -#ifdef CONFIG_SERIAL_8250_CONSOLE - else if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - goto not_found; - } - } - } -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -#ifdef CONFIG_PPC_PSERIES - else if (strcmp(name, "vty") == 0) { - u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); - char *compat = (char *)get_property(prom_stdout, "compatible", NULL); - - if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { - /* Host Virtual Serial Interface */ - int offset; - switch (reg[0]) { - case 0x30000000: - offset = 0; - break; - case 0x30000001: - offset = 1; - break; - default: - goto not_found; - } - of_node_put(prom_stdout); - DBG("Found hvsi console at offset %d\n", offset); - return add_preferred_console("hvsi", offset, NULL); - } else { - /* pSeries LPAR virtual console */ - of_node_put(prom_stdout); - DBG("Found hvc console\n"); - return add_preferred_console("hvc", 0, NULL); - } - } -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - else - goto not_found; - of_node_put(prom_stdout); - - DBG("Found serial console at ttyS%d\n", offset); - - if (spd) { - static char __initdata opt[16]; - sprintf(opt, "%d", *spd); - return add_preferred_console("ttyS", offset, opt); - } else - return add_preferred_console("ttyS", offset, NULL); - - not_found: - DBG("No preferred console found !\n"); - of_node_put(prom_stdout); - return -ENODEV; -} -console_initcall(set_preferred_console); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - #ifdef CONFIG_IRQSTACKS static void __init irqstack_early_init(void) { From bf20a0000377f7bdeb42b78b10ed578deb3d63f1 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 16:45:29 +1000 Subject: [PATCH 0751/1939] powerpc: undeprecate the old OF device tree accessors for now The recent addition of __deprecated to the declarations for find_devices etc. produces a whole pile of warnings from the ppc32 code. Since those functions still work perfectly well on ppc32, which doesn't have hotplug support for anything in the OF device tree, and we don't have time to fix that code now, remove the __deprecated markings for now. Signed-off-by: Paul Mackerras --- include/asm-powerpc/prom.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 49d2c7455f8e..3a0104fa0462 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -155,12 +155,12 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e /* OBSOLETE: Old style node lookup */ -extern __deprecated struct device_node *find_devices(const char *name); -extern __deprecated struct device_node *find_type_devices(const char *type); -extern __deprecated struct device_node *find_path_device(const char *path); -extern __deprecated struct device_node *find_compatible_devices(const char *type, +extern struct device_node *find_devices(const char *name); +extern struct device_node *find_type_devices(const char *type); +extern struct device_node *find_path_device(const char *path); +extern struct device_node *find_compatible_devices(const char *type, const char *compat); -extern __deprecated struct device_node *find_all_nodes(void); +extern struct device_node *find_all_nodes(void); /* New style node lookup */ extern struct device_node *of_find_node_by_name(struct device_node *from, From 8168f902fa9c2ca8930ea8d72cce283234df03b8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 25 Oct 2005 16:56:43 +1000 Subject: [PATCH 0752/1939] [PATCH] ppc64: make dma_addr_t 64 bits There has been a need expressed for dma_addr_t to be 64 bits on PPC64. This patch does that. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/net/ibmveth.c | 2 +- include/asm-powerpc/types.h | 4 ++++ include/asm-ppc64/scatterlist.h | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index f5dc632452f1..cbe9368a4d56 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -532,7 +532,7 @@ static int ibmveth_open(struct net_device *netdev) if(lpar_rc != H_Success) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); - ibmveth_error_printk("buffer TCE:0x%x filter TCE:0x%x rxq desc:0x%lx MAC:0x%lx\n", + ibmveth_error_printk("buffer TCE:0x%lx filter TCE:0x%lx rxq desc:0x%lx MAC:0x%lx\n", adapter->buffer_list_dma, adapter->filter_list_dma, rxq_desc.desc, diff --git a/include/asm-powerpc/types.h b/include/asm-powerpc/types.h index f70cd3fb32d9..ec3c2ee8bf86 100644 --- a/include/asm-powerpc/types.h +++ b/include/asm-powerpc/types.h @@ -85,7 +85,11 @@ typedef unsigned long long u64; typedef __vector128 vector128; +#ifdef __powerpc64__ +typedef u64 dma_addr_t; +#else typedef u32 dma_addr_t; +#endif typedef u64 dma64_addr_t; typedef struct { diff --git a/include/asm-ppc64/scatterlist.h b/include/asm-ppc64/scatterlist.h index cecce6c6dfbb..65a2a027ac94 100644 --- a/include/asm-ppc64/scatterlist.h +++ b/include/asm-ppc64/scatterlist.h @@ -19,7 +19,7 @@ struct scatterlist { unsigned int length; /* For TCE support */ - u32 dma_address; + dma_addr_t dma_address; u32 dma_length; }; From 89edce0b4e71f6f78e27d7c18c63e957469b74d3 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 25 Oct 2005 16:59:03 +1000 Subject: [PATCH 0753/1939] [PATCH] powerpc: merge scatterlist.h This depends on the 64bit dma_addr_t patch. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- .../{asm-ppc64 => asm-powerpc}/scatterlist.h | 22 +++++++++++++--- include/asm-ppc/scatterlist.h | 25 ------------------- 2 files changed, 18 insertions(+), 29 deletions(-) rename include/{asm-ppc64 => asm-powerpc}/scatterlist.h (54%) delete mode 100644 include/asm-ppc/scatterlist.h diff --git a/include/asm-ppc64/scatterlist.h b/include/asm-powerpc/scatterlist.h similarity index 54% rename from include/asm-ppc64/scatterlist.h rename to include/asm-powerpc/scatterlist.h index 65a2a027ac94..8c992d1491d4 100644 --- a/include/asm-ppc64/scatterlist.h +++ b/include/asm-powerpc/scatterlist.h @@ -1,6 +1,5 @@ -#ifndef _PPC64_SCATTERLIST_H -#define _PPC64_SCATTERLIST_H - +#ifndef _ASM_POWERPC_SCATTERLIST_H +#define _ASM_POWERPC_SCATTERLIST_H /* * Copyright (C) 2001 PPC64 Team, IBM Corp * @@ -10,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ +#ifdef __KERNEL__ #include #include @@ -23,9 +23,23 @@ struct scatterlist { u32 dma_length; }; +/* + * These macros should be used after a dma_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. + */ #define sg_dma_address(sg) ((sg)->dma_address) +#ifdef __powerpc64__ #define sg_dma_len(sg) ((sg)->dma_length) +#else +#define sg_dma_len(sg) ((sg)->length) +#endif +#ifdef __powerpc64__ #define ISA_DMA_THRESHOLD (~0UL) +#endif -#endif /* !(_PPC64_SCATTERLIST_H) */ +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_SCATTERLIST_H */ diff --git a/include/asm-ppc/scatterlist.h b/include/asm-ppc/scatterlist.h deleted file mode 100644 index f21f18f56548..000000000000 --- a/include/asm-ppc/scatterlist.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifdef __KERNEL__ -#ifndef _PPC_SCATTERLIST_H -#define _PPC_SCATTERLIST_H - -#include - -struct scatterlist { - struct page *page; - unsigned int offset; - dma_addr_t dma_address; - unsigned int length; -}; - -/* - * These macros should be used after a pci_map_sg call has been done - * to get bus addresses of each of the SG entries and their lengths. - * You should only work with the number of sg entries pci_map_sg - * returns, or alternatively stop on the first sg_dma_len(sg) which - * is 0. - */ -#define sg_dma_address(sg) ((sg)->dma_address) -#define sg_dma_len(sg) ((sg)->length) - -#endif /* !(_PPC_SCATTERLIST_H) */ -#endif /* __KERNEL__ */ From fda262b8978d0089758ef9444508434c74113a61 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 20:20:42 +1000 Subject: [PATCH 0754/1939] [PATCH] ppc64: remove arch/ppc64/kernel/setup.c and use setup_64.c from the merged tree instead. The only difference between them was the code to set up the syscall maps. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 5 +- arch/powerpc/kernel/setup_64.c | 18 +- arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/setup.c | 1307 -------------------------------- 4 files changed, 17 insertions(+), 1315 deletions(-) delete mode 100644 arch/ppc64/kernel/setup.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 30101762f7c0..a733347964a0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,7 +12,8 @@ endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ signal_32.o pmc.o -obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o +obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ + ptrace32.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o @@ -34,7 +35,7 @@ extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ prom.o systbl.o traps.o setup-common.o obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o -obj-$(CONFIG_PPC64) += setup_64.o misc_64.o +obj-$(CONFIG_PPC64) += misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 9cdf294e76f6..721adeea601d 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -702,6 +702,17 @@ static void __init emergency_stack_init(void) limit)) + PAGE_SIZE; } +extern unsigned long *sys_call_table; +extern unsigned long sys_ni_syscall; +#ifdef CONFIG_PPC_MERGE +#define SYS_CALL_ENTRY64(i) sys_call_table[(i) * 2] +#define SYS_CALL_ENTRY32(i) sys_call_table[(i) * 2 + 1] +#else +extern unsigned long *sys_call_table32; +#define SYS_CALL_ENTRY64(i) sys_call_table[(i)] +#define SYS_CALL_ENTRY32(i) sys_call_table32[(i)] +#endif + /* * Called from setup_arch to initialize the bitmap of available * syscalls in the systemcfg page @@ -709,17 +720,14 @@ static void __init emergency_stack_init(void) void __init setup_syscall_map(void) { unsigned int i, count64 = 0, count32 = 0; - extern unsigned long *sys_call_table; - extern unsigned long sys_ni_syscall; - for (i = 0; i < __NR_syscalls; i++) { - if (sys_call_table[i*2] != sys_ni_syscall) { + if (SYS_CALL_ENTRY64(i) != sys_ni_syscall) { count64++; systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); } - if (sys_call_table[i*2+1] != sys_ni_syscall) { + if (SYS_CALL_ENTRY32(i) != sys_ni_syscall) { count32++; systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 83ecefdcfef7..f2f60c9cc55f 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -7,7 +7,7 @@ ifneq ($(CONFIG_PPC_MERGE),y) EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds -obj-y := setup.o entry.o misc.o prom.o +obj-y := entry.o misc.o prom.o endif diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c deleted file mode 100644 index 44ee6ebe9a60..000000000000 --- a/arch/ppc64/kernel/setup.c +++ /dev/null @@ -1,1307 +0,0 @@ -/* - * - * Common boot and setup code. - * - * Copyright (C) 2001 PPC64 Team, 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. - */ - -#undef DEBUG - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * Here are some early debugging facilities. You can enable one - * but your kernel will not boot on anything else if you do so - */ - -/* This one is for use on LPAR machines that support an HVC console - * on vterm 0 - */ -extern void udbg_init_debug_lpar(void); -/* This one is for use on Apple G5 machines - */ -extern void udbg_init_pmac_realmode(void); -/* That's RTAS panel debug */ -extern void call_rtas_display_status_delay(unsigned char c); -/* Here's maple real mode debug */ -extern void udbg_init_maple_realmode(void); - -#define EARLY_DEBUG_INIT() do {} while(0) - -#if 0 -#define EARLY_DEBUG_INIT() udbg_init_debug_lpar() -#define EARLY_DEBUG_INIT() udbg_init_maple_realmode() -#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() -#define EARLY_DEBUG_INIT() \ - do { udbg_putc = call_rtas_display_status_delay; } while(0) -#endif - -/* extern void *stab; */ -extern unsigned long klimit; - -extern void mm_init_ppc64(void); -extern void stab_initialize(unsigned long stab); -extern void htab_initialize(void); -extern void early_init_devtree(void *flat_dt); -extern void unflatten_device_tree(void); - -extern void smp_release_cpus(void); - -int have_of = 1; -int boot_cpuid = 0; -int boot_cpuid_phys = 0; -dev_t boot_dev; -u64 ppc64_pft_size; - -struct ppc64_caches ppc64_caches; -EXPORT_SYMBOL_GPL(ppc64_caches); - -/* - * These are used in binfmt_elf.c to put aux entries on the stack - * for each elf executable being started. - */ -int dcache_bsize; -int icache_bsize; -int ucache_bsize; - -/* The main machine-dep calls structure - */ -struct machdep_calls ppc_md; -EXPORT_SYMBOL(ppc_md); - -#ifdef CONFIG_MAGIC_SYSRQ -unsigned long SYSRQ_KEY; -#endif /* CONFIG_MAGIC_SYSRQ */ - - -static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); -static struct notifier_block ppc64_panic_block = { - .notifier_call = ppc64_panic_event, - .priority = INT_MIN /* may not return; must be done last */ -}; - -/* - * Perhaps we can put the pmac screen_info[] here - * on pmac as well so we don't need the ifdef's. - * Until we get multiple-console support in here - * that is. -- Cort - * Maybe tie it to serial consoles, since this is really what - * these processors use on existing boards. -- Dan - */ -struct screen_info screen_info = { - .orig_x = 0, - .orig_y = 25, - .orig_video_cols = 80, - .orig_video_lines = 25, - .orig_video_isVGA = 1, - .orig_video_points = 16 -}; - -#ifdef CONFIG_SMP - -static int smt_enabled_cmdline; - -/* Look for ibm,smt-enabled OF option */ -static void check_smt_enabled(void) -{ - struct device_node *dn; - char *smt_option; - - /* Allow the command line to overrule the OF option */ - if (smt_enabled_cmdline) - return; - - dn = of_find_node_by_path("/options"); - - if (dn) { - smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); - - if (smt_option) { - if (!strcmp(smt_option, "on")) - smt_enabled_at_boot = 1; - else if (!strcmp(smt_option, "off")) - smt_enabled_at_boot = 0; - } - } -} - -/* Look for smt-enabled= cmdline option */ -static int __init early_smt_enabled(char *p) -{ - smt_enabled_cmdline = 1; - - if (!p) - return 0; - - if (!strcmp(p, "on") || !strcmp(p, "1")) - smt_enabled_at_boot = 1; - else if (!strcmp(p, "off") || !strcmp(p, "0")) - smt_enabled_at_boot = 0; - - return 0; -} -early_param("smt-enabled", early_smt_enabled); - -/** - * setup_cpu_maps - initialize the following cpu maps: - * cpu_possible_map - * cpu_present_map - * cpu_sibling_map - * - * Having the possible map set up early allows us to restrict allocations - * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. - * - * We do not initialize the online map here; cpus set their own bits in - * cpu_online_map as they come up. - * - * This function is valid only for Open Firmware systems. finish_device_tree - * must be called before using this. - * - * While we're here, we may as well set the "physical" cpu ids in the paca. - */ -static void __init setup_cpu_maps(void) -{ - struct device_node *dn = NULL; - int cpu = 0; - int swap_cpuid = 0; - - check_smt_enabled(); - - while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { - u32 *intserv; - int j, len = sizeof(u32), nthreads; - - intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", - &len); - if (!intserv) - intserv = (u32 *)get_property(dn, "reg", NULL); - - nthreads = len / sizeof(u32); - - for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { - cpu_set(cpu, cpu_present_map); - set_hard_smp_processor_id(cpu, intserv[j]); - - if (intserv[j] == boot_cpuid_phys) - swap_cpuid = cpu; - cpu_set(cpu, cpu_possible_map); - cpu++; - } - } - - /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that - * boot cpu is logical 0. - */ - if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { - u32 tmp; - tmp = get_hard_smp_processor_id(0); - set_hard_smp_processor_id(0, boot_cpuid_phys); - set_hard_smp_processor_id(swap_cpuid, tmp); - } - - /* - * On pSeries LPAR, we need to know how many cpus - * could possibly be added to this partition. - */ - if (systemcfg->platform == PLATFORM_PSERIES_LPAR && - (dn = of_find_node_by_path("/rtas"))) { - int num_addr_cell, num_size_cell, maxcpus; - unsigned int *ireg; - - num_addr_cell = prom_n_addr_cells(dn); - num_size_cell = prom_n_size_cells(dn); - - ireg = (unsigned int *) - get_property(dn, "ibm,lrdr-capacity", NULL); - - if (!ireg) - goto out; - - maxcpus = ireg[num_addr_cell + num_size_cell]; - - /* Double maxcpus for processors which have SMT capability */ - if (cpu_has_feature(CPU_FTR_SMT)) - maxcpus *= 2; - - if (maxcpus > NR_CPUS) { - printk(KERN_WARNING - "Partition configured for %d cpus, " - "operating system maximum is %d.\n", - maxcpus, NR_CPUS); - maxcpus = NR_CPUS; - } else - printk(KERN_INFO "Partition configured for %d cpus.\n", - maxcpus); - - for (cpu = 0; cpu < maxcpus; cpu++) - cpu_set(cpu, cpu_possible_map); - out: - of_node_put(dn); - } - - /* - * Do the sibling map; assume only two threads per processor. - */ - for_each_cpu(cpu) { - cpu_set(cpu, cpu_sibling_map[cpu]); - if (cpu_has_feature(CPU_FTR_SMT)) - cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); - } - - systemcfg->processorCount = num_present_cpus(); -} -#endif /* CONFIG_SMP */ - -extern struct machdep_calls pSeries_md; -extern struct machdep_calls pmac_md; -extern struct machdep_calls maple_md; -extern struct machdep_calls bpa_md; -extern struct machdep_calls iseries_md; - -/* Ultimately, stuff them in an elf section like initcalls... */ -static struct machdep_calls __initdata *machines[] = { -#ifdef CONFIG_PPC_PSERIES - &pSeries_md, -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_PPC_PMAC - &pmac_md, -#endif /* CONFIG_PPC_PMAC */ -#ifdef CONFIG_PPC_MAPLE - &maple_md, -#endif /* CONFIG_PPC_MAPLE */ -#ifdef CONFIG_PPC_BPA - &bpa_md, -#endif -#ifdef CONFIG_PPC_ISERIES - &iseries_md, -#endif - NULL -}; - -/* - * Early initialization entry point. This is called by head.S - * with MMU translation disabled. We rely on the "feature" of - * the CPU that ignores the top 2 bits of the address in real - * mode so we can access kernel globals normally provided we - * only toy with things in the RMO region. From here, we do - * some early parsing of the device-tree to setup out LMB - * data structures, and allocate & initialize the hash table - * and segment tables so we can start running with translation - * enabled. - * - * It is this function which will call the probe() callback of - * the various platform types and copy the matching one to the - * global ppc_md structure. Your platform can eventually do - * some very early initializations from the probe() routine, but - * this is not recommended, be very careful as, for example, the - * device-tree is not accessible via normal means at this point. - */ - -void __init early_setup(unsigned long dt_ptr) -{ - struct paca_struct *lpaca = get_paca(); - static struct machdep_calls **mach; - - /* - * Enable early debugging if any specified (see top of - * this file) - */ - EARLY_DEBUG_INIT(); - - DBG(" -> early_setup()\n"); - - /* - * Fill the default DBG level (do we want to keep - * that old mecanism around forever ?) - */ - ppcdbg_initialize(); - - /* - * Do early initializations using the flattened device - * tree, like retreiving the physical memory map or - * calculating/retreiving the hash table size - */ - early_init_devtree(__va(dt_ptr)); - - /* - * Iterate all ppc_md structures until we find the proper - * one for the current machine type - */ - DBG("Probing machine type for platform %x...\n", - systemcfg->platform); - - for (mach = machines; *mach; mach++) { - if ((*mach)->probe(systemcfg->platform)) - break; - } - /* What can we do if we didn't find ? */ - if (*mach == NULL) { - DBG("No suitable machine found !\n"); - for (;;); - } - ppc_md = **mach; - - DBG("Found, Initializing memory management...\n"); - - /* - * Initialize stab / SLB management - */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - stab_initialize(lpaca->stab_real); - - /* - * Initialize the MMU Hash table and create the linear mapping - * of memory - */ - htab_initialize(); - - DBG(" <- early_setup()\n"); -} - - -/* - * Initialize some remaining members of the ppc64_caches and systemcfg structures - * (at least until we get rid of them completely). This is mostly some - * cache informations about the CPU that will be used by cache flush - * routines and/or provided to userland - */ -static void __init initialize_cache_info(void) -{ - struct device_node *np; - unsigned long num_cpus = 0; - - DBG(" -> initialize_cache_info()\n"); - - for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { - num_cpus += 1; - - /* We're assuming *all* of the CPUs have the same - * d-cache and i-cache sizes... -Peter - */ - - if ( num_cpus == 1 ) { - u32 *sizep, *lsizep; - u32 size, lsize; - const char *dc, *ic; - - /* Then read cache informations */ - if (systemcfg->platform == PLATFORM_POWERMAC) { - dc = "d-cache-block-size"; - ic = "i-cache-block-size"; - } else { - dc = "d-cache-line-size"; - ic = "i-cache-line-size"; - } - - size = 0; - lsize = cur_cpu_spec->dcache_bsize; - sizep = (u32 *)get_property(np, "d-cache-size", NULL); - if (sizep != NULL) - size = *sizep; - lsizep = (u32 *) get_property(np, dc, NULL); - if (lsizep != NULL) - lsize = *lsizep; - if (sizep == 0 || lsizep == 0) - DBG("Argh, can't find dcache properties ! " - "sizep: %p, lsizep: %p\n", sizep, lsizep); - - systemcfg->dcache_size = ppc64_caches.dsize = size; - systemcfg->dcache_line_size = - ppc64_caches.dline_size = lsize; - ppc64_caches.log_dline_size = __ilog2(lsize); - ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; - - size = 0; - lsize = cur_cpu_spec->icache_bsize; - sizep = (u32 *)get_property(np, "i-cache-size", NULL); - if (sizep != NULL) - size = *sizep; - lsizep = (u32 *)get_property(np, ic, NULL); - if (lsizep != NULL) - lsize = *lsizep; - if (sizep == 0 || lsizep == 0) - DBG("Argh, can't find icache properties ! " - "sizep: %p, lsizep: %p\n", sizep, lsizep); - - systemcfg->icache_size = ppc64_caches.isize = size; - systemcfg->icache_line_size = - ppc64_caches.iline_size = lsize; - ppc64_caches.log_iline_size = __ilog2(lsize); - ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; - } - } - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); - systemcfg->version.major = SYSTEMCFG_MAJOR; - systemcfg->version.minor = SYSTEMCFG_MINOR; - systemcfg->processor = mfspr(SPRN_PVR); - - DBG(" <- initialize_cache_info()\n"); -} - -static void __init check_for_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - u64 *prop; - - DBG(" -> check_for_initrd()\n"); - - if (of_chosen) { - prop = (u64 *)get_property(of_chosen, - "linux,initrd-start", NULL); - if (prop != NULL) { - initrd_start = (unsigned long)__va(*prop); - prop = (u64 *)get_property(of_chosen, - "linux,initrd-end", NULL); - if (prop != NULL) { - initrd_end = (unsigned long)__va(*prop); - initrd_below_start_ok = 1; - } else - initrd_start = 0; - } - } - - /* If we were passed an initrd, set the ROOT_DEV properly if the values - * look sensible. If not, clear initrd reference. - */ - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && - initrd_end > initrd_start) - ROOT_DEV = Root_RAM0; - else - initrd_start = initrd_end = 0; - - if (initrd_start) - printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); - - DBG(" <- check_for_initrd()\n"); -#endif /* CONFIG_BLK_DEV_INITRD */ -} - -/* - * Do some initial setup of the system. The parameters are those which - * were passed in from the bootloader. - */ -void __init setup_system(void) -{ - DBG(" -> setup_system()\n"); - - /* - * Unflatten the device-tree passed by prom_init or kexec - */ - unflatten_device_tree(); - - /* - * Fill the ppc64_caches & systemcfg structures with informations - * retreived from the device-tree. Need to be called before - * finish_device_tree() since the later requires some of the - * informations filled up here to properly parse the interrupt - * tree. - * It also sets up the cache line sizes which allows to call - * routines like flush_icache_range (used by the hash init - * later on). - */ - initialize_cache_info(); - -#ifdef CONFIG_PPC_RTAS - /* - * Initialize RTAS if available - */ - rtas_initialize(); -#endif /* CONFIG_PPC_RTAS */ - - /* - * Check if we have an initrd provided via the device-tree - */ - check_for_initrd(); - - /* - * Do some platform specific early initializations, that includes - * setting up the hash table pointers. It also sets up some interrupt-mapping - * related options that will be used by finish_device_tree() - */ - ppc_md.init_early(); - - /* - * "Finish" the device-tree, that is do the actual parsing of - * some of the properties like the interrupt map - */ - finish_device_tree(); - -#ifdef CONFIG_BOOTX_TEXT - init_boot_display(); -#endif - - /* - * Initialize xmon - */ -#ifdef CONFIG_XMON_DEFAULT - xmon_init(1); -#endif - /* - * Register early console - */ - register_early_udbg_console(); - - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - - parse_early_param(); - -#ifdef CONFIG_SMP - /* - * iSeries has already initialized the cpu maps at this point. - */ - setup_cpu_maps(); - - /* Release secondary cpus out of their spinloops at 0x60 now that - * we can map physical -> logical CPU ids - */ - smp_release_cpus(); -#endif - - printk("Starting Linux PPC64 %s\n", system_utsname.version); - - printk("-----------------------------------------------------\n"); - printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); - printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); - printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); - printk("systemcfg = 0x%p\n", systemcfg); - printk("systemcfg->platform = 0x%x\n", systemcfg->platform); - printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); - printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); - printk("ppc64_caches.dcache_line_size = 0x%x\n", - ppc64_caches.dline_size); - printk("ppc64_caches.icache_line_size = 0x%x\n", - ppc64_caches.iline_size); - printk("htab_address = 0x%p\n", htab_address); - printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); - printk("-----------------------------------------------------\n"); - - mm_init_ppc64(); - - DBG(" <- setup_system()\n"); -} - -/* also used by kexec */ -void machine_shutdown(void) -{ - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); -} - -void machine_restart(char *cmd) -{ - machine_shutdown(); - ppc_md.restart(cmd); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - -void machine_power_off(void) -{ - machine_shutdown(); - ppc_md.power_off(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} -/* Used by the G5 thermal driver */ -EXPORT_SYMBOL_GPL(machine_power_off); - -void machine_halt(void) -{ - machine_shutdown(); - ppc_md.halt(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - -static int ppc64_panic_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - ppc_md.panic((char *)ptr); /* May not return */ - return NOTIFY_DONE; -} - - -#ifdef CONFIG_SMP -DEFINE_PER_CPU(unsigned int, pvr); -#endif - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long cpu_id = (unsigned long)v - 1; - unsigned int pvr; - unsigned short maj; - unsigned short min; - - if (cpu_id == NR_CPUS) { - seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - - if (ppc_md.show_cpuinfo != NULL) - ppc_md.show_cpuinfo(m); - - return 0; - } - - /* We only show online cpus: disable preempt (overzealous, I - * knew) to prevent cpu going down. */ - preempt_disable(); - if (!cpu_online(cpu_id)) { - preempt_enable(); - return 0; - } - -#ifdef CONFIG_SMP - pvr = per_cpu(pvr, cpu_id); -#else - pvr = mfspr(SPRN_PVR); -#endif - maj = (pvr >> 8) & 0xFF; - min = pvr & 0xFF; - - seq_printf(m, "processor\t: %lu\n", cpu_id); - seq_printf(m, "cpu\t\t: "); - - if (cur_cpu_spec->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec->cpu_name); - else - seq_printf(m, "unknown (%08x)", pvr); - -#ifdef CONFIG_ALTIVEC - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - seq_printf(m, ", altivec supported"); -#endif /* CONFIG_ALTIVEC */ - - seq_printf(m, "\n"); - - /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ - seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, - ppc_proc_freq % 1000000); - - seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); - - preempt_enable(); - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -/* - * These three variables are used to save values passed to us by prom_init() - * via the device tree. The TCE variables are needed because with a memory_limit - * in force we may need to explicitly map the TCE are at the top of RAM. - */ -unsigned long memory_limit; -unsigned long tce_alloc_start; -unsigned long tce_alloc_end; - -#ifdef CONFIG_PPC_ISERIES -/* - * 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) - return 0; - - memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); - - return 0; -} -early_param("mem", early_parsemem); -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_MULTIPLATFORM -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout = NULL; - char *name; - u32 *spd; - int offset = 0; - - DBG(" -> set_preferred_console()\n"); - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) { - DBG(" console was specified !\n"); - return -EBUSY; - } - - if (!of_chosen) { - DBG(" of_chosen is NULL !\n"); - return -ENODEV; - } - /* We are getting a weird phandle from OF ... */ - /* ... So use the full path instead */ - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) { - DBG(" no linux,stdout-path !\n"); - return -ENODEV; - } - prom_stdout = of_find_node_by_path(name); - if (!prom_stdout) { - DBG(" can't find stdout package %s !\n", name); - return -ENODEV; - } - DBG("stdout is %s\n", prom_stdout->full_name); - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) { - DBG(" stdout package has no name !\n"); - goto not_found; - } - spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); - - if (0) - ; -#ifdef CONFIG_SERIAL_8250_CONSOLE - else if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - goto not_found; - } - } - } -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -#ifdef CONFIG_PPC_PSERIES - else if (strcmp(name, "vty") == 0) { - u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); - char *compat = (char *)get_property(prom_stdout, "compatible", NULL); - - if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { - /* Host Virtual Serial Interface */ - int offset; - switch (reg[0]) { - case 0x30000000: - offset = 0; - break; - case 0x30000001: - offset = 1; - break; - default: - goto not_found; - } - of_node_put(prom_stdout); - DBG("Found hvsi console at offset %d\n", offset); - return add_preferred_console("hvsi", offset, NULL); - } else { - /* pSeries LPAR virtual console */ - of_node_put(prom_stdout); - DBG("Found hvc console\n"); - return add_preferred_console("hvc", 0, NULL); - } - } -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - else - goto not_found; - of_node_put(prom_stdout); - - DBG("Found serial console at ttyS%d\n", offset); - - if (spd) { - static char __initdata opt[16]; - sprintf(opt, "%d", *spd); - return add_preferred_console("ttyS", offset, opt); - } else - return add_preferred_console("ttyS", offset, NULL); - - not_found: - DBG("No preferred console found !\n"); - of_node_put(prom_stdout); - return -ENODEV; -} -console_initcall(set_preferred_console); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -#ifdef CONFIG_IRQSTACKS -static void __init irqstack_early_init(void) -{ - unsigned int i; - - /* - * interrupt stacks must be under 256MB, we cannot afford to take - * SLB misses on them. - */ - for_each_cpu(i) { - softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); - hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); - } -} -#else -#define irqstack_early_init() -#endif - -/* - * Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. - */ -static void __init emergency_stack_init(void) -{ - unsigned long limit; - unsigned int i; - - /* - * Emergency stacks must be under 256MB, we cannot afford to take - * SLB misses on them. The ABI also requires them to be 128-byte - * aligned. - * - * Since we use these as temporary stacks during secondary CPU - * bringup, we need to get at them in real mode. This means they - * must also be within the RMO region. - */ - limit = min(0x10000000UL, lmb.rmo_size); - - for_each_cpu(i) - paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, - limit)) + PAGE_SIZE; -} - -/* - * Called from setup_arch to initialize the bitmap of available - * syscalls in the systemcfg page - */ -void __init setup_syscall_map(void) -{ - unsigned int i, count64 = 0, count32 = 0; - extern unsigned long *sys_call_table; - extern unsigned long *sys_call_table32; - extern unsigned long sys_ni_syscall; - - - for (i = 0; i < __NR_syscalls; i++) { - if (sys_call_table[i] == sys_ni_syscall) - continue; - count64++; - systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); - } - for (i = 0; i < __NR_syscalls; i++) { - if (sys_call_table32[i] == sys_ni_syscall) - continue; - count32++; - systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); - } - printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", - count32, count64); -} - -/* - * Called into from start_kernel, after lock_kernel has been called. - * Initializes bootmem, which is unsed to manage page allocation until - * mem_init is called. - */ -void __init setup_arch(char **cmdline_p) -{ - extern void do_init_bootmem(void); - - ppc64_boot_msg(0x12, "Setup Arch"); - - *cmdline_p = cmd_line; - - /* - * Set cache line size based on type of cpu as a default. - * Systems with OF can look in the properties on the cpu node(s) - * for a possibly more accurate value. - */ - dcache_bsize = ppc64_caches.dline_size; - icache_bsize = ppc64_caches.iline_size; - - /* reboot on panic */ - panic_timeout = 180; - - if (ppc_md.panic) - notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); - - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = klimit; - - irqstack_early_init(); - emergency_stack_init(); - - stabs_alloc(); - - /* set up the bootmem stuff with available memory */ - do_init_bootmem(); - sparse_init(); - - /* initialize the syscall map in systemcfg */ - setup_syscall_map(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - ppc_md.setup_arch(); - - /* Use the default idle loop if the platform hasn't provided one. */ - if (NULL == ppc_md.idle_loop) { - ppc_md.idle_loop = default_idle; - printk(KERN_INFO "Using default idle loop\n"); - } - - paging_init(); - ppc64_boot_msg(0x15, "Setup Done"); -} - - -/* ToDo: do something useful if ppc_md is not yet setup. */ -#define PPC64_LINUX_FUNCTION 0x0f000000 -#define PPC64_IPL_MESSAGE 0xc0000000 -#define PPC64_TERM_MESSAGE 0xb0000000 - -static void ppc64_do_msg(unsigned int src, const char *msg) -{ - if (ppc_md.progress) { - char buf[128]; - - sprintf(buf, "%08X\n", src); - ppc_md.progress(buf, 0); - snprintf(buf, 128, "%s", msg); - ppc_md.progress(buf, 0); - } -} - -/* Print a boot progress message. */ -void ppc64_boot_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); - printk("[boot]%04x %s\n", src, msg); -} - -/* Print a termination message (print only -- does not stop the kernel) */ -void ppc64_terminate_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); - printk("[terminate]%04x %s\n", src, msg); -} - -#ifndef CONFIG_PPC_ISERIES -/* - * This function can be used by platforms to "find" legacy serial ports. - * It works for "serial" nodes under an "isa" node, and will try to - * respect the "ibm,aix-loc" property if any. It works with up to 8 - * ports. - */ - -#define MAX_LEGACY_SERIAL_PORTS 8 -static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; -static unsigned int old_serial_count; - -void __init generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed) -{ - struct device_node *np; - u32 *sizeprop; - - struct isa_reg_property { - u32 space; - u32 address; - u32 size; - }; - struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; - }; - - DBG(" -> generic_find_legacy_serial_port()\n"); - - *physport = 0; - if (default_speed) - *default_speed = 0; - - np = of_find_node_by_path("/"); - if (!np) - return; - - /* First fill our array */ - for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { - struct device_node *isa, *pci; - struct isa_reg_property *reg; - unsigned long phys_size, addr_size, io_base; - u32 *rangesp; - u32 *interrupts, *clk, *spd; - char *typep; - int index, rlen, rentsize; - - /* Ok, first check if it's under an "isa" parent */ - isa = of_get_parent(np); - if (!isa || strcmp(isa->name, "isa")) { - DBG("%s: no isa parent found\n", np->full_name); - continue; - } - - /* Now look for an "ibm,aix-loc" property that gives us ordering - * if any... - */ - typep = (char *)get_property(np, "ibm,aix-loc", NULL); - - /* Get the ISA port number */ - reg = (struct isa_reg_property *)get_property(np, "reg", NULL); - if (reg == NULL) - goto next_port; - /* We assume the interrupt number isn't translated ... */ - interrupts = (u32 *)get_property(np, "interrupts", NULL); - /* get clock freq. if present */ - clk = (u32 *)get_property(np, "clock-frequency", NULL); - /* get default speed if present */ - spd = (u32 *)get_property(np, "current-speed", NULL); - /* Default to locate at end of array */ - index = old_serial_count; /* end of the array by default */ - - /* If we have a location index, then use it */ - if (typep && *typep == 'S') { - index = simple_strtol(typep+1, NULL, 0) - 1; - /* if index is out of range, use end of array instead */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - index = old_serial_count; - /* if our index is still out of range, that mean that - * array is full, we could scan for a free slot but that - * make little sense to bother, just skip the port - */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - /* Check if there is a port who already claimed our slot */ - if (serial_ports[index].iobase != 0) { - /* if we still have some room, move it, else override */ - if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { - DBG("Moved legacy port %d -> %d\n", index, - old_serial_count); - serial_ports[old_serial_count++] = - serial_ports[index]; - } else { - DBG("Replacing legacy port %d\n", index); - } - } - } - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - - /* Now fill the entry */ - memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); - serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; - serial_ports[index].iobase = reg->address; - serial_ports[index].irq = interrupts ? interrupts[0] : 0; - serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; - - DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", - index, - serial_ports[index].iobase, - serial_ports[index].irq, - serial_ports[index].uartclk); - - /* Get phys address of IO reg for port 1 */ - if (index != 0) - goto next_port; - - pci = of_get_parent(isa); - if (!pci) { - DBG("%s: no pci parent found\n", np->full_name); - goto next_port; - } - - rangesp = (u32 *)get_property(pci, "ranges", &rlen); - if (rangesp == NULL) { - of_node_put(pci); - goto next_port; - } - rlen /= 4; - - /* we need the #size-cells of the PCI bridge node itself */ - phys_size = 1; - sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); - if (sizeprop != NULL) - phys_size = *sizeprop; - /* we need the parent #addr-cells */ - addr_size = prom_n_addr_cells(pci); - rentsize = 3 + addr_size + phys_size; - io_base = 0; - for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { - if (((rangesp[0] >> 24) & 0x3) != 1) - continue; /* not IO space */ - io_base = rangesp[3]; - if (addr_size == 2) - io_base = (io_base << 32) | rangesp[4]; - } - if (io_base != 0) { - *physport = io_base + reg->address; - if (default_speed && spd) - *default_speed = *spd; - } - of_node_put(pci); - next_port: - of_node_put(isa); - } - - DBG(" <- generic_find_legacy_serial_port()\n"); -} - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_ports, - }, -}; - -static int __init serial_dev_init(void) -{ - return platform_device_register(&serial_device); -} -arch_initcall(serial_dev_init); - -#endif /* CONFIG_PPC_ISERIES */ - -int check_legacy_ioport(unsigned long base_port) -{ - if (ppc_md.check_legacy_ioport == NULL) - return 0; - return ppc_md.check_legacy_ioport(base_port); -} -EXPORT_SYMBOL(check_legacy_ioport); - -#ifdef CONFIG_XMON -static int __init early_xmon(char *p) -{ - /* ensure xmon is enabled */ - if (p) { - if (strncmp(p, "on", 2) == 0) - xmon_init(1); - if (strncmp(p, "off", 3) == 0) - xmon_init(0); - if (strncmp(p, "early", 5) != 0) - return 0; - } - xmon_init(1); - debugger(NULL); - - return 0; -} -early_param("xmon", early_xmon); -#endif - -void cpu_die(void) -{ - if (ppc_md.cpu_die) - ppc_md.cpu_die(); -} From 25c8a78b1e00ac0cc640677eda78b462c2cd4c6e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 27 Oct 2005 16:27:25 +1000 Subject: [PATCH 0755/1939] [PATCH] powerpc: Fix handling of fpscr on 64-bit The recent merge of fpu.S broken the handling of fpscr for ARCH=powerpc and CONFIG_PPC64=y. FP registers could be corrupted, leading to strange random application crashes. The confusion arises, because the thread_struct has (and requires) a 64-bit area to save the fpscr, because we use load/store double instructions to get it in to/out of the FPU. However, only the low 32-bits are actually used, so we want to treat it as a 32-bit quantity when manipulating its bits to avoid extra load/stores on 32-bit. This patch replaces the current definition with a structure of two 32-bit quantities (pad and val), to clarify things as much as is possible. The 'val' field is used when manipulating bits, the structure itself is used when obtaining the address for loading/unloading the value from the FPU. While we're at it, consolidate the 4 (!) almost identical versions of cvt_fd() and cvt_df() (arch/ppc/kernel/misc.S, arch/ppc64/kernel/misc.S, arch/powerpc/kernel/misc_32.S, arch/powerpc/kernel/misc_64.S) into a single version in fpu.S. The new version takes a pointer to thread_struct and applies the correct offset itself, rather than a pointer to the fpscr field itself, again to avoid confusion as to which is the correct field to use. Finally, this patch makes ARCH=ppc64 also use the consolidated fpu.S code, which it previously did not. Built for G5 (ARCH=ppc64 and ARCH=powerpc), 32-bit powermac (ARCH=ppc and ARCH=powerpc) and Walnut (ARCH=ppc, CONFIG_MATH_EMULATION=y). Booted on G5 (ARCH=powerpc) and things which previously fell over no longer do. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 5 ++- arch/powerpc/kernel/fpu.S | 31 +++++++++++++++-- arch/powerpc/kernel/misc_32.S | 27 --------------- arch/powerpc/kernel/misc_64.S | 19 ----------- arch/powerpc/kernel/process.c | 2 +- arch/powerpc/kernel/signal_32.c | 2 +- arch/powerpc/kernel/traps.c | 2 +- arch/ppc/kernel/align.c | 4 +-- arch/ppc/kernel/misc.S | 27 --------------- arch/ppc/kernel/process.c | 2 +- arch/ppc/kernel/traps.c | 2 +- arch/ppc/math-emu/sfp-machine.h | 2 +- arch/ppc64/Kconfig | 3 ++ arch/ppc64/Makefile | 1 + arch/ppc64/kernel/align.c | 4 +-- arch/ppc64/kernel/head.S | 59 ++------------------------------- arch/ppc64/kernel/misc.S | 51 ---------------------------- arch/ppc64/kernel/signal.c | 2 +- include/asm-powerpc/processor.h | 11 +++--- include/asm-powerpc/system.h | 4 +-- include/asm-ppc/system.h | 4 +-- include/asm-ppc64/system.h | 4 +-- 22 files changed, 59 insertions(+), 209 deletions(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a733347964a0..94cf917b7854 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -29,7 +29,6 @@ extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_PPC64) += entry_64.o -extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ @@ -49,7 +48,7 @@ else # stuff used from here for ARCH=ppc or ARCH=ppc64 obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o -fpux-$(CONFIG_PPC32) += fpu.o -extra-$(CONFIG_PPC_FPU) += $(fpux-y) endif + +extra-$(CONFIG_PPC_FPU) += fpu.o diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 563d445ff584..51fd78da25b7 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -48,7 +48,7 @@ _GLOBAL(load_up_fpu) addi r4,r4,THREAD /* want last_task_used_math->thread */ SAVE_32FPRS(0, r4) mffs fr0 - stfd fr0,THREAD_FPSCR-4(r4) + stfd fr0,THREAD_FPSCR(r4) LDL r5,PT_REGS(r4) tophys(r5,r5) LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) @@ -71,7 +71,7 @@ _GLOBAL(load_up_fpu) or r12,r12,r4 std r12,_MSR(r1) #endif - lfd fr0,THREAD_FPSCR-4(r5) + lfd fr0,THREAD_FPSCR(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) #ifndef CONFIG_SMP @@ -104,7 +104,7 @@ _GLOBAL(giveup_fpu) CMPI 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 - stfd fr0,THREAD_FPSCR-4(r3) + stfd fr0,THREAD_FPSCR(r3) beq 1f LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r3,MSR_FP|MSR_FE0|MSR_FE1 @@ -117,3 +117,28 @@ _GLOBAL(giveup_fpu) STL r5,OFF(last_task_used_math)(r4) #endif /* CONFIG_SMP */ blr + +/* + * These are used in the alignment trap handler when emulating + * single-precision loads and stores. + * We restore and save the fpscr so the task gets the same result + * and exceptions as if the cpu had performed the load or store. + */ + +_GLOBAL(cvt_fd) + lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfs 0,0(r3) + stfd 0,0(r4) + mffs 0 + stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */ + blr + +_GLOBAL(cvt_df) + lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 + stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */ + blr diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 303229b090b8..3bedb532aed9 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -992,33 +992,6 @@ _GLOBAL(_get_SP) mr r3,r1 /* Close enough */ blr -/* - * These are used in the alignment trap handler when emulating - * single-precision loads and stores. - * We restore and save the fpscr so the task gets the same result - * and exceptions as if the cpu had performed the load or store. - */ - -#ifdef CONFIG_PPC_FPU -_GLOBAL(cvt_fd) - lfd 0,-4(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfs 0,0(r3) - stfd 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,-4(r5) - blr - -_GLOBAL(cvt_df) - lfd 0,-4(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfd 0,0(r3) - stfs 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,-4(r5) - blr -#endif - /* * Create a kernel thread * kernel_thread(fn, arg, flags) diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 4775bed42cac..b3e95ff0dba0 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -462,25 +462,6 @@ _GLOBAL(_outsl_ns) sync blr - -_GLOBAL(cvt_fd) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfs 0,0(r3) - stfd 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - -_GLOBAL(cvt_df) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfd 0,0(r3) - stfs 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - /* * identify_cpu and calls setup_cpu * In: r3 = base of the cpu_specs array diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 047da1ae21fe..8f85dabe4df3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -665,7 +665,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #endif #endif /* CONFIG_SMP */ memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); - current->thread.fpscr = 0; + current->thread.fpscr.val = 0; #ifdef CONFIG_ALTIVEC memset(current->thread.vr, 0, sizeof(current->thread.vr)); memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 92452b2db26a..444c3e81884c 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -403,7 +403,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, ELF_NFPREG * sizeof(double))) return 1; - current->thread.fpscr = 0; /* turn off all fp exceptions */ + current->thread.fpscr.val = 0; /* turn off all fp exceptions */ #ifdef CONFIG_ALTIVEC /* save altivec registers */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f87580382da4..5d638ecddbd0 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -549,7 +549,7 @@ static void parse_fpe(struct pt_regs *regs) flush_fp_to_thread(current); - fpscr = current->thread.fpscr; + fpscr = current->thread.fpscr.val; /* Invalid operation */ if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index ff81da9598d8..ab398c4b70b6 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -375,7 +375,7 @@ fix_alignment(struct pt_regs *regs) #ifdef CONFIG_PPC_FPU preempt_disable(); enable_kernel_fp(); - cvt_fd(&data.f, &data.d, ¤t->thread.fpscr); + cvt_fd(&data.f, &data.d, ¤t->thread); preempt_enable(); #else return 0; @@ -385,7 +385,7 @@ fix_alignment(struct pt_regs *regs) #ifdef CONFIG_PPC_FPU preempt_disable(); enable_kernel_fp(); - cvt_df(&data.d, &data.f, ¤t->thread.fpscr); + cvt_df(&data.d, &data.f, ¤t->thread); preempt_enable(); #else return 0; diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 2350f3e09f95..3056ede2424d 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -967,33 +967,6 @@ _GLOBAL(_get_SP) mr r3,r1 /* Close enough */ blr -/* - * These are used in the alignment trap handler when emulating - * single-precision loads and stores. - * We restore and save the fpscr so the task gets the same result - * and exceptions as if the cpu had performed the load or store. - */ - -#ifdef CONFIG_PPC_FPU -_GLOBAL(cvt_fd) - lfd 0,-4(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfs 0,0(r3) - stfd 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,-4(r5) - blr - -_GLOBAL(cvt_df) - lfd 0,-4(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfd 0,0(r3) - stfs 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,-4(r5) - blr -#endif - /* * Create a kernel thread * kernel_thread(fn, arg, flags) diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 6d60c40598e7..78ea10197a0b 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -542,7 +542,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) last_task_used_spe = NULL; #endif memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); - current->thread.fpscr = 0; + current->thread.fpscr.val = 0; #ifdef CONFIG_ALTIVEC memset(current->thread.vr, 0, sizeof(current->thread.vr)); memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 5e4bf88a1ef5..f265b81e7008 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -659,7 +659,7 @@ void program_check_exception(struct pt_regs *regs) giveup_fpu(current); preempt_enable(); - fpscr = current->thread.fpscr; + fpscr = current->thread.fpscr.val; fpscr &= fpscr << 22; /* mask summary bits with enables */ if (fpscr & FPSCR_VX) code = FPE_FLTINV; diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h index 686e06d29186..4b17d83cfcdd 100644 --- a/arch/ppc/math-emu/sfp-machine.h +++ b/arch/ppc/math-emu/sfp-machine.h @@ -166,7 +166,7 @@ extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long); #include #include -#define __FPU_FPSCR (current->thread.fpscr) +#define __FPU_FPSCR (current->thread.fpscr.val) /* We only actually write to the destination register * if exceptions signalled (if any) will not trap. diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 8cc73cc1b4c4..b889277ab7de 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -197,6 +197,9 @@ config BOOTX_TEXT config POWER4 def_bool y +config PPC_FPU + def_bool y + config POWER4_ONLY bool "Optimize for POWER4" default n diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 4d18bdb680f0..ba59225fd373 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -80,6 +80,7 @@ endif CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/ppc64/kernel/head.o +head-y += arch/powerpc/kernel/fpu.o libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c index 330e7ef81427..256d5b592aa1 100644 --- a/arch/ppc64/kernel/align.c +++ b/arch/ppc64/kernel/align.c @@ -313,7 +313,7 @@ fix_alignment(struct pt_regs *regs) /* Doing stfs, have to convert to single */ preempt_disable(); enable_kernel_fp(); - cvt_df(¤t->thread.fpr[reg], (float *)&data.v[4], ¤t->thread.fpscr); + cvt_df(¤t->thread.fpr[reg], (float *)&data.v[4], ¤t->thread); disable_kernel_fp(); preempt_enable(); } @@ -349,7 +349,7 @@ fix_alignment(struct pt_regs *regs) /* Doing lfs, have to convert to double */ preempt_disable(); enable_kernel_fp(); - cvt_fd((float *)&data.v[4], ¤t->thread.fpr[reg], ¤t->thread.fpscr); + cvt_fd((float *)&data.v[4], ¤t->thread.fpr[reg], ¤t->thread); disable_kernel_fp(); preempt_enable(); } diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index f58af9c246cb..929f9f42cf7a 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -81,7 +81,7 @@ _stext: _GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION - b .__start_initialization_multiplatform + b .__start_initialization_multiplatform END_FTR_SECTION(0, 1) #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -747,6 +747,7 @@ bad_stack: * any task or sent any task a signal, you should use * ret_from_except or ret_from_except_lite instead of this. */ + .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) ld r11,_NIP(r1) @@ -858,62 +859,6 @@ fp_unavailable_common: bl .kernel_fp_unavailable_exception BUG_OPCODE -/* - * load_up_fpu(unused, unused, tsk) - * Disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - * On SMP we know the fpu is free, since we give it up every - * switch (ie, no lazy save of the FP registers). - * On entry: r13 == 'current' && last_task_used_math != 'current' - */ -_STATIC(load_up_fpu) - mfmsr r5 /* grab the current MSR */ - ori r5,r5,MSR_FP - mtmsrd r5 /* enable use of fpu now */ - isync -/* - * For SMP, we don't do lazy FPU switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_fpu in switch_to. - * - */ -#ifndef CONFIG_SMP - ld r3,last_task_used_math@got(r2) - ld r4,0(r3) - cmpdi 0,r4,0 - beq 1f - /* Save FP state to last_task_used_math's THREAD struct */ - addi r4,r4,THREAD - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,THREAD_FPSCR(r4) - /* Disable FP for last_task_used_math */ - ld r5,PT_REGS(r4) - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r6,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r6 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of FP after return */ - ld r4,PACACURRENT(r13) - addi r5,r4,THREAD /* Get THREAD */ - ld r4,THREAD_FPEXC_MODE(r5) - ori r12,r12,MSR_FP - or r12,r12,r4 - std r12,_MSR(r1) - lfd fr0,THREAD_FPSCR(r5) - mtfsf 0xff,fr0 - REST_32FPRS(0, r5) -#ifndef CONFIG_SMP - /* Update last_task_used_math to 'current' */ - subi r4,r5,THREAD /* Back to 'current' */ - std r4,0(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - b fast_exception_return - .align 7 .globl altivec_unavailable_common altivec_unavailable_common: diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index a33448c2bd91..9cae3d5c40e6 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -451,25 +451,6 @@ _GLOBAL(_outsl_ns) sync blr - -_GLOBAL(cvt_fd) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfs 0,0(r3) - stfd 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - -_GLOBAL(cvt_df) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfd 0,0(r3) - stfs 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - /* * identify_cpu and calls setup_cpu * In: r3 = base of the cpu_specs array @@ -655,38 +636,6 @@ _GLOBAL(disable_kernel_fp) isync blr -/* - * giveup_fpu(tsk) - * Disable FP for the task given as the argument, - * and save the floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - */ -_GLOBAL(giveup_fpu) - mfmsr r5 - ori r5,r5,MSR_FP - mtmsrd r5 /* enable use of fpu now */ - isync - cmpdi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - ld r5,PT_REGS(r3) - cmpdi 0,r5,0 - SAVE_32FPRS(0, r3) - mffs fr0 - stfd fr0,THREAD_FPSCR(r3) - beq 1f - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r3,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r3 /* disable FP for previous task */ - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - ld r4,last_task_used_math@got(r2) - std r5,0(r4) -#endif /* CONFIG_SMP */ - blr - #ifdef CONFIG_ALTIVEC #if 0 /* this has no callers for now */ diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 347112cca3c0..ec9d0984b6a0 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -133,7 +133,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, flush_fp_to_thread(current); /* Make sure signal doesn't get spurrious FP exceptions */ - current->thread.fpscr = 0; + current->thread.fpscr.val = 0; #ifdef CONFIG_ALTIVEC err |= __put_user(v_regs, &sc->v_regs); diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index 9592f533e058..eee954a001fd 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -162,10 +162,11 @@ struct thread_struct { unsigned long dbcr1; #endif double fpr[32]; /* Complete floating point set */ -#ifdef CONFIG_PPC32 - unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ -#endif - unsigned long fpscr; /* Floating point status */ + struct { /* fpr ... fpscr must be contiguous */ + + unsigned int pad; + unsigned int val; /* Floating point status */ + } fpscr; int fpexc_mode; /* floating-point exception mode */ #ifdef CONFIG_PPC64 unsigned long start_tb; /* Start purr when proc switched in */ @@ -207,7 +208,7 @@ struct thread_struct { .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ .fs = KERNEL_DS, \ .fpr = {0}, \ - .fpscr = 0, \ + .fpscr = { .val = 0, }, \ .fpexc_mode = MSR_FE0|MSR_FE1, \ } #endif diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index d60c8c928922..e926e43c4ae6 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -132,8 +132,8 @@ extern int emulate_altivec(struct pt_regs *); extern void giveup_spe(struct task_struct *); extern void load_up_spe(struct task_struct *); extern int fix_alignment(struct pt_regs *); -extern void cvt_fd(float *from, double *to, unsigned long *fpscr); -extern void cvt_df(double *from, float *to, unsigned long *fpscr); +extern void cvt_fd(float *from, double *to, struct thread_struct *thread); +extern void cvt_df(double *from, float *to, struct thread_struct *thread); #ifdef CONFIG_ALTIVEC extern void flush_altivec_to_thread(struct task_struct *); diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 1f310783757e..eb30c09516ae 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -82,8 +82,8 @@ extern int emulate_altivec(struct pt_regs *); extern void giveup_spe(struct task_struct *); extern void load_up_spe(struct task_struct *); extern int fix_alignment(struct pt_regs *); -extern void cvt_fd(float *from, double *to, unsigned long *fpscr); -extern void cvt_df(double *from, float *to, unsigned long *fpscr); +extern void cvt_fd(float *from, double *to, struct thread_struct *thread); +extern void cvt_df(double *from, float *to, struct thread_struct *thread); #ifdef CONFIG_ALTIVEC extern void flush_altivec_to_thread(struct task_struct *); diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 2e17ef7dbeb4..fd7c1f890c45 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -120,8 +120,8 @@ extern void giveup_altivec(struct task_struct *); extern void disable_kernel_altivec(void); extern void enable_kernel_altivec(void); extern int emulate_altivec(struct pt_regs *); -extern void cvt_fd(float *from, double *to, unsigned long *fpscr); -extern void cvt_df(double *from, float *to, unsigned long *fpscr); +extern void cvt_fd(float *from, double *to, struct thread_struct *thread); +extern void cvt_df(double *from, float *to, struct thread_struct *thread); #ifdef CONFIG_ALTIVEC extern void flush_altivec_to_thread(struct task_struct *); From e37bc5df8e96c72f27ec3579499726b656e4e641 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 24 Oct 2005 11:41:33 +1000 Subject: [PATCH 0756/1939] [PATCH] powerpc: Purge bootinfo.h With ARCH=powerpc we assume the presence of a device tree, so we don't require any support for the old bi_recs method of passing boot parameters. Likewise, we've never needed it for ppc64, but we still had an include/asm-ppc64/bootinfo.h from which nothing was used. This patch removes that file, and all references to it in arch/ppc64 and arch/powerpc. A related, unused variable 'boot_mem_size' is also removed from setup_32.c. The bootinfo stuff remains in ARCH=ppc for the time being. Built and booted on Power5 (ARCH=ppc64 and ARCH=powerpc), built for 32-bit powermac (ARCH=powerpc and ARCH=ppc). Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 1 - arch/powerpc/kernel/setup_32.c | 5 ----- arch/powerpc/kernel/setup_64.c | 1 - arch/powerpc/mm/init_32.c | 1 - arch/powerpc/mm/mem.c | 1 - arch/ppc64/kernel/prom.c | 1 - arch/ppc64/kernel/prom_init.c | 1 - 7 files changed, 11 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 2ad9947bd675..9750b3cd8ecd 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 0cac112ca89d..21ef643a0208 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -60,10 +59,6 @@ struct ide_machdep_calls ppc_ide_md; int __irq_offset_value; EXPORT_SYMBOL(__irq_offset_value); -/* Used with the BI_MEMSIZE bootinfo parameter to store the memory - size value reported by the boot loader. */ -unsigned long boot_mem_size; - unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 721adeea601d..a8f7ff5ab1a4 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 8dd1f7d0e23c..4612a79dfb6e 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 5e9206715f09..695db6a588ce 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index a0866f12647f..cd41a47dd43f 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index f252670874a4..69924ba4d7d9 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include From 2765ca254060adb9a5abc2cfc6264b8daafc5742 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 24 Oct 2005 13:07:23 +1000 Subject: [PATCH 0757/1939] [PATCH] powerpc: Merge parport.h Save for the header #define, ppc32 and ppc64 versions of parport.h are identical. This patch merges them. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- include/{asm-ppc => asm-powerpc}/parport.h | 6 +++--- include/asm-ppc64/parport.h | 18 ------------------ 2 files changed, 3 insertions(+), 21 deletions(-) rename include/{asm-ppc => asm-powerpc}/parport.h (80%) delete mode 100644 include/asm-ppc64/parport.h diff --git a/include/asm-ppc/parport.h b/include/asm-powerpc/parport.h similarity index 80% rename from include/asm-ppc/parport.h rename to include/asm-powerpc/parport.h index 11f96d3de5b6..d86b410a6f8b 100644 --- a/include/asm-ppc/parport.h +++ b/include/asm-powerpc/parport.h @@ -6,8 +6,8 @@ * This file should only be included by drivers/parport/parport_pc.c. */ -#ifndef _ASM_PPC_PARPORT_H -#define _ASM_PPC_PARPORT_H +#ifndef _ASM_POWERPC_PARPORT_H +#define _ASM_POWERPC_PARPORT_H static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma); static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) @@ -15,4 +15,4 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) return parport_pc_find_isa_ports (autoirq, autodma); } -#endif /* !(_ASM_PPC_PARPORT_H) */ +#endif /* !(_ASM_POWERPC_PARPORT_H) */ diff --git a/include/asm-ppc64/parport.h b/include/asm-ppc64/parport.h deleted file mode 100644 index 2f8874c581cc..000000000000 --- a/include/asm-ppc64/parport.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * parport.h: platform-specific PC-style parport initialisation - * - * Copyright (C) 1999, 2000 Tim Waugh - * - * This file should only be included by drivers/parport/parport_pc.c. - */ - -#ifndef _ASM_PPC64_PARPORT_H -#define _ASM_PPC64_PARPORT_H - -static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma); -static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) -{ - return parport_pc_find_isa_ports (autoirq, autodma); -} - -#endif /* !(_ASM_PPC_PARPORT_H) */ From 328985b2c69d2592edd7f181a6b7360e51b08515 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 24 Oct 2005 14:05:38 +1000 Subject: [PATCH 0758/1939] [PATCH] powerpc: Don't use kmalloc() for kernel stacks In readiness for 64k pages, when THREAD_SIZE will be less than PAGE_SIZE, ppc64 uses kmalloc() rather than __get_free_pages() to allocate kernel stacks, and since thread_info.h was merged, so does ppc32. However that adds some overhead which we don't really want when PAGE_SIZE <= THREAD_SIZE (including all ppc32 machines), so this patch avoids it. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- include/asm-powerpc/thread_info.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index 0b4c24551c21..ab17db79f69d 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h @@ -66,19 +66,26 @@ struct thread_info { /* thread information allocation */ #ifdef CONFIG_DEBUG_STACK_USAGE -#define alloc_thread_info(tsk) \ - ({ \ - struct thread_info *ret; \ - \ - ret = kmalloc(THREAD_SIZE, GFP_KERNEL); \ - if (ret) \ - memset(ret, 0, THREAD_SIZE); \ - ret; \ - }) +#define THREAD_INFO_GFP GFP_KERNEL | __GFP_ZERO #else -#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL) +#define THREAD_INFO_GFP GFP_KERNEL #endif + +#if THREAD_SHIFT >= PAGE_SHIFT + +#define THREAD_ORDER (THREAD_SHIFT - PAGE_SHIFT) + +#define alloc_thread_info(tsk) \ + ((struct thread_info *)__get_free_pages(THREAD_INFO_GFP, THREAD_ORDER)) +#define free_thread_info(ti) free_pages((unsigned long)ti, THREAD_ORDER) + +#else /* THREAD_SHIFT < PAGE_SHIFT */ + +#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, THREAD_INFO_GFP) #define free_thread_info(ti) kfree(ti) + +#endif /* THREAD_SHIFT < PAGE_SHIFT */ + #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) From cffb09ce6ba7706c89c6df9ca8e72c81adda13f0 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 26 Oct 2005 09:55:41 -0500 Subject: [PATCH 0759/1939] [PATCH] powerpc: Fix warning related to do_dabr do_dabr() is not relevant on 40x or Book-E processors so dont build it Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/mm/fault.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 3df641fa789d..841d8b6323a8 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -80,6 +80,7 @@ static int store_updates_sp(struct pt_regs *regs) return 0; } +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) static void do_dabr(struct pt_regs *regs, unsigned long error_code) { siginfo_t info; @@ -101,6 +102,7 @@ static void do_dabr(struct pt_regs *regs, unsigned long error_code) info.si_addr = (void __user *)regs->nip; force_sig_info(SIGTRAP, &info, current); } +#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ /* * For 600- and 800-family processors, the error_code parameter is DSISR From 4b24b01c6c0bab24e6a4c3e4a02d53b564f2d05c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 26 Oct 2005 09:56:10 -0500 Subject: [PATCH 0760/1939] [PATCH] powerpc: Moved dcr support to arch/powerpc Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/Makefile | 2 ++ arch/{ppc/syslib => powerpc/sysdev}/dcr.S | 0 arch/ppc/syslib/Makefile | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/{ppc/syslib => powerpc/sysdev}/dcr.S (100%) diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 97119c0ffc72..d071ae875e25 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_MPIC) += mpic.o obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_MPC106) += grackle.o +obj-$(CONFIG_BOOKE) += dcr.o +obj-$(CONFIG_40x) += dcr.o diff --git a/arch/ppc/syslib/dcr.S b/arch/powerpc/sysdev/dcr.S similarity index 100% rename from arch/ppc/syslib/dcr.S rename to arch/powerpc/sysdev/dcr.S diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index e6e6aa4d291e..b4ef15b45c4a 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -86,8 +86,6 @@ endif obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o ppc_sys.o obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o -obj-$(CONFIG_40x) += dcr.o -obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \ ppc_sys.o mpc85xx_sys.o \ mpc85xx_devices.o From eef69e3cfb38d83166dbd8bcb12ededa1b6e78b6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 22:21:37 +1000 Subject: [PATCH 0761/1939] powerpc: remove duplicate screen_info from setup_32.c Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 21ef643a0208..150a919269ae 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -94,21 +94,6 @@ int dcache_bsize; int icache_bsize; int ucache_bsize; -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \ - defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA) -struct screen_info screen_info = { - 0, 25, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ -}; -#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */ - /* * We're called here very early in the boot. We determine the machine * type and call the appropriate low-level setup functions. From 80579e1f4a6b5f5dec92faa6c3e0645961c99091 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 22:42:04 +1000 Subject: [PATCH 0762/1939] powerpc: 32-bit CHRP SMP fixes Untested, but "should" work... at least this way it compiles. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 12 +++++----- arch/powerpc/kernel/setup_32.c | 4 ++++ arch/powerpc/platforms/chrp/smp.c | 40 ++++++++++++++++++++++++++----- include/asm-ppc/smp.h | 10 +++++++- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index ab9b291dda54..6309a1a17c4a 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1110,22 +1110,22 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } #endif -#ifdef CONFIG_PPC64 + boot_cpuid = 0; + boot_cpuid_phys = 0; if (initial_boot_params && initial_boot_params->version >= 2) { /* version 2 of the kexec param format adds the phys cpuid * of booted proc. */ boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; - boot_cpuid = 0; } else { - /* Check if it's the boot-cpu, set it's hw index in paca now */ + /* Check if it's the boot-cpu, set it's hw index now */ if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { prop = get_flat_dt_prop(node, "reg", NULL); - set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); - boot_cpuid_phys = get_hard_smp_processor_id(0); + if (prop != NULL) + boot_cpuid_phys = *prop; } } -#endif + set_hard_smp_processor_id(0, boot_cpuid_phys); #ifdef CONFIG_ALTIVEC /* Check if we have a VMX and eventually update CPU features */ diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 150a919269ae..7c99e6b8c76c 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -59,6 +59,10 @@ struct ide_machdep_calls ppc_ide_md; int __irq_offset_value; EXPORT_SYMBOL(__irq_offset_value); +int boot_cpuid; +EXPORT_SYMBOL_GPL(boot_cpuid); +int boot_cpuid_phys; + unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index bf68282670dd..31ee49c25014 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -32,15 +32,44 @@ #include #include #include +#include +#include extern unsigned long smp_chrp_cpu_nr; static int __init smp_chrp_probe(void) { - if (smp_chrp_cpu_nr > 1) - openpic_request_IPIs(); + struct device_node *cpus = NULL; + unsigned int *reg; + int reglen; + int ncpus = 0; + int cpuid; + unsigned int phys; - return smp_chrp_cpu_nr; + /* Count CPUs in the device-tree */ + cpuid = 1; /* the boot cpu is logical cpu 0 */ + while ((cpus = of_find_node_by_type(cpus, "cpu")) != NULL) { + phys = ncpus; + reg = (unsigned int *) get_property(cpus, "reg", ®len); + if (reg && reglen >= sizeof(unsigned int)) + /* hmmm, not having a reg property would be bad */ + phys = *reg; + if (phys != boot_cpuid_phys) { + set_hard_smp_processor_id(cpuid, phys); + ++cpuid; + } + ++ncpus; + } + + printk(KERN_INFO "CHRP SMP probe found %d cpus\n", ncpus); + + /* Nothing more to do if less than 2 of them */ + if (ncpus <= 1) + return 1; + + mpic_request_ipis(); + + return ncpus; } static void __devinit smp_chrp_kick_cpu(int nr) @@ -51,8 +80,7 @@ static void __devinit smp_chrp_kick_cpu(int nr) static void __devinit smp_chrp_setup_cpu(int cpu_nr) { - if (OpenPIC_Addr) - do_openpic_setup_cpu(); + mpic_setup_this_cpu(); } static DEFINE_SPINLOCK(timebase_lock); @@ -85,7 +113,7 @@ void __devinit smp_chrp_take_timebase(void) /* CHRP with openpic */ struct smp_ops_t chrp_smp_ops = { - .message_pass = smp_openpic_message_pass, + .message_pass = smp_mpic_message_pass, .probe = smp_chrp_probe, .kick_cpu = smp_chrp_kick_cpu, .setup_cpu = smp_chrp_setup_cpu, diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index 063d7dedc691..30e9268a888c 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -53,16 +53,24 @@ extern int __cpu_up(unsigned int cpu); extern int smp_hw_index[]; #define hard_smp_processor_id() (smp_hw_index[smp_processor_id()]) #define get_hard_smp_processor_id(cpu) (smp_hw_index[(cpu)]) - +#define set_hard_smp_processor_id(cpu, phys)\ + (smp_hw_index[(cpu)] = (phys)) + #endif /* __ASSEMBLY__ */ #else /* !(CONFIG_SMP) */ static inline void cpu_die(void) { } #define get_hard_smp_processor_id(cpu) 0 +#define set_hard_smp_processor_id(cpu, phys) #define hard_smp_processor_id() 0 #endif /* !(CONFIG_SMP) */ +#ifndef __ASSEMBLY__ +extern int boot_cpuid; +extern int boot_cpuid_phys; +#endif + #endif /* !(_PPC_SMP_H) */ #endif /* __KERNEL__ */ From 6316222ea050d469c3155881d9dee2c7671d9fef Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 22:44:39 +1000 Subject: [PATCH 0763/1939] powerpc: Introduce toreal/fromreal assembly macros On 32-bit platforms, these convert from kernel virtual addresses to real (physical addresses), like tophys/tovirt but they use the same register for the source and destination. On 64-bit platforms, they do nothing because the hardware ignores the top two bits of the address in real mode. These new macros are used in fpu.S now. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/fpu.S | 8 ++++---- include/asm-powerpc/ppc_asm.h | 29 +++++++++++++++-------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 51fd78da25b7..4d6001fa1cf2 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -40,17 +40,17 @@ _GLOBAL(load_up_fpu) */ #ifndef CONFIG_SMP LOADBASE(r3, last_task_used_math) - tophys(r3,r3) + toreal(r3) LDL r4,OFF(last_task_used_math)(r3) CMPI 0,r4,0 beq 1f - tophys(r4,r4) + toreal(r4) addi r4,r4,THREAD /* want last_task_used_math->thread */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,THREAD_FPSCR(r4) LDL r5,PT_REGS(r4) - tophys(r5,r5) + toreal(r5) LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r10,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r10 /* disable FP for previous task */ @@ -76,7 +76,7 @@ _GLOBAL(load_up_fpu) REST_32FPRS(0, r5) #ifndef CONFIG_SMP subi r4,r5,THREAD - tovirt(r4,r4) + fromreal(r4) STL r4,OFF(last_task_used_math)(r3) #endif /* CONFIG_SMP */ /* restore registers and return */ diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index f8ad5df6ebef..470d7400ac59 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -154,7 +154,7 @@ GLUE(.,name): * loads the address of 'name' into 'rn' * * LOADBASE( rn, name ) - * loads the address (less the low 16 bits) of 'name' into 'rn' + * loads the address (possibly without the low 16 bits) of 'name' into 'rn' * suitable for base+disp addressing */ #ifdef __powerpc64__ @@ -166,10 +166,7 @@ GLUE(.,name): ori rn,rn,name##@l #define LOADBASE(rn,name) \ - .section .toc,"aw"; \ -1: .tc name[TC],name; \ - .previous; \ - ld rn,1b@toc(r2) + ld rn,name@got(r2) #define OFF(name) 0 @@ -278,6 +275,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #if defined(CONFIG_BOOKE) +#define toreal(rd) +#define fromreal(rd) + #define tophys(rd,rs) \ addis rd,rs,0 @@ -285,23 +285,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) addis rd,rs,0 #elif defined(CONFIG_PPC64) -/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., - * Then we can easily do this with one asm insn. -Peter - */ +#define toreal(rd) /* we can access c000... in real mode */ +#define fromreal(rd) + #define tophys(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - sub rd,rs,rd + clrldi rd,rs,2 #define tovirt(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - add rd,rs,rd + rotldi rd,rs,16; \ + ori rd,rd,((KERNELBASE>>48)&0xFFFF);\ + rotldi rd,rd,48 #else /* * On APUS (Amiga PowerPC cpu upgrade board), we don't know the * physical base address of RAM at compile time. */ +#define toreal(rd) tophys(rd,rd) +#define fromreal(rd) tovirt(rd,rd) + #define tophys(rd,rs) \ 0: addis rd,rs,-KERNELBASE@h; \ .section ".vtop_fixup","aw"; \ From bfab1019b7e8b499dfc471a0dfc98b587420dda9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 27 Oct 2005 22:45:33 +1000 Subject: [PATCH 0764/1939] powerpc: Fix new-world powermac detection My G5 was being reported as an OldWorld in /proc/cpuinfo, which is obviously not right... :) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/setup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 72cd503d3d33..6f62af597291 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -317,7 +317,9 @@ void __init pmac_setup_arch(void) } /* See if newworld or oldworld */ - ic = of_find_node_by_name(NULL, "interrupt-controller"); + for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; ) + if (get_property(ic, "interrupt-controller", NULL)) + break; pmac_newworld = (ic != NULL); if (ic) of_node_put(ic); From a362f463a6d316d14daed0f817e151835ce97ff7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 27 Oct 2005 09:07:33 -0700 Subject: [PATCH 0765/1939] Revert "remove false BUG_ON() from run_posix_cpu_timers()" This reverts commit 3de463c7d9d58f8cf3395268230cb20a4c15bffa. Roland has another patch that allows us to leave the BUG_ON() in place by just making sure that the condition it tests for really is always true. That goes in next. Signed-off-by: Linus Torvalds --- kernel/exit.c | 8 ++++++++ kernel/posix-cpu-timers.c | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 4897977a1f4b..3b25b182d2be 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -825,6 +825,14 @@ fastcall NORET_TYPE void do_exit(long code) tsk->flags |= PF_EXITING; + /* + * Make sure we don't try to process any timer firings + * while we are already exiting. + */ + tsk->it_virt_expires = cputime_zero; + tsk->it_prof_expires = cputime_zero; + tsk->it_sched_expires = 0; + if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 383ba22f0b62..ea1aca5e7c2b 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1293,30 +1293,30 @@ void run_posix_cpu_timers(struct task_struct *tsk) #undef UNEXPIRED + BUG_ON(tsk->exit_state); + /* * Double-check with locks held. */ read_lock(&tasklist_lock); - if (likely(tsk->signal != NULL)) { - spin_lock(&tsk->sighand->siglock); + spin_lock(&tsk->sighand->siglock); - /* - * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] - * all the timers that are firing, and put them on the firing list. - */ - check_thread_timers(tsk, &firing); - check_process_timers(tsk, &firing); + /* + * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] + * all the timers that are firing, and put them on the firing list. + */ + check_thread_timers(tsk, &firing); + check_process_timers(tsk, &firing); - /* - * We must release these locks before taking any timer's lock. - * There is a potential race with timer deletion here, as the - * siglock now protects our private firing list. We have set - * the firing flag in each timer, so that a deletion attempt - * that gets the timer lock before we do will give it up and - * spin until we've taken care of that timer below. - */ - spin_unlock(&tsk->sighand->siglock); - } + /* + * We must release these locks before taking any timer's lock. + * There is a potential race with timer deletion here, as the + * siglock now protects our private firing list. We have set + * the firing flag in each timer, so that a deletion attempt + * that gets the timer lock before we do will give it up and + * spin until we've taken care of that timer below. + */ + spin_unlock(&tsk->sighand->siglock); read_unlock(&tasklist_lock); /* From 72ab373a5688a78cbdaf3bf96012e597d5399bb7 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 27 Oct 2005 03:16:42 -0700 Subject: [PATCH 0766/1939] [PATCH] Yet more posix-cpu-timer fixes This just makes sure that a thread's expiry times can't get reset after it clears them in do_exit. This is what allowed us to re-introduce the stricter BUG_ON() check in a362f463a6d316d14daed0f817e151835ce97ff7. Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index ea1aca5e7c2b..bf374fceb39c 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -497,7 +497,7 @@ static void process_timer_rebalance(struct task_struct *p, left = cputime_div(cputime_sub(expires.cpu, val.cpu), nthreads); do { - if (!unlikely(t->exit_state)) { + if (!unlikely(t->flags & PF_EXITING)) { ticks = cputime_add(prof_ticks(t), left); if (cputime_eq(t->it_prof_expires, cputime_zero) || @@ -512,7 +512,7 @@ static void process_timer_rebalance(struct task_struct *p, left = cputime_div(cputime_sub(expires.cpu, val.cpu), nthreads); do { - if (!unlikely(t->exit_state)) { + if (!unlikely(t->flags & PF_EXITING)) { ticks = cputime_add(virt_ticks(t), left); if (cputime_eq(t->it_virt_expires, cputime_zero) || @@ -527,7 +527,7 @@ static void process_timer_rebalance(struct task_struct *p, nsleft = expires.sched - val.sched; do_div(nsleft, nthreads); do { - if (!unlikely(t->exit_state)) { + if (!unlikely(t->flags & PF_EXITING)) { ns = t->sched_time + nsleft; if (t->it_sched_expires == 0 || t->it_sched_expires > ns) { @@ -566,6 +566,9 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now) struct cpu_timer_list *next; unsigned long i; + if (CPUCLOCK_PERTHREAD(timer->it_clock) && (p->flags & PF_EXITING)) + return; + head = (CPUCLOCK_PERTHREAD(timer->it_clock) ? p->cpu_timers : p->signal->cpu_timers); head += CPUCLOCK_WHICH(timer->it_clock); @@ -1204,7 +1207,7 @@ static void check_process_timers(struct task_struct *tsk, do { t = next_thread(t); - } while (unlikely(t->exit_state)); + } while (unlikely(t->flags & PF_EXITING)); } while (t != tsk); } } From 2ad41065d9fe518759b695fc2640cf9c07261dd2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 27 Oct 2005 18:47:46 +1000 Subject: [PATCH 0767/1939] [TCP]: Clear stale pred_flags when snd_wnd changes This bug is responsible for causing the infamous "Treason uncloaked" messages that's been popping up everywhere since the printk was added. It has usually been blamed on foreign operating systems. However, some of those reports implicate Linux as both systems are running Linux or the TCP connection is going across the loopback interface. In fact, there really is a bug in the Linux TCP header prediction code that's been there since at least 2.1.8. This bug was tracked down with help from Dale Blount. The effect of this bug ranges from harmless "Treason uncloaked" messages to hung/aborted TCP connections. The details of the bug and fix is as follows. When snd_wnd is updated, we only update pred_flags if tcp_fast_path_check succeeds. When it fails (for example, when our rcvbuf is used up), we will leave pred_flags with an out-of-date snd_wnd value. When the out-of-date pred_flags happens to match the next incoming packet we will again hit the fast path and use the current snd_wnd which will be wrong. In the case of the treason messages, it just happens that the snd_wnd cached in pred_flags is zero while tp->snd_wnd is non-zero. Therefore when a zero-window packet comes in we incorrectly conclude that the window is non-zero. In fact if the peer continues to send us zero-window pure ACKs we will continue making the same mistake. It's only when the peer transmits a zero-window packet with data attached that we get a chance to snap out of it. This is what triggers the treason message at the next retransmit timeout. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 677419d0c9ad..3e98b57578dc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2239,6 +2239,7 @@ static int tcp_ack_update_window(struct sock *sk, struct tcp_sock *tp, /* Note, it is the only place, where * fast path is recovered for sending TCP. */ + tp->pred_flags = 0; tcp_fast_path_check(sk, tp); if (nwin > tp->max_window) { From 3d155f8cd0d077938d271225d26ee52f8eb26082 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 27 Oct 2005 11:03:38 -0700 Subject: [PATCH 0768/1939] [IB] mthca: first pass at catastrophic error reporting Add some initial support for detecting and reporting catastrophic errors reported by Mellanox HCAs. We start a periodic timer which polls the catastrophic error reporting buffer in device memory. If an error is detected, we dump the contents of the buffer for port-mortem debugging, and report a fatal asynchronous error to higher levels. In the future we can try to recover from these errors by resetting the device, but this will require some work in higher-level code as well. Let's get this in now, so that we at least get catastrophic errors reported in logs. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/Makefile | 3 +- drivers/infiniband/hw/mthca/mthca_catas.c | 153 +++++++++++++++++++ drivers/infiniband/hw/mthca/mthca_cmd.c | 5 + drivers/infiniband/hw/mthca/mthca_dev.h | 13 ++ drivers/infiniband/hw/mthca/mthca_provider.c | 3 + 5 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/mthca/mthca_catas.c diff --git a/drivers/infiniband/hw/mthca/Makefile b/drivers/infiniband/hw/mthca/Makefile index c44f7bae5424..47ec5a7cba0b 100644 --- a/drivers/infiniband/hw/mthca/Makefile +++ b/drivers/infiniband/hw/mthca/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mthca.o ib_mthca-y := mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \ mthca_allocator.o mthca_eq.o mthca_pd.o mthca_cq.o \ mthca_mr.o mthca_qp.o mthca_av.o mthca_mcg.o mthca_mad.o \ - mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o + mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o \ + mthca_catas.o diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c new file mode 100644 index 000000000000..7ac52af43b99 --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" + +enum { + MTHCA_CATAS_POLL_INTERVAL = 5 * HZ, + + MTHCA_CATAS_TYPE_INTERNAL = 0, + MTHCA_CATAS_TYPE_UPLINK = 3, + MTHCA_CATAS_TYPE_DDR = 4, + MTHCA_CATAS_TYPE_PARITY = 5, +}; + +static DEFINE_SPINLOCK(catas_lock); + +static void handle_catas(struct mthca_dev *dev) +{ + struct ib_event event; + const char *type; + int i; + + event.device = &dev->ib_dev; + event.event = IB_EVENT_DEVICE_FATAL; + event.element.port_num = 0; + + ib_dispatch_event(&event); + + switch (swab32(readl(dev->catas_err.map)) >> 24) { + case MTHCA_CATAS_TYPE_INTERNAL: + type = "internal error"; + break; + case MTHCA_CATAS_TYPE_UPLINK: + type = "uplink bus error"; + break; + case MTHCA_CATAS_TYPE_DDR: + type = "DDR data error"; + break; + case MTHCA_CATAS_TYPE_PARITY: + type = "internal parity error"; + break; + default: + type = "unknown error"; + break; + } + + mthca_err(dev, "Catastrophic error detected: %s\n", type); + for (i = 0; i < dev->catas_err.size; ++i) + mthca_err(dev, " buf[%02x]: %08x\n", + i, swab32(readl(dev->catas_err.map + i))); +} + +static void poll_catas(unsigned long dev_ptr) +{ + struct mthca_dev *dev = (struct mthca_dev *) dev_ptr; + unsigned long flags; + int i; + + for (i = 0; i < dev->catas_err.size; ++i) + if (readl(dev->catas_err.map + i)) { + handle_catas(dev); + return; + } + + spin_lock_irqsave(&catas_lock, flags); + if (dev->catas_err.stop) + mod_timer(&dev->catas_err.timer, + jiffies + MTHCA_CATAS_POLL_INTERVAL); + spin_unlock_irqrestore(&catas_lock, flags); + + return; +} + +void mthca_start_catas_poll(struct mthca_dev *dev) +{ + unsigned long addr; + + init_timer(&dev->catas_err.timer); + dev->catas_err.stop = 0; + dev->catas_err.map = NULL; + + addr = pci_resource_start(dev->pdev, 0) + + ((pci_resource_len(dev->pdev, 0) - 1) & + dev->catas_err.addr); + + if (!request_mem_region(addr, dev->catas_err.size * 4, + DRV_NAME)) { + mthca_warn(dev, "couldn't request catastrophic error region " + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + return; + } + + dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); + if (!dev->catas_err.map) { + mthca_warn(dev, "couldn't map catastrophic error region " + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + release_mem_region(addr, dev->catas_err.size * 4); + return; + } + + dev->catas_err.timer.data = (unsigned long) dev; + dev->catas_err.timer.function = poll_catas; + dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; + add_timer(&dev->catas_err.timer); +} + +void mthca_stop_catas_poll(struct mthca_dev *dev) +{ + spin_lock_irq(&catas_lock); + dev->catas_err.stop = 1; + spin_unlock_irq(&catas_lock); + + del_timer_sync(&dev->catas_err.timer); + + if (dev->catas_err.map) { + iounmap(dev->catas_err.map); + release_mem_region(pci_resource_start(dev->pdev, 0) + + ((pci_resource_len(dev->pdev, 0) - 1) & + dev->catas_err.addr), + dev->catas_err.size * 4); + } +} diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 1bd7dc8f778c..9220473dbfbd 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -706,9 +707,13 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); dev->cmd.max_cmds = 1 << lg; + MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET); + MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET); mthca_dbg(dev, "FW version %012llx, max commands %d\n", (unsigned long long) dev->fw_ver, dev->cmd.max_cmds); + mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n", + (unsigned long long) dev->catas_err.addr, dev->catas_err.size); if (mthca_is_memfree(dev)) { MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index f106bac0f925..7e68bd4a3780 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -258,6 +258,14 @@ struct mthca_mcg_table { struct mthca_icm_table *table; }; +struct mthca_catas_err { + u64 addr; + u32 __iomem *map; + unsigned long stop; + u32 size; + struct timer_list timer; +}; + struct mthca_dev { struct ib_device ib_dev; struct pci_dev *pdev; @@ -318,6 +326,8 @@ struct mthca_dev { struct mthca_av_table av_table; struct mthca_mcg_table mcg_table; + struct mthca_catas_err catas_err; + struct mthca_uar driver_uar; struct mthca_db_table *db_tab; struct mthca_pd driver_pd; @@ -405,6 +415,9 @@ void mthca_cleanup_mcg_table(struct mthca_dev *dev); int mthca_register_device(struct mthca_dev *dev); void mthca_unregister_device(struct mthca_dev *dev); +void mthca_start_catas_poll(struct mthca_dev *dev); +void mthca_stop_catas_poll(struct mthca_dev *dev); + int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 9e911a1ea415..1b9477edbd7b 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1175,10 +1175,13 @@ int mthca_register_device(struct mthca_dev *dev) } } + mthca_start_catas_poll(dev); + return 0; } void mthca_unregister_device(struct mthca_dev *dev) { + mthca_stop_catas_poll(dev); ib_unregister_device(&dev->ib_dev); } From c1902aae322952f8726469a6657df7b9d5c794fe Mon Sep 17 00:00:00 2001 From: Dean Roe Date: Thu, 27 Oct 2005 15:41:04 -0500 Subject: [PATCH 0769/1939] [IA64] - Avoid slow TLB purges on SGI Altix systems flush_tlb_all() can be a scaling issue on large SGI Altix systems since it uses the global call_lock and always executes on all cpus. When a process enters flush_tlb_range() to purge TLBs for another process, it is possible to avoid flush_tlb_all() and instead allow sn2_global_tlb_purge() to purge TLBs only where necessary. This patch modifies flush_tlb_range() so that this case can be handled by platform TLB purge functions and updates ia64_global_tlb_purge() accordingly. sn2_global_tlb_purge() now calculates the region register value from the mm argument introduced with this patch. Signed-off-by: Dean Roe Signed-off-by: Tony Luck --- arch/ia64/mm/tlb.c | 16 +++++++++------- arch/ia64/sn/kernel/sn2/sn2_smp.c | 31 +++++++++++++++++++------------ include/asm-ia64/machvec.h | 2 +- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 464557e4ed82..99ea8c70f408 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -86,10 +86,15 @@ wrap_mmu_context (struct mm_struct *mm) } void -ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long nbits) { static DEFINE_SPINLOCK(ptcg_lock); + if (mm != current->active_mm) { + flush_tlb_all(); + return; + } + /* HW requires global serialization of ptc.ga. */ spin_lock(&ptcg_lock); { @@ -135,15 +140,12 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long unsigned long size = end - start; unsigned long nbits; +#ifndef CONFIG_SMP if (mm != current->active_mm) { - /* this does happen, but perhaps it's not worth optimizing for? */ -#ifdef CONFIG_SMP - flush_tlb_all(); -#else mm->context = 0; -#endif return; } +#endif nbits = ia64_fls(size + 0xfff); while (unlikely (((1UL << nbits) & purge.mask) == 0) && (nbits < purge.max_bits)) @@ -153,7 +155,7 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long start &= ~((1UL << nbits) - 1); # ifdef CONFIG_SMP - platform_global_tlb_purge(start, end, nbits); + platform_global_tlb_purge(mm, start, end, nbits); # else do { ia64_ptcl(start, (nbits<<2)); diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 0a4ee50c302f..49b530c39a42 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -177,6 +177,7 @@ void sn_tlb_migrate_finish(struct mm_struct *mm) /** * sn2_global_tlb_purge - globally purge translation cache of virtual address range + * @mm: mm_struct containing virtual address range * @start: start of virtual address range * @end: end of virtual address range * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) @@ -188,21 +189,22 @@ void sn_tlb_migrate_finish(struct mm_struct *mm) * - cpu_vm_mask is a bit mask that indicates which cpus have loaded the context. * - cpu_vm_mask is converted into a nodemask of the nodes containing the * cpus in cpu_vm_mask. - * - if only one bit is set in cpu_vm_mask & it is the current cpu, - * then only the local TLB needs to be flushed. This flushing can be done - * using ptc.l. This is the common case & avoids the global spinlock. + * - if only one bit is set in cpu_vm_mask & it is the current cpu & the + * process is purging its own virtual address range, then only the + * local TLB needs to be flushed. This flushing can be done using + * ptc.l. This is the common case & avoids the global spinlock. * - if multiple cpus have loaded the context, then flushing has to be * done with ptc.g/MMRs under protection of the global ptc_lock. */ void -sn2_global_tlb_purge(unsigned long start, unsigned long end, - unsigned long nbits) +sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, + unsigned long end, unsigned long nbits) { int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; + int mymm = (mm == current->active_mm); volatile unsigned long *ptc0, *ptc1; - unsigned long itc, itc2, flags, data0 = 0, data1 = 0; - struct mm_struct *mm = current->active_mm; + unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value; short nasids[MAX_NUMNODES], nix; nodemask_t nodes_flushed; @@ -216,9 +218,12 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, i++; } + if (i == 0) + return; + preempt_disable(); - if (likely(i == 1 && lcpu == smp_processor_id())) { + if (likely(i == 1 && lcpu == smp_processor_id() && mymm)) { do { ia64_ptcl(start, nbits << 2); start += (1UL << nbits); @@ -229,7 +234,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, return; } - if (atomic_read(&mm->mm_users) == 1) { + if (atomic_read(&mm->mm_users) == 1 && mymm) { flush_tlb_mm(mm); __get_cpu_var(ptcstats).change_rid++; preempt_enable(); @@ -241,11 +246,13 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, for_each_node_mask(cnode, nodes_flushed) nasids[nix++] = cnodeid_to_nasid(cnode); + rr_value = (mm->context << 3) | REGION_NUMBER(start); + shub1 = is_shub1(); if (shub1) { data0 = (1UL << SH1_PTC_0_A_SHFT) | (nbits << SH1_PTC_0_PS_SHFT) | - ((ia64_get_rr(start) >> 8) << SH1_PTC_0_RID_SHFT) | + (rr_value << SH1_PTC_0_RID_SHFT) | (1UL << SH1_PTC_0_START_SHFT); ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_0); ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_1); @@ -254,7 +261,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, (nbits << SH2_PTC_PS_SHFT) | (1UL << SH2_PTC_START_SHFT); ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH2_PTC + - ((ia64_get_rr(start) >> 8) << SH2_PTC_RID_SHFT) ); + (rr_value << SH2_PTC_RID_SHFT)); ptc1 = NULL; } @@ -275,7 +282,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); for (i = 0; i < nix; i++) { nasid = nasids[i]; - if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) { + if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid && mymm)) { ia64_ptcga(start, nbits << 2); ia64_srlz_i(); } else { diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 79e89a7db566..522c7f5ba8ce 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -26,7 +26,7 @@ typedef void ia64_mv_cpu_init_t (void); typedef void ia64_mv_irq_init_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *); -typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long); +typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long); typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *); typedef unsigned int ia64_mv_local_vector_to_irq (u8); typedef char *ia64_mv_pci_get_legacy_mem_t (struct pci_bus *); From 09eee6347166a7baab74783999ef1bf23827647f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 08:29:36 +1000 Subject: [PATCH 0770/1939] powerpc: Move U3 IOMMU driver to arch/powerpc/sysdev Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/Makefile | 1 + arch/{ppc64/kernel => powerpc/sysdev}/u3_iommu.c | 0 arch/ppc64/kernel/Makefile | 2 -- 3 files changed, 1 insertion(+), 2 deletions(-) rename arch/{ppc64/kernel => powerpc/sysdev}/u3_iommu.c (100%) diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index d071ae875e25..8acd21dee05d 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_40x) += dcr.o +obj-$(CONFIG_U3_DART) += u3_iommu.o diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c similarity index 100% rename from arch/ppc64/kernel/u3_iommu.c rename to arch/powerpc/sysdev/u3_iommu.c diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index f2f60c9cc55f..863bd7d746fb 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -60,8 +60,6 @@ obj-$(CONFIG_PPC_PMAC) += udbg_scc.o obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ udbg_16550.o -obj-$(CONFIG_U3_DART) += u3_iommu.o - ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += smp-tbsync.o obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o From 9675c7ebcf1f6308d66b0fcb42ae585e200e80a9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 08:30:25 +1000 Subject: [PATCH 0771/1939] ppc64: Include arch/powerpc/kernel/setup-common.o ... which is needed now that ARCH=ppc64 is using the merged setup_64.c. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 94cf917b7854..68543201df3d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -46,7 +46,8 @@ endif else # stuff used from here for ARCH=ppc or ARCH=ppc64 -obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o +obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o \ + setup-common.o endif From 6fa05b17367f04ada501e89d3b9cb56adec0d930 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 19:08:18 -0400 Subject: [PATCH 0772/1939] Revert "RPC: stops the release_pipe() funtion from being called twice" This reverts 747c5534c9a6da4aa87e7cdc2209ea98ea27f381 commit. --- net/sunrpc/rpc_pipe.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 649d609e7d94..ded6c63f11ec 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -177,8 +177,6 @@ rpc_pipe_release(struct inode *inode, struct file *filp) __rpc_purge_upcall(inode, -EPIPE); if (rpci->ops->release_pipe) rpci->ops->release_pipe(inode); - if (!rpci->nreaders && !rpci->nwriters) - rpci->ops = NULL; out: up(&inode->i_sem); return 0; From 34123da66e613602de5a886b05c875b6a91b8ed2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 19:10:09 -0400 Subject: [PATCH 0773/1939] NFS: Fix a bad cast in nfs3_read_done Signed-off-by: Trond Myklebust --- fs/nfs/nfs3proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index df80477c5af4..e4a1cd48195e 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -735,7 +735,7 @@ extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); static void nfs3_read_done(struct rpc_task *task) { - struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; + struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; if (nfs3_async_handle_jukebox(task)) return; From 4ac0068f44f192f2de95a7bb36df3e19767a45fb Mon Sep 17 00:00:00 2001 From: Cliff Wickman Date: Thu, 27 Oct 2005 10:29:08 -0500 Subject: [PATCH 0774/1939] [IA64] ptrace - find memory sharers on children list In arch/ia64/kernel/ptrace.c there is a test for a peek or poke of a register image (in register backing storage). The test can be unnecessarily long (and occurs while holding the tasklist_lock). Especially long on a large system with thousands of active tasks. The ptrace caller (presumably a debugger) specifies the pid of its target and an address to peek or poke. But the debugger could be attached to several tasks. The idea of find_thread_for_addr() is to find whether the target address is in the RBS for any of those tasks. Currently it searches the thread-list of the target pid. If that search does not find a match, and the shared mm-struct's user count indicates that there are other tasks sharing this address space (a rare occurrence), a search is made of all the tasks in the system. Another approach can drastically shorten this procedure. It depends upon the fact that in order to peek or poke from/to any task, the debugger must first attach to that task. And when it does, the attached task is made a child of the debugger (is chained to its children list). Therefore we can search just the debugger's children list. Signed-off-by: Cliff Wickman Signed-off-by: Tony Luck --- arch/ia64/kernel/ptrace.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index bbb8bc7c0552..9a9c1bd01dbc 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -589,6 +589,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr) { struct task_struct *g, *p; struct mm_struct *mm; + struct list_head *this, *next; int mm_users; if (!(mm = get_task_mm(child))) @@ -600,28 +601,21 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr) goto out; /* not multi-threaded */ /* - * First, traverse the child's thread-list. Good for scalability with - * NPTL-threads. + * Traverse the current process' children list. Every task that + * one attaches to becomes a child. And it is only attached children + * of the debugger that are of interest (ptrace_check_attach checks + * for this). */ - p = child; - do { - if (thread_matches(p, addr)) { - child = p; - goto out; - } - if (mm_users-- <= 1) - goto out; - } while ((p = next_thread(p)) != child); - - do_each_thread(g, p) { - if (child->mm != mm) + list_for_each_safe(this, next, ¤t->children) { + p = list_entry(this, struct task_struct, sibling); + if (p->mm != mm) continue; - if (thread_matches(p, addr)) { child = p; goto out; } - } while_each_thread(g, p); + } + out: mmput(mm); return child; From 79b95a454bb5c1d9b7287d1016a70885ba3f346c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 27 Oct 2005 16:28:39 -0700 Subject: [PATCH 0775/1939] Revert "x86-64: Avoid unnecessary double bouncing for swiotlb" Commit id 6142891a0c0209c91aa4a98f725de0d6e2ed4918 Andi Kleen reports that it seems to break things for some people, and since it's purely a small optimization, revert it for now. Signed-off-by: Linus Torvalds --- include/asm-x86_64/pci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h index 5a82a6762c21..eeb3088a1c9e 100644 --- a/include/asm-x86_64/pci.h +++ b/include/asm-x86_64/pci.h @@ -50,10 +50,10 @@ extern int iommu_setup(char *opt); * address space. The networking and block device layers use * this boolean for bounce buffer decisions * - * On x86-64 it mostly equals, but we set it to zero to tell some subsystems - * that an hard or soft IOMMU is available. + * On AMD64 it mostly equals, but we set it to zero to tell some subsystems + * that an IOMMU is available. */ -#define PCI_DMA_BUS_IS_PHYS 0 +#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0) /* * x86-64 always supports DAC, but sometimes it is useful to force From 927321440976d0781a252eefe686ae6b0f236ae2 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 27 Oct 2005 16:16:25 -0700 Subject: [PATCH 0776/1939] [PATCH] cpufreq: SMP fix for conservative governor Don't try to access not-present CPUs. Conservative governor will always oops on SMP without this fix. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=4781 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq_conservative.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index e1df376e709e..2ed5c4363b53 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -315,9 +315,9 @@ static void dbs_check_cpu(int cpu) policy = this_dbs_info->cur_policy; if ( init_flag == 0 ) { - for ( /* NULL */; init_flag < NR_CPUS; init_flag++ ) { - dbs_info = &per_cpu(cpu_dbs_info, init_flag); - requested_freq[cpu] = dbs_info->cur_policy->cur; + for_each_online_cpu(j) { + dbs_info = &per_cpu(cpu_dbs_info, j); + requested_freq[j] = dbs_info->cur_policy->cur; } init_flag = 1; } From 741b2252a5e14d6c60a913c77a6099abe73a854a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 27 Oct 2005 17:02:08 -0700 Subject: [PATCH 0777/1939] Linux v2.6.14 "Better late than never" --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4a7000e353b5..1fa7e5343464 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 14 -EXTRAVERSION =-rc5 +EXTRAVERSION = NAME=Affluent Albatross # *DOCUMENTATION* From e6b4fe92effe88944af2df7257688ccff811996d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 27 Oct 2005 08:54:36 -0500 Subject: [PATCH 0778/1939] [PATCH] powerpc: only build idle_6xx for 6xx For the current time idle_6xx only applies to 6xx ppc32 CPUs Signed-off-by: Kumar K. Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 68543201df3d..8421f1975dad 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -33,11 +33,12 @@ extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ prom.o systbl.o traps.o setup-common.o -obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o +obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o obj-$(CONFIG_PPC64) += misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o +obj-$(CONFIG_6xx) += idle_6xx.o ifeq ($(CONFIG_PPC_ISERIES),y) $(obj)/head_64.o: $(obj)/lparmap.s From a8e3d48150d70ceab3b8249a4bdbe5c50567a357 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 28 Oct 2005 10:31:49 +1000 Subject: [PATCH 0779/1939] [PATCH] powerpc: Remove dregs of bootinfo.h Since I sent the patch to purge bootinfo.h from ARCH=powerpc and ARCH=ppc64, setup-common.c has come into existence, and another #include of bootinfo.h slipped in. This patch removes it. It also removes include/asm-ppc64/bootinfo.h, which somehow survived the previous patch which was supposed to remove it. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup-common.c | 1 - include/asm-ppc64/bootinfo.h | 70 ------------------------------ 2 files changed, 71 deletions(-) delete mode 100644 include/asm-ppc64/bootinfo.h diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index d4f0a4c3b5bc..aa743a50a20a 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/include/asm-ppc64/bootinfo.h b/include/asm-ppc64/bootinfo.h deleted file mode 100644 index f55e7cb48f46..000000000000 --- a/include/asm-ppc64/bootinfo.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Non-machine dependent bootinfo structure. Basic idea - * borrowed from the m68k. - * - * Copyright (C) 1999 Cort Dougan - * Copyright (c) 2001 PPC64 Team, 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. - */ - - -#ifndef _PPC64_BOOTINFO_H -#define _PPC64_BOOTINFO_H - -#include - -/* We use a u32 for the type of the fields since they're written by - * the bootloader which is a 32-bit process and read by the kernel - * which is a 64-bit process. This way they can both agree on the - * size of the type. - */ -typedef u32 bi_rec_field; - -struct bi_record { - bi_rec_field tag; /* tag ID */ - bi_rec_field size; /* size of record (in bytes) */ - bi_rec_field data[0]; /* data */ -}; - -#define BI_FIRST 0x1010 /* first record - marker */ -#define BI_LAST 0x1011 /* last record - marker */ -#define BI_CMD_LINE 0x1012 -#define BI_BOOTLOADER_ID 0x1013 -#define BI_INITRD 0x1014 -#define BI_SYSMAP 0x1015 -#define BI_MACHTYPE 0x1016 - -static __inline__ struct bi_record * bi_rec_init(unsigned long addr) -{ - struct bi_record *bi_recs; - bi_recs = (struct bi_record *)_ALIGN(addr, PAGE_SIZE); - bi_recs->size = 0; - return bi_recs; -} - -static __inline__ struct bi_record * bi_rec_alloc(struct bi_record *rec, - unsigned long args) -{ - rec = (struct bi_record *)((unsigned long)rec + rec->size); - rec->size = sizeof(struct bi_record) + args*sizeof(bi_rec_field); - return rec; -} - -static __inline__ struct bi_record * bi_rec_alloc_bytes(struct bi_record *rec, - unsigned long bytes) -{ - rec = (struct bi_record *)((unsigned long)rec + rec->size); - rec->size = sizeof(struct bi_record) + bytes; - return rec; -} - -static __inline__ struct bi_record * bi_rec_next(struct bi_record *rec) -{ - return (struct bi_record *)((unsigned long)rec + rec->size); -} - -#endif /* _PPC64_BOOTINFO_H */ From 2227718ca2f7d5fcc2741c1bbca4d0c2efd340ce Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 11:47:17 +1000 Subject: [PATCH 0780/1939] ppc64: Use the correct prototypes for i8259 functions We still had an old copy of i8259.h lying around; this gets rid of it and corrects the callers of i8259_init and i8259_irq. Signed-off-by: Paul Mackerras --- arch/ppc64/kernel/i8259.h | 17 ----------------- arch/ppc64/kernel/xics.c | 7 +++---- 2 files changed, 3 insertions(+), 21 deletions(-) delete mode 100644 arch/ppc64/kernel/i8259.h diff --git a/arch/ppc64/kernel/i8259.h b/arch/ppc64/kernel/i8259.h deleted file mode 100644 index f74764ba0bfa..000000000000 --- a/arch/ppc64/kernel/i8259.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * c 2001 PPC 64 Team, 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. - */ -#ifndef _PPC_KERNEL_i8259_H -#define _PPC_KERNEL_i8259_H - -extern struct hw_interrupt_type i8259_pic; - -extern void i8259_init(int offset); -extern int i8259_irq(int); - -#endif /* _PPC_KERNEL_i8259_H */ diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index daf93885dcfa..a32207dcf2e3 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -28,8 +28,7 @@ #include #include #include - -#include "i8259.h" +#include static unsigned int xics_startup(unsigned int irq); static void xics_enable_irq(unsigned int irq); @@ -366,7 +365,7 @@ int xics_get_irq(struct pt_regs *regs) /* for sanity, this had better be < NR_IRQS - 16 */ if (vec == xics_irq_8259_cascade_real) { - irq = i8259_irq(cpu); + irq = i8259_irq(regs); if (irq == -1) { /* Spurious cascaded interrupt. Still must ack xics */ xics_end_irq(irq_offset_up(xics_irq_8259_cascade)); @@ -589,7 +588,7 @@ static int __init xics_setup_i8259(void) no_action, 0, "8259 cascade", NULL)) printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 " "cascade\n"); - i8259_init(0); + i8259_init(0, 0); } return 0; } From 0e574af1be5f569a5d7f2800333b0bfb358a5e34 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:38 -0400 Subject: [PATCH 0781/1939] NFS: Cleanup initialisation of struct nfs_fattr Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 1 + fs/nfs/nfs3proc.c | 58 +++++++++++++++++++++--------------------- fs/nfs/nfs4proc.c | 43 +++++++++++++++---------------- fs/nfs/proc.c | 26 +++++++++---------- fs/nfs/read.c | 1 + fs/nfs/write.c | 2 ++ include/linux/nfs_fs.h | 5 ++++ 7 files changed, 71 insertions(+), 65 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index eb50c19fc253..b8a73045e9a0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -532,6 +532,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) my_entry.eof = 0; my_entry.fh = &fh; my_entry.fattr = &fattr; + nfs_fattr_init(&fattr); desc->entry = &my_entry; while(!desc->entry->eof) { diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index e4a1cd48195e..4b1b48b139f6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -78,7 +78,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("%s: call fsinfo\n", __FUNCTION__); - info->fattr->valid = 0; + nfs_fattr_init(info->fattr); status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); if (!(info->fattr->valid & NFS_ATTR_FATTR)) { @@ -98,7 +98,7 @@ nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call getattr\n"); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply getattr: %d\n", status); @@ -117,7 +117,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, int status; dprintk("NFS call setattr\n"); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); if (status == 0) nfs_setattr_update_inode(inode, sattr); @@ -143,8 +143,8 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, int status; dprintk("NFS call lookup %s\n", name->name); - dir_attr.valid = 0; - fattr->valid = 0; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, @@ -174,7 +174,6 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) int status; dprintk("NFS call access\n"); - fattr.valid = 0; if (mode & MAY_READ) arg.access |= NFS3_ACCESS_READ; @@ -189,6 +188,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_EXECUTE; } + nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_refresh_inode(inode, &fattr); if (status == 0) { @@ -217,7 +217,7 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, int status; dprintk("NFS call readlink\n"); - fattr.valid = 0; + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, &fattr, 0); nfs_refresh_inode(inode, &fattr); @@ -240,7 +240,7 @@ static int nfs3_proc_read(struct nfs_read_data *rdata) dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -263,7 +263,7 @@ static int nfs3_proc_write(struct nfs_write_data *wdata) dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -285,7 +285,7 @@ static int nfs3_proc_commit(struct nfs_write_data *cdata) dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -329,8 +329,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, sattr->ia_mode &= ~current->fs->umask; again: - dir_attr.valid = 0; - fattr.valid = 0; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); @@ -401,7 +401,7 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name) int status; dprintk("NFS call remove %s\n", name->name); - dir_attr.valid = 0; + nfs_fattr_init(&dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); @@ -422,7 +422,7 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr ptr->arg.fh = NFS_FH(dir->d_inode); ptr->arg.name = name->name; ptr->arg.len = name->len; - ptr->res.valid = 0; + nfs_fattr_init(&ptr->res); msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; msg->rpc_argp = &ptr->arg; msg->rpc_resp = &ptr->res; @@ -465,8 +465,8 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - old_dir_attr.valid = 0; - new_dir_attr.valid = 0; + nfs_fattr_init(&old_dir_attr); + nfs_fattr_init(&new_dir_attr); status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); nfs_refresh_inode(old_dir, &old_dir_attr); nfs_refresh_inode(new_dir, &new_dir_attr); @@ -491,8 +491,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) int status; dprintk("NFS call link %s\n", name->name); - dir_attr.valid = 0; - fattr.valid = 0; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); nfs_refresh_inode(inode, &fattr); @@ -524,8 +524,8 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, if (path->len > NFS3_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); - dir_attr.valid = 0; - fattr->valid = 0; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply symlink: %d\n", status); @@ -552,11 +552,11 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); - dir_attr.valid = 0; - fattr.valid = 0; sattr->ia_mode &= ~current->fs->umask; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); if (status != 0) @@ -582,7 +582,7 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name) int status; dprintk("NFS call rmdir %s\n", name->name); - dir_attr.valid = 0; + nfs_fattr_init(&dir_attr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); @@ -634,7 +634,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, dprintk("NFS call readdir%s %d\n", plus? "plus" : "", (unsigned int) cookie); - dir_attr.valid = 0; + nfs_fattr_init(&dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); @@ -676,8 +676,8 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, sattr->ia_mode &= ~current->fs->umask; - dir_attr.valid = 0; - fattr.valid = 0; + nfs_fattr_init(&dir_attr); + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); if (status != 0) @@ -698,7 +698,7 @@ nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call fsstat\n"); - stat->fattr->valid = 0; + nfs_fattr_init(stat->fattr); status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0); dprintk("NFS reply statfs: %d\n", status); return status; @@ -711,7 +711,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call fsinfo\n"); - info->fattr->valid = 0; + nfs_fattr_init(info->fattr); status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); dprintk("NFS reply fsinfo: %d\n", status); return status; @@ -724,7 +724,7 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call pathconf\n"); - info->fattr->valid = 0; + nfs_fattr_init(info->fattr); status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0); dprintk("NFS reply pathconf: %d\n", status); return status; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9c1da34036aa..2a759e8e387c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -494,9 +494,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs_delegation *delegation = NFS_I(inode)->delegation; - struct nfs_fattr f_attr = { - .valid = 0, - }; + struct nfs_fattr f_attr; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = state->state, @@ -522,6 +520,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st status = -ENOMEM; if (o_arg.seqid == NULL) goto out; + nfs_fattr_init(&f_attr); status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_nodeleg; @@ -692,9 +691,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st struct nfs4_client *clp = server->nfs4_state; struct inode *inode = NULL; int status; - struct nfs_fattr f_attr = { - .valid = 0, - }; + struct nfs_fattr f_attr; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = flags, @@ -726,6 +723,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); if (o_arg.seqid == NULL) return -ENOMEM; + nfs_fattr_init(&f_attr); status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_err; @@ -824,7 +822,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, }; int status; - fattr->valid = 0; + nfs_fattr_init(fattr); if (state != NULL) { msg.rpc_cred = state->owner->so_cred; @@ -1107,13 +1105,12 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { - struct nfs_fattr * fattr = info->fattr; struct nfs4_lookup_root_arg args = { .bitmask = nfs4_fattr_bitmap, }; struct nfs4_lookup_res res = { .server = server, - .fattr = fattr, + .fattr = info->fattr, .fh = fhandle, }; struct rpc_message msg = { @@ -1121,7 +1118,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, .rpc_argp = &args, .rpc_resp = &res, }; - fattr->valid = 0; + nfs_fattr_init(info->fattr); return rpc_call_sync(server->client, &msg, 0); } @@ -1184,7 +1181,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, q.len = p - q.name; do { - fattr->valid = 0; + nfs_fattr_init(fattr); status = nfs4_handle_exception(server, rpc_call_sync(server->client, &msg, 0), &exception); @@ -1221,7 +1218,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, .rpc_resp = &res, }; - fattr->valid = 0; + nfs_fattr_init(fattr); return rpc_call_sync(server->client, &msg, 0); } @@ -1263,7 +1260,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct nfs4_state *state; int status; - fattr->valid = 0; + nfs_fattr_init(fattr); cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); if (IS_ERR(cred)) @@ -1309,7 +1306,7 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, .rpc_resp = &res, }; - fattr->valid = 0; + nfs_fattr_init(fattr); dprintk("NFS call lookup %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); @@ -1458,7 +1455,7 @@ static int _nfs4_proc_read(struct nfs_read_data *rdata) dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, flags); if (!status) renew_lease(server, timestamp); @@ -1495,7 +1492,7 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata) dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, rpcflags); dprintk("NFS reply write: %d\n", status); return status; @@ -1529,7 +1526,7 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata) dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply commit: %d\n", status); return status; @@ -1769,7 +1766,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, if (path->len > NFS4_MAXPATHLEN) return -ENAMETOOLONG; arg.u.symlink = path; - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) @@ -1818,7 +1815,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, }; int status; - fattr.valid = 0; + nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) { @@ -1916,7 +1913,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, int status; int mode = sattr->ia_mode; - fattr.valid = 0; + nfs_fattr_init(&fattr); BUG_ON(!(sattr->ia_valid & ATTR_MODE)); BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); @@ -1969,7 +1966,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, .rpc_resp = fsstat, }; - fsstat->fattr->valid = 0; + nfs_fattr_init(fsstat->fattr); return rpc_call_sync(server->client, &msg, 0); } @@ -2016,7 +2013,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) { - fsinfo->fattr->valid = 0; + nfs_fattr_init(fsinfo->fattr); return nfs4_do_fsinfo(server, fhandle, fsinfo); } @@ -2039,7 +2036,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle return 0; } - pathconf->fattr->valid = 0; + nfs_fattr_init(pathconf->fattr); return rpc_call_sync(server->client, &msg, 0); } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 8fef86523d7f..5ef28f08f424 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -61,7 +61,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("%s: call getattr\n", __FUNCTION__); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0); dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); if (status) @@ -93,7 +93,7 @@ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call getattr\n"); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply getattr: %d\n", status); @@ -112,7 +112,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, int status; dprintk("NFS call setattr\n"); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); if (status == 0) nfs_setattr_update_inode(inode, sattr); @@ -136,7 +136,7 @@ nfs_proc_lookup(struct inode *dir, struct qstr *name, int status; dprintk("NFS call lookup %s\n", name->name); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; @@ -174,7 +174,7 @@ static int nfs_proc_read(struct nfs_read_data *rdata) dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); @@ -203,7 +203,7 @@ static int nfs_proc_write(struct nfs_write_data *wdata) dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); - fattr->valid = 0; + nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); @@ -232,7 +232,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, }; int status; - fattr.valid = 0; + nfs_fattr_init(&fattr); dprintk("NFS call create %s\n", dentry->d_name.name); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == 0) @@ -273,12 +273,12 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ } - fattr.valid = 0; + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; - fattr.valid = 0; + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); } if (status == 0) @@ -391,7 +391,7 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, if (path->len > NFS2_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); - fattr->valid = 0; + nfs_fattr_init(fattr); fhandle->size = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); dprintk("NFS reply symlink: %d\n", status); @@ -416,7 +416,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); - fattr.valid = 0; + nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); @@ -484,7 +484,7 @@ nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call statfs\n"); - stat->fattr->valid = 0; + nfs_fattr_init(stat->fattr); status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); dprintk("NFS reply statfs: %d\n", status); if (status) @@ -507,7 +507,7 @@ nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, int status; dprintk("NFS call fsinfo\n"); - info->fattr->valid = 0; + nfs_fattr_init(info->fattr); status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); dprintk("NFS reply fsinfo: %d\n", status); if (status) diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 9758ebd49905..43b03b19731b 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -215,6 +215,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, data->res.fattr = &data->fattr; data->res.count = count; data->res.eof = 0; + nfs_fattr_init(&data->fattr); NFS_PROTO(inode)->read_setup(data); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5130eda231d7..819a65f5071f 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -870,6 +870,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, data->res.fattr = &data->fattr; data->res.count = count; data->res.verf = &data->verf; + nfs_fattr_init(&data->fattr); NFS_PROTO(inode)->write_setup(data, how); @@ -1237,6 +1238,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, data->res.count = 0; data->res.fattr = &data->fattr; data->res.verf = &data->verf; + nfs_fattr_init(&data->fattr); NFS_PROTO(inode)->commit_setup(data, how); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7bac2785c6e4..8120fd68dee5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -316,6 +316,11 @@ extern void nfs_file_clear_open_context(struct file *filp); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ extern u32 root_nfs_parse_addr(char *name); /*__init*/ +static inline void nfs_fattr_init(struct nfs_fattr *fattr) +{ + fattr->valid = 0; +} + /* * linux/fs/nfs/file.c */ From 913a70fc170530f7e1ff0693595155457cc6d0ca Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:38 -0400 Subject: [PATCH 0782/1939] NFS: Convert cache_change_attribute into a jiffy-based value Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 8 ++++---- include/linux/nfs_fs.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 65d5ab45ddc5..449df8c8aa31 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1135,7 +1135,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) * We may need to keep the attributes marked as invalid if * we raced with nfs_end_attr_update(). */ - if (verifier == nfsi->cache_change_attribute) + if (time_after_eq(verifier, nfsi->cache_change_attribute)) nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); spin_unlock(&inode->i_lock); @@ -1202,7 +1202,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) if (S_ISDIR(inode->i_mode)) { memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); /* This ensures we revalidate child dentries */ - nfsi->cache_change_attribute++; + nfsi->cache_change_attribute = jiffies; } spin_unlock(&inode->i_lock); @@ -1242,7 +1242,7 @@ void nfs_end_data_update(struct inode *inode) nfsi->cache_validity |= NFS_INO_INVALID_DATA; spin_unlock(&inode->i_lock); } - nfsi->cache_change_attribute ++; + nfsi->cache_change_attribute = jiffies; atomic_dec(&nfsi->data_updates); } @@ -1391,7 +1391,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign /* Do we perhaps have any outstanding writes? */ if (nfsi->npages == 0) { /* No, but did we race with nfs_end_data_update()? */ - if (verifier == nfsi->cache_change_attribute) { + if (time_after_eq(verifier, nfsi->cache_change_attribute)) { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_DATA; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 8120fd68dee5..abf890f5fbfb 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -280,7 +280,7 @@ static inline long nfs_save_change_attribute(struct inode *inode) static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr) { return !nfs_caches_unstable(inode) - && chattr == NFS_I(inode)->cache_change_attribute; + && time_after_eq(chattr, NFS_I(inode)->cache_change_attribute); } /* From 33801147a8fda6b04d7e9afe1d42f1c01d3d6837 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:39 -0400 Subject: [PATCH 0783/1939] NFS: Optimise inode attribute cache updates Allow nfs_refresh_inode() also to update attributes on the inode if the RPC call was sent after the last call to nfs_update_inode(). Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 54 ++++++++++++++++++++++++++++++----------- fs/nfs/nfs2xdr.c | 1 - fs/nfs/nfs3xdr.c | 1 - fs/nfs/nfs4xdr.c | 4 +-- include/linux/nfs_fs.h | 2 ++ include/linux/nfs_xdr.h | 2 +- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 449df8c8aa31..b7d4f8f13ac2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -785,7 +785,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) else init_special_inode(inode, inode->i_mode, fattr->rdev); - nfsi->read_cache_jiffies = fattr->timestamp; + nfsi->read_cache_jiffies = fattr->time_start; + nfsi->last_updated = jiffies; inode->i_atime = fattr->atime; inode->i_mtime = fattr->mtime; inode->i_ctime = fattr->ctime; @@ -1120,14 +1121,15 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) goto out; } + spin_lock(&inode->i_lock); status = nfs_update_inode(inode, &fattr, verifier); if (status) { + spin_unlock(&inode->i_lock); dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode), status); goto out; } - spin_lock(&inode->i_lock); cache_validity = nfsi->cache_validity; nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; @@ -1247,7 +1249,7 @@ void nfs_end_data_update(struct inode *inode) } /** - * nfs_refresh_inode - verify consistency of the inode attribute cache + * nfs_check_inode_attributes - verify consistency of the inode attribute cache * @inode - pointer to inode * @fattr - updated attributes * @@ -1255,13 +1257,12 @@ void nfs_end_data_update(struct inode *inode) * so that fattr carries weak cache consistency data, then it may * also update the ctime/mtime/change_attribute. */ -int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) +static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; int data_unstable; - spin_lock(&inode->i_lock); /* Are we in the process of updating data on the server? */ data_unstable = nfs_caches_unstable(inode); @@ -1325,11 +1326,40 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if (!timespec_equal(&inode->i_atime, &fattr->atime)) nfsi->cache_validity |= NFS_INO_INVALID_ATIME; - nfsi->read_cache_jiffies = fattr->timestamp; - spin_unlock(&inode->i_lock); + nfsi->read_cache_jiffies = fattr->time_start; return 0; } +/** + * nfs_refresh_inode - try to update the inode attribute cache + * @inode - pointer to inode + * @fattr - updated attributes + * + * Check that an RPC call that returned attributes has not overlapped with + * other recent updates of the inode metadata, then decide whether it is + * safe to do a full update of the inode attributes, or whether just to + * call nfs_check_inode_attributes. + */ +int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) +{ + struct nfs_inode *nfsi = NFS_I(inode); + int status; + + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; + spin_lock(&inode->i_lock); + nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; + if (nfs_verify_change_attribute(inode, fattr->time_start)) + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); + if (time_after(fattr->time_start, nfsi->last_updated)) + status = nfs_update_inode(inode, fattr, fattr->time_start); + else + status = nfs_check_inode_attributes(inode, fattr); + + spin_unlock(&inode->i_lock); + return status; +} + /* * Many nfs protocol calls return the new file attributes after * an operation. Here we update the inode to reflect the state @@ -1365,20 +1395,17 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign goto out_err; } - spin_lock(&inode->i_lock); - /* * Make sure the inode's type hasn't changed. */ - if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { - spin_unlock(&inode->i_lock); + if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; - } /* * Update the read time so we don't revalidate too often. */ - nfsi->read_cache_jiffies = fattr->timestamp; + nfsi->read_cache_jiffies = fattr->time_start; + nfsi->last_updated = jiffies; /* Are we racing with known updates of the metadata on the server? */ data_unstable = ! (nfs_verify_change_attribute(inode, verifier) || @@ -1467,7 +1494,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign if (!nfs_have_delegation(inode, FMODE_READ)) nfsi->cache_validity |= invalid; - spin_unlock(&inode->i_lock); return 0; out_changed: /* diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index d91b69044a4d..59049e864ca7 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -143,7 +143,6 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; fattr->rdev = 0; } - fattr->timestamp = jiffies; return p; } diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index db4a904810a4..0498bd36602c 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -174,7 +174,6 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) /* Update the mode bits */ fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3); - fattr->timestamp = jiffies; return p; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index cd762648fa9a..8b21de8a06fa 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2799,10 +2799,8 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons goto xdr_error; if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0) goto xdr_error; - if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) { + if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; - fattr->timestamp = jiffies; - } xdr_error: if (status != 0) printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index abf890f5fbfb..faeaad666ca8 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -141,6 +141,7 @@ struct nfs_inode { unsigned long attrtimeo_timestamp; __u64 change_attr; /* v4 only */ + unsigned long last_updated; /* "Generation counter" for the attribute cache. This is * bumped whenever we update the metadata on the * server. @@ -319,6 +320,7 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/ static inline void nfs_fattr_init(struct nfs_fattr *fattr) { fattr->valid = 0; + fattr->time_start = jiffies; } /* diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 60086dac11d5..aeaee7e7c51d 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -41,7 +41,7 @@ struct nfs_fattr { __u32 bitmap[2]; /* NFSv4 returned attribute bitmap */ __u64 change_attr; /* NFSv4 change attribute */ __u64 pre_change_attr;/* pre-op NFSv4 change attribute */ - unsigned long timestamp; + unsigned long time_start; }; #define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */ From decf491f3076190262d4c649bed877650623903a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:39 -0400 Subject: [PATCH 0784/1939] NFS: Don't let nfs_end_data_update() clobber attribute update information Since we almost always call nfs_end_data_update() after we called nfs_refresh_inode(), we now end up marking the inode metadata as needing revalidation immediately after having updated it. This patch rearranges things so that we mark the inode as needing revalidation _before_ we call nfs_refresh_inode() on those operations that need it. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 38 ++++++++++++++++++++++++++++++++------ fs/nfs/nfs3proc.c | 30 +++++++++++++++--------------- fs/nfs/nfs4proc.c | 3 +++ fs/nfs/proc.c | 16 +++++++++++++--- include/linux/nfs_fs.h | 15 ++++++++++----- 5 files changed, 73 insertions(+), 29 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b7d4f8f13ac2..6b3156e15350 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1236,13 +1236,12 @@ void nfs_end_data_update(struct inode *inode) struct nfs_inode *nfsi = NFS_I(inode); if (!nfs_have_delegation(inode, FMODE_READ)) { - /* Mark the attribute cache for revalidation */ - spin_lock(&inode->i_lock); - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; - /* Directories and symlinks: invalidate page cache too */ - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + /* Directories and symlinks: invalidate page cache */ + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + spin_lock(&inode->i_lock); nfsi->cache_validity |= NFS_INO_INVALID_DATA; - spin_unlock(&inode->i_lock); + spin_unlock(&inode->i_lock); + } } nfsi->cache_change_attribute = jiffies; atomic_dec(&nfsi->data_updates); @@ -1360,6 +1359,33 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) return status; } +/** + * nfs_post_op_update_inode - try to update the inode attribute cache + * @inode - pointer to inode + * @fattr - updated attributes + * + * After an operation that has changed the inode metadata, mark the + * attribute cache as being invalid, then try to update it. + */ +int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) +{ + struct nfs_inode *nfsi = NFS_I(inode); + int status = 0; + + spin_lock(&inode->i_lock); + if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) { + nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; + goto out; + } + status = nfs_update_inode(inode, fattr, fattr->time_start); + if (time_after_eq(fattr->time_start, nfsi->cache_change_attribute)) + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); + nfsi->cache_change_attribute = jiffies; +out: + spin_unlock(&inode->i_lock); + return status; +} + /* * Many nfs protocol calls return the new file attributes after * an operation. Here we update the inode to reflect the state diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 4b1b48b139f6..92c870d19ccd 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -266,7 +266,7 @@ static int nfs3_proc_write(struct nfs_write_data *wdata) nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); if (status >= 0) - nfs_refresh_inode(inode, fattr); + nfs_post_op_update_inode(inode, fattr); dprintk("NFS reply write: %d\n", status); return status < 0? status : wdata->res.count; } @@ -288,7 +288,7 @@ static int nfs3_proc_commit(struct nfs_write_data *cdata) nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status >= 0) - nfs_refresh_inode(inode, fattr); + nfs_post_op_update_inode(inode, fattr); dprintk("NFS reply commit: %d\n", status); return status; } @@ -332,7 +332,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); /* If the server doesn't support the exclusive creation semantics, * try again with simple 'guarded' mode. */ @@ -403,7 +403,7 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name) dprintk("NFS call remove %s\n", name->name); nfs_fattr_init(&dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; } @@ -439,7 +439,7 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) return 1; if (msg->rpc_argp) { dir_attr = (struct nfs_fattr*)msg->rpc_resp; - nfs_refresh_inode(dir->d_inode, dir_attr); + nfs_post_op_update_inode(dir->d_inode, dir_attr); kfree(msg->rpc_argp); } return 0; @@ -468,8 +468,8 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, nfs_fattr_init(&old_dir_attr); nfs_fattr_init(&new_dir_attr); status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); - nfs_refresh_inode(old_dir, &old_dir_attr); - nfs_refresh_inode(new_dir, &new_dir_attr); + nfs_post_op_update_inode(old_dir, &old_dir_attr); + nfs_post_op_update_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); return status; } @@ -494,8 +494,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); - nfs_refresh_inode(dir, &dir_attr); - nfs_refresh_inode(inode, &fattr); + nfs_post_op_update_inode(dir, &dir_attr); + nfs_post_op_update_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); return status; } @@ -527,7 +527,7 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, nfs_fattr_init(&dir_attr); nfs_fattr_init(fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); dprintk("NFS reply symlink: %d\n", status); return status; } @@ -558,7 +558,7 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); if (status != 0) goto out; status = nfs_instantiate(dentry, &fhandle, &fattr); @@ -584,7 +584,7 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name) dprintk("NFS call rmdir %s\n", name->name); nfs_fattr_init(&dir_attr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -679,7 +679,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); - nfs_refresh_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &dir_attr); if (status != 0) goto out; status = nfs_instantiate(dentry, &fh, &fattr); @@ -775,7 +775,7 @@ nfs3_write_done(struct rpc_task *task) return; data = (struct nfs_write_data *)task->tk_calldata; if (task->tk_status >= 0) - nfs_refresh_inode(data->inode, data->res.fattr); + nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_writeback_done(task); } @@ -819,7 +819,7 @@ nfs3_commit_done(struct rpc_task *task) return; data = (struct nfs_write_data *)task->tk_calldata; if (task->tk_status >= 0) - nfs_refresh_inode(data->inode, data->res.fattr); + nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_commit_done(task); } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2a759e8e387c..3274f2d354f3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -187,8 +187,11 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf { struct nfs_inode *nfsi = NFS_I(inode); + spin_lock(&inode->i_lock); + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (cinfo->before == nfsi->change_attr && cinfo->atomic) nfsi->change_attr = cinfo->after; + spin_unlock(&inode->i_lock); } /* Helper for asynchronous RPC calls */ diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 5ef28f08f424..a48a003242c0 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -206,7 +206,7 @@ static int nfs_proc_write(struct nfs_write_data *wdata) nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { - nfs_refresh_inode(inode, fattr); + nfs_post_op_update_inode(inode, fattr); wdata->res.count = wdata->args.count; wdata->verf.committed = NFS_FILE_SYNC; } @@ -275,6 +275,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); + nfs_mark_for_revalidate(dir); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; @@ -305,6 +306,7 @@ nfs_proc_remove(struct inode *dir, struct qstr *name) dprintk("NFS call remove %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_mark_for_revalidate(dir); dprintk("NFS reply remove: %d\n", status); return status; @@ -331,8 +333,10 @@ nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task) { struct rpc_message *msg = &task->tk_msg; - if (msg->rpc_argp) + if (msg->rpc_argp) { + nfs_mark_for_revalidate(dir->d_inode); kfree(msg->rpc_argp); + } return 0; } @@ -352,6 +356,8 @@ nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); + nfs_mark_for_revalidate(old_dir); + nfs_mark_for_revalidate(new_dir); dprintk("NFS reply rename: %d\n", status); return status; } @@ -369,6 +375,7 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) dprintk("NFS call link %s\n", name->name); status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); + nfs_mark_for_revalidate(dir); dprintk("NFS reply link: %d\n", status); return status; } @@ -394,6 +401,7 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, nfs_fattr_init(fattr); fhandle->size = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); + nfs_mark_for_revalidate(dir); dprintk("NFS reply symlink: %d\n", status); return status; } @@ -418,6 +426,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) dprintk("NFS call mkdir %s\n", dentry->d_name.name); nfs_fattr_init(&fattr); status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); + nfs_mark_for_revalidate(dir); if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mkdir: %d\n", status); @@ -436,6 +445,7 @@ nfs_proc_rmdir(struct inode *dir, struct qstr *name) dprintk("NFS call rmdir %s\n", name->name); status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); + nfs_mark_for_revalidate(dir); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -579,7 +589,7 @@ nfs_write_done(struct rpc_task *task) struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; if (task->tk_status >= 0) - nfs_refresh_inode(data->inode, data->res.fattr); + nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_writeback_done(task); } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index faeaad666ca8..325fe7ae49bb 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -241,13 +241,17 @@ static inline int nfs_caches_unstable(struct inode *inode) return atomic_read(&NFS_I(inode)->data_updates) != 0; } +static inline void nfs_mark_for_revalidate(struct inode *inode) +{ + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; + spin_unlock(&inode->i_lock); +} + static inline void NFS_CACHEINV(struct inode *inode) { - if (!nfs_caches_unstable(inode)) { - spin_lock(&inode->i_lock); - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; - spin_unlock(&inode->i_lock); - } + if (!nfs_caches_unstable(inode)) + nfs_mark_for_revalidate(inode); } static inline int nfs_server_capable(struct inode *inode, int cap) @@ -291,6 +295,7 @@ extern void nfs_zap_caches(struct inode *); extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); +extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_permission(struct inode *, int, struct nameidata *); extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *); From 0c70b50150cfb0b43ff500a8a394a52b4d5f1350 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 25 Oct 2005 11:48:36 -0400 Subject: [PATCH 0785/1939] NFS: nfs_lookup doesn't need to revalidate the parent directory's inode nfs_lookup() used to consult a lookup cache before trying an actual wire lookup operation. The lookup cache would be invalid, of course, if the parent directory's mtime had changed, so nfs_lookup performed an inode revalidation on the parent. Since nfs_lookup() doesn't use a cache anymore, the revalidation is no longer necessary. There are cases where it will generate a lot of unnecessary GETATTR traffic. See http://bugzilla.linux-nfs.org/show_bug.cgi?id=9 Test-plan: Use lndir and "rm -rf" and watch for excess GETATTR traffic or application level errors. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b8a73045e9a0..ce8f77dadff9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -853,12 +853,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru dentry->d_op = NFS_PROTO(dir)->dentry_ops; lock_kernel(); - /* Revalidate parent directory attribute cache */ - error = nfs_revalidate_inode(NFS_SERVER(dir), dir); - if (error < 0) { - res = ERR_PTR(error); - goto out_unlock; - } /* If we're doing an exclusive create, optimize away the lookup */ if (nfs_is_exclusive_create(dir, nd)) From 56ae19f38f10aad4f27f7e12138a29b295dff07a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:40 -0400 Subject: [PATCH 0786/1939] NFSv4: Add directory post-op attributes to the CREATE operations. Since the directory attributes change every time we CREATE a file, we might as well pick up the new directory attributes in the same compound. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 28 ++++++++++++++--- fs/nfs/nfs4xdr.c | 69 +++++++++++++++++++++++++++++++++++------ include/linux/nfs_xdr.h | 2 ++ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3274f2d354f3..f363fd6c7f4d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -443,7 +443,11 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru nfs_increment_open_seqid(status, o_arg->seqid); if (status != 0) goto out; - update_changeattr(dir, &o_res->cinfo); + if (o_arg->open_flags & O_CREAT) { + update_changeattr(dir, &o_res->cinfo); + nfs_post_op_update_inode(dir, o_res->dir_attr); + } else + nfs_refresh_inode(dir, o_res->dir_attr); if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { status = _nfs4_proc_open_confirm(server->client, &o_res->fh, sp, &o_res->stateid, o_arg->seqid); @@ -497,7 +501,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs_delegation *delegation = NFS_I(inode)->delegation; - struct nfs_fattr f_attr; + struct nfs_fattr f_attr, dir_attr; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = state->state, @@ -507,6 +511,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st }; struct nfs_openres o_res = { .f_attr = &f_attr, + .dir_attr = &dir_attr, .server = server, }; int status = 0; @@ -524,6 +529,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st if (o_arg.seqid == NULL) goto out; nfs_fattr_init(&f_attr); + nfs_fattr_init(&dir_attr); status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_nodeleg; @@ -694,7 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st struct nfs4_client *clp = server->nfs4_state; struct inode *inode = NULL; int status; - struct nfs_fattr f_attr; + struct nfs_fattr f_attr, dir_attr; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = flags, @@ -705,6 +711,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st }; struct nfs_openres o_res = { .f_attr = &f_attr, + .dir_attr = &dir_attr, .server = server, }; @@ -727,6 +734,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st if (o_arg.seqid == NULL) return -ENOMEM; nfs_fattr_init(&f_attr); + nfs_fattr_init(&dir_attr); status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); if (status != 0) goto out_err; @@ -1746,6 +1754,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr) { struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fattr dir_fattr; struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), .server = server, @@ -1758,6 +1767,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, .server = server, .fh = fhandle, .fattr = fattr, + .dir_fattr = &dir_fattr, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK], @@ -1770,10 +1780,12 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, return -ENAMETOOLONG; arg.u.symlink = path; nfs_fattr_init(fattr); + nfs_fattr_init(&dir_fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); return status; } @@ -1797,7 +1809,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, { struct nfs_server *server = NFS_SERVER(dir); struct nfs_fh fhandle; - struct nfs_fattr fattr; + struct nfs_fattr fattr, dir_fattr; struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), .server = server, @@ -1810,6 +1822,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, .server = server, .fh = &fhandle, .fattr = &fattr, + .dir_fattr = &dir_fattr, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1819,10 +1832,12 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, int status; nfs_fattr_init(&fattr); + nfs_fattr_init(&dir_fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) { update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); status = nfs_instantiate(dentry, &fhandle, &fattr); } return status; @@ -1895,7 +1910,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, { struct nfs_server *server = NFS_SERVER(dir); struct nfs_fh fh; - struct nfs_fattr fattr; + struct nfs_fattr fattr, dir_fattr; struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), .server = server, @@ -1907,6 +1922,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, .server = server, .fh = &fh, .fattr = &fattr, + .dir_fattr = &dir_fattr, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1917,6 +1933,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, int mode = sattr->ia_mode; nfs_fattr_init(&fattr); + nfs_fattr_init(&dir_fattr); BUG_ON(!(sattr->ia_valid & ATTR_MODE)); BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); @@ -1938,6 +1955,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) { update_changeattr(dir, &res.dir_cinfo); + nfs_post_op_update_inode(dir, res.dir_fattr); status = nfs_instantiate(dentry, &fh, &fattr); } return status; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8b21de8a06fa..7f91d613d31a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -95,6 +95,8 @@ static int nfs_stat_to_errno(int); #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) +#define encode_restorefh_maxsz (op_encode_hdr_maxsz) +#define decode_restorefh_maxsz (op_decode_hdr_maxsz) #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) @@ -336,14 +338,20 @@ static int nfs_stat_to_errno(int); decode_getfh_maxsz) #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ + encode_savefh_maxsz + \ encode_create_maxsz + \ + encode_getfh_maxsz + \ encode_getattr_maxsz + \ - encode_getfh_maxsz) + encode_restorefh_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ + decode_savefh_maxsz + \ decode_create_maxsz + \ + decode_getfh_maxsz + \ decode_getattr_maxsz + \ - decode_getfh_maxsz) + decode_restorefh_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz) @@ -1112,6 +1120,17 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client return 0; } +static int +encode_restorefh(struct xdr_stream *xdr) +{ + uint32_t *p; + + RESERVE_SPACE(4); + WRITE32(OP_RESTOREFH); + + return 0; +} + static int encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) { @@ -1358,7 +1377,7 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 7, }; int status; @@ -1366,10 +1385,16 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n encode_compound_hdr(&xdr, &hdr); if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; + if ((status = encode_savefh(&xdr)) != 0) + goto out; if ((status = encode_create(&xdr, args)) != 0) goto out; if ((status = encode_getfh(&xdr)) != 0) goto out; + if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) + goto out; + if ((status = encode_restorefh(&xdr)) != 0) + goto out; status = encode_getfattr(&xdr, args->bitmask); out: return status; @@ -1429,7 +1454,7 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 7, }; int status; @@ -1439,6 +1464,9 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_savefh(&xdr); if (status) goto out; status = encode_open(&xdr, args); @@ -1448,6 +1476,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena if (status) goto out; status = encode_getfattr(&xdr, args->bitmask); + if (status) + goto out; + status = encode_restorefh(&xdr); + if (status) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -3218,6 +3252,12 @@ static int decode_renew(struct xdr_stream *xdr) return decode_op_hdr(xdr, OP_RENEW); } +static int +decode_restorefh(struct xdr_stream *xdr) +{ + return decode_op_hdr(xdr, OP_RESTOREFH); +} + static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, size_t *acl_len) { @@ -3510,13 +3550,17 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ goto out; if ((status = decode_putfh(&xdr)) != 0) goto out; + if ((status = decode_savefh(&xdr)) != 0) + goto out; if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0) goto out; if ((status = decode_getfh(&xdr, res->fh)) != 0) goto out; - status = decode_getfattr(&xdr, res->fattr, res->server); - if (status == NFS4ERR_DELAY) - status = 0; + if (decode_getfattr(&xdr, res->fattr, res->server) != 0) + goto out; + if ((status = decode_restorefh(&xdr)) != 0) + goto out; + decode_getfattr(&xdr, res->dir_fattr, res->server); out: return status; } @@ -3654,15 +3698,20 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ope status = decode_putfh(&xdr); if (status) goto out; + status = decode_savefh(&xdr); + if (status) + goto out; status = decode_open(&xdr, res); if (status) goto out; status = decode_getfh(&xdr, &res->fh); if (status) goto out; - status = decode_getfattr(&xdr, res->f_attr, res->server); - if (status == NFS4ERR_DELAY) - status = 0; + if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) + goto out; + if ((status = decode_restorefh(&xdr)) != 0) + goto out; + decode_getfattr(&xdr, res->dir_attr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index aeaee7e7c51d..6485b8b41b83 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -124,6 +124,7 @@ struct nfs_openres { struct nfs4_change_info cinfo; __u32 rflags; struct nfs_fattr * f_attr; + struct nfs_fattr * dir_attr; const struct nfs_server *server; int delegation_type; nfs4_stateid delegation; @@ -540,6 +541,7 @@ struct nfs4_create_res { struct nfs_fh * fh; struct nfs_fattr * fattr; struct nfs4_change_info dir_cinfo; + struct nfs_fattr * dir_fattr; }; struct nfs4_fsinfo_arg { From 3338c143b4fde2d256016b63043ec8e2c93eba19 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:41 -0400 Subject: [PATCH 0787/1939] NFS: Optimise attribute revalidation on close(). Only force a getattr in nfs_file_flush() if the attribute cache is stale. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 572d8593486f..57d3e77d97ee 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -205,8 +205,8 @@ nfs_file_flush(struct file *file) if (!status) { status = ctx->error; ctx->error = 0; - if (!status && !nfs_have_delegation(inode, FMODE_READ)) - __nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (!status) + nfs_revalidate_inode(NFS_SERVER(inode), inode); } unlock_kernel(); return status; From 516a6af641bb50c608329a5bd751acd0d65cc4ab Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:41 -0400 Subject: [PATCH 0788/1939] NFS: Add optional post-op getattr instruction to the NFSv4 file close. "Optional" means that the close call will not fail if the getattr at the end of the compound fails. If it does succeed, try to refresh inode attributes. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 9 ++++++++- fs/nfs/nfs4xdr.c | 34 ++++++++++++++++++++++++++++------ include/linux/nfs_xdr.h | 3 +++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f363fd6c7f4d..7be3d2d15d6f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -865,6 +865,7 @@ struct nfs4_closedata { struct nfs4_state *state; struct nfs_closeargs arg; struct nfs_closeres res; + struct nfs_fattr fattr; }; static void nfs4_free_closedata(struct nfs4_closedata *calldata) @@ -904,6 +905,7 @@ static void nfs4_close_done(struct rpc_task *task) return; } } + nfs_refresh_inode(calldata->inode, calldata->res.fattr); state->state = calldata->arg.open_flags; nfs4_free_closedata(calldata); } @@ -941,6 +943,7 @@ static void nfs4_close_begin(struct rpc_task *task) rpc_exit(task, 0); return; } + nfs_fattr_init(calldata->res.fattr); if (mode != 0) msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; calldata->arg.open_flags = mode; @@ -960,6 +963,7 @@ static void nfs4_close_begin(struct rpc_task *task) */ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) { + struct nfs_server *server = NFS_SERVER(inode); struct nfs4_closedata *calldata; int status = -ENOMEM; @@ -974,8 +978,11 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); if (calldata->arg.seqid == NULL) goto out_free_calldata; + calldata->arg.bitmask = server->attr_bitmask; + calldata->res.fattr = &calldata->fattr; + calldata->res.server = server; - status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_close_begin, + status = nfs4_call_async(server->client, nfs4_close_begin, nfs4_close_done, calldata); if (status == 0) goto out; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7f91d613d31a..cd9e26cfa868 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -198,17 +198,21 @@ static int nfs_stat_to_errno(int); #define NFS4_enc_open_downgrade_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 7) + op_encode_hdr_maxsz + 7 + \ + encode_getattr_maxsz) #define NFS4_dec_open_downgrade_sz \ (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4) + op_decode_hdr_maxsz + 4 + \ + decode_getattr_maxsz) #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 5) + op_encode_hdr_maxsz + 5 + \ + encode_getattr_maxsz) #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4) + op_decode_hdr_maxsz + 4 + \ + decode_getattr_maxsz) #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + 4 + \ @@ -1433,7 +1437,7 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; @@ -1443,6 +1447,9 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos if(status) goto out; status = encode_close(&xdr, args); + if (status != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -1541,7 +1548,7 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; @@ -1551,6 +1558,9 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct if (status) goto out; status = encode_open_downgrade(&xdr, args); + if (status != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -3403,6 +3413,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, stru if (status) goto out; status = decode_open_downgrade(&xdr, res); + if (status != 0) + goto out; + decode_getfattr(&xdr, res->fattr, res->server); out: return status; } @@ -3678,6 +3691,15 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_cl if (status) goto out; status = decode_close(&xdr, res); + if (status != 0) + goto out; + /* + * Note: Server may do delete on close for this file + * in which case the getattr call will fail with + * an ESTALE error. Shouldn't be a problem, + * though, since fattr->valid will remain unset. + */ + decode_getfattr(&xdr, res->fattr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6485b8b41b83..4f03dc21cf4a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -153,10 +153,13 @@ struct nfs_closeargs { nfs4_stateid * stateid; struct nfs_seqid * seqid; int open_flags; + const u32 * bitmask; }; struct nfs_closeres { nfs4_stateid stateid; + struct nfs_fattr * fattr; + const struct nfs_server *server; }; /* * * Arguments to the lock,lockt, and locku call. From cf809556149f076b7a020c10e066b2b96e79b6a1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:42 -0400 Subject: [PATCH 0789/1939] NFS: Ensure that nfs_link() instantiates the dentry correctly Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ce8f77dadff9..8272ed3fc707 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1432,17 +1432,14 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) old_dentry->d_parent->d_name.name, old_dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name); - /* - * Drop the dentry in advance to force a new lookup. - * Since nfs_proc_link doesn't return a file handle, - * we can't use the existing dentry. - */ lock_kernel(); - d_drop(dentry); - nfs_begin_data_update(dir); nfs_begin_data_update(inode); error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); + if (error == 0) { + atomic_inc(&inode->i_count); + d_instantiate(dentry, inode); + } nfs_end_data_update(inode); nfs_end_data_update(dir); unlock_kernel(); From 91ba2eeec5e8e86e054937eb3bf5aec5b22b1830 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:42 -0400 Subject: [PATCH 0790/1939] NFSv4: Add post-op attributes to nfs4_proc_link() Optimise attribute revalidation when hardlinking. Add post-op attributes for the directory and the original inode. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 22 +++++++++++++++++----- fs/nfs/nfs4xdr.c | 34 ++++++++++++++++++++++++++++------ include/linux/nfs_xdr.h | 9 +++++++++ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7be3d2d15d6f..04995e39e867 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1724,22 +1724,34 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { + struct nfs_server *server = NFS_SERVER(inode); struct nfs4_link_arg arg = { .fh = NFS_FH(inode), .dir_fh = NFS_FH(dir), .name = name, + .bitmask = server->attr_bitmask, + }; + struct nfs_fattr fattr, dir_attr; + struct nfs4_link_res res = { + .server = server, + .fattr = &fattr, + .dir_attr = &dir_attr, }; - struct nfs4_change_info cinfo = { }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], .rpc_argp = &arg, - .rpc_resp = &cinfo, + .rpc_resp = &res, }; int status; - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); - if (!status) - update_changeattr(dir, &cinfo); + nfs_fattr_init(res.fattr); + nfs_fattr_init(res.dir_attr); + status = rpc_call_sync(server->client, &msg, 0); + if (!status) { + update_changeattr(dir, &res.cinfo); + nfs_post_op_update_inode(dir, res.dir_attr); + nfs_refresh_inode(inode, res.fattr); + } return status; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index cd9e26cfa868..f624b693ce21 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -324,12 +324,18 @@ static int nfs_stat_to_errno(int); encode_putfh_maxsz + \ encode_savefh_maxsz + \ encode_putfh_maxsz + \ - encode_link_maxsz) + encode_link_maxsz + \ + decode_getattr_maxsz + \ + encode_restorefh_maxsz + \ + decode_getattr_maxsz) #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_savefh_maxsz + \ decode_putfh_maxsz + \ - decode_link_maxsz) + decode_link_maxsz + \ + decode_getattr_maxsz + \ + decode_restorefh_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_symlink_maxsz + \ @@ -1357,7 +1363,7 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 7, }; int status; @@ -1369,7 +1375,13 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs goto out; if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; - status = encode_link(&xdr, args->name); + if ((status = encode_link(&xdr, args->name)) != 0) + goto out; + if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) + goto out; + if ((status = encode_restorefh(&xdr)) != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -3529,7 +3541,7 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ /* * Decode LINK response */ -static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3544,7 +3556,17 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ch goto out; if ((status = decode_putfh(&xdr)) != 0) goto out; - status = decode_link(&xdr, cinfo); + if ((status = decode_link(&xdr, &res->cinfo)) != 0) + goto out; + /* + * Note order: OP_LINK leaves the directory as the current + * filehandle. + */ + if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0) + goto out; + if ((status = decode_restorefh(&xdr)) != 0) + goto out; + decode_getfattr(&xdr, res->fattr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 4f03dc21cf4a..89238b799cfd 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -566,8 +566,17 @@ struct nfs4_link_arg { const struct nfs_fh * fh; const struct nfs_fh * dir_fh; const struct qstr * name; + const u32 * bitmask; }; +struct nfs4_link_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; + struct nfs4_change_info cinfo; + struct nfs_fattr * dir_attr; +}; + + struct nfs4_lookup_arg { const struct nfs_fh * dir_fh; const struct qstr * name; From 6caf2c8276d371679a798058e8fdf49f5ff831a3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:43 -0400 Subject: [PATCH 0791/1939] NFSv4: Add post-op attributes to nfs4_proc_rename() Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 15 +++++++++++++-- fs/nfs/nfs4xdr.c | 29 ++++++++++++++++++++++++----- include/linux/nfs_xdr.h | 4 ++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 04995e39e867..f96bc12c0fa0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1685,13 +1685,20 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name) { + struct nfs_server *server = NFS_SERVER(old_dir); struct nfs4_rename_arg arg = { .old_dir = NFS_FH(old_dir), .new_dir = NFS_FH(new_dir), .old_name = old_name, .new_name = new_name, + .bitmask = server->attr_bitmask, + }; + struct nfs_fattr old_fattr, new_fattr; + struct nfs4_rename_res res = { + .server = server, + .old_fattr = &old_fattr, + .new_fattr = &new_fattr, }; - struct nfs4_rename_res res = { }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], .rpc_argp = &arg, @@ -1699,11 +1706,15 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, }; int status; - status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); + nfs_fattr_init(res.old_fattr); + nfs_fattr_init(res.new_fattr); + status = rpc_call_sync(server->client, &msg, 0); if (!status) { update_changeattr(old_dir, &res.old_cinfo); + nfs_post_op_update_inode(old_dir, res.old_fattr); update_changeattr(new_dir, &res.new_cinfo); + nfs_post_op_update_inode(new_dir, res.new_fattr); } return status; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index f624b693ce21..2a07755bd347 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -314,12 +314,18 @@ static int nfs_stat_to_errno(int); encode_putfh_maxsz + \ encode_savefh_maxsz + \ encode_putfh_maxsz + \ - encode_rename_maxsz) + encode_rename_maxsz + \ + encode_getattr_maxsz + \ + encode_restorefh_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_savefh_maxsz + \ decode_putfh_maxsz + \ - decode_rename_maxsz) + decode_rename_maxsz + \ + decode_getattr_maxsz + \ + decode_restorefh_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_savefh_maxsz + \ @@ -1339,7 +1345,7 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct n { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 7, }; int status; @@ -1351,7 +1357,13 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct n goto out; if ((status = encode_putfh(&xdr, args->new_dir)) != 0) goto out; - status = encode_rename(&xdr, args->old_name, args->new_name); + if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0) + goto out; + if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) + goto out; + if ((status = encode_restorefh(&xdr)) != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -3533,7 +3545,14 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ goto out; if ((status = decode_putfh(&xdr)) != 0) goto out; - status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo); + if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) + goto out; + /* Current FH is target directory */ + if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0) + goto out; + if ((status = decode_restorefh(&xdr)) != 0) + goto out; + decode_getfattr(&xdr, res->old_fattr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 89238b799cfd..6f0804280824 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -630,11 +630,15 @@ struct nfs4_rename_arg { const struct nfs_fh * new_dir; const struct qstr * old_name; const struct qstr * new_name; + const u32 * bitmask; }; struct nfs4_rename_res { + const struct nfs_server * server; struct nfs4_change_info old_cinfo; + struct nfs_fattr * old_fattr; struct nfs4_change_info new_cinfo; + struct nfs_fattr * new_fattr; }; struct nfs4_setclientid { From 16e429596dec4d28e16812b3a9be27f18412c567 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:44 -0400 Subject: [PATCH 0792/1939] NFSv4: Add post-op attributes to nfs4_proc_remove() Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 27 +++++++++++++++++++++------ fs/nfs/nfs4xdr.c | 25 +++++++++++++++++-------- include/linux/nfs_xdr.h | 7 +++++++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f96bc12c0fa0..bab47c4cb41c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1614,11 +1614,17 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) { + struct nfs_server *server = NFS_SERVER(dir); struct nfs4_remove_arg args = { .fh = NFS_FH(dir), .name = name, + .bitmask = server->attr_bitmask, + }; + struct nfs_fattr dir_attr; + struct nfs4_remove_res res = { + .server = server, + .dir_attr = &dir_attr, }; - struct nfs4_change_info res; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], .rpc_argp = &args, @@ -1626,9 +1632,12 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) }; int status; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); - if (status == 0) - update_changeattr(dir, &res); + nfs_fattr_init(res.dir_attr); + status = rpc_call_sync(server->client, &msg, 0); + if (status == 0) { + update_changeattr(dir, &res.cinfo); + nfs_post_op_update_inode(dir, res.dir_attr); + } return status; } @@ -1646,12 +1655,14 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) struct unlink_desc { struct nfs4_remove_arg args; - struct nfs4_change_info res; + struct nfs4_remove_res res; + struct nfs_fattr dir_attr; }; static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { + struct nfs_server *server = NFS_SERVER(dir->d_inode); struct unlink_desc *up; up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); @@ -1660,6 +1671,9 @@ static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, up->args.fh = NFS_FH(dir->d_inode); up->args.name = name; + up->args.bitmask = server->attr_bitmask; + up->res.server = server; + up->res.dir_attr = &up->dir_attr; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; msg->rpc_argp = &up->args; @@ -1674,7 +1688,8 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) if (msg->rpc_resp != NULL) { up = container_of(msg->rpc_resp, struct unlink_desc, res); - update_changeattr(dir->d_inode, &up->res); + update_changeattr(dir->d_inode, &up->res.cinfo); + nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr); kfree(up); msg->rpc_resp = NULL; msg->rpc_argp = NULL; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 2a07755bd347..3ee3a1669d28 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -306,10 +306,12 @@ static int nfs_stat_to_errno(int); decode_getfh_maxsz) #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_remove_maxsz) + encode_remove_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 5) + op_decode_hdr_maxsz + 5 + \ + decode_getattr_maxsz) #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_savefh_maxsz + \ @@ -1327,14 +1329,18 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct n { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - if ((status = encode_putfh(&xdr, args->fh)) == 0) - status = encode_remove(&xdr, args->name); + if ((status = encode_putfh(&xdr, args->fh)) != 0) + goto out; + if ((status = encode_remove(&xdr, args->name)) != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); +out: return status; } @@ -3512,7 +3518,7 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct /* * Decode REMOVE response */ -static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3521,8 +3527,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) == 0) - status = decode_remove(&xdr, cinfo); + if ((status = decode_putfh(&xdr)) != 0) + goto out; + if ((status = decode_remove(&xdr, &res->cinfo)) != 0) + goto out; + decode_getfattr(&xdr, res->dir_attr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6f0804280824..deeba7e2c518 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -623,6 +623,13 @@ struct nfs4_readlink { struct nfs4_remove_arg { const struct nfs_fh * fh; const struct qstr * name; + const u32 * bitmask; +}; + +struct nfs4_remove_res { + const struct nfs_server * server; + struct nfs4_change_info cinfo; + struct nfs_fattr * dir_attr; }; struct nfs4_rename_arg { From 4f9838c7ecd14f31f701f64fa65ded132fc0db8a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:44 -0400 Subject: [PATCH 0793/1939] NFSv4: Add post-op attributes to NFSv4 write and commit callbacks. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 13 ++++++++++++- fs/nfs/nfs4xdr.c | 28 ++++++++++++++++++++++------ include/linux/nfs_xdr.h | 2 ++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index bab47c4cb41c..933e13b383f8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2169,8 +2169,10 @@ nfs4_write_done(struct rpc_task *task) rpc_restart_call(task); return; } - if (task->tk_status >= 0) + if (task->tk_status >= 0) { renew_lease(NFS_SERVER(inode), data->timestamp); + nfs_post_op_update_inode(inode, data->res.fattr); + } /* Call back common NFS writeback processing */ nfs_writeback_done(task); } @@ -2186,6 +2188,7 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) .rpc_cred = data->cred, }; struct inode *inode = data->inode; + struct nfs_server *server = NFS_SERVER(inode); int stable; int flags; @@ -2197,6 +2200,8 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) } else stable = NFS_UNSTABLE; data->args.stable = stable; + data->args.bitmask = server->attr_bitmask; + data->res.server = server; data->timestamp = jiffies; @@ -2218,6 +2223,8 @@ nfs4_commit_done(struct rpc_task *task) rpc_restart_call(task); return; } + if (task->tk_status >= 0) + nfs_post_op_update_inode(inode, data->res.fattr); /* Call back common NFS writeback processing */ nfs_commit_done(task); } @@ -2233,8 +2240,12 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) .rpc_cred = data->cred, }; struct inode *inode = data->inode; + struct nfs_server *server = NFS_SERVER(inode); int flags; + data->args.bitmask = server->attr_bitmask; + data->res.server = server; + /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3ee3a1669d28..6f1bf182e0e0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -159,16 +159,20 @@ static int nfs_stat_to_errno(int); op_decode_hdr_maxsz + 2) #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 8) + op_encode_hdr_maxsz + 8 + \ + encode_getattr_maxsz) #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4) + op_decode_hdr_maxsz + 4 + \ + decode_getattr_maxsz) #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 3) + op_encode_hdr_maxsz + 3 + \ + encode_getattr_maxsz) #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 2) + op_decode_hdr_maxsz + 2 + \ + decode_getattr_maxsz) #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + \ @@ -1799,7 +1803,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writ { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; @@ -1809,6 +1813,9 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writ if (status) goto out; status = encode_write(&xdr, args); + if (status) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -1820,7 +1827,7 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_wri { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; @@ -1830,6 +1837,9 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_wri if (status) goto out; status = encode_commit(&xdr, args); + if (status) + goto out; + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -4001,6 +4011,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_wr if (status) goto out; status = decode_write(&xdr, res); + if (status) + goto out; + decode_getfattr(&xdr, res->fattr, res->server); if (!status) status = res->count; out: @@ -4024,6 +4037,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_w if (status) goto out; status = decode_commit(&xdr, res); + if (status) + goto out; + decode_getfattr(&xdr, res->fattr, res->server); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index deeba7e2c518..40718669b9c8 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -256,6 +256,7 @@ struct nfs_writeargs { enum nfs3_stable_how stable; unsigned int pgbase; struct page ** pages; + const u32 * bitmask; }; struct nfs_writeverf { @@ -267,6 +268,7 @@ struct nfs_writeres { struct nfs_fattr * fattr; struct nfs_writeverf * verf; __u32 count; + const struct nfs_server *server; }; /* From 16c32b71bc53d6f7143702ebb264b4ef20d8f1e5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:45 -0400 Subject: [PATCH 0794/1939] NFSv4: Convert unnecessary XDR warning messages into dprintk() Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6f1bf182e0e0..fbbace8a30c4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2766,8 +2766,7 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re goto xdr_error; status = verify_attr_len(xdr, savep, attrlen); xdr_error: - if (status != 0) - printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); return status; } @@ -2800,8 +2799,7 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) status = verify_attr_len(xdr, savep, attrlen); xdr_error: - if (status != 0) - printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); return status; } @@ -2826,8 +2824,7 @@ static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf status = verify_attr_len(xdr, savep, attrlen); xdr_error: - if (status != 0) - printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); return status; } @@ -2886,8 +2883,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; xdr_error: - if (status != 0) - printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d\n", __FUNCTION__, -status); return status; } @@ -2920,8 +2916,7 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) status = verify_attr_len(xdr, savep, attrlen); xdr_error: - if (status != 0) - printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); return status; } @@ -3088,7 +3083,7 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) p += bmlen; return decode_delegation(xdr, res); xdr_error: - printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__); + dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); return -EIO; } From bec273b491bd16351a9cdb8e9a51d30afa7fe9f4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:45 -0400 Subject: [PATCH 0795/1939] NFS: Allow files that are open for write to invalidate caches Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6b3156e15350..f2781ca42761 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1057,15 +1057,11 @@ int nfs_open(struct inode *inode, struct file *filp) ctx->mode = filp->f_mode; nfs_file_set_open_context(filp, ctx); put_nfs_open_context(ctx); - if ((filp->f_mode & FMODE_WRITE) != 0) - nfs_begin_data_update(inode); return 0; } int nfs_release(struct inode *inode, struct file *filp) { - if ((filp->f_mode & FMODE_WRITE) != 0) - nfs_end_data_update(inode); nfs_file_clear_open_context(filp); return 0; } From 6070fe6f82c67021367092855c0812a98becf0fa Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 22:12:46 -0400 Subject: [PATCH 0796/1939] RPC: Ensure that nobody can queue up new upcalls after rpc_close_pipes() Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ded6c63f11ec..4f188d0a5d11 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -76,25 +76,35 @@ int rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) { struct rpc_inode *rpci = RPC_I(inode); - int res = 0; + int res = -EPIPE; down(&inode->i_sem); + if (rpci->ops == NULL) + goto out; if (rpci->nreaders) { list_add_tail(&msg->list, &rpci->pipe); rpci->pipelen += msg->len; + res = 0; } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { if (list_empty(&rpci->pipe)) schedule_delayed_work(&rpci->queue_timeout, RPC_UPCALL_TIMEOUT); list_add_tail(&msg->list, &rpci->pipe); rpci->pipelen += msg->len; - } else - res = -EPIPE; + res = 0; + } +out: up(&inode->i_sem); wake_up(&rpci->waitq); return res; } +static inline void +rpc_inode_setowner(struct inode *inode, void *private) +{ + RPC_I(inode)->private = private; +} + static void rpc_close_pipes(struct inode *inode) { @@ -111,15 +121,10 @@ rpc_close_pipes(struct inode *inode) rpci->ops->release_pipe(inode); rpci->ops = NULL; } + rpc_inode_setowner(inode, NULL); up(&inode->i_sem); } -static inline void -rpc_inode_setowner(struct inode *inode, void *private) -{ - RPC_I(inode)->private = private; -} - static struct inode * rpc_alloc_inode(struct super_block *sb) { @@ -501,7 +506,6 @@ rpc_depopulate(struct dentry *parent) dentry = dvec[--n]; if (dentry->d_inode) { rpc_close_pipes(dentry->d_inode); - rpc_inode_setowner(dentry->d_inode, NULL); simple_unlink(dir, dentry); } dput(dentry); @@ -576,10 +580,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry) int error; shrink_dcache_parent(dentry); - if (dentry->d_inode) { + if (dentry->d_inode) rpc_close_pipes(dentry->d_inode); - rpc_inode_setowner(dentry->d_inode, NULL); - } if ((error = simple_rmdir(dir, dentry)) != 0) return error; if (!error) { @@ -732,7 +734,6 @@ rpc_unlink(char *path) d_drop(dentry); if (dentry->d_inode) { rpc_close_pipes(dentry->d_inode); - rpc_inode_setowner(dentry->d_inode, NULL); error = simple_unlink(dir, dentry); } dput(dentry); From 640768eef245f1578e75e02c17d277a1496a535b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 28 Oct 2005 12:51:45 +1000 Subject: [PATCH 0797/1939] ppc64: use the merged syscall table This allows us to also use entry_64.S from the merged tree and reverts the setup_64.c part of fda262b8978d0089758ef9444508434c74113a61. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/Makefile | 9 +- arch/powerpc/kernel/setup_64.c | 18 +- arch/ppc64/Makefile | 1 + arch/ppc64/kernel/Makefile | 2 +- arch/ppc64/kernel/entry.S | 845 --------------------------------- arch/ppc64/kernel/misc.S | 563 ---------------------- 6 files changed, 12 insertions(+), 1426 deletions(-) delete mode 100644 arch/ppc64/kernel/entry.S diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 68543201df3d..0118e516b01f 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -13,7 +13,7 @@ endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ signal_32.o pmc.o obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ - ptrace32.o + ptrace32.o systbl.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o @@ -28,12 +28,12 @@ extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o -extra-$(CONFIG_PPC64) += entry_64.o extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ - prom.o systbl.o traps.o setup-common.o -obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o + prom.o traps.o setup-common.o +obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o \ + systbl.o obj-$(CONFIG_PPC64) += misc_64.o obj-$(CONFIG_PPC_OF) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o @@ -53,3 +53,4 @@ obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o \ endif extra-$(CONFIG_PPC_FPU) += fpu.o +extra-$(CONFIG_PPC64) += entry_64.o diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index a8f7ff5ab1a4..950e6f0fea98 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -701,17 +701,6 @@ static void __init emergency_stack_init(void) limit)) + PAGE_SIZE; } -extern unsigned long *sys_call_table; -extern unsigned long sys_ni_syscall; -#ifdef CONFIG_PPC_MERGE -#define SYS_CALL_ENTRY64(i) sys_call_table[(i) * 2] -#define SYS_CALL_ENTRY32(i) sys_call_table[(i) * 2 + 1] -#else -extern unsigned long *sys_call_table32; -#define SYS_CALL_ENTRY64(i) sys_call_table[(i)] -#define SYS_CALL_ENTRY32(i) sys_call_table32[(i)] -#endif - /* * Called from setup_arch to initialize the bitmap of available * syscalls in the systemcfg page @@ -719,14 +708,17 @@ extern unsigned long *sys_call_table32; void __init setup_syscall_map(void) { unsigned int i, count64 = 0, count32 = 0; + extern unsigned long *sys_call_table; + extern unsigned long sys_ni_syscall; + for (i = 0; i < __NR_syscalls; i++) { - if (SYS_CALL_ENTRY64(i) != sys_ni_syscall) { + if (sys_call_table[i*2] != sys_ni_syscall) { count64++; systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); } - if (SYS_CALL_ENTRY32(i) != sys_ni_syscall) { + if (sys_call_table[i*2+1] != sys_ni_syscall) { count32++; systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index ba59225fd373..66ee04f13b26 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -81,6 +81,7 @@ CFLAGS += $(call cc-option,-funit-at-a-time) head-y := arch/ppc64/kernel/head.o head-y += arch/powerpc/kernel/fpu.o +head-y += arch/powerpc/kernel/entry_64.o libs-y += arch/ppc64/lib/ core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 863bd7d746fb..a20a305b825d 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -7,7 +7,7 @@ ifneq ($(CONFIG_PPC_MERGE),y) EXTRA_CFLAGS += -mno-minimal-toc extra-y := head.o vmlinux.lds -obj-y := entry.o misc.o prom.o +obj-y := misc.o prom.o endif diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S deleted file mode 100644 index 5d2fcbe384c1..000000000000 --- a/arch/ppc64/kernel/entry.S +++ /dev/null @@ -1,845 +0,0 @@ -/* - * arch/ppc64/kernel/entry.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). - * - * This file contains the system call entry code, context switch - * code, and exception/interrupt return code for PowerPC. - * - * 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 - -#ifdef CONFIG_PPC_ISERIES -#define DO_SOFT_DISABLE -#endif - -/* - * System calls. - */ - .section ".toc","aw" -.SYS_CALL_TABLE: - .tc .sys_call_table[TC],.sys_call_table - -.SYS_CALL_TABLE32: - .tc .sys_call_table32[TC],.sys_call_table32 - -/* This value is used to mark exception frames on the stack. */ -exception_marker: - .tc ID_72656773_68657265[TC],0x7265677368657265 - - .section ".text" - .align 7 - -#undef SHOW_SYSCALLS - - .globl system_call_common -system_call_common: - andi. r10,r12,MSR_PR - mr r10,r1 - addi r1,r1,-INT_FRAME_SIZE - beq- 1f - ld r1,PACAKSAVE(r13) -1: std r10,0(r1) - std r11,_NIP(r1) - std r12,_MSR(r1) - std r0,GPR0(r1) - std r10,GPR1(r1) - std r2,GPR2(r1) - std r3,GPR3(r1) - std r4,GPR4(r1) - std r5,GPR5(r1) - std r6,GPR6(r1) - std r7,GPR7(r1) - std r8,GPR8(r1) - li r11,0 - std r11,GPR9(r1) - std r11,GPR10(r1) - std r11,GPR11(r1) - std r11,GPR12(r1) - std r9,GPR13(r1) - crclr so - mfcr r9 - mflr r10 - li r11,0xc01 - std r9,_CCR(r1) - std r10,_LINK(r1) - std r11,_TRAP(r1) - mfxer r9 - mfctr r10 - std r9,_XER(r1) - std r10,_CTR(r1) - std r3,ORIG_GPR3(r1) - ld r2,PACATOC(r13) - addi r9,r1,STACK_FRAME_OVERHEAD - ld r11,exception_marker@toc(r2) - std r11,-16(r9) /* "regshere" marker */ -#ifdef CONFIG_PPC_ISERIES - /* Hack for handling interrupts when soft-enabling on iSeries */ - cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ - andi. r10,r12,MSR_PR /* from kernel */ - crand 4*cr0+eq,4*cr1+eq,4*cr0+eq - beq hardware_interrupt_entry - lbz r10,PACAPROCENABLED(r13) - std r10,SOFTE(r1) -#endif - mfmsr r11 - ori r11,r11,MSR_EE - mtmsrd r11,1 - -#ifdef SHOW_SYSCALLS - bl .do_show_syscall - REST_GPR(0,r1) - REST_4GPRS(3,r1) - REST_2GPRS(7,r1) - addi r9,r1,STACK_FRAME_OVERHEAD -#endif - clrrdi r11,r1,THREAD_SHIFT - li r12,0 - ld r10,TI_FLAGS(r11) - stb r12,TI_SC_NOERR(r11) - andi. r11,r10,_TIF_SYSCALL_T_OR_A - bne- syscall_dotrace -syscall_dotrace_cont: - cmpldi 0,r0,NR_syscalls - bge- syscall_enosys - -system_call: /* label this so stack traces look sane */ -/* - * Need to vector to 32 Bit or default sys_call_table here, - * based on caller's run-mode / personality. - */ - ld r11,.SYS_CALL_TABLE@toc(2) - andi. r10,r10,_TIF_32BIT - beq 15f - ld r11,.SYS_CALL_TABLE32@toc(2) - clrldi r3,r3,32 - clrldi r4,r4,32 - clrldi r5,r5,32 - clrldi r6,r6,32 - clrldi r7,r7,32 - clrldi r8,r8,32 -15: - slwi r0,r0,3 - ldx r10,r11,r0 /* Fetch system call handler [ptr] */ - mtctr r10 - bctrl /* Call handler */ - -syscall_exit: -#ifdef SHOW_SYSCALLS - std r3,GPR3(r1) - bl .do_show_syscall_exit - ld r3,GPR3(r1) -#endif - std r3,RESULT(r1) - ld r5,_CCR(r1) - li r10,-_LAST_ERRNO - cmpld r3,r10 - clrrdi r12,r1,THREAD_SHIFT - bge- syscall_error -syscall_error_cont: - - /* check for syscall tracing or audit */ - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - bne- syscall_exit_trace -syscall_exit_trace_cont: - - /* disable interrupts so current_thread_info()->flags can't change, - and so that we don't get interrupted after loading SRR0/1. */ - ld r8,_MSR(r1) - andi. r10,r8,MSR_RI - beq- unrecov_restore - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 - mtmsrd r10,1 - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) - bne- syscall_exit_work - ld r7,_NIP(r1) - stdcx. r0,0,r1 /* to clear the reservation */ - andi. r6,r8,MSR_PR - ld r4,_LINK(r1) - beq- 1f /* only restore r13 if */ - ld r13,GPR13(r1) /* returning to usermode */ -1: ld r2,GPR2(r1) - li r12,MSR_RI - andc r10,r10,r12 - mtmsrd r10,1 /* clear MSR.RI */ - ld r1,GPR1(r1) - mtlr r4 - mtcr r5 - mtspr SPRN_SRR0,r7 - mtspr SPRN_SRR1,r8 - rfid - b . /* prevent speculative execution */ - -syscall_enosys: - li r3,-ENOSYS - std r3,RESULT(r1) - clrrdi r12,r1,THREAD_SHIFT - ld r5,_CCR(r1) - -syscall_error: - lbz r11,TI_SC_NOERR(r12) - cmpwi 0,r11,0 - bne- syscall_error_cont - neg r3,r3 - oris r5,r5,0x1000 /* Set SO bit in CR */ - std r5,_CCR(r1) - b syscall_error_cont - -/* Traced system call support */ -syscall_dotrace: - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_enter - ld r0,GPR0(r1) /* Restore original registers */ - ld r3,GPR3(r1) - ld r4,GPR4(r1) - ld r5,GPR5(r1) - ld r6,GPR6(r1) - ld r7,GPR7(r1) - ld r8,GPR8(r1) - addi r9,r1,STACK_FRAME_OVERHEAD - clrrdi r10,r1,THREAD_SHIFT - ld r10,TI_FLAGS(r10) - b syscall_dotrace_cont - -syscall_exit_trace: - std r3,GPR3(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave - REST_NVGPRS(r1) - ld r3,GPR3(r1) - ld r5,_CCR(r1) - clrrdi r12,r1,THREAD_SHIFT - b syscall_exit_trace_cont - -/* Stuff to do on exit from a system call. */ -syscall_exit_work: - std r3,GPR3(r1) - std r5,_CCR(r1) - b .ret_from_except_lite - -/* Save non-volatile GPRs, if not already saved. */ -_GLOBAL(save_nvgprs) - ld r11,_TRAP(r1) - andi. r0,r11,1 - beqlr- - SAVE_NVGPRS(r1) - clrrdi r0,r11,1 - std r0,_TRAP(r1) - blr - -/* - * The sigsuspend and rt_sigsuspend system calls can call do_signal - * and thus put the process into the stopped state where we might - * want to examine its user state with ptrace. Therefore we need - * to save all the nonvolatile registers (r14 - r31) before calling - * the C code. Similarly, fork, vfork and clone need the full - * register state on the stack so that it can be copied to the child. - */ -_GLOBAL(ppc32_sigsuspend) - bl .save_nvgprs - bl .compat_sys_sigsuspend - b 70f - -_GLOBAL(ppc64_rt_sigsuspend) - bl .save_nvgprs - bl .sys_rt_sigsuspend - b 70f - -_GLOBAL(ppc32_rt_sigsuspend) - bl .save_nvgprs - bl .compat_sys_rt_sigsuspend -70: cmpdi 0,r3,0 - /* If it returned an error, we need to return via syscall_exit to set - the SO bit in cr0 and potentially stop for ptrace. */ - bne syscall_exit - /* If sigsuspend() returns zero, we are going into a signal handler. We - may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ -#ifdef CONFIG_AUDIT - ld r3,PACACURRENT(r13) - ld r4,AUDITCONTEXT(r3) - cmpdi 0,r4,0 - beq .ret_from_except /* No audit_context: Leave immediately. */ - li r4, 2 /* AUDITSC_FAILURE */ - li r5,-4 /* It's always -EINTR */ - bl .audit_syscall_exit -#endif - b .ret_from_except - -_GLOBAL(ppc_fork) - bl .save_nvgprs - bl .sys_fork - b syscall_exit - -_GLOBAL(ppc_vfork) - bl .save_nvgprs - bl .sys_vfork - b syscall_exit - -_GLOBAL(ppc_clone) - bl .save_nvgprs - bl .sys_clone - b syscall_exit - -_GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .compat_sys_swapcontext - b 80f - -_GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext - b 80f - -_GLOBAL(ppc32_sigreturn) - bl .compat_sys_sigreturn - b 80f - -_GLOBAL(ppc32_rt_sigreturn) - bl .compat_sys_rt_sigreturn - b 80f - -_GLOBAL(ppc64_rt_sigreturn) - bl .sys_rt_sigreturn - -80: cmpdi 0,r3,0 - blt syscall_exit - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq+ 81f - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave -81: b .ret_from_except - -_GLOBAL(ret_from_fork) - bl .schedule_tail - REST_NVGPRS(r1) - li r3,0 - b syscall_exit - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via ret_from_except. - * On entry, r3 points to the THREAD for the current task, r4 - * points to the THREAD for the new task. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this you'll have to change - * the fork code also. - * - * The code which creates the new task context is in 'copy_thread' - * in arch/ppc64/kernel/process.c - */ - .align 7 -_GLOBAL(_switch) - mflr r0 - std r0,16(r1) - stdu r1,-SWITCH_FRAME_SIZE(r1) - /* r3-r13 are caller saved -- Cort */ - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mflr r20 /* Return to switch caller */ - mfmsr r22 - li r0, MSR_FP -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - oris r0,r0,MSR_VEC@h /* Disable altivec */ - mfspr r24,SPRN_VRSAVE /* save vrsave register value */ - std r24,THREAD_VRSAVE(r3) -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - and. r0,r0,r22 - beq+ 1f - andc r22,r22,r0 - mtmsrd r22 - isync -1: std r20,_NIP(r1) - mfcr r23 - std r23,_CCR(r1) - std r1,KSP(r3) /* Set old stack pointer */ - -#ifdef CONFIG_SMP - /* We need a sync somewhere here to make sure that if the - * previous task gets rescheduled on another CPU, it sees all - * stores it has performed on this one. - */ - sync -#endif /* CONFIG_SMP */ - - addi r6,r4,-THREAD /* Convert THREAD to 'current' */ - std r6,PACACURRENT(r13) /* Set new 'current' */ - - ld r8,KSP(r4) /* new stack pointer */ -BEGIN_FTR_SECTION - clrrdi r6,r8,28 /* get its ESID */ - clrrdi r9,r1,28 /* get current sp ESID */ - clrldi. r0,r6,2 /* is new ESID c00000000? */ - cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ - cror eq,4*cr1+eq,eq - beq 2f /* if yes, don't slbie it */ - - /* Bolt in the new stack SLB entry */ - ld r7,KSP_VSID(r4) /* Get new stack's VSID */ - oris r0,r6,(SLB_ESID_V)@h - ori r0,r0,(SLB_NUM_BOLTED-1)@l - slbie r6 - slbie r6 /* Workaround POWER5 < DD2.1 issue */ - slbmte r7,r0 - isync - -2: -END_FTR_SECTION_IFSET(CPU_FTR_SLB) - clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ - /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE - because we don't need to leave the 288-byte ABI gap at the - top of the kernel stack. */ - addi r7,r7,THREAD_SIZE-SWITCH_FRAME_SIZE - - mr r1,r8 /* start using new stack pointer */ - std r7,PACAKSAVE(r13) - - ld r6,_CCR(r1) - mtcrf 0xFF,r6 - -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - ld r0,THREAD_VRSAVE(r4) - mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - - /* r3-r13 are destroyed -- Cort */ - REST_8GPRS(14, r1) - REST_10GPRS(22, r1) - - /* convert old thread to its task_struct for return value */ - addi r3,r3,-THREAD - ld r7,_NIP(r1) /* Return to _switch caller in new task */ - mtlr r7 - addi r1,r1,SWITCH_FRAME_SIZE - blr - - .align 7 -_GLOBAL(ret_from_except) - ld r11,_TRAP(r1) - andi. r0,r11,1 - bne .ret_from_except_lite - REST_NVGPRS(r1) - -_GLOBAL(ret_from_except_lite) - /* - * Disable interrupts so that current_thread_info()->flags - * can't change between when we test it and when we return - * from the interrupt. - */ - mfmsr r10 /* Get current interrupt state */ - rldicl r9,r10,48,1 /* clear MSR_EE */ - rotldi r9,r9,16 - mtmsrd r9,1 /* Update machine state */ - -#ifdef CONFIG_PREEMPT - clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */ - li r0,_TIF_NEED_RESCHED /* bits to check */ - ld r3,_MSR(r1) - ld r4,TI_FLAGS(r9) - /* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */ - rlwimi r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING - and. r0,r4,r0 /* check NEED_RESCHED and maybe SIGPENDING */ - bne do_work - -#else /* !CONFIG_PREEMPT */ - ld r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR - beq restore /* if not, just restore regs and return */ - - /* Check current_thread_info()->flags */ - clrrdi r9,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r9) - andi. r0,r4,_TIF_USER_WORK_MASK - bne do_work -#endif - -restore: -#ifdef CONFIG_PPC_ISERIES - ld r5,SOFTE(r1) - cmpdi 0,r5,0 - beq 4f - /* Check for pending interrupts (iSeries) */ - ld r3,PACALPPACA+LPPACAANYINT(r13) - cmpdi r3,0 - beq+ 4f /* skip do_IRQ if no interrupts */ - - li r3,0 - stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ - ori r10,r10,MSR_EE - mtmsrd r10 /* hard-enable again */ - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_IRQ - b .ret_from_except_lite /* loop back and handle more */ - -4: stb r5,PACAPROCENABLED(r13) -#endif - - ld r3,_MSR(r1) - andi. r0,r3,MSR_RI - beq- unrecov_restore - - andi. r0,r3,MSR_PR - - /* - * r13 is our per cpu area, only restore it if we are returning to - * userspace - */ - beq 1f - REST_GPR(13, r1) -1: - ld r3,_CTR(r1) - ld r0,_LINK(r1) - mtctr r3 - mtlr r0 - ld r3,_XER(r1) - mtspr SPRN_XER,r3 - - REST_8GPRS(5, r1) - - stdcx. r0,0,r1 /* to clear the reservation */ - - mfmsr r0 - li r2, MSR_RI - andc r0,r0,r2 - mtmsrd r0,1 - - ld r0,_MSR(r1) - mtspr SPRN_SRR1,r0 - - ld r2,_CCR(r1) - mtcrf 0xFF,r2 - ld r2,_NIP(r1) - mtspr SPRN_SRR0,r2 - - ld r0,GPR0(r1) - ld r2,GPR2(r1) - ld r3,GPR3(r1) - ld r4,GPR4(r1) - ld r1,GPR1(r1) - - rfid - b . /* prevent speculative execution */ - -/* Note: this must change if we start using the TIF_NOTIFY_RESUME bit */ -do_work: -#ifdef CONFIG_PREEMPT - andi. r0,r3,MSR_PR /* Returning to user mode? */ - bne user_work - /* Check that preempt_count() == 0 and interrupts are enabled */ - lwz r8,TI_PREEMPT(r9) - cmpwi cr1,r8,0 -#ifdef CONFIG_PPC_ISERIES - ld r0,SOFTE(r1) - cmpdi r0,0 -#else - andi. r0,r3,MSR_EE -#endif - crandc eq,cr1*4+eq,eq - bne restore - /* here we are preempting the current task */ -1: -#ifdef CONFIG_PPC_ISERIES - li r0,1 - stb r0,PACAPROCENABLED(r13) -#endif - ori r10,r10,MSR_EE - mtmsrd r10,1 /* reenable interrupts */ - bl .preempt_schedule - mfmsr r10 - clrrdi r9,r1,THREAD_SHIFT - rldicl r10,r10,48,1 /* disable interrupts again */ - rotldi r10,r10,16 - mtmsrd r10,1 - ld r4,TI_FLAGS(r9) - andi. r0,r4,_TIF_NEED_RESCHED - bne 1b - b restore - -user_work: -#endif - /* Enable interrupts */ - ori r10,r10,MSR_EE - mtmsrd r10,1 - - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - bl .schedule - b .ret_from_except_lite - -1: bl .save_nvgprs - li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD - bl .do_signal - b .ret_from_except - -unrecov_restore: - addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b unrecov_restore - -#ifdef CONFIG_PPC_RTAS -/* - * On CHRP, the Run-Time Abstraction Services (RTAS) have to be - * called with the MMU off. - * - * In addition, we need to be in 32b mode, at least for now. - * - * Note: r3 is an input parameter to rtas, so don't trash it... - */ -_GLOBAL(enter_rtas) - mflr r0 - std r0,16(r1) - stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */ - - /* Because RTAS is running in 32b mode, it clobbers the high order half - * of all registers that it saves. We therefore save those registers - * RTAS might touch to the stack. (r0, r3-r13 are caller saved) - */ - SAVE_GPR(2, r1) /* Save the TOC */ - SAVE_GPR(13, r1) /* Save paca */ - SAVE_8GPRS(14, r1) /* Save the non-volatiles */ - SAVE_10GPRS(22, r1) /* ditto */ - - mfcr r4 - std r4,_CCR(r1) - mfctr r5 - std r5,_CTR(r1) - mfspr r6,SPRN_XER - std r6,_XER(r1) - mfdar r7 - std r7,_DAR(r1) - mfdsisr r8 - std r8,_DSISR(r1) - mfsrr0 r9 - std r9,_SRR0(r1) - mfsrr1 r10 - std r10,_SRR1(r1) - - /* There is no way it is acceptable to get here with interrupts enabled, - * check it with the asm equivalent of WARN_ON - */ - mfmsr r6 - andi. r0,r6,MSR_EE -1: tdnei r0,0 -.section __bug_table,"a" - .llong 1b,__LINE__ + 0x1000000, 1f, 2f -.previous -.section .rodata,"a" -1: .asciz __FILE__ -2: .asciz "enter_rtas" -.previous - - /* Unfortunately, the stack pointer and the MSR are also clobbered, - * so they are saved in the PACA which allows us to restore - * our original state after RTAS returns. - */ - std r1,PACAR1(r13) - std r6,PACASAVEDMSR(r13) - - /* Setup our real return addr */ - SET_REG_TO_LABEL(r4,.rtas_return_loc) - SET_REG_TO_CONST(r9,KERNELBASE) - sub r4,r4,r9 - mtlr r4 - - li r0,0 - ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI - andc r0,r6,r0 - - li r9,1 - rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG) - ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP - andc r6,r0,r9 - ori r6,r6,MSR_RI - sync /* disable interrupts so SRR0/1 */ - mtmsrd r0 /* don't get trashed */ - - SET_REG_TO_LABEL(r4,rtas) - ld r5,RTASENTRY(r4) /* get the rtas->entry value */ - ld r4,RTASBASE(r4) /* get the rtas->base value */ - - mtspr SPRN_SRR0,r5 - mtspr SPRN_SRR1,r6 - rfid - b . /* prevent speculative execution */ - -_STATIC(rtas_return_loc) - /* relocation is off at this point */ - mfspr r4,SPRN_SPRG3 /* Get PACA */ - SET_REG_TO_CONST(r5, KERNELBASE) - sub r4,r4,r5 /* RELOC the PACA base pointer */ - - mfmsr r6 - li r0,MSR_RI - andc r6,r6,r0 - sync - mtmsrd r6 - - ld r1,PACAR1(r4) /* Restore our SP */ - LOADADDR(r3,.rtas_restore_regs) - ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ - - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - rfid - b . /* prevent speculative execution */ - -_STATIC(rtas_restore_regs) - /* relocation is on at this point */ - REST_GPR(2, r1) /* Restore the TOC */ - REST_GPR(13, r1) /* Restore paca */ - REST_8GPRS(14, r1) /* Restore the non-volatiles */ - REST_10GPRS(22, r1) /* ditto */ - - mfspr r13,SPRN_SPRG3 - - ld r4,_CCR(r1) - mtcr r4 - ld r5,_CTR(r1) - mtctr r5 - ld r6,_XER(r1) - mtspr SPRN_XER,r6 - ld r7,_DAR(r1) - mtdar r7 - ld r8,_DSISR(r1) - mtdsisr r8 - ld r9,_SRR0(r1) - mtsrr0 r9 - ld r10,_SRR1(r1) - mtsrr1 r10 - - addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */ - ld r0,16(r1) /* get return address */ - - mtlr r0 - blr /* return to caller */ - -#endif /* CONFIG_PPC_RTAS */ - -#ifdef CONFIG_PPC_MULTIPLATFORM - -_GLOBAL(enter_prom) - mflr r0 - std r0,16(r1) - stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ - - /* Because PROM is running in 32b mode, it clobbers the high order half - * of all registers that it saves. We therefore save those registers - * PROM might touch to the stack. (r0, r3-r13 are caller saved) - */ - SAVE_8GPRS(2, r1) - SAVE_GPR(13, r1) - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mfcr r4 - std r4,_CCR(r1) - mfctr r5 - std r5,_CTR(r1) - mfspr r6,SPRN_XER - std r6,_XER(r1) - mfdar r7 - std r7,_DAR(r1) - mfdsisr r8 - std r8,_DSISR(r1) - mfsrr0 r9 - std r9,_SRR0(r1) - mfsrr1 r10 - std r10,_SRR1(r1) - mfmsr r11 - std r11,_MSR(r1) - - /* Get the PROM entrypoint */ - ld r0,GPR4(r1) - mtlr r0 - - /* Switch MSR to 32 bits mode - */ - mfmsr r11 - li r12,1 - rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) - andc r11,r11,r12 - li r12,1 - rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) - andc r11,r11,r12 - mtmsrd r11 - isync - - /* Restore arguments & enter PROM here... */ - ld r3,GPR3(r1) - blrl - - /* Just make sure that r1 top 32 bits didn't get - * corrupt by OF - */ - rldicl r1,r1,0,32 - - /* Restore the MSR (back to 64 bits) */ - ld r0,_MSR(r1) - mtmsrd r0 - isync - - /* Restore other registers */ - REST_GPR(2, r1) - REST_GPR(13, r1) - REST_8GPRS(14, r1) - REST_10GPRS(22, r1) - ld r4,_CCR(r1) - mtcr r4 - ld r5,_CTR(r1) - mtctr r5 - ld r6,_XER(r1) - mtspr SPRN_XER,r6 - ld r7,_DAR(r1) - mtdar r7 - ld r8,_DSISR(r1) - mtdsisr r8 - ld r9,_SRR0(r1) - mtsrr0 r9 - ld r10,_SRR1(r1) - mtsrr1 r10 - - addi r1,r1,PROM_FRAME_SIZE - ld r0,16(r1) - mtlr r0 - blr - -#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 9cae3d5c40e6..077507ffbab8 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -867,566 +867,3 @@ _GLOBAL(kexec_sequence) li r5,0 blr /* image->start(physid, image->start, 0); */ #endif /* CONFIG_KEXEC */ - -/* Why isn't this a) automatic, b) written in 'C'? */ - .balign 8 -_GLOBAL(sys_call_table32) - .llong .sys_restart_syscall /* 0 */ - .llong .sys_exit - .llong .ppc_fork - .llong .sys_read - .llong .sys_write - .llong .compat_sys_open /* 5 */ - .llong .sys_close - .llong .compat_sys_waitpid - .llong .compat_sys_creat - .llong .sys_link - .llong .sys_unlink /* 10 */ - .llong .compat_sys_execve - .llong .sys_chdir - .llong .compat_sys_time - .llong .sys_mknod - .llong .sys_chmod /* 15 */ - .llong .sys_lchown - .llong .sys_ni_syscall /* old break syscall */ - .llong .sys_ni_syscall /* old stat syscall */ - .llong .ppc32_lseek - .llong .sys_getpid /* 20 */ - .llong .compat_sys_mount - .llong .sys_oldumount - .llong .sys_setuid - .llong .sys_getuid - .llong .compat_sys_stime /* 25 */ - .llong .compat_sys_ptrace - .llong .sys_alarm - .llong .sys_ni_syscall /* old fstat syscall */ - .llong .compat_sys_pause - .llong .compat_sys_utime /* 30 */ - .llong .sys_ni_syscall /* old stty syscall */ - .llong .sys_ni_syscall /* old gtty syscall */ - .llong .compat_sys_access - .llong .compat_sys_nice - .llong .sys_ni_syscall /* 35 - old ftime syscall */ - .llong .sys_sync - .llong .compat_sys_kill - .llong .sys_rename - .llong .compat_sys_mkdir - .llong .sys_rmdir /* 40 */ - .llong .sys_dup - .llong .sys_pipe - .llong .compat_sys_times - .llong .sys_ni_syscall /* old prof syscall */ - .llong .sys_brk /* 45 */ - .llong .sys_setgid - .llong .sys_getgid - .llong .sys_signal - .llong .sys_geteuid - .llong .sys_getegid /* 50 */ - .llong .sys_acct - .llong .sys_umount - .llong .sys_ni_syscall /* old lock syscall */ - .llong .compat_sys_ioctl - .llong .compat_sys_fcntl /* 55 */ - .llong .sys_ni_syscall /* old mpx syscall */ - .llong .compat_sys_setpgid - .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys_olduname - .llong .compat_sys_umask /* 60 */ - .llong .sys_chroot - .llong .sys_ustat - .llong .sys_dup2 - .llong .sys_getppid - .llong .sys_getpgrp /* 65 */ - .llong .sys_setsid - .llong .compat_sys_sigaction - .llong .sys_sgetmask - .llong .compat_sys_ssetmask - .llong .sys_setreuid /* 70 */ - .llong .sys_setregid - .llong .ppc32_sigsuspend - .llong .compat_sys_sigpending - .llong .compat_sys_sethostname - .llong .compat_sys_setrlimit /* 75 */ - .llong .compat_sys_old_getrlimit - .llong .compat_sys_getrusage - .llong .compat_sys_gettimeofday - .llong .compat_sys_settimeofday - .llong .compat_sys_getgroups /* 80 */ - .llong .compat_sys_setgroups - .llong .sys_ni_syscall /* old select syscall */ - .llong .sys_symlink - .llong .sys_ni_syscall /* old lstat syscall */ - .llong .compat_sys_readlink /* 85 */ - .llong .sys_uselib - .llong .sys_swapon - .llong .sys_reboot - .llong .old32_readdir - .llong .sys_mmap /* 90 */ - .llong .sys_munmap - .llong .sys_truncate - .llong .sys_ftruncate - .llong .sys_fchmod - .llong .sys_fchown /* 95 */ - .llong .compat_sys_getpriority - .llong .compat_sys_setpriority - .llong .sys_ni_syscall /* old profil syscall */ - .llong .compat_sys_statfs - .llong .compat_sys_fstatfs /* 100 */ - .llong .sys_ni_syscall /* old ioperm syscall */ - .llong .compat_sys_socketcall - .llong .compat_sys_syslog - .llong .compat_sys_setitimer - .llong .compat_sys_getitimer /* 105 */ - .llong .compat_sys_newstat - .llong .compat_sys_newlstat - .llong .compat_sys_newfstat - .llong .sys_uname - .llong .sys_ni_syscall /* 110 old iopl syscall */ - .llong .sys_vhangup - .llong .sys_ni_syscall /* old idle syscall */ - .llong .sys_ni_syscall /* old vm86 syscall */ - .llong .compat_sys_wait4 - .llong .sys_swapoff /* 115 */ - .llong .compat_sys_sysinfo - .llong .sys32_ipc - .llong .sys_fsync - .llong .ppc32_sigreturn - .llong .ppc_clone /* 120 */ - .llong .compat_sys_setdomainname - .llong .ppc_newuname - .llong .sys_ni_syscall /* old modify_ldt syscall */ - .llong .compat_sys_adjtimex - .llong .sys_mprotect /* 125 */ - .llong .compat_sys_sigprocmask - .llong .sys_ni_syscall /* old create_module syscall */ - .llong .sys_init_module - .llong .sys_delete_module - .llong .sys_ni_syscall /* 130 old get_kernel_syms syscall */ - .llong .sys_quotactl - .llong .compat_sys_getpgid - .llong .sys_fchdir - .llong .sys_bdflush - .llong .compat_sys_sysfs /* 135 */ - .llong .ppc64_personality - .llong .sys_ni_syscall /* for afs_syscall */ - .llong .sys_setfsuid - .llong .sys_setfsgid - .llong .sys_llseek /* 140 */ - .llong .compat_sys_getdents - .llong .ppc32_select - .llong .sys_flock - .llong .sys_msync - .llong .compat_sys_readv /* 145 */ - .llong .compat_sys_writev - .llong .compat_sys_getsid - .llong .sys_fdatasync - .llong .compat_sys_sysctl - .llong .sys_mlock /* 150 */ - .llong .sys_munlock - .llong .sys_mlockall - .llong .sys_munlockall - .llong .compat_sys_sched_setparam - .llong .compat_sys_sched_getparam /* 155 */ - .llong .compat_sys_sched_setscheduler - .llong .compat_sys_sched_getscheduler - .llong .sys_sched_yield - .llong .compat_sys_sched_get_priority_max - .llong .compat_sys_sched_get_priority_min /* 160 */ - .llong .compat_sys_sched_rr_get_interval - .llong .compat_sys_nanosleep - .llong .sys_mremap - .llong .sys_setresuid - .llong .sys_getresuid /* 165 */ - .llong .sys_ni_syscall /* old query_module syscall */ - .llong .sys_poll - .llong .compat_sys_nfsservctl - .llong .sys_setresgid - .llong .sys_getresgid /* 170 */ - .llong .compat_sys_prctl - .llong .ppc32_rt_sigreturn - .llong .compat_sys_rt_sigaction - .llong .compat_sys_rt_sigprocmask - .llong .compat_sys_rt_sigpending /* 175 */ - .llong .compat_sys_rt_sigtimedwait - .llong .compat_sys_rt_sigqueueinfo - .llong .ppc32_rt_sigsuspend - .llong .compat_sys_pread64 - .llong .compat_sys_pwrite64 /* 180 */ - .llong .sys_chown - .llong .sys_getcwd - .llong .sys_capget - .llong .sys_capset - .llong .compat_sys_sigaltstack /* 185 */ - .llong .compat_sys_sendfile - .llong .sys_ni_syscall /* reserved for streams1 */ - .llong .sys_ni_syscall /* reserved for streams2 */ - .llong .ppc_vfork - .llong .compat_sys_getrlimit /* 190 */ - .llong .compat_sys_readahead - .llong .compat_sys_mmap2 - .llong .compat_sys_truncate64 - .llong .compat_sys_ftruncate64 - .llong .sys_stat64 /* 195 */ - .llong .sys_lstat64 - .llong .sys_fstat64 - .llong .compat_sys_pciconfig_read - .llong .compat_sys_pciconfig_write - .llong .compat_sys_pciconfig_iobase /* 200 - pciconfig_iobase */ - .llong .sys_ni_syscall /* reserved for MacOnLinux */ - .llong .sys_getdents64 - .llong .sys_pivot_root - .llong .compat_sys_fcntl64 - .llong .sys_madvise /* 205 */ - .llong .sys_mincore - .llong .sys_gettid - .llong .sys_tkill - .llong .sys_setxattr - .llong .sys_lsetxattr /* 210 */ - .llong .sys_fsetxattr - .llong .sys_getxattr - .llong .sys_lgetxattr - .llong .sys_fgetxattr - .llong .sys_listxattr /* 215 */ - .llong .sys_llistxattr - .llong .sys_flistxattr - .llong .sys_removexattr - .llong .sys_lremovexattr - .llong .sys_fremovexattr /* 220 */ - .llong .compat_sys_futex - .llong .compat_sys_sched_setaffinity - .llong .compat_sys_sched_getaffinity - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ - .llong .compat_sys_sendfile64 - .llong .compat_sys_io_setup - .llong .sys_io_destroy - .llong .compat_sys_io_getevents - .llong .compat_sys_io_submit - .llong .sys_io_cancel - .llong .sys_set_tid_address - .llong .ppc32_fadvise64 - .llong .sys_exit_group - .llong .ppc32_lookup_dcookie /* 235 */ - .llong .sys_epoll_create - .llong .sys_epoll_ctl - .llong .sys_epoll_wait - .llong .sys_remap_file_pages - .llong .ppc32_timer_create /* 240 */ - .llong .compat_sys_timer_settime - .llong .compat_sys_timer_gettime - .llong .sys_timer_getoverrun - .llong .sys_timer_delete - .llong .compat_sys_clock_settime/* 245 */ - .llong .compat_sys_clock_gettime - .llong .compat_sys_clock_getres - .llong .compat_sys_clock_nanosleep - .llong .ppc32_swapcontext - .llong .compat_sys_tgkill /* 250 */ - .llong .compat_sys_utimes - .llong .compat_sys_statfs64 - .llong .compat_sys_fstatfs64 - .llong .ppc_fadvise64_64 /* 32bit only fadvise64_64 */ - .llong .ppc_rtas /* 255 */ - .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ - .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .compat_sys_mbind - .llong .compat_sys_get_mempolicy /* 260 */ - .llong .compat_sys_set_mempolicy - .llong .compat_sys_mq_open - .llong .sys_mq_unlink - .llong .compat_sys_mq_timedsend - .llong .compat_sys_mq_timedreceive /* 265 */ - .llong .compat_sys_mq_notify - .llong .compat_sys_mq_getsetattr - .llong .compat_sys_kexec_load - .llong .compat_sys_add_key - .llong .compat_sys_request_key /* 270 */ - .llong .compat_sys_keyctl - .llong .compat_sys_waitid - .llong .compat_sys_ioprio_set - .llong .compat_sys_ioprio_get - .llong .sys_inotify_init /* 275 */ - .llong .sys_inotify_add_watch - .llong .sys_inotify_rm_watch - - .balign 8 -_GLOBAL(sys_call_table) - .llong .sys_restart_syscall /* 0 */ - .llong .sys_exit - .llong .ppc_fork - .llong .sys_read - .llong .sys_write - .llong .sys_open /* 5 */ - .llong .sys_close - .llong .sys_waitpid - .llong .sys_creat - .llong .sys_link - .llong .sys_unlink /* 10 */ - .llong .sys_execve - .llong .sys_chdir - .llong .sys64_time - .llong .sys_mknod - .llong .sys_chmod /* 15 */ - .llong .sys_lchown - .llong .sys_ni_syscall /* old break syscall */ - .llong .sys_ni_syscall /* old stat syscall */ - .llong .sys_lseek - .llong .sys_getpid /* 20 */ - .llong .sys_mount - .llong .sys_ni_syscall /* old umount syscall */ - .llong .sys_setuid - .llong .sys_getuid - .llong .sys_stime /* 25 */ - .llong .sys_ptrace - .llong .sys_alarm - .llong .sys_ni_syscall /* old fstat syscall */ - .llong .sys_pause - .llong .sys_utime /* 30 */ - .llong .sys_ni_syscall /* old stty syscall */ - .llong .sys_ni_syscall /* old gtty syscall */ - .llong .sys_access - .llong .sys_nice - .llong .sys_ni_syscall /* 35 - old ftime syscall */ - .llong .sys_sync - .llong .sys_kill - .llong .sys_rename - .llong .sys_mkdir - .llong .sys_rmdir /* 40 */ - .llong .sys_dup - .llong .sys_pipe - .llong .sys_times - .llong .sys_ni_syscall /* old prof syscall */ - .llong .sys_brk /* 45 */ - .llong .sys_setgid - .llong .sys_getgid - .llong .sys_signal - .llong .sys_geteuid - .llong .sys_getegid /* 50 */ - .llong .sys_acct - .llong .sys_umount - .llong .sys_ni_syscall /* old lock syscall */ - .llong .sys_ioctl - .llong .sys_fcntl /* 55 */ - .llong .sys_ni_syscall /* old mpx syscall */ - .llong .sys_setpgid - .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys_ni_syscall /* old uname syscall */ - .llong .sys_umask /* 60 */ - .llong .sys_chroot - .llong .sys_ustat - .llong .sys_dup2 - .llong .sys_getppid - .llong .sys_getpgrp /* 65 */ - .llong .sys_setsid - .llong .sys_ni_syscall - .llong .sys_sgetmask - .llong .sys_ssetmask - .llong .sys_setreuid /* 70 */ - .llong .sys_setregid - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_sethostname - .llong .sys_setrlimit /* 75 */ - .llong .sys_ni_syscall /* old getrlimit syscall */ - .llong .sys_getrusage - .llong .sys_gettimeofday - .llong .sys_settimeofday - .llong .sys_getgroups /* 80 */ - .llong .sys_setgroups - .llong .sys_ni_syscall /* old select syscall */ - .llong .sys_symlink - .llong .sys_ni_syscall /* old lstat syscall */ - .llong .sys_readlink /* 85 */ - .llong .sys_uselib - .llong .sys_swapon - .llong .sys_reboot - .llong .sys_ni_syscall /* old readdir syscall */ - .llong .sys_mmap /* 90 */ - .llong .sys_munmap - .llong .sys_truncate - .llong .sys_ftruncate - .llong .sys_fchmod - .llong .sys_fchown /* 95 */ - .llong .sys_getpriority - .llong .sys_setpriority - .llong .sys_ni_syscall /* old profil syscall holder */ - .llong .sys_statfs - .llong .sys_fstatfs /* 100 */ - .llong .sys_ni_syscall /* old ioperm syscall */ - .llong .sys_socketcall - .llong .sys_syslog - .llong .sys_setitimer - .llong .sys_getitimer /* 105 */ - .llong .sys_newstat - .llong .sys_newlstat - .llong .sys_newfstat - .llong .sys_ni_syscall /* old uname syscall */ - .llong .sys_ni_syscall /* 110 old iopl syscall */ - .llong .sys_vhangup - .llong .sys_ni_syscall /* old idle syscall */ - .llong .sys_ni_syscall /* old vm86 syscall */ - .llong .sys_wait4 - .llong .sys_swapoff /* 115 */ - .llong .sys_sysinfo - .llong .sys_ipc - .llong .sys_fsync - .llong .sys_ni_syscall - .llong .ppc_clone /* 120 */ - .llong .sys_setdomainname - .llong .ppc_newuname - .llong .sys_ni_syscall /* old modify_ldt syscall */ - .llong .sys_adjtimex - .llong .sys_mprotect /* 125 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* old create_module syscall */ - .llong .sys_init_module - .llong .sys_delete_module - .llong .sys_ni_syscall /* 130 old get_kernel_syms syscall */ - .llong .sys_quotactl - .llong .sys_getpgid - .llong .sys_fchdir - .llong .sys_bdflush - .llong .sys_sysfs /* 135 */ - .llong .ppc64_personality - .llong .sys_ni_syscall /* for afs_syscall */ - .llong .sys_setfsuid - .llong .sys_setfsgid - .llong .sys_llseek /* 140 */ - .llong .sys_getdents - .llong .sys_select - .llong .sys_flock - .llong .sys_msync - .llong .sys_readv /* 145 */ - .llong .sys_writev - .llong .sys_getsid - .llong .sys_fdatasync - .llong .sys_sysctl - .llong .sys_mlock /* 150 */ - .llong .sys_munlock - .llong .sys_mlockall - .llong .sys_munlockall - .llong .sys_sched_setparam - .llong .sys_sched_getparam /* 155 */ - .llong .sys_sched_setscheduler - .llong .sys_sched_getscheduler - .llong .sys_sched_yield - .llong .sys_sched_get_priority_max - .llong .sys_sched_get_priority_min /* 160 */ - .llong .sys_sched_rr_get_interval - .llong .sys_nanosleep - .llong .sys_mremap - .llong .sys_setresuid - .llong .sys_getresuid /* 165 */ - .llong .sys_ni_syscall /* old query_module syscall */ - .llong .sys_poll - .llong .sys_nfsservctl - .llong .sys_setresgid - .llong .sys_getresgid /* 170 */ - .llong .sys_prctl - .llong .ppc64_rt_sigreturn - .llong .sys_rt_sigaction - .llong .sys_rt_sigprocmask - .llong .sys_rt_sigpending /* 175 */ - .llong .sys_rt_sigtimedwait - .llong .sys_rt_sigqueueinfo - .llong .ppc64_rt_sigsuspend - .llong .sys_pread64 - .llong .sys_pwrite64 /* 180 */ - .llong .sys_chown - .llong .sys_getcwd - .llong .sys_capget - .llong .sys_capset - .llong .sys_sigaltstack /* 185 */ - .llong .sys_sendfile64 - .llong .sys_ni_syscall /* reserved for streams1 */ - .llong .sys_ni_syscall /* reserved for streams2 */ - .llong .ppc_vfork - .llong .sys_getrlimit /* 190 */ - .llong .sys_readahead - .llong .sys_ni_syscall /* 32bit only mmap2 */ - .llong .sys_ni_syscall /* 32bit only truncate64 */ - .llong .sys_ni_syscall /* 32bit only ftruncate64 */ - .llong .sys_ni_syscall /* 195 - 32bit only stat64 */ - .llong .sys_ni_syscall /* 32bit only lstat64 */ - .llong .sys_ni_syscall /* 32bit only fstat64 */ - .llong .sys_pciconfig_read - .llong .sys_pciconfig_write - .llong .sys_pciconfig_iobase /* 200 - pciconfig_iobase */ - .llong .sys_ni_syscall /* reserved for MacOnLinux */ - .llong .sys_getdents64 - .llong .sys_pivot_root - .llong .sys_ni_syscall /* 32bit only fcntl64 */ - .llong .sys_madvise /* 205 */ - .llong .sys_mincore - .llong .sys_gettid - .llong .sys_tkill - .llong .sys_setxattr - .llong .sys_lsetxattr /* 210 */ - .llong .sys_fsetxattr - .llong .sys_getxattr - .llong .sys_lgetxattr - .llong .sys_fgetxattr - .llong .sys_listxattr /* 215 */ - .llong .sys_llistxattr - .llong .sys_flistxattr - .llong .sys_removexattr - .llong .sys_lremovexattr - .llong .sys_fremovexattr /* 220 */ - .llong .sys_futex - .llong .sys_sched_setaffinity - .llong .sys_sched_getaffinity - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ - .llong .sys_ni_syscall /* 32bit only sendfile64 */ - .llong .sys_io_setup - .llong .sys_io_destroy - .llong .sys_io_getevents - .llong .sys_io_submit /* 230 */ - .llong .sys_io_cancel - .llong .sys_set_tid_address - .llong .sys_fadvise64 - .llong .sys_exit_group - .llong .sys_lookup_dcookie /* 235 */ - .llong .sys_epoll_create - .llong .sys_epoll_ctl - .llong .sys_epoll_wait - .llong .sys_remap_file_pages - .llong .sys_timer_create /* 240 */ - .llong .sys_timer_settime - .llong .sys_timer_gettime - .llong .sys_timer_getoverrun - .llong .sys_timer_delete - .llong .sys_clock_settime /* 245 */ - .llong .sys_clock_gettime - .llong .sys_clock_getres - .llong .sys_clock_nanosleep - .llong .ppc64_swapcontext - .llong .sys_tgkill /* 250 */ - .llong .sys_utimes - .llong .sys_statfs64 - .llong .sys_fstatfs64 - .llong .sys_ni_syscall /* 32bit only fadvise64_64 */ - .llong .ppc_rtas /* 255 */ - .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ - .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_mbind - .llong .sys_get_mempolicy /* 260 */ - .llong .sys_set_mempolicy - .llong .sys_mq_open - .llong .sys_mq_unlink - .llong .sys_mq_timedsend - .llong .sys_mq_timedreceive /* 265 */ - .llong .sys_mq_notify - .llong .sys_mq_getsetattr - .llong .sys_kexec_load - .llong .sys_add_key - .llong .sys_request_key /* 270 */ - .llong .sys_keyctl - .llong .sys_waitid - .llong .sys_ioprio_set - .llong .sys_ioprio_get - .llong .sys_inotify_init /* 275 */ - .llong .sys_inotify_add_watch - .llong .sys_inotify_rm_watch From 1a3c061efd32b620cf6498b71687ff0768cfe2d8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:25:05 +1000 Subject: [PATCH 0798/1939] ppc64: use checksum_64.S from powerpc as it is identical to checksum.S from ppc64. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 5 +- arch/ppc64/Makefile | 1 + arch/ppc64/lib/Makefile | 2 +- arch/ppc64/lib/checksum.S | 229 -------------------------------------- 4 files changed, 6 insertions(+), 231 deletions(-) delete mode 100644 arch/ppc64/lib/checksum.S diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 30367a0237dd..1f1f01b757d4 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -2,12 +2,15 @@ # Makefile for ppc-specific library files.. # +ifeq ($(CONFIG_PPC_MERGE),y) obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o memcpy_64.o \ - usercopy_64.o sstep.o checksum_64.o mem_64.o + usercopy_64.o sstep.o mem_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o endif +endif +obj-$(CONFIG_PPC64) += checksum_64.o diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 66ee04f13b26..2a7af765bfb6 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -88,6 +88,7 @@ core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ core-y += arch/powerpc/mm/ core-y += arch/powerpc/sysdev/ core-y += arch/powerpc/platforms/ +core-y += arch/powerpc/lib/ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 0b6e967de948..fa457a24cae1 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc64-specific library files.. # -lib-y := checksum.o string.o strcase.o +lib-y := string.o strcase.o lib-y += copypage.o memcpy.o copyuser.o usercopy.o # Lock primitives are defined as no-ops in include/linux/spinlock.h diff --git a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S deleted file mode 100644 index ef96c6c58efc..000000000000 --- a/arch/ppc64/lib/checksum.S +++ /dev/null @@ -1,229 +0,0 @@ -/* - * This file contains assembly-language implementations - * of IP-style 1's complement checksum routines. - * - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * 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. - * - * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). - */ - -#include -#include -#include -#include - -/* - * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header - * len is in words and is always >= 5. - * - * In practice len == 5, but this is not guaranteed. So this code does not - * attempt to use doubleword instructions. - */ -_GLOBAL(ip_fast_csum) - lwz r0,0(r3) - lwzu r5,4(r3) - addic. r4,r4,-2 - addc r0,r0,r5 - mtctr r4 - blelr- -1: lwzu r4,4(r3) - adde r0,r0,r4 - bdnz 1b - addze r0,r0 /* add in final carry */ - rldicl r4,r0,32,0 /* fold two 32-bit halves together */ - add r0,r0,r4 - srdi r0,r0,32 - rlwinm r3,r0,16,0,31 /* fold two halves together */ - add r3,r0,r3 - not r3,r3 - srwi r3,r3,16 - blr - -/* - * Compute checksum of TCP or UDP pseudo-header: - * csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum) - * No real gain trying to do this specially for 64 bit, but - * the 32 bit addition may spill into the upper bits of - * the doubleword so we still must fold it down from 64. - */ -_GLOBAL(csum_tcpudp_magic) - rlwimi r5,r6,16,0,15 /* put proto in upper half of len */ - addc r0,r3,r4 /* add 4 32-bit words together */ - adde r0,r0,r5 - adde r0,r0,r7 - rldicl r4,r0,32,0 /* fold 64 bit value */ - add r0,r4,r0 - srdi r0,r0,32 - rlwinm r3,r0,16,0,31 /* fold two halves together */ - add r3,r0,r3 - not r3,r3 - srwi r3,r3,16 - blr - -/* - * Computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit). - * - * This code assumes at least halfword alignment, though the length - * can be any number of bytes. The sum is accumulated in r5. - * - * csum_partial(r3=buff, r4=len, r5=sum) - */ -_GLOBAL(csum_partial) - subi r3,r3,8 /* we'll offset by 8 for the loads */ - srdi. r6,r4,3 /* divide by 8 for doubleword count */ - addic r5,r5,0 /* clear carry */ - beq 3f /* if we're doing < 8 bytes */ - andi. r0,r3,2 /* aligned on a word boundary already? */ - beq+ 1f - lhz r6,8(r3) /* do 2 bytes to get aligned */ - addi r3,r3,2 - subi r4,r4,2 - addc r5,r5,r6 - srdi. r6,r4,3 /* recompute number of doublewords */ - beq 3f /* any left? */ -1: mtctr r6 -2: ldu r6,8(r3) /* main sum loop */ - adde r5,r5,r6 - bdnz 2b - andi. r4,r4,7 /* compute bytes left to sum after doublewords */ -3: cmpwi 0,r4,4 /* is at least a full word left? */ - blt 4f - lwz r6,8(r3) /* sum this word */ - addi r3,r3,4 - subi r4,r4,4 - adde r5,r5,r6 -4: cmpwi 0,r4,2 /* is at least a halfword left? */ - blt+ 5f - lhz r6,8(r3) /* sum this halfword */ - addi r3,r3,2 - subi r4,r4,2 - adde r5,r5,r6 -5: cmpwi 0,r4,1 /* is at least a byte left? */ - bne+ 6f - lbz r6,8(r3) /* sum this byte */ - slwi r6,r6,8 /* this byte is assumed to be the upper byte of a halfword */ - adde r5,r5,r6 -6: addze r5,r5 /* add in final carry */ - rldicl r4,r5,32,0 /* fold two 32-bit halves together */ - add r3,r4,r5 - srdi r3,r3,32 - blr - -/* - * Computes the checksum of a memory block at src, length len, - * and adds in "sum" (32-bit), while copying the block to dst. - * If an access exception occurs on src or dst, it stores -EFAULT - * to *src_err or *dst_err respectively, and (for an error on - * src) zeroes the rest of dst. - * - * This code needs to be reworked to take advantage of 64 bit sum+copy. - * However, due to tokenring halfword alignment problems this will be very - * tricky. For now we'll leave it until we instrument it somehow. - * - * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err) - */ -_GLOBAL(csum_partial_copy_generic) - addic r0,r6,0 - subi r3,r3,4 - subi r4,r4,4 - srwi. r6,r5,2 - beq 3f /* if we're doing < 4 bytes */ - andi. r9,r4,2 /* Align dst to longword boundary */ - beq+ 1f -81: lhz r6,4(r3) /* do 2 bytes to get aligned */ - addi r3,r3,2 - subi r5,r5,2 -91: sth r6,4(r4) - addi r4,r4,2 - addc r0,r0,r6 - srwi. r6,r5,2 /* # words to do */ - beq 3f -1: mtctr r6 -82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */ -92: stwu r6,4(r4) /* be unnecessary to unroll this loop */ - adde r0,r0,r6 - bdnz 82b - andi. r5,r5,3 -3: cmpwi 0,r5,2 - blt+ 4f -83: lhz r6,4(r3) - addi r3,r3,2 - subi r5,r5,2 -93: sth r6,4(r4) - addi r4,r4,2 - adde r0,r0,r6 -4: cmpwi 0,r5,1 - bne+ 5f -84: lbz r6,4(r3) -94: stb r6,4(r4) - slwi r6,r6,8 /* Upper byte of word */ - adde r0,r0,r6 -5: addze r3,r0 /* add in final carry (unlikely with 64-bit regs) */ - rldicl r4,r3,32,0 /* fold 64 bit value */ - add r3,r4,r3 - srdi r3,r3,32 - blr - -/* These shouldn't go in the fixup section, since that would - cause the ex_table addresses to get out of order. */ - - .globl src_error_1 -src_error_1: - li r6,0 - subi r5,r5,2 -95: sth r6,4(r4) - addi r4,r4,2 - srwi. r6,r5,2 - beq 3f - mtctr r6 - .globl src_error_2 -src_error_2: - li r6,0 -96: stwu r6,4(r4) - bdnz 96b -3: andi. r5,r5,3 - beq src_error - .globl src_error_3 -src_error_3: - li r6,0 - mtctr r5 - addi r4,r4,3 -97: stbu r6,1(r4) - bdnz 97b - .globl src_error -src_error: - cmpdi 0,r7,0 - beq 1f - li r6,-EFAULT - stw r6,0(r7) -1: addze r3,r0 - blr - - .globl dst_error -dst_error: - cmpdi 0,r8,0 - beq 1f - li r6,-EFAULT - stw r6,0(r8) -1: addze r3,r0 - blr - -.section __ex_table,"a" - .align 3 - .llong 81b,src_error_1 - .llong 91b,dst_error - .llong 82b,src_error_2 - .llong 92b,dst_error - .llong 83b,src_error_3 - .llong 93b,dst_error - .llong 84b,src_error_3 - .llong 94b,dst_error - .llong 95b,dst_error - .llong 96b,dst_error - .llong 97b,dst_error From 454fb016b3407e7cacbe17e590521ddf86a54f7f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:28:43 +1000 Subject: [PATCH 0799/1939] ppc64: use e2a.c from powerpc/lib since it is identical to e2a.c from ppc64/lib Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 2 +- arch/ppc64/lib/Makefile | 5 -- arch/ppc64/lib/e2a.c | 108 -------------------------------------- 3 files changed, 1 insertion(+), 114 deletions(-) delete mode 100644 arch/ppc64/lib/e2a.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 1f1f01b757d4..87153891d7a7 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,10 +7,10 @@ obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o memcpy_64.o \ usercopy_64.o sstep.o mem_64.o -obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o endif endif obj-$(CONFIG_PPC64) += checksum_64.o +obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index fa457a24cae1..62c3116b003f 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -10,9 +10,4 @@ lib-y += copypage.o memcpy.o copyuser.o usercopy.o lib-$(CONFIG_SMP) += locks.o -# e2a provides EBCDIC to ASCII conversions. -ifdef CONFIG_PPC_ISERIES -obj-y += e2a.o -endif - lib-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/arch/ppc64/lib/e2a.c b/arch/ppc64/lib/e2a.c deleted file mode 100644 index d2b834887920..000000000000 --- a/arch/ppc64/lib/e2a.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * arch/ppc64/lib/e2a.c - * - * EBCDIC to ASCII conversion - * - * This function moved here from arch/ppc64/kernel/viopath.c - * - * (C) Copyright 2000-2004 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) anyu 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 - -unsigned char e2a(unsigned char x) -{ - switch (x) { - case 0xF0: - return '0'; - case 0xF1: - return '1'; - case 0xF2: - return '2'; - case 0xF3: - return '3'; - case 0xF4: - return '4'; - case 0xF5: - return '5'; - case 0xF6: - return '6'; - case 0xF7: - return '7'; - case 0xF8: - return '8'; - case 0xF9: - return '9'; - case 0xC1: - return 'A'; - case 0xC2: - return 'B'; - case 0xC3: - return 'C'; - case 0xC4: - return 'D'; - case 0xC5: - return 'E'; - case 0xC6: - return 'F'; - case 0xC7: - return 'G'; - case 0xC8: - return 'H'; - case 0xC9: - return 'I'; - case 0xD1: - return 'J'; - case 0xD2: - return 'K'; - case 0xD3: - return 'L'; - case 0xD4: - return 'M'; - case 0xD5: - return 'N'; - case 0xD6: - return 'O'; - case 0xD7: - return 'P'; - case 0xD8: - return 'Q'; - case 0xD9: - return 'R'; - case 0xE2: - return 'S'; - case 0xE3: - return 'T'; - case 0xE4: - return 'U'; - case 0xE5: - return 'V'; - case 0xE6: - return 'W'; - case 0xE7: - return 'X'; - case 0xE8: - return 'Y'; - case 0xE9: - return 'Z'; - } - return ' '; -} -EXPORT_SYMBOL(e2a); - - From 34faa82841b87e6f375b01dad3262ca345de25c0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:35:43 +1000 Subject: [PATCH 0800/1939] ppc64: use copypage_64.S from powerpc/lib since it is identical to copypage.S from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 4 +- arch/ppc64/lib/Makefile | 2 +- arch/ppc64/lib/copypage.S | 121 -------------------------------------- 3 files changed, 3 insertions(+), 124 deletions(-) delete mode 100644 arch/ppc64/lib/copypage.S diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 87153891d7a7..5e481944250e 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -5,12 +5,12 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o -obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o memcpy_64.o \ +obj-$(CONFIG_PPC64) += copyuser_64.o memcpy_64.o \ usercopy_64.o sstep.o mem_64.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o endif endif -obj-$(CONFIG_PPC64) += checksum_64.o +obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 62c3116b003f..820021885e1a 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -3,7 +3,7 @@ # lib-y := string.o strcase.o -lib-y += copypage.o memcpy.o copyuser.o usercopy.o +lib-y += memcpy.o copyuser.o usercopy.o # Lock primitives are defined as no-ops in include/linux/spinlock.h # for non-SMP configs. Don't build the real versions. diff --git a/arch/ppc64/lib/copypage.S b/arch/ppc64/lib/copypage.S deleted file mode 100644 index 733d61618bbf..000000000000 --- a/arch/ppc64/lib/copypage.S +++ /dev/null @@ -1,121 +0,0 @@ -/* - * arch/ppc64/lib/copypage.S - * - * Copyright (C) 2002 Paul Mackerras, 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 - -_GLOBAL(copy_page) - std r31,-8(1) - std r30,-16(1) - std r29,-24(1) - std r28,-32(1) - std r27,-40(1) - std r26,-48(1) - std r25,-56(1) - std r24,-64(1) - std r23,-72(1) - std r22,-80(1) - std r21,-88(1) - std r20,-96(1) - li r5,4096/32 - 1 - addi r3,r3,-8 - li r12,5 -0: addi r5,r5,-24 - mtctr r12 - ld r22,640(4) - ld r21,512(4) - ld r20,384(4) - ld r11,256(4) - ld r9,128(4) - ld r7,0(4) - ld r25,648(4) - ld r24,520(4) - ld r23,392(4) - ld r10,264(4) - ld r8,136(4) - ldu r6,8(4) - cmpwi r5,24 -1: std r22,648(3) - std r21,520(3) - std r20,392(3) - std r11,264(3) - std r9,136(3) - std r7,8(3) - ld r28,648(4) - ld r27,520(4) - ld r26,392(4) - ld r31,264(4) - ld r30,136(4) - ld r29,8(4) - std r25,656(3) - std r24,528(3) - std r23,400(3) - std r10,272(3) - std r8,144(3) - std r6,16(3) - ld r22,656(4) - ld r21,528(4) - ld r20,400(4) - ld r11,272(4) - ld r9,144(4) - ld r7,16(4) - std r28,664(3) - std r27,536(3) - std r26,408(3) - std r31,280(3) - std r30,152(3) - stdu r29,24(3) - ld r25,664(4) - ld r24,536(4) - ld r23,408(4) - ld r10,280(4) - ld r8,152(4) - ldu r6,24(4) - bdnz 1b - std r22,648(3) - std r21,520(3) - std r20,392(3) - std r11,264(3) - std r9,136(3) - std r7,8(3) - addi r4,r4,640 - addi r3,r3,648 - bge 0b - mtctr r5 - ld r7,0(4) - ld r8,8(4) - ldu r9,16(4) -3: ld r10,8(4) - std r7,8(3) - ld r7,16(4) - std r8,16(3) - ld r8,24(4) - std r9,24(3) - ldu r9,32(4) - stdu r10,32(3) - bdnz 3b -4: ld r10,8(4) - std r7,8(3) - std r8,16(3) - std r9,24(3) - std r10,32(3) -9: ld r20,-96(1) - ld r21,-88(1) - ld r22,-80(1) - ld r23,-72(1) - ld r24,-64(1) - ld r25,-56(1) - ld r26,-48(1) - ld r27,-40(1) - ld r28,-32(1) - ld r29,-24(1) - ld r30,-16(1) - ld r31,-8(1) - blr From 43f35ec35c2b9a1c984d885893084eed2101e1bf Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:40:05 +1000 Subject: [PATCH 0801/1939] ppc64: use copyuser_64.S from powerpc/lib since it is identical to copyuser.S from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 4 +- arch/ppc64/lib/Makefile | 2 +- arch/ppc64/lib/copyuser.S | 576 -------------------------------------- 3 files changed, 3 insertions(+), 579 deletions(-) delete mode 100644 arch/ppc64/lib/copyuser.S diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 5e481944250e..3474c9309e2f 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -5,12 +5,12 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o -obj-$(CONFIG_PPC64) += copyuser_64.o memcpy_64.o \ +obj-$(CONFIG_PPC64) += memcpy_64.o \ usercopy_64.o sstep.o mem_64.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o endif endif -obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o +obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 820021885e1a..f29e76559950 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -3,7 +3,7 @@ # lib-y := string.o strcase.o -lib-y += memcpy.o copyuser.o usercopy.o +lib-y += memcpy.o usercopy.o # Lock primitives are defined as no-ops in include/linux/spinlock.h # for non-SMP configs. Don't build the real versions. diff --git a/arch/ppc64/lib/copyuser.S b/arch/ppc64/lib/copyuser.S deleted file mode 100644 index a0b3fbbd6fb1..000000000000 --- a/arch/ppc64/lib/copyuser.S +++ /dev/null @@ -1,576 +0,0 @@ -/* - * arch/ppc64/lib/copyuser.S - * - * Copyright (C) 2002 Paul Mackerras, 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 - - .align 7 -_GLOBAL(__copy_tofrom_user) - /* first check for a whole page copy on a page boundary */ - cmpldi cr1,r5,16 - cmpdi cr6,r5,4096 - or r0,r3,r4 - neg r6,r3 /* LS 3 bits = # bytes to 8-byte dest bdry */ - andi. r0,r0,4095 - std r3,-24(r1) - crand cr0*4+2,cr0*4+2,cr6*4+2 - std r4,-16(r1) - std r5,-8(r1) - dcbt 0,r4 - beq .Lcopy_page - andi. r6,r6,7 - mtcrf 0x01,r5 - blt cr1,.Lshort_copy - bne .Ldst_unaligned -.Ldst_aligned: - andi. r0,r4,7 - addi r3,r3,-16 - bne .Lsrc_unaligned - srdi r7,r5,4 -20: ld r9,0(r4) - addi r4,r4,-8 - mtctr r7 - andi. r5,r5,7 - bf cr7*4+0,22f - addi r3,r3,8 - addi r4,r4,8 - mr r8,r9 - blt cr1,72f -21: ld r9,8(r4) -70: std r8,8(r3) -22: ldu r8,16(r4) -71: stdu r9,16(r3) - bdnz 21b -72: std r8,8(r3) - beq+ 3f - addi r3,r3,16 -23: ld r9,8(r4) -.Ldo_tail: - bf cr7*4+1,1f - rotldi r9,r9,32 -73: stw r9,0(r3) - addi r3,r3,4 -1: bf cr7*4+2,2f - rotldi r9,r9,16 -74: sth r9,0(r3) - addi r3,r3,2 -2: bf cr7*4+3,3f - rotldi r9,r9,8 -75: stb r9,0(r3) -3: li r3,0 - blr - -.Lsrc_unaligned: - srdi r6,r5,3 - addi r5,r5,-16 - subf r4,r0,r4 - srdi r7,r5,4 - sldi r10,r0,3 - cmpldi cr6,r6,3 - andi. r5,r5,7 - mtctr r7 - subfic r11,r10,64 - add r5,r5,r0 - bt cr7*4+0,28f - -24: ld r9,0(r4) /* 3+2n loads, 2+2n stores */ -25: ld r0,8(r4) - sld r6,r9,r10 -26: ldu r9,16(r4) - srd r7,r0,r11 - sld r8,r0,r10 - or r7,r7,r6 - blt cr6,79f -27: ld r0,8(r4) - b 2f - -28: ld r0,0(r4) /* 4+2n loads, 3+2n stores */ -29: ldu r9,8(r4) - sld r8,r0,r10 - addi r3,r3,-8 - blt cr6,5f -30: ld r0,8(r4) - srd r12,r9,r11 - sld r6,r9,r10 -31: ldu r9,16(r4) - or r12,r8,r12 - srd r7,r0,r11 - sld r8,r0,r10 - addi r3,r3,16 - beq cr6,78f - -1: or r7,r7,r6 -32: ld r0,8(r4) -76: std r12,8(r3) -2: srd r12,r9,r11 - sld r6,r9,r10 -33: ldu r9,16(r4) - or r12,r8,r12 -77: stdu r7,16(r3) - srd r7,r0,r11 - sld r8,r0,r10 - bdnz 1b - -78: std r12,8(r3) - or r7,r7,r6 -79: std r7,16(r3) -5: srd r12,r9,r11 - or r12,r8,r12 -80: std r12,24(r3) - bne 6f - li r3,0 - blr -6: cmpwi cr1,r5,8 - addi r3,r3,32 - sld r9,r9,r10 - ble cr1,.Ldo_tail -34: ld r0,8(r4) - srd r7,r0,r11 - or r9,r7,r9 - b .Ldo_tail - -.Ldst_unaligned: - mtcrf 0x01,r6 /* put #bytes to 8B bdry into cr7 */ - subf r5,r6,r5 - li r7,0 - cmpldi r1,r5,16 - bf cr7*4+3,1f -35: lbz r0,0(r4) -81: stb r0,0(r3) - addi r7,r7,1 -1: bf cr7*4+2,2f -36: lhzx r0,r7,r4 -82: sthx r0,r7,r3 - addi r7,r7,2 -2: bf cr7*4+1,3f -37: lwzx r0,r7,r4 -83: stwx r0,r7,r3 -3: mtcrf 0x01,r5 - add r4,r6,r4 - add r3,r6,r3 - b .Ldst_aligned - -.Lshort_copy: - bf cr7*4+0,1f -38: lwz r0,0(r4) -39: lwz r9,4(r4) - addi r4,r4,8 -84: stw r0,0(r3) -85: stw r9,4(r3) - addi r3,r3,8 -1: bf cr7*4+1,2f -40: lwz r0,0(r4) - addi r4,r4,4 -86: stw r0,0(r3) - addi r3,r3,4 -2: bf cr7*4+2,3f -41: lhz r0,0(r4) - addi r4,r4,2 -87: sth r0,0(r3) - addi r3,r3,2 -3: bf cr7*4+3,4f -42: lbz r0,0(r4) -88: stb r0,0(r3) -4: li r3,0 - blr - -/* - * exception handlers follow - * we have to return the number of bytes not copied - * for an exception on a load, we set the rest of the destination to 0 - */ - -136: -137: - add r3,r3,r7 - b 1f -130: -131: - addi r3,r3,8 -120: -122: -124: -125: -126: -127: -128: -129: -133: - addi r3,r3,8 -121: -132: - addi r3,r3,8 -123: -134: -135: -138: -139: -140: -141: -142: - -/* - * here we have had a fault on a load and r3 points to the first - * unmodified byte of the destination - */ -1: ld r6,-24(r1) - ld r4,-16(r1) - ld r5,-8(r1) - subf r6,r6,r3 - add r4,r4,r6 - subf r5,r6,r5 /* #bytes left to go */ - -/* - * first see if we can copy any more bytes before hitting another exception - */ - mtctr r5 -43: lbz r0,0(r4) - addi r4,r4,1 -89: stb r0,0(r3) - addi r3,r3,1 - bdnz 43b - li r3,0 /* huh? all copied successfully this time? */ - blr - -/* - * here we have trapped again, need to clear ctr bytes starting at r3 - */ -143: mfctr r5 - li r0,0 - mr r4,r3 - mr r3,r5 /* return the number of bytes not copied */ -1: andi. r9,r4,7 - beq 3f -90: stb r0,0(r4) - addic. r5,r5,-1 - addi r4,r4,1 - bne 1b - blr -3: cmpldi cr1,r5,8 - srdi r9,r5,3 - andi. r5,r5,7 - blt cr1,93f - mtctr r9 -91: std r0,0(r4) - addi r4,r4,8 - bdnz 91b -93: beqlr - mtctr r5 -92: stb r0,0(r4) - addi r4,r4,1 - bdnz 92b - blr - -/* - * exception handlers for stores: we just need to work - * out how many bytes weren't copied - */ -182: -183: - add r3,r3,r7 - b 1f -180: - addi r3,r3,8 -171: -177: - addi r3,r3,8 -170: -172: -176: -178: - addi r3,r3,4 -185: - addi r3,r3,4 -173: -174: -175: -179: -181: -184: -186: -187: -188: -189: -1: - ld r6,-24(r1) - ld r5,-8(r1) - add r6,r6,r5 - subf r3,r3,r6 /* #bytes not copied */ -190: -191: -192: - blr /* #bytes not copied in r3 */ - - .section __ex_table,"a" - .align 3 - .llong 20b,120b - .llong 21b,121b - .llong 70b,170b - .llong 22b,122b - .llong 71b,171b - .llong 72b,172b - .llong 23b,123b - .llong 73b,173b - .llong 74b,174b - .llong 75b,175b - .llong 24b,124b - .llong 25b,125b - .llong 26b,126b - .llong 27b,127b - .llong 28b,128b - .llong 29b,129b - .llong 30b,130b - .llong 31b,131b - .llong 32b,132b - .llong 76b,176b - .llong 33b,133b - .llong 77b,177b - .llong 78b,178b - .llong 79b,179b - .llong 80b,180b - .llong 34b,134b - .llong 35b,135b - .llong 81b,181b - .llong 36b,136b - .llong 82b,182b - .llong 37b,137b - .llong 83b,183b - .llong 38b,138b - .llong 39b,139b - .llong 84b,184b - .llong 85b,185b - .llong 40b,140b - .llong 86b,186b - .llong 41b,141b - .llong 87b,187b - .llong 42b,142b - .llong 88b,188b - .llong 43b,143b - .llong 89b,189b - .llong 90b,190b - .llong 91b,191b - .llong 92b,192b - - .text - -/* - * Routine to copy a whole page of data, optimized for POWER4. - * On POWER4 it is more than 50% faster than the simple loop - * above (following the .Ldst_aligned label) but it runs slightly - * slower on POWER3. - */ -.Lcopy_page: - std r31,-32(1) - std r30,-40(1) - std r29,-48(1) - std r28,-56(1) - std r27,-64(1) - std r26,-72(1) - std r25,-80(1) - std r24,-88(1) - std r23,-96(1) - std r22,-104(1) - std r21,-112(1) - std r20,-120(1) - li r5,4096/32 - 1 - addi r3,r3,-8 - li r0,5 -0: addi r5,r5,-24 - mtctr r0 -20: ld r22,640(4) -21: ld r21,512(4) -22: ld r20,384(4) -23: ld r11,256(4) -24: ld r9,128(4) -25: ld r7,0(4) -26: ld r25,648(4) -27: ld r24,520(4) -28: ld r23,392(4) -29: ld r10,264(4) -30: ld r8,136(4) -31: ldu r6,8(4) - cmpwi r5,24 -1: -32: std r22,648(3) -33: std r21,520(3) -34: std r20,392(3) -35: std r11,264(3) -36: std r9,136(3) -37: std r7,8(3) -38: ld r28,648(4) -39: ld r27,520(4) -40: ld r26,392(4) -41: ld r31,264(4) -42: ld r30,136(4) -43: ld r29,8(4) -44: std r25,656(3) -45: std r24,528(3) -46: std r23,400(3) -47: std r10,272(3) -48: std r8,144(3) -49: std r6,16(3) -50: ld r22,656(4) -51: ld r21,528(4) -52: ld r20,400(4) -53: ld r11,272(4) -54: ld r9,144(4) -55: ld r7,16(4) -56: std r28,664(3) -57: std r27,536(3) -58: std r26,408(3) -59: std r31,280(3) -60: std r30,152(3) -61: stdu r29,24(3) -62: ld r25,664(4) -63: ld r24,536(4) -64: ld r23,408(4) -65: ld r10,280(4) -66: ld r8,152(4) -67: ldu r6,24(4) - bdnz 1b -68: std r22,648(3) -69: std r21,520(3) -70: std r20,392(3) -71: std r11,264(3) -72: std r9,136(3) -73: std r7,8(3) -74: addi r4,r4,640 -75: addi r3,r3,648 - bge 0b - mtctr r5 -76: ld r7,0(4) -77: ld r8,8(4) -78: ldu r9,16(4) -3: -79: ld r10,8(4) -80: std r7,8(3) -81: ld r7,16(4) -82: std r8,16(3) -83: ld r8,24(4) -84: std r9,24(3) -85: ldu r9,32(4) -86: stdu r10,32(3) - bdnz 3b -4: -87: ld r10,8(4) -88: std r7,8(3) -89: std r8,16(3) -90: std r9,24(3) -91: std r10,32(3) -9: ld r20,-120(1) - ld r21,-112(1) - ld r22,-104(1) - ld r23,-96(1) - ld r24,-88(1) - ld r25,-80(1) - ld r26,-72(1) - ld r27,-64(1) - ld r28,-56(1) - ld r29,-48(1) - ld r30,-40(1) - ld r31,-32(1) - li r3,0 - blr - -/* - * on an exception, reset to the beginning and jump back into the - * standard __copy_tofrom_user - */ -100: ld r20,-120(1) - ld r21,-112(1) - ld r22,-104(1) - ld r23,-96(1) - ld r24,-88(1) - ld r25,-80(1) - ld r26,-72(1) - ld r27,-64(1) - ld r28,-56(1) - ld r29,-48(1) - ld r30,-40(1) - ld r31,-32(1) - ld r3,-24(r1) - ld r4,-16(r1) - li r5,4096 - b .Ldst_aligned - - .section __ex_table,"a" - .align 3 - .llong 20b,100b - .llong 21b,100b - .llong 22b,100b - .llong 23b,100b - .llong 24b,100b - .llong 25b,100b - .llong 26b,100b - .llong 27b,100b - .llong 28b,100b - .llong 29b,100b - .llong 30b,100b - .llong 31b,100b - .llong 32b,100b - .llong 33b,100b - .llong 34b,100b - .llong 35b,100b - .llong 36b,100b - .llong 37b,100b - .llong 38b,100b - .llong 39b,100b - .llong 40b,100b - .llong 41b,100b - .llong 42b,100b - .llong 43b,100b - .llong 44b,100b - .llong 45b,100b - .llong 46b,100b - .llong 47b,100b - .llong 48b,100b - .llong 49b,100b - .llong 50b,100b - .llong 51b,100b - .llong 52b,100b - .llong 53b,100b - .llong 54b,100b - .llong 55b,100b - .llong 56b,100b - .llong 57b,100b - .llong 58b,100b - .llong 59b,100b - .llong 60b,100b - .llong 61b,100b - .llong 62b,100b - .llong 63b,100b - .llong 64b,100b - .llong 65b,100b - .llong 66b,100b - .llong 67b,100b - .llong 68b,100b - .llong 69b,100b - .llong 70b,100b - .llong 71b,100b - .llong 72b,100b - .llong 73b,100b - .llong 74b,100b - .llong 75b,100b - .llong 76b,100b - .llong 77b,100b - .llong 78b,100b - .llong 79b,100b - .llong 80b,100b - .llong 81b,100b - .llong 82b,100b - .llong 83b,100b - .llong 84b,100b - .llong 85b,100b - .llong 86b,100b - .llong 87b,100b - .llong 88b,100b - .llong 89b,100b - .llong 90b,100b - .llong 91b,100b From ecc81e0f719f566b75b222b8aef64c8b809b2e29 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:45:38 +1000 Subject: [PATCH 0802/1939] ppc64: use lockc.c from powerpc/lib since it is effectively the same as locks.c from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 6 +-- arch/ppc64/lib/Makefile | 5 --- arch/ppc64/lib/locks.c | 95 --------------------------------------- 3 files changed, 3 insertions(+), 103 deletions(-) delete mode 100644 arch/ppc64/lib/locks.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 3474c9309e2f..955c06421590 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,10 +7,10 @@ obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += memcpy_64.o \ usercopy_64.o sstep.o mem_64.o -ifeq ($(CONFIG_PPC64),y) -obj-$(CONFIG_SMP) += locks.o -endif endif obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o +ifeq ($(CONFIG_PPC64),y) +obj-$(CONFIG_SMP) += locks.o +endif diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index f29e76559950..87c2ff5e1883 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -5,9 +5,4 @@ lib-y := string.o strcase.o lib-y += memcpy.o usercopy.o -# Lock primitives are defined as no-ops in include/linux/spinlock.h -# for non-SMP configs. Don't build the real versions. - -lib-$(CONFIG_SMP) += locks.o - lib-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c deleted file mode 100644 index 033643ab69e0..000000000000 --- a/arch/ppc64/lib/locks.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Spin and read/write lock operations. - * - * Copyright (C) 2001-2004 Paul Mackerras , IBM - * Copyright (C) 2001 Anton Blanchard , IBM - * Copyright (C) 2002 Dave Engebretsen , IBM - * Rework to support virtual processors - * - * 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 - -/* waiting for a spinlock... */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) - -void __spin_yield(raw_spinlock_t *lock) -{ - unsigned int lock_value, holder_cpu, yield_count; - struct paca_struct *holder_paca; - - lock_value = lock->slock; - if (lock_value == 0) - return; - holder_cpu = lock_value & 0xffff; - BUG_ON(holder_cpu >= NR_CPUS); - holder_paca = &paca[holder_cpu]; - yield_count = holder_paca->lppaca.yield_count; - if ((yield_count & 1) == 0) - return; /* virtual cpu is currently running */ - rmb(); - if (lock->slock != lock_value) - return; /* something has changed */ -#ifdef CONFIG_PPC_ISERIES - HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, - ((u64)holder_cpu << 32) | yield_count); -#else - plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), - yield_count); -#endif -} - -/* - * Waiting for a read lock or a write lock on a rwlock... - * This turns out to be the same for read and write locks, since - * we only know the holder if it is write-locked. - */ -void __rw_yield(raw_rwlock_t *rw) -{ - int lock_value; - unsigned int holder_cpu, yield_count; - struct paca_struct *holder_paca; - - lock_value = rw->lock; - if (lock_value >= 0) - return; /* no write lock at present */ - holder_cpu = lock_value & 0xffff; - BUG_ON(holder_cpu >= NR_CPUS); - holder_paca = &paca[holder_cpu]; - yield_count = holder_paca->lppaca.yield_count; - if ((yield_count & 1) == 0) - return; /* virtual cpu is currently running */ - rmb(); - if (rw->lock != lock_value) - return; /* something has changed */ -#ifdef CONFIG_PPC_ISERIES - HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, - ((u64)holder_cpu << 32) | yield_count); -#else - plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), - yield_count); -#endif -} -#endif - -void __raw_spin_unlock_wait(raw_spinlock_t *lock) -{ - while (lock->slock) { - HMT_low(); - if (SHARED_PROCESSOR) - __spin_yield(lock); - } - HMT_medium(); -} - -EXPORT_SYMBOL(__raw_spin_unlock_wait); From 12a39407f021fd17d5f9d33d78bddb005bd106fb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 16:49:44 +1000 Subject: [PATCH 0803/1939] ppc64: use memcpy_64.S from powerpc/lib since it is identical to mempcy.S from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 6 +- arch/ppc64/lib/Makefile | 2 +- arch/ppc64/lib/memcpy.S | 172 -------------------------------------- 3 files changed, 4 insertions(+), 176 deletions(-) delete mode 100644 arch/ppc64/lib/memcpy.S diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 955c06421590..9cf35ed3f33a 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -5,11 +5,11 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o -obj-$(CONFIG_PPC64) += memcpy_64.o \ - usercopy_64.o sstep.o mem_64.o +obj-$(CONFIG_PPC64) += usercopy_64.o sstep.o mem_64.o endif -obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o +obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ + memcpy_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 87c2ff5e1883..49af089c6049 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -3,6 +3,6 @@ # lib-y := string.o strcase.o -lib-y += memcpy.o usercopy.o +lib-y += usercopy.o lib-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/arch/ppc64/lib/memcpy.S b/arch/ppc64/lib/memcpy.S deleted file mode 100644 index 9ccacdf5bcb9..000000000000 --- a/arch/ppc64/lib/memcpy.S +++ /dev/null @@ -1,172 +0,0 @@ -/* - * arch/ppc64/lib/memcpy.S - * - * Copyright (C) 2002 Paul Mackerras, 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 - - .align 7 -_GLOBAL(memcpy) - mtcrf 0x01,r5 - cmpldi cr1,r5,16 - neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry - andi. r6,r6,7 - dcbt 0,r4 - blt cr1,.Lshort_copy - bne .Ldst_unaligned -.Ldst_aligned: - andi. r0,r4,7 - addi r3,r3,-16 - bne .Lsrc_unaligned - srdi r7,r5,4 - ld r9,0(r4) - addi r4,r4,-8 - mtctr r7 - andi. r5,r5,7 - bf cr7*4+0,2f - addi r3,r3,8 - addi r4,r4,8 - mr r8,r9 - blt cr1,3f -1: ld r9,8(r4) - std r8,8(r3) -2: ldu r8,16(r4) - stdu r9,16(r3) - bdnz 1b -3: std r8,8(r3) - beqlr - addi r3,r3,16 - ld r9,8(r4) -.Ldo_tail: - bf cr7*4+1,1f - rotldi r9,r9,32 - stw r9,0(r3) - addi r3,r3,4 -1: bf cr7*4+2,2f - rotldi r9,r9,16 - sth r9,0(r3) - addi r3,r3,2 -2: bf cr7*4+3,3f - rotldi r9,r9,8 - stb r9,0(r3) -3: blr - -.Lsrc_unaligned: - srdi r6,r5,3 - addi r5,r5,-16 - subf r4,r0,r4 - srdi r7,r5,4 - sldi r10,r0,3 - cmpdi cr6,r6,3 - andi. r5,r5,7 - mtctr r7 - subfic r11,r10,64 - add r5,r5,r0 - - bt cr7*4+0,0f - - ld r9,0(r4) # 3+2n loads, 2+2n stores - ld r0,8(r4) - sld r6,r9,r10 - ldu r9,16(r4) - srd r7,r0,r11 - sld r8,r0,r10 - or r7,r7,r6 - blt cr6,4f - ld r0,8(r4) - # s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12 - b 2f - -0: ld r0,0(r4) # 4+2n loads, 3+2n stores - ldu r9,8(r4) - sld r8,r0,r10 - addi r3,r3,-8 - blt cr6,5f - ld r0,8(r4) - srd r12,r9,r11 - sld r6,r9,r10 - ldu r9,16(r4) - or r12,r8,r12 - srd r7,r0,r11 - sld r8,r0,r10 - addi r3,r3,16 - beq cr6,3f - - # d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9 -1: or r7,r7,r6 - ld r0,8(r4) - std r12,8(r3) -2: srd r12,r9,r11 - sld r6,r9,r10 - ldu r9,16(r4) - or r12,r8,r12 - stdu r7,16(r3) - srd r7,r0,r11 - sld r8,r0,r10 - bdnz 1b - -3: std r12,8(r3) - or r7,r7,r6 -4: std r7,16(r3) -5: srd r12,r9,r11 - or r12,r8,r12 - std r12,24(r3) - beqlr - cmpwi cr1,r5,8 - addi r3,r3,32 - sld r9,r9,r10 - ble cr1,.Ldo_tail - ld r0,8(r4) - srd r7,r0,r11 - or r9,r7,r9 - b .Ldo_tail - -.Ldst_unaligned: - mtcrf 0x01,r6 # put #bytes to 8B bdry into cr7 - subf r5,r6,r5 - li r7,0 - cmpldi r1,r5,16 - bf cr7*4+3,1f - lbz r0,0(r4) - stb r0,0(r3) - addi r7,r7,1 -1: bf cr7*4+2,2f - lhzx r0,r7,r4 - sthx r0,r7,r3 - addi r7,r7,2 -2: bf cr7*4+1,3f - lwzx r0,r7,r4 - stwx r0,r7,r3 -3: mtcrf 0x01,r5 - add r4,r6,r4 - add r3,r6,r3 - b .Ldst_aligned - -.Lshort_copy: - bf cr7*4+0,1f - lwz r0,0(r4) - lwz r9,4(r4) - addi r4,r4,8 - stw r0,0(r3) - stw r9,4(r3) - addi r3,r3,8 -1: bf cr7*4+1,2f - lwz r0,0(r4) - addi r4,r4,4 - stw r0,0(r3) - addi r3,r3,4 -2: bf cr7*4+2,3f - lhz r0,0(r4) - addi r4,r4,2 - sth r0,0(r3) - addi r3,r3,2 -3: bf cr7*4+3,4f - lbz r0,0(r4) - stb r0,0(r3) -4: blr From a0d8bf9cf1f9722204936d8ef53370d7ae1181d9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 17:05:27 +1000 Subject: [PATCH 0804/1939] ppc64: use sstep.c from powerpc/lib since it is identical to sstep.c from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 3 +- arch/ppc64/lib/Makefile | 2 - arch/ppc64/lib/sstep.c | 141 -------------------------------------- 3 files changed, 2 insertions(+), 144 deletions(-) delete mode 100644 arch/ppc64/lib/sstep.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 9cf35ed3f33a..a7af96ce9df2 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -5,7 +5,7 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := strcase.o string.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o -obj-$(CONFIG_PPC64) += usercopy_64.o sstep.o mem_64.o +obj-$(CONFIG_PPC64) += usercopy_64.o mem_64.o endif obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ @@ -13,4 +13,5 @@ obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o +obj-$(CONFIG_DEBUG_KERNEL) += sstep.o endif diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 49af089c6049..e8ce831d8eae 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -4,5 +4,3 @@ lib-y := string.o strcase.o lib-y += usercopy.o - -lib-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/arch/ppc64/lib/sstep.c b/arch/ppc64/lib/sstep.c deleted file mode 100644 index e79123d1485c..000000000000 --- a/arch/ppc64/lib/sstep.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Single-step support. - * - * Copyright (C) 2004 Paul Mackerras , IBM - * - * 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 - -extern char system_call_common[]; - -/* Bits in SRR1 that are copied from MSR */ -#define MSR_MASK 0xffffffff87c0ffff - -/* - * Determine whether a conditional branch instruction would branch. - */ -static int branch_taken(unsigned int instr, struct pt_regs *regs) -{ - unsigned int bo = (instr >> 21) & 0x1f; - unsigned int bi; - - if ((bo & 4) == 0) { - /* decrement counter */ - --regs->ctr; - if (((bo >> 1) & 1) ^ (regs->ctr == 0)) - return 0; - } - if ((bo & 0x10) == 0) { - /* check bit from CR */ - bi = (instr >> 16) & 0x1f; - if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1)) - return 0; - } - return 1; -} - -/* - * Emulate instructions that cause a transfer of control. - * Returns 1 if the step was emulated, 0 if not, - * or -1 if the instruction is one that should not be stepped, - * such as an rfid, or a mtmsrd that would clear MSR_RI. - */ -int emulate_step(struct pt_regs *regs, unsigned int instr) -{ - unsigned int opcode, rd; - unsigned long int imm; - - opcode = instr >> 26; - switch (opcode) { - case 16: /* bc */ - imm = (signed short)(instr & 0xfffc); - if ((instr & 2) == 0) - imm += regs->nip; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; - if (instr & 1) - regs->link = regs->nip; - if (branch_taken(instr, regs)) - regs->nip = imm; - return 1; - case 17: /* sc */ - /* - * N.B. this uses knowledge about how the syscall - * entry code works. If that is changed, this will - * need to be changed also. - */ - regs->gpr[9] = regs->gpr[13]; - regs->gpr[11] = regs->nip + 4; - regs->gpr[12] = regs->msr & MSR_MASK; - regs->gpr[13] = (unsigned long) get_paca(); - regs->nip = (unsigned long) &system_call_common; - regs->msr = MSR_KERNEL; - return 1; - case 18: /* b */ - imm = instr & 0x03fffffc; - if (imm & 0x02000000) - imm -= 0x04000000; - if ((instr & 2) == 0) - imm += regs->nip; - if (instr & 1) { - regs->link = regs->nip + 4; - if ((regs->msr & MSR_SF) == 0) - regs->link &= 0xffffffffUL; - } - if ((regs->msr & MSR_SF) == 0) - imm &= 0xffffffffUL; - regs->nip = imm; - return 1; - case 19: - switch (instr & 0x7fe) { - case 0x20: /* bclr */ - case 0x420: /* bcctr */ - imm = (instr & 0x400)? regs->ctr: regs->link; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) { - regs->nip &= 0xffffffffUL; - imm &= 0xffffffffUL; - } - if (instr & 1) - regs->link = regs->nip; - if (branch_taken(instr, regs)) - regs->nip = imm; - return 1; - case 0x24: /* rfid, scary */ - return -1; - } - case 31: - rd = (instr >> 21) & 0x1f; - switch (instr & 0x7fe) { - case 0xa6: /* mfmsr */ - regs->gpr[rd] = regs->msr & MSR_MASK; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; - return 1; - case 0x164: /* mtmsrd */ - /* only MSR_EE and MSR_RI get changed if bit 15 set */ - /* mtmsrd doesn't change MSR_HV and MSR_ME */ - imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL; - imm = (regs->msr & MSR_MASK & ~imm) - | (regs->gpr[rd] & imm); - if ((imm & MSR_RI) == 0) - /* can't step mtmsrd that would clear MSR_RI */ - return -1; - regs->msr = imm; - regs->nip += 4; - if ((imm & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; - return 1; - } - } - return 0; -} From a2b0ca84a1198505f0b3c7b55b7769dd5dbd0791 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 17:12:52 +1000 Subject: [PATCH 0805/1939] ppc64: user strcase.c from powerpc/lib since it is identical to strcase.c from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 5 +++-- arch/ppc64/lib/Makefile | 2 +- arch/ppc64/lib/strcase.c | 31 ------------------------------- 3 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 arch/ppc64/lib/strcase.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index a7af96ce9df2..0726235ef25d 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -3,11 +3,12 @@ # ifeq ($(CONFIG_PPC_MERGE),y) -obj-y := strcase.o string.o -obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o +obj-y := string.o obj-$(CONFIG_PPC64) += usercopy_64.o mem_64.o endif +obj-y += strcase.o +obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ memcpy_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index e8ce831d8eae..f4732c5ffd5f 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -2,5 +2,5 @@ # Makefile for ppc64-specific library files.. # -lib-y := string.o strcase.o +lib-y := string.o lib-y += usercopy.o diff --git a/arch/ppc64/lib/strcase.c b/arch/ppc64/lib/strcase.c deleted file mode 100644 index e84f243368c0..000000000000 --- a/arch/ppc64/lib/strcase.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * c 2001 PPC 64 Team, 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 - -int strcasecmp(const char *s1, const char *s2) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 == c2 && c1 != 0); - return c1 - c2; -} - -int strncasecmp(const char *s1, const char *s2, int n) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while ((--n > 0) && c1 == c2 && c1 != 0); - return c1 - c2; -} From a4a264f144d5389a52d467a7e41bec2834cfde75 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 17:28:21 +1000 Subject: [PATCH 0806/1939] ppc64: use usercopy_64.c from powerpc/lib since it is identical to usercopy.c from ppc64/lib. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 4 ++-- arch/ppc64/lib/Makefile | 1 - arch/ppc64/lib/usercopy.c | 41 --------------------------------------- 3 files changed, 2 insertions(+), 44 deletions(-) delete mode 100644 arch/ppc64/lib/usercopy.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 0726235ef25d..15b6b2696500 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -4,13 +4,13 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := string.o -obj-$(CONFIG_PPC64) += usercopy_64.o mem_64.o +obj-$(CONFIG_PPC64) += mem_64.o endif obj-y += strcase.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ - memcpy_64.o + memcpy_64.o usercopy_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index f4732c5ffd5f..42d5295bf345 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -3,4 +3,3 @@ # lib-y := string.o -lib-y += usercopy.o diff --git a/arch/ppc64/lib/usercopy.c b/arch/ppc64/lib/usercopy.c deleted file mode 100644 index 5eea6f3c1e03..000000000000 --- a/arch/ppc64/lib/usercopy.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Functions which are too large to be inlined. - * - * 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 - -unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) -{ - if (likely(access_ok(VERIFY_READ, from, n))) - n = __copy_from_user(to, from, n); - else - memset(to, 0, n); - return n; -} - -unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) -{ - if (likely(access_ok(VERIFY_WRITE, to, n))) - n = __copy_to_user(to, from, n); - return n; -} - -unsigned long copy_in_user(void __user *to, const void __user *from, - unsigned long n) -{ - might_sleep(); - if (likely(access_ok(VERIFY_READ, from, n) && - access_ok(VERIFY_WRITE, to, n))) - n =__copy_tofrom_user(to, from, n); - return n; -} - -EXPORT_SYMBOL(copy_from_user); -EXPORT_SYMBOL(copy_to_user); -EXPORT_SYMBOL(copy_in_user); - From 299f6ce491aa28515d86f29af2779cbfdc7a4790 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Oct 2005 18:03:58 +1000 Subject: [PATCH 0807/1939] ppc64: use mem_64.S from powerpc/lib and remove the same bits from ppc64/lib/string.S. Signed-off-by: Stephen Rothwell --- arch/powerpc/lib/Makefile | 3 +- arch/ppc64/lib/string.S | 106 -------------------------------------- 2 files changed, 1 insertion(+), 108 deletions(-) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 15b6b2696500..0115bf96751c 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -4,13 +4,12 @@ ifeq ($(CONFIG_PPC_MERGE),y) obj-y := string.o -obj-$(CONFIG_PPC64) += mem_64.o endif obj-y += strcase.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ - memcpy_64.o usercopy_64.o + memcpy_64.o usercopy_64.o mem_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o diff --git a/arch/ppc64/lib/string.S b/arch/ppc64/lib/string.S index 813587e5c2ec..e21a0038a4d6 100644 --- a/arch/ppc64/lib/string.S +++ b/arch/ppc64/lib/string.S @@ -65,112 +65,6 @@ _GLOBAL(strlen) subf r3,r3,r4 blr -_GLOBAL(memset) - neg r0,r3 - rlwimi r4,r4,8,16,23 - andi. r0,r0,7 /* # bytes to be 8-byte aligned */ - rlwimi r4,r4,16,0,15 - cmplw cr1,r5,r0 /* do we get that far? */ - rldimi r4,r4,32,0 - mtcrf 1,r0 - mr r6,r3 - blt cr1,8f - beq+ 3f /* if already 8-byte aligned */ - subf r5,r0,r5 - bf 31,1f - stb r4,0(r6) - addi r6,r6,1 -1: bf 30,2f - sth r4,0(r6) - addi r6,r6,2 -2: bf 29,3f - stw r4,0(r6) - addi r6,r6,4 -3: srdi. r0,r5,6 - clrldi r5,r5,58 - mtctr r0 - beq 5f -4: std r4,0(r6) - std r4,8(r6) - std r4,16(r6) - std r4,24(r6) - std r4,32(r6) - std r4,40(r6) - std r4,48(r6) - std r4,56(r6) - addi r6,r6,64 - bdnz 4b -5: srwi. r0,r5,3 - clrlwi r5,r5,29 - mtcrf 1,r0 - beq 8f - bf 29,6f - std r4,0(r6) - std r4,8(r6) - std r4,16(r6) - std r4,24(r6) - addi r6,r6,32 -6: bf 30,7f - std r4,0(r6) - std r4,8(r6) - addi r6,r6,16 -7: bf 31,8f - std r4,0(r6) - addi r6,r6,8 -8: cmpwi r5,0 - mtcrf 1,r5 - beqlr+ - bf 29,9f - stw r4,0(r6) - addi r6,r6,4 -9: bf 30,10f - sth r4,0(r6) - addi r6,r6,2 -10: bflr 31 - stb r4,0(r6) - blr - -_GLOBAL(memmove) - cmplw 0,r3,r4 - bgt .backwards_memcpy - b .memcpy - -_GLOBAL(backwards_memcpy) - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - add r6,r3,r5 - add r4,r4,r5 - beq 2f - andi. r0,r6,3 - mtctr r7 - bne 5f -1: lwz r7,-4(r4) - lwzu r8,-8(r4) - stw r7,-4(r6) - stwu r8,-8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,-4(r4) - subi r5,r5,4 - stwu r0,-4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 -4: lbzu r0,-1(r4) - stbu r0,-1(r6) - bdnz 4b - blr -5: mtctr r0 -6: lbzu r7,-1(r4) - stbu r7,-1(r6) - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - _GLOBAL(memcmp) cmpwi 0,r5,0 ble- 2f From 089a1bedd84be16a4f49a319e7ccb4a128da5ce9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 27 Oct 2005 20:33:43 -0700 Subject: [PATCH 0808/1939] [IB] ib_umad: fix crash when freeing send buffers The conversion of user_mad.c to the new MAD send API was slightly off: in a few places, we used packet->msg instead of packet->msg->mad when referring to the actual data buffer, which ended up corrupting the underlying data structure and crashing when we free an invalid pointer. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index fc5519a3de99..a48166a8e04b 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -398,12 +398,12 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, * transaction ID matches the agent being used to send the * MAD. */ - method = ((struct ib_mad_hdr *) packet->msg)->method; + method = ((struct ib_mad_hdr *) packet->msg->mad)->method; if (!(method & IB_MGMT_METHOD_RESP) && method != IB_MGMT_METHOD_TRAP_REPRESS && method != IB_MGMT_METHOD_SEND) { - tid = &((struct ib_mad_hdr *) packet->msg)->tid; + tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | (be64_to_cpup(tid) & 0xffffffff)); } From cb0f0910f4b41772a6771bdb4fb2d419b27bcd77 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Thu, 27 Oct 2005 20:48:11 -0700 Subject: [PATCH 0809/1939] [IB] ib_umad: various cleanups Simplify user_mad.c code in a few places, and convert from kmalloc() + memset() to kzalloc(). This also fixes a theoretical race window by not accessing packet->length after posting the send buffer (the send could complete and packet could be freed before we get to the return statement at the end of ib_umad_write()). Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 73 +++++++++--------------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index a48166a8e04b..17ec0a19dbc0 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -99,7 +99,6 @@ struct ib_umad_packet { struct ib_mad_send_buf *msg; struct list_head list; int length; - DECLARE_PCI_UNMAP_ADDR(mapping) struct ib_user_mad mad; }; @@ -145,15 +144,12 @@ static void send_handler(struct ib_mad_agent *agent, ib_free_send_mad(packet->msg); if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { - timeout = kmalloc(sizeof *timeout + sizeof (struct ib_mad_hdr), - GFP_KERNEL); + timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL); if (!timeout) goto out; - memset(timeout, 0, sizeof *timeout + sizeof (struct ib_mad_hdr)); - - timeout->length = sizeof (struct ib_mad_hdr); - timeout->mad.hdr.id = packet->mad.hdr.id; + timeout->length = IB_MGMT_MAD_HDR; + timeout->mad.hdr.id = packet->mad.hdr.id; timeout->mad.hdr.status = ETIMEDOUT; memcpy(timeout->mad.data, packet->mad.data, sizeof (struct ib_mad_hdr)); @@ -176,11 +172,10 @@ static void recv_handler(struct ib_mad_agent *agent, goto out; length = mad_recv_wc->mad_len; - packet = kmalloc(sizeof *packet + length, GFP_KERNEL); + packet = kzalloc(sizeof *packet + length, GFP_KERNEL); if (!packet) goto out; - memset(packet, 0, sizeof *packet + length); packet->length = length; ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data); @@ -246,7 +241,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, else ret = -ENOSPC; } else if (copy_to_user(buf, &packet->mad, - packet->length + sizeof (struct ib_user_mad))) + packet->length + sizeof (struct ib_user_mad))) ret = -EFAULT; else ret = packet->length + sizeof (struct ib_user_mad); @@ -271,22 +266,19 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, struct ib_rmpp_mad *rmpp_mad; u8 method; __be64 *tid; - int ret, length, hdr_len, rmpp_hdr_size; + int ret, length, hdr_len, copy_offset; int rmpp_active = 0; if (count < sizeof (struct ib_user_mad)) return -EINVAL; length = count - sizeof (struct ib_user_mad); - packet = kmalloc(sizeof *packet + sizeof(struct ib_mad_hdr) + - sizeof (struct ib_rmpp_hdr), GFP_KERNEL); + packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); if (!packet) return -ENOMEM; if (copy_from_user(&packet->mad, buf, - sizeof (struct ib_user_mad) + - sizeof (struct ib_mad_hdr) + - sizeof (struct ib_rmpp_hdr))) { + sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) { ret = -EFAULT; goto err; } @@ -297,8 +289,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } - packet->length = length; - down_read(&file->agent_mutex); agent = file->agent[packet->mad.hdr.id]; @@ -345,12 +335,10 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err_ah; } rmpp_active = 1; + copy_offset = IB_MGMT_RMPP_HDR; } else { - if (length > sizeof (struct ib_mad)) { - ret = -EINVAL; - goto err_ah; - } hdr_len = IB_MGMT_MAD_HDR; + copy_offset = IB_MGMT_MAD_HDR; } packet->msg = ib_create_send_mad(agent, @@ -368,28 +356,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, packet->msg->retries = packet->mad.hdr.retries; packet->msg->context[0] = packet; - if (!rmpp_active) { - /* Copy message from user into send buffer */ - if (copy_from_user(packet->msg->mad, - buf + sizeof (struct ib_user_mad), length)) { - ret = -EFAULT; - goto err_msg; - } - } else { - rmpp_hdr_size = sizeof (struct ib_mad_hdr) + - sizeof (struct ib_rmpp_hdr); - - /* Only copy MAD headers (RMPP header in place) */ - memcpy(packet->msg->mad, packet->mad.data, - sizeof (struct ib_mad_hdr)); - - /* Now, copy rest of message from user into send buffer */ - if (copy_from_user(((struct ib_rmpp_mad *) packet->msg->mad)->data, - buf + sizeof (struct ib_user_mad) + rmpp_hdr_size, - length - rmpp_hdr_size)) { - ret = -EFAULT; - goto err_msg; - } + /* Copy MAD headers (RMPP header in place) */ + memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); + /* Now, copy rest of message from user into send buffer */ + if (copy_from_user(packet->msg->mad + copy_offset, + buf + sizeof (struct ib_user_mad) + copy_offset, + length - copy_offset)) { + ret = -EFAULT; + goto err_msg; } /* @@ -414,7 +388,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, up_read(&file->agent_mutex); - return sizeof (struct ib_user_mad_hdr) + packet->length; + return count; err_msg: ib_free_send_mad(packet->msg); @@ -564,12 +538,10 @@ static int ib_umad_open(struct inode *inode, struct file *filp) container_of(inode->i_cdev, struct ib_umad_port, dev); struct ib_umad_file *file; - file = kmalloc(sizeof *file, GFP_KERNEL); + file = kzalloc(sizeof *file, GFP_KERNEL); if (!file) return -ENOMEM; - memset(file, 0, sizeof *file); - spin_lock_init(&file->recv_lock); init_rwsem(&file->agent_mutex); INIT_LIST_HEAD(&file->recv_list); @@ -814,15 +786,12 @@ static void ib_umad_add_one(struct ib_device *device) e = device->phys_port_cnt; } - umad_dev = kmalloc(sizeof *umad_dev + + umad_dev = kzalloc(sizeof *umad_dev + (e - s + 1) * sizeof (struct ib_umad_port), GFP_KERNEL); if (!umad_dev) return; - memset(umad_dev, 0, sizeof *umad_dev + - (e - s + 1) * sizeof (struct ib_umad_port)); - kref_init(&umad_dev->ref); umad_dev->start_port = s; From 20e5c81fcff89535dced2ed71cf24c6c648ff40e Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Thu, 13 Oct 2005 21:48:42 +0200 Subject: [PATCH 0810/1939] [patch] remove gendisk->stamp_idle field struct gendisk has these two fields: stamp, stamp_idle. Update to stamp_idle is always in sync with stamp and they are always the same. Therefore, it does not add any value in having two fields tracking same timestamp. Suggest to remove it. Also, we should only update gendisk stats with non-zero value. Advantage is that we don't have to needlessly calculate memory address, and then add zero to the content. Signed-off-by: Ken Chen Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 11 +++++------ fs/partitions/check.c | 2 +- include/linux/genhd.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index baedac522945..c42071fd2e95 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2433,13 +2433,12 @@ void disk_round_stats(struct gendisk *disk) { unsigned long now = jiffies; - __disk_stat_add(disk, time_in_queue, - disk->in_flight * (now - disk->stamp)); + if (disk->in_flight) { + __disk_stat_add(disk, time_in_queue, + disk->in_flight * (now - disk->stamp)); + __disk_stat_add(disk, io_ticks, (now - disk->stamp)); + } disk->stamp = now; - - if (disk->in_flight) - __disk_stat_add(disk, io_ticks, (now - disk->stamp_idle)); - disk->stamp_idle = now; } /* diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 77e178f13162..1e848648a322 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -430,7 +430,7 @@ void del_gendisk(struct gendisk *disk) disk->flags &= ~GENHD_FL_UP; unlink_gendisk(disk); disk_stat_set_all(disk, 0); - disk->stamp = disk->stamp_idle = 0; + disk->stamp = 0; devfs_remove_disk(disk); diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 01796c41c951..142e1c1e0689 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -119,7 +119,7 @@ struct gendisk { int policy; atomic_t sync_io; /* RAID */ - unsigned long stamp, stamp_idle; + unsigned long stamp; int in_flight; #ifdef CONFIG_SMP struct disk_stats *dkstats; From b2982649ce38293b14684b26bcda20cfc54164e6 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Thu, 13 Oct 2005 21:49:29 +0200 Subject: [PATCH 0811/1939] Following the same idea, it occurs to me that we should only update disk stat when "now" is different from disk->stamp. Otherwise, we are again needlessly adding zero to the stats. Signed-off-by: Ken Chen Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index c42071fd2e95..4e2b1b06b411 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2433,6 +2433,9 @@ void disk_round_stats(struct gendisk *disk) { unsigned long now = jiffies; + if (now == disk->stamp) + return; + if (disk->in_flight) { __disk_stat_add(disk, time_in_queue, disk->in_flight * (now - disk->stamp)); From 2824bc9328467127083c1325f54b67d298c333b2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Oct 2005 10:56:41 +0200 Subject: [PATCH 0812/1939] [PATCH] fix try_module_get race in elevator_find This patch removes try_module_get race in elevator_find. try_module_get should always be called with the spinlock protecting what the module init/cleanup routines register/unregister to held. In the case of elevators, we should be holding elv_list to avoid it going away between spin_unlock_irq and try_module_get. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 98f0126a2deb..4144f30d82a9 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -97,7 +97,6 @@ static struct elevator_type *elevator_find(const char *name) struct elevator_type *e = NULL; struct list_head *entry; - spin_lock_irq(&elv_list_lock); list_for_each(entry, &elv_list) { struct elevator_type *__e; @@ -108,7 +107,6 @@ static struct elevator_type *elevator_find(const char *name) break; } } - spin_unlock_irq(&elv_list_lock); return e; } @@ -120,12 +118,15 @@ static void elevator_put(struct elevator_type *e) static struct elevator_type *elevator_get(const char *name) { - struct elevator_type *e = elevator_find(name); + struct elevator_type *e; - if (!e) - return NULL; - if (!try_module_get(e->elevator_owner)) - return NULL; + spin_lock_irq(&elv_list_lock); + + e = elevator_find(name); + if (e && !try_module_get(e->elevator_owner)) + e = NULL; + + spin_unlock_irq(&elv_list_lock); return e; } @@ -153,11 +154,15 @@ static char chosen_elevator[16]; static void elevator_setup_default(void) { + struct elevator_type *e; + /* * check if default is set and exists */ - if (chosen_elevator[0] && elevator_find(chosen_elevator)) + if (chosen_elevator[0] && (e = elevator_get(chosen_elevator))) { + elevator_put(e); return; + } #if defined(CONFIG_IOSCHED_AS) strcpy(chosen_elevator, "anticipatory"); @@ -555,10 +560,9 @@ void elv_unregister_queue(struct request_queue *q) int elv_register(struct elevator_type *e) { + spin_lock_irq(&elv_list_lock); if (elevator_find(e->elevator_name)) BUG(); - - spin_lock_irq(&elv_list_lock); list_add_tail(&e->list, &elv_list); spin_unlock_irq(&elv_list_lock); From 007e8f51b26ae7b6a17651af5a0f01ab6491cdca Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 28 Oct 2005 15:35:50 +1000 Subject: [PATCH 0813/1939] [PATCH] powerpc: Move xics.[ch] into platforms/pseries This patch moves the XICS interrupt controller code into the platforms/pseries directory, since it only appears on pSeries machines. If it ever appears on some other machine we can move it to sysdev, although xics.c itself will need a bunch of changes in that case to remove pSeries specific assumptions. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/Makefile | 1 + arch/powerpc/platforms/pseries/setup.c | 2 +- arch/powerpc/platforms/pseries/smp.c | 2 +- .../platforms/pseries}/xics.c | 25 ++++++++++--------- .../powerpc/platforms/pseries}/xics.h | 10 ++++---- arch/ppc64/kernel/Makefile | 2 -- 6 files changed, 21 insertions(+), 21 deletions(-) rename arch/{ppc64/kernel => powerpc/platforms/pseries}/xics.c (98%) rename {include/asm-ppc64 => arch/powerpc/platforms/pseries}/xics.h (84%) diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index d5c160b789e3..5ef494e3a70f 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -2,3 +2,4 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o rtas-fw.o ras.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_IBMVIO) += vio.o +obj-$(CONFIG_XICS) += xics.o diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 7e7e556e6b48..10cb0f2d9b5b 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -59,7 +59,7 @@ #include #include #include -#include +#include "xics.h" #include #include #include diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index ae1bd270f308..9c9458ddfc25 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include "xics.h" #include #include #include diff --git a/arch/ppc64/kernel/xics.c b/arch/powerpc/platforms/pseries/xics.c similarity index 98% rename from arch/ppc64/kernel/xics.c rename to arch/powerpc/platforms/pseries/xics.c index a32207dcf2e3..c72c86f05cb6 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -1,5 +1,5 @@ -/* - * arch/ppc64/kernel/xics.c +/* + * arch/powerpc/platforms/pseries/xics.c * * Copyright 2000 IBM Corporation. * @@ -25,11 +25,12 @@ #include #include #include -#include #include #include #include +#include "xics.h" + static unsigned int xics_startup(unsigned int irq); static void xics_enable_irq(unsigned int irq); static void xics_disable_irq(unsigned int irq); @@ -61,7 +62,7 @@ static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC); /* Want a priority other than 0. Various HW issues require this. */ #define DEFAULT_PRIORITY 5 -/* +/* * Mark IPIs as higher priority so we can take them inside interrupts that * arent marked SA_INTERRUPT */ @@ -168,11 +169,11 @@ static inline long plpar_xirr(unsigned long *xirr_ret) static int pSeriesLP_xirr_info_get(int n_cpu) { unsigned long lpar_rc; - unsigned long return_value; + unsigned long return_value; lpar_rc = plpar_xirr(&return_value); if (lpar_rc != H_Success) - panic(" bad return code xirr - rc = %lx \n", lpar_rc); + panic(" bad return code xirr - rc = %lx \n", lpar_rc); return (int)return_value; } @@ -184,7 +185,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value) lpar_rc = plpar_eoi(val64); if (lpar_rc != H_Success) panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, - val64); + val64); } void pSeriesLP_cppr_info(int n_cpu, u8 value) @@ -193,7 +194,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value) lpar_rc = plpar_cppr(value); if (lpar_rc != H_Success) - panic("bad return code cppr - rc = %lx\n", lpar_rc); + panic("bad return code cppr - rc = %lx\n", lpar_rc); } static void pSeriesLP_qirr_info(int n_cpu , u8 value) @@ -202,7 +203,7 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value) lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); if (lpar_rc != H_Success) - panic("bad return code qirr - rc = %lx\n", lpar_rc); + panic("bad return code qirr - rc = %lx\n", lpar_rc); } xics_ops pSeriesLP_ops = { @@ -461,7 +462,7 @@ void xics_init_IRQ(void) struct xics_interrupt_node { unsigned long addr; unsigned long size; - } intnodes[NR_CPUS]; + } intnodes[NR_CPUS]; ppc64_boot_msg(0x20, "XICS Init"); @@ -486,7 +487,7 @@ void xics_init_IRQ(void) ireg = (uint *)get_property(np, "reg", &ilen); if (!ireg) panic("xics_init_IRQ: can't find interrupt reg property"); - + while (ilen) { intnodes[indx].addr = (unsigned long)*ireg++ << 32; ilen -= sizeof(uint); @@ -554,7 +555,7 @@ void xics_init_IRQ(void) continue; hard_id = get_hard_smp_processor_id(i); - xics_per_cpu[i] = ioremap(intnodes[hard_id].addr, + xics_per_cpu[i] = ioremap(intnodes[hard_id].addr, intnodes[hard_id].size); } #else diff --git a/include/asm-ppc64/xics.h b/arch/powerpc/platforms/pseries/xics.h similarity index 84% rename from include/asm-ppc64/xics.h rename to arch/powerpc/platforms/pseries/xics.h index 1092af55d707..e14c70868f1d 100644 --- a/include/asm-ppc64/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h @@ -1,5 +1,5 @@ -/* - * arch/ppc64/kernel/xics.h +/* + * arch/powerpc/platforms/pseries/xics.h * * Copyright 2000 IBM Corporation. * @@ -9,8 +9,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _PPC64_KERNEL_XICS_H -#define _PPC64_KERNEL_XICS_H +#ifndef _POWERPC_KERNEL_XICS_H +#define _POWERPC_KERNEL_XICS_H #include @@ -31,4 +31,4 @@ struct xics_ipi_struct { extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; -#endif /* _PPC64_KERNEL_XICS_H */ +#endif /* _POWERPC_KERNEL_XICS_H */ diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index a20a305b825d..3cf7f3dab511 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -53,8 +53,6 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o endif obj-$(CONFIG_HVCS) += hvcserver.o -obj-$(CONFIG_XICS) += xics.o - obj-$(CONFIG_PPC_PMAC) += udbg_scc.o obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ From 8922e16cf6269e668123acb1ae1fdc62b7a3a4fc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Oct 2005 16:23:44 +0200 Subject: [PATCH 0814/1939] [PATCH] 01/05 Implement generic dispatch queue Implements generic dispatch queue which can replace all dispatch queues implemented by each iosched. This reduces code duplication, eases enforcing semantics over dispatch queue, and simplifies specific ioscheds. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 242 ++++++++++++++++++++++++++------------ drivers/block/ll_rw_blk.c | 25 ++-- include/linux/blkdev.h | 17 ++- include/linux/elevator.h | 16 ++- 4 files changed, 202 insertions(+), 98 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 4144f30d82a9..a27555908d35 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -40,6 +40,11 @@ static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); +static inline sector_t rq_last_sector(struct request *rq) +{ + return rq->sector + rq->nr_sectors; +} + /* * can we safely merge with this request? */ @@ -143,6 +148,9 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, INIT_LIST_HEAD(&q->queue_head); q->last_merge = NULL; q->elevator = eq; + q->last_sector = 0; + q->boundary_rq = NULL; + q->max_back_kb = 0; if (eq->ops->elevator_init_fn) ret = eq->ops->elevator_init_fn(q, eq); @@ -225,6 +233,48 @@ void elevator_exit(elevator_t *e) kfree(e); } +/* + * Insert rq into dispatch queue of q. Queue lock must be held on + * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be + * appended to the dispatch queue. To be used by specific elevators. + */ +void elv_dispatch_insert(request_queue_t *q, struct request *rq, int sort) +{ + sector_t boundary; + unsigned max_back; + struct list_head *entry; + + if (!sort) { + /* Specific elevator is performing sort. Step away. */ + q->last_sector = rq_last_sector(rq); + q->boundary_rq = rq; + list_add_tail(&rq->queuelist, &q->queue_head); + return; + } + + boundary = q->last_sector; + max_back = q->max_back_kb * 2; + boundary = boundary > max_back ? boundary - max_back : 0; + + list_for_each_prev(entry, &q->queue_head) { + struct request *pos = list_entry_rq(entry); + + if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) + break; + if (rq->sector >= boundary) { + if (pos->sector < boundary) + continue; + } else { + if (pos->sector >= boundary) + break; + } + if (rq->sector >= pos->sector) + break; + } + + list_add(&rq->queuelist, entry); +} + int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; @@ -255,13 +305,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, e->ops->elevator_merge_req_fn(q, rq, next); } -/* - * For careful internal use by the block layer. Essentially the same as - * a requeue in that it tells the io scheduler that this request is not - * active in the driver or hardware anymore, but we don't want the request - * added back to the scheduler. Function is not exported. - */ -void elv_deactivate_request(request_queue_t *q, struct request *rq) +void elv_requeue_request(request_queue_t *q, struct request *rq) { elevator_t *e = q->elevator; @@ -269,19 +313,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq) * it already went through dequeue, we need to decrement the * in_flight count again */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; + if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); + } rq->flags &= ~REQ_STARTED; - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); -} - -void elv_requeue_request(request_queue_t *q, struct request *rq) -{ - elv_deactivate_request(q, rq); - /* * if this is the flush, requeue the original instead and drop the flush */ @@ -290,55 +329,89 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) rq = rq->end_io_data; } - /* - * the request is prepped and may have some resources allocated. - * allowing unprepped requests to pass this one may cause resource - * deadlock. turn on softbarrier. - */ - rq->flags |= REQ_SOFTBARRIER; - - /* - * if iosched has an explicit requeue hook, then use that. otherwise - * just put the request at the front of the queue - */ - if (q->elevator->ops->elevator_requeue_req_fn) - q->elevator->ops->elevator_requeue_req_fn(q, rq); - else - __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); + __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); } void __elv_add_request(request_queue_t *q, struct request *rq, int where, int plug) { - /* - * barriers implicitly indicate back insertion - */ - if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) && - where == ELEVATOR_INSERT_SORT) - where = ELEVATOR_INSERT_BACK; + if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { + /* + * barriers implicitly indicate back insertion + */ + if (where == ELEVATOR_INSERT_SORT) + where = ELEVATOR_INSERT_BACK; + + /* + * this request is scheduling boundary, update last_sector + */ + if (blk_fs_request(rq)) { + q->last_sector = rq_last_sector(rq); + q->boundary_rq = rq; + } + } if (plug) blk_plug_device(q); rq->q = q; - if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) { - q->elevator->ops->elevator_add_req_fn(q, rq, where); - - if (blk_queue_plugged(q)) { - int nrq = q->rq.count[READ] + q->rq.count[WRITE] - - q->in_flight; - - if (nrq >= q->unplug_thresh) - __generic_unplug_device(q); - } - } else + if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { /* * if drain is set, store the request "locally". when the drain * is finished, the requests will be handed ordered to the io * scheduler */ list_add_tail(&rq->queuelist, &q->drain_list); + return; + } + + switch (where) { + case ELEVATOR_INSERT_FRONT: + rq->flags |= REQ_SOFTBARRIER; + + list_add(&rq->queuelist, &q->queue_head); + break; + + case ELEVATOR_INSERT_BACK: + rq->flags |= REQ_SOFTBARRIER; + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + list_add_tail(&rq->queuelist, &q->queue_head); + /* + * We kick the queue here for the following reasons. + * - The elevator might have returned NULL previously + * to delay requests and returned them now. As the + * queue wasn't empty before this request, ll_rw_blk + * won't run the queue on return, resulting in hang. + * - Usually, back inserted requests won't be merged + * with anything. There's no point in delaying queue + * processing. + */ + blk_remove_plug(q); + q->request_fn(q); + break; + + case ELEVATOR_INSERT_SORT: + BUG_ON(!blk_fs_request(rq)); + rq->flags |= REQ_SORTED; + q->elevator->ops->elevator_add_req_fn(q, rq); + break; + + default: + printk(KERN_ERR "%s: bad insertion point %d\n", + __FUNCTION__, where); + BUG(); + } + + if (blk_queue_plugged(q)) { + int nrq = q->rq.count[READ] + q->rq.count[WRITE] + - q->in_flight; + + if (nrq >= q->unplug_thresh) + __generic_unplug_device(q); + } } void elv_add_request(request_queue_t *q, struct request *rq, int where, @@ -353,13 +426,19 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, static inline struct request *__elv_next_request(request_queue_t *q) { - struct request *rq = q->elevator->ops->elevator_next_req_fn(q); + struct request *rq; + + if (unlikely(list_empty(&q->queue_head) && + !q->elevator->ops->elevator_dispatch_fn(q, 0))) + return NULL; + + rq = list_entry_rq(q->queue_head.next); /* * if this is a barrier write and the device has to issue a * flush sequence to support it, check how far we are */ - if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) { + if (blk_fs_request(rq) && blk_barrier_rq(rq)) { BUG_ON(q->ordered == QUEUE_ORDERED_NONE); if (q->ordered == QUEUE_ORDERED_FLUSH && @@ -376,16 +455,34 @@ struct request *elv_next_request(request_queue_t *q) int ret; while ((rq = __elv_next_request(q)) != NULL) { - /* - * just mark as started even if we don't start it, a request - * that has been delayed should not be passed by new incoming - * requests - */ - rq->flags |= REQ_STARTED; + if (!(rq->flags & REQ_STARTED)) { + elevator_t *e = q->elevator; + + /* + * This is the first time the device driver + * sees this request (possibly after + * requeueing). Notify IO scheduler. + */ + if (blk_sorted_rq(rq) && + e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); + + /* + * just mark as started even if we don't start + * it, a request that has been delayed should + * not be passed by new incoming requests + */ + rq->flags |= REQ_STARTED; + } if (rq == q->last_merge) q->last_merge = NULL; + if (!q->boundary_rq || q->boundary_rq == rq) { + q->last_sector = rq_last_sector(rq); + q->boundary_rq = NULL; + } + if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn) break; @@ -396,9 +493,9 @@ struct request *elv_next_request(request_queue_t *q) /* * the request may have been (partially) prepped. * we need to keep this request in the front to - * avoid resource deadlock. turn on softbarrier. + * avoid resource deadlock. REQ_STARTED will + * prevent other fs requests from passing this one. */ - rq->flags |= REQ_SOFTBARRIER; rq = NULL; break; } else if (ret == BLKPREP_KILL) { @@ -421,16 +518,16 @@ struct request *elv_next_request(request_queue_t *q) return rq; } -void elv_remove_request(request_queue_t *q, struct request *rq) +void elv_dequeue_request(request_queue_t *q, struct request *rq) { - elevator_t *e = q->elevator; + BUG_ON(list_empty(&rq->queuelist)); + + list_del_init(&rq->queuelist); /* * the time frame between a request being removed from the lists * and to it is freed is accounted as io that is in progress at - * the driver side. note that we only account requests that the - * driver has seen (REQ_STARTED set), to avoid false accounting - * for request-request merges + * the driver side. */ if (blk_account_rq(rq)) q->in_flight++; @@ -444,19 +541,19 @@ void elv_remove_request(request_queue_t *q, struct request *rq) */ if (rq == q->last_merge) q->last_merge = NULL; - - if (e->ops->elevator_remove_req_fn) - e->ops->elevator_remove_req_fn(q, rq); } int elv_queue_empty(request_queue_t *q) { elevator_t *e = q->elevator; + if (!list_empty(&q->queue_head)) + return 0; + if (e->ops->elevator_queue_empty_fn) return e->ops->elevator_queue_empty_fn(q); - return list_empty(&q->queue_head); + return 1; } struct request *elv_latter_request(request_queue_t *q, struct request *rq) @@ -528,11 +625,11 @@ void elv_completed_request(request_queue_t *q, struct request *rq) /* * request is released from the driver, io must be done */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; - - if (e->ops->elevator_completed_req_fn) - e->ops->elevator_completed_req_fn(q, rq); + if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) + e->ops->elevator_completed_req_fn(q, rq); + } } int elv_register_queue(struct request_queue *q) @@ -705,11 +802,12 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } +EXPORT_SYMBOL(elv_dispatch_insert); EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_requeue_request); EXPORT_SYMBOL(elv_next_request); -EXPORT_SYMBOL(elv_remove_request); +EXPORT_SYMBOL(elv_dequeue_request); EXPORT_SYMBOL(elv_queue_empty); EXPORT_SYMBOL(elv_completed_request); EXPORT_SYMBOL(elevator_exit); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 4e2b1b06b411..d2a66fd309c3 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -353,6 +353,8 @@ static void blk_pre_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_PREFLUSH; if (!flush_rq->errors) @@ -369,6 +371,8 @@ static void blk_post_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_POSTFLUSH; q->end_flush_fn(q, flush_rq); @@ -408,8 +412,6 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) if (!list_empty(&rq->queuelist)) blkdev_dequeue_request(rq); - elv_deactivate_request(q, rq); - flush_rq->end_io_data = rq; flush_rq->end_io = blk_pre_flush_end_io; @@ -1040,6 +1042,7 @@ EXPORT_SYMBOL(blk_queue_invalidate_tags); static char *rq_flags[] = { "REQ_RW", "REQ_FAILFAST", + "REQ_SORTED", "REQ_SOFTBARRIER", "REQ_HARDBARRIER", "REQ_CMD", @@ -2456,6 +2459,8 @@ static void __blk_put_request(request_queue_t *q, struct request *req) if (unlikely(--req->ref_count)) return; + elv_completed_request(q, req); + req->rq_status = RQ_INACTIVE; req->rl = NULL; @@ -2466,8 +2471,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req) if (rl) { int rw = rq_data_dir(req); - elv_completed_request(q, req); - BUG_ON(!list_empty(&req->queuelist)); blk_free_request(q, req); @@ -2477,14 +2480,14 @@ static void __blk_put_request(request_queue_t *q, struct request *req) void blk_put_request(struct request *req) { - /* - * if req->rl isn't set, this request didnt originate from the - * block layer, so it's safe to just disregard it - */ - if (req->rl) { - unsigned long flags; - request_queue_t *q = req->q; + unsigned long flags; + request_queue_t *q = req->q; + /* + * Gee, IDE calls in w/ NULL q. Fix IDE and remove the + * following if (q) test. + */ + if (q) { spin_lock_irqsave(q->queue_lock, flags); __blk_put_request(q, req); spin_unlock_irqrestore(q->queue_lock, flags); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index efdc9b5bc05c..2c7b9154927a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -203,6 +203,7 @@ struct request { enum rq_flag_bits { __REQ_RW, /* not set, read. set, write */ __REQ_FAILFAST, /* no low level driver retries */ + __REQ_SORTED, /* elevator knows about this request */ __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ __REQ_HARDBARRIER, /* may not be passed by drive either */ __REQ_CMD, /* is a regular fs rw request */ @@ -235,6 +236,7 @@ enum rq_flag_bits { #define REQ_RW (1 << __REQ_RW) #define REQ_FAILFAST (1 << __REQ_FAILFAST) +#define REQ_SORTED (1 << __REQ_SORTED) #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) #define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) #define REQ_CMD (1 << __REQ_CMD) @@ -332,6 +334,13 @@ struct request_queue prepare_flush_fn *prepare_flush_fn; end_flush_fn *end_flush_fn; + /* + * Dispatch queue sorting + */ + sector_t last_sector; + struct request *boundary_rq; + unsigned int max_back_kb; + /* * Auto-unplugging state */ @@ -454,6 +463,7 @@ enum { #define blk_pm_request(rq) \ ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME)) +#define blk_sorted_rq(rq) ((rq)->flags & REQ_SORTED) #define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER) #define blk_barrier_preflush(rq) ((rq)->flags & REQ_BAR_PREFLUSH) #define blk_barrier_postflush(rq) ((rq)->flags & REQ_BAR_POSTFLUSH) @@ -611,12 +621,7 @@ extern void end_request(struct request *req, int uptodate); static inline void blkdev_dequeue_request(struct request *req) { - BUG_ON(list_empty(&req->queuelist)); - - list_del_init(&req->queuelist); - - if (req->rl) - elv_remove_request(req->q, req); + elv_dequeue_request(req->q, req); } /* diff --git a/include/linux/elevator.h b/include/linux/elevator.h index ea6bbc2d7407..76f4f6920744 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -8,18 +8,17 @@ typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struc typedef void (elevator_merged_fn) (request_queue_t *, struct request *); -typedef struct request *(elevator_next_req_fn) (request_queue_t *); +typedef int (elevator_dispatch_fn) (request_queue_t *, int); -typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, int); +typedef void (elevator_add_req_fn) (request_queue_t *, struct request *); typedef int (elevator_queue_empty_fn) (request_queue_t *); -typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); -typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *); typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *); typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *); typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, int); typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); +typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *); typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); typedef int (elevator_init_fn) (request_queue_t *, elevator_t *); @@ -31,10 +30,9 @@ struct elevator_ops elevator_merged_fn *elevator_merged_fn; elevator_merge_req_fn *elevator_merge_req_fn; - elevator_next_req_fn *elevator_next_req_fn; + elevator_dispatch_fn *elevator_dispatch_fn; elevator_add_req_fn *elevator_add_req_fn; - elevator_remove_req_fn *elevator_remove_req_fn; - elevator_requeue_req_fn *elevator_requeue_req_fn; + elevator_activate_req_fn *elevator_activate_req_fn; elevator_deactivate_req_fn *elevator_deactivate_req_fn; elevator_queue_empty_fn *elevator_queue_empty_fn; @@ -81,15 +79,15 @@ struct elevator_queue /* * block elevator interface */ +extern void elv_dispatch_insert(request_queue_t *, struct request *, int); extern void elv_add_request(request_queue_t *, struct request *, int, int); extern void __elv_add_request(request_queue_t *, struct request *, int, int); extern int elv_merge(request_queue_t *, struct request **, struct bio *); extern void elv_merge_requests(request_queue_t *, struct request *, struct request *); extern void elv_merged_request(request_queue_t *, struct request *); -extern void elv_remove_request(request_queue_t *, struct request *); +extern void elv_dequeue_request(request_queue_t *, struct request *); extern void elv_requeue_request(request_queue_t *, struct request *); -extern void elv_deactivate_request(request_queue_t *, struct request *); extern int elv_queue_empty(request_queue_t *); extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(request_queue_t *, struct request *); From 1b47f531e244e339b648dfff071c086f936e49e1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 20 Oct 2005 16:37:00 +0200 Subject: [PATCH 0815/1939] [PATCH] generic dispatch fixes - Split elv_dispatch_insert() into two functions - Rename rq_last_sector() to rq_end_sector() Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 33 ++++++++++++--------------------- include/linux/blkdev.h | 13 ++++++++++++- include/linux/elevator.h | 4 +++- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index a27555908d35..237e43d760c8 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -40,11 +40,6 @@ static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); -static inline sector_t rq_last_sector(struct request *rq) -{ - return rq->sector + rq->nr_sectors; -} - /* * can we safely merge with this request? */ @@ -148,7 +143,7 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, INIT_LIST_HEAD(&q->queue_head); q->last_merge = NULL; q->elevator = eq; - q->last_sector = 0; + q->end_sector = 0; q->boundary_rq = NULL; q->max_back_kb = 0; @@ -233,29 +228,25 @@ void elevator_exit(elevator_t *e) kfree(e); } +void elv_dispatch_insert_tail(request_queue_t *q, struct request *rq) +{ +} + /* * Insert rq into dispatch queue of q. Queue lock must be held on * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be * appended to the dispatch queue. To be used by specific elevators. */ -void elv_dispatch_insert(request_queue_t *q, struct request *rq, int sort) +void elv_dispatch_sort(request_queue_t *q, struct request *rq) { sector_t boundary; unsigned max_back; struct list_head *entry; - if (!sort) { - /* Specific elevator is performing sort. Step away. */ - q->last_sector = rq_last_sector(rq); - q->boundary_rq = rq; - list_add_tail(&rq->queuelist, &q->queue_head); - return; - } - - boundary = q->last_sector; + boundary = q->end_sector; max_back = q->max_back_kb * 2; boundary = boundary > max_back ? boundary - max_back : 0; - + list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); @@ -343,10 +334,10 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, where = ELEVATOR_INSERT_BACK; /* - * this request is scheduling boundary, update last_sector + * this request is scheduling boundary, update end_sector */ if (blk_fs_request(rq)) { - q->last_sector = rq_last_sector(rq); + q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; } } @@ -479,7 +470,7 @@ struct request *elv_next_request(request_queue_t *q) q->last_merge = NULL; if (!q->boundary_rq || q->boundary_rq == rq) { - q->last_sector = rq_last_sector(rq); + q->end_sector = rq_end_sector(rq); q->boundary_rq = NULL; } @@ -802,7 +793,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } -EXPORT_SYMBOL(elv_dispatch_insert); +EXPORT_SYMBOL(elv_dispatch_sort); EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_requeue_request); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2c7b9154927a..a2e496f285a4 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -337,7 +337,7 @@ struct request_queue /* * Dispatch queue sorting */ - sector_t last_sector; + sector_t end_sector; struct request *boundary_rq; unsigned int max_back_kb; @@ -624,6 +624,17 @@ static inline void blkdev_dequeue_request(struct request *req) elv_dequeue_request(req->q, req); } +/* + * This should be in elevator.h, but that requires pulling in rq and q + */ +static inline void elv_dispatch_add_tail(struct request_queue *q, + struct request *rq) +{ + q->end_sector = rq_end_sector(rq); + q->boundary_rq = rq; + list_add_tail(&rq->queuelist, &q->queue_head); +} + /* * Access functions for manipulating queue properties */ diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 76f4f6920744..f9b5ec38121a 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -79,7 +79,7 @@ struct elevator_queue /* * block elevator interface */ -extern void elv_dispatch_insert(request_queue_t *, struct request *, int); +extern void elv_dispatch_sort(request_queue_t *, struct request *); extern void elv_add_request(request_queue_t *, struct request *, int, int); extern void __elv_add_request(request_queue_t *, struct request *, int, int); extern int elv_merge(request_queue_t *, struct request **, struct bio *); @@ -140,4 +140,6 @@ enum { ELV_MQUEUE_MUST, }; +#define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) + #endif From d9ebb192aa13a026edc6faff137dcb14f2c91731 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 20 Oct 2005 16:37:38 +0200 Subject: [PATCH 0816/1939] [PATCH] elevator: leftover function declaration Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 237e43d760c8..29d6c8237ab3 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -228,10 +228,6 @@ void elevator_exit(elevator_t *e) kfree(e); } -void elv_dispatch_insert_tail(request_queue_t *q, struct request *rq) -{ -} - /* * Insert rq into dispatch queue of q. Queue lock must be held on * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be From b4878f245ec8e168cdd1f170f823a750b7dd4af5 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 20 Oct 2005 16:42:29 +0200 Subject: [PATCH 0817/1939] [PATCH] 02/05: update ioscheds to use generic dispatch queue This patch updates all four ioscheds to use generic dispatch queue. There's one behavior change in as-iosched. * In as-iosched, when force dispatching (ELEVATOR_INSERT_BACK), batch_data_dir is reset to REQ_SYNC and changed_batch and new_batch are cleared to zero. This prevernts AS from doing incorrect update_write_batch after the forced dispatched requests are finished. * In cfq-iosched, cfqd->rq_in_driver currently counts the number of activated (removed) requests to determine whether queue-kicking is needed and cfq_max_depth has been reached. With generic dispatch queue, I think counting the number of dispatched requests would be more appropriate. * cfq_max_depth can be lowered to 1 again. Original from Tejun Heo, modified version applied. Signed-off-by: Jens Axboe --- drivers/block/as-iosched.c | 298 ++++++++------------------ drivers/block/cfq-iosched.c | 344 ++++++++----------------------- drivers/block/deadline-iosched.c | 95 ++------- drivers/block/noop-iosched.c | 17 +- 4 files changed, 193 insertions(+), 561 deletions(-) diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 95c0a3690b0f..1775ffe9edc7 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -98,7 +98,6 @@ struct as_data { struct as_rq *next_arq[2]; /* next in sort order */ sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned long exit_prob; /* probability a task will exit while @@ -239,6 +238,25 @@ static struct io_context *as_get_io_context(void) return ioc; } +static void as_put_io_context(struct as_rq *arq) +{ + struct as_io_context *aic; + + if (unlikely(!arq->io_context)) + return; + + aic = arq->io_context->aic; + + if (arq->is_sync == REQ_SYNC && aic) { + spin_lock(&aic->lock); + set_bit(AS_TASK_IORUNNING, &aic->state); + aic->last_end_request = jiffies; + spin_unlock(&aic->lock); + } + + put_io_context(arq->io_context); +} + /* * the back merge hash support functions */ @@ -950,23 +968,12 @@ static void as_completed_request(request_queue_t *q, struct request *rq) WARN_ON(!list_empty(&rq->queuelist)); - if (arq->state == AS_RQ_PRESCHED) { - WARN_ON(arq->io_context); - goto out; - } - - if (arq->state == AS_RQ_MERGED) - goto out_ioc; - if (arq->state != AS_RQ_REMOVED) { printk("arq->state %d\n", arq->state); WARN_ON(1); goto out; } - if (!blk_fs_request(rq)) - goto out; - if (ad->changed_batch && ad->nr_dispatched == 1) { kblockd_schedule_work(&ad->antic_work); ad->changed_batch = 0; @@ -1001,21 +1008,7 @@ static void as_completed_request(request_queue_t *q, struct request *rq) } } -out_ioc: - if (!arq->io_context) - goto out; - - if (arq->is_sync == REQ_SYNC) { - struct as_io_context *aic = arq->io_context->aic; - if (aic) { - spin_lock(&aic->lock); - set_bit(AS_TASK_IORUNNING, &aic->state); - aic->last_end_request = jiffies; - spin_unlock(&aic->lock); - } - } - - put_io_context(arq->io_context); + as_put_io_context(arq); out: arq->state = AS_RQ_POSTSCHED; } @@ -1051,68 +1044,6 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) as_del_arq_rb(ad, arq); } -/* - * as_remove_dispatched_request is called to remove a request which has gone - * to the dispatch list. - */ -static void as_remove_dispatched_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - struct as_io_context *aic; - - if (!arq) { - WARN_ON(1); - return; - } - - WARN_ON(arq->state != AS_RQ_DISPATCHED); - WARN_ON(ON_RB(&arq->rb_node)); - if (arq->io_context && arq->io_context->aic) { - aic = arq->io_context->aic; - if (aic) { - WARN_ON(!atomic_read(&aic->nr_dispatched)); - atomic_dec(&aic->nr_dispatched); - } - } -} - -/* - * as_remove_request is called when a driver has finished with a request. - * This should be only called for dispatched requests, but for some reason - * a POWER4 box running hwscan it does not. - */ -static void as_remove_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - - if (unlikely(arq->state == AS_RQ_NEW)) - goto out; - - if (ON_RB(&arq->rb_node)) { - if (arq->state != AS_RQ_QUEUED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - /* - * We'll lose the aliased request(s) here. I don't think this - * will ever happen, but if it does, hopefully someone will - * report it. - */ - WARN_ON(!list_empty(&rq->queuelist)); - as_remove_queued_request(q, rq); - } else { - if (arq->state != AS_RQ_DISPATCHED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - as_remove_dispatched_request(q, rq); - } -out: - arq->state = AS_RQ_REMOVED; -} - /* * as_fifo_expired returns 0 if there are no expired reads on the fifo, * 1 otherwise. It is ratelimited so that we only perform the check once per @@ -1165,7 +1096,6 @@ static inline int as_batch_expired(struct as_data *ad) static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; - struct list_head *insert; const int data_dir = arq->is_sync; BUG_ON(!ON_RB(&arq->rb_node)); @@ -1198,13 +1128,13 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) /* * take it off the sort and fifo list, add to dispatch queue */ - insert = ad->dispatch->prev; - while (!list_empty(&rq->queuelist)) { struct request *__rq = list_entry_rq(rq->queuelist.next); struct as_rq *__arq = RQ_DATA(__rq); - list_move_tail(&__rq->queuelist, ad->dispatch); + list_del(&__rq->queuelist); + + elv_dispatch_add_tail(ad->q, __rq); if (__arq->io_context && __arq->io_context->aic) atomic_inc(&__arq->io_context->aic->nr_dispatched); @@ -1218,7 +1148,8 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) as_remove_queued_request(ad->q, rq); WARN_ON(arq->state != AS_RQ_QUEUED); - list_add(&rq->queuelist, insert); + elv_dispatch_sort(ad->q, rq); + arq->state = AS_RQ_DISPATCHED; if (arq->io_context && arq->io_context->aic) atomic_inc(&arq->io_context->aic->nr_dispatched); @@ -1230,12 +1161,42 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) * read/write expire, batch expire, etc, and moves it to the dispatch * queue. Returns 1 if a request was found, 0 otherwise. */ -static int as_dispatch_request(struct as_data *ad) +static int as_dispatch_request(request_queue_t *q, int force) { + struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq; const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]); const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]); + if (unlikely(force)) { + /* + * Forced dispatch, accounting is useless. Reset + * accounting states and dump fifo_lists. Note that + * batch_data_dir is reset to REQ_SYNC to avoid + * screwing write batch accounting as write batch + * accounting occurs on W->R transition. + */ + int dispatched = 0; + + ad->batch_data_dir = REQ_SYNC; + ad->changed_batch = 0; + ad->new_batch = 0; + + while (ad->next_arq[REQ_SYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_SYNC] = jiffies; + + while (ad->next_arq[REQ_ASYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_ASYNC] = jiffies; + + return dispatched; + } + /* Signal that the write batch was uncontended, so we can't time it */ if (ad->batch_data_dir == REQ_ASYNC && !reads) { if (ad->current_write_count == 0 || !writes) @@ -1359,20 +1320,6 @@ static int as_dispatch_request(struct as_data *ad) return 1; } -static struct request *as_next_request(request_queue_t *q) -{ - struct as_data *ad = q->elevator->elevator_data; - struct request *rq = NULL; - - /* - * if there are still requests on the dispatch queue, grab the first - */ - if (!list_empty(ad->dispatch) || as_dispatch_request(ad)) - rq = list_entry_rq(ad->dispatch->next); - - return rq; -} - /* * Add arq to a list behind alias */ @@ -1410,11 +1357,19 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia /* * add arq to rbtree and fifo */ -static void as_add_request(struct as_data *ad, struct as_rq *arq) +static void as_add_request(request_queue_t *q, struct request *rq) { + struct as_data *ad = q->elevator->elevator_data; + struct as_rq *arq = RQ_DATA(rq); struct as_rq *alias; int data_dir; + if (arq->state != AS_RQ_PRESCHED) { + printk("arq->state: %d\n", arq->state); + WARN_ON(1); + } + arq->state = AS_RQ_NEW; + if (rq_data_dir(arq->request) == READ || current->flags&PF_SYNCWRITE) arq->is_sync = 1; @@ -1463,96 +1418,24 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->state = AS_RQ_QUEUED; } +static void as_activate_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + + WARN_ON(arq->state != AS_RQ_DISPATCHED); + arq->state = AS_RQ_REMOVED; + if (arq->io_context && arq->io_context->aic) + atomic_dec(&arq->io_context->aic->nr_dispatched); +} + static void as_deactivate_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state == AS_RQ_REMOVED) { - arq->state = AS_RQ_DISPATCHED; - if (arq->io_context && arq->io_context->aic) - atomic_inc(&arq->io_context->aic->nr_dispatched); - } - } else - WARN_ON(blk_fs_request(rq) - && (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) ); - - /* Stop anticipating - let this request get through */ - as_antic_stop(ad); -} - -/* - * requeue the request. The request has not been completed, nor is it a - * new request, so don't touch accounting. - */ -static void as_requeue_request(request_queue_t *q, struct request *rq) -{ - as_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); -} - -/* - * Account a request that is inserted directly onto the dispatch queue. - * arq->io_context->aic->nr_dispatched should not need to be incremented - * because only new requests should come through here: requeues go through - * our explicit requeue handler. - */ -static void as_account_queued_request(struct as_data *ad, struct request *rq) -{ - if (blk_fs_request(rq)) { - struct as_rq *arq = RQ_DATA(rq); - arq->state = AS_RQ_DISPATCHED; - ad->nr_dispatched++; - } -} - -static void -as_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct as_data *ad = q->elevator->elevator_data; - struct as_rq *arq = RQ_DATA(rq); - - if (arq) { - if (arq->state != AS_RQ_PRESCHED) { - printk("arq->state: %d\n", arq->state); - WARN_ON(1); - } - arq->state = AS_RQ_NEW; - } - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) { - WARN_ON(1); - where = ELEVATOR_INSERT_BACK; - } - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (ad->next_arq[REQ_SYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); - - while (ad->next_arq[REQ_ASYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); - - list_add_tail(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - as_add_request(ad, arq); - break; - default: - BUG(); - return; - } + WARN_ON(arq->state != AS_RQ_REMOVED); + arq->state = AS_RQ_DISPATCHED; + if (arq->io_context && arq->io_context->aic) + atomic_inc(&arq->io_context->aic->nr_dispatched); } /* @@ -1565,12 +1448,8 @@ static int as_queue_empty(request_queue_t *q) { struct as_data *ad = q->elevator->elevator_data; - if (!list_empty(&ad->fifo_list[REQ_ASYNC]) - || !list_empty(&ad->fifo_list[REQ_SYNC]) - || !list_empty(ad->dispatch)) - return 0; - - return 1; + return list_empty(&ad->fifo_list[REQ_ASYNC]) + && list_empty(&ad->fifo_list[REQ_SYNC]); } static struct request * @@ -1763,6 +1642,7 @@ as_merged_requests(request_queue_t *q, struct request *req, * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); + as_put_io_context(anext); anext->state = AS_RQ_MERGED; } @@ -1782,7 +1662,7 @@ static void as_work_handler(void *data) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - if (as_next_request(q)) + if (!as_queue_empty(q)) q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1797,7 +1677,9 @@ static void as_put_request(request_queue_t *q, struct request *rq) return; } - if (arq->state != AS_RQ_POSTSCHED && arq->state != AS_RQ_PRESCHED) { + if (unlikely(arq->state != AS_RQ_POSTSCHED && + arq->state != AS_RQ_PRESCHED && + arq->state != AS_RQ_MERGED)) { printk("arq->state %d\n", arq->state); WARN_ON(1); } @@ -1907,7 +1789,6 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); ad->sort_list[REQ_SYNC] = RB_ROOT; ad->sort_list[REQ_ASYNC] = RB_ROOT; - ad->dispatch = &q->queue_head; ad->fifo_expire[REQ_SYNC] = default_read_expire; ad->fifo_expire[REQ_ASYNC] = default_write_expire; ad->antic_expire = default_antic_expire; @@ -2072,10 +1953,9 @@ static struct elevator_type iosched_as = { .elevator_merge_fn = as_merge, .elevator_merged_fn = as_merged_request, .elevator_merge_req_fn = as_merged_requests, - .elevator_next_req_fn = as_next_request, - .elevator_add_req_fn = as_insert_request, - .elevator_remove_req_fn = as_remove_request, - .elevator_requeue_req_fn = as_requeue_request, + .elevator_dispatch_fn = as_dispatch_request, + .elevator_add_req_fn = as_add_request, + .elevator_activate_req_fn = as_activate_request, .elevator_deactivate_req_fn = as_deactivate_request, .elevator_queue_empty_fn = as_queue_empty, .elevator_completed_req_fn = as_completed_request, diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index cd056e7e64ec..7b14160e0798 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -84,7 +84,6 @@ static int cfq_max_depth = 2; (node)->rb_left = NULL; \ } while (0) #define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) -#define ON_RB(node) ((node)->rb_color != RB_NONE) #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) #define rq_rb_key(rq) (rq)->sector @@ -271,10 +270,7 @@ CFQ_CFQQ_FNS(expired); #undef CFQ_CFQQ_FNS enum cfq_rq_state_flags { - CFQ_CRQ_FLAG_in_flight = 0, - CFQ_CRQ_FLAG_in_driver, - CFQ_CRQ_FLAG_is_sync, - CFQ_CRQ_FLAG_requeued, + CFQ_CRQ_FLAG_is_sync = 0, }; #define CFQ_CRQ_FNS(name) \ @@ -291,14 +287,11 @@ static inline int cfq_crq_##name(const struct cfq_rq *crq) \ return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \ } -CFQ_CRQ_FNS(in_flight); -CFQ_CRQ_FNS(in_driver); CFQ_CRQ_FNS(is_sync); -CFQ_CRQ_FNS(requeued); #undef CFQ_CRQ_FNS static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); -static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *); +static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); static void cfq_put_cfqd(struct cfq_data *cfqd); #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) @@ -347,18 +340,13 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) return NULL; } -static inline int cfq_pending_requests(struct cfq_data *cfqd) -{ - return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues; -} - /* * scheduler run of queue, if there are requests pending and no one in the * driver that will restart queueing */ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { - if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd)) + if (!cfqd->rq_in_driver && cfqd->busy_queues) kblockd_schedule_work(&cfqd->unplug_work); } @@ -366,7 +354,7 @@ static int cfq_queue_empty(request_queue_t *q) { struct cfq_data *cfqd = q->elevator->elevator_data; - return !cfq_pending_requests(cfqd); + return !cfqd->busy_queues; } /* @@ -386,11 +374,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) if (crq2 == NULL) return crq1; - if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) - return crq1; - else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) - return crq2; - if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) return crq1; else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) @@ -461,10 +444,7 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq_next = NULL, *crq_prev = NULL; struct rb_node *rbnext, *rbprev; - rbnext = NULL; - if (ON_RB(&last->rb_node)) - rbnext = rb_next(&last->rb_node); - if (!rbnext) { + if (!(rbnext = rb_next(&last->rb_node))) { rbnext = rb_first(&cfqq->sort_list); if (rbnext == &last->rb_node) rbnext = NULL; @@ -545,13 +525,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) * the pending list according to last request service */ static inline void -cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue) +cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { BUG_ON(cfq_cfqq_on_rr(cfqq)); cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; - cfq_resort_rr_list(cfqq, requeue); + cfq_resort_rr_list(cfqq, 0); } static inline void @@ -571,22 +551,19 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) static inline void cfq_del_crq_rb(struct cfq_rq *crq) { struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); - if (ON_RB(&crq->rb_node)) { - struct cfq_data *cfqd = cfqq->cfqd; - const int sync = cfq_crq_is_sync(crq); + BUG_ON(!cfqq->queued[sync]); + cfqq->queued[sync]--; - BUG_ON(!cfqq->queued[sync]); - cfqq->queued[sync]--; + cfq_update_next_crq(crq); - cfq_update_next_crq(crq); + rb_erase(&crq->rb_node, &cfqq->sort_list); + RB_CLEAR_COLOR(&crq->rb_node); - rb_erase(&crq->rb_node, &cfqq->sort_list); - RB_CLEAR_COLOR(&crq->rb_node); - - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) - cfq_del_cfqq_rr(cfqd, cfqq); - } + if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) + cfq_del_cfqq_rr(cfqd, cfqq); } static struct cfq_rq * @@ -627,12 +604,12 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) * if that happens, put the alias on the dispatch list */ while ((__alias = __cfq_add_crq_rb(crq)) != NULL) - cfq_dispatch_sort(cfqd->queue, __alias); + cfq_dispatch_insert(cfqd->queue, __alias); rb_insert_color(&crq->rb_node, &cfqq->sort_list); if (!cfq_cfqq_on_rr(cfqq)) - cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq)); + cfq_add_cfqq_rr(cfqd, cfqq); /* * check if this request is a better next-serve candidate @@ -643,10 +620,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) static inline void cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) { - if (ON_RB(&crq->rb_node)) { - rb_erase(&crq->rb_node, &cfqq->sort_list); - cfqq->queued[cfq_crq_is_sync(crq)]--; - } + rb_erase(&crq->rb_node, &cfqq->sort_list); + cfqq->queued[cfq_crq_is_sync(crq)]--; cfq_add_crq_rb(crq); } @@ -676,49 +651,28 @@ static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector) return NULL; } +static void cfq_activate_request(request_queue_t *q, struct request *rq) +{ + struct cfq_data *cfqd = q->elevator->elevator_data; + + cfqd->rq_in_driver++; +} + static void cfq_deactivate_request(request_queue_t *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_rq *crq = RQ_DATA(rq); - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - - if (cfq_crq_in_driver(crq)) { - cfq_clear_crq_in_driver(crq); - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - } - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); - - cfq_clear_crq_in_flight(crq); - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; - } - cfq_mark_crq_requeued(crq); - } + WARN_ON(!cfqd->rq_in_driver); + cfqd->rq_in_driver--; } -/* - * make sure the service time gets corrected on reissue of this request - */ -static void cfq_requeue_request(request_queue_t *q, struct request *rq) -{ - cfq_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); -} - -static void cfq_remove_request(request_queue_t *q, struct request *rq) +static void cfq_remove_request(struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - if (crq) { - list_del_init(&rq->queuelist); - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - } + list_del_init(&rq->queuelist); + cfq_del_crq_rb(crq); + cfq_remove_merge_hints(rq->q, crq); } static int @@ -762,7 +716,7 @@ static void cfq_merged_request(request_queue_t *q, struct request *req) cfq_del_crq_hash(crq); cfq_add_crq_hash(cfqd, crq); - if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { + if (rq_rb_key(req) != crq->rb_key) { struct cfq_queue *cfqq = crq->cfq_queue; cfq_update_next_crq(crq); @@ -785,7 +739,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq, time_before(next->start_time, rq->start_time)) list_move(&rq->queuelist, &next->queuelist); - cfq_remove_request(q, next); + cfq_remove_request(next); } static inline void @@ -992,53 +946,15 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) return 1; } -/* - * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues, - * this function sector sorts the selected request to minimize seeks. we start - * at cfqd->last_sector, not 0. - */ -static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq) +static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = crq->cfq_queue; - struct list_head *head = &q->queue_head, *entry = head; - struct request *__rq; - sector_t last; - - list_del(&crq->request->queuelist); - - last = cfqd->last_sector; - list_for_each_entry_reverse(__rq, head, queuelist) { - struct cfq_rq *__crq = RQ_DATA(__rq); - - if (blk_barrier_rq(__rq)) - break; - if (!blk_fs_request(__rq)) - break; - if (cfq_crq_requeued(__crq)) - break; - - if (__rq->sector <= crq->request->sector) - break; - if (__rq->sector > last && crq->request->sector < last) { - last = crq->request->sector + crq->request->nr_sectors; - break; - } - entry = &__rq->queuelist; - } - - cfqd->last_sector = last; cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq); - - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - cfq_mark_crq_in_flight(crq); - cfq_clear_crq_requeued(crq); - + cfq_remove_request(crq->request); cfqq->on_dispatch[cfq_crq_is_sync(crq)]++; - list_add_tail(&crq->request->queuelist, entry); + elv_dispatch_sort(q, crq->request); } /* @@ -1159,7 +1075,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, /* * finally, insert request into driver dispatch list */ - cfq_dispatch_sort(cfqd->queue, crq); + cfq_dispatch_insert(cfqd->queue, crq); cfqd->dispatch_slice++; dispatched++; @@ -1194,7 +1110,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, } static int -cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) +cfq_dispatch_requests(request_queue_t *q, int force) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq; @@ -1204,12 +1120,25 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) cfqq = cfq_select_queue(cfqd, force); if (cfqq) { + int max_dispatch; + + /* + * if idle window is disabled, allow queue buildup + */ + if (!cfq_cfqq_idle_window(cfqq) && + cfqd->rq_in_driver >= cfqd->cfq_max_depth) + return 0; + cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); del_timer(&cfqd->idle_slice_timer); - if (cfq_class_idle(cfqq)) - max_dispatch = 1; + if (!force) { + max_dispatch = cfqd->cfq_quantum; + if (cfq_class_idle(cfqq)) + max_dispatch = 1; + } else + max_dispatch = INT_MAX; return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); } @@ -1217,93 +1146,6 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) return 0; } -static inline void cfq_account_dispatch(struct cfq_rq *crq) -{ - struct cfq_queue *cfqq = crq->cfq_queue; - struct cfq_data *cfqd = cfqq->cfqd; - - if (unlikely(!blk_fs_request(crq->request))) - return; - - /* - * accounted bit is necessary since some drivers will call - * elv_next_request() many times for the same request (eg ide) - */ - if (cfq_crq_in_driver(crq)) - return; - - cfq_mark_crq_in_driver(crq); - cfqd->rq_in_driver++; -} - -static inline void -cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq) -{ - struct cfq_data *cfqd = cfqq->cfqd; - unsigned long now; - - if (!cfq_crq_in_driver(crq)) - return; - - now = jiffies; - - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - - if (!cfq_class_idle(cfqq)) - cfqd->last_end_request = now; - - if (!cfq_cfqq_dispatched(cfqq)) { - if (cfq_cfqq_on_rr(cfqq)) { - cfqq->service_last = now; - cfq_resort_rr_list(cfqq, 0); - } - if (cfq_cfqq_expired(cfqq)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - } - - if (cfq_crq_is_sync(crq)) - crq->io_context->last_end_request = now; -} - -static struct request *cfq_next_request(request_queue_t *q) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct request *rq; - - if (!list_empty(&q->queue_head)) { - struct cfq_rq *crq; -dispatch: - rq = list_entry_rq(q->queue_head.next); - - crq = RQ_DATA(rq); - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - - /* - * if idle window is disabled, allow queue buildup - */ - if (!cfq_crq_in_driver(crq) && - !cfq_cfqq_idle_window(cfqq) && - !blk_barrier_rq(rq) && - cfqd->rq_in_driver >= cfqd->cfq_max_depth) - return NULL; - - cfq_remove_merge_hints(q, crq); - cfq_account_dispatch(crq); - } - - return rq; - } - - if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0)) - goto dispatch; - - return NULL; -} - /* * task holds one reference to the queue, dropped when task exits. each crq * in-flight on this queue also holds a reference, dropped when crq is freed. @@ -1816,8 +1658,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } } -static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) +static void cfq_insert_request(request_queue_t *q, struct request *rq) { + struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_rq *crq = RQ_DATA(rq); struct cfq_queue *cfqq = crq->cfq_queue; @@ -1837,56 +1680,37 @@ static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) cfq_crq_enqueued(cfqd, cfqq, crq); } -static void -cfq_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (cfq_dispatch_requests(q, INT_MAX, 1)) - ; - list_add_tail(&rq->queuelist, &q->queue_head); - /* - * If we were idling with pending requests on - * inactive cfqqs, force dispatching will - * remove the idle timer and the queue won't - * be kicked by __make_request() afterward. - * Kick it here. - */ - cfq_schedule_dispatch(cfqd); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, &q->queue_head); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - cfq_enqueue(cfqd, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static void cfq_completed_request(request_queue_t *q, struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - struct cfq_queue *cfqq; + struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); + unsigned long now; - if (unlikely(!blk_fs_request(rq))) - return; + now = jiffies; - cfqq = crq->cfq_queue; + WARN_ON(!cfqd->rq_in_driver); + WARN_ON(!cfqq->on_dispatch[sync]); + cfqd->rq_in_driver--; + cfqq->on_dispatch[sync]--; - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); + if (!cfq_class_idle(cfqq)) + cfqd->last_end_request = now; - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; + if (!cfq_cfqq_dispatched(cfqq)) { + if (cfq_cfqq_on_rr(cfqq)) { + cfqq->service_last = now; + cfq_resort_rr_list(cfqq, 0); + } + if (cfq_cfqq_expired(cfqq)) { + __cfq_slice_expired(cfqd, cfqq, 0); + cfq_schedule_dispatch(cfqd); + } } - cfq_account_completion(cfqq, crq); + if (cfq_crq_is_sync(crq)) + crq->io_context->last_end_request = now; } static struct request * @@ -2118,9 +1942,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, INIT_HLIST_NODE(&crq->hash); crq->cfq_queue = cfqq; crq->io_context = cic; - cfq_clear_crq_in_flight(crq); - cfq_clear_crq_in_driver(crq); - cfq_clear_crq_requeued(crq); if (rw == READ || process_sync(tsk)) cfq_mark_crq_is_sync(crq); @@ -2201,7 +2022,7 @@ static void cfq_idle_slice_timer(unsigned long data) * only expire and reinvoke request handler, if there are * other queues with pending requests */ - if (!cfq_pending_requests(cfqd)) { + if (!cfqd->busy_queues) { cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end); add_timer(&cfqd->idle_slice_timer); goto out_cont; @@ -2576,10 +2397,9 @@ static struct elevator_type iosched_cfq = { .elevator_merge_fn = cfq_merge, .elevator_merged_fn = cfq_merged_request, .elevator_merge_req_fn = cfq_merged_requests, - .elevator_next_req_fn = cfq_next_request, + .elevator_dispatch_fn = cfq_dispatch_requests, .elevator_add_req_fn = cfq_insert_request, - .elevator_remove_req_fn = cfq_remove_request, - .elevator_requeue_req_fn = cfq_requeue_request, + .elevator_activate_req_fn = cfq_activate_request, .elevator_deactivate_req_fn = cfq_deactivate_request, .elevator_queue_empty_fn = cfq_queue_empty, .elevator_completed_req_fn = cfq_completed_request, diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 52a3ae5289a0..07de4d24ddba 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -50,7 +50,6 @@ struct deadline_data { * next in sort order. read, write or both are NULL */ struct deadline_rq *next_drq[2]; - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned int batching; /* number of sequential requests made */ sector_t last_sector; /* head position */ @@ -239,10 +238,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq) dd->next_drq[data_dir] = rb_entry_drq(rbnext); } - if (ON_RB(&drq->rb_node)) { - rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); - RB_CLEAR(&drq->rb_node); - } + BUG_ON(!ON_RB(&drq->rb_node)); + rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); + RB_CLEAR(&drq->rb_node); } static struct request * @@ -286,7 +284,7 @@ deadline_find_first_drq(struct deadline_data *dd, int data_dir) /* * add drq to rbtree and fifo */ -static inline void +static void deadline_add_request(struct request_queue *q, struct request *rq) { struct deadline_data *dd = q->elevator->elevator_data; @@ -315,14 +313,11 @@ deadline_add_request(struct request_queue *q, struct request *rq) static void deadline_remove_request(request_queue_t *q, struct request *rq) { struct deadline_rq *drq = RQ_DATA(rq); + struct deadline_data *dd = q->elevator->elevator_data; - if (drq) { - struct deadline_data *dd = q->elevator->elevator_data; - - list_del_init(&drq->fifo); - deadline_remove_merge_hints(q, drq); - deadline_del_drq_rb(dd, drq); - } + list_del_init(&drq->fifo); + deadline_remove_merge_hints(q, drq); + deadline_del_drq_rb(dd, drq); } static int @@ -452,7 +447,7 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq) request_queue_t *q = drq->request->q; deadline_remove_request(q, drq->request); - list_add_tail(&drq->request->queuelist, dd->dispatch); + elv_dispatch_add_tail(q, drq->request); } /* @@ -502,8 +497,9 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) * deadline_dispatch_requests selects the best request according to * read/write expire, fifo_batch, etc */ -static int deadline_dispatch_requests(struct deadline_data *dd) +static int deadline_dispatch_requests(request_queue_t *q, int force) { + struct deadline_data *dd = q->elevator->elevator_data; const int reads = !list_empty(&dd->fifo_list[READ]); const int writes = !list_empty(&dd->fifo_list[WRITE]); struct deadline_rq *drq; @@ -597,65 +593,12 @@ static int deadline_dispatch_requests(struct deadline_data *dd) return 1; } -static struct request *deadline_next_request(request_queue_t *q) -{ - struct deadline_data *dd = q->elevator->elevator_data; - struct request *rq; - - /* - * if there are still requests on the dispatch queue, grab the first one - */ - if (!list_empty(dd->dispatch)) { -dispatch: - rq = list_entry_rq(dd->dispatch->next); - return rq; - } - - if (deadline_dispatch_requests(dd)) - goto dispatch; - - return NULL; -} - -static void -deadline_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct deadline_data *dd = q->elevator->elevator_data; - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) - where = ELEVATOR_INSERT_BACK; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (deadline_dispatch_requests(dd)) - ; - list_add_tail(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - deadline_add_request(q, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static int deadline_queue_empty(request_queue_t *q) { struct deadline_data *dd = q->elevator->elevator_data; - if (!list_empty(&dd->fifo_list[WRITE]) - || !list_empty(&dd->fifo_list[READ]) - || !list_empty(dd->dispatch)) - return 0; - - return 1; + return list_empty(&dd->fifo_list[WRITE]) + && list_empty(&dd->fifo_list[READ]); } static struct request * @@ -733,7 +676,6 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&dd->fifo_list[WRITE]); dd->sort_list[READ] = RB_ROOT; dd->sort_list[WRITE] = RB_ROOT; - dd->dispatch = &q->queue_head; dd->fifo_expire[READ] = read_expire; dd->fifo_expire[WRITE] = write_expire; dd->writes_starved = writes_starved; @@ -748,10 +690,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq) struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq = RQ_DATA(rq); - if (drq) { - mempool_free(drq, dd->drq_pool); - rq->elevator_private = NULL; - } + mempool_free(drq, dd->drq_pool); + rq->elevator_private = NULL; } static int @@ -917,9 +857,8 @@ static struct elevator_type iosched_deadline = { .elevator_merge_fn = deadline_merge, .elevator_merged_fn = deadline_merged_request, .elevator_merge_req_fn = deadline_merged_requests, - .elevator_next_req_fn = deadline_next_request, - .elevator_add_req_fn = deadline_insert_request, - .elevator_remove_req_fn = deadline_remove_request, + .elevator_dispatch_fn = deadline_dispatch_requests, + .elevator_add_req_fn = deadline_add_request, .elevator_queue_empty_fn = deadline_queue_empty, .elevator_former_req_fn = deadline_former_request, .elevator_latter_req_fn = deadline_latter_request, diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index b1730b62c37e..bc2252b6f2e5 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c @@ -28,13 +28,9 @@ static void elevator_noop_merge_requests(request_queue_t *q, struct request *req list_del_init(&next->queuelist); } -static void elevator_noop_add_request(request_queue_t *q, struct request *rq, - int where) +static void elevator_noop_add_request(request_queue_t *q, struct request *rq) { - if (where == ELEVATOR_INSERT_FRONT) - list_add(&rq->queuelist, &q->queue_head); - else - list_add_tail(&rq->queuelist, &q->queue_head); + elv_dispatch_add_tail(q, rq); /* * new merges must not precede this barrier @@ -45,19 +41,16 @@ static void elevator_noop_add_request(request_queue_t *q, struct request *rq, q->last_merge = rq; } -static struct request *elevator_noop_next_request(request_queue_t *q) +static int elevator_noop_dispatch(request_queue_t *q, int force) { - if (!list_empty(&q->queue_head)) - return list_entry_rq(q->queue_head.next); - - return NULL; + return 0; } static struct elevator_type elevator_noop = { .ops = { .elevator_merge_fn = elevator_noop_merge, .elevator_merge_req_fn = elevator_noop_merge_requests, - .elevator_next_req_fn = elevator_noop_next_request, + .elevator_dispatch_fn = elevator_noop_dispatch, .elevator_add_req_fn = elevator_noop_add_request, }, .elevator_name = "noop", From 06b86245c052963029bfd9020ca1f08ceb66f85a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Oct 2005 16:46:23 +0200 Subject: [PATCH 0818/1939] [PATCH] 03/05 move last_merge handlin into generic elevator code Currently, both generic elevator code and specific ioscheds participate in the management and usage of last_merge. This and the following patches move last_merge handling into generic elevator code. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 43 +++++++++++++++++----------------------- include/linux/blkdev.h | 3 +++ 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 29d6c8237ab3..415144372c75 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -83,15 +83,6 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) } EXPORT_SYMBOL(elv_try_merge); -inline int elv_try_last_merge(request_queue_t *q, struct bio *bio) -{ - if (q->last_merge) - return elv_try_merge(q->last_merge, bio); - - return ELEVATOR_NO_MERGE; -} -EXPORT_SYMBOL(elv_try_last_merge); - static struct elevator_type *elevator_find(const char *name) { struct elevator_type *e = NULL; @@ -239,6 +230,9 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) unsigned max_back; struct list_head *entry; + if (q->last_merge == rq) + q->last_merge = NULL; + boundary = q->end_sector; max_back = q->max_back_kb * 2; boundary = boundary > max_back ? boundary - max_back : 0; @@ -265,6 +259,15 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; + int ret; + + if (q->last_merge) { + ret = elv_try_merge(q->last_merge, bio); + if (ret != ELEVATOR_NO_MERGE) { + *req = q->last_merge; + return ret; + } + } if (e->ops->elevator_merge_fn) return e->ops->elevator_merge_fn(q, req, bio); @@ -278,6 +281,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) if (e->ops->elevator_merged_fn) e->ops->elevator_merged_fn(q, rq); + + q->last_merge = rq; } void elv_merge_requests(request_queue_t *q, struct request *rq, @@ -285,11 +290,10 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, { elevator_t *e = q->elevator; - if (q->last_merge == next) - q->last_merge = NULL; - if (e->ops->elevator_merge_req_fn) e->ops->elevator_merge_req_fn(q, rq, next); + + q->last_merge = rq; } void elv_requeue_request(request_queue_t *q, struct request *rq) @@ -384,6 +388,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, BUG_ON(!blk_fs_request(rq)); rq->flags |= REQ_SORTED; q->elevator->ops->elevator_add_req_fn(q, rq); + if (q->last_merge == NULL && rq_mergeable(rq)) + q->last_merge = rq; break; default: @@ -462,9 +468,6 @@ struct request *elv_next_request(request_queue_t *q) rq->flags |= REQ_STARTED; } - if (rq == q->last_merge) - q->last_merge = NULL; - if (!q->boundary_rq || q->boundary_rq == rq) { q->end_sector = rq_end_sector(rq); q->boundary_rq = NULL; @@ -518,16 +521,6 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq) */ if (blk_account_rq(rq)) q->in_flight++; - - /* - * the main clearing point for q->last_merge is on retrieval of - * request by driver (it calls elv_next_request()), but it _can_ - * also happen here if a request is added to the queue but later - * deleted without ever being given to driver (merged with another - * request). - */ - if (rq == q->last_merge) - q->last_merge = NULL; } int elv_queue_empty(request_queue_t *q) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a2e496f285a4..bd55b1df8997 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -630,6 +630,9 @@ static inline void blkdev_dequeue_request(struct request *req) static inline void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) { + if (q->last_merge == rq) + q->last_merge = NULL; + q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; list_add_tail(&rq->queuelist, &q->queue_head); From 98b11471d72a374f346bec50a00d0887719b85b3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Oct 2005 16:46:54 +0200 Subject: [PATCH 0819/1939] [PATCH] 04/05 remove last_merge handling from ioscheds Remove last_merge handling from all ioscheds. This patch removes merging capability of noop iosched. Signed-off-by: Tejun Heo --- drivers/block/as-iosched.c | 35 ++++---------------------------- drivers/block/cfq-iosched.c | 26 ++---------------------- drivers/block/deadline-iosched.c | 30 ++------------------------- drivers/block/noop-iosched.c | 31 ---------------------------- 4 files changed, 8 insertions(+), 114 deletions(-) diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 1775ffe9edc7..5d20e4bcbc78 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -279,14 +279,6 @@ static inline void as_del_arq_hash(struct as_rq *arq) __as_del_arq_hash(arq); } -static void as_remove_merge_hints(request_queue_t *q, struct as_rq *arq) -{ - as_del_arq_hash(arq); - - if (q->last_merge == arq->request) - q->last_merge = NULL; -} - static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; @@ -330,7 +322,7 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) BUG_ON(!arq->on_hash); if (!rq_mergeable(__rq)) { - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); continue; } @@ -1040,7 +1032,7 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) ad->next_arq[data_dir] = as_find_next_arq(ad, arq); list_del_init(&arq->fifo); - as_remove_merge_hints(q, arq); + as_del_arq_hash(arq); as_del_arq_rb(ad, arq); } @@ -1351,7 +1343,7 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia /* * Don't want to have to handle merges. */ - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); } /* @@ -1392,12 +1384,8 @@ static void as_add_request(request_queue_t *q, struct request *rq) arq->expires = jiffies + ad->fifo_expire[data_dir]; list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]); - if (rq_mergeable(arq->request)) { + if (rq_mergeable(arq->request)) as_add_arq_hash(ad, arq); - - if (!ad->q->last_merge) - ad->q->last_merge = arq->request; - } as_update_arq(ad, arq); /* keep state machine up to date */ } else { @@ -1486,15 +1474,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - /* * see if the merge hash can satisfy a back merge */ @@ -1523,9 +1502,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - if (rq_mergeable(__rq)) - q->last_merge = __rq; -out_insert: if (ret) { if (rq_mergeable(__rq)) as_hot_arq_hash(ad, RQ_DATA(__rq)); @@ -1572,9 +1548,6 @@ static void as_merged_request(request_queue_t *q, struct request *req) * behind the disk head. We currently don't bother adjusting. */ } - - if (arq->on_hash) - q->last_merge = req; } static void diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 7b14160e0798..62a19ed0443b 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -304,14 +304,6 @@ static inline void cfq_del_crq_hash(struct cfq_rq *crq) hlist_del_init(&crq->hash); } -static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq) -{ - cfq_del_crq_hash(crq); - - if (q->last_merge == crq->request) - q->last_merge = NULL; -} - static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) { const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); @@ -672,7 +664,7 @@ static void cfq_remove_request(struct request *rq) list_del_init(&rq->queuelist); cfq_del_crq_rb(crq); - cfq_remove_merge_hints(rq->q, crq); + cfq_del_crq_hash(crq); } static int @@ -682,12 +674,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_BACK_MERGE; @@ -702,8 +688,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: *req = __rq; return ret; } @@ -722,8 +706,6 @@ static void cfq_merged_request(request_queue_t *q, struct request *req) cfq_update_next_crq(crq); cfq_reposition_crq_rb(cfqq, crq); } - - q->last_merge = req; } static void @@ -1670,13 +1652,9 @@ static void cfq_insert_request(request_queue_t *q, struct request *rq) list_add_tail(&rq->queuelist, &cfqq->fifo); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) cfq_add_crq_hash(cfqd, crq); - if (!cfqd->queue->last_merge) - cfqd->queue->last_merge = rq; - } - cfq_crq_enqueued(cfqd, cfqq, crq); } diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 07de4d24ddba..43d93155efb8 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -112,15 +112,6 @@ static inline void deadline_del_drq_hash(struct deadline_rq *drq) __deadline_del_drq_hash(drq); } -static void -deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq) -{ - deadline_del_drq_hash(drq); - - if (q->last_merge == drq->request) - q->last_merge = NULL; -} - static inline void deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) { @@ -299,12 +290,8 @@ deadline_add_request(struct request_queue *q, struct request *rq) drq->expires = jiffies + dd->fifo_expire[data_dir]; list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) deadline_add_drq_hash(dd, drq); - - if (!q->last_merge) - q->last_merge = rq; - } } /* @@ -316,8 +303,8 @@ static void deadline_remove_request(request_queue_t *q, struct request *rq) struct deadline_data *dd = q->elevator->elevator_data; list_del_init(&drq->fifo); - deadline_remove_merge_hints(q, drq); deadline_del_drq_rb(dd, drq); + deadline_del_drq_hash(drq); } static int @@ -327,15 +314,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - /* * see if the merge hash can satisfy a back merge */ @@ -368,8 +346,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: if (ret) deadline_hot_drq_hash(dd, RQ_DATA(__rq)); *req = __rq; @@ -394,8 +370,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req) deadline_del_drq_rb(dd, drq); deadline_add_drq_rb(dd, drq); } - - q->last_merge = req; } static void diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index bc2252b6f2e5..f56b8edb06e4 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c @@ -7,38 +7,9 @@ #include #include -/* - * See if we can find a request that this buffer can be coalesced with. - */ -static int elevator_noop_merge(request_queue_t *q, struct request **req, - struct bio *bio) -{ - int ret; - - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) - *req = q->last_merge; - - return ret; -} - -static void elevator_noop_merge_requests(request_queue_t *q, struct request *req, - struct request *next) -{ - list_del_init(&next->queuelist); -} - static void elevator_noop_add_request(request_queue_t *q, struct request *rq) { elv_dispatch_add_tail(q, rq); - - /* - * new merges must not precede this barrier - */ - if (rq->flags & REQ_HARDBARRIER) - q->last_merge = NULL; - else if (!q->last_merge) - q->last_merge = rq; } static int elevator_noop_dispatch(request_queue_t *q, int force) @@ -48,8 +19,6 @@ static int elevator_noop_dispatch(request_queue_t *q, int force) static struct elevator_type elevator_noop = { .ops = { - .elevator_merge_fn = elevator_noop_merge, - .elevator_merge_req_fn = elevator_noop_merge_requests, .elevator_dispatch_fn = elevator_noop_dispatch, .elevator_add_req_fn = elevator_noop_add_request, }, From 4c9f7836406f41ef9da6ee68d7a0448fdb97b5ef Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Oct 2005 16:47:40 +0200 Subject: [PATCH 0820/1939] [PATCH] 05/05 update biodoc to match new generic dispatch api Updates biodoc to reflect changes in elevator API Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 113 +++++++++++++++------------------ 1 file changed, 52 insertions(+), 61 deletions(-) diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 6dd274d7e1cf..2d65c2182161 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -906,9 +906,20 @@ Aside: 4. The I/O scheduler -I/O schedulers are now per queue. They should be runtime switchable and modular -but aren't yet. Jens has most bits to do this, but the sysfs implementation is -missing. +I/O scheduler, a.k.a. elevator, is implemented in two layers. Generic dispatch +queue and specific I/O schedulers. Unless stated otherwise, elevator is used +to refer to both parts and I/O scheduler to specific I/O schedulers. + +Block layer implements generic dispatch queue in ll_rw_blk.c and elevator.c. +The generic dispatch queue is responsible for properly ordering barrier +requests, requeueing, handling non-fs requests and all other subtleties. + +Specific I/O schedulers are responsible for ordering normal filesystem +requests. They can also choose to delay certain requests to improve +throughput or whatever purpose. As the plural form indicates, there are +multiple I/O schedulers. They can be built as modules but at least one should +be built inside the kernel. Each queue can choose different one and can also +change to another one dynamically. A block layer call to the i/o scheduler follows the convention elv_xxx(). This calls elevator_xxx_fn in the elevator switch (drivers/block/elevator.c). Oh, @@ -921,44 +932,36 @@ keeping work. The functions an elevator may implement are: (* are mandatory) elevator_merge_fn called to query requests for merge with a bio -elevator_merge_req_fn " " " with another request +elevator_merge_req_fn called when two requests get merged. the one + which gets merged into the other one will be + never seen by I/O scheduler again. IOW, after + being merged, the request is gone. elevator_merged_fn called when a request in the scheduler has been involved in a merge. It is used in the deadline scheduler for example, to reposition the request if its sorting order has changed. -*elevator_next_req_fn returns the next scheduled request, or NULL - if there are none (or none are ready). +elevator_dispatch_fn fills the dispatch queue with ready requests. + I/O schedulers are free to postpone requests by + not filling the dispatch queue unless @force + is non-zero. Once dispatched, I/O schedulers + are not allowed to manipulate the requests - + they belong to generic dispatch queue. -*elevator_add_req_fn called to add a new request into the scheduler +elevator_add_req_fn called to add a new request into the scheduler elevator_queue_empty_fn returns true if the merge queue is empty. Drivers shouldn't use this, but rather check if elv_next_request is NULL (without losing the request if one exists!) -elevator_remove_req_fn This is called when a driver claims ownership of - the target request - it now belongs to the - driver. It must not be modified or merged. - Drivers must not lose the request! A subsequent - call of elevator_next_req_fn must return the - _next_ request. - -elevator_requeue_req_fn called to add a request to the scheduler. This - is used when the request has alrnadebeen - returned by elv_next_request, but hasn't - completed. If this is not implemented then - elevator_add_req_fn is called instead. - elevator_former_req_fn elevator_latter_req_fn These return the request before or after the one specified in disk sort order. Used by the block layer to find merge possibilities. -elevator_completed_req_fn called when a request is completed. This might - come about due to being merged with another or - when the device completes the request. +elevator_completed_req_fn called when a request is completed. elevator_may_queue_fn returns true if the scheduler wants to allow the current context to queue a new request even if @@ -967,13 +970,33 @@ elevator_may_queue_fn returns true if the scheduler wants to allow the elevator_set_req_fn elevator_put_req_fn Must be used to allocate and free any elevator - specific storate for a request. + specific storage for a request. + +elevator_activate_req_fn Called when device driver first sees a request. + I/O schedulers can use this callback to + determine when actual execution of a request + starts. +elevator_deactivate_req_fn Called when device driver decides to delay + a request by requeueing it. elevator_init_fn elevator_exit_fn Allocate and free any elevator specific storage for a queue. -4.2 I/O scheduler implementation +4.2 Request flows seen by I/O schedulers +All requests seens by I/O schedulers strictly follow one of the following three +flows. + + set_req_fn -> + + i. add_req_fn -> (merged_fn ->)* -> dispatch_fn -> activate_req_fn -> + (deactivate_req_fn -> activate_req_fn ->)* -> completed_req_fn + ii. add_req_fn -> (merged_fn ->)* -> merge_req_fn + iii. [none] + + -> put_req_fn + +4.3 I/O scheduler implementation The generic i/o scheduler algorithm attempts to sort/merge/batch requests for optimal disk scan and request servicing performance (based on generic principles and device capabilities), optimized for: @@ -993,18 +1016,7 @@ request in sort order to prevent binary tree lookups. This arrangement is not a generic block layer characteristic however, so elevators may implement queues as they please. -ii. Last merge hint -The last merge hint is part of the generic queue layer. I/O schedulers must do -some management on it. For the most part, the most important thing is to make -sure q->last_merge is cleared (set to NULL) when the request on it is no longer -a candidate for merging (for example if it has been sent to the driver). - -The last merge performed is cached as a hint for the subsequent request. If -sequential data is being submitted, the hint is used to perform merges without -any scanning. This is not sufficient when there are multiple processes doing -I/O though, so a "merge hash" is used by some schedulers. - -iii. Merge hash +ii. Merge hash AS and deadline use a hash table indexed by the last sector of a request. This enables merging code to quickly look up "back merge" candidates, even when multiple I/O streams are being performed at once on one disk. @@ -1013,29 +1025,8 @@ multiple I/O streams are being performed at once on one disk. are far less common than "back merges" due to the nature of most I/O patterns. Front merges are handled by the binary trees in AS and deadline schedulers. -iv. Handling barrier cases -A request with flags REQ_HARDBARRIER or REQ_SOFTBARRIER must not be ordered -around. That is, they must be processed after all older requests, and before -any newer ones. This includes merges! - -In AS and deadline schedulers, barriers have the effect of flushing the reorder -queue. The performance cost of this will vary from nothing to a lot depending -on i/o patterns and device characteristics. Obviously they won't improve -performance, so their use should be kept to a minimum. - -v. Handling insertion position directives -A request may be inserted with a position directive. The directives are one of -ELEVATOR_INSERT_BACK, ELEVATOR_INSERT_FRONT, ELEVATOR_INSERT_SORT. - -ELEVATOR_INSERT_SORT is a general directive for non-barrier requests. -ELEVATOR_INSERT_BACK is used to insert a barrier to the back of the queue. -ELEVATOR_INSERT_FRONT is used to insert a barrier to the front of the queue, and -overrides the ordering requested by any previous barriers. In practice this is -harmless and required, because it is used for SCSI requeueing. This does not -require flushing the reorder queue, so does not impose a performance penalty. - -vi. Plugging the queue to batch requests in anticipation of opportunities for - merge/sort optimizations +iii. Plugging the queue to batch requests in anticipation of opportunities for + merge/sort optimizations This is just the same as in 2.4 so far, though per-device unplugging support is anticipated for 2.5. Also with a priority-based i/o scheduler, @@ -1069,7 +1060,7 @@ Aside: blk_kick_queue() to unplug a specific queue (right away ?) or optionally, all queues, is in the plan. -4.3 I/O contexts +4.4 I/O contexts I/O contexts provide a dynamically allocated per process data area. They may be used in I/O schedulers, and in the block layer (could be used for IO statis, priorities for example). See *io_context in drivers/block/ll_rw_blk.c, and From cb19833dccb32f97cacbfff834b53523915f13f6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 24 Oct 2005 08:35:58 +0200 Subject: [PATCH 0821/1939] [BLOCK] kill generic max_back_kb handling This patch kills max_back_kb handling from elv_dispatch_sort() and kills max_back_kb field from struct request_queue. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 6 +----- include/linux/blkdev.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 415144372c75..af2388e73f61 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -136,7 +136,6 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, q->elevator = eq; q->end_sector = 0; q->boundary_rq = NULL; - q->max_back_kb = 0; if (eq->ops->elevator_init_fn) ret = eq->ops->elevator_init_fn(q, eq); @@ -227,16 +226,13 @@ void elevator_exit(elevator_t *e) void elv_dispatch_sort(request_queue_t *q, struct request *rq) { sector_t boundary; - unsigned max_back; struct list_head *entry; if (q->last_merge == rq) q->last_merge = NULL; boundary = q->end_sector; - max_back = q->max_back_kb * 2; - boundary = boundary > max_back ? boundary - max_back : 0; - + list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index bd55b1df8997..159dbcd2eb59 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -339,7 +339,6 @@ struct request_queue */ sector_t end_sector; struct request *boundary_rq; - unsigned int max_back_kb; /* * Auto-unplugging state From cb98fc8bb9c141009e2bda99c0db39d387e142cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Oct 2005 08:29:39 +0200 Subject: [PATCH 0822/1939] [BLOCK] Reimplement elevator switch This patch reimplements elevator switch. This patch assumes generic dispatch queue patchset is applied. * Each request is tagged with REQ_ELVPRIV flag if it has its elevator private data set. * Requests which doesn't have REQ_ELVPRIV flag set never enter iosched. They are always directly back inserted to dispatch queue. Of course, elevator_put_req_fn is called only for requests which have its REQ_ELVPRIV set. * Request queue maintains the current number of requests which have its elevator data set (elevator_set_req_fn called) in q->rq->elvpriv. * If a request queue has QUEUE_FLAG_BYPASS set, elevator private data is not allocated for new requests. To switch to another iosched, we set QUEUE_FLAG_BYPASS and wait until elvpriv goes to zero; then, we attach the new iosched and clears QUEUE_FLAG_BYPASS. New implementation is much simpler and main code paths are less cluttered, IMHO. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 78 ++++++++++----------- drivers/block/ll_rw_blk.c | 142 ++++++++------------------------------ include/linux/blkdev.h | 10 ++- 3 files changed, 66 insertions(+), 164 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index af2388e73f61..272d93946621 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -131,11 +132,7 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, eq->ops = &e->ops; eq->elevator_type = e; - INIT_LIST_HEAD(&q->queue_head); - q->last_merge = NULL; q->elevator = eq; - q->end_sector = 0; - q->boundary_rq = NULL; if (eq->ops->elevator_init_fn) ret = eq->ops->elevator_init_fn(q, eq); @@ -184,6 +181,12 @@ int elevator_init(request_queue_t *q, char *name) struct elevator_queue *eq; int ret = 0; + INIT_LIST_HEAD(&q->queue_head); + q->last_merge = NULL; + q->end_sector = 0; + q->boundary_rq = NULL; + q->max_back_kb = 0; + elevator_setup_default(); if (!name) @@ -336,23 +339,14 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; } - } + } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) + where = ELEVATOR_INSERT_BACK; if (plug) blk_plug_device(q); rq->q = q; - if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { - /* - * if drain is set, store the request "locally". when the drain - * is finished, the requests will be handed ordered to the io - * scheduler - */ - list_add_tail(&rq->queuelist, &q->drain_list); - return; - } - switch (where) { case ELEVATOR_INSERT_FRONT: rq->flags |= REQ_SOFTBARRIER; @@ -659,25 +653,36 @@ EXPORT_SYMBOL_GPL(elv_unregister); * switch to new_e io scheduler. be careful not to introduce deadlocks - * we don't free the old io scheduler, before we have allocated what we * need for the new one. this way we have a chance of going back to the old - * one, if the new one fails init for some reason. we also do an intermediate - * switch to noop to ensure safety with stack-allocated requests, since they - * don't originate from the block layer allocator. noop is safe here, because - * it never needs to touch the elevator itself for completion events. DRAIN - * flags will make sure we don't touch it for additions either. + * one, if the new one fails init for some reason. */ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) { - elevator_t *e = kmalloc(sizeof(elevator_t), GFP_KERNEL); - struct elevator_type *noop_elevator = NULL; - elevator_t *old_elevator; + elevator_t *old_elevator, *e; + /* + * Allocate new elevator + */ + e = kmalloc(sizeof(elevator_t), GFP_KERNEL); if (!e) goto error; /* - * first step, drain requests from the block freelist + * Turn on BYPASS and drain all requests w/ elevator private data */ - blk_wait_queue_drained(q, 0); + spin_lock_irq(q->queue_lock); + + set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + + while (q->rq.elvpriv) { + spin_unlock_irq(q->queue_lock); + msleep(100); + spin_lock_irq(q->queue_lock); + } + + spin_unlock_irq(q->queue_lock); /* * unregister old elevator data @@ -685,18 +690,6 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) elv_unregister_queue(q); old_elevator = q->elevator; - /* - * next step, switch to noop since it uses no private rq structures - * and doesn't allocate any memory for anything. then wait for any - * non-fs requests in-flight - */ - noop_elevator = elevator_get("noop"); - spin_lock_irq(q->queue_lock); - elevator_attach(q, noop_elevator, e); - spin_unlock_irq(q->queue_lock); - - blk_wait_queue_drained(q, 1); - /* * attach and start new elevator */ @@ -707,11 +700,10 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) goto fail_register; /* - * finally exit old elevator and start queue again + * finally exit old elevator and turn off BYPASS. */ elevator_exit(old_elevator); - blk_finish_queue_drain(q); - elevator_put(noop_elevator); + clear_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); return; fail_register: @@ -720,13 +712,13 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) * one again (along with re-adding the sysfs dir) */ elevator_exit(e); + e = NULL; fail: q->elevator = old_elevator; elv_register_queue(q); - blk_finish_queue_drain(q); + clear_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + kfree(e); error: - if (noop_elevator) - elevator_put(noop_elevator); elevator_put(new_e); printk(KERN_ERR "elevator: switch to %s failed\n",new_e->elevator_name); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index d2a66fd309c3..f7c9931cb380 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -263,8 +263,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); blk_queue_activity_fn(q, NULL, NULL); - - INIT_LIST_HEAD(&q->drain_list); } EXPORT_SYMBOL(blk_queue_make_request); @@ -1050,6 +1048,7 @@ static char *rq_flags[] = { "REQ_STARTED", "REQ_DONTPREP", "REQ_QUEUED", + "REQ_ELVPRIV", "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE", @@ -1640,9 +1639,9 @@ static int blk_init_free_list(request_queue_t *q) rl->count[READ] = rl->count[WRITE] = 0; rl->starved[READ] = rl->starved[WRITE] = 0; + rl->elvpriv = 0; init_waitqueue_head(&rl->wait[READ]); init_waitqueue_head(&rl->wait[WRITE]); - init_waitqueue_head(&rl->drain); rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep, q->node); @@ -1785,12 +1784,14 @@ EXPORT_SYMBOL(blk_get_queue); static inline void blk_free_request(request_queue_t *q, struct request *rq) { - elv_put_request(q, rq); + if (rq->flags & REQ_ELVPRIV) + elv_put_request(q, rq); mempool_free(rq, q->rq.rq_pool); } static inline struct request * -blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) +blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, + int priv, int gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -1803,11 +1804,15 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) */ rq->flags = rw; - if (!elv_set_request(q, rq, bio, gfp_mask)) - return rq; + if (priv) { + if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { + mempool_free(rq, q->rq.rq_pool); + return NULL; + } + rq->flags |= REQ_ELVPRIV; + } - mempool_free(rq, q->rq.rq_pool); - return NULL; + return rq; } /* @@ -1863,22 +1868,18 @@ static void __freed_request(request_queue_t *q, int rw) * A request has just been released. Account for it, update the full and * congestion status, wake up any waiters. Called under q->queue_lock. */ -static void freed_request(request_queue_t *q, int rw) +static void freed_request(request_queue_t *q, int rw, int priv) { struct request_list *rl = &q->rq; rl->count[rw]--; + if (priv) + rl->elvpriv--; __freed_request(q, rw); if (unlikely(rl->starved[rw ^ 1])) __freed_request(q, rw ^ 1); - - if (!rl->count[READ] && !rl->count[WRITE]) { - smp_mb(); - if (unlikely(waitqueue_active(&rl->drain))) - wake_up(&rl->drain); - } } #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) @@ -1893,9 +1894,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, struct request *rq = NULL; struct request_list *rl = &q->rq; struct io_context *ioc = current_io_context(GFP_ATOMIC); - - if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) - goto out; + int priv; if (rl->count[rw]+1 >= q->nr_requests) { /* @@ -1940,9 +1939,14 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); + + priv = !test_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + if (priv) + rl->elvpriv++; + spin_unlock_irq(q->queue_lock); - rq = blk_alloc_request(q, rw, bio, gfp_mask); + rq = blk_alloc_request(q, rw, bio, priv, gfp_mask); if (!rq) { /* * Allocation failed presumably due to memory. Undo anything @@ -1952,7 +1956,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, * wait queue, but this is pretty rare. */ spin_lock_irq(q->queue_lock); - freed_request(q, rw); + freed_request(q, rw, priv); /* * in the very unlikely event that allocation failed and no @@ -2470,11 +2474,12 @@ static void __blk_put_request(request_queue_t *q, struct request *req) */ if (rl) { int rw = rq_data_dir(req); + int priv = req->flags & REQ_ELVPRIV; BUG_ON(!list_empty(&req->queuelist)); blk_free_request(q, req); - freed_request(q, rw); + freed_request(q, rw, priv); } } @@ -2802,97 +2807,6 @@ static inline void blk_partition_remap(struct bio *bio) } } -void blk_finish_queue_drain(request_queue_t *q) -{ - struct request_list *rl = &q->rq; - struct request *rq; - int requeued = 0; - - spin_lock_irq(q->queue_lock); - clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (!list_empty(&q->drain_list)) { - rq = list_entry_rq(q->drain_list.next); - - list_del_init(&rq->queuelist); - elv_requeue_request(q, rq); - requeued++; - } - - if (requeued) - q->request_fn(q); - - spin_unlock_irq(q->queue_lock); - - wake_up(&rl->wait[0]); - wake_up(&rl->wait[1]); - wake_up(&rl->drain); -} - -static int wait_drain(request_queue_t *q, struct request_list *rl, int dispatch) -{ - int wait = rl->count[READ] + rl->count[WRITE]; - - if (dispatch) - wait += !list_empty(&q->queue_head); - - return wait; -} - -/* - * We rely on the fact that only requests allocated through blk_alloc_request() - * have io scheduler private data structures associated with them. Any other - * type of request (allocated on stack or through kmalloc()) should not go - * to the io scheduler core, but be attached to the queue head instead. - */ -void blk_wait_queue_drained(request_queue_t *q, int wait_dispatch) -{ - struct request_list *rl = &q->rq; - DEFINE_WAIT(wait); - - spin_lock_irq(q->queue_lock); - set_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (wait_drain(q, rl, wait_dispatch)) { - prepare_to_wait(&rl->drain, &wait, TASK_UNINTERRUPTIBLE); - - if (wait_drain(q, rl, wait_dispatch)) { - __generic_unplug_device(q); - spin_unlock_irq(q->queue_lock); - io_schedule(); - spin_lock_irq(q->queue_lock); - } - - finish_wait(&rl->drain, &wait); - } - - spin_unlock_irq(q->queue_lock); -} - -/* - * block waiting for the io scheduler being started again. - */ -static inline void block_wait_queue_running(request_queue_t *q) -{ - DEFINE_WAIT(wait); - - while (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { - struct request_list *rl = &q->rq; - - prepare_to_wait_exclusive(&rl->drain, &wait, - TASK_UNINTERRUPTIBLE); - - /* - * re-check the condition. avoids using prepare_to_wait() - * in the fast path (queue is running) - */ - if (test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) - io_schedule(); - - finish_wait(&rl->drain, &wait); - } -} - static void handle_bad_sector(struct bio *bio) { char b[BDEVNAME_SIZE]; @@ -2988,8 +2902,6 @@ void generic_make_request(struct bio *bio) if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) goto end_io; - block_wait_queue_running(q); - /* * If this device has partitions, remap block n * of partition p to block n+start(p) of the disk. diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 159dbcd2eb59..6186d5e2110f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -107,9 +107,9 @@ typedef void (rq_end_io_fn)(struct request *); struct request_list { int count[2]; int starved[2]; + int elvpriv; mempool_t *rq_pool; wait_queue_head_t wait[2]; - wait_queue_head_t drain; }; #define BLK_MAX_CDB 16 @@ -211,6 +211,7 @@ enum rq_flag_bits { __REQ_STARTED, /* drive already may have started this one */ __REQ_DONTPREP, /* don't call prep for this one */ __REQ_QUEUED, /* uses queueing */ + __REQ_ELVPRIV, /* elevator private data attached */ /* * for ATA/ATAPI devices */ @@ -244,6 +245,7 @@ enum rq_flag_bits { #define REQ_STARTED (1 << __REQ_STARTED) #define REQ_DONTPREP (1 << __REQ_DONTPREP) #define REQ_QUEUED (1 << __REQ_QUEUED) +#define REQ_ELVPRIV (1 << __REQ_ELVPRIV) #define REQ_PC (1 << __REQ_PC) #define REQ_BLOCK_PC (1 << __REQ_BLOCK_PC) #define REQ_SENSE (1 << __REQ_SENSE) @@ -413,8 +415,6 @@ struct request_queue unsigned int sg_reserved_size; int node; - struct list_head drain_list; - /* * reserved for flush operations */ @@ -442,7 +442,7 @@ enum { #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ #define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ #define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */ -#define QUEUE_FLAG_DRAIN 8 /* draining queue for sched switch */ +#define QUEUE_FLAG_BYPASS 8 /* don't use elevator, just do FIFO */ #define QUEUE_FLAG_FLUSH 9 /* doing barrier flush sequence */ #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) @@ -668,8 +668,6 @@ extern void blk_dump_rq_flags(struct request *, char *); extern void generic_unplug_device(request_queue_t *); extern void __generic_unplug_device(request_queue_t *); extern long nr_blockdev_pages(void); -extern void blk_wait_queue_drained(request_queue_t *, int); -extern void blk_finish_queue_drain(request_queue_t *); int blk_get_queue(request_queue_t *); request_queue_t *blk_alloc_queue(int gfp_mask); From 64521d1a3ba7cc7fe4ab5640da83d88144f05340 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Oct 2005 08:30:39 +0200 Subject: [PATCH 0823/1939] [BLOCK] elevator switch fixes/cleanup - 100msec sleep is a little excessive, lots of requests can complete in that timeframe. Use 10msec instead. - Rename QUEUE_FLAG_BYPASS to QUEUE_FLAG_ELVSWITCH to indicate what is going on. Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 8 ++++---- drivers/block/ll_rw_blk.c | 2 +- include/linux/blkdev.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 272d93946621..cf9bedbb761b 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -671,14 +671,14 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) */ spin_lock_irq(q->queue_lock); - set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); while (q->elevator->ops->elevator_dispatch_fn(q, 1)) ; while (q->rq.elvpriv) { spin_unlock_irq(q->queue_lock); - msleep(100); + msleep(10); spin_lock_irq(q->queue_lock); } @@ -703,7 +703,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) * finally exit old elevator and turn off BYPASS. */ elevator_exit(old_elevator); - clear_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); return; fail_register: @@ -716,7 +716,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) fail: q->elevator = old_elevator; elv_register_queue(q); - clear_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); kfree(e); error: elevator_put(new_e); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f7c9931cb380..fc12d019b19d 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1940,7 +1940,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); - priv = !test_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); + priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); if (priv) rl->elvpriv++; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6186d5e2110f..7d9d14d6d8f9 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -442,7 +442,7 @@ enum { #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ #define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ #define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */ -#define QUEUE_FLAG_BYPASS 8 /* don't use elevator, just do FIFO */ +#define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */ #define QUEUE_FLAG_FLUSH 9 /* doing barrier flush sequence */ #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) From 772eca7825358f52cf208afd7ab8ce22722ce41a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Oct 2005 09:01:17 +0200 Subject: [PATCH 0824/1939] [BLOCK] Leftover reference to ->max_back_kb Signed-off-by: Jens Axboe --- drivers/block/elevator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index cf9bedbb761b..8de77416bd2f 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -185,7 +185,6 @@ int elevator_init(request_queue_t *q, char *name) q->last_merge = NULL; q->end_sector = 0; q->boundary_rq = NULL; - q->max_back_kb = 0; elevator_setup_default(); From 7fca0aa489c82bef85514b5447f6a0be81543115 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 10:20:25 +0100 Subject: [PATCH 0825/1939] [ARM] 1/4: Move include of asm/hardware.h to asm-arm/arch-*/io.h Including asm/hardware.h into asm/io.h can cause #define clashes between platform specific definitions and driver local definitions. Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/io.h | 2 ++ include/asm-arm/arch-cl7500/io.h | 2 ++ include/asm-arm/arch-clps711x/io.h | 2 ++ include/asm-arm/arch-ebsa110/io.h | 2 ++ include/asm-arm/arch-ebsa285/io.h | 2 ++ include/asm-arm/arch-epxa10db/io.h | 2 ++ include/asm-arm/arch-h720x/io.h | 2 +- include/asm-arm/arch-imx/io.h | 2 ++ include/asm-arm/arch-integrator/io.h | 2 ++ include/asm-arm/arch-iop3xx/io.h | 2 ++ include/asm-arm/arch-ixp2000/io.h | 2 ++ include/asm-arm/arch-l7200/io.h | 2 +- include/asm-arm/arch-lh7a40x/io.h | 2 ++ include/asm-arm/arch-omap/io.h | 2 ++ include/asm-arm/arch-pxa/io.h | 2 ++ include/asm-arm/arch-rpc/io.h | 2 ++ include/asm-arm/arch-s3c2410/io.h | 2 ++ include/asm-arm/arch-sa1100/io.h | 2 ++ include/asm-arm/arch-shark/io.h | 2 ++ include/asm-arm/arch-versatile/io.h | 2 ++ include/asm-arm/io.h | 1 - 21 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/asm-arm/arch-aaec2000/io.h b/include/asm-arm/arch-aaec2000/io.h index c58a8d10425a..8d67907fd4f0 100644 --- a/include/asm-arm/arch-aaec2000/io.h +++ b/include/asm-arm/arch-aaec2000/io.h @@ -6,6 +6,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-cl7500/io.h b/include/asm-arm/arch-cl7500/io.h index f0113bc75630..89a33287f4fe 100644 --- a/include/asm-arm/arch-cl7500/io.h +++ b/include/asm-arm/arch-cl7500/io.h @@ -10,6 +10,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-clps711x/io.h b/include/asm-arm/arch-clps711x/io.h index 14d7e8da5453..62613b0e2d96 100644 --- a/include/asm-arm/arch-clps711x/io.h +++ b/include/asm-arm/arch-clps711x/io.h @@ -20,6 +20,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff #define __io(a) ((void __iomem *)(a)) diff --git a/include/asm-arm/arch-ebsa110/io.h b/include/asm-arm/arch-ebsa110/io.h index 68e04c0bb3f7..ecf433634246 100644 --- a/include/asm-arm/arch-ebsa110/io.h +++ b/include/asm-arm/arch-ebsa110/io.h @@ -13,6 +13,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffff u8 __inb8(unsigned int port); diff --git a/include/asm-arm/arch-ebsa285/io.h b/include/asm-arm/arch-ebsa285/io.h index 70576b17f922..776f9d377057 100644 --- a/include/asm-arm/arch-ebsa285/io.h +++ b/include/asm-arm/arch-ebsa285/io.h @@ -14,6 +14,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffff /* diff --git a/include/asm-arm/arch-epxa10db/io.h b/include/asm-arm/arch-epxa10db/io.h index 1f0afa257621..9fe100c9d6be 100644 --- a/include/asm-arm/arch-epxa10db/io.h +++ b/include/asm-arm/arch-epxa10db/io.h @@ -20,6 +20,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffff diff --git a/include/asm-arm/arch-h720x/io.h b/include/asm-arm/arch-h720x/io.h index 68814828c9a7..d3ccfd8172b7 100644 --- a/include/asm-arm/arch-h720x/io.h +++ b/include/asm-arm/arch-h720x/io.h @@ -14,7 +14,7 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#include +#include #define IO_SPACE_LIMIT 0xffffffff diff --git a/include/asm-arm/arch-imx/io.h b/include/asm-arm/arch-imx/io.h index 28a4cca6a4cb..b191cdd05576 100644 --- a/include/asm-arm/arch-imx/io.h +++ b/include/asm-arm/arch-imx/io.h @@ -20,6 +20,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff #define __io(a) ((void __iomem *)(a)) diff --git a/include/asm-arm/arch-integrator/io.h b/include/asm-arm/arch-integrator/io.h index fbea8be67d26..1329a731160d 100644 --- a/include/asm-arm/arch-integrator/io.h +++ b/include/asm-arm/arch-integrator/io.h @@ -20,6 +20,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffff #define __io(a) ((void __iomem *)(PCI_IO_VADDR + (a))) diff --git a/include/asm-arm/arch-iop3xx/io.h b/include/asm-arm/arch-iop3xx/io.h index 2761dfd8694d..f39046a6ab14 100644 --- a/include/asm-arm/arch-iop3xx/io.h +++ b/include/asm-arm/arch-iop3xx/io.h @@ -11,6 +11,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff #define __io(p) ((void __iomem *)(p)) diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h index 3241cd6f0778..7fbcdf9931ee 100644 --- a/include/asm-arm/arch-ixp2000/io.h +++ b/include/asm-arm/arch-ixp2000/io.h @@ -15,6 +15,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff #define __mem_pci(a) (a) diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h index fc012a39e2cb..cab8ad0adf09 100644 --- a/include/asm-arm/arch-l7200/io.h +++ b/include/asm-arm/arch-l7200/io.h @@ -10,7 +10,7 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#include +#include #define IO_SPACE_LIMIT 0xffffffff diff --git a/include/asm-arm/arch-lh7a40x/io.h b/include/asm-arm/arch-lh7a40x/io.h index c13bdd9add92..bbcd4335f441 100644 --- a/include/asm-arm/arch-lh7a40x/io.h +++ b/include/asm-arm/arch-lh7a40x/io.h @@ -11,6 +11,8 @@ #ifndef __ASM_ARCH_IO_H #define __ASM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* No ISA or PCI bus on this machine. */ diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h index 11fbf629bf75..3d5bcd545082 100644 --- a/include/asm-arm/arch-omap/io.h +++ b/include/asm-arm/arch-omap/io.h @@ -34,6 +34,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-pxa/io.h b/include/asm-arm/arch-pxa/io.h index c3bdbe44e21f..eb2dd58d397f 100644 --- a/include/asm-arm/arch-pxa/io.h +++ b/include/asm-arm/arch-pxa/io.h @@ -6,6 +6,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-rpc/io.h b/include/asm-arm/arch-rpc/io.h index 24453c405a87..b4da08d7a336 100644 --- a/include/asm-arm/arch-rpc/io.h +++ b/include/asm-arm/arch-rpc/io.h @@ -13,6 +13,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-s3c2410/io.h b/include/asm-arm/arch-s3c2410/io.h index 4bf272ed9add..16fbc8afffd9 100644 --- a/include/asm-arm/arch-s3c2410/io.h +++ b/include/asm-arm/arch-s3c2410/io.h @@ -15,6 +15,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-sa1100/io.h b/include/asm-arm/arch-sa1100/io.h index 7d969ffbd3bb..9c8f588f35db 100644 --- a/include/asm-arm/arch-sa1100/io.h +++ b/include/asm-arm/arch-sa1100/io.h @@ -10,6 +10,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-shark/io.h b/include/asm-arm/arch-shark/io.h index 5e6ed0038b2b..87ffa27f2962 100644 --- a/include/asm-arm/arch-shark/io.h +++ b/include/asm-arm/arch-shark/io.h @@ -11,6 +11,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h index 47e904cf25c7..c2eed7f04b78 100644 --- a/include/asm-arm/arch-versatile/io.h +++ b/include/asm-arm/arch-versatile/io.h @@ -20,6 +20,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff static inline void __iomem *__io(unsigned long addr) diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 5c4ae8f5dbb0..2e6799632f12 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -26,7 +26,6 @@ #include #include #include -#include /* * ISA I/O bus memory addresses are 1:1 with the physical address. From 766529fa2c95e2006ad4c4485c4cde0912d21f12 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 10:29:21 +0100 Subject: [PATCH 0826/1939] [ARM] 2/4: Remove asm/hardware.h from asm-arm/arch-ebsa110/io.h EBSA110 only requires hardware.h to be included for a couple of files. Move the include there. Signed-off-by: Russell King --- arch/arm/mach-ebsa110/io.c | 1 + drivers/net/arm/am79c961a.c | 1 + include/asm-arm/arch-ebsa110/io.h | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c index ef7eb5dc91bd..c648bfb676a1 100644 --- a/arch/arm/mach-ebsa110/io.c +++ b/arch/arm/mach-ebsa110/io.c @@ -24,6 +24,7 @@ #include #include +#include #include #include diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index c56d86d371a9..3d50e953faaa 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -29,6 +29,7 @@ #include #include +#include #include #define TX_BUFFERS 15 diff --git a/include/asm-arm/arch-ebsa110/io.h b/include/asm-arm/arch-ebsa110/io.h index ecf433634246..68e04c0bb3f7 100644 --- a/include/asm-arm/arch-ebsa110/io.h +++ b/include/asm-arm/arch-ebsa110/io.h @@ -13,8 +13,6 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#include - #define IO_SPACE_LIMIT 0xffff u8 __inb8(unsigned int port); From d73e0c99f5c45e7b86d38725a4ff49f6746f5353 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 22:45:25 +1000 Subject: [PATCH 0827/1939] powerpc: Rename asm offset TRAP to _TRAP for 32-bit ... for consistency with 64-bit. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 3 +-- arch/powerpc/kernel/entry_32.S | 44 +++++++++++++++---------------- arch/powerpc/kernel/head_32.S | 2 +- arch/powerpc/kernel/head_4xx.S | 2 +- arch/powerpc/kernel/head_8xx.S | 2 +- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 710336a9f0fd..330cd783206f 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -209,6 +209,7 @@ int main(void) DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); + DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); #ifndef CONFIG_PPC64 DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); /* @@ -219,9 +220,7 @@ int main(void) */ DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); #else /* CONFIG_PPC64 */ - DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 960da7bea043..2e99ae41723c 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -278,7 +278,7 @@ ret_from_fork: syscall_dotrace: SAVE_NVGPRS(r1) li r0,0xc00 - stw r0,TRAP(r1) + stw r0,_TRAP(r1) addi r3,r1,STACK_FRAME_OVERHEAD bl do_syscall_trace_enter lwz r0,GPR0(r1) /* Restore original registers */ @@ -299,12 +299,12 @@ syscall_exit_work: ori r10,r10,MSR_EE SYNC MTMSRD(r10) /* re-enable interrupts */ - lwz r4,TRAP(r1) + lwz r4,_TRAP(r1) andi. r4,r4,1 beq 4f SAVE_NVGPRS(r1) li r4,0xc00 - stw r4,TRAP(r1) + stw r4,_TRAP(r1) 4: addi r3,r1,STACK_FRAME_OVERHEAD bl do_syscall_trace_leave @@ -410,49 +410,49 @@ show_syscalls_task: .globl ppc_sigsuspend ppc_sigsuspend: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ + stw r0,_TRAP(r1) /* register set saved */ b sys_sigsuspend .globl ppc_rt_sigsuspend ppc_rt_sigsuspend: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 - stw r0,TRAP(r1) + stw r0,_TRAP(r1) b sys_rt_sigsuspend .globl ppc_fork ppc_fork: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ + stw r0,_TRAP(r1) /* register set saved */ b sys_fork .globl ppc_vfork ppc_vfork: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ + stw r0,_TRAP(r1) /* register set saved */ b sys_vfork .globl ppc_clone ppc_clone: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ + stw r0,_TRAP(r1) /* register set saved */ b sys_clone .globl ppc_swapcontext ppc_swapcontext: SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ + stw r0,_TRAP(r1) /* register set saved */ b sys_swapcontext /* @@ -469,9 +469,9 @@ handle_page_fault: cmpwi r3,0 beq+ ret_from_except SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) + lwz r0,_TRAP(r1) clrrwi r0,r0,1 - stw r0,TRAP(r1) + stw r0,_TRAP(r1) mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD lwz r4,_DAR(r1) @@ -617,7 +617,7 @@ BEGIN_FTR_SECTION b 2b END_FTR_SECTION_IFSET(CPU_FTR_601) li r10,-1 - stw r10,TRAP(r11) + stw r10,_TRAP(r11) addi r3,r1,STACK_FRAME_OVERHEAD lis r10,MSR_KERNEL@h ori r10,r10,MSR_KERNEL@l @@ -899,12 +899,12 @@ do_user_signal: /* r10 contains MSR_KERNEL here */ SYNC MTMSRD(r10) /* hard-enable interrupts */ /* save r13-r31 in the exception frame, if not already done */ - lwz r3,TRAP(r1) + lwz r3,_TRAP(r1) andi. r0,r3,1 beq 2f SAVE_NVGPRS(r1) rlwinm r3,r3,0,0,30 - stw r3,TRAP(r1) + stw r3,_TRAP(r1) 2: li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl do_signal @@ -936,12 +936,12 @@ nonrecoverable: BEGIN_FTR_SECTION blr END_FTR_SECTION_IFSET(CPU_FTR_601) - lwz r3,TRAP(r1) + lwz r3,_TRAP(r1) andi. r0,r3,1 beq 4f SAVE_NVGPRS(r1) rlwinm r3,r3,0,0,30 - stw r3,TRAP(r1) + stw r3,_TRAP(r1) 4: addi r3,r1,STACK_FRAME_OVERHEAD bl nonrecoverable_exception /* shouldn't return */ diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index f8673f7b2b2d..600ea19d08b5 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -294,7 +294,7 @@ label: \ #define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ li r10,trap; \ - stw r10,TRAP(r11); \ + stw r10,_TRAP(r11); \ li r10,MSR_KERNEL; \ copyee(r10, r9); \ bl tfer; \ diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S index 10c261c67021..2590e97f5539 100644 --- a/arch/powerpc/kernel/head_4xx.S +++ b/arch/powerpc/kernel/head_4xx.S @@ -214,7 +214,7 @@ label: #define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ li r10,trap; \ - stw r10,TRAP(r11); \ + stw r10,_TRAP(r11); \ lis r10,msr@h; \ ori r10,r10,msr@l; \ copyee(r10, r9); \ diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index de0978742221..bc6d1ac55235 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -175,7 +175,7 @@ label: \ #define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ li r10,trap; \ - stw r10,TRAP(r11); \ + stw r10,_TRAP(r11); \ li r10,MSR_KERNEL; \ copyee(r10, r9); \ bl tfer; \ From c032524f0ddea5fcc3a2cece0d4a61f37e5ca9cd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 22:48:08 +1000 Subject: [PATCH 0828/1939] powerpc: Make single-stepping emulation (mostly) usable on 32-bit The sc instruction emulation can't be done the same way on 32-bit as 64-bit yet, but this should work OK. Signed-off-by: Paul Mackerras --- arch/powerpc/lib/sstep.c | 17 +++++++++++++++++ include/asm-powerpc/reg.h | 8 ++++++++ include/{asm-ppc64 => asm-powerpc}/sstep.h | 4 +++- 3 files changed, 28 insertions(+), 1 deletion(-) rename include/{asm-ppc64 => asm-powerpc}/sstep.h (85%) diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index e79123d1485c..666c2aa55016 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -10,13 +10,18 @@ */ #include #include +#include #include #include extern char system_call_common[]; +#ifdef CONFIG_PPC64 /* Bits in SRR1 that are copied from MSR */ #define MSR_MASK 0xffffffff87c0ffff +#else +#define MSR_MASK 0x87c0ffff +#endif /* * Determine whether a conditional branch instruction would branch. @@ -66,6 +71,7 @@ int emulate_step(struct pt_regs *regs, unsigned int instr) if (branch_taken(instr, regs)) regs->nip = imm; return 1; +#ifdef CONFIG_PPC64 case 17: /* sc */ /* * N.B. this uses knowledge about how the syscall @@ -79,6 +85,7 @@ int emulate_step(struct pt_regs *regs, unsigned int instr) regs->nip = (unsigned long) &system_call_common; regs->msr = MSR_KERNEL; return 1; +#endif case 18: /* b */ imm = instr & 0x03fffffc; if (imm & 0x02000000) @@ -121,6 +128,15 @@ int emulate_step(struct pt_regs *regs, unsigned int instr) if ((regs->msr & MSR_SF) == 0) regs->nip &= 0xffffffffUL; return 1; + case 0x124: /* mtmsr */ + imm = regs->gpr[rd]; + if ((imm & MSR_RI) == 0) + /* can't step mtmsr that would clear MSR_RI */ + return -1; + regs->msr = imm; + regs->nip += 4; + return 1; +#ifdef CONFIG_PPC64 case 0x164: /* mtmsrd */ /* only MSR_EE and MSR_RI get changed if bit 15 set */ /* mtmsrd doesn't change MSR_HV and MSR_ME */ @@ -135,6 +151,7 @@ int emulate_step(struct pt_regs *regs, unsigned int instr) if ((imm & MSR_SF) == 0) regs->nip &= 0xffffffffUL; return 1; +#endif } } return 0; diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 68058d72d8da..bfb45a4523d3 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -51,9 +51,17 @@ #define __MASK(X) (1UL<<(X)) #endif +#ifdef CONFIG_PPC64 #define MSR_SF __MASK(MSR_SF_LG) /* Enable 64 bit mode */ #define MSR_ISF __MASK(MSR_ISF_LG) /* Interrupt 64b mode valid on 630 */ #define MSR_HV __MASK(MSR_HV_LG) /* Hypervisor state */ +#else +/* so tests for these bits fail on 32-bit */ +#define MSR_SF 0 +#define MSR_ISF 0 +#define MSR_HV 0 +#endif + #define MSR_VEC __MASK(MSR_VEC_LG) /* Enable AltiVec */ #define MSR_POW __MASK(MSR_POW_LG) /* Enable Power Management */ #define MSR_WE __MASK(MSR_WE_LG) /* Wait State Enable */ diff --git a/include/asm-ppc64/sstep.h b/include/asm-powerpc/sstep.h similarity index 85% rename from include/asm-ppc64/sstep.h rename to include/asm-powerpc/sstep.h index 4a68db50ee6f..630a9889c07c 100644 --- a/include/asm-ppc64/sstep.h +++ b/include/asm-powerpc/sstep.h @@ -16,8 +16,10 @@ struct pt_regs; * we don't allow putting a breakpoint on an mtmsrd instruction. * Similarly we don't allow breakpoints on rfid instructions. * These macros tell us if an instruction is a mtmsrd or rfid. + * Note that IS_MTMSRD returns true for both an mtmsr (32-bit) + * and an mtmsrd (64-bit). */ -#define IS_MTMSRD(instr) (((instr) & 0xfc0007fe) == 0x7c000164) +#define IS_MTMSRD(instr) (((instr) & 0xfc0007be) == 0x7c000124) #define IS_RFID(instr) (((instr) & 0xfc0007fe) == 0x4c000024) /* Emulate instructions that cause a transfer of control. */ From f78541dcec327b0c46b150ee7d727f3db80275c4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Oct 2005 22:53:37 +1000 Subject: [PATCH 0829/1939] powerpc: Merge xmon The merged version follows the ppc64 version pretty closely mostly, and in fact ARCH=ppc64 now uses the arch/powerpc/xmon version. The main difference for ppc64 is that the 'p' command to call show_state (which was always pretty dodgy) has been replaced by the ppc32 'p' command, which calls a given procedure (so in fact the old 'p' command behaviour can be achieved with 'p $show_state'). Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 2 +- arch/powerpc/kernel/head_32.S | 3 + arch/powerpc/kernel/ppc_ksyms.c | 5 - arch/powerpc/kernel/setup_32.c | 6 +- arch/powerpc/kernel/setup_64.c | 1 + arch/powerpc/lib/Makefile | 2 + arch/powerpc/xmon/Makefile | 11 + arch/{ppc64 => powerpc}/xmon/ansidecl.h | 0 arch/{ppc64 => powerpc}/xmon/nonstdio.h | 0 arch/{ppc64 => powerpc}/xmon/ppc-dis.c | 0 arch/{ppc64 => powerpc}/xmon/ppc-opc.c | 0 arch/{ppc64 => powerpc}/xmon/ppc.h | 0 arch/powerpc/xmon/setjmp.S | 135 ++++ arch/powerpc/xmon/start_32.c | 624 ++++++++++++++++++ .../xmon/start.c => powerpc/xmon/start_64.c} | 0 arch/powerpc/xmon/start_8xx.c | 287 ++++++++ arch/{ppc64 => powerpc}/xmon/subr_prf.c | 11 +- arch/{ppc64 => powerpc}/xmon/xmon.c | 394 +++++------ arch/ppc64/Makefile | 2 +- arch/ppc64/xmon/Makefile | 5 - arch/ppc64/xmon/setjmp.S | 73 -- include/asm-powerpc/ppc_asm.h | 8 + include/asm-powerpc/reg.h | 1 + include/asm-powerpc/xmon.h | 2 +- 24 files changed, 1289 insertions(+), 283 deletions(-) create mode 100644 arch/powerpc/xmon/Makefile rename arch/{ppc64 => powerpc}/xmon/ansidecl.h (100%) rename arch/{ppc64 => powerpc}/xmon/nonstdio.h (100%) rename arch/{ppc64 => powerpc}/xmon/ppc-dis.c (100%) rename arch/{ppc64 => powerpc}/xmon/ppc-opc.c (100%) rename arch/{ppc64 => powerpc}/xmon/ppc.h (100%) create mode 100644 arch/powerpc/xmon/setjmp.S create mode 100644 arch/powerpc/xmon/start_32.c rename arch/{ppc64/xmon/start.c => powerpc/xmon/start_64.c} (100%) create mode 100644 arch/powerpc/xmon/start_8xx.c rename arch/{ppc64 => powerpc}/xmon/subr_prf.c (84%) rename arch/{ppc64 => powerpc}/xmon/xmon.c (90%) delete mode 100644 arch/ppc64/xmon/Makefile delete mode 100644 arch/ppc64/xmon/setjmp.S diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index dedf1219761a..29cda0732703 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -131,7 +131,7 @@ core-y += arch/powerpc/kernel/ \ arch/powerpc/sysdev/ \ arch/powerpc/platforms/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ -#core-$(CONFIG_XMON) += arch/powerpc/xmon/ +core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_APUS) += arch/ppc/amiga/ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 600ea19d08b5..b102e3a2415e 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -271,6 +271,9 @@ __secondary_hold_acknowledge: li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ MTMSRD(r10); /* (except for mach check in rtas) */ \ stw r0,GPR0(r11); \ + lis r10,0x7265; /* put exception frame marker */ \ + addi r10,r10,0x6773; \ + stw r10,8(r11); \ SAVE_4GPRS(3, r11); \ SAVE_2GPRS(7, r11) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 5f3a12bb8961..8bc540337ba0 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -44,7 +44,6 @@ #include #include #include -#include #ifdef CONFIG_8xx #include @@ -238,10 +237,6 @@ EXPORT_SYMBOL(console_drivers); EXPORT_SYMBOL(cacheable_memcpy); #endif -#ifdef CONFIG_XMON -EXPORT_SYMBOL(xmon); -EXPORT_SYMBOL(xmon_printf); -#endif EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 7c99e6b8c76c..9680ae99b084 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -302,8 +302,10 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_XMON xmon_map_scc(); - if (strstr(cmd_line, "xmon")) - xmon(NULL); + if (strstr(cmd_line, "xmon")) { + xmon_init(1); + debugger(NULL); + } #endif /* CONFIG_XMON */ if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 950e6f0fea98..681537f8ea10 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 0115bf96751c..e6b2be3bcec1 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o obj-$(CONFIG_PPC_ISERIES) += e2a.o +obj-$(CONFIG_XMON) += sstep.o + ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o obj-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile new file mode 100644 index 000000000000..79a784f0e7a9 --- /dev/null +++ b/arch/powerpc/xmon/Makefile @@ -0,0 +1,11 @@ +# Makefile for xmon + +ifdef CONFIG_PPC64 +EXTRA_CFLAGS += -mno-minimal-toc +endif + +obj-$(CONFIG_8xx) += start_8xx.o +obj-$(CONFIG_6xx) += start_32.o +obj-$(CONFIG_4xx) += start_32.o +obj-$(CONFIG_PPC64) += start_64.o +obj-y += xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o diff --git a/arch/ppc64/xmon/ansidecl.h b/arch/powerpc/xmon/ansidecl.h similarity index 100% rename from arch/ppc64/xmon/ansidecl.h rename to arch/powerpc/xmon/ansidecl.h diff --git a/arch/ppc64/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h similarity index 100% rename from arch/ppc64/xmon/nonstdio.h rename to arch/powerpc/xmon/nonstdio.h diff --git a/arch/ppc64/xmon/ppc-dis.c b/arch/powerpc/xmon/ppc-dis.c similarity index 100% rename from arch/ppc64/xmon/ppc-dis.c rename to arch/powerpc/xmon/ppc-dis.c diff --git a/arch/ppc64/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c similarity index 100% rename from arch/ppc64/xmon/ppc-opc.c rename to arch/powerpc/xmon/ppc-opc.c diff --git a/arch/ppc64/xmon/ppc.h b/arch/powerpc/xmon/ppc.h similarity index 100% rename from arch/ppc64/xmon/ppc.h rename to arch/powerpc/xmon/ppc.h diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/xmon/setjmp.S new file mode 100644 index 000000000000..f8e40dfd2bff --- /dev/null +++ b/arch/powerpc/xmon/setjmp.S @@ -0,0 +1,135 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * 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. + * + * NOTE: assert(sizeof(buf) > 23 * sizeof(long)) + */ +#include +#include +#include + +_GLOBAL(xmon_setjmp) + mflr r0 + STL r0,0(r3) + STL r1,SZL(r3) + STL r2,2*SZL(r3) + mfcr r0 + STL r0,3*SZL(r3) + STL r13,4*SZL(r3) + STL r14,5*SZL(r3) + STL r15,6*SZL(r3) + STL r16,7*SZL(r3) + STL r17,8*SZL(r3) + STL r18,9*SZL(r3) + STL r19,10*SZL(r3) + STL r20,11*SZL(r3) + STL r21,12*SZL(r3) + STL r22,13*SZL(r3) + STL r23,14*SZL(r3) + STL r24,15*SZL(r3) + STL r25,16*SZL(r3) + STL r26,17*SZL(r3) + STL r27,18*SZL(r3) + STL r28,19*SZL(r3) + STL r29,20*SZL(r3) + STL r30,21*SZL(r3) + STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(xmon_longjmp) + CMPI r4,0 + bne 1f + li r4,1 +1: LDL r13,4*SZL(r3) + LDL r14,5*SZL(r3) + LDL r15,6*SZL(r3) + LDL r16,7*SZL(r3) + LDL r17,8*SZL(r3) + LDL r18,9*SZL(r3) + LDL r19,10*SZL(r3) + LDL r20,11*SZL(r3) + LDL r21,12*SZL(r3) + LDL r22,13*SZL(r3) + LDL r23,14*SZL(r3) + LDL r24,15*SZL(r3) + LDL r25,16*SZL(r3) + LDL r26,17*SZL(r3) + LDL r27,18*SZL(r3) + LDL r28,19*SZL(r3) + LDL r29,20*SZL(r3) + LDL r30,21*SZL(r3) + LDL r31,22*SZL(r3) + LDL r0,3*SZL(r3) + mtcrf 0x38,r0 + LDL r0,0(r3) + LDL r1,SZL(r3) + LDL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr + +/* + * Grab the register values as they are now. + * This won't do a particularily good job because we really + * want our caller's caller's registers, and our caller has + * already executed its prologue. + * ToDo: We could reach back into the caller's save area to do + * a better job of representing the caller's state (note that + * that will be different for 32-bit and 64-bit, because of the + * different ABIs, though). + */ +_GLOBAL(xmon_save_regs) + STL r0,0*SZL(r3) + STL r2,2*SZL(r3) + STL r3,3*SZL(r3) + STL r4,4*SZL(r3) + STL r5,5*SZL(r3) + STL r6,6*SZL(r3) + STL r7,7*SZL(r3) + STL r8,8*SZL(r3) + STL r9,9*SZL(r3) + STL r10,10*SZL(r3) + STL r11,11*SZL(r3) + STL r12,12*SZL(r3) + STL r13,13*SZL(r3) + STL r14,14*SZL(r3) + STL r15,15*SZL(r3) + STL r16,16*SZL(r3) + STL r17,17*SZL(r3) + STL r18,18*SZL(r3) + STL r19,19*SZL(r3) + STL r20,20*SZL(r3) + STL r21,21*SZL(r3) + STL r22,22*SZL(r3) + STL r23,23*SZL(r3) + STL r24,24*SZL(r3) + STL r25,25*SZL(r3) + STL r26,26*SZL(r3) + STL r27,27*SZL(r3) + STL r28,28*SZL(r3) + STL r29,29*SZL(r3) + STL r30,30*SZL(r3) + STL r31,31*SZL(r3) + /* go up one stack frame for SP */ + LDL r4,0(r1) + STL r4,1*SZL(r3) + /* get caller's LR */ + LDL r0,LRSAVE(r4) + STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) + STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) + mfmsr r0 + STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) + mfctr r0 + STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) + mfxer r0 + STL r0,_XER-STACK_FRAME_OVERHEAD(r3) + mfcr r0 + STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) + li r0,0 + STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) + blr diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c new file mode 100644 index 000000000000..69b658c0f760 --- /dev/null +++ b/arch/powerpc/xmon/start_32.c @@ -0,0 +1,624 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile unsigned char __iomem *sccc, *sccd; +unsigned int TXRDY, RXRDY, DLAB; +static int xmon_expect(const char *str, unsigned int timeout); + +static int use_serial; +static int use_screen; +static int via_modem; +static int xmon_use_sccb; +static struct device_node *channel_node; + +#define TB_SPEED 25000000 + +static inline unsigned int readtb(void) +{ + unsigned int ret; + + asm volatile("mftb %0" : "=r" (ret) :); + return ret; +} + +void buf_access(void) +{ + if (DLAB) + sccd[3] &= ~DLAB; /* reset DLAB */ +} + +extern int adb_init(void); + +#ifdef CONFIG_PPC_CHRP +/* + * This looks in the "ranges" property for the primary PCI host bridge + * to find the physical address of the start of PCI/ISA I/O space. + * It is basically a cut-down version of pci_process_bridge_OF_ranges. + */ +static unsigned long chrp_find_phys_io_base(void) +{ + struct device_node *node; + unsigned int *ranges; + unsigned long base = CHRP_ISA_IO_BASE; + int rlen = 0; + int np; + + node = find_devices("isa"); + if (node != NULL) { + node = node->parent; + if (node == NULL || node->type == NULL + || strcmp(node->type, "pci") != 0) + node = NULL; + } + if (node == NULL) + node = find_devices("pci"); + if (node == NULL) + return base; + + ranges = (unsigned int *) get_property(node, "ranges", &rlen); + np = prom_n_addr_cells(node) + 5; + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + if ((ranges[0] >> 24) == 1 && ranges[2] == 0) { + /* I/O space starting at 0, grab the phys base */ + base = ranges[np - 3]; + break; + } + ranges += np; + } + return base; +} +#endif /* CONFIG_PPC_CHRP */ + +#ifdef CONFIG_MAGIC_SYSRQ +static void sysrq_handle_xmon(int key, struct pt_regs *regs, + struct tty_struct *tty) +{ + xmon(regs); +} + +static struct sysrq_key_op sysrq_xmon_op = +{ + .handler = sysrq_handle_xmon, + .help_msg = "Xmon", + .action_msg = "Entering xmon", +}; +#endif + +void +xmon_map_scc(void) +{ +#ifdef CONFIG_PPC_MULTIPLATFORM + volatile unsigned char __iomem *base; + + if (_machine == _MACH_Pmac) { + struct device_node *np; + unsigned long addr; +#ifdef CONFIG_BOOTX_TEXT + if (!use_screen && !use_serial + && !machine_is_compatible("iMac")) { + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (np = find_devices("keyboard"); np; np = np->next) + if (np->parent && np->parent->type + && strcmp(np->parent->type, "adb") == 0) + break; + + /* needs to be hacked if xmon_printk is to be used + from within find_via_pmu() */ +#ifdef CONFIG_ADB_PMU + if (np != NULL && boot_text_mapped && find_via_pmu()) + use_screen = 1; +#endif +#ifdef CONFIG_ADB_CUDA + if (np != NULL && boot_text_mapped && find_via_cuda()) + use_screen = 1; +#endif + } + if (!use_screen && (np = find_devices("escc")) != NULL) { + /* + * look for the device node for the serial port + * we're using and see if it says it has a modem + */ + char *name = xmon_use_sccb? "ch-b": "ch-a"; + char *slots; + int l; + + np = np->child; + while (np != NULL && strcmp(np->name, name) != 0) + np = np->sibling; + if (np != NULL) { + /* XXX should parse this properly */ + channel_node = np; + slots = get_property(np, "slot-names", &l); + if (slots != NULL && l >= 10 + && strcmp(slots+4, "Modem") == 0) + via_modem = 1; + } + } + btext_drawstring("xmon uses "); + if (use_screen) + btext_drawstring("screen and keyboard\n"); + else { + if (via_modem) + btext_drawstring("modem on "); + btext_drawstring(xmon_use_sccb? "printer": "modem"); + btext_drawstring(" port\n"); + } + +#endif /* CONFIG_BOOTX_TEXT */ + +#ifdef CHRP_ESCC + addr = 0xc1013020; +#else + addr = 0xf3013020; +#endif + TXRDY = 4; + RXRDY = 1; + + np = find_devices("mac-io"); + if (np && np->n_addrs) + addr = np->addrs[0].address + 0x13020; + base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); + sccc = base + (addr & ~PAGE_MASK); + sccd = sccc + 0x10; + + } else { + base = (volatile unsigned char *) isa_io_base; + +#ifdef CONFIG_PPC_CHRP + if (_machine == _MACH_chrp) + base = (volatile unsigned char __iomem *) + ioremap(chrp_find_phys_io_base(), 0x1000); +#endif + + sccc = base + 0x3fd; + sccd = base + 0x3f8; + if (xmon_use_sccb) { + sccc -= 0x100; + sccd -= 0x100; + } + TXRDY = 0x20; + RXRDY = 1; + DLAB = 0x80; + } +#elif defined(CONFIG_GEMINI) + /* should already be mapped by the kernel boot */ + sccc = (volatile unsigned char __iomem *) 0xffeffb0d; + sccd = (volatile unsigned char __iomem *) 0xffeffb08; + TXRDY = 0x20; + RXRDY = 1; + DLAB = 0x80; +#elif defined(CONFIG_405GP) + sccc = (volatile unsigned char __iomem *)0xef600305; + sccd = (volatile unsigned char __iomem *)0xef600300; + TXRDY = 0x20; + RXRDY = 1; + DLAB = 0x80; +#endif /* platform */ + + register_sysrq_key('x', &sysrq_xmon_op); +} + +static int scc_initialized = 0; + +void xmon_init_scc(void); +extern void cuda_poll(void); + +static inline void do_poll_adb(void) +{ +#ifdef CONFIG_ADB_PMU + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll_adb(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (sys_ctrler == SYS_CTRLER_CUDA) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} + +int +xmon_write(void *handle, void *ptr, int nb) +{ + char *p = ptr; + int i, c, ct; + +#ifdef CONFIG_SMP + static unsigned long xmon_write_lock; + int lock_wait = 1000000; + int locked; + + while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0) + if (--lock_wait == 0) + break; +#endif + +#ifdef CONFIG_BOOTX_TEXT + if (use_screen) { + /* write it on the screen */ + for (i = 0; i < nb; ++i) + btext_drawchar(*p++); + goto out; + } +#endif + if (!scc_initialized) + xmon_init_scc(); + ct = 0; + for (i = 0; i < nb; ++i) { + while ((*sccc & TXRDY) == 0) + do_poll_adb(); + c = p[i]; + if (c == '\n' && !ct) { + c = '\r'; + ct = 1; + --i; + } else { + ct = 0; + } + buf_access(); + *sccd = c; + eieio(); + } + + out: +#ifdef CONFIG_SMP + if (!locked) + clear_bit(0, &xmon_write_lock); +#endif + return nb; +} + +int xmon_wants_key; +int xmon_adb_keycode; + +#ifdef CONFIG_BOOTX_TEXT +static int xmon_adb_shiftstate; + +static unsigned char xmon_keytab[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80]o" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static unsigned char xmon_shift_keytab[128] = + "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ + "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ + "U{IP\rLJ\"K:|" /* 0x20 - 0x2f */ + "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static int +xmon_get_adb_key(void) +{ + int k, t, on; + + xmon_wants_key = 1; + for (;;) { + xmon_adb_keycode = -1; + t = 0; + on = 0; + do { + if (--t < 0) { + on = 1 - on; + btext_drawchar(on? 0xdb: 0x20); + btext_drawchar('\b'); + t = 200000; + } + do_poll_adb(); + } while (xmon_adb_keycode == -1); + k = xmon_adb_keycode; + if (on) + btext_drawstring(" \b"); + + /* test for shift keys */ + if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { + xmon_adb_shiftstate = (k & 0x80) == 0; + continue; + } + if (k >= 0x80) + continue; /* ignore up transitions */ + k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; + if (k != 0) + break; + } + xmon_wants_key = 0; + return k; +} +#endif /* CONFIG_BOOTX_TEXT */ + +int +xmon_read(void *handle, void *ptr, int nb) +{ + char *p = ptr; + int i; + +#ifdef CONFIG_BOOTX_TEXT + if (use_screen) { + for (i = 0; i < nb; ++i) + *p++ = xmon_get_adb_key(); + return i; + } +#endif + if (!scc_initialized) + xmon_init_scc(); + for (i = 0; i < nb; ++i) { + while ((*sccc & RXRDY) == 0) + do_poll_adb(); + buf_access(); + *p++ = *sccd; + } + return i; +} + +int +xmon_read_poll(void) +{ + if ((*sccc & RXRDY) == 0) { + do_poll_adb(); + return -1; + } + buf_access(); + return *sccd; +} + +static unsigned char scc_inittab[] = { + 13, 0, /* set baud rate divisor */ + 12, 1, + 14, 1, /* baud rate gen enable, src=rtxc */ + 11, 0x50, /* clocks = br gen */ + 5, 0xea, /* tx 8 bits, assert DTR & RTS */ + 4, 0x46, /* x16 clock, 1 stop */ + 3, 0xc1, /* rx enable, 8 bits */ +}; + +void +xmon_init_scc(void) +{ + if ( _machine == _MACH_chrp ) + { + sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ + sccd[0] = 12; eieio(); /* DLL = 9600 baud */ + sccd[1] = 0; eieio(); + sccd[2] = 0; eieio(); /* FCR = 0 */ + sccd[3] = 3; eieio(); /* LCR = 8N1 */ + sccd[1] = 0; eieio(); /* IER = 0 */ + } + else if ( _machine == _MACH_Pmac ) + { + int i, x; + + if (channel_node != 0) + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + channel_node, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + printk(KERN_INFO "Serial port locked ON by debugger !\n"); + if (via_modem && channel_node != 0) { + unsigned int t0; + + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + channel_node, 0, 1); + printk(KERN_INFO "Modem powered up by debugger !\n"); + t0 = readtb(); + while (readtb() - t0 < 3*TB_SPEED) + eieio(); + } + /* use the B channel if requested */ + if (xmon_use_sccb) { + sccc = (volatile unsigned char *) + ((unsigned long)sccc & ~0x20); + sccd = sccc + 0x10; + } + for (i = 20000; i != 0; --i) { + x = *sccc; eieio(); + } + *sccc = 9; eieio(); /* reset A or B side */ + *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio(); + for (i = 0; i < sizeof(scc_inittab); ++i) { + *sccc = scc_inittab[i]; + eieio(); + } + } + scc_initialized = 1; + if (via_modem) { + for (;;) { + xmon_write(NULL, "ATE1V1\r", 7); + if (xmon_expect("OK", 5)) { + xmon_write(NULL, "ATA\r", 4); + if (xmon_expect("CONNECT", 40)) + break; + } + xmon_write(NULL, "+++", 3); + xmon_expect("OK", 3); + } + } +} + +void *xmon_stdin; +void *xmon_stdout; +void *xmon_stderr; + +int xmon_putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + xmon_putc('\r', f); + return xmon_write(f, &ch, 1) == 1? c: -1; +} + +int xmon_putchar(int c) +{ + return xmon_putc(c, xmon_stdout); +} + +int xmon_fputs(char *str, void *f) +{ + int n = strlen(str); + + return xmon_write(f, str, n) == n? 0: -1; +} + +int +xmon_readchar(void) +{ + char ch; + + for (;;) { + switch (xmon_read(xmon_stdin, &ch, 1)) { + case 1: + return ch; + case -1: + xmon_printf("read(stdin) returned -1\r\n", 0, 0); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int xmon_expect(const char *str, unsigned int timeout) +{ + int c; + unsigned int t0; + + timeout *= TB_SPEED; + t0 = readtb(); + do { + lineptr = line; + for (;;) { + c = xmon_read_poll(); + if (c == -1) { + if (readtb() - t0 > timeout) + return 0; + continue; + } + if (c == '\n') + break; + if (c != '\r' && lineptr < &line[sizeof(line) - 1]) + *lineptr++ = c; + } + *lineptr = 0; + } while (strstr(line, str) == NULL); + return 1; +} + +int +xmon_getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = xmon_readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + xmon_putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + xmon_putchar('\a'); + else { + xmon_putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +char * +xmon_fgets(char *str, int nb, void *f) +{ + char *p; + int c; + + for (p = str; p < str + nb - 1; ) { + c = xmon_getchar(); + if (c == -1) { + if (p == str) + return NULL; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = 0; + return str; +} + +void +xmon_enter(void) +{ +#ifdef CONFIG_ADB_PMU + if (_machine == _MACH_Pmac) { + pmu_suspend(); + } +#endif +} + +void +xmon_leave(void) +{ +#ifdef CONFIG_ADB_PMU + if (_machine == _MACH_Pmac) { + pmu_resume(); + } +#endif +} diff --git a/arch/ppc64/xmon/start.c b/arch/powerpc/xmon/start_64.c similarity index 100% rename from arch/ppc64/xmon/start.c rename to arch/powerpc/xmon/start_64.c diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c new file mode 100644 index 000000000000..a48bd594cf61 --- /dev/null +++ b/arch/powerpc/xmon/start_8xx.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * Copyright (C) 2000 Dan Malek. + * Quick hack of Paul's code to make XMON work on 8xx processors. Lots + * of assumptions, like the SMC1 is used, it has been initialized by the + * loader at some point, and we can just stuff and suck bytes. + * We rely upon the 8xx uart driver to support us, as the interface + * changes between boot up and operational phases of the kernel. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +extern void xmon_printf(const char *fmt, ...); +extern int xmon_8xx_write(char *str, int nb); +extern int xmon_8xx_read_poll(void); +extern int xmon_8xx_read_char(void); +void prom_drawhex(uint); +void prom_drawstring(const char *str); + +static int use_screen = 1; /* default */ + +#define TB_SPEED 25000000 + +static inline unsigned int readtb(void) +{ + unsigned int ret; + + asm volatile("mftb %0" : "=r" (ret) :); + return ret; +} + +void buf_access(void) +{ +} + +void +xmon_map_scc(void) +{ + + cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + use_screen = 0; + + prom_drawstring("xmon uses serial port\n"); +} + +static int scc_initialized = 0; + +void xmon_init_scc(void); + +int +xmon_write(void *handle, void *ptr, int nb) +{ + char *p = ptr; + int i, c, ct; + + if (!scc_initialized) + xmon_init_scc(); + + return(xmon_8xx_write(ptr, nb)); +} + +int xmon_wants_key; + +int +xmon_read(void *handle, void *ptr, int nb) +{ + char *p = ptr; + int i; + + if (!scc_initialized) + xmon_init_scc(); + + for (i = 0; i < nb; ++i) { + *p++ = xmon_8xx_read_char(); + } + return i; +} + +int +xmon_read_poll(void) +{ + return(xmon_8xx_read_poll()); +} + +void +xmon_init_scc() +{ + scc_initialized = 1; +} + +#if 0 +extern int (*prom_entry)(void *); + +int +xmon_exit(void) +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom_entry)(&args); + } +} +#endif + +void *xmon_stdin; +void *xmon_stdout; +void *xmon_stderr; + +void +xmon_init(void) +{ +} + +int +xmon_putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + xmon_putc('\r', f); + return xmon_write(f, &ch, 1) == 1? c: -1; +} + +int +xmon_putchar(int c) +{ + return xmon_putc(c, xmon_stdout); +} + +int +xmon_fputs(char *str, void *f) +{ + int n = strlen(str); + + return xmon_write(f, str, n) == n? 0: -1; +} + +int +xmon_readchar(void) +{ + char ch; + + for (;;) { + switch (xmon_read(xmon_stdin, &ch, 1)) { + case 1: + return ch; + case -1: + xmon_printf("read(stdin) returned -1\r\n", 0, 0); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +#if 0 +int xmon_expect(const char *str, unsigned int timeout) +{ + int c; + unsigned int t0; + + timeout *= TB_SPEED; + t0 = readtb(); + do { + lineptr = line; + for (;;) { + c = xmon_read_poll(); + if (c == -1) { + if (readtb() - t0 > timeout) + return 0; + continue; + } + if (c == '\n') + break; + if (c != '\r' && lineptr < &line[sizeof(line) - 1]) + *lineptr++ = c; + } + *lineptr = 0; + } while (strstr(line, str) == NULL); + return 1; +} +#endif + +int +xmon_getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = xmon_readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + xmon_putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + xmon_putchar('\a'); + else { + xmon_putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +char * +xmon_fgets(char *str, int nb, void *f) +{ + char *p; + int c; + + for (p = str; p < str + nb - 1; ) { + c = xmon_getchar(); + if (c == -1) { + if (p == str) + return 0; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = 0; + return str; +} + +void +prom_drawhex(uint val) +{ + unsigned char buf[10]; + + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789abcdef"[val & 0x0f]; + val >>= 4; + } + buf[8] = '\0'; + xmon_fputs(buf, xmon_stdout); +} + +void +prom_drawstring(const char *str) +{ + xmon_fputs(str, xmon_stdout); +} diff --git a/arch/ppc64/xmon/subr_prf.c b/arch/powerpc/xmon/subr_prf.c similarity index 84% rename from arch/ppc64/xmon/subr_prf.c rename to arch/powerpc/xmon/subr_prf.c index 5242bd7d0959..b48738c6dd33 100644 --- a/arch/ppc64/xmon/subr_prf.c +++ b/arch/powerpc/xmon/subr_prf.c @@ -18,13 +18,13 @@ #include #include +#include #include #include "nonstdio.h" extern int xmon_write(void *, void *, int); -void -xmon_vfprintf(void *f, const char *fmt, va_list ap) +void xmon_vfprintf(void *f, const char *fmt, va_list ap) { static char xmon_buf[2048]; int n; @@ -33,8 +33,7 @@ xmon_vfprintf(void *f, const char *fmt, va_list ap) xmon_write(f, xmon_buf, n); } -void -xmon_printf(const char *fmt, ...) +void xmon_printf(const char *fmt, ...) { va_list ap; @@ -42,9 +41,9 @@ xmon_printf(const char *fmt, ...) xmon_vfprintf(stdout, fmt, ap); va_end(ap); } +EXPORT_SYMBOL(xmon_printf); -void -xmon_fprintf(void *f, const char *fmt, ...) +void xmon_fprintf(void *f, const char *fmt, ...) { va_list ap; diff --git a/arch/ppc64/xmon/xmon.c b/arch/powerpc/xmon/xmon.c similarity index 90% rename from arch/ppc64/xmon/xmon.c rename to arch/powerpc/xmon/xmon.c index 74e63a886a69..d0623e0fd8ee 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -17,25 +17,31 @@ #include #include #include +#include #include #include #include #include +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif #include #include #include #include -#include -#include #include #include #include #include + +#ifdef CONFIG_PPC64 #include +#include +#endif #include "nonstdio.h" -#include "privinst.h" #define scanhex xmon_scanhex #define skipbl xmon_skipbl @@ -58,7 +64,7 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN (184/sizeof(long)) +#define JMP_BUF_LEN 23 static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; @@ -130,23 +136,36 @@ static void cacheflush(void); static int cpu_cmd(void); static void csum(void); static void bootcmds(void); +static void proccall(void); void dump_segments(void); static void symbol_lookup(void); static void xmon_print_symbol(unsigned long address, const char *mid, const char *after); static const char *getvecname(unsigned long vec); -static void debug_trace(void); - extern int print_insn_powerpc(unsigned long, unsigned long, int); extern void printf(const char *fmt, ...); extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); extern int xmon_putc(int c, void *f); extern int putchar(int ch); + +extern void xmon_enter(void); +extern void xmon_leave(void); + extern int xmon_read_poll(void); -extern int setjmp(long *); -extern void longjmp(long *, int); -extern unsigned long _ASR; +extern long setjmp(long *); +extern void longjmp(long *, long); +extern void xmon_save_regs(struct pt_regs *); + +#ifdef CONFIG_PPC64 +#define REG "%.16lx" +#define REGS_PER_LINE 4 +#define LAST_VOLATILE 13 +#else +#define REG "%.8lx" +#define REGS_PER_LINE 8 +#define LAST_VOLATILE 12 +#endif #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) @@ -186,47 +205,46 @@ Commands:\n\ ml locate a block of memory\n\ mz zero a block of memory\n\ mi show information about memory allocation\n\ - p show the task list\n\ + p call a procedure\n\ r print registers\n\ s single step\n\ S print special registers\n\ t print backtrace\n\ T Enable/Disable PPCDBG flags\n\ x exit monitor and recover\n\ - X exit monitor and dont recover\n\ - u dump segment table or SLB\n\ - ? help\n" - "\ - zr reboot\n\ + X exit monitor and dont recover\n" +#ifdef CONFIG_PPC64 +" u dump segment table or SLB\n" +#endif +#ifdef CONFIG_PPC_STD_MMU_32 +" u dump segment registers\n" +#endif +" ? help\n" +" zr reboot\n\ zh halt\n" ; static struct pt_regs *xmon_regs; -extern inline void sync(void) +static inline void sync(void) { asm volatile("sync; isync"); } -/* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs). - A PPC stack frame looks like this: +static inline void store_inst(void *p) +{ + asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); +} - High Address - Back Chain - FP reg save area - GP reg save area - Local var space - Parameter save area (SP+48) - TOC save area (SP+40) - link editor doubleword (SP+32) - compiler doubleword (SP+24) - LR save (SP+16) - CR save (SP+8) - Back Chain (SP+0) +static inline void cflush(void *p) +{ + asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); +} - Note that the LR (ret addr) may not be saved in the current frame if - no functions have been called from the current function. - */ +static inline void cinval(void *p) +{ + asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); +} /* * Disable surveillance (the service processor watchdog function) @@ -310,8 +328,8 @@ int xmon_core(struct pt_regs *regs, int fromipi) unsigned long timeout; #endif - msr = get_msr(); - set_msrd(msr & ~MSR_EE); /* disable interrupts */ + msr = mfmsr(); + mtmsr(msr & ~MSR_EE); /* disable interrupts */ bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { @@ -487,7 +505,7 @@ int xmon_core(struct pt_regs *regs, int fromipi) insert_cpu_bpts(); - set_msrd(msr); /* restore interrupt enable */ + mtmsr(msr); /* restore interrupt enable */ return cmd != 'X'; } @@ -497,56 +515,23 @@ int xmon(struct pt_regs *excp) struct pt_regs regs; if (excp == NULL) { - /* Ok, grab regs as they are now. - This won't do a particularily good job because the - prologue has already been executed. - ToDo: We could reach back into the callers save - area to do a better job of representing the - caller's state. - */ - asm volatile ("std 0,0(%0)\n\ - std 1,8(%0)\n\ - std 2,16(%0)\n\ - std 3,24(%0)\n\ - std 4,32(%0)\n\ - std 5,40(%0)\n\ - std 6,48(%0)\n\ - std 7,56(%0)\n\ - std 8,64(%0)\n\ - std 9,72(%0)\n\ - std 10,80(%0)\n\ - std 11,88(%0)\n\ - std 12,96(%0)\n\ - std 13,104(%0)\n\ - std 14,112(%0)\n\ - std 15,120(%0)\n\ - std 16,128(%0)\n\ - std 17,136(%0)\n\ - std 18,144(%0)\n\ - std 19,152(%0)\n\ - std 20,160(%0)\n\ - std 21,168(%0)\n\ - std 22,176(%0)\n\ - std 23,184(%0)\n\ - std 24,192(%0)\n\ - std 25,200(%0)\n\ - std 26,208(%0)\n\ - std 27,216(%0)\n\ - std 28,224(%0)\n\ - std 29,232(%0)\n\ - std 30,240(%0)\n\ - std 31,248(%0)" : : "b" (®s)); - - regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2]; - regs.msr = get_msr(); - regs.ctr = get_ctr(); - regs.xer = get_xer(); - regs.ccr = get_cr(); - regs.trap = 0; + xmon_save_regs(®s); excp = ®s; } return xmon_core(excp, 0); } +EXPORT_SYMBOL(xmon); + +irqreturn_t +xmon_irq(int irq, void *d, struct pt_regs *regs) +{ + unsigned long flags; + local_irq_save(flags); + printf("Keyboard interrupt\n"); + xmon(regs); + local_irq_restore(flags); + return IRQ_HANDLED; +} int xmon_bpt(struct pt_regs *regs) { @@ -718,7 +703,7 @@ static void insert_cpu_bpts(void) if (dabr.enabled) set_dabr(dabr.address | (dabr.enabled & 7)); if (iabr && cpu_has_feature(CPU_FTR_IABR)) - set_iabr(iabr->address + mtspr(SPRN_IABR, iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); } @@ -746,7 +731,7 @@ static void remove_cpu_bpts(void) { set_dabr(0); if (cpu_has_feature(CPU_FTR_IABR)) - set_iabr(0); + mtspr(SPRN_IABR, 0); } /* Command interpreting routine */ @@ -830,9 +815,6 @@ cmds(struct pt_regs *excp) case '?': printf(help_string); break; - case 'p': - show_state(); - break; case 'b': bpt_cmds(); break; @@ -846,12 +828,14 @@ cmds(struct pt_regs *excp) case 'z': bootcmds(); break; - case 'T': - debug_trace(); + case 'p': + proccall(); break; +#ifdef CONFIG_PPC_STD_MMU case 'u': dump_segments(); break; +#endif default: printf("Unrecognized command: "); do { @@ -1070,6 +1054,7 @@ bpt_cmds(void) cmd = inchar(); switch (cmd) { +#ifndef CONFIG_8xx case 'd': /* bd - hardware data breakpoint */ mode = 7; cmd = inchar(); @@ -1111,6 +1096,7 @@ bpt_cmds(void) iabr = bp; } break; +#endif case 'c': if (!scanhex(&a)) { @@ -1152,7 +1138,7 @@ bpt_cmds(void) /* print all breakpoints */ printf(" type address\n"); if (dabr.enabled) { - printf(" data %.16lx [", dabr.address); + printf(" data "REG" [", dabr.address); if (dabr.enabled & 1) printf("r"); if (dabr.enabled & 2) @@ -1231,6 +1217,18 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp, static int xmon_depth_to_print = 64; +#ifdef CONFIG_PPC64 +#define LRSAVE_OFFSET 0x10 +#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */ +#define MARKER_OFFSET 0x60 +#define REGS_OFFSET 0x70 +#else +#define LRSAVE_OFFSET 4 +#define REG_FRAME_MARKER 0x72656773 +#define MARKER_OFFSET 8 +#define REGS_OFFSET 16 +#endif + static void xmon_show_stack(unsigned long sp, unsigned long lr, unsigned long pc) { @@ -1247,7 +1245,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, break; } - if (!mread(sp + 16, &ip, sizeof(unsigned long)) + if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long)) || !mread(sp, &newsp, sizeof(unsigned long))) { printf("Couldn't read stack frame at %lx\n", sp); break; @@ -1266,7 +1264,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, get_function_bounds(pc, &fnstart, &fnend); nextip = 0; if (newsp > sp) - mread(newsp + 16, &nextip, + mread(newsp + LRSAVE_OFFSET, &nextip, sizeof(unsigned long)); if (lr == ip) { if (lr < PAGE_OFFSET @@ -1280,24 +1278,24 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, xmon_print_symbol(lr, " ", "\n"); } if (printip) { - printf("[%.16lx] ", sp); + printf("["REG"] ", sp); xmon_print_symbol(ip, " ", " (unreliable)\n"); } pc = lr = 0; } else { - printf("[%.16lx] ", sp); + printf("["REG"] ", sp); xmon_print_symbol(ip, " ", "\n"); } /* Look for "regshere" marker to see if this is an exception frame. */ - if (mread(sp + 0x60, &marker, sizeof(unsigned long)) - && marker == 0x7265677368657265ul) { - if (mread(sp + 0x70, ®s, sizeof(regs)) + if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long)) + && marker == REG_FRAME_MARKER) { + if (mread(sp + REGS_OFFSET, ®s, sizeof(regs)) != sizeof(regs)) { printf("Couldn't read registers at %lx\n", - sp + 0x70); + sp + REGS_OFFSET); break; } printf("--- Exception: %lx %s at ", regs.trap, @@ -1371,7 +1369,9 @@ void excprint(struct pt_regs *fp) } printf(" current = 0x%lx\n", current); +#ifdef CONFIG_PPC64 printf(" paca = 0x%lx\n", get_paca()); +#endif if (current) { printf(" pid = %ld, comm = %s\n", current->pid, current->comm); @@ -1383,7 +1383,7 @@ void excprint(struct pt_regs *fp) void prregs(struct pt_regs *fp) { - int n; + int n, trap; unsigned long base; struct pt_regs regs; @@ -1396,7 +1396,7 @@ void prregs(struct pt_regs *fp) __delay(200); } else { catch_memory_errors = 0; - printf("*** Error reading registers from %.16lx\n", + printf("*** Error reading registers from "REG"\n", base); return; } @@ -1404,22 +1404,36 @@ void prregs(struct pt_regs *fp) fp = ®s; } +#ifdef CONFIG_PPC64 if (FULL_REGS(fp)) { for (n = 0; n < 16; ++n) - printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", + printf("R%.2ld = "REG" R%.2ld = "REG"\n", n, fp->gpr[n], n+16, fp->gpr[n+16]); } else { for (n = 0; n < 7; ++n) - printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", + printf("R%.2ld = "REG" R%.2ld = "REG"\n", n, fp->gpr[n], n+7, fp->gpr[n+7]); } +#else + for (n = 0; n < 32; ++n) { + printf("R%.2d = %.8x%s", n, fp->gpr[n], + (n & 3) == 3? "\n": " "); + if (n == 12 && !FULL_REGS(fp)) { + printf("\n"); + break; + } + } +#endif printf("pc = "); xmon_print_symbol(fp->nip, " ", "\n"); printf("lr = "); xmon_print_symbol(fp->link, " ", "\n"); - printf("msr = %.16lx cr = %.8lx\n", fp->msr, fp->ccr); - printf("ctr = %.16lx xer = %.16lx trap = %8lx\n", + printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr); + printf("ctr = "REG" xer = "REG" trap = %4lx\n", fp->ctr, fp->xer, fp->trap); + trap = TRAP(fp); + if (trap == 0x300 || trap == 0x380 || trap == 0x600) + printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr); } void cacheflush(void) @@ -1519,8 +1533,7 @@ static unsigned long regno; extern char exc_prolog; extern char dec_exc; -void -super_regs(void) +void super_regs(void) { int cmd; unsigned long val; @@ -1536,12 +1549,14 @@ super_regs(void) asm("mr %0,1" : "=r" (sp) :); asm("mr %0,2" : "=r" (toc) :); - printf("msr = %.16lx sprg0= %.16lx\n", get_msr(), get_sprg0()); - printf("pvr = %.16lx sprg1= %.16lx\n", get_pvr(), get_sprg1()); - printf("dec = %.16lx sprg2= %.16lx\n", get_dec(), get_sprg2()); - printf("sp = %.16lx sprg3= %.16lx\n", sp, get_sprg3()); - printf("toc = %.16lx dar = %.16lx\n", toc, get_dar()); - printf("srr0 = %.16lx srr1 = %.16lx\n", get_srr0(), get_srr1()); + printf("msr = "REG" sprg0= "REG"\n", + mfmsr(), mfspr(SPRN_SPRG0)); + printf("pvr = "REG" sprg1= "REG"\n", + mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); + printf("dec = "REG" sprg2= "REG"\n", + mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); + printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); + printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); #ifdef CONFIG_PPC_ISERIES // Dump out relevant Paca data areas. printf("Paca: \n"); @@ -1578,11 +1593,6 @@ super_regs(void) case 'r': printf("spr %lx = %lx\n", regno, read_spr(regno)); break; - case 'm': - val = get_msr(); - scanhex(&val); - set_msrd(val); - break; } scannl(); } @@ -1604,13 +1614,13 @@ mread(unsigned long adrs, void *buf, int size) q = (char *)buf; switch (size) { case 2: - *(short *)q = *(short *)p; + *(u16 *)q = *(u16 *)p; break; case 4: - *(int *)q = *(int *)p; + *(u32 *)q = *(u32 *)p; break; case 8: - *(long *)q = *(long *)p; + *(u64 *)q = *(u64 *)p; break; default: for( ; n < size; ++n) { @@ -1641,13 +1651,13 @@ mwrite(unsigned long adrs, void *buf, int size) q = (char *) buf; switch (size) { case 2: - *(short *)p = *(short *)q; + *(u16 *)p = *(u16 *)q; break; case 4: - *(int *)p = *(int *)q; + *(u32 *)p = *(u32 *)q; break; case 8: - *(long *)p = *(long *)q; + *(u64 *)p = *(u64 *)q; break; default: for ( ; n < size; ++n) { @@ -1667,11 +1677,12 @@ mwrite(unsigned long adrs, void *buf, int size) } static int fault_type; +static int fault_except; static char *fault_chars[] = { "--", "**", "##" }; -static int -handle_fault(struct pt_regs *regs) +static int handle_fault(struct pt_regs *regs) { + fault_except = TRAP(regs); switch (TRAP(regs)) { case 0x200: fault_type = 0; @@ -1960,7 +1971,7 @@ prdump(unsigned long adrs, long ndump) unsigned char temp[16]; for (n = ndump; n > 0;) { - printf("%.16lx", adrs); + printf(REG, adrs); putchar(' '); r = n < 16? n: 16; nr = mread(adrs, temp, r); @@ -2008,7 +2019,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr) if (nr == 0) { if (praddr) { const char *x = fault_chars[fault_type]; - printf("%.16lx %s%s%s%s\n", adr, x, x, x, x); + printf(REG" %s%s%s%s\n", adr, x, x, x, x); } break; } @@ -2023,7 +2034,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr) dotted = 0; last_inst = inst; if (praddr) - printf("%.16lx %.8x", adr, inst); + printf(REG" %.8x", adr, inst); printf("\t"); print_insn_powerpc(inst, adr, 0); /* always returns 4 */ printf("\n"); @@ -2152,6 +2163,42 @@ memzcan(void) printf("%.8x\n", a - mskip); } +void proccall(void) +{ + unsigned long args[8]; + unsigned long ret; + int i; + typedef unsigned long (*callfunc_t)(unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long); + callfunc_t func; + + if (!scanhex(&adrs)) + return; + if (termch != '\n') + termch = 0; + for (i = 0; i < 8; ++i) + args[i] = 0; + for (i = 0; i < 8; ++i) { + if (!scanhex(&args[i]) || termch == '\n') + break; + termch = 0; + } + func = (callfunc_t) adrs; + ret = 0; + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + ret = func(args[0], args[1], args[2], args[3], + args[4], args[5], args[6], args[7]); + sync(); + printf("return value is %x\n", ret); + } else { + printf("*** %x exception occurred\n", fault_except); + } + catch_memory_errors = 0; +} + /* Input scanning routines */ int skipbl(void) @@ -2174,7 +2221,12 @@ static char *regnames[N_PTREGS] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", - "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "softe", + "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", +#ifdef CONFIG_PPC64 + "softe", +#else + "mq", +#endif "trap", "dar", "dsisr", "res" }; @@ -2280,8 +2332,7 @@ scannl(void) c = inchar(); } -int -hexdigit(int c) +int hexdigit(int c) { if( '0' <= c && c <= '9' ) return c - '0'; @@ -2378,7 +2429,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid, const char *name = NULL; unsigned long offset, size; - printf("%.16lx", address); + printf(REG, address); if (setjmp(bus_error_jmp) == 0) { catch_memory_errors = 1; sync(); @@ -2399,55 +2450,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid, printf("%s", after); } -static void debug_trace(void) -{ - unsigned long val, cmd, on; - - cmd = skipbl(); - if (cmd == '\n') { - /* show current state */ - unsigned long i; - printf("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); - for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) { - on = PPCDBG_BITVAL(i) & ppc64_debug_switch; - printf("%02x %s %12s ", i, on ? "on " : "off", trace_names[i] ? trace_names[i] : ""); - if (((i+1) % 3) == 0) - printf("\n"); - } - printf("\n"); - return; - } - while (cmd != '\n') { - on = 1; /* default if no sign given */ - while (cmd == '+' || cmd == '-') { - on = (cmd == '+'); - cmd = inchar(); - if (cmd == ' ' || cmd == '\n') { /* Turn on or off based on + or - */ - ppc64_debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE; - printf("Setting all values to %s...\n", on ? "on" : "off"); - if (cmd == '\n') return; - else cmd = skipbl(); - } - else - termch = cmd; - } - termch = cmd; /* not +/- ... let scanhex see it */ - scanhex((void *)&val); - if (val >= 64) { - printf("Value %x out of range:\n", val); - return; - } - if (on) { - ppc64_debug_switch |= PPCDBG_BITVAL(val); - printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); - } else { - ppc64_debug_switch &= ~PPCDBG_BITVAL(val); - printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); - } - cmd = skipbl(); - } -} - +#ifdef CONFIG_PPC64 static void dump_slb(void) { int i; @@ -2484,6 +2487,27 @@ static void dump_stab(void) } } +void dump_segments(void) +{ + if (cpu_has_feature(CPU_FTR_SLB)) + dump_slb(); + else + dump_stab(); +} +#endif + +#ifdef CONFIG_PPC_STD_MMU_32 +void dump_segments(void) +{ + int i; + + printf("sr0-15 ="); + for (i = 0; i < 16; ++i) + printf(" %x", mfsrin(i)); + printf("\n"); +} +#endif + void xmon_init(int enable) { if (enable) { @@ -2504,11 +2528,3 @@ void xmon_init(int enable) __debugger_fault_handler = NULL; } } - -void dump_segments(void) -{ - if (cpu_has_feature(CPU_FTR_SLB)) - dump_slb(); - else - dump_stab(); -} diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 2a7af765bfb6..743f0dbdebf3 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -89,7 +89,7 @@ core-y += arch/powerpc/mm/ core-y += arch/powerpc/sysdev/ core-y += arch/powerpc/platforms/ core-y += arch/powerpc/lib/ -core-$(CONFIG_XMON) += arch/ppc64/xmon/ +core-$(CONFIG_XMON) += arch/powerpc/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ boot := arch/ppc64/boot diff --git a/arch/ppc64/xmon/Makefile b/arch/ppc64/xmon/Makefile deleted file mode 100644 index fb21a7088d3e..000000000000 --- a/arch/ppc64/xmon/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Makefile for xmon - -EXTRA_CFLAGS += -mno-minimal-toc - -obj-y := start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o diff --git a/arch/ppc64/xmon/setjmp.S b/arch/ppc64/xmon/setjmp.S deleted file mode 100644 index 30ee643d557c..000000000000 --- a/arch/ppc64/xmon/setjmp.S +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * - * 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. - * - * NOTE: assert(sizeof(buf) > 184) - */ -#include -#include - -_GLOBAL(xmon_setjmp) - mflr r0 - std r0,0(r3) - std r1,8(r3) - std r2,16(r3) - mfcr r0 - std r0,24(r3) - std r13,32(r3) - std r14,40(r3) - std r15,48(r3) - std r16,56(r3) - std r17,64(r3) - std r18,72(r3) - std r19,80(r3) - std r20,88(r3) - std r21,96(r3) - std r22,104(r3) - std r23,112(r3) - std r24,120(r3) - std r25,128(r3) - std r26,136(r3) - std r27,144(r3) - std r28,152(r3) - std r29,160(r3) - std r30,168(r3) - std r31,176(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - cmpdi r4,0 - bne 1f - li r4,1 -1: ld r13,32(r3) - ld r14,40(r3) - ld r15,48(r3) - ld r16,56(r3) - ld r17,64(r3) - ld r18,72(r3) - ld r19,80(r3) - ld r20,88(r3) - ld r21,96(r3) - ld r22,104(r3) - ld r23,112(r3) - ld r24,120(r3) - ld r25,128(r3) - ld r26,136(r3) - ld r27,144(r3) - ld r28,152(r3) - ld r29,160(r3) - ld r30,168(r3) - ld r31,176(r3) - ld r0,24(r3) - mtcrf 56,r0 - ld r0,0(r3) - ld r1,8(r3) - ld r2,16(r3) - mtlr r0 - mr r3,r4 - blr diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 470d7400ac59..f99f2af82ca5 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -188,6 +188,10 @@ GLUE(.,name): #define LDL ld #define STL std #define CMPI cmpdi +#define SZL 8 + +/* offsets for stack frame layout */ +#define LRSAVE 16 #else /* 32-bit */ #define LOADADDR(rn,name) \ @@ -203,6 +207,10 @@ GLUE(.,name): #define LDL lwz #define STL stw #define CMPI cmpwi +#define SZL 4 + +/* offsets for stack frame layout */ +#define LRSAVE 4 #endif diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index bfb45a4523d3..da848412f11b 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -546,6 +546,7 @@ #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ : : "r" (v)) #define mtmsrd(v) __mtmsrd((v), 0) +#define mtmsr(v) mtmsrd(v) #else #define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) #endif diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index ca5f33277e0c..43f7129984c7 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h @@ -4,7 +4,7 @@ struct pt_regs; -extern void xmon(struct pt_regs *excp); +extern int xmon(struct pt_regs *excp); extern void xmon_printf(const char *fmt, ...); extern void xmon_init(int); From c6b8fdad144bbb915d124ffd95011ad55730bf9f Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:05:16 +0100 Subject: [PATCH 0830/1939] [ARM] 3/4: Remove asm/hardware.h from Versatile and Integrator io.h Signed-off-by: Russell King --- drivers/mmc/mmci.c | 1 + drivers/serial/amba-pl010.c | 1 + drivers/serial/amba-pl011.c | 1 + drivers/video/amba-clcd.c | 1 + include/asm-arm/arch-integrator/hardware.h | 9 --------- include/asm-arm/arch-integrator/io.h | 10 ++++++++-- include/asm-arm/arch-versatile/io.h | 2 -- sound/arm/aaci.c | 1 + 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 91c74843dc0d..1e6bdba26756 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 679e678c7e6a..ddd0307fece2 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -50,6 +50,7 @@ #include #include +#include #include #include diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 1ff629c74750..938d185841c9 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -50,6 +50,7 @@ #include #include +#include #include #include #include diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 321dbe91dc14..cde6fd8eb390 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -22,6 +22,7 @@ #include #include +#include #include #include diff --git a/include/asm-arm/arch-integrator/hardware.h b/include/asm-arm/arch-integrator/hardware.h index be2716eeaa02..6f0947bc500d 100644 --- a/include/asm-arm/arch-integrator/hardware.h +++ b/include/asm-arm/arch-integrator/hardware.h @@ -33,15 +33,6 @@ #define IO_SIZE 0x0B000000 // How much? #define IO_START INTEGRATOR_HDR_BASE // PA of IO -/* - * Similar to above, but for PCI addresses (memory, IO, Config and the - * V3 chip itself). WARNING: this has to mirror definitions in platform.h - */ -#define PCI_MEMORY_VADDR 0xe8000000 -#define PCI_CONFIG_VADDR 0xec000000 -#define PCI_V3_VADDR 0xed000000 -#define PCI_IO_VADDR 0xee000000 - #define PCIO_BASE PCI_IO_VADDR #define PCIMEM_BASE PCI_MEMORY_VADDR diff --git a/include/asm-arm/arch-integrator/io.h b/include/asm-arm/arch-integrator/io.h index 1329a731160d..31f2deab51b0 100644 --- a/include/asm-arm/arch-integrator/io.h +++ b/include/asm-arm/arch-integrator/io.h @@ -20,10 +20,16 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#include - #define IO_SPACE_LIMIT 0xffff +/* + * WARNING: this has to mirror definitions in platform.h + */ +#define PCI_MEMORY_VADDR 0xe8000000 +#define PCI_CONFIG_VADDR 0xec000000 +#define PCI_V3_VADDR 0xed000000 +#define PCI_IO_VADDR 0xee000000 + #define __io(a) ((void __iomem *)(PCI_IO_VADDR + (a))) #define __mem_pci(a) (a) #define __mem_isa(a) ((a) + PCI_MEMORY_VADDR) diff --git a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h index c2eed7f04b78..47e904cf25c7 100644 --- a/include/asm-arm/arch-versatile/io.h +++ b/include/asm-arm/arch-versatile/io.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#include - #define IO_SPACE_LIMIT 0xffffffff static inline void __iomem *__io(unsigned long addr) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b2d5db20ec8c..559ead6367da 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -20,6 +20,7 @@ #include #include +#include #include #include From 674c04538284736c4a44224c78cb784b2c972f98 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:25:28 +0100 Subject: [PATCH 0831/1939] [ARM] 3/4: Remove asm/hardware.h from SA1100 io.h Signed-off-by: Russell King --- arch/arm/mm/ioremap.c | 1 + drivers/mtd/maps/sa1100-flash.c | 1 + include/asm-arm/arch-sa1100/hardware.h | 7 ------- include/asm-arm/arch-sa1100/io.h | 6 +++++- include/asm-arm/arch-sa1100/system.h | 1 + 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 7110e54182b1..6fb1258df1b5 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 8dcaa357b4bb..9133351ba483 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/include/asm-arm/arch-sa1100/hardware.h b/include/asm-arm/arch-sa1100/hardware.h index 19c3b1e186bb..28711aaa4968 100644 --- a/include/asm-arm/arch-sa1100/hardware.h +++ b/include/asm-arm/arch-sa1100/hardware.h @@ -21,13 +21,6 @@ #define UNCACHEABLE_ADDR 0xfa050000 -/* - * We requires absolute addresses i.e. (PCMCIA_IO_0_BASE + 0x3f8) for - * in*()/out*() macros to be usable for all cases. - */ -#define PCIO_BASE 0 - - /* * SA1100 internal I/O mappings * diff --git a/include/asm-arm/arch-sa1100/io.h b/include/asm-arm/arch-sa1100/io.h index 9c8f588f35db..9d4fe6cf205b 100644 --- a/include/asm-arm/arch-sa1100/io.h +++ b/include/asm-arm/arch-sa1100/io.h @@ -18,7 +18,11 @@ * We don't actually have real ISA nor PCI buses, but there is so many * drivers out there that might just work if we fake them... */ -#define __io(a) ((void __iomem *)(PCIO_BASE + (a))) +static inline void __iomem *__io(unsigned long addr) +{ + return (void __iomem *)addr; +} +#define __io(a) __io(a) #define __mem_pci(a) (a) #define __mem_isa(a) (a) diff --git a/include/asm-arm/arch-sa1100/system.h b/include/asm-arm/arch-sa1100/system.h index 6f52118ba1a4..0f0612f79b2b 100644 --- a/include/asm-arm/arch-sa1100/system.h +++ b/include/asm-arm/arch-sa1100/system.h @@ -4,6 +4,7 @@ * Copyright (c) 1999 Nicolas Pitre */ #include +#include static inline void arch_idle(void) { From f339ab3d6c59f8f898c165384aa2b6a0ae5d4c1c Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:29:43 +0100 Subject: [PATCH 0832/1939] [ARM] Fix sparse warnings Fix sparse warnings in arch/arm/kernel/module.c, arch/arm/mm/consistent.c, drivers/pcmcia/sa1111_generic.c, and platform support files. Signed-off-by: Russell King --- arch/arm/kernel/module.c | 1 + arch/arm/mm/consistent.c | 6 +++--- drivers/pcmcia/sa1111_generic.c | 2 +- include/asm-arm/mach/arch.h | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 1a85cfdad5ac..6055e1427ba3 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -11,6 +11,7 @@ */ #include #include +#include #include #include #include diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 26356ce4da54..0f32de977f5e 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -75,7 +75,7 @@ static struct vm_region consistent_head = { }; static struct vm_region * -vm_region_alloc(struct vm_region *head, size_t size, int gfp) +vm_region_alloc(struct vm_region *head, size_t size, unsigned int gfp) { unsigned long addr = head->vm_start, end = head->vm_end - size; unsigned long flags; @@ -133,8 +133,8 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad #endif static void * -__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, - pgprot_t prot) +__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, + unsigned int gfp, pgprot_t prot) { struct page *page; struct vm_region *c; diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index bb90a1448a53..81ded52c8959 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -122,7 +122,7 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) static int pcmcia_probe(struct sa1111_dev *dev) { - char *base; + void __iomem *base; if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index 4fa95084a8c0..7273c6fd95b5 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -48,10 +48,10 @@ struct machine_desc { * Set of macros to define architecture features. This is built into * a table by the linker. */ -#define MACHINE_START(_type,_name) \ -const struct machine_desc __mach_desc_##_type \ +#define MACHINE_START(_type,_name) \ +static const struct machine_desc __mach_desc_##_type \ __attribute__((__section__(".arch.info.init"))) = { \ - .nr = MACH_TYPE_##_type, \ + .nr = MACH_TYPE_##_type, \ .name = _name, #define MACHINE_END \ From 90072059d2963dec237ae0cf49831ef77ddb5739 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:48:37 +0100 Subject: [PATCH 0833/1939] [ARM] Re-jig bootmem initialisation Make ARM independent of the way bootmem operates internally. We now map each node as we initialise it, and place the bootmem bitmap inside each node, rather than all in the first node. Signed-off-by: Russell King --- arch/arm/mm/init.c | 508 +++++++++++++++++++++--------------------- arch/arm/mm/mm-armv.c | 110 +-------- 2 files changed, 256 insertions(+), 362 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index edffa47a4b2a..d1f1ec73500f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/init.c * - * Copyright (C) 1995-2002 Russell King + * Copyright (C) 1995-2005 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 @@ -86,14 +86,19 @@ void show_mem(void) printk("%d pages swap cached\n", cached); } -struct node_info { - unsigned int start; - unsigned int end; - int bootmap_pages; -}; +static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) +{ + return pmd_offset(pgd, virt); +} -#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) +static inline pmd_t *pmd_off_k(unsigned long virt) +{ + return pmd_off(pgd_offset_k(virt), virt); +} + +#define for_each_nodebank(iter,mi,no) \ + for (iter = 0; iter < mi->nr_banks; iter++) \ + if (mi->bank[iter].node == no) /* * FIXME: We really want to avoid allocating the bootmap bitmap @@ -106,15 +111,12 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) { unsigned int start_pfn, bank, bootmap_pfn; - start_pfn = O_PFN_UP(__pa(&_end)); + start_pfn = PAGE_ALIGN(__pa(&_end)) >> PAGE_SHIFT; bootmap_pfn = 0; - for (bank = 0; bank < mi->nr_banks; bank ++) { + for_each_nodebank(bank, mi, node) { unsigned int start, end; - if (mi->bank[bank].node != node) - continue; - start = mi->bank[bank].start >> PAGE_SHIFT; end = (mi->bank[bank].size + mi->bank[bank].start) >> PAGE_SHIFT; @@ -140,92 +142,6 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) return bootmap_pfn; } -/* - * Scan the memory info structure and pull out: - * - the end of memory - * - the number of nodes - * - the pfn range of each node - * - the number of bootmem bitmap pages - */ -static unsigned int __init -find_memend_and_nodes(struct meminfo *mi, struct node_info *np) -{ - unsigned int i, bootmem_pages = 0, memend_pfn = 0; - - for (i = 0; i < MAX_NUMNODES; i++) { - np[i].start = -1U; - np[i].end = 0; - np[i].bootmap_pages = 0; - } - - for (i = 0; i < mi->nr_banks; i++) { - unsigned long start, end; - int node; - - if (mi->bank[i].size == 0) { - /* - * Mark this bank with an invalid node number - */ - mi->bank[i].node = -1; - continue; - } - - node = mi->bank[i].node; - - /* - * Make sure we haven't exceeded the maximum number of nodes - * that we have in this configuration. If we have, we're in - * trouble. (maybe we ought to limit, instead of bugging?) - */ - if (node >= MAX_NUMNODES) - BUG(); - node_set_online(node); - - /* - * Get the start and end pfns for this bank - */ - start = mi->bank[i].start >> PAGE_SHIFT; - end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT; - - if (np[node].start > start) - np[node].start = start; - - if (np[node].end < end) - np[node].end = end; - - if (memend_pfn < end) - memend_pfn = end; - } - - /* - * Calculate the number of pages we require to - * store the bootmem bitmaps. - */ - for_each_online_node(i) { - if (np[i].end == 0) - continue; - - np[i].bootmap_pages = bootmem_bootmap_pages(np[i].end - - np[i].start); - bootmem_pages += np[i].bootmap_pages; - } - - high_memory = __va(memend_pfn << PAGE_SHIFT); - - /* - * This doesn't seem to be used by the Linux memory - * manager any more. If we can get rid of it, we - * also get rid of some of the stuff above as well. - * - * Note: max_low_pfn and max_pfn reflect the number - * of _pages_ in the system, not the maximum PFN. - */ - max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET); - max_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET); - - return bootmem_pages; -} - static int __init check_initrd(struct meminfo *mi) { int initrd_node = -2; @@ -266,9 +182,8 @@ static int __init check_initrd(struct meminfo *mi) /* * Reserve the various regions of node 0 */ -static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages) +static __init void reserve_node_zero(pg_data_t *pgdat) { - pg_data_t *pgdat = NODE_DATA(0); unsigned long res_size = 0; /* @@ -288,13 +203,6 @@ static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot reserve_bootmem_node(pgdat, __pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); - /* - * And don't forget to reserve the allocator bitmap, - * which will be freed later. - */ - reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT, - bootmap_pages << PAGE_SHIFT); - /* * Hmm... This should go elsewhere, but we really really need to * stop things allocating the low memory; ideally we need a better @@ -324,93 +232,256 @@ static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size); } -/* - * Register all available RAM in this node with the bootmem allocator. - */ -static inline void free_bootmem_node_bank(int node, struct meminfo *mi) +void __init build_mem_type_table(void); +void __init create_mapping(struct map_desc *md); + +static unsigned long __init +bootmem_init_node(int node, int initrd_node, struct meminfo *mi) { - pg_data_t *pgdat = NODE_DATA(node); - int bank; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; + unsigned long start_pfn, end_pfn, boot_pfn; + unsigned int boot_pages; + pg_data_t *pgdat; + int i; - for (bank = 0; bank < mi->nr_banks; bank++) - if (mi->bank[bank].node == node) - free_bootmem_node(pgdat, mi->bank[bank].start, - mi->bank[bank].size); -} - -/* - * Initialise the bootmem allocator for all nodes. This is called - * early during the architecture specific initialisation. - */ -static void __init bootmem_init(struct meminfo *mi) -{ - struct node_info node_info[MAX_NUMNODES], *np = node_info; - unsigned int bootmap_pages, bootmap_pfn, map_pg; - int node, initrd_node; - - bootmap_pages = find_memend_and_nodes(mi, np); - bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages); - initrd_node = check_initrd(mi); - - map_pg = bootmap_pfn; + start_pfn = -1UL; + end_pfn = 0; /* - * Initialise the bootmem nodes. - * - * What we really want to do is: - * - * unmap_all_regions_except_kernel(); - * for_each_node_in_reverse_order(node) { - * map_node(node); - * allocate_bootmem_map(node); - * init_bootmem_node(node); - * free_bootmem_node(node); - * } - * - * but this is a 2.5-type change. For now, we just set - * the nodes up in reverse order. - * - * (we could also do with rolling bootmem_init and paging_init - * into one generic "memory_init" type function). + * Calculate the pfn range, and map the memory banks for this node. */ - np += num_online_nodes() - 1; - for (node = num_online_nodes() - 1; node >= 0; node--, np--) { - /* - * If there are no pages in this node, ignore it. - * Note that node 0 must always have some pages. - */ - if (np->end == 0 || !node_online(node)) { - if (node == 0) - BUG(); - continue; - } + for_each_nodebank(i, mi, node) { + unsigned long start, end; + struct map_desc map; - /* - * Initialise the bootmem allocator. - */ - init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end); - free_bootmem_node_bank(node, mi); - map_pg += np->bootmap_pages; + start = mi->bank[i].start >> PAGE_SHIFT; + end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT; - /* - * If this is node 0, we need to reserve some areas ASAP - - * we may use bootmem on node 0 to setup the other nodes. - */ - if (node == 0) - reserve_node_zero(bootmap_pfn, bootmap_pages); + if (start_pfn > start) + start_pfn = start; + if (end_pfn < end) + end_pfn = end; + + map.physical = mi->bank[i].start; + map.virtual = __phys_to_virt(map.physical); + map.length = mi->bank[i].size; + map.type = MT_MEMORY; + + create_mapping(&map); } + /* + * If there is no memory in this node, ignore it. + */ + if (end_pfn == 0) + return end_pfn; + + /* + * Allocate the bootmem bitmap page. + */ + boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); + boot_pfn = find_bootmap_pfn(node, mi, boot_pages); + + /* + * Initialise the bootmem allocator for this node, handing the + * memory banks over to bootmem. + */ + node_set_online(node); + pgdat = NODE_DATA(node); + init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn); + + for_each_nodebank(i, mi, node) + free_bootmem_node(pgdat, mi->bank[i].start, mi->bank[i].size); + + /* + * Reserve the bootmem bitmap for this node. + */ + reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, + boot_pages << PAGE_SHIFT); #ifdef CONFIG_BLK_DEV_INITRD - if (phys_initrd_size && initrd_node >= 0) { - reserve_bootmem_node(NODE_DATA(initrd_node), phys_initrd_start, + /* + * If the initrd is in this node, reserve its memory. + */ + if (node == initrd_node) { + reserve_bootmem_node(pgdat, phys_initrd_start, phys_initrd_size); initrd_start = __phys_to_virt(phys_initrd_start); initrd_end = initrd_start + phys_initrd_size; } #endif - BUG_ON(map_pg != bootmap_pfn + bootmap_pages); + /* + * Finally, reserve any node zero regions. + */ + if (node == 0) + reserve_node_zero(pgdat); + + /* + * initialise the zones within this node. + */ + memset(zone_size, 0, sizeof(zone_size)); + memset(zhole_size, 0, sizeof(zhole_size)); + + /* + * The size of this node has already been determined. If we need + * to do anything fancy with the allocation of this memory to the + * zones, now is the time to do it. + */ + zone_size[0] = end_pfn - start_pfn; + + /* + * For each bank in this node, calculate the size of the holes. + * holes = node_size - sum(bank_sizes_in_node) + */ + zhole_size[0] = zone_size[0]; + for_each_nodebank(i, mi, node) + zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT; + + /* + * Adjust the sizes according to any special requirements for + * this machine type. + */ + arch_adjust_zones(node, zone_size, zhole_size); + + free_area_init_node(node, pgdat, zone_size, start_pfn, zhole_size); + + return end_pfn; +} + +static void __init bootmem_init(struct meminfo *mi) +{ + unsigned long addr, memend_pfn = 0; + int node, initrd_node, i; + + /* + * Invalidate the node number for empty or invalid memory banks + */ + for (i = 0; i < mi->nr_banks; i++) + if (mi->bank[i].size == 0 || mi->bank[i].node >= MAX_NUMNODES) + mi->bank[i].node = -1; + + memcpy(&meminfo, mi, sizeof(meminfo)); + +#ifdef CONFIG_XIP_KERNEL +#error needs fixing + p->physical = CONFIG_XIP_PHYS_ADDR & PMD_MASK; + p->virtual = (unsigned long)&_stext & PMD_MASK; + p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK; + p->type = MT_ROM; + p ++; +#endif + + /* + * Clear out all the mappings below the kernel image. + * FIXME: what about XIP? + */ + for (addr = 0; addr < PAGE_OFFSET; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + + /* + * Clear out all the kernel space mappings, except for the first + * memory bank, up to the end of the vmalloc region. + */ + for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size); + addr < VMALLOC_END; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + + /* + * Locate which node contains the ramdisk image, if any. + */ + initrd_node = check_initrd(mi); + + /* + * Run through each node initialising the bootmem allocator. + */ + for_each_node(node) { + unsigned long end_pfn; + + end_pfn = bootmem_init_node(node, initrd_node, mi); + + /* + * Remember the highest memory PFN. + */ + if (end_pfn > memend_pfn) + memend_pfn = end_pfn; + } + + high_memory = __va(memend_pfn << PAGE_SHIFT); + + /* + * This doesn't seem to be used by the Linux memory manager any + * more, but is used by ll_rw_block. If we can get rid of it, we + * also get rid of some of the stuff above as well. + * + * Note: max_low_pfn and max_pfn reflect the number of _pages_ in + * the system, not the maximum PFN. + */ + max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET; +} + +/* + * Set up device the mappings. Since we clear out the page tables for all + * mappings above VMALLOC_END, we will remove any debug device mappings. + * This means you have to be careful how you debug this function, or any + * called function. (Do it by code inspection!) + */ +static void __init devicemaps_init(struct machine_desc *mdesc) +{ + struct map_desc map; + unsigned long addr; + void *vectors; + + for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + + /* + * Map the cache flushing regions. + */ +#ifdef FLUSH_BASE + map.physical = FLUSH_BASE_PHYS; + map.virtual = FLUSH_BASE; + map.length = PGDIR_SIZE; + map.type = MT_CACHECLEAN; + create_mapping(&map); +#endif +#ifdef FLUSH_BASE_MINICACHE + map.physical = FLUSH_BASE_PHYS + PGDIR_SIZE; + map.virtual = FLUSH_BASE_MINICACHE; + map.length = PGDIR_SIZE; + map.type = MT_MINICLEAN; + create_mapping(&map); +#endif + + flush_cache_all(); + local_flush_tlb_all(); + + vectors = alloc_bootmem_low_pages(PAGE_SIZE); + BUG_ON(!vectors); + + /* + * Create a mapping for the machine vectors at the high-vectors + * location (0xffff0000). If we aren't using high-vectors, also + * create a mapping at the low-vectors virtual address. + */ + map.physical = virt_to_phys(vectors); + map.virtual = 0xffff0000; + map.length = PAGE_SIZE; + map.type = MT_HIGH_VECTORS; + create_mapping(&map); + + if (!vectors_high()) { + map.virtual = 0; + map.type = MT_LOW_VECTORS; + create_mapping(&map); + } + + /* + * Ask the machine support to map in the statically mapped devices. + * After this point, we can start to touch devices again. + */ + if (mdesc->map_io) + mdesc->map_io(); } /* @@ -420,87 +491,17 @@ static void __init bootmem_init(struct meminfo *mi) void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) { void *zero_page; - int node; + build_mem_type_table(); bootmem_init(mi); + devicemaps_init(mdesc); - memcpy(&meminfo, mi, sizeof(meminfo)); + top_pmd = pmd_off_k(0xffff0000); /* * allocate the zero page. Note that we count on this going ok. */ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); - - /* - * initialise the page tables. - */ - memtable_init(mi); - if (mdesc->map_io) - mdesc->map_io(); - local_flush_tlb_all(); - - /* - * initialise the zones within each node - */ - for_each_online_node(node) { - unsigned long zone_size[MAX_NR_ZONES]; - unsigned long zhole_size[MAX_NR_ZONES]; - struct bootmem_data *bdata; - pg_data_t *pgdat; - int i; - - /* - * Initialise the zone size information. - */ - for (i = 0; i < MAX_NR_ZONES; i++) { - zone_size[i] = 0; - zhole_size[i] = 0; - } - - pgdat = NODE_DATA(node); - bdata = pgdat->bdata; - - /* - * The size of this node has already been determined. - * If we need to do anything fancy with the allocation - * of this memory to the zones, now is the time to do - * it. - */ - zone_size[0] = bdata->node_low_pfn - - (bdata->node_boot_start >> PAGE_SHIFT); - - /* - * If this zone has zero size, skip it. - */ - if (!zone_size[0]) - continue; - - /* - * For each bank in this node, calculate the size of the - * holes. holes = node_size - sum(bank_sizes_in_node) - */ - zhole_size[0] = zone_size[0]; - for (i = 0; i < mi->nr_banks; i++) { - if (mi->bank[i].node != node) - continue; - - zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT; - } - - /* - * Adjust the sizes according to any special - * requirements for this machine type. - */ - arch_adjust_zones(node, zone_size, zhole_size); - - free_area_init_node(node, pgdat, zone_size, - bdata->node_boot_start >> PAGE_SHIFT, zhole_size); - } - - /* - * finish off the bad pages once - * the mem_map is initialised - */ memzero(zero_page, PAGE_SIZE); empty_zero_page = virt_to_page(zero_page); flush_dcache_page(empty_zero_page); @@ -562,10 +563,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi) * may not be the case, especially if the user has provided the * information on the command line. */ - for (i = 0; i < mi->nr_banks; i++) { - if (mi->bank[i].size == 0 || mi->bank[i].node != node) - continue; - + for_each_nodebank(i, mi, node) { bank_start = mi->bank[i].start >> PAGE_SHIFT; if (bank_start < prev_bank_end) { printk(KERN_ERR "MEM: unordered memory banks. " diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index d125a3dc061c..c626361c0f5e 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/mm-armv.c * - * Copyright (C) 1998-2002 Russell King + * Copyright (C) 1998-2005 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 @@ -305,16 +305,6 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); } -/* - * Clear any PGD mapping. On a two-level page table system, - * the clearance is done by the middle-level functions (pmd) - * rather than the top-level (pgd) functions. - */ -static inline void clear_mapping(unsigned long virt) -{ - pmd_clear(pmd_off_k(virt)); -} - struct mem_types { unsigned int prot_pte; unsigned int prot_l1; @@ -373,7 +363,7 @@ static struct mem_types mem_types[] __initdata = { /* * Adjust the PMD section entries according to the CPU in use. */ -static void __init build_mem_type_table(void) +void __init build_mem_type_table(void) { struct cachepolicy *cp; unsigned int cr = get_cr(); @@ -483,7 +473,7 @@ static void __init build_mem_type_table(void) * offsets, and we take full advantage of sections and * supersections. */ -static void __init create_mapping(struct map_desc *md) +void __init create_mapping(struct map_desc *md) { unsigned long virt, length; int prot_sect, prot_l1, domain; @@ -601,100 +591,6 @@ void setup_mm_for_reboot(char mode) } } -extern void _stext, _etext; - -/* - * Setup initial mappings. We use the page we allocated for zero page to hold - * the mappings, which will get overwritten by the vectors in traps_init(). - * The mappings must be in virtual address order. - */ -void __init memtable_init(struct meminfo *mi) -{ - struct map_desc *init_maps, *p, *q; - unsigned long address = 0; - int i; - - build_mem_type_table(); - - init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE); - -#ifdef CONFIG_XIP_KERNEL - p->physical = CONFIG_XIP_PHYS_ADDR & PMD_MASK; - p->virtual = (unsigned long)&_stext & PMD_MASK; - p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK; - p->type = MT_ROM; - p ++; -#endif - - for (i = 0; i < mi->nr_banks; i++) { - if (mi->bank[i].size == 0) - continue; - - p->physical = mi->bank[i].start; - p->virtual = __phys_to_virt(p->physical); - p->length = mi->bank[i].size; - p->type = MT_MEMORY; - p ++; - } - -#ifdef FLUSH_BASE - p->physical = FLUSH_BASE_PHYS; - p->virtual = FLUSH_BASE; - p->length = PGDIR_SIZE; - p->type = MT_CACHECLEAN; - p ++; -#endif - -#ifdef FLUSH_BASE_MINICACHE - p->physical = FLUSH_BASE_PHYS + PGDIR_SIZE; - p->virtual = FLUSH_BASE_MINICACHE; - p->length = PGDIR_SIZE; - p->type = MT_MINICLEAN; - p ++; -#endif - - /* - * Go through the initial mappings, but clear out any - * pgdir entries that are not in the description. - */ - q = init_maps; - do { - if (address < q->virtual || q == p) { - clear_mapping(address); - address += PGDIR_SIZE; - } else { - create_mapping(q); - - address = q->virtual + q->length; - address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; - - q ++; - } - } while (address != 0); - - /* - * Create a mapping for the machine vectors at the high-vectors - * location (0xffff0000). If we aren't using high-vectors, also - * create a mapping at the low-vectors virtual address. - */ - init_maps->physical = virt_to_phys(init_maps); - init_maps->virtual = 0xffff0000; - init_maps->length = PAGE_SIZE; - init_maps->type = MT_HIGH_VECTORS; - create_mapping(init_maps); - - if (!vectors_high()) { - init_maps->virtual = 0; - init_maps->type = MT_LOW_VECTORS; - create_mapping(init_maps); - } - - flush_cache_all(); - local_flush_tlb_all(); - - top_pmd = pmd_off_k(0xffff0000); -} - /* * Create the architecture specific mappings */ From b5893c56ca7e664aef010a71c2638db768d4e996 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:51:15 +0100 Subject: [PATCH 0834/1939] [ARM] 1/4 Move oprofile driver model code Signed-off-by: Russell King --- arch/arm/oprofile/common.c | 99 ++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index e57dde882898..5b1d752edbc3 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include "op_counter.h" #include "op_arm_model.h" @@ -20,57 +20,6 @@ static struct op_arm_model_spec *pmu_model; static int pmu_enabled; static struct semaphore pmu_sem; -static int pmu_start(void); -static int pmu_setup(void); -static void pmu_stop(void); -static int pmu_create_files(struct super_block *, struct dentry *); - -#ifdef CONFIG_PM -static int pmu_suspend(struct sys_device *dev, pm_message_t state) -{ - if (pmu_enabled) - pmu_stop(); - return 0; -} - -static int pmu_resume(struct sys_device *dev) -{ - if (pmu_enabled) - pmu_start(); - return 0; -} - -static struct sysdev_class oprofile_sysclass = { - set_kset_name("oprofile"), - .resume = pmu_resume, - .suspend = pmu_suspend, -}; - -static struct sys_device device_oprofile = { - .id = 0, - .cls = &oprofile_sysclass, -}; - -static int __init init_driverfs(void) -{ - int ret; - - if (!(ret = sysdev_class_register(&oprofile_sysclass))) - ret = sysdev_register(&device_oprofile); - - return ret; -} - -static void exit_driverfs(void) -{ - sysdev_unregister(&device_oprofile); - sysdev_class_unregister(&oprofile_sysclass); -} -#else -#define init_driverfs() do { } while (0) -#define exit_driverfs() do { } while (0) -#endif /* CONFIG_PM */ - struct op_counter_config counter_config[OP_MAX_COUNTER]; static int pmu_create_files(struct super_block *sb, struct dentry *root) @@ -126,6 +75,52 @@ static void pmu_stop(void) up(&pmu_sem); } +#ifdef CONFIG_PM +static int pmu_suspend(struct sys_device *dev, pm_message_t state) +{ + if (pmu_enabled) + pmu_stop(); + return 0; +} + +static int pmu_resume(struct sys_device *dev) +{ + if (pmu_enabled) + pmu_start(); + return 0; +} + +static struct sysdev_class oprofile_sysclass = { + set_kset_name("oprofile"), + .resume = pmu_resume, + .suspend = pmu_suspend, +}; + +static struct sys_device device_oprofile = { + .id = 0, + .cls = &oprofile_sysclass, +}; + +static int __init init_driverfs(void) +{ + int ret; + + if (!(ret = sysdev_class_register(&oprofile_sysclass))) + ret = sysdev_register(&device_oprofile); + + return ret; +} + +static void exit_driverfs(void) +{ + sysdev_unregister(&device_oprofile); + sysdev_class_unregister(&oprofile_sysclass); +} +#else +#define init_driverfs() do { } while (0) +#define exit_driverfs() do { } while (0) +#endif /* CONFIG_PM */ + int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) { init_MUTEX(&pmu_sem); From 7c5b3fc20807279d8f8e78f1e2ef275128668796 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:52:30 +0100 Subject: [PATCH 0835/1939] [ARM] 2/4 Fix oprofile suspend/resume The oprofile suspend/resume was missing locking. If we failed to start oprofile on resume, we still reported that it was enabled. Instead, disable oprofile on error. Signed-off-by: Russell King --- arch/arm/oprofile/common.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index 5b1d752edbc3..02e5d6f45166 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -78,15 +78,19 @@ static void pmu_stop(void) #ifdef CONFIG_PM static int pmu_suspend(struct sys_device *dev, pm_message_t state) { + down(&pmu_sem); if (pmu_enabled) - pmu_stop(); + pmu_model->stop(); + up(&pmu_sem); return 0; } static int pmu_resume(struct sys_device *dev) { - if (pmu_enabled) - pmu_start(); + down(&pmu_sem); + if (pmu_enabled && pmu_model->start()) + pmu_enabled = 0; + up(&pmu_sem); return 0; } From 55f052341ff75e5815b1f7f4d2d3b69314ea8712 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:54:21 +0100 Subject: [PATCH 0836/1939] [ARM] 3/4 Rename common oprofile code The common oprofile code assumes the name "PMU" (from Intel's performance management unit). This is misleading when we start adding oprofile support for other machine types which don't use the same terminology. Call it op_arm_* instead of pmu_*. Signed-off-by: Russell King --- arch/arm/oprofile/common.c | 88 ++++++++++++++++---------------- arch/arm/oprofile/init.c | 4 +- arch/arm/oprofile/op_arm_model.h | 4 +- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index 02e5d6f45166..7ce6dfa06c85 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -16,17 +16,17 @@ #include "op_counter.h" #include "op_arm_model.h" -static struct op_arm_model_spec *pmu_model; -static int pmu_enabled; -static struct semaphore pmu_sem; +static struct op_arm_model_spec *op_arm_model; +static int op_arm_enabled; +static struct semaphore op_arm_sem; struct op_counter_config counter_config[OP_MAX_COUNTER]; -static int pmu_create_files(struct super_block *sb, struct dentry *root) +static int op_arm_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; - for (i = 0; i < pmu_model->num_counters; i++) { + for (i = 0; i < op_arm_model->num_counters; i++) { struct dentry *dir; char buf[2]; @@ -43,61 +43,61 @@ static int pmu_create_files(struct super_block *sb, struct dentry *root) return 0; } -static int pmu_setup(void) +static int op_arm_setup(void) { int ret; spin_lock(&oprofilefs_lock); - ret = pmu_model->setup_ctrs(); + ret = op_arm_model->setup_ctrs(); spin_unlock(&oprofilefs_lock); return ret; } -static int pmu_start(void) +static int op_arm_start(void) { int ret = -EBUSY; - down(&pmu_sem); - if (!pmu_enabled) { - ret = pmu_model->start(); - pmu_enabled = !ret; + down(&op_arm_sem); + if (!op_arm_enabled) { + ret = op_arm_model->start(); + op_arm_enabled = !ret; } - up(&pmu_sem); + up(&op_arm_sem); return ret; } -static void pmu_stop(void) +static void op_arm_stop(void) { - down(&pmu_sem); - if (pmu_enabled) - pmu_model->stop(); - pmu_enabled = 0; - up(&pmu_sem); + down(&op_arm_sem); + if (op_arm_enabled) + op_arm_model->stop(); + op_arm_enabled = 0; + up(&op_arm_sem); } #ifdef CONFIG_PM -static int pmu_suspend(struct sys_device *dev, pm_message_t state) +static int op_arm_suspend(struct sys_device *dev, pm_message_t state) { - down(&pmu_sem); - if (pmu_enabled) - pmu_model->stop(); - up(&pmu_sem); + down(&op_arm_sem); + if (op_arm_enabled) + op_arm_model->stop(); + up(&op_arm_sem); return 0; } -static int pmu_resume(struct sys_device *dev) +static int op_arm_resume(struct sys_device *dev) { - down(&pmu_sem); - if (pmu_enabled && pmu_model->start()) - pmu_enabled = 0; - up(&pmu_sem); + down(&op_arm_sem); + if (op_arm_enabled && op_arm_model->start()) + op_arm_enabled = 0; + up(&op_arm_sem); return 0; } static struct sysdev_class oprofile_sysclass = { set_kset_name("oprofile"), - .resume = pmu_resume, - .suspend = pmu_suspend, + .resume = op_arm_resume, + .suspend = op_arm_suspend, }; static struct sys_device device_oprofile = { @@ -125,31 +125,31 @@ static void exit_driverfs(void) #define exit_driverfs() do { } while (0) #endif /* CONFIG_PM */ -int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) +int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) { - init_MUTEX(&pmu_sem); + init_MUTEX(&op_arm_sem); if (spec->init() < 0) return -ENODEV; - pmu_model = spec; + op_arm_model = spec; init_driverfs(); - ops->create_files = pmu_create_files; - ops->setup = pmu_setup; - ops->shutdown = pmu_stop; - ops->start = pmu_start; - ops->stop = pmu_stop; - ops->cpu_type = pmu_model->name; - printk(KERN_INFO "oprofile: using %s PMU\n", spec->name); + ops->create_files = op_arm_create_files; + ops->setup = op_arm_setup; + ops->shutdown = op_arm_stop; + ops->start = op_arm_start; + ops->stop = op_arm_stop; + ops->cpu_type = op_arm_model->name; + printk(KERN_INFO "oprofile: using %s\n", spec->name); return 0; } -void pmu_exit(void) +void op_arm_exit(void) { - if (pmu_model) { + if (op_arm_model) { exit_driverfs(); - pmu_model = NULL; + op_arm_model = NULL; } } diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c index d315a3a86c86..ccd8c54934a2 100644 --- a/arch/arm/oprofile/init.c +++ b/arch/arm/oprofile/init.c @@ -17,7 +17,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) int ret = -ENODEV; #ifdef CONFIG_CPU_XSCALE - ret = pmu_init(ops, &op_xscale_spec); + ret = op_arm_init(ops, &op_xscale_spec); #endif ops->backtrace = arm_backtrace; @@ -28,6 +28,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) void oprofile_arch_exit(void) { #ifdef CONFIG_CPU_XSCALE - pmu_exit(); + op_arm_exit(); #endif } diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h index 2148d07484b7..38c6ad158547 100644 --- a/arch/arm/oprofile/op_arm_model.h +++ b/arch/arm/oprofile/op_arm_model.h @@ -26,6 +26,6 @@ extern struct op_arm_model_spec op_xscale_spec; extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth); -extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); -extern void pmu_exit(void); +extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); +extern void op_arm_exit(void); #endif /* OP_ARM_MODEL_H */ From c6b9dafce3e3b434a3e7ffd5072815c03d18cc84 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 14:56:04 +0100 Subject: [PATCH 0837/1939] [ARM] 4/4 Combine oprofile common and init code There is nothing special about having the init code separate from the common code, so combine the two. Signed-off-by: Russell King --- arch/arm/oprofile/Makefile | 4 ++-- arch/arm/oprofile/common.c | 40 ++++++++++++++++++++++++-------------- arch/arm/oprofile/init.c | 33 ------------------------------- 3 files changed, 27 insertions(+), 50 deletions(-) delete mode 100644 arch/arm/oprofile/init.c diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile index 8ffb523e6c77..6a94e54848fd 100644 --- a/arch/arm/oprofile/Makefile +++ b/arch/arm/oprofile/Makefile @@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -oprofile-y := $(DRIVER_OBJS) init.o backtrace.o -oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o +oprofile-y := $(DRIVER_OBJS) common.o backtrace.o +oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index 7ce6dfa06c85..1415930ceee1 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -125,27 +125,37 @@ static void exit_driverfs(void) #define exit_driverfs() do { } while (0) #endif /* CONFIG_PM */ -int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) +int __init oprofile_arch_init(struct oprofile_operations *ops) { - init_MUTEX(&op_arm_sem); + struct op_arm_model_spec *spec = NULL; + int ret = -ENODEV; - if (spec->init() < 0) - return -ENODEV; +#ifdef CONFIG_CPU_XSCALE + spec = &op_xscale_spec; +#endif - op_arm_model = spec; - init_driverfs(); - ops->create_files = op_arm_create_files; - ops->setup = op_arm_setup; - ops->shutdown = op_arm_stop; - ops->start = op_arm_start; - ops->stop = op_arm_stop; - ops->cpu_type = op_arm_model->name; - printk(KERN_INFO "oprofile: using %s\n", spec->name); + if (spec) { + init_MUTEX(&op_arm_sem); - return 0; + if (spec->init() < 0) + return -ENODEV; + + op_arm_model = spec; + init_driverfs(); + ops->create_files = op_arm_create_files; + ops->setup = op_arm_setup; + ops->shutdown = op_arm_stop; + ops->start = op_arm_start; + ops->stop = op_arm_stop; + ops->cpu_type = op_arm_model->name; + ops->backtrace = arm_backtrace; + printk(KERN_INFO "oprofile: using %s\n", spec->name); + } + + return ret; } -void op_arm_exit(void) +void oprofile_arch_exit(void) { if (op_arm_model) { exit_driverfs(); diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c deleted file mode 100644 index ccd8c54934a2..000000000000 --- a/arch/arm/oprofile/init.c +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file init.c - * - * @remark Copyright 2004 Oprofile Authors - * @remark Read the file COPYING - * - * @author Zwane Mwaikambo - */ - -#include -#include -#include -#include "op_arm_model.h" - -int __init oprofile_arch_init(struct oprofile_operations *ops) -{ - int ret = -ENODEV; - -#ifdef CONFIG_CPU_XSCALE - ret = op_arm_init(ops, &op_xscale_spec); -#endif - - ops->backtrace = arm_backtrace; - - return ret; -} - -void oprofile_arch_exit(void) -{ -#ifdef CONFIG_CPU_XSCALE - op_arm_exit(); -#endif -} From f70cd65658388ca2a06071bdbd8a5a6beac5aa47 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:18:56 +0100 Subject: [PATCH 0838/1939] [ARM] 2982/1: Replace map_desc.physical with map_desc.pfn: aaec2000 Patch from Deepak Saxena aaec2000 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-aaec2000/core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index aece0cd4f0a3..9be6c3213254 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -40,9 +40,17 @@ * default mapping provided here. */ static struct map_desc standard_io_desc[] __initdata = { - /* virtual physical length type */ - { VIO_APB_BASE, PIO_APB_BASE, IO_APB_LENGTH, MT_DEVICE }, - { VIO_AHB_BASE, PIO_AHB_BASE, IO_AHB_LENGTH, MT_DEVICE } + { + .virtual = VIO_APB_BASE, + .physical = __phys_to_pfn(PIO_APB_BASE), + .length = IO_APB_LENGTH, + .type = MT_DEVICE + }, { + .virtual = VIO_AHB_BASE, + .physical = __phys_to_pfn(PIO_AHB_BASE), + .length = IO_AHB_LENGTH, + .type = MT_DEVICE + } }; void __init aaec2000_map_io(void) From 4835e64a5f44366e97dde9b6e26ede2ec16249da Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:18:57 +0100 Subject: [PATCH 0839/1939] [ARM] 2983/1: Replace map_desc.physical with map_desc.pfn: IOP3xx Patch from Deepak Saxena IOP3xx map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-iop3xx/iop321-setup.c | 18 +++++++++++------- arch/arm/mach-iop3xx/iop331-setup.c | 18 +++++++++++------- arch/arm/mach-iop3xx/iq31244-mm.c | 10 ++++++---- arch/arm/mach-iop3xx/iq80321-mm.c | 10 ++++++---- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c index 0f921ba2750c..bb5091223b63 100644 --- a/arch/arm/mach-iop3xx/iop321-setup.c +++ b/arch/arm/mach-iop3xx/iop321-setup.c @@ -38,13 +38,17 @@ * Standard IO mapping for all IOP321 based systems */ static struct map_desc iop321_std_desc[] __initdata = { - /* virtual physical length type */ - - /* mem mapped registers */ - { IOP321_VIRT_MEM_BASE, IOP321_PHYS_MEM_BASE, 0x00002000, MT_DEVICE }, - - /* PCI IO space */ - { IOP321_PCI_LOWER_IO_VA, IOP321_PCI_LOWER_IO_PA, IOP321_PCI_IO_WINDOW_SIZE, MT_DEVICE } + { /* mem mapped registers */ + .virtual = IOP321_VIRT_MEM_BASE, + .pfn = __phys_to_pfn(IOP321_PHYS_MEM_BASE), + .length = 0x00002000, + .type = MT_DEVICE + }, { /* PCI IO space */ + .virtual = IOP321_PCI_LOWER_IO_VA, + .pfn = __phys_to_pfn(IOP321_PCI_LOWER_IO_PA), + .length = IOP321_PCI_IO_WINDOW_SIZE, + .type = MT_DEVICE + } }; #ifdef CONFIG_ARCH_IQ80321 diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c index fc74b722f72f..a2533c3ab42f 100644 --- a/arch/arm/mach-iop3xx/iop331-setup.c +++ b/arch/arm/mach-iop3xx/iop331-setup.c @@ -37,13 +37,17 @@ * Standard IO mapping for all IOP331 based systems */ static struct map_desc iop331_std_desc[] __initdata = { - /* virtual physical length type */ - - /* mem mapped registers */ - { IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE }, - - /* PCI IO space */ - { IOP331_PCI_LOWER_IO_VA, IOP331_PCI_LOWER_IO_PA, IOP331_PCI_IO_WINDOW_SIZE, MT_DEVICE } + { /* mem mapped registers */ + .virtual = IOP331_VIRT_MEM_BASE, + .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE), + .length = 0x00002000, + .type = MT_DEVICE + }, { /* PCI IO space */ + .virtual = IOP331_PCI_LOWER_IO_VA, + .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA), + .length = IOP331_PCI_IO_WINDOW_SIZE, + .type = MT_DEVICE + } }; static struct uart_port iop331_serial_ports[] = { diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c index 55992ab586ba..e874b54eefe3 100644 --- a/arch/arm/mach-iop3xx/iq31244-mm.c +++ b/arch/arm/mach-iop3xx/iq31244-mm.c @@ -29,10 +29,12 @@ * We use RedBoot's setup for the onboard devices. */ static struct map_desc iq31244_io_desc[] __initdata = { - /* virtual physical length type */ - - /* on-board devices */ - { IQ31244_UART, IQ31244_UART, 0x00100000, MT_DEVICE } + { /* on-board devices */ + .virtual = IQ31244_UART, + .pfn = __phys_to_pfn(IQ31244_UART), + .length = 0x00100000, + .type = MT_DEVICE + } }; void __init iq31244_map_io(void) diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c index bb3e9e5a9aff..d9cac5e1fc3d 100644 --- a/arch/arm/mach-iop3xx/iq80321-mm.c +++ b/arch/arm/mach-iop3xx/iq80321-mm.c @@ -29,10 +29,12 @@ * We use RedBoot's setup for the onboard devices. */ static struct map_desc iq80321_io_desc[] __initdata = { - /* virtual physical length type */ - - /* on-board devices */ - { IQ80321_UART, IQ80321_UART, 0x00100000, MT_DEVICE } + { /* on-board devices */ + .virtual = IQ80321_UART, + .pfn = __phys_to_pfn(IQ80321_UART), + .length = 0x00100000, + .type = MT_DEVICE + } }; void __init iq80321_map_io(void) From db0d087e34d251254f6349e607c2a2ec295cd90b Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:18:58 +0100 Subject: [PATCH 0840/1939] [ARM] 2984/1: Replace map_desc.physical with map_desc.pfn: IXP2000 Patch from Deepak Saxena IXP2000 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp2000/core.c | 16 ++++++++-------- arch/arm/mach-ixp2000/ixdp2x00.c | 2 +- arch/arm/mach-ixp2000/ixdp2x01.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index f4d7f1f6ef85..01c393c504d0 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -83,42 +83,42 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg) static struct map_desc ixp2000_io_desc[] __initdata = { { .virtual = IXP2000_CAP_VIRT_BASE, - .physical = IXP2000_CAP_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE), .length = IXP2000_CAP_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_INTCTL_VIRT_BASE, - .physical = IXP2000_INTCTL_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE), .length = IXP2000_INTCTL_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_PCI_CREG_VIRT_BASE, - .physical = IXP2000_PCI_CREG_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE), .length = IXP2000_PCI_CREG_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_PCI_CSR_VIRT_BASE, - .physical = IXP2000_PCI_CSR_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE), .length = IXP2000_PCI_CSR_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_MSF_VIRT_BASE, - .physical = IXP2000_MSF_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE), .length = IXP2000_MSF_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_PCI_IO_VIRT_BASE, - .physical = IXP2000_PCI_IO_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE), .length = IXP2000_PCI_IO_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_PCI_CFG0_VIRT_BASE, - .physical = IXP2000_PCI_CFG0_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE), .length = IXP2000_PCI_CFG0_SIZE, .type = MT_DEVICE }, { .virtual = IXP2000_PCI_CFG1_VIRT_BASE, - .physical = IXP2000_PCI_CFG1_PHYS_BASE, + .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE), .length = IXP2000_PCI_CFG1_SIZE, .type = MT_DEVICE } diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 63ba0191aa65..8b4a839b6279 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -176,7 +176,7 @@ void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *************************************************************************/ static struct map_desc ixdp2x00_io_desc __initdata = { .virtual = IXDP2X00_VIRT_CPLD_BASE, - .physical = IXDP2X00_PHYS_CPLD_BASE, + .pfn = __phys_to_pfn(IXDP2X00_PHYS_CPLD_BASE), .length = IXDP2X00_CPLD_SIZE, .type = MT_DEVICE }; diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index 7a5109921287..fee1d7b73503 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -136,7 +136,7 @@ void __init ixdp2x01_init_irq(void) *************************************************************************/ static struct map_desc ixdp2x01_io_desc __initdata = { .virtual = IXDP2X01_VIRT_CPLD_BASE, - .physical = IXDP2X01_PHYS_CPLD_BASE, + .pfn = __phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE), .length = IXDP2X01_CPLD_REGION_SIZE, .type = MT_DEVICE }; From 87fe04bd2a39f263211cc232da9f4f094eaffea0 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:18:59 +0100 Subject: [PATCH 0841/1939] [ARM] 2985/1: Replace map_desc.physical with map_desc.pfn: IXP4xx Patch from Deepak Saxena IXP4xx map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 36b6045213ee..6c396447c4e0 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -44,24 +44,24 @@ static struct map_desc ixp4xx_io_desc[] __initdata = { { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */ .virtual = IXP4XX_PERIPHERAL_BASE_VIRT, - .physical = IXP4XX_PERIPHERAL_BASE_PHYS, + .pfn = __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS), .length = IXP4XX_PERIPHERAL_REGION_SIZE, .type = MT_DEVICE }, { /* Expansion Bus Config Registers */ .virtual = IXP4XX_EXP_CFG_BASE_VIRT, - .physical = IXP4XX_EXP_CFG_BASE_PHYS, + .pfn = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS), .length = IXP4XX_EXP_CFG_REGION_SIZE, .type = MT_DEVICE }, { /* PCI Registers */ .virtual = IXP4XX_PCI_CFG_BASE_VIRT, - .physical = IXP4XX_PCI_CFG_BASE_PHYS, + .pfn = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS), .length = IXP4XX_PCI_CFG_REGION_SIZE, .type = MT_DEVICE }, #ifdef CONFIG_DEBUG_LL { /* Debug UART mapping */ .virtual = IXP4XX_DEBUG_UART_BASE_VIRT, - .physical = IXP4XX_DEBUG_UART_BASE_PHYS, + .pfn = __phys_to_pfn(IXP4XX_DEBUG_UART_BASE_PHYS), .length = IXP4XX_DEBUG_UART_REGION_SIZE, .type = MT_DEVICE } From 36d28c03d17506dd30aeed9d68a4023f3e7631dc Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:18:59 +0100 Subject: [PATCH 0842/1939] [ARM] 2986/1: Replace map_desc.physical with map_desc.pfn: LH7A40x Patch from Deepak Saxena LH7A40x map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-lh7a40x/arch-kev7a400.c | 13 +++- arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 86 ++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c index cb3dcd3bd00a..19f2fa2244c4 100644 --- a/arch/arm/mach-lh7a40x/arch-kev7a400.c +++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c @@ -26,8 +26,17 @@ /* This function calls the board specific IRQ initialization function. */ static struct map_desc kev7a400_io_desc[] __initdata = { - { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, - { CPLD_VIRT, CPLD_PHYS, CPLD_SIZE, MT_DEVICE }, + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD_VIRT, + .pfn = __phys_to_pfn(CPLD_PHYS), + .length = CPLD_SIZE, + .type = MT_DEVICE + } }; void __init kev7a400_map_io(void) diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index 6eb61a17c63b..a20eabc132b0 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -227,23 +227,79 @@ void __init lh7a40x_init_board_irq (void) } static struct map_desc lpd7a400_io_desc[] __initdata = { - { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, - /* Mapping added to work around chip select problems */ - { IOBARRIER_VIRT, IOBARRIER_PHYS, IOBARRIER_SIZE, MT_DEVICE }, - { CF_VIRT, CF_PHYS, CF_SIZE, MT_DEVICE }, + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, { /* Mapping added to work around chip select problems */ + .virtual = IOBARRIER_VIRT, + .pfn = __phys_to_pfn(IOBARRIER_PHYS), + .length = IOBARRIER_SIZE, + .type = MT_DEVICE + }, { + .virtual = CF_VIRT, + .pfn = __phys_to_pfn(CF_PHYS), + .length = CF_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD02_VIRT, + .pfn = __phys_to_pfn(CPLD02_PHYS), + .length = CPLD02_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD06_VIRT, + .pfn = __phys_to_pfn(CPLD06_PHYS), + .length = CPLD06_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD08_VIRT, + .pfn = __phys_to_pfn(CPLD08_PHYS), + .length = CPLD08_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD0C_VIRT, + .pfn = __phys_to_pfn(CPLD0C_PHYS), + .length = CPLD0C_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD0E_VIRT, + .pfn = __phys_to_pfn(CPLD0E_PHYS), + .length = CPLD0E_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD10_VIRT, + .pfn = __phys_to_pfn(CPLD10_PHYS), + .length = CPLD10_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD12_VIRT, + .pfn = __phys_to_pfn(CPLD12_PHYS), + .length = CPLD12_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD14_VIRT, + .pfn = __phys_to_pfn(CPLD14_PHYS), + .length = CPLD14_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD16_VIRT, + .pfn = __phys_to_pfn(CPLD16_PHYS), + .length = CPLD16_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD18_VIRT, + .pfn = __phys_to_pfn(CPLD18_PHYS), + .length = CPLD18_SIZE, + .type = MT_DEVICE + }, { + .virtual = CPLD1A_VIRT, + .pfn = __phys_to_pfn(CPLD1A_PHYS), + .length = CPLD1A_SIZE, + .type = MT_DEVICE + }, /* This mapping is redundant since the smc driver performs another. */ /* { CPLD00_VIRT, CPLD00_PHYS, CPLD00_SIZE, MT_DEVICE }, */ - { CPLD02_VIRT, CPLD02_PHYS, CPLD02_SIZE, MT_DEVICE }, - { CPLD06_VIRT, CPLD06_PHYS, CPLD06_SIZE, MT_DEVICE }, - { CPLD08_VIRT, CPLD08_PHYS, CPLD08_SIZE, MT_DEVICE }, - { CPLD0C_VIRT, CPLD0C_PHYS, CPLD0C_SIZE, MT_DEVICE }, - { CPLD0E_VIRT, CPLD0E_PHYS, CPLD0E_SIZE, MT_DEVICE }, - { CPLD10_VIRT, CPLD10_PHYS, CPLD10_SIZE, MT_DEVICE }, - { CPLD12_VIRT, CPLD12_PHYS, CPLD12_SIZE, MT_DEVICE }, - { CPLD14_VIRT, CPLD14_PHYS, CPLD14_SIZE, MT_DEVICE }, - { CPLD16_VIRT, CPLD16_PHYS, CPLD16_SIZE, MT_DEVICE }, - { CPLD18_VIRT, CPLD18_PHYS, CPLD18_SIZE, MT_DEVICE }, - { CPLD1A_VIRT, CPLD1A_PHYS, CPLD1A_SIZE, MT_DEVICE }, }; void __init From 9fe133b149e8a48742a64b72f22041bcd31fe827 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:00 +0100 Subject: [PATCH 0843/1939] [ARM] 2987/1: Replace map_desc.physical with map_desc.pfn: OMAP Patch from Deepak Saxena OMAP map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-omap1/board-innovator.c | 8 +++-- arch/arm/mach-omap1/board-perseus2.c | 8 +++-- arch/arm/mach-omap1/io.c | 46 +++++++++++++++++++++++---- arch/arm/plat-omap/sram.c | 6 +++- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index df0312b596e4..fd9183ff2ed5 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -103,8 +103,12 @@ static struct platform_device innovator_flash_device = { /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc innovator1510_io_desc[] __initdata = { -{ OMAP1510_FPGA_BASE, OMAP1510_FPGA_START, OMAP1510_FPGA_SIZE, - MT_DEVICE }, + { + .virtual = OMAP1510_FPGA_BASE, + .pfn = __phys_to_pfn(OMAP1510_FPGA_START), + .length = OMAP1510_FPGA_SIZE, + .type = MT_DEVICE + } }; static struct resource innovator1510_smc91x_resources[] = { diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 107c68c8ab54..2ba26e239108 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -134,8 +134,12 @@ void omap_perseus2_init_irq(void) /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc omap_perseus2_io_desc[] __initdata = { - {H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE, - MT_DEVICE}, + { + .virtual = H2P2_DBG_FPGA_BASE, + .pfn = __phys_to_pfn(H2P2_DBG_FPGA_START), + .length = H2P2_DBG_FPGA_SIZE, + .type = MT_DEVICE + } }; static void __init omap_perseus2_map_io(void) diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index eb8261d7dead..79fb86535ebc 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -26,27 +26,59 @@ extern void omap_sram_init(void); * default mapping provided here. */ static struct map_desc omap_io_desc[] __initdata = { - { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + } }; #ifdef CONFIG_ARCH_OMAP730 static struct map_desc omap730_io_desc[] __initdata = { - { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE }, - { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE }, + { + .virtual = OMAP730_DSP_BASE, + .pfn = __phys_to_pfn(OMAP730_DSP_START), + .length = OMAP730_DSP_SIZE, + .type = MT_DEVICE + }, { + .virtual = OMAP730_DSPREG_BASE, + .pfn = __phys_to_pfn(OMAP730_DSPREG_START), + .length = OMAP730_DSPREG_SIZE, + .type = MT_DEVICE + } }; #endif #ifdef CONFIG_ARCH_OMAP1510 static struct map_desc omap1510_io_desc[] __initdata = { - { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE }, - { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE }, + { + .virtual = OMAP1510_DSP_BASE, + .pfn = __phys_to_pfn(OMAP1510_DSP_START), + .length = OMAP1510_DSP_SIZE, + .type = MT_DEVICE + }, { + .virtual = OMAP1510_DSPREG_BASE, + .pfn = __phys_to_pfn(OMAP1510_DSPREG_START), + .length = OMAP1510_DSPREG_SIZE, + .type = MT_DEVICE + } }; #endif #if defined(CONFIG_ARCH_OMAP16XX) static struct map_desc omap16xx_io_desc[] __initdata = { - { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, - { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, + { + .virtual = OMAP16XX_DSP_BASE, + .pfn = __phys_to_pfn(OMAP16XX_DSP_START), + .length = OMAP16XX_DSP_SIZE, + .type = MT_DEVICE + }, { + .virtual = OMAP16XX_DSPREG_BASE, + .pfn = __phys_to_pfn(OMAP16XX_DSPREG_START), + .length = OMAP16XX_DSPREG_SIZE, + .type = MT_DEVICE + } }; #endif diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 7719a4062e3a..7ad69f14a3e7 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -59,7 +59,11 @@ void __init omap_detect_sram(void) } static struct map_desc omap_sram_io_desc[] __initdata = { - { OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE } + { /* .length gets filled in at runtime */ + .virtual = OMAP1_SRAM_BASE, + .pfn = __phys_to_pfn(OMAP1_SRAM_START), + .type = MT_DEVICE + } }; /* From 6f9182eb32a4e6c46813928bee50df71e3fd1c74 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:01 +0100 Subject: [PATCH 0844/1939] [ARM] 2988/1: Replace map_desc.physical with map_desc.pfn: PXA Patch from Deepak Saxena PXA map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-pxa/generic.c | 44 ++++++++++++++++++++++++++++------- arch/arm/mach-pxa/idp.c | 21 +++++++++-------- arch/arm/mach-pxa/lubbock.c | 7 +++++- arch/arm/mach-pxa/mainstone.c | 7 +++++- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 1d7677669a76..2e9e1702c4b3 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -92,14 +92,42 @@ EXPORT_SYMBOL(pxa_set_cken); * and cache flush area. */ static struct map_desc standard_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf2000000, 0x40000000, 0x02000000, MT_DEVICE }, /* Devs */ - { 0xf4000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */ - { 0xf6000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */ - { 0xf8000000, 0x4c000000, 0x00100000, MT_DEVICE }, /* USB host */ - { 0xfa000000, 0x50000000, 0x00100000, MT_DEVICE }, /* Camera */ - { 0xfe000000, 0x58000000, 0x00100000, MT_DEVICE }, /* IMem ctl */ - { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */ + { /* Devs */ + .virtual = 0xf2000000, + .pfn = __phys_to_pfn(0x40000000), + .length = 0x02000000, + .type = MT_DEVICE + }, { /* LCD */ + .virtual = 0xf4000000, + .pfn = __phys_to_pfn(0x44000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* Mem Ctl */ + .virtual = 0xf6000000, + .pfn = __phys_to_pfn(0x48000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* USB host */ + .virtual = 0xf8000000, + .pfn = __phys_to_pfn(0x4c000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* Camera */ + .virtual = 0xfa000000, + .pfn = __phys_to_pfn(0x50000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* IMem ctl */ + .virtual = 0xfe000000, + .pfn = __phys_to_pfn(0x58000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* UNCACHED_PHYS_0 */ + .virtual = 0xff000000, + .pfn = __phys_to_pfn(0x00000000), + .length = 0x00100000, + .type = MT_DEVICE + } }; void __init pxa_map_io(void) diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 386e107b53cc..01a83ab09ac3 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -152,16 +152,17 @@ static void __init idp_init_irq(void) } static struct map_desc idp_io_desc[] __initdata = { - /* virtual physical length type */ - - { IDP_COREVOLT_VIRT, - IDP_COREVOLT_PHYS, - IDP_COREVOLT_SIZE, - MT_DEVICE }, - { IDP_CPLD_VIRT, - IDP_CPLD_PHYS, - IDP_CPLD_SIZE, - MT_DEVICE } + { + .virtual = IDP_COREVOLT_VIRT, + .pfn = __phys_to_pfn(IDP_COREVOLT_PHYS), + .length = IDP_COREVOLT_SIZE, + .type = MT_DEVICE + }, { + .virtual = IDP_CPLD_VIRT, + .pfn = __phys_to_pfn(IDP_CPLD_PHYS), + .length = IDP_CPLD_SIZE, + .type = MT_DEVICE + } }; static void __init idp_map_io(void) diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 1f38033921e9..69abc7f61ed0 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -246,7 +246,12 @@ static void __init lubbock_init(void) } static struct map_desc lubbock_io_desc[] __initdata = { - { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ + { /* CPLD */ + .virtual = LUBBOCK_FPGA_VIRT, + .pfn = __phys_to_pfn(LUBBOCK_FPGA_PHYS), + .length = 0x00100000, + .type = MT_DEVICE + } }; static void __init lubbock_map_io(void) diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 85fdb5b1470a..8b4a21623fc0 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -317,7 +317,12 @@ static void __init mainstone_init(void) static struct map_desc mainstone_io_desc[] __initdata = { - { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */ + { /* CPLD */ + .virtual = MST_FPGA_VIRT, + .pfn = __phys_to_pfn(MST_FPGA_PHYS), + .length = 0x00100000, + .type = MT_DEVICE + } }; static void __init mainstone_map_io(void) From f9258f226baf663099acb7972287ea0e26ce05a7 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:02 +0100 Subject: [PATCH 0845/1939] [ARM] 2989/1: Replace map_desc.physical with map_desc.pfn: RiscPC Patch from Deepak Saxena RiscPC map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-rpc/riscpc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index e3587efec4bf..5c4ac1c008a6 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -61,9 +61,22 @@ static int __init parse_tag_acorn(const struct tag *tag) __tagtable(ATAG_ACORN, parse_tag_acorn); static struct map_desc rpc_io_desc[] __initdata = { - { SCREEN_BASE, SCREEN_START, 2*1048576, MT_DEVICE }, /* VRAM */ - { (u32)IO_BASE, IO_START, IO_SIZE , MT_DEVICE }, /* IO space */ - { EASI_BASE, EASI_START, EASI_SIZE, MT_DEVICE } /* EASI space */ + { /* VRAM */ + .virtual = SCREEN_BASE, + .pfn = __phys_to_pfn(SCREEN_START), + .length = 2*1048576, + .type = MT_DEVICE + }, { /* IO space */ + .virtual = (u32)IO_BASE, + .pfn = __phys_to_pfn(IO_START), + .length = IO_SIZE , + .type = MT_DEVICE + }, { /* EASI space */ + .virtual = EASI_BASE, + .pfn = __phys_to_pfn(EASI_START), + .length = EASI_SIZE, + .type = MT_DEVICE + } }; static void __init rpc_map_io(void) From 1cc977a76642b1eec2ab4ba80a6f0db9a63a091e Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:02 +0100 Subject: [PATCH 0846/1939] [ARM] 2990/1: Replace map_desc.physical with map_desc.pfn: S3C2410 Patch from Deepak Saxena S3C2410 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-s3c2410/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h index 478c15c0e36a..9cbe5eef492b 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/arch/arm/mach-s3c2410/cpu.h @@ -21,7 +21,7 @@ /* todo - fix when rmk changes iodescs to use `void __iomem *` */ -#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE } +#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C2410_PA_##x), S3C24XX_SZ_##x, MT_DEVICE } #ifndef MHZ #define MHZ (1000*1000) From cd5fc8bffd70b2d87953334b6195db4bc2125ff9 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:03 +0100 Subject: [PATCH 0847/1939] [ARM] 2991/1: Replace map_desc.physical with map_desc.pfn: Shark Patch from Deepak Saxena Shark map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-shark/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index 946c0d11c73b..2d428b6dbb58 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -62,7 +62,12 @@ arch_initcall(shark_init); extern void shark_init_irq(void); static struct map_desc shark_io_desc[] __initdata = { - { IO_BASE , IO_START , IO_SIZE , MT_DEVICE } + { + .virtual = IO_BASE, + .pfn = __phys_to_pfn(IO_START), + .length = IO_SIZE, + .type = MT_DEVICE + } }; static void __init shark_map_io(void) From 92519d82828a93743adc31202927f411601c0d04 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:04 +0100 Subject: [PATCH 0848/1939] [ARM] 2992/1: Replace map_desc.physical with map_desc.pfn: SA1100 Patch from Deepak Saxena SA1100 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-sa1100/assabet.c | 14 +++++++++++--- arch/arm/mach-sa1100/badge4.c | 20 ++++++++++++++++---- arch/arm/mach-sa1100/cerf.c | 8 ++++++-- arch/arm/mach-sa1100/collie.c | 14 +++++++++++--- arch/arm/mach-sa1100/generic.c | 26 +++++++++++++++++++++----- arch/arm/mach-sa1100/h3600.c | 20 ++++++++++++++++---- arch/arm/mach-sa1100/hackkit.c | 8 ++++++-- arch/arm/mach-sa1100/jornada720.c | 20 ++++++++++++++++---- arch/arm/mach-sa1100/lart.c | 14 +++++++++++--- arch/arm/mach-sa1100/neponset.c | 14 +++++++++++--- arch/arm/mach-sa1100/simpad.c | 16 +++++++++++----- 11 files changed, 136 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 24687f511bf5..75efb5da5b6d 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -388,9 +388,17 @@ static struct sa1100_port_fns assabet_port_fns __initdata = { }; static struct map_desc assabet_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */ - { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE } /* MQ200 */ + { /* Board Control Register */ + .virtual = 0xf1000000, + .pfn = __phys_to_pfn(0x12000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* MQ200 */ + .virtual = 0xf2800000, + .pfn = __phys_to_pfn(0x4b800000), + .length = 0x00800000, + .type = MT_DEVICE + } }; static void __init assabet_map_io(void) diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index b6169cb09196..c92cebff7f8e 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -254,10 +254,22 @@ EXPORT_SYMBOL(badge4_set_5V); static struct map_desc badge4_io_desc[] __initdata = { - /* virtual physical length type */ - {0xf1000000, 0x08000000, 0x00100000, MT_DEVICE },/* SRAM bank 1 */ - {0xf2000000, 0x10000000, 0x00100000, MT_DEVICE },/* SRAM bank 2 */ - {0xf4000000, 0x48000000, 0x00100000, MT_DEVICE } /* SA-1111 */ + { /* SRAM bank 1 */ + .virtual = 0xf1000000, + .pfn = __phys_to_pfn(0x08000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* SRAM bank 2 */ + .virtual = 0xf2000000, + .pfn = __phys_to_pfn(0x10000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* SA-1111 */ + .virtual = 0xf4000000, + .pfn = __phys_to_pfn(0x48000000), + .length = 0x00100000, + .type = MT_DEVICE + } }; static void diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 9484be7dc671..23cb74885275 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -100,8 +100,12 @@ static void __init cerf_init_irq(void) } static struct map_desc cerf_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE } /* Crystal Ethernet Chip */ + { /* Crystal Ethernet Chip */ + .virtual = 0xf0000000, + .pfn = __phys_to_pfn(0x08000000), + .length = 0x00100000, + .type = MT_DEVICE + } }; static void __init cerf_map_io(void) diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 6ecab7e2c238..7fd6e29c36b7 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -171,9 +171,17 @@ static void __init collie_init(void) } static struct map_desc collie_io_desc[] __initdata = { - /* virtual physical length type */ - {0xe8000000, 0x00000000, 0x02000000, MT_DEVICE}, /* 32M main flash (cs0) */ - {0xea000000, 0x08000000, 0x02000000, MT_DEVICE}, /* 32M boot flash (cs1) */ + { /* 32M main flash (cs0) */ + .virtual = 0xe8000000, + .pfn = __phys_to_pfn(0x00000000), + .length = 0x02000000, + .type = MT_DEVICE + }, { /* 32M boot flash (cs1) */ + .virtual = 0xea000000, + .pfn = __phys_to_pfn(0x08000000), + .length = 0x02000000, + .type = MT_DEVICE + } }; static void __init collie_map_io(void) diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 3f1e358455e5..93619497779c 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -369,11 +369,27 @@ EXPORT_SYMBOL(sa1100fb_lcd_power); */ static struct map_desc standard_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf8000000, 0x80000000, 0x00100000, MT_DEVICE }, /* PCM */ - { 0xfa000000, 0x90000000, 0x00100000, MT_DEVICE }, /* SCM */ - { 0xfc000000, 0xa0000000, 0x00100000, MT_DEVICE }, /* MER */ - { 0xfe000000, 0xb0000000, 0x00200000, MT_DEVICE } /* LCD + DMA */ + { /* PCM */ + .virtual = 0xf8000000, + .pfn = __phys_to_pfn(0x80000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* SCM */ + .virtual = 0xfa000000, + .pfn = __phys_to_pfn(0x90000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* MER */ + .virtual = 0xfc000000, + .pfn = __phys_to_pfn(0xa0000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* LCD + DMA */ + .virtual = 0xfe000000, + .pfn = __phys_to_pfn(0xb0000000), + .length = 0x00200000, + .type = MT_DEVICE + }, }; void __init sa1100_map_io(void) diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index e7aa2681ca64..e8352b7f74b0 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -223,10 +223,22 @@ static void h3xxx_lcd_power(int enable) } static struct map_desc h3600_io_desc[] __initdata = { - /* virtual physical length type */ - { H3600_BANK_2_VIRT, SA1100_CS2_PHYS, 0x02800000, MT_DEVICE }, /* static memory bank 2 CS#2 */ - { H3600_BANK_4_VIRT, SA1100_CS4_PHYS, 0x00800000, MT_DEVICE }, /* static memory bank 4 CS#4 */ - { H3600_EGPIO_VIRT, H3600_EGPIO_PHYS, 0x01000000, MT_DEVICE }, /* EGPIO 0 CS#5 */ + { /* static memory bank 2 CS#2 */ + .virtual = H3600_BANK_2_VIRT, + .pfn = __phys_to_pfn(SA1100_CS2_PHYS), + .length = 0x02800000, + .type = MT_DEVICE + }, { /* static memory bank 4 CS#4 */ + .virtual = H3600_BANK_4_VIRT, + .pfn = __phys_to_pfn(SA1100_CS4_PHYS), + .length = 0x00800000, + .type = MT_DEVICE + }, { /* EGPIO 0 CS#5 */ + .virtual = H3600_EGPIO_VIRT, + .pfn = __phys_to_pfn(H3600_EGPIO_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + } }; /* diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index 502d65cfe654..c922e043c424 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -57,8 +57,12 @@ static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate) */ static struct map_desc hackkit_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xe8000000, 0x00000000, 0x01000000, MT_DEVICE } /* Flash bank 0 */ + { /* Flash bank 0 */ + .virtual = 0xe8000000, + .pfn = __phys_to_pfn(0x00000000), + .length = 0x01000000, + .type = MT_DEVICE + }, }; static struct sa1100_port_fns hackkit_port_fns __initdata = { diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 2f497112c96a..9c363bfcf310 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -81,10 +81,22 @@ static int __init jornada720_init(void) arch_initcall(jornada720_init); static struct map_desc jornada720_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf0000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Epson registers */ - { 0xf1000000, 0x48200000, 0x00100000, MT_DEVICE }, /* Epson frame buffer */ - { 0xf4000000, 0x40000000, 0x00100000, MT_DEVICE } /* SA-1111 */ + { /* Epson registers */ + .virtual = 0xf0000000, + .pfn = __phys_to_pfn(0x48000000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* Epson frame buffer */ + .virtual = 0xf1000000, + .pfn = __phys_to_pfn(0x48200000), + .length = 0x00100000, + .type = MT_DEVICE + }, { /* SA-1111 */ + .virtual = 0xf4000000, + .pfn = __phys_to_pfn(0x40000000), + .length = 0x00100000, + .type = MT_DEVICE + } }; static void __init jornada720_map_io(void) diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index ed6744d480af..8c9e3dd52942 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -31,9 +31,17 @@ static void __init lart_init(void) } static struct map_desc lart_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */ - { 0xec000000, 0x08000000, 0x00400000, MT_DEVICE } /* main flash, alternative location */ + { /* main flash memory */ + .virtual = 0xe8000000, + .pfn = __phys_to_pfn(0x00000000), + .length = 0x00400000, + .type = MT_DEVICE + }, { /* main flash, alternative location */ + .virtual = 0xec000000, + .pfn = __phys_to_pfn(0x08000000), + .length = 0x00400000, + .type = MT_DEVICE + } }; static void __init lart_map_io(void) diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index fc061641b7be..0c5eff3bdc09 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -331,9 +331,17 @@ static int __init neponset_init(void) subsys_initcall(neponset_init); static struct map_desc neponset_io_desc[] __initdata = { - /* virtual physical length type */ - { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */ - { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE } /* SA-1111 */ + { /* System Registers */ + .virtual = 0xf3000000, + .pfn = __phys_to_pfn(0x10000000), + .length = SZ_1M, + .type = MT_DEVICE + }, { /* SA-1111 */ + .virtual = 0xf4000000, + .pfn = __phys_to_pfn(0x40000000), + .length = SZ_1M, + .type = MT_DEVICE + } }; void __init neponset_map_io(void) diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index 07f6d5fd7bb0..cfb6658e5cdf 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -60,11 +60,17 @@ EXPORT_SYMBOL(set_cs3_bit); EXPORT_SYMBOL(clear_cs3_bit); static struct map_desc simpad_io_desc[] __initdata = { - /* virtual physical length type */ - /* MQ200 */ - { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }, - /* Paules CS3, write only */ - { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE }, + { /* MQ200 */ + .virtual = 0xf2800000, + .pfn = __phys_to_pfn(0x4b800000), + .length = 0x00800000, + .type = MT_DEVICE + }, { /* Paules CS3, write only */ + .virtual = 0xf1000000, + .pfn = __phys_to_pfn(0x18000000), + .length = 0x00100000, + .type = MT_DEVICE + }, }; From f10083f5a6f4a2735cca3a8c762457272ea66bf0 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:05 +0100 Subject: [PATCH 0849/1939] [ARM] 2993/1: Replace map_desc.physical with map_desc.pfn: CLPS711x Patch from Deepak Saxena CLSP711x map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-clps711x/autcpu12.c | 12 ++++++++---- arch/arm/mach-clps711x/cdb89712.c | 7 ++++++- arch/arm/mach-clps711x/ceiva.c | 12 +++++++----- arch/arm/mach-clps711x/edb7211-mm.c | 30 ++++++++++++++++++++--------- arch/arm/mach-clps711x/mm.c | 8 +++++++- arch/arm/mach-clps711x/p720t.c | 14 ++++++++++++-- 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c index dc73feb1ffb0..43b9423d1440 100644 --- a/arch/arm/mach-clps711x/autcpu12.c +++ b/arch/arm/mach-clps711x/autcpu12.c @@ -46,10 +46,14 @@ */ static struct map_desc autcpu12_io_desc[] __initdata = { - /* virtual, physical, length, type */ - /* memory-mapped extra io and CS8900A Ethernet chip */ - /* ethernet chip */ - { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, MT_DEVICE } + /* memory-mapped extra io and CS8900A Ethernet chip */ + /* ethernet chip */ + { + .virtual = AUTCPU12_VIRT_CS8900A, + .pfn = __phys_to_pfn(AUTCPU12_PHYS_CS8900A), + .length = SZ_1M, + .type = MT_DEVICE + } }; void __init autcpu12_map_io(void) diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c index a46c82cd2711..cba7be5a06c3 100644 --- a/arch/arm/mach-clps711x/cdb89712.c +++ b/arch/arm/mach-clps711x/cdb89712.c @@ -39,7 +39,12 @@ * ethernet driver, perhaps. */ static struct map_desc cdb89712_io_desc[] __initdata = { - { ETHER_BASE, ETHER_START, ETHER_SIZE, MT_DEVICE } + { + .virtual = ETHER_BASE, + .pfn =__phys_to_pfn(ETHER_START), + .length = ETHER_SIZE, + .type = MT_DEVICE + } }; static void __init cdb89712_map_io(void) diff --git a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c index 780d91805984..35d51a759b59 100644 --- a/arch/arm/mach-clps711x/ceiva.c +++ b/arch/arm/mach-clps711x/ceiva.c @@ -37,11 +37,13 @@ #include "common.h" static struct map_desc ceiva_io_desc[] __initdata = { - /* virtual, physical, length, type */ - - /* SED1355 controlled video RAM & registers */ - { CEIVA_VIRT_SED1355, CEIVA_PHYS_SED1355, SZ_2M, MT_DEVICE } - + /* SED1355 controlled video RAM & registers */ + { + .virtual = CEIVA_VIRT_SED1355, + .pfn = __phys_to_pfn(CEIVA_PHYS_SED1355), + .length = SZ_2M, + .type = MT_DEVICE + } }; diff --git a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c index 7fd7b01822d0..72f8bb05d55e 100644 --- a/arch/arm/mach-clps711x/edb7211-mm.c +++ b/arch/arm/mach-clps711x/edb7211-mm.c @@ -51,15 +51,27 @@ extern void clps711x_map_io(void); * happens). */ static struct map_desc edb7211_io_desc[] __initdata = { - /* virtual, physical, length, type */ - - /* memory-mapped extra keyboard row and CS8900A Ethernet chip */ - { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, SZ_1M, MT_DEVICE }, - { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, SZ_1M, MT_DEVICE }, - - /* flash banks */ - { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, SZ_8M, MT_DEVICE }, - { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, SZ_8M, MT_DEVICE } + { /* memory-mapped extra keyboard row */ + .virtual = EP7211_VIRT_EXTKBD, + .pfn = __phys_to_pfn(EP7211_PHYS_EXTKBD), + .length = SZ_1M, + .type - MT_DEVICE + }, { /* and CS8900A Ethernet chip */ + .virtual = EP7211_VIRT_CS8900A, + .pfn = __phys_to_pfn(EP7211_PHYS_CS8900A), + .length = SZ_1M, + .type = MT_DEVICE + }, { /* flash banks */ + .virtual = EP7211_VIRT_FLASH1, + .pfn = __phys_to_pfn(EP7211_PHYS_FLASH1), + .length = SZ_8M, + .type = MT_DEVICE + }, { + .virtual = EP7211_VIRT_FLASH2, + .pfn = __phys_to_pfn(EP7211_PHYS_FLASH2), + .length = SZ_8M, + .type = MT_DEVICE + } }; void __init edb7211_map_io(void) diff --git a/arch/arm/mach-clps711x/mm.c b/arch/arm/mach-clps711x/mm.c index 120b7cac84b5..a00f77ef8df8 100644 --- a/arch/arm/mach-clps711x/mm.c +++ b/arch/arm/mach-clps711x/mm.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,12 @@ * This maps the generic CLPS711x registers */ static struct map_desc clps711x_io_desc[] __initdata = { - { CLPS7111_VIRT_BASE, CLPS7111_PHYS_BASE, 1048576, MT_DEVICE } + { + .virtual = CLPS7111_VIRT_BASE, + .pfn = __phys_to_pfn(CLPS7111_PHYS_BASE), + .length = SZ_1M, + .type = MT_DEVICE + } }; void __init clps711x_map_io(void) diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c index 5bdb90edf992..a1acb945fb51 100644 --- a/arch/arm/mach-clps711x/p720t.c +++ b/arch/arm/mach-clps711x/p720t.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -42,8 +43,17 @@ * We map both here. */ static struct map_desc p720t_io_desc[] __initdata = { - { SYSPLD_VIRT_BASE, SYSPLD_PHYS_BASE, 1048576, MT_DEVICE }, - { 0xfe400000, 0x10400000, 1048576, MT_DEVICE } + { + .virtual = SYSPLD_VIRT_BASE, + .pfn = __phys_to_pfn(SYSPLD_PHYS_BASE), + .length = SZ_1M, + .type = MT_DEVICE + }, { + .virtual = 0xfe400000, + .pfn = __phys_to_pfn(0x10400000), + .length = SZ_1M, + .type = MT_DEVICE + } }; static void __init From d157e9ecec59383a676d676e2bb39367430396a2 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:05 +0100 Subject: [PATCH 0850/1939] [ARM] 2994/1: Replace map_desc.physical with map_desc.pfn: CLPS7500 Patch from Deepak Saxena CLSP7500 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-clps7500/core.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index e216ab8b9e8f..0364ba4b539e 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -259,10 +259,27 @@ static void __init clps7500_init_irq(void) } static struct map_desc cl7500_io_desc[] __initdata = { - { IO_BASE, IO_START, IO_SIZE, MT_DEVICE }, /* IO space */ - { ISA_BASE, ISA_START, ISA_SIZE, MT_DEVICE }, /* ISA space */ - { FLASH_BASE, FLASH_START, FLASH_SIZE, MT_DEVICE }, /* Flash */ - { LED_BASE, LED_START, LED_SIZE, MT_DEVICE } /* LED */ + { /* IO space */ + .virtual = IO_BASE, + .pfn = __phys_to_pfn(IO_START), + .length = IO_SIZE, + .type = MT_DEVICE + }, { /* ISA space */ + .virtual = ISA_BASE, + .pfn = __phys_to_pfn(ISA_START), + .length = ISA_SIZE, + .type = MT_DEVICE + }, { /* Flash */ + .virtual = FLASH_BASE, + .pfn = __phys_to_pfn(FLASH_START), + .length = FLASH_SIZE, + .type = MT_DEVICE + }, { /* LED */ + .virtual = LED_BASE, + .pfn = __phys_to_pfn(LED_START), + .length = LED_SIZE, + .type = MT_DEVICE + } }; static void __init clps7500_map_io(void) From 1311521fb1b8ebbb0b470d028df13f2cbc643e51 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:06 +0100 Subject: [PATCH 0851/1939] [ARM] 2995/1: Replace map_desc.physical with map_desc.pfn: Versatile Patch from Deepak Saxena Versatile map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-versatile/core.c | 83 ++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index a30e0451df72..7e4bdd07f4af 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -186,25 +186,82 @@ void __init versatile_init_irq(void) } static struct map_desc versatile_io_desc[] __initdata = { - { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, + { + .virtual = IO_ADDRESS(VERSATILE_SYS_BASE), + .pfn = __phys_to_pfn(VERSATILE_SYS_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(VERSATILE_SIC_BASE), + .pfn = __phys_to_pfn(VERSATILE_SIC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(VERSATILE_VIC_BASE), + .pfn = __phys_to_pfn(VERSATILE_VIC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE), + .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE), + .length = SZ_4K * 9, + .type = MT_DEVICE + }, #ifdef CONFIG_MACH_VERSATILE_AB - { IO_ADDRESS(VERSATILE_GPIO0_BASE), VERSATILE_GPIO0_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(VERSATILE_IB2_BASE), VERSATILE_IB2_BASE, SZ_64M, MT_DEVICE }, + { + .virtual = IO_ADDRESS(VERSATILE_GPIO0_BASE), + .pfn = __phys_to_pfn(VERSATILE_GPIO0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(VERSATILE_IB2_BASE), + .pfn = __phys_to_pfn(VERSATILE_IB2_BASE), + .length = SZ_64M, + .type = MT_DEVICE + }, #endif #ifdef CONFIG_DEBUG_LL - { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, + { + .virtual = IO_ADDRESS(VERSATILE_UART0_BASE), + .pfn = __phys_to_pfn(VERSATILE_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, #endif #ifdef CONFIG_PCI - { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, - { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, - { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, + { + .virtual = IO_ADDRESS(VERSATILE_PCI_CORE_BASE), + .pfn = __phys_to_pfn(VERSATILE_PCI_CORE_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = VERSATILE_PCI_VIRT_BASE, + .pfn = __phys_to_pfn(VERSATILE_PCI_BASE), + .length = VERSATILE_PCI_BASE_SIZE, + .type = MT_DEVICE + }, { + .virtual = VERSATILE_PCI_CFG_VIRT_BASE, + .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE), + .length = VERSATILE_PCI_CFG_BASE_SIZE, + .type = MT_DEVICE + }, #if 0 - { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, - { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, - { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, + { + .virtual = VERSATILE_PCI_VIRT_MEM_BASE0, + .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE0), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = VERSATILE_PCI_VIRT_MEM_BASE1, + .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE1), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = VERSATILE_PCI_VIRT_MEM_BASE2, + .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE2), + .length = SZ_16M, + .type = MT_DEVICE + }, #endif #endif }; From 7a557e246f5c24f4c7218f41f8caf03c492f40f9 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:07 +0100 Subject: [PATCH 0852/1939] [ARM] 2996/1: Replace map_desc.physical with map_desc.pfn: EPXA10DB Patch from Deepak Saxena EPXA10DB mapd_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-epxa10db/mm.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-epxa10db/mm.c b/arch/arm/mach-epxa10db/mm.c index 2aa57fa46da3..e8832d0910ee 100644 --- a/arch/arm/mach-epxa10db/mm.c +++ b/arch/arm/mach-epxa10db/mm.c @@ -31,12 +31,37 @@ /* Page table mapping for I/O region */ static struct map_desc epxa10db_io_desc[] __initdata = { - { IO_ADDRESS(EXC_REGISTERS_BASE), EXC_REGISTERS_BASE, SZ_16K, MT_DEVICE }, - { IO_ADDRESS(EXC_PLD_BLOCK0_BASE), EXC_PLD_BLOCK0_BASE, SZ_16K, MT_DEVICE }, - { IO_ADDRESS(EXC_PLD_BLOCK1_BASE), EXC_PLD_BLOCK1_BASE, SZ_16K, MT_DEVICE }, - { IO_ADDRESS(EXC_PLD_BLOCK2_BASE), EXC_PLD_BLOCK2_BASE, SZ_16K, MT_DEVICE }, - { IO_ADDRESS(EXC_PLD_BLOCK3_BASE), EXC_PLD_BLOCK3_BASE, SZ_16K, MT_DEVICE }, - { FLASH_VADDR(EXC_EBI_BLOCK0_BASE), EXC_EBI_BLOCK0_BASE, SZ_16M, MT_DEVICE } + { + .virtual = IO_ADDRESS(EXC_REGISTERS_BASE), + .pfn = __phys_to_pfn(EXC_REGISTERS_BASE), + .length = SZ_16K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(EXC_PLD_BLOCK0_BASE), + .pfn = __phys_to_pfn(EXC_PLD_BLOCK0_BASE), + .length = SZ_16K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(EXC_PLD_BLOCK1_BASE), + .pfn =__phys_to_pfn(EXC_PLD_BLOCK1_BASE), + .length = SZ_16K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(EXC_PLD_BLOCK2_BASE), + .physical = __phys_to_pfn(EXC_PLD_BLOCK2_BASE), + .length = SZ_16K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(EXC_PLD_BLOCK3_BASE), + .pfn = __phys_to_pfn(EXC_PLD_BLOCK3_BASE), + .length = SZ_16K, + .type = MT_DEVICE + }, { + .virtual = FLASH_VADDR(EXC_EBI_BLOCK0_BASE), + .pfn = __phys_to_pfn(EXC_EBI_BLOCK0_BASE), + .length = SZ_16M, + .type = MT_DEVICE + } }; void __init epxa10db_map_io(void) From 6cb1907c1a88563c84123c923b46424ea68b53eb Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:08 +0100 Subject: [PATCH 0853/1939] [ARM] 2997/1: Replace map_desc.physical with map_desc.pfn: EBSA110 Patch from Deepak Saxena EBSA110 map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ebsa110/core.c | 38 ++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 5aeadfd72143..15261646dcdd 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -76,16 +76,42 @@ static struct map_desc ebsa110_io_desc[] __initdata = { /* * sparse external-decode ISAIO space */ - { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */ - { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */ - { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, MT_DEVICE }, /* SOFT_BASE */ - { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, MT_DEVICE }, /* PIT_BASE */ + { /* IRQ_STAT/IRQ_MCLR */ + .virtual = IRQ_STAT, + .pfn = __phys_to_pfn(TRICK4_PHYS), + .length = PGDIR_SIZE, + .type = MT_DEVICE + }, { /* IRQ_MASK/IRQ_MSET */ + .virtual = IRQ_MASK, + .pfn = __phys_to_pfn(TRICK3_PHYS), + .length = PGDIR_SIZE, + .type = MT_DEVICE + }, { /* SOFT_BASE */ + .virtual = SOFT_BASE, + .pfn = __phys_to_pfn(TRICK1_PHYS), + .length = PGDIR_SIZE, + .type = MT_DEVICE + }, { /* PIT_BASE */ + .virtual = PIT_BASE, + .pfn = __phys_to_pfn(TRICK0_PHYS), + .length = PGDIR_SIZE, + .type = MT_DEVICE + }, /* * self-decode ISAIO space */ - { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, MT_DEVICE }, - { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE } + { + .virtual = ISAIO_BASE, + .pfn = __phys_to_pfn(ISAIO_PHYS), + .length = ISAIO_SIZE, + .type = MT_DEVICE + }, { + .virtual = ISAMEM_BASE, + .pfn = __phys_to_pfn(ISAMEM_PHYS), + .length = ISAMEM_SIZE, + .type = MT_DEVICE + } }; static void __init ebsa110_map_io(void) From a427ceef934d8162c8c61d152e969bc3ec21a4e5 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:08 +0100 Subject: [PATCH 0854/1939] [ARM] 2998/1: Replace map_desc.physical with map_desc.pfn: Footbridge Patch from Deepak Saxena Footbridge map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-footbridge/common.c | 57 ++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c index eb8238c1ef06..dc09fd200c16 100644 --- a/arch/arm/mach-footbridge/common.c +++ b/arch/arm/mach-footbridge/common.c @@ -130,8 +130,17 @@ void __init footbridge_init_irq(void) * it means that we have extra bullet protection on our feet. */ static struct map_desc fb_common_io_desc[] __initdata = { - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, MT_DEVICE }, - { XBUS_BASE, 0x40000000, XBUS_SIZE, MT_DEVICE } + { + .virtual = ARMCSR_BASE, + .pfn = DC21285_ARMCSR_BASE, + .length = ARMCSR_SIZE, + .type = MT_DEVICE + }, { + .virtual = XBUS_BASE, + .pfn = __phys_to_pfn(0x40000000), + .length = XBUS_SIZE, + .type = MT_DEVICE + } }; /* @@ -140,11 +149,32 @@ static struct map_desc fb_common_io_desc[] __initdata = { */ static struct map_desc ebsa285_host_io_desc[] __initdata = { #if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE }, - { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE }, - { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE }, - { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, MT_DEVICE }, - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE } + { + .virtual = PCIMEM_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_MEM), + .length = PCIMEM_SIZE, + .type = MT_DEVICE + }, { + .virtual = PCICFG0_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG), + .length = PCICFG0_SIZE, + .type = MT_DEVICE + }, { + .virtual = PCICFG1_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG), + .length = PCICFG1_SIZE, + .type = MT_DEVICE + }, { + .virtual = PCIIACK_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_IACK), + .length = PCIIACK_SIZE, + .type = MT_DEVICE + }, { + .virtual = PCIO_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_IO), + .length = PCIO_SIZE, + .type = MT_DEVICE + } #endif }; @@ -153,8 +183,17 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = { */ static struct map_desc co285_io_desc[] __initdata = { #ifdef CONFIG_ARCH_CO285 - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE }, - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE } + { + .virtual = PCIO_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_IO), + .length = PCIO_SIZE, + .type = MT_DEVICE + }, { + .virtual = PCIMEM_BASE, + .pfn = __phys_to_pfn(DC21285_PCI_MEM), + .length = PCIMEM_SIZE, + .type = MT_DEVICE + } #endif }; From 3e9635e4060238549ffac239de34f6122b053653 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:09 +0100 Subject: [PATCH 0855/1939] [ARM] 2999/1: Replace map_desc.physical with map_desc.pfn: H720x Patch from Deepak Saxena H720x map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-h720x/common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c index 5110e2e65ddd..c096b4569308 100644 --- a/arch/arm/mach-h720x/common.c +++ b/arch/arm/mach-h720x/common.c @@ -237,7 +237,12 @@ void __init h720x_init_irq (void) } static struct map_desc h720x_io_desc[] __initdata = { - { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, }; /* Initialize io tables */ From adecef744fc5b4e9316c851feec2a4d2640dd7ae Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:10 +0100 Subject: [PATCH 0856/1939] [ARM] 3000/1: Replace map_desc.physical with map_desc.pfn: iMX Patch from Deepak Saxena iMX map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-imx/generic.c | 8 ++++++-- arch/arm/mach-imx/mx1ads.c | 38 ++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index f8a742bb2d5b..cb14b0682cef 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -273,8 +273,12 @@ static struct platform_device *devices[] __initdata = { }; static struct map_desc imx_io_desc[] __initdata = { - /* virtual physical length type */ - {IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE}, + { + .virtual = IMX_IO_BASE, + .pfn = __phys_to_pfn(IMX_IO_PHYS), + .length = IMX_IO_SIZE, + .type = MT_DEVICE + } }; void __init diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index a7511ddfe364..4cbdc1fe04b1 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -61,13 +61,37 @@ mx1ads_init(void) } static struct map_desc mx1ads_io_desc[] __initdata = { - /* virtual physical length type */ - {IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE}, - {IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE}, - {IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE}, - {IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE}, - {IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE}, - {IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE}, + { + .virtual = IMX_CS0_VIRT, + .pfn = __phys_to_pfn(IMX_CS0_PHYS), + .length = IMX_CS0_SIZE, + .type = MT_DEVICE + }, { + .virtual = IMX_CS1_VIRT, + .pfn = __phys_to_pfn(IMX_CS1_PHYS), + .length = IMX_CS1_SIZE, + .type = MT_DEVICE + }, { + .virtual = IMX_CS2_VIRT, + .pfn = __phys_to_pfn(IMX_CS2_PHYS), + .length = IMX_CS2_SIZE, + .type = MT_DEVICE + }, { + .virtual = IMX_CS3_VIRT, + .pfn = __phys_to_pfn(IMX_CS3_PHYS), + .length = IMX_CS3_SIZE, + .type = MT_DEVICE + }, { + .virtual = IMX_CS4_VIRT, + .pfn = __phys_to_pfn(IMX_CS4_PHYS), + .length = IMX_CS4_SIZE, + .type = MT_DEVICE + }, { + .virtual = IMX_CS5_VIRT, + .pfn = __phys_to_pfn(IMX_CS5_PHYS), + .length = IMX_CS5_SIZE, + .type = MT_DEVICE + } }; static void __init From c8d2729858d76de4ef7522c8171004fc1959cc44 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:10 +0100 Subject: [PATCH 0857/1939] [ARM] 3001/1: Replace map_desc.physical with map_desc.pfn: Integrator Patch from Deepak Saxena Integrator map_desc.pfn conversion Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-integrator/integrator_ap.c | 79 ++++++++++++++++++++---- arch/arm/mach-integrator/integrator_cp.c | 67 ++++++++++++++++---- 2 files changed, 122 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 36e2b6eb67b7..f368b85f0447 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -75,19 +75,72 @@ */ static struct map_desc ap_io_desc[] __initdata = { - { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, - { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, - { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, - { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE }, - { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE } + { + .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = PCI_MEMORY_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = PCI_CONFIG_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = PCI_V3_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_V3_BASE), + .length = SZ_64K, + .type = MT_DEVICE + }, { + .virtual = PCI_IO_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_IO_BASE), + .length = SZ_64K, + .type = MT_DEVICE + } }; static void __init ap_map_io(void) diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 2be5c03ab87f..aa34c58b96c4 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -74,17 +74,62 @@ */ static struct map_desc intcp_io_desc[] __initdata = { - { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, - { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE }, - { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE }, + { + .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = 0xfca00000, + .pfn = __phys_to_pfn(0xca000000), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = 0xfcb00000, + .pfn = __phys_to_pfn(0xcb000000), + .length = SZ_4K, + .type = MT_DEVICE + } }; static void __init intcp_map_io(void) From 9769c2468d423a1562dd59a5db250bd0a5533ec9 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:11 +0100 Subject: [PATCH 0858/1939] [ARM] 3016/1: Replace map_desc.physical with map_desc.pfn Patch from Deepak Saxena Convert map_desc.physical to map_desc.pfn. This allows us to add support for 36-bit addressed physical devices in the static maps without having to resort to u64 variables. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mm/init.c | 12 ++++++------ arch/arm/mm/mm-armv.c | 8 ++++---- include/asm-arm/mach/map.h | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index d1f1ec73500f..f4496813615a 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -262,8 +262,8 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi) if (end_pfn < end) end_pfn = end; - map.physical = mi->bank[i].start; - map.virtual = __phys_to_virt(map.physical); + map.pfn = __phys_to_pfn(mi->bank[i].start); + map.virtual = __phys_to_virt(mi->bank[i].start); map.length = mi->bank[i].size; map.type = MT_MEMORY; @@ -365,7 +365,7 @@ static void __init bootmem_init(struct meminfo *mi) #ifdef CONFIG_XIP_KERNEL #error needs fixing - p->physical = CONFIG_XIP_PHYS_ADDR & PMD_MASK; + p->pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PMD_MASK); p->virtual = (unsigned long)&_stext & PMD_MASK; p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK; p->type = MT_ROM; @@ -439,14 +439,14 @@ static void __init devicemaps_init(struct machine_desc *mdesc) * Map the cache flushing regions. */ #ifdef FLUSH_BASE - map.physical = FLUSH_BASE_PHYS; + map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS); map.virtual = FLUSH_BASE; map.length = PGDIR_SIZE; map.type = MT_CACHECLEAN; create_mapping(&map); #endif #ifdef FLUSH_BASE_MINICACHE - map.physical = FLUSH_BASE_PHYS + PGDIR_SIZE; + map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + PGDIR_SIZE); map.virtual = FLUSH_BASE_MINICACHE; map.length = PGDIR_SIZE; map.type = MT_MINICLEAN; @@ -464,7 +464,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) * location (0xffff0000). If we aren't using high-vectors, also * create a mapping at the low-vectors virtual address. */ - map.physical = virt_to_phys(vectors); + map.pfn = __phys_to_pfn(virt_to_phys(vectors)); map.virtual = 0xffff0000; map.length = PAGE_SIZE; map.type = MT_HIGH_VECTORS; diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index c626361c0f5e..64db10e806b3 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -483,7 +483,7 @@ void __init create_mapping(struct map_desc *md) if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { printk(KERN_WARNING "BUG: not creating mapping for " "0x%08lx at 0x%08lx in user region\n", - md->physical, md->virtual); + __pfn_to_phys(md->pfn), md->virtual); return; } @@ -491,7 +491,7 @@ void __init create_mapping(struct map_desc *md) md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { printk(KERN_WARNING "BUG: mapping for 0x%08lx at 0x%08lx " "overlaps vmalloc space\n", - md->physical, md->virtual); + __pfn_to_phys(md->pfn), md->virtual); } domain = mem_types[md->type].domain; @@ -500,14 +500,14 @@ void __init create_mapping(struct map_desc *md) prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); virt = md->virtual; - off = md->physical - virt; + off = __pfn_to_phys(md->pfn) - virt; length = md->length; if (mem_types[md->type].prot_l1 == 0 && (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) { printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not " "be mapped using pages, ignoring.\n", - md->physical, md->virtual); + __pfn_to_phys(md->pfn), md->virtual); return; } diff --git a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h index 9ac47cf8d2e4..0619522bd926 100644 --- a/include/asm-arm/mach/map.h +++ b/include/asm-arm/mach/map.h @@ -11,7 +11,7 @@ */ struct map_desc { unsigned long virtual; - unsigned long physical; + unsigned long pfn; unsigned long length; unsigned int type; }; @@ -27,6 +27,9 @@ struct meminfo; #define MT_ROM 6 #define MT_IXP2000_DEVICE 7 +#define __phys_to_pfn(paddr) (paddr >> PAGE_SHIFT) +#define __pfn_to_phys(pfn) (pfn << PAGE_SHIFT) + extern void create_memmap_holes(struct meminfo *); extern void memtable_init(struct meminfo *); extern void iotable_init(struct map_desc *, int); From 0b7cd62ecdc1f09b7df4608a3fee644b1c27985b Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Fri, 28 Oct 2005 15:19:12 +0100 Subject: [PATCH 0859/1939] [ARM] 3017/1: Add support for 36-bit addresses to create_mapping() Patch from Deepak Saxena This patch adds support for 36-bit static mapped I/O. While there are no platforms in the tree ATM that use it, it has been tested tested on the IXP2350 NPU and I would like to get the support for that chipset upstream one piece at a time. There are also other Intel chipset ports in development that are waiting on this to go upstream. The patch replaces the print formats for physical addresses with %016llx which will create a bit extraneous output on 32-bit systems, but I think that is cleaner than having #ifdefs, specially since users will only see the output in error cases. Depends on 3016/1. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mm/mm-armv.c | 58 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 64db10e806b3..61bc2fa0511e 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -478,20 +478,20 @@ void __init create_mapping(struct map_desc *md) unsigned long virt, length; int prot_sect, prot_l1, domain; pgprot_t prot_pte; - long off; + unsigned long off = (u32)__pfn_to_phys(md->pfn); if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { printk(KERN_WARNING "BUG: not creating mapping for " - "0x%08lx at 0x%08lx in user region\n", - __pfn_to_phys(md->pfn), md->virtual); + "0x%016llx at 0x%08lx in user region\n", + __pfn_to_phys((u64)md->pfn), md->virtual); return; } if ((md->type == MT_DEVICE || md->type == MT_ROM) && md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { - printk(KERN_WARNING "BUG: mapping for 0x%08lx at 0x%08lx " + printk(KERN_WARNING "BUG: mapping for 0x%016llx at 0x%08lx " "overlaps vmalloc space\n", - __pfn_to_phys(md->pfn), md->virtual); + __pfn_to_phys((u64)md->pfn), md->virtual); } domain = mem_types[md->type].domain; @@ -499,8 +499,33 @@ void __init create_mapping(struct map_desc *md) prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain); prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); + /* + * Catch 36-bit addresses + */ + if(md->pfn >= 0x100000) { + if(domain) { + printk(KERN_ERR "MM: invalid domain in supersection " + "mapping for 0x%016llx at 0x%08lx\n", + __pfn_to_phys((u64)md->pfn), md->virtual); + return; + } + if((md->virtual | md->length | __pfn_to_phys(md->pfn)) + & ~SUPERSECTION_MASK) { + printk(KERN_ERR "MM: cannot create mapping for " + "0x%016llx at 0x%08lx invalid alignment\n", + __pfn_to_phys((u64)md->pfn), md->virtual); + return; + } + + /* + * Shift bits [35:32] of address into bits [23:20] of PMD + * (See ARMv6 spec). + */ + off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20); + } + virt = md->virtual; - off = __pfn_to_phys(md->pfn) - virt; + off -= virt; length = md->length; if (mem_types[md->type].prot_l1 == 0 && @@ -525,13 +550,22 @@ void __init create_mapping(struct map_desc *md) * of the actual domain assignments in use. */ if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) { - /* Align to supersection boundary */ - while ((virt & ~SUPERSECTION_MASK || (virt + off) & - ~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) { - alloc_init_section(virt, virt + off, prot_sect); + /* + * Align to supersection boundary if !high pages. + * High pages have already been checked for proper + * alignment above and they will fail the SUPSERSECTION_MASK + * check because of the way the address is encoded into + * offset. + */ + if (md->pfn <= 0x100000) { + while ((virt & ~SUPERSECTION_MASK || + (virt + off) & ~SUPERSECTION_MASK) && + length >= (PGDIR_SIZE / 2)) { + alloc_init_section(virt, virt + off, prot_sect); - virt += (PGDIR_SIZE / 2); - length -= (PGDIR_SIZE / 2); + virt += (PGDIR_SIZE / 2); + length -= (PGDIR_SIZE / 2); + } } while (length >= SUPERSECTION_SIZE) { From c09f98271f685af349d3f0199360f1c0e85550e0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 28 Oct 2005 15:26:40 +0100 Subject: [PATCH 0860/1939] [ARM] 2930/1: optimized sha1 implementation for ARM Patch from Nicolas Pitre Here's an ARM assembly SHA1 implementation to replace the default C version. It is approximately 50% faster than the generic C version. On an XScale processor running at 400MHz: generic C version: 9.8 MB/s my version: 14.5 MB/s This code is useful to quite a few callers in the tree: crypto/sha1.c: sha_transform(sctx->state, sctx->buffer, temp); crypto/sha1.c: sha_transform(sctx->state, &data[i], temp); drivers/char/random.c: sha_transform(buf, (__u8 *)r->pool+i, buf + 5); drivers/char/random.c: sha_transform(buf, (__u8 *)data, buf + 5); net/ipv4/syncookies.c: sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); Signed-off-by: Nicolas Pitre Seems to work fine on big-endian as well. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/lib/Makefile | 2 +- arch/arm/lib/sha1.S | 206 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 arch/arm/lib/sha1.S diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 8725d63e4219..71e5b99e519e 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -11,7 +11,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ strnlen_user.o strchr.o strrchr.o testchangebit.o \ testclearbit.o testsetbit.o uaccess.o getuser.o \ putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ - ucmpdi2.o lib1funcs.o div64.o \ + ucmpdi2.o lib1funcs.o div64.o sha1.o \ io-readsb.o io-writesb.o io-readsl.o io-writesl.o ifeq ($(CONFIG_CPU_32v3),y) diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S new file mode 100644 index 000000000000..ff6ece487ffc --- /dev/null +++ b/arch/arm/lib/sha1.S @@ -0,0 +1,206 @@ +/* + * linux/arch/arm/lib/sha1.S + * + * SHA transform optimized for ARM + * + * Copyright: (C) 2005 by Nicolas Pitre + * Created: September 17, 2005 + * + * 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. + * + * The reference implementation for this code is linux/lib/sha1.c + */ + +#include + + .text + + +/* + * void sha_transform(__u32 *digest, const char *in, __u32 *W) + * + * Note: the "in" ptr may be unaligned. + */ + +ENTRY(sha_transform) + + stmfd sp!, {r4 - r8, lr} + + @ for (i = 0; i < 16; i++) + @ W[i] = be32_to_cpu(in[i]); */ + +#ifdef __ARMEB__ + mov r4, r0 + mov r0, r2 + mov r2, #64 + bl memcpy + mov r2, r0 + mov r0, r4 +#else + mov r3, r2 + mov lr, #16 +1: ldrb r4, [r1], #1 + ldrb r5, [r1], #1 + ldrb r6, [r1], #1 + ldrb r7, [r1], #1 + subs lr, lr, #1 + orr r5, r5, r4, lsl #8 + orr r6, r6, r5, lsl #8 + orr r7, r7, r6, lsl #8 + str r7, [r3], #4 + bne 1b +#endif + + @ for (i = 0; i < 64; i++) + @ W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31); + + sub r3, r2, #4 + mov lr, #64 +2: ldr r4, [r3, #4]! + subs lr, lr, #1 + ldr r5, [r3, #8] + ldr r6, [r3, #32] + ldr r7, [r3, #52] + eor r4, r4, r5 + eor r4, r4, r6 + eor r4, r4, r7 + mov r4, r4, ror #31 + str r4, [r3, #64] + bne 2b + + /* + * The SHA functions are: + * + * f1(B,C,D) = (D ^ (B & (C ^ D))) + * f2(B,C,D) = (B ^ C ^ D) + * f3(B,C,D) = ((B & C) | (D & (B | C))) + * + * Then the sub-blocks are processed as follows: + * + * A' = ror(A, 27) + f(B,C,D) + E + K + *W++ + * B' = A + * C' = ror(B, 2) + * D' = C + * E' = D + * + * We therefore unroll each loop 5 times to avoid register shuffling. + * Also the ror for C (and also D and E which are successivelyderived + * from it) is applied in place to cut on an additional mov insn for + * each round. + */ + + .macro sha_f1, A, B, C, D, E + ldr r3, [r2], #4 + eor ip, \C, \D + add \E, r1, \E, ror #2 + and ip, \B, ip, ror #2 + add \E, \E, \A, ror #27 + eor ip, ip, \D, ror #2 + add \E, \E, r3 + add \E, \E, ip + .endm + + .macro sha_f2, A, B, C, D, E + ldr r3, [r2], #4 + add \E, r1, \E, ror #2 + eor ip, \B, \C, ror #2 + add \E, \E, \A, ror #27 + eor ip, ip, \D, ror #2 + add \E, \E, r3 + add \E, \E, ip + .endm + + .macro sha_f3, A, B, C, D, E + ldr r3, [r2], #4 + add \E, r1, \E, ror #2 + orr ip, \B, \C, ror #2 + add \E, \E, \A, ror #27 + and ip, ip, \D, ror #2 + add \E, \E, r3 + and r3, \B, \C, ror #2 + orr ip, ip, r3 + add \E, \E, ip + .endm + + ldmia r0, {r4 - r8} + + mov lr, #4 + ldr r1, .L_sha_K + 0 + + /* adjust initial values */ + mov r6, r6, ror #30 + mov r7, r7, ror #30 + mov r8, r8, ror #30 + +3: subs lr, lr, #1 + sha_f1 r4, r5, r6, r7, r8 + sha_f1 r8, r4, r5, r6, r7 + sha_f1 r7, r8, r4, r5, r6 + sha_f1 r6, r7, r8, r4, r5 + sha_f1 r5, r6, r7, r8, r4 + bne 3b + + ldr r1, .L_sha_K + 4 + mov lr, #4 + +4: subs lr, lr, #1 + sha_f2 r4, r5, r6, r7, r8 + sha_f2 r8, r4, r5, r6, r7 + sha_f2 r7, r8, r4, r5, r6 + sha_f2 r6, r7, r8, r4, r5 + sha_f2 r5, r6, r7, r8, r4 + bne 4b + + ldr r1, .L_sha_K + 8 + mov lr, #4 + +5: subs lr, lr, #1 + sha_f3 r4, r5, r6, r7, r8 + sha_f3 r8, r4, r5, r6, r7 + sha_f3 r7, r8, r4, r5, r6 + sha_f3 r6, r7, r8, r4, r5 + sha_f3 r5, r6, r7, r8, r4 + bne 5b + + ldr r1, .L_sha_K + 12 + mov lr, #4 + +6: subs lr, lr, #1 + sha_f2 r4, r5, r6, r7, r8 + sha_f2 r8, r4, r5, r6, r7 + sha_f2 r7, r8, r4, r5, r6 + sha_f2 r6, r7, r8, r4, r5 + sha_f2 r5, r6, r7, r8, r4 + bne 6b + + ldmia r0, {r1, r2, r3, ip, lr} + add r4, r1, r4 + add r5, r2, r5 + add r6, r3, r6, ror #2 + add r7, ip, r7, ror #2 + add r8, lr, r8, ror #2 + stmia r0, {r4 - r8} + + ldmfd sp!, {r4 - r8, pc} + +.L_sha_K: + .word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 + + +/* + * void sha_init(__u32 *buf) + */ + +.L_sha_initial_digest: + .word 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 + +ENTRY(sha_init) + + str lr, [sp, #-4]! + adr r1, .L_sha_initial_digest + ldmia r1, {r1, r2, r3, ip, lr} + stmia r0, {r1, r2, r3, ip, lr} + ldr pc, [sp], #4 + From 42d3a120fe9a1831b88e7037ce0b048d82433b09 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 28 Oct 2005 15:26:41 +0100 Subject: [PATCH 0861/1939] [ARM] 3033/1: S3C2410 - add generic gpio_cfgpin options Patch from Ben Dooks Add generic values for the parameters to the s3c2410_gpio_cfgpin() function, so that a caller does not need to know the exact constant for the specified pin. This is very useful for the case where a driver is passed a gpio pin number and needs to reconfigure the pin's function. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/gpio.c | 22 ++++++++++++++++++++++ include/asm-arm/arch-s3c2410/regs-gpio.h | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c index 94f1776cf312..23ea3d5fa09c 100644 --- a/arch/arm/mach-s3c2410/gpio.c +++ b/arch/arm/mach-s3c2410/gpio.c @@ -30,6 +30,7 @@ * 04-Oct-2004 BJD Added irq filter controls for GPIO * 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code * 13-Mar-2005 BJD Updates for __iomem + * 26-Oct-2005 BJD Added generic configuration types */ @@ -58,6 +59,27 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; } + switch (function) { + case S3C2410_GPIO_LEAVE: + mask = 0; + function = 0; + break; + + case S3C2410_GPIO_INPUT: + case S3C2410_GPIO_OUTPUT: + case S3C2410_GPIO_SFN2: + case S3C2410_GPIO_SFN3: + if (pin < S3C2410_GPIO_BANKB) { + function &= 1; + function <<= S3C2410_GPIO_OFFSET(pin); + } else { + function &= 3; + function <<= S3C2410_GPIO_OFFSET(pin)*2; + } + } + + /* modify the specified register wwith IRQs off */ + local_irq_save(flags); con = __raw_readl(base + 0x00); diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index 2053cbacffc3..cb33d57c146c 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -20,6 +20,7 @@ * 18-11-2004 BJD Added S3C2440 AC97 controls * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * 28-Mar-2005 LCVR Fixed definition of GPB10 + * 26-Oct-2005 BJD Added generic configuration types */ @@ -43,6 +44,11 @@ /* general configuration options */ #define S3C2410_GPIO_LEAVE (0xFFFFFFFF) +#define S3C2410_GPIO_INPUT (0xFFFFFFF0) +#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1) +#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */ +#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* not available on A */ +#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */ /* configure GPIO ports A..G */ From a0e0adb96ebe6bf0b8b3fe4cd6c214b1e8964609 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 28 Oct 2005 15:26:42 +0100 Subject: [PATCH 0862/1939] [ARM] 3034/1: S3C2410 - fix size of devices in devs.c Patch from Ben Dooks From: Guillaume GOURAT A number of devices have an extra byte on the end of their areas due to mis-calculating the .end field of their resources Signed-off-by: Guillaume GOURAT Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/devs.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index 0077937a7ab8..8a37236b04ab 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -47,7 +47,7 @@ struct platform_device *s3c24xx_uart_devs[3]; static struct resource s3c_usb_resource[] = { [0] = { .start = S3C2410_PA_USBHOST, - .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST, + .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -77,7 +77,7 @@ EXPORT_SYMBOL(s3c_device_usb); static struct resource s3c_lcd_resource[] = { [0] = { .start = S3C2410_PA_LCD, - .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD, + .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -117,7 +117,7 @@ EXPORT_SYMBOL(set_s3c2410fb_info); static struct resource s3c_nand_resource[] = { [0] = { .start = S3C2410_PA_NAND, - .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND, + .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1, .flags = IORESOURCE_MEM, } }; @@ -136,7 +136,7 @@ EXPORT_SYMBOL(s3c_device_nand); static struct resource s3c_usbgadget_resource[] = { [0] = { .start = S3C2410_PA_USBDEV, - .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV, + .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -161,7 +161,7 @@ EXPORT_SYMBOL(s3c_device_usbgadget); static struct resource s3c_wdt_resource[] = { [0] = { .start = S3C2410_PA_WATCHDOG, - .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG, + .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -186,7 +186,7 @@ EXPORT_SYMBOL(s3c_device_wdt); static struct resource s3c_i2c_resource[] = { [0] = { .start = S3C2410_PA_IIC, - .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC, + .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -211,7 +211,7 @@ EXPORT_SYMBOL(s3c_device_i2c); static struct resource s3c_iis_resource[] = { [0] = { .start = S3C2410_PA_IIS, - .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS, + .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS -1, .flags = IORESOURCE_MEM, } }; @@ -265,7 +265,7 @@ EXPORT_SYMBOL(s3c_device_rtc); static struct resource s3c_adc_resource[] = { [0] = { .start = S3C2410_PA_ADC, - .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC, + .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -288,7 +288,7 @@ struct platform_device s3c_device_adc = { static struct resource s3c_sdi_resource[] = { [0] = { .start = S3C2410_PA_SDI, - .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI, + .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -465,7 +465,7 @@ EXPORT_SYMBOL(s3c_device_timer3); static struct resource s3c_camif_resource[] = { [0] = { .start = S3C2440_PA_CAMIF, - .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF, + .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF - 1, .flags = IORESOURCE_MEM, }, [1] = { From 63a4b52c9ddca944afc1b78aacbf641c650780d7 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 28 Oct 2005 15:26:42 +0100 Subject: [PATCH 0863/1939] [ARM] 3044/1: Fix sparse warnings about incompatible pointer types for register defined in pxa-regs.h Patch from Ian Campbell The sparse warning initially surfaced in sound/arm/pxa2xx-ac97.c because it was using u32 * variables to hold the unsigned long * register addresses. I submitted an ALSA patch for this http://thread.gmane.org/gmane.linux.alsa.devel/27804 issue and it was suggested that it might be preferable to change the register definitions to use u32. Most other subarches seem to use u32 for their register type, at least the ones which use a __REG macro (like the PXA) do. Nico indicated in the thread above that he wouldn't mind this patch. Changing the type required fixes for opposite warnings in the pxa2xx usb gadget code but that was the only new warning introduced on defconfig or lubbock, mainstone and our own PXA255 boards. Signed-off-by: Ian Campbell Signed-off-by: Russell King --- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.h | 8 ++++---- include/asm-arm/arch-pxa/hardware.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 73f8c9404156..feae7c0c5dd9 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -422,7 +422,7 @@ static inline void ep0_idle (struct pxa2xx_udc *dev) } static int -write_packet(volatile unsigned long *uddr, struct pxa2xx_request *req, unsigned max) +write_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max) { u8 *buf; unsigned length, count; diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index a58f3e6e71f1..19a883f7d1b8 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -69,11 +69,11 @@ struct pxa2xx_ep { * UDDR = UDC Endpoint Data Register (the fifo) * DRCM = DMA Request Channel Map */ - volatile unsigned long *reg_udccs; - volatile unsigned long *reg_ubcr; - volatile unsigned long *reg_uddr; + volatile u32 *reg_udccs; + volatile u32 *reg_ubcr; + volatile u32 *reg_uddr; #ifdef USE_DMA - volatile unsigned long *reg_drcmr; + volatile u32 *reg_drcmr; #define drcmr(n) .reg_drcmr = & DRCMR ## n , #else #define drcmr(n) diff --git a/include/asm-arm/arch-pxa/hardware.h b/include/asm-arm/arch-pxa/hardware.h index cf35721cfa45..3e70bd95472c 100644 --- a/include/asm-arm/arch-pxa/hardware.h +++ b/include/asm-arm/arch-pxa/hardware.h @@ -44,12 +44,12 @@ #ifndef __ASSEMBLY__ -# define __REG(x) (*((volatile unsigned long *)io_p2v(x))) +# define __REG(x) (*((volatile u32 *)io_p2v(x))) /* With indexed regs we don't want to feed the index through io_p2v() especially if it is a variable, otherwise horrible code will result. */ # define __REG2(x,y) \ - (*(volatile unsigned long *)((unsigned long)&__REG(x) + (y))) + (*(volatile u32 *)((u32)&__REG(x) + (y))) # define __PREG(x) (io_v2p((u32)&(x))) From 3b90c9c33361d49893645ffcebe6ca230f434705 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 28 Oct 2005 15:31:45 +0100 Subject: [PATCH 0864/1939] [ARM] 2908/1: add register definitions for ixp2000 msf Patch from Lennert Buytenhek We already had a mapping for the msf, but we didn't have any register definitions for it yet. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/ixp2000-regs.h | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index 32aece069869..def089d693d2 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -392,4 +392,47 @@ #define WDT_RESET_ENABLE 0x01000000 +/* + * MSF registers. The IXP2400 and IXP2800 have somewhat different MSF + * units, but the registers that differ between the two don't overlap, + * so we can have one register list for both. + */ +#define IXP2000_MSF_REG(x) ((volatile unsigned long*)(IXP2000_MSF_VIRT_BASE + (x))) +#define IXP2000_MSF_RX_CONTROL IXP2000_MSF_REG(0x0000) +#define IXP2000_MSF_TX_CONTROL IXP2000_MSF_REG(0x0004) +#define IXP2000_MSF_INTERRUPT_STATUS IXP2000_MSF_REG(0x0008) +#define IXP2000_MSF_INTERRUPT_ENABLE IXP2000_MSF_REG(0x000c) +#define IXP2000_MSF_CSIX_TYPE_MAP IXP2000_MSF_REG(0x0010) +#define IXP2000_MSF_FC_EGRESS_STATUS IXP2000_MSF_REG(0x0014) +#define IXP2000_MSF_FC_INGRESS_STATUS IXP2000_MSF_REG(0x0018) +#define IXP2000_MSF_HWM_CONTROL IXP2000_MSF_REG(0x0024) +#define IXP2000_MSF_FC_STATUS_OVERRIDE IXP2000_MSF_REG(0x0028) +#define IXP2000_MSF_CLOCK_CONTROL IXP2000_MSF_REG(0x002c) +#define IXP2000_MSF_RX_PORT_MAP IXP2000_MSF_REG(0x0040) +#define IXP2000_MSF_RBUF_ELEMENT_DONE IXP2000_MSF_REG(0x0044) +#define IXP2000_MSF_RX_MPHY_POLL_LIMIT IXP2000_MSF_REG(0x0048) +#define IXP2000_MSF_RX_CALENDAR_LENGTH IXP2000_MSF_REG(0x0048) +#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_0 IXP2000_MSF_REG(0x0050) +#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_1 IXP2000_MSF_REG(0x0054) +#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_2 IXP2000_MSF_REG(0x0058) +#define IXP2000_MSF_TX_SEQUENCE_0 IXP2000_MSF_REG(0x0060) +#define IXP2000_MSF_TX_SEQUENCE_1 IXP2000_MSF_REG(0x0064) +#define IXP2000_MSF_TX_SEQUENCE_2 IXP2000_MSF_REG(0x0068) +#define IXP2000_MSF_TX_MPHY_POLL_LIMIT IXP2000_MSF_REG(0x0070) +#define IXP2000_MSF_TX_CALENDAR_LENGTH IXP2000_MSF_REG(0x0070) +#define IXP2000_MSF_RX_UP_CONTROL_0 IXP2000_MSF_REG(0x0080) +#define IXP2000_MSF_RX_UP_CONTROL_1 IXP2000_MSF_REG(0x0084) +#define IXP2000_MSF_RX_UP_CONTROL_2 IXP2000_MSF_REG(0x0088) +#define IXP2000_MSF_RX_UP_CONTROL_3 IXP2000_MSF_REG(0x008c) +#define IXP2000_MSF_TX_UP_CONTROL_0 IXP2000_MSF_REG(0x0090) +#define IXP2000_MSF_TX_UP_CONTROL_1 IXP2000_MSF_REG(0x0094) +#define IXP2000_MSF_TX_UP_CONTROL_2 IXP2000_MSF_REG(0x0098) +#define IXP2000_MSF_TX_UP_CONTROL_3 IXP2000_MSF_REG(0x009c) +#define IXP2000_MSF_TRAIN_DATA IXP2000_MSF_REG(0x00a0) +#define IXP2000_MSF_TRAIN_CALENDAR IXP2000_MSF_REG(0x00a4) +#define IXP2000_MSF_TRAIN_FLOW_CONTROL IXP2000_MSF_REG(0x00a8) +#define IXP2000_MSF_TX_CALENDAR_0 IXP2000_MSF_REG(0x1000) +#define IXP2000_MSF_RX_PORT_CALENDAR_STATUS IXP2000_MSF_REG(0x1400) + + #endif /* _IXP2000_H_ */ From 893b03094c2ed929648d76a29cbbfc9e215e8636 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 28 Oct 2005 15:31:45 +0100 Subject: [PATCH 0865/1939] [ARM] 3045/2: S3C2410 - change init for lcd platform data Patch from Ben Dooks Change set_s3c2410fb_info to s3c2410_fb_set_platdata and use kmalloc() for the copy of the information it is passed. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/devs.c | 16 ++++++++++------ arch/arm/mach-s3c2410/mach-h1940.c | 3 ++- include/asm-arm/arch-s3c2410/fb.h | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index 8a37236b04ab..08bc7d95a45d 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -103,14 +103,18 @@ struct platform_device s3c_device_lcd = { EXPORT_SYMBOL(s3c_device_lcd); -static struct s3c2410fb_mach_info s3c2410fb_info; - -void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info) +void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd) { - memcpy(&s3c2410fb_info,hard_s3c2410fb_info,sizeof(struct s3c2410fb_mach_info)); - s3c_device_lcd.dev.platform_data = &s3c2410fb_info; + struct s3c2410fb_mach_info *npd; + + npd = kmalloc(sizeof(*npd), GFP_KERNEL); + if (npd) { + memcpy(npd, pd, sizeof(*npd)); + s3c_device_lcd.dev.platform_data = npd; + } else { + printk(KERN_ERR "no memory for LCD platform data\n"); + } } -EXPORT_SYMBOL(set_s3c2410fb_info); /* NAND Controller */ diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index fb3cb01266e5..7efeaaad2361 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -25,6 +25,7 @@ * 14-Jan-2005 BJD Added clock init * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * 20-Sep-2005 BJD Added static to non-exported items + * 26-Oct-2005 BJD Changed name of fb init call */ #include @@ -164,7 +165,7 @@ static void __init h1940_init_irq(void) static void __init h1940_init(void) { - set_s3c2410fb_info(&h1940_lcdcfg); + s3c24xx_fb_set_platdata(&h1940_lcdcfg); } MACHINE_START(H1940, "IPAQ-H1940") diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h index ac57bc887d82..4790491ba9d0 100644 --- a/include/asm-arm/arch-s3c2410/fb.h +++ b/include/asm-arm/arch-s3c2410/fb.h @@ -13,6 +13,7 @@ * 07-Sep-2004 RTP Created file * 03-Nov-2004 BJD Updated and minor cleanups * 03-Aug-2005 RTP Renamed to fb.h + * 26-Oct-2005 BJD Changed name of platdata init */ #ifndef __ASM_ARM_FB_H @@ -64,6 +65,6 @@ struct s3c2410fb_mach_info { unsigned long lpcsel; }; -void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info); +extern void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *); #endif /* __ASM_ARM_FB_H */ From 58c8d570f30d65836b53903fbdf355707a19aa52 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 28 Oct 2005 15:31:46 +0100 Subject: [PATCH 0866/1939] [ARM] 3046/1: BAST - add framebuffer platform data Patch from Ben Dooks Add framebuffer platform data Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-bast.c | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 7b51bfd0ba6d..c1b5c63ec24a 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -32,6 +32,7 @@ * 25-Jul-2005 BJD Removed ASIX static mappings * 27-Jul-2005 BJD Ensure maximum frequency of i2c bus * 20-Sep-2005 BJD Added static to non-exported items + * 26-Oct-2005 BJD Added FB platform data */ #include @@ -61,8 +62,10 @@ #include #include #include + #include #include +#include #include #include @@ -399,6 +402,38 @@ static struct s3c2410_platform_i2c bast_i2c_info = { .max_freq = 130*1000, }; + +static struct s3c2410fb_mach_info __initdata bast_lcd_info = { + .width = 640, + .height = 480, + + .xres = { + .min = 320, + .max = 1024, + .defval = 640, + }, + + .yres = { + .min = 240, + .max = 600, + .defval = 480, + }, + + .bpp = { + .min = 4, + .max = 16, + .defval = 8, + }, + + .regs = { + .lcdcon1 = 0x00000176, + .lcdcon2 = 0x1d77c7c2, + .lcdcon3 = 0x013a7f13, + .lcdcon4 = 0x00000057, + .lcdcon5 = 0x00014b02, + } +}; + /* Standard BAST devices */ static struct platform_device *bast_devices[] __initdata = { @@ -454,6 +489,10 @@ static void __init bast_map_io(void) usb_simtec_init(); } +static void __init bast_init(void) +{ + s3c24xx_fb_set_platdata(&bast_lcd_info); +} MACHINE_START(BAST, "Simtec-BAST") /* Maintainer: Ben Dooks */ @@ -463,5 +502,6 @@ MACHINE_START(BAST, "Simtec-BAST") .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = bast_map_io, .init_irq = s3c24xx_init_irq, + .init_machine = bast_init, .timer = &s3c24xx_timer, MACHINE_END From 57718976141c2929bddd6219efb32c2abea8360c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 28 Oct 2005 15:31:47 +0100 Subject: [PATCH 0867/1939] [ARM] 3047/1: SMDK2440 - add framebuffer platform data Patch from Ben Dooks Add platform data for framebuffer for the onboard LCD module Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-smdk2440.c | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index 722ef46b630a..6950e61b7914 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -19,6 +19,7 @@ * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA * 14-Mar-2005 BJD void __iomem fixes * 20-Sep-2005 BJD Added static to non-exported items + * 26-Oct-2005 BJD Added framebuffer data */ #include @@ -41,7 +42,10 @@ //#include #include #include +#include + #include +#include #include "s3c2410.h" #include "s3c2440.h" @@ -86,6 +90,70 @@ static struct s3c2410_uartcfg smdk2440_uartcfgs[] = { } }; +/* LCD driver info */ + +static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = { + .regs = { + + .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | + S3C2410_LCDCON1_TFT | + S3C2410_LCDCON1_CLKVAL(0x04), + + .lcdcon2 = S3C2410_LCDCON2_VBPD(7) | + S3C2410_LCDCON2_LINEVAL(319) | + S3C2410_LCDCON2_VFPD(6) | + S3C2410_LCDCON2_VSPW(3), + + .lcdcon3 = S3C2410_LCDCON3_HBPD(19) | + S3C2410_LCDCON3_HOZVAL(239) | + S3C2410_LCDCON3_HFPD(7), + + .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | + S3C2410_LCDCON4_HSPW(3), + + .lcdcon5 = S3C2410_LCDCON5_FRM565 | + S3C2410_LCDCON5_INVVLINE | + S3C2410_LCDCON5_INVVFRAME | + S3C2410_LCDCON5_PWREN | + S3C2410_LCDCON5_HWSWP, + }, + +#if 0 + /* currently setup by downloader */ + .gpccon = 0xaa940659, + .gpccon_mask = 0xffffffff, + .gpcup = 0x0000ffff, + .gpcup_mask = 0xffffffff, + .gpdcon = 0xaa84aaa0, + .gpdcon_mask = 0xffffffff, + .gpdup = 0x0000faff, + .gpdup_mask = 0xffffffff, +#endif + + .lpcsel = ((0xCE6) & ~7) | 1<<4, + + .width = 240, + .height = 320, + + .xres = { + .min = 240, + .max = 240, + .defval = 240, + }, + + .yres = { + .min = 320, + .max = 320, + .defval = 320, + }, + + .bpp = { + .min = 16, + .max = 16, + .defval = 16, + }, +}; + static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, @@ -121,6 +189,8 @@ static void __init smdk2440_machine_init(void) s3c2410_gpio_setpin(S3C2410_GPF6, 0); s3c2410_gpio_setpin(S3C2410_GPF7, 0); + s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg); + s3c2410_pm_init(); } From b57235215933d5fde4013e2448223b934b4ac2b7 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 28 Oct 2005 15:31:48 +0100 Subject: [PATCH 0868/1939] [ARM] 3048/1: register i2s resources not i2c resources for the pxa i2s platform device Patch from Ian Campbell As noted by Uli Luckas in the comments of 3025 there is a typo in the i2s platform device. The i2s platform device refers to the i2c resources. Signed-off-by: Ian Campbell Signed-off-by: Russell King --- arch/arm/mach-pxa/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 2e9e1702c4b3..719b91e93fa2 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -293,7 +293,7 @@ static struct resource i2s_resources[] = { static struct platform_device i2s_device = { .name = "pxa2xx-i2s", .id = -1, - .resource = i2c_resources, + .resource = i2s_resources, .num_resources = ARRAY_SIZE(i2s_resources), }; From af4ca457eaf2d6682059c18463eb106e2ce58198 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 02:55:38 -0400 Subject: [PATCH 0869/1939] [PATCH] gfp_t: infrastructure Beginning of gfp_t annotations: - -Wbitwise added to CHECKFLAGS - old __bitwise renamed to __bitwise__ - __bitwise defined to either __bitwise__ or nothing, depending on __CHECK_ENDIAN__ being defined - gfp_t switched from __nocast to __bitwise__ - force cast to gfp_t added to __GFP_... constants - new helper - gfp_zone(); extracts zone bits out of gfp_t value and casts the result to int Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- Makefile | 2 +- fs/buffer.c | 2 +- include/linux/gfp.h | 39 ++++++++++++++++++++------------------- include/linux/types.h | 9 +++++++-- mm/mempolicy.c | 6 +++--- mm/page_alloc.c | 4 ++-- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index 1fa7e5343464..f1d121f23025 100644 --- a/Makefile +++ b/Makefile @@ -334,7 +334,7 @@ KALLSYMS = scripts/kallsyms PERL = perl CHECK = sparse -CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ $(CF) +CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS) diff --git a/fs/buffer.c b/fs/buffer.c index 1216c0d3c8ce..9657696fd6d7 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -502,7 +502,7 @@ static void free_more_memory(void) yield(); for_each_pgdat(pgdat) { - zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones; + zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones; if (*zones) try_to_free_pages(zones, GFP_NOFS); } diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 3010e172394d..c3779432a723 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -12,8 +12,8 @@ struct vm_area_struct; * GFP bitmasks.. */ /* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */ -#define __GFP_DMA 0x01u -#define __GFP_HIGHMEM 0x02u +#define __GFP_DMA ((__force gfp_t)0x01u) +#define __GFP_HIGHMEM ((__force gfp_t)0x02u) /* * Action modifiers - doesn't change the zoning @@ -26,24 +26,24 @@ struct vm_area_struct; * * __GFP_NORETRY: The VM implementation must not retry indefinitely. */ -#define __GFP_WAIT 0x10u /* Can wait and reschedule? */ -#define __GFP_HIGH 0x20u /* Should access emergency pools? */ -#define __GFP_IO 0x40u /* Can start physical IO? */ -#define __GFP_FS 0x80u /* Can call down to low-level FS? */ -#define __GFP_COLD 0x100u /* Cache-cold page required */ -#define __GFP_NOWARN 0x200u /* Suppress page allocation failure warning */ -#define __GFP_REPEAT 0x400u /* Retry the allocation. Might fail */ -#define __GFP_NOFAIL 0x800u /* Retry for ever. Cannot fail */ -#define __GFP_NORETRY 0x1000u /* Do not retry. Might fail */ -#define __GFP_NO_GROW 0x2000u /* Slab internal usage */ -#define __GFP_COMP 0x4000u /* Add compound page metadata */ -#define __GFP_ZERO 0x8000u /* Return zeroed page on success */ -#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */ -#define __GFP_NORECLAIM 0x20000u /* No realy zone reclaim during allocation */ -#define __GFP_HARDWALL 0x40000u /* Enforce hardwall cpuset memory allocs */ +#define __GFP_WAIT ((__force gfp_t)0x10u) /* Can wait and reschedule? */ +#define __GFP_HIGH ((__force gfp_t)0x20u) /* Should access emergency pools? */ +#define __GFP_IO ((__force gfp_t)0x40u) /* Can start physical IO? */ +#define __GFP_FS ((__force gfp_t)0x80u) /* Can call down to low-level FS? */ +#define __GFP_COLD ((__force gfp_t)0x100u) /* Cache-cold page required */ +#define __GFP_NOWARN ((__force gfp_t)0x200u) /* Suppress page allocation failure warning */ +#define __GFP_REPEAT ((__force gfp_t)0x400u) /* Retry the allocation. Might fail */ +#define __GFP_NOFAIL ((__force gfp_t)0x800u) /* Retry for ever. Cannot fail */ +#define __GFP_NORETRY ((__force gfp_t)0x1000u)/* Do not retry. Might fail */ +#define __GFP_NO_GROW ((__force gfp_t)0x2000u)/* Slab internal usage */ +#define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */ +#define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */ +#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */ +#define __GFP_NORECLAIM ((__force gfp_t)0x20000u) /* No realy zone reclaim during allocation */ +#define __GFP_HARDWALL ((__force gfp_t)0x40000u) /* Enforce hardwall cpuset memory allocs */ #define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */ -#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) +#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) /* if you forget to add the bitmask here kernel will crash, period */ #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \ @@ -64,6 +64,7 @@ struct vm_area_struct; #define GFP_DMA __GFP_DMA +#define gfp_zone(mask) ((__force int)((mask) & (__force gfp_t)GFP_ZONEMASK)) /* * There is only one page-allocator function, and two main namespaces to @@ -94,7 +95,7 @@ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, return NULL; return __alloc_pages(gfp_mask, order, - NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK)); + NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_mask)); } #ifdef CONFIG_NUMA diff --git a/include/linux/types.h b/include/linux/types.h index 0aee34f9da9f..21b9ce803644 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -151,7 +151,12 @@ typedef unsigned long sector_t; */ #ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) +#define __bitwise__ __attribute__((bitwise)) +#else +#define __bitwise__ +#endif +#ifdef __CHECK_ENDIAN__ +#define __bitwise __bitwise__ #else #define __bitwise #endif @@ -166,7 +171,7 @@ typedef __u64 __bitwise __be64; #endif #ifdef __KERNEL__ -typedef unsigned __nocast gfp_t; +typedef unsigned __bitwise__ gfp_t; #endif struct ustat { diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 37af443eb094..1d5c64df1653 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -700,7 +700,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy) case MPOL_BIND: /* Lower zones don't get a policy applied */ /* Careful: current->mems_allowed might have moved */ - if ((gfp & GFP_ZONEMASK) >= policy_zone) + if (gfp_zone(gfp) >= policy_zone) if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist)) return policy->v.zonelist; /*FALL THROUGH*/ @@ -712,7 +712,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy) nd = 0; BUG(); } - return NODE_DATA(nd)->node_zonelists + (gfp & GFP_ZONEMASK); + return NODE_DATA(nd)->node_zonelists + gfp_zone(gfp); } /* Do dynamic interleaving for a process */ @@ -757,7 +757,7 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order, unsigned ni struct page *page; BUG_ON(!node_online(nid)); - zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK); + zl = NODE_DATA(nid)->node_zonelists + gfp_zone(gfp); page = __alloc_pages(gfp, order, zl); if (page && page_zone(page) == zl->zones[0]) { zone_pcp(zl->zones[0],get_cpu())->interleave_hit++; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index e1d3d77f4aee..aa43ae3ab8c9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1089,7 +1089,7 @@ static unsigned int nr_free_zone_pages(int offset) */ unsigned int nr_free_buffer_pages(void) { - return nr_free_zone_pages(GFP_USER & GFP_ZONEMASK); + return nr_free_zone_pages(gfp_zone(GFP_USER)); } /* @@ -1097,7 +1097,7 @@ unsigned int nr_free_buffer_pages(void) */ unsigned int nr_free_pagecache_pages(void) { - return nr_free_zone_pages(GFP_HIGHUSER & GFP_ZONEMASK); + return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER)); } #ifdef CONFIG_HIGHMEM From 6daa0e28627abf362138244a620a821a9027d816 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:18:50 -0400 Subject: [PATCH 0870/1939] [PATCH] gfp_t: mm/* (easy parts) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 +- include/linux/pagemap.h | 6 +++--- include/linux/slab.h | 2 +- include/linux/swap.h | 4 ++-- mm/filemap.c | 8 ++++---- mm/mempool.c | 2 +- mm/shmem.c | 4 ++-- mm/slab.c | 8 ++++---- mm/vmscan.c | 8 ++++---- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 097b3a3c693d..e1649578fb0c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -747,7 +747,7 @@ extern unsigned long do_mremap(unsigned long addr, * The callback will be passed nr_to_scan == 0 when the VM is querying the * cache size, so a fastpath for that case is appropriate. */ -typedef int (*shrinker_t)(int nr_to_scan, unsigned int gfp_mask); +typedef int (*shrinker_t)(int nr_to_scan, gfp_t gfp_mask); /* * Add an aging callback. The int is the number of 'seeks' it takes diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index acbf31c154f8..efbae53fb078 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -69,7 +69,7 @@ extern struct page * find_lock_page(struct address_space *mapping, extern struct page * find_trylock_page(struct address_space *mapping, unsigned long index); extern struct page * find_or_create_page(struct address_space *mapping, - unsigned long index, unsigned int gfp_mask); + unsigned long index, gfp_t gfp_mask); unsigned find_get_pages(struct address_space *mapping, pgoff_t start, unsigned int nr_pages, struct page **pages); unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, @@ -92,9 +92,9 @@ extern int read_cache_pages(struct address_space *mapping, struct list_head *pages, filler_t *filler, void *data); int add_to_page_cache(struct page *page, struct address_space *mapping, - unsigned long index, int gfp_mask); + unsigned long index, gfp_t gfp_mask); int add_to_page_cache_lru(struct page *page, struct address_space *mapping, - unsigned long index, int gfp_mask); + unsigned long index, gfp_t gfp_mask); extern void remove_from_page_cache(struct page *page); extern void __remove_from_page_cache(struct page *page); diff --git a/include/linux/slab.h b/include/linux/slab.h index 5fc04a16ecb0..09b9aa60063d 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -121,7 +121,7 @@ extern unsigned int ksize(const void *); extern void *kmem_cache_alloc_node(kmem_cache_t *, gfp_t flags, int node); extern void *kmalloc_node(size_t size, gfp_t flags, int node); #else -static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node) +static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int node) { return kmem_cache_alloc(cachep, flags); } diff --git a/include/linux/swap.h b/include/linux/swap.h index a7bf1a3b1496..20c975642cab 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -171,8 +171,8 @@ extern int rotate_reclaimable_page(struct page *page); extern void swap_setup(void); /* linux/mm/vmscan.c */ -extern int try_to_free_pages(struct zone **, unsigned int); -extern int zone_reclaim(struct zone *, unsigned int, unsigned int); +extern int try_to_free_pages(struct zone **, gfp_t); +extern int zone_reclaim(struct zone *, gfp_t, unsigned int); extern int shrink_all_memory(int); extern int vm_swappiness; diff --git a/mm/filemap.c b/mm/filemap.c index b5346576e58d..1c31b2fd2ca5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -377,7 +377,7 @@ int filemap_write_and_wait_range(struct address_space *mapping, * This function does not add the page to the LRU. The caller must do that. */ int add_to_page_cache(struct page *page, struct address_space *mapping, - pgoff_t offset, int gfp_mask) + pgoff_t offset, gfp_t gfp_mask) { int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); @@ -401,7 +401,7 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, EXPORT_SYMBOL(add_to_page_cache); int add_to_page_cache_lru(struct page *page, struct address_space *mapping, - pgoff_t offset, int gfp_mask) + pgoff_t offset, gfp_t gfp_mask) { int ret = add_to_page_cache(page, mapping, offset, gfp_mask); if (ret == 0) @@ -591,7 +591,7 @@ EXPORT_SYMBOL(find_lock_page); * memory exhaustion. */ struct page *find_or_create_page(struct address_space *mapping, - unsigned long index, unsigned int gfp_mask) + unsigned long index, gfp_t gfp_mask) { struct page *page, *cached_page = NULL; int err; @@ -683,7 +683,7 @@ struct page * grab_cache_page_nowait(struct address_space *mapping, unsigned long index) { struct page *page = find_get_page(mapping, index); - unsigned int gfp_mask; + gfp_t gfp_mask; if (page) { if (!TestSetPageLocked(page)) diff --git a/mm/mempool.c b/mm/mempool.c index 9e377ea700b2..1a99b80480d3 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -205,7 +205,7 @@ void * mempool_alloc(mempool_t *pool, gfp_t gfp_mask) void *element; unsigned long flags; wait_queue_t wait; - unsigned int gfp_temp; + gfp_t gfp_temp; might_sleep_if(gfp_mask & __GFP_WAIT); diff --git a/mm/shmem.c b/mm/shmem.c index ea064d89cda9..55e04a0734c1 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -85,7 +85,7 @@ enum sgp_type { static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **pagep, enum sgp_type sgp, int *type); -static inline struct page *shmem_dir_alloc(unsigned int gfp_mask) +static inline struct page *shmem_dir_alloc(gfp_t gfp_mask) { /* * The above definition of ENTRIES_PER_PAGE, and the use of @@ -898,7 +898,7 @@ struct page *shmem_swapin(struct shmem_inode_info *info, swp_entry_t entry, } static struct page * -shmem_alloc_page(unsigned long gfp, struct shmem_inode_info *info, +shmem_alloc_page(gfp_t gfp, struct shmem_inode_info *info, unsigned long idx) { struct vm_area_struct pvma; diff --git a/mm/slab.c b/mm/slab.c index d05c678bceb3..d30423f167a2 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -386,7 +386,7 @@ struct kmem_cache_s { unsigned int gfporder; /* force GFP flags, e.g. GFP_DMA */ - unsigned int gfpflags; + gfp_t gfpflags; size_t colour; /* cache colouring range */ unsigned int colour_off; /* colour offset */ @@ -2117,7 +2117,7 @@ static void cache_init_objs(kmem_cache_t *cachep, slabp->free = 0; } -static void kmem_flagcheck(kmem_cache_t *cachep, unsigned int flags) +static void kmem_flagcheck(kmem_cache_t *cachep, gfp_t flags) { if (flags & SLAB_DMA) { if (!(cachep->gfpflags & GFP_DMA)) @@ -2152,7 +2152,7 @@ static int cache_grow(kmem_cache_t *cachep, gfp_t flags, int nodeid) struct slab *slabp; void *objp; size_t offset; - unsigned int local_flags; + gfp_t local_flags; unsigned long ctor_flags; struct kmem_list3 *l3; @@ -2546,7 +2546,7 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags) /* * A interface to enable slab creation on nodeid */ -static void *__cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) +static void *__cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid) { struct list_head *entry; struct slab *slabp; diff --git a/mm/vmscan.c b/mm/vmscan.c index 64f9570cff56..843c87d1e61f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -70,7 +70,7 @@ struct scan_control { unsigned int priority; /* This context's GFP mask */ - unsigned int gfp_mask; + gfp_t gfp_mask; int may_writepage; @@ -186,7 +186,7 @@ EXPORT_SYMBOL(remove_shrinker); * * Returns the number of slab objects which we shrunk. */ -static int shrink_slab(unsigned long scanned, unsigned int gfp_mask, +static int shrink_slab(unsigned long scanned, gfp_t gfp_mask, unsigned long lru_pages) { struct shrinker *shrinker; @@ -926,7 +926,7 @@ shrink_caches(struct zone **zones, struct scan_control *sc) * holds filesystem locks which prevent writeout this might not work, and the * allocation attempt will fail. */ -int try_to_free_pages(struct zone **zones, unsigned int gfp_mask) +int try_to_free_pages(struct zone **zones, gfp_t gfp_mask) { int priority; int ret = 0; @@ -1338,7 +1338,7 @@ module_init(kswapd_init) /* * Try to free up some pages from this zone through reclaim. */ -int zone_reclaim(struct zone *zone, unsigned int gfp_mask, unsigned int order) +int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) { struct scan_control sc; int nr_pages = 1 << order; From fd4f2df24bc23e6b8fc069765b425c7dacf52347 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:18:50 -0400 Subject: [PATCH 0871/1939] [PATCH] gfp_t: lib/* Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/idr.h | 2 +- include/linux/kobject.h | 2 +- include/linux/radix-tree.h | 2 +- include/linux/textsearch.h | 4 ++-- lib/idr.c | 2 +- lib/kobject.c | 2 +- lib/kobject_uevent.c | 4 ++-- lib/textsearch.c | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/linux/idr.h b/include/linux/idr.h index 3d5de45f961b..7fb3ff9c7b0e 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -71,7 +71,7 @@ struct idr { */ void *idr_find(struct idr *idp, int id); -int idr_pre_get(struct idr *idp, unsigned gfp_mask); +int idr_pre_get(struct idr *idp, gfp_t gfp_mask); int idr_get_new(struct idr *idp, void *ptr, int *id); int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); void idr_remove(struct idr *idp, int id); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 3b22304f12fd..7f7403aa4a41 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -65,7 +65,7 @@ extern void kobject_unregister(struct kobject *); extern struct kobject * kobject_get(struct kobject *); extern void kobject_put(struct kobject *); -extern char * kobject_get_path(struct kobject *, int); +extern char * kobject_get_path(struct kobject *, gfp_t); struct kobj_type { void (*release)(struct kobject *); diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 045d4761febc..9f0f9281f42a 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -24,7 +24,7 @@ struct radix_tree_root { unsigned int height; - unsigned int gfp_mask; + gfp_t gfp_mask; struct radix_tree_node *rnode; }; diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h index 515046d1b2f4..fc5bb4e91a58 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -40,7 +40,7 @@ struct ts_state struct ts_ops { const char *name; - struct ts_config * (*init)(const void *, unsigned int, int); + struct ts_config * (*init)(const void *, unsigned int, gfp_t); unsigned int (*find)(struct ts_config *, struct ts_state *); void (*destroy)(struct ts_config *); @@ -148,7 +148,7 @@ static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf) extern int textsearch_register(struct ts_ops *); extern int textsearch_unregister(struct ts_ops *); extern struct ts_config *textsearch_prepare(const char *, const void *, - unsigned int, int, int); + unsigned int, gfp_t, int); extern void textsearch_destroy(struct ts_config *conf); extern unsigned int textsearch_find_continuous(struct ts_config *, struct ts_state *, diff --git a/lib/idr.c b/lib/idr.c index d4df21debc4d..6414b2fb482d 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -72,7 +72,7 @@ static void free_layer(struct idr *idp, struct idr_layer *p) * If the system is REALLY out of memory this function returns 0, * otherwise 1. */ -int idr_pre_get(struct idr *idp, unsigned gfp_mask) +int idr_pre_get(struct idr *idp, gfp_t gfp_mask) { while (idp->id_free_cnt < IDR_FREE_MAX) { struct idr_layer *new; diff --git a/lib/kobject.c b/lib/kobject.c index dd0917dd9fa9..253d3004ace9 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -100,7 +100,7 @@ static void fill_kobj_path(struct kobject *kobj, char *path, int length) * @kobj: kobject in question, with which to build the path * @gfp_mask: the allocation type used to allocate the path */ -char *kobject_get_path(struct kobject *kobj, int gfp_mask) +char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) { char *path; int len; diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 04ca4429ddfa..7ef6f6a17aa6 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -62,7 +62,7 @@ static struct sock *uevent_sock; * @gfp_mask: */ static int send_uevent(const char *signal, const char *obj, - char **envp, int gfp_mask) + char **envp, gfp_t gfp_mask) { struct sk_buff *skb; char *pos; @@ -98,7 +98,7 @@ static int send_uevent(const char *signal, const char *obj, } static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action, - struct attribute *attr, int gfp_mask) + struct attribute *attr, gfp_t gfp_mask) { char *path; char *attrpath; diff --git a/lib/textsearch.c b/lib/textsearch.c index 1e934c196f0f..6f3093efbd7b 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c @@ -254,7 +254,7 @@ unsigned int textsearch_find_continuous(struct ts_config *conf, * parameters or a ERR_PTR(). */ struct ts_config *textsearch_prepare(const char *algo, const void *pattern, - unsigned int len, int gfp_mask, int flags) + unsigned int len, gfp_t gfp_mask, int flags) { int err = -ENOENT; struct ts_config *conf; From 7d877f3bda870ab5f001bd92528654471d5966b3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:20:43 -0400 Subject: [PATCH 0872/1939] [PATCH] gfp_t: net/* Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/security.h | 2 +- include/net/sock.h | 2 +- net/core/sock.c | 2 +- net/dccp/output.c | 2 +- net/netlink/af_netlink.c | 2 +- security/dummy.c | 2 +- security/selinux/hooks.c | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index 627382e74057..dac956ed98f0 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1210,7 +1210,7 @@ struct security_operations { int (*socket_shutdown) (struct socket * sock, int how); int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb); int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len); - int (*sk_alloc_security) (struct sock *sk, int family, int priority); + int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); void (*sk_free_security) (struct sock *sk); #endif /* CONFIG_SECURITY_NETWORK */ }; diff --git a/include/net/sock.h b/include/net/sock.h index ecb75526cba0..e0498bd36004 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -207,7 +207,7 @@ struct sock { struct sk_buff_head sk_write_queue; int sk_wmem_queued; int sk_forward_alloc; - unsigned int sk_allocation; + gfp_t sk_allocation; int sk_sndbuf; int sk_route_caps; unsigned long sk_flags; diff --git a/net/core/sock.c b/net/core/sock.c index 1c52fe809eda..9602ceb3bac9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -940,7 +940,7 @@ static struct sk_buff *sock_alloc_send_pskb(struct sock *sk, int noblock, int *errcode) { struct sk_buff *skb; - unsigned int gfp_mask; + gfp_t gfp_mask; long timeo; int err; diff --git a/net/dccp/output.c b/net/dccp/output.c index 29250749f16f..d59f86f7ceab 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -495,7 +495,7 @@ void dccp_send_close(struct sock *sk, const int active) { struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; - const unsigned int prio = active ? GFP_KERNEL : GFP_ATOMIC; + const gfp_t prio = active ? GFP_KERNEL : GFP_ATOMIC; skb = alloc_skb(sk->sk_prot->max_header, prio); if (skb == NULL) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 678c3f2c0d0b..291df2e4c492 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -827,7 +827,7 @@ struct netlink_broadcast_data { int failure; int congested; int delivered; - unsigned int allocation; + gfp_t allocation; struct sk_buff *skb, *skb2; }; diff --git a/security/dummy.c b/security/dummy.c index 9623a61dfc76..3d34f3de7e82 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -768,7 +768,7 @@ static int dummy_socket_getpeersec(struct socket *sock, char __user *optval, return -ENOPROTOOPT; } -static inline int dummy_sk_alloc_security (struct sock *sk, int family, int priority) +static inline int dummy_sk_alloc_security (struct sock *sk, int family, gfp_t priority) { return 0; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b13be15165f5..447a1e0f48cb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -262,7 +262,7 @@ static void superblock_free_security(struct super_block *sb) } #ifdef CONFIG_SECURITY_NETWORK -static int sk_alloc_security(struct sock *sk, int family, int priority) +static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) { struct sk_security_struct *ssec; @@ -3380,7 +3380,7 @@ static int selinux_socket_getpeersec(struct socket *sock, char __user *optval, return err; } -static int selinux_sk_alloc_security(struct sock *sk, int family, int priority) +static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) { return sk_alloc_security(sk, family, priority); } From 27496a8c67bef4d789d8e3c8317ca35813a507ae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:20:48 -0400 Subject: [PATCH 0873/1939] [PATCH] gfp_t: fs/* - ->releasepage() annotated (s/int/gfp_t), instances updated - missing gfp_t in fs/* added - fixed misannotation from the original sweep caught by bitwise checks: XFS used __nocast both for gfp_t and for flags used by XFS allocator. The latter left with unsigned int __nocast; we might want to add a different type for those but for now let's leave them alone. That, BTW, is a case when __nocast use had been actively confusing - it had been used in the same code for two different and similar types, with no way to catch misuses. Switch of gfp_t to bitwise had caught that immediately... One tricky bit is left alone to be dealt with later - mapping->flags is a mix of gfp_t and error indications. Left alone for now. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/afs/file.c | 4 ++-- fs/bio.c | 4 ++-- fs/buffer.c | 2 +- fs/dcache.c | 2 +- fs/dquot.c | 2 +- fs/ext3/inode.c | 2 +- fs/hfs/inode.c | 2 +- fs/hfsplus/inode.c | 2 +- fs/inode.c | 2 +- fs/jbd/journal.c | 2 +- fs/jbd/transaction.c | 2 +- fs/jfs/jfs_metapage.c | 4 ++-- fs/mbcache.c | 6 +++--- fs/reiserfs/fix_node.c | 2 +- fs/reiserfs/inode.c | 2 +- fs/xfs/linux-2.6/kmem.c | 22 +++++++++++----------- fs/xfs/linux-2.6/kmem.h | 18 +++++++++--------- fs/xfs/linux-2.6/xfs_aops.c | 2 +- fs/xfs/linux-2.6/xfs_buf.c | 8 ++++---- include/linux/bio.h | 2 +- include/linux/buffer_head.h | 2 +- include/linux/fs.h | 2 +- include/linux/jbd.h | 4 ++-- include/linux/mbcache.h | 2 +- include/linux/reiserfs_fs.h | 2 +- 25 files changed, 52 insertions(+), 52 deletions(-) diff --git a/fs/afs/file.c b/fs/afs/file.c index 23c125128024..0d576987ec67 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -29,7 +29,7 @@ static int afs_file_release(struct inode *inode, struct file *file); static int afs_file_readpage(struct file *file, struct page *page); static int afs_file_invalidatepage(struct page *page, unsigned long offset); -static int afs_file_releasepage(struct page *page, int gfp_flags); +static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); static ssize_t afs_file_write(struct file *file, const char __user *buf, size_t size, loff_t *off); @@ -279,7 +279,7 @@ static int afs_file_invalidatepage(struct page *page, unsigned long offset) /* * release a page and cleanup its private data */ -static int afs_file_releasepage(struct page *page, int gfp_flags) +static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) { struct cachefs_page *pageio; diff --git a/fs/bio.c b/fs/bio.c index 7d81a93afd48..460554b07ff9 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -778,7 +778,7 @@ static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err) static struct bio *__bio_map_kern(request_queue_t *q, void *data, - unsigned int len, unsigned int gfp_mask) + unsigned int len, gfp_t gfp_mask) { unsigned long kaddr = (unsigned long)data; unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -825,7 +825,7 @@ static struct bio *__bio_map_kern(request_queue_t *q, void *data, * device. Returns an error pointer in case of error. */ struct bio *bio_map_kern(request_queue_t *q, void *data, unsigned int len, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct bio *bio; diff --git a/fs/buffer.c b/fs/buffer.c index 9657696fd6d7..b1667986442f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1571,7 +1571,7 @@ static inline void discard_buffer(struct buffer_head * bh) * * NOTE: @gfp_mask may go away, and this function may become non-blocking. */ -int try_to_release_page(struct page *page, int gfp_mask) +int try_to_release_page(struct page *page, gfp_t gfp_mask) { struct address_space * const mapping = page->mapping; diff --git a/fs/dcache.c b/fs/dcache.c index fb10386c59be..e90512ed35a4 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -689,7 +689,7 @@ void shrink_dcache_anon(struct hlist_head *head) * * In this case we return -1 to tell the caller that we baled. */ -static int shrink_dcache_memory(int nr, unsigned int gfp_mask) +static int shrink_dcache_memory(int nr, gfp_t gfp_mask) { if (nr) { if (!(gfp_mask & __GFP_FS)) diff --git a/fs/dquot.c b/fs/dquot.c index b9732335bcdc..05f3327d64a3 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -500,7 +500,7 @@ static void prune_dqcache(int count) * more memory */ -static int shrink_dqcache_memory(int nr, unsigned int gfp_mask) +static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) { if (nr) { spin_lock(&dq_list_lock); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b5177c90d6f1..8b38f2232796 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1434,7 +1434,7 @@ static int ext3_invalidatepage(struct page *page, unsigned long offset) return journal_invalidatepage(journal, page, offset); } -static int ext3_releasepage(struct page *page, int wait) +static int ext3_releasepage(struct page *page, gfp_t wait) { journal_t *journal = EXT3_JOURNAL(page->mapping->host); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index f1570b9f9de3..3f680c5675bf 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -46,7 +46,7 @@ static sector_t hfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, hfs_get_block); } -static int hfs_releasepage(struct page *page, int mask) +static int hfs_releasepage(struct page *page, gfp_t mask) { struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index d5642705f633..f205773ddfbe 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -40,7 +40,7 @@ static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, hfsplus_get_block); } -static int hfsplus_releasepage(struct page *page, int mask) +static int hfsplus_releasepage(struct page *page, gfp_t mask) { struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; diff --git a/fs/inode.c b/fs/inode.c index f80a79ff156b..7d3316527767 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -475,7 +475,7 @@ static void prune_icache(int nr_to_scan) * This function is passed the number of inodes to scan, and it returns the * total number of remaining possibly-reclaimable inodes. */ -static int shrink_icache_memory(int nr, unsigned int gfp_mask) +static int shrink_icache_memory(int nr, gfp_t gfp_mask) { if (nr) { /* diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 7ae2c4fe506b..e4b516ac4989 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1606,7 +1606,7 @@ int journal_blocks_per_page(struct inode *inode) * Simple support for retrying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ -void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry) +void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) { return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); } diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 49bbc2be3d72..13cb05bf6048 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1621,7 +1621,7 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) * while the data is part of a transaction. Yes? */ int journal_try_to_free_buffers(journal_t *journal, - struct page *page, int unused_gfp_mask) + struct page *page, gfp_t unused_gfp_mask) { struct buffer_head *head; struct buffer_head *bh; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 13d7e3f1feb4..eeb37d70e650 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -198,7 +198,7 @@ static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) } } -static inline struct metapage *alloc_metapage(unsigned int gfp_mask) +static inline struct metapage *alloc_metapage(gfp_t gfp_mask) { return mempool_alloc(metapage_mempool, gfp_mask); } @@ -534,7 +534,7 @@ static int metapage_readpage(struct file *fp, struct page *page) return -EIO; } -static int metapage_releasepage(struct page *page, int gfp_mask) +static int metapage_releasepage(struct page *page, gfp_t gfp_mask) { struct metapage *mp; int busy = 0; diff --git a/fs/mbcache.c b/fs/mbcache.c index b002a088857d..298997f17475 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -116,7 +116,7 @@ mb_cache_indexes(struct mb_cache *cache) * What the mbcache registers as to get shrunk dynamically. */ -static int mb_cache_shrink_fn(int nr_to_scan, unsigned int gfp_mask); +static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask); static inline int @@ -140,7 +140,7 @@ __mb_cache_entry_unhash(struct mb_cache_entry *ce) static inline void -__mb_cache_entry_forget(struct mb_cache_entry *ce, int gfp_mask) +__mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask) { struct mb_cache *cache = ce->e_cache; @@ -193,7 +193,7 @@ __mb_cache_entry_release_unlock(struct mb_cache_entry *ce) * Returns the number of objects which are present in the cache. */ static int -mb_cache_shrink_fn(int nr_to_scan, unsigned int gfp_mask) +mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask) { LIST_HEAD(free_list); struct list_head *l, *ltmp; diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 2706e2adffab..45829889dcdc 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -2022,7 +2022,7 @@ static int get_neighbors(struct tree_balance *p_s_tb, int n_h) } #ifdef CONFIG_REISERFS_CHECK -void *reiserfs_kmalloc(size_t size, int flags, struct super_block *s) +void *reiserfs_kmalloc(size_t size, gfp_t flags, struct super_block *s) { void *vp; static size_t malloced; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index d76ee6c4f9b8..5f82352b97e1 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2842,7 +2842,7 @@ static int reiserfs_set_page_dirty(struct page *page) * even in -o notail mode, we can't be sure an old mount without -o notail * didn't create files with tails. */ -static int reiserfs_releasepage(struct page *page, int unused_gfp_flags) +static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags) { struct inode *inode = page->mapping->host; struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb); diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index d2653b589b1c..3c92162dc728 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -45,11 +45,11 @@ void * -kmem_alloc(size_t size, gfp_t flags) +kmem_alloc(size_t size, unsigned int __nocast flags) { - int retries = 0; - unsigned int lflags = kmem_flags_convert(flags); - void *ptr; + int retries = 0; + gfp_t lflags = kmem_flags_convert(flags); + void *ptr; do { if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS) @@ -67,7 +67,7 @@ kmem_alloc(size_t size, gfp_t flags) } void * -kmem_zalloc(size_t size, gfp_t flags) +kmem_zalloc(size_t size, unsigned int __nocast flags) { void *ptr; @@ -90,7 +90,7 @@ kmem_free(void *ptr, size_t size) void * kmem_realloc(void *ptr, size_t newsize, size_t oldsize, - gfp_t flags) + unsigned int __nocast flags) { void *new; @@ -105,11 +105,11 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize, } void * -kmem_zone_alloc(kmem_zone_t *zone, gfp_t flags) +kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) { - int retries = 0; - unsigned int lflags = kmem_flags_convert(flags); - void *ptr; + int retries = 0; + gfp_t lflags = kmem_flags_convert(flags); + void *ptr; do { ptr = kmem_cache_alloc(zone, lflags); @@ -124,7 +124,7 @@ kmem_zone_alloc(kmem_zone_t *zone, gfp_t flags) } void * -kmem_zone_zalloc(kmem_zone_t *zone, gfp_t flags) +kmem_zone_zalloc(kmem_zone_t *zone, unsigned int __nocast flags) { void *ptr; diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index ee7010f085bc..f4bb78c268c0 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -81,9 +81,9 @@ typedef unsigned long xfs_pflags_t; *(NSTATEP) = *(OSTATEP); \ } while (0) -static __inline unsigned int kmem_flags_convert(gfp_t flags) +static __inline gfp_t kmem_flags_convert(unsigned int __nocast flags) { - unsigned int lflags = __GFP_NOWARN; /* we'll report problems, if need be */ + gfp_t lflags = __GFP_NOWARN; /* we'll report problems, if need be */ #ifdef DEBUG if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) { @@ -125,16 +125,16 @@ kmem_zone_destroy(kmem_zone_t *zone) BUG(); } -extern void *kmem_zone_zalloc(kmem_zone_t *, gfp_t); -extern void *kmem_zone_alloc(kmem_zone_t *, gfp_t); +extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast); +extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast); -extern void *kmem_alloc(size_t, gfp_t); -extern void *kmem_realloc(void *, size_t, size_t, gfp_t); -extern void *kmem_zalloc(size_t, gfp_t); +extern void *kmem_alloc(size_t, unsigned int __nocast); +extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast); +extern void *kmem_zalloc(size_t, unsigned int __nocast); extern void kmem_free(void *, size_t); typedef struct shrinker *kmem_shaker_t; -typedef int (*kmem_shake_func_t)(int, unsigned int); +typedef int (*kmem_shake_func_t)(int, gfp_t); static __inline kmem_shaker_t kmem_shake_register(kmem_shake_func_t sfunc) @@ -149,7 +149,7 @@ kmem_shake_deregister(kmem_shaker_t shrinker) } static __inline int -kmem_shake_allow(unsigned int gfp_mask) +kmem_shake_allow(gfp_t gfp_mask) { return (gfp_mask & __GFP_WAIT); } diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c6c077978fe3..7aa398724706 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1296,7 +1296,7 @@ linvfs_invalidate_page( STATIC int linvfs_release_page( struct page *page, - int gfp_mask) + gfp_t gfp_mask) { struct inode *inode = page->mapping->host; int dirty, delalloc, unmapped, unwritten; diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index e82cf72ac599..ba4767c04adf 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -64,7 +64,7 @@ STATIC kmem_cache_t *pagebuf_zone; STATIC kmem_shaker_t pagebuf_shake; -STATIC int xfsbufd_wakeup(int, unsigned int); +STATIC int xfsbufd_wakeup(int, gfp_t); STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); STATIC struct workqueue_struct *xfslogd_workqueue; @@ -383,7 +383,7 @@ _pagebuf_lookup_pages( size_t blocksize = bp->pb_target->pbr_bsize; size_t size = bp->pb_count_desired; size_t nbytes, offset; - int gfp_mask = pb_to_gfp(flags); + gfp_t gfp_mask = pb_to_gfp(flags); unsigned short page_count, i; pgoff_t first; loff_t end; @@ -1749,8 +1749,8 @@ STATIC int xfsbufd_force_sleep; STATIC int xfsbufd_wakeup( - int priority, - unsigned int mask) + int priority, + gfp_t mask) { if (xfsbufd_force_sleep) return 0; diff --git a/include/linux/bio.h b/include/linux/bio.h index 3344b4e8e43a..685fd3720df5 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -301,7 +301,7 @@ extern struct bio *bio_map_user_iov(struct request_queue *, struct sg_iovec *, int, int); extern void bio_unmap_user(struct bio *); extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int, - unsigned int); + gfp_t); extern void bio_set_pages_dirty(struct bio *bio); extern void bio_check_pages_dirty(struct bio *bio); extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 6a1d154c0825..88af42f5e04a 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -188,7 +188,7 @@ extern int buffer_heads_over_limit; * Generic address_space_operations implementations for buffer_head-backed * address_spaces. */ -int try_to_release_page(struct page * page, int gfp_mask); +int try_to_release_page(struct page * page, gfp_t gfp_mask); int block_invalidatepage(struct page *page, unsigned long offset); int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc); diff --git a/include/linux/fs.h b/include/linux/fs.h index e0b77c5af9a0..f83d997c5582 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -320,7 +320,7 @@ struct address_space_operations { /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ sector_t (*bmap)(struct address_space *, sector_t); int (*invalidatepage) (struct page *, unsigned long); - int (*releasepage) (struct page *, int); + int (*releasepage) (struct page *, gfp_t); ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); struct page* (*get_xip_page)(struct address_space *, sector_t, diff --git a/include/linux/jbd.h b/include/linux/jbd.h index ff853b3173c6..be197eb90077 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -69,7 +69,7 @@ extern int journal_enable_debug; #define jbd_debug(f, a...) /**/ #endif -extern void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry); +extern void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry); #define jbd_kmalloc(size, flags) \ __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) #define jbd_rep_kmalloc(size, flags) \ @@ -890,7 +890,7 @@ extern int journal_forget (handle_t *, struct buffer_head *); extern void journal_sync_buffer (struct buffer_head *); extern int journal_invalidatepage(journal_t *, struct page *, unsigned long); -extern int journal_try_to_free_buffers(journal_t *, struct page *, int); +extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); extern int journal_stop(handle_t *); extern int journal_flush (journal_t *); extern void journal_lock_updates (journal_t *); diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h index 9263d2db2d67..99e044b4efc6 100644 --- a/include/linux/mbcache.h +++ b/include/linux/mbcache.h @@ -22,7 +22,7 @@ struct mb_cache_entry { }; struct mb_cache_op { - int (*free)(struct mb_cache_entry *, int); + int (*free)(struct mb_cache_entry *, gfp_t); }; /* Functions on caches */ diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index af00b10294cd..001ab82df051 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -1972,7 +1972,7 @@ extern struct address_space_operations reiserfs_address_space_operations; /* fix_nodes.c */ #ifdef CONFIG_REISERFS_CHECK -void *reiserfs_kmalloc(size_t size, int flags, struct super_block *s); +void *reiserfs_kmalloc(size_t size, gfp_t flags, struct super_block *s); void reiserfs_kfree(const void *vp, size_t size, struct super_block *s); #else static inline void *reiserfs_kmalloc(size_t size, int flags, From 8267e268e0914ac9371d07f711fcf20cc572993c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:20:53 -0400 Subject: [PATCH 0874/1939] [PATCH] gfp_t: block layer core Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/as-iosched.c | 2 +- drivers/block/cfq-iosched.c | 8 ++++---- drivers/block/deadline-iosched.c | 2 +- drivers/block/elevator.c | 2 +- drivers/block/ll_rw_blk.c | 16 ++++++++-------- include/linux/blkdev.h | 14 +++++++------- include/linux/elevator.h | 4 ++-- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 95c0a3690b0f..1f08e14697e9 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -1807,7 +1807,7 @@ static void as_put_request(request_queue_t *q, struct request *rq) } static int as_set_request(request_queue_t *q, struct request *rq, - struct bio *bio, int gfp_mask) + struct bio *bio, gfp_t gfp_mask) { struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask); diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index cd056e7e64ec..d3bfe8cfb039 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -1422,7 +1422,7 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) } static struct cfq_io_context * -cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask) +cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) { struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); @@ -1517,7 +1517,7 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, - int gfp_mask) + gfp_t gfp_mask) { const int hashval = hash_long(key, CFQ_QHASH_SHIFT); struct cfq_queue *cfqq, *new_cfqq = NULL; @@ -1578,7 +1578,7 @@ cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, * cfqq, so we don't need to worry about it disappearing */ static struct cfq_io_context * -cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask) +cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) { struct io_context *ioc = NULL; struct cfq_io_context *cic; @@ -2075,7 +2075,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq) */ static int cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 52a3ae5289a0..753546ba2262 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -756,7 +756,7 @@ static void deadline_put_request(request_queue_t *q, struct request *rq) static int deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq; diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 98f0126a2deb..c744d2a13062 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -487,7 +487,7 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq) } int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { elevator_t *e = q->elevator; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index baedac522945..0f64ee7d8d27 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1652,13 +1652,13 @@ static int blk_init_free_list(request_queue_t *q) static int __make_request(request_queue_t *, struct bio *); -request_queue_t *blk_alloc_queue(int gfp_mask) +request_queue_t *blk_alloc_queue(gfp_t gfp_mask) { return blk_alloc_queue_node(gfp_mask, -1); } EXPORT_SYMBOL(blk_alloc_queue); -request_queue_t *blk_alloc_queue_node(int gfp_mask, int node_id) +request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) { request_queue_t *q; @@ -1787,7 +1787,7 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq) } static inline struct request * -blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) +blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -1885,7 +1885,7 @@ static void freed_request(request_queue_t *q, int rw) * Returns !NULL on success, with queue_lock *not held*. */ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct request *rq = NULL; struct request_list *rl = &q->rq; @@ -2019,7 +2019,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw, return rq; } -struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) +struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask) { struct request *rq; @@ -2251,7 +2251,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * @gfp_mask: memory allocation flags */ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, - unsigned int len, unsigned int gfp_mask) + unsigned int len, gfp_t gfp_mask) { struct bio *bio; @@ -3393,7 +3393,7 @@ void exit_io_context(void) * but since the current task itself holds a reference, the context can be * used in general code, so long as it stays within `current` context. */ -struct io_context *current_io_context(int gfp_flags) +struct io_context *current_io_context(gfp_t gfp_flags) { struct task_struct *tsk = current; struct io_context *ret; @@ -3424,7 +3424,7 @@ EXPORT_SYMBOL(current_io_context); * * This is always called in the context of the task which submitted the I/O. */ -struct io_context *get_io_context(int gfp_flags) +struct io_context *get_io_context(gfp_t gfp_flags) { struct io_context *ret; ret = current_io_context(gfp_flags); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index efdc9b5bc05c..1afbdb2d752c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -96,8 +96,8 @@ struct io_context { void put_io_context(struct io_context *ioc); void exit_io_context(void); -struct io_context *current_io_context(int gfp_flags); -struct io_context *get_io_context(int gfp_flags); +struct io_context *current_io_context(gfp_t gfp_flags); +struct io_context *get_io_context(gfp_t gfp_flags); void copy_io_context(struct io_context **pdst, struct io_context **psrc); void swap_io_context(struct io_context **ioc1, struct io_context **ioc2); @@ -354,7 +354,7 @@ struct request_queue * queue needs bounce pages for pages above this limit */ unsigned long bounce_pfn; - unsigned int bounce_gfp; + gfp_t bounce_gfp; /* * various queue flags, see QUEUE_* below @@ -550,7 +550,7 @@ extern void generic_make_request(struct bio *bio); extern void blk_put_request(struct request *); extern void blk_end_sync_rq(struct request *rq); extern void blk_attempt_remerge(request_queue_t *, struct request *); -extern struct request *blk_get_request(request_queue_t *, int, int); +extern struct request *blk_get_request(request_queue_t *, int, gfp_t); extern void blk_insert_request(request_queue_t *, struct request *, int, void *); extern void blk_requeue_request(request_queue_t *, struct request *); extern void blk_plug_device(request_queue_t *); @@ -565,7 +565,7 @@ extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); extern int blk_rq_unmap_user(struct bio *, unsigned int); -extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int); +extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *, int); @@ -654,8 +654,8 @@ extern void blk_wait_queue_drained(request_queue_t *, int); extern void blk_finish_queue_drain(request_queue_t *); int blk_get_queue(request_queue_t *); -request_queue_t *blk_alloc_queue(int gfp_mask); -request_queue_t *blk_alloc_queue_node(int,int); +request_queue_t *blk_alloc_queue(gfp_t); +request_queue_t *blk_alloc_queue_node(gfp_t, int); #define blk_put_queue(q) blk_cleanup_queue((q)) /* diff --git a/include/linux/elevator.h b/include/linux/elevator.h index ea6bbc2d7407..ed93125c1db5 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -18,7 +18,7 @@ typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct re typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *); -typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, int); +typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, gfp_t); typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); @@ -98,7 +98,7 @@ extern int elv_register_queue(request_queue_t *q); extern void elv_unregister_queue(request_queue_t *q); extern int elv_may_queue(request_queue_t *, int, struct bio *); extern void elv_completed_request(request_queue_t *, struct request *); -extern int elv_set_request(request_queue_t *, struct request *, struct bio *, int); +extern int elv_set_request(request_queue_t *, struct request *, struct bio *, gfp_t); extern void elv_put_request(request_queue_t *, struct request *); /* From f9e3214a7964f523e12b4f30b6bd6396794818bd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:20:58 -0400 Subject: [PATCH 0875/1939] [PATCH] gfp_t: dma-mapping (arm) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/mm/consistent.c | 8 ++++---- include/asm-arm/dma-mapping.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 26356ce4da54..82f4d5e27c54 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -75,7 +75,7 @@ static struct vm_region consistent_head = { }; static struct vm_region * -vm_region_alloc(struct vm_region *head, size_t size, int gfp) +vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) { unsigned long addr = head->vm_start, end = head->vm_end - size; unsigned long flags; @@ -133,7 +133,7 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad #endif static void * -__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, +__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, pgprot_t prot) { struct page *page; @@ -251,7 +251,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, * virtual and bus address for that space. */ void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) { return __dma_alloc(dev, size, handle, gfp, pgprot_noncached(pgprot_kernel)); @@ -263,7 +263,7 @@ EXPORT_SYMBOL(dma_alloc_coherent); * dma_alloc_coherent above. */ void * -dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp) +dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) { return __dma_alloc(dev, size, handle, gfp, pgprot_writecombine(pgprot_kernel)); diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h index d62ade4e4cbb..e3e8541ee63b 100644 --- a/include/asm-arm/dma-mapping.h +++ b/include/asm-arm/dma-mapping.h @@ -70,7 +70,7 @@ static inline int dma_mapping_error(dma_addr_t dma_addr) * device-viewed address. */ extern void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp); +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); /** * dma_free_coherent - free memory allocated by dma_alloc_coherent @@ -117,7 +117,7 @@ int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, * device-viewed address. */ extern void * -dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp); +dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); #define dma_free_writecombine(dev,size,cpu_addr,handle) \ dma_free_coherent(dev,size,cpu_addr,handle) From 06a544971fad0992fe8b92c5647538d573089dd4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:03 -0400 Subject: [PATCH 0876/1939] [PATCH] gfp_t: dma-mapping (ia64) ... and related annotations for amd64 - swiotlb code is shared, but prototypes are not. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ia64/hp/common/hwsw_iommu.c | 2 +- arch/ia64/hp/common/sba_iommu.c | 2 +- arch/ia64/lib/swiotlb.c | 2 +- arch/ia64/sn/pci/pci_dma.c | 2 +- include/asm-ia64/machvec.h | 2 +- include/asm-x86_64/swiotlb.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index 80f8ef013939..1ba02baf2f94 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ b/arch/ia64/hp/common/hwsw_iommu.c @@ -71,7 +71,7 @@ hwsw_init (void) } void * -hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flags) +hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { if (use_swiotlb(dev)) return swiotlb_alloc_coherent(dev, size, dma_handle, flags); diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 11957598a8b9..21bffba78b6d 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1076,7 +1076,7 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) * See Documentation/DMA-mapping.txt */ void * -sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flags) +sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { struct ioc *ioc; void *addr; diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c index a604efc7f6c9..3ebbb3c8ba36 100644 --- a/arch/ia64/lib/swiotlb.c +++ b/arch/ia64/lib/swiotlb.c @@ -314,7 +314,7 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir) void * swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, int flags) + dma_addr_t *dma_handle, gfp_t flags) { unsigned long dev_addr; void *ret; diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index 0e4b9ad9ef02..75e6e874bebf 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -75,7 +75,7 @@ EXPORT_SYMBOL(sn_dma_set_mask); * more information. */ void *sn_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int flags) + dma_addr_t * dma_handle, gfp_t flags) { void *cpuaddr; unsigned long phys_addr; diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 79e89a7db566..a2f6ac5aef7d 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -37,7 +37,7 @@ typedef int ia64_mv_pci_legacy_write_t (struct pci_bus *, u16 port, u32 val, /* DMA-mapping interface: */ typedef void ia64_mv_dma_init (void); -typedef void *ia64_mv_dma_alloc_coherent (struct device *, size_t, dma_addr_t *, int); +typedef void *ia64_mv_dma_alloc_coherent (struct device *, size_t, dma_addr_t *, gfp_t); typedef void ia64_mv_dma_free_coherent (struct device *, size_t, void *, dma_addr_t); typedef dma_addr_t ia64_mv_dma_map_single (struct device *, void *, size_t, int); typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int); diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h index 36293061f4ed..7cbfd10ecc3c 100644 --- a/include/asm-x86_64/swiotlb.h +++ b/include/asm-x86_64/swiotlb.h @@ -27,7 +27,7 @@ extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, int direction); extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr); extern void *swiotlb_alloc_coherent (struct device *hwdev, size_t size, - dma_addr_t *dma_handle, int flags); + dma_addr_t *dma_handle, gfp_t flags); extern void swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); From 55c5d74b3ac3a6b8bdde4e5fab4015eccd557d52 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:08 -0400 Subject: [PATCH 0877/1939] [PATCH] gfp_t: dma-mapping (alpha) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/pci-noop.c | 2 +- include/asm-alpha/dma-mapping.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c index 582a3519fb28..9903e3a79102 100644 --- a/arch/alpha/kernel/pci-noop.c +++ b/arch/alpha/kernel/pci-noop.c @@ -154,7 +154,7 @@ pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) void * dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; diff --git a/include/asm-alpha/dma-mapping.h b/include/asm-alpha/dma-mapping.h index c675f282d6ad..680f7ecbb28f 100644 --- a/include/asm-alpha/dma-mapping.h +++ b/include/asm-alpha/dma-mapping.h @@ -31,7 +31,7 @@ #else /* no PCI - no IOMMU. */ void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int gfp); + dma_addr_t *dma_handle, gfp_t gfp); int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction); From 43b7eae1f5c5424a49ea4a65e9b0e9d5d2fd9446 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:13 -0400 Subject: [PATCH 0878/1939] [PATCH] gfp_t: dma-mapping (cris) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-cris/dma-mapping.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-cris/dma-mapping.h b/include/asm-cris/dma-mapping.h index 0b5c3fdaefe1..8eff51349ae7 100644 --- a/include/asm-cris/dma-mapping.h +++ b/include/asm-cris/dma-mapping.h @@ -15,14 +15,14 @@ #ifdef CONFIG_PCI void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag); + dma_addr_t *dma_handle, gfp_t flag); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); #else static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { BUG(); return NULL; From a5da7d3c6e8fcd7aaab6c4e1e9101ba333248ffb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:18 -0400 Subject: [PATCH 0879/1939] [PATCH] gfp_t: dma-mapping (frv) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/frv/mb93090-mb00/pci-dma-nommu.c | 2 +- arch/frv/mb93090-mb00/pci-dma.c | 2 +- arch/frv/mm/dma-alloc.c | 2 +- include/asm-frv/dma-mapping.h | 2 +- include/asm-frv/pci.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c index 819895cf0b9e..2082a9647f4f 100644 --- a/arch/frv/mb93090-mb00/pci-dma-nommu.c +++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c @@ -33,7 +33,7 @@ struct dma_alloc_record { static DEFINE_SPINLOCK(dma_alloc_lock); static LIST_HEAD(dma_alloc_list); -void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp) +void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) { struct dma_alloc_record *new; struct list_head *this = &dma_alloc_list; diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c index 27eb12066507..86fbdadc51b6 100644 --- a/arch/frv/mb93090-mb00/pci-dma.c +++ b/arch/frv/mb93090-mb00/pci-dma.c @@ -17,7 +17,7 @@ #include #include -void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp) +void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) { void *ret; diff --git a/arch/frv/mm/dma-alloc.c b/arch/frv/mm/dma-alloc.c index 4b38d45435f6..cfc4f97490c6 100644 --- a/arch/frv/mm/dma-alloc.c +++ b/arch/frv/mm/dma-alloc.c @@ -81,7 +81,7 @@ static int map_page(unsigned long va, unsigned long pa, pgprot_t prot) * portions of the kernel with single large page TLB entries, and * still get unique uncached pages for consistent DMA. */ -void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) +void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle) { struct vm_struct *area; unsigned long page, va, pa; diff --git a/include/asm-frv/dma-mapping.h b/include/asm-frv/dma-mapping.h index 0206ab35eae0..5003e017fd1e 100644 --- a/include/asm-frv/dma-mapping.h +++ b/include/asm-frv/dma-mapping.h @@ -13,7 +13,7 @@ extern unsigned long __nongprelbss dma_coherent_mem_start; extern unsigned long __nongprelbss dma_coherent_mem_end; -void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int gfp); +void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); /* diff --git a/include/asm-frv/pci.h b/include/asm-frv/pci.h index b4efe5e3591a..1168451c275f 100644 --- a/include/asm-frv/pci.h +++ b/include/asm-frv/pci.h @@ -32,7 +32,7 @@ extern void pcibios_set_master(struct pci_dev *dev); extern void pcibios_penalize_isa_irq(int irq); #ifdef CONFIG_MMU -extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle); +extern void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle); extern void consistent_free(void *vaddr); extern void consistent_sync(void *vaddr, size_t size, int direction); extern void consistent_sync_page(struct page *page, unsigned long offset, From 185a8ff52875d8db31b9346ab186f75baa616dee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:23 -0400 Subject: [PATCH 0880/1939] [PATCH] gfp_t: dma-mapping (mips) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/mips/mm/dma-coherent.c | 4 ++-- arch/mips/mm/dma-ip27.c | 4 ++-- arch/mips/mm/dma-ip32.c | 4 ++-- arch/mips/mm/dma-noncoherent.c | 4 ++-- include/asm-mips/dma-mapping.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c index 97a50d38c98f..a617f8c327e8 100644 --- a/arch/mips/mm/dma-coherent.c +++ b/arch/mips/mm/dma-coherent.c @@ -18,7 +18,7 @@ #include void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; /* ignore region specifiers */ @@ -39,7 +39,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, EXPORT_SYMBOL(dma_alloc_noncoherent); void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) __attribute__((alias("dma_alloc_noncoherent"))); EXPORT_SYMBOL(dma_alloc_coherent); diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c index aa7c94b5d781..8da19fd22ac6 100644 --- a/arch/mips/mm/dma-ip27.c +++ b/arch/mips/mm/dma-ip27.c @@ -22,7 +22,7 @@ pdev_to_baddr(to_pci_dev(dev), (addr)) void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; @@ -44,7 +44,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, EXPORT_SYMBOL(dma_alloc_noncoherent); void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) __attribute__((alias("dma_alloc_noncoherent"))); EXPORT_SYMBOL(dma_alloc_coherent); diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c index 2cbe196c35fb..a7e3072ff78d 100644 --- a/arch/mips/mm/dma-ip32.c +++ b/arch/mips/mm/dma-ip32.c @@ -37,7 +37,7 @@ #define RAM_OFFSET_MASK 0x3fffffff void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; /* ignore region specifiers */ @@ -61,7 +61,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, EXPORT_SYMBOL(dma_alloc_noncoherent); void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index 59e54f12212e..4ce02028a292 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -24,7 +24,7 @@ */ void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; /* ignore region specifiers */ @@ -45,7 +45,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, EXPORT_SYMBOL(dma_alloc_noncoherent); void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int gfp) + dma_addr_t * dma_handle, gfp_t gfp) { void *ret; diff --git a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h index af28dc88930b..43288634c38a 100644 --- a/include/asm-mips/dma-mapping.h +++ b/include/asm-mips/dma-mapping.h @@ -5,13 +5,13 @@ #include void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag); + dma_addr_t *dma_handle, gfp_t flag); void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag); + dma_addr_t *dma_handle, gfp_t flag); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); From 5c1fb41f40b7b6d819a617f52dbd66b6938ef362 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:28 -0400 Subject: [PATCH 0881/1939] [PATCH] gfp_t: dma-mapping (parisc) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/parisc/kernel/pci-dma.c | 6 +++--- drivers/parisc/ccio-dma.c | 2 +- drivers/parisc/sba_iommu.c | 2 +- include/asm-parisc/dma-mapping.h | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 368cc095c99f..844c2877a2e3 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -349,7 +349,7 @@ pcxl_dma_init(void) __initcall(pcxl_dma_init); -static void * pa11_dma_alloc_consistent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) +static void * pa11_dma_alloc_consistent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { unsigned long vaddr; unsigned long paddr; @@ -502,13 +502,13 @@ struct hppa_dma_ops pcxl_dma_ops = { }; static void *fail_alloc_consistent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { return NULL; } static void *pa11_dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { void *addr = NULL; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 0e98a9d9834c..a3bd91a61827 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -836,7 +836,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * This function implements the pci_alloc_consistent function. */ static void * -ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) +ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *ret; #if 0 diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 82ea68b55df4..bd8b3e5a5cd7 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -986,7 +986,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * See Documentation/DMA-mapping.txt */ static void *sba_alloc_consistent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, int gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; diff --git a/include/asm-parisc/dma-mapping.h b/include/asm-parisc/dma-mapping.h index 4db84f969e9e..74d4ac6f2151 100644 --- a/include/asm-parisc/dma-mapping.h +++ b/include/asm-parisc/dma-mapping.h @@ -9,8 +9,8 @@ /* See Documentation/DMA-mapping.txt */ struct hppa_dma_ops { int (*dma_supported)(struct device *dev, u64 mask); - void *(*alloc_consistent)(struct device *dev, size_t size, dma_addr_t *iova, int flag); - void *(*alloc_noncoherent)(struct device *dev, size_t size, dma_addr_t *iova, int flag); + void *(*alloc_consistent)(struct device *dev, size_t size, dma_addr_t *iova, gfp_t flag); + void *(*alloc_noncoherent)(struct device *dev, size_t size, dma_addr_t *iova, gfp_t flag); void (*free_consistent)(struct device *dev, size_t size, void *vaddr, dma_addr_t iova); dma_addr_t (*map_single)(struct device *dev, void *addr, size_t size, enum dma_data_direction direction); void (*unmap_single)(struct device *dev, dma_addr_t iova, size_t size, enum dma_data_direction direction); @@ -49,14 +49,14 @@ extern struct hppa_dma_ops *hppa_dma_ops; static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { return hppa_dma_ops->alloc_consistent(dev, size, dma_handle, flag); } static inline void * dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { return hppa_dma_ops->alloc_noncoherent(dev, size, dma_handle, flag); } From e82dd4d6472304495afa271b2f63b572868b23d9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:33 -0400 Subject: [PATCH 0882/1939] [PATCH] gfp_t: dma-mapping (ppc) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ppc/kernel/dma-mapping.c | 4 ++-- include/asm-ppc/dma-mapping.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c index 8edee806dae7..0f710d2baec6 100644 --- a/arch/ppc/kernel/dma-mapping.c +++ b/arch/ppc/kernel/dma-mapping.c @@ -115,7 +115,7 @@ static struct vm_region consistent_head = { }; static struct vm_region * -vm_region_alloc(struct vm_region *head, size_t size, int gfp) +vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) { unsigned long addr = head->vm_start, end = head->vm_end - size; unsigned long flags; @@ -173,7 +173,7 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad * virtual and bus address for that space. */ void * -__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp) +__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) { struct page *page; struct vm_region *c; diff --git a/include/asm-ppc/dma-mapping.h b/include/asm-ppc/dma-mapping.h index 061bfcac1bf1..6e9635114433 100644 --- a/include/asm-ppc/dma-mapping.h +++ b/include/asm-ppc/dma-mapping.h @@ -19,7 +19,7 @@ * allocate the space "normally" and use the cache management functions * to ensure it is consistent. */ -extern void *__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp); +extern void *__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp); extern void __dma_free_coherent(size_t size, void *vaddr); extern void __dma_sync(void *vaddr, size_t size, int direction); extern void __dma_sync_page(struct page *page, unsigned long offset, From 6dae2c2306684d9e76a04c22dc090380a9009f12 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:38 -0400 Subject: [PATCH 0883/1939] [PATCH] gfp_t: dma-mapping (sh) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/sh/boards/renesas/rts7751r2d/mach.c | 2 +- arch/sh/cchips/voyagergx/consistent.c | 2 +- arch/sh/drivers/pci/dma-dreamcast.c | 2 +- arch/sh/mm/consistent.c | 2 +- include/asm-sh/dma-mapping.h | 4 ++-- include/asm-sh/machvec.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c index 1efc18e786d5..610740512d56 100644 --- a/arch/sh/boards/renesas/rts7751r2d/mach.c +++ b/arch/sh/boards/renesas/rts7751r2d/mach.c @@ -23,7 +23,7 @@ extern void init_rts7751r2d_IRQ(void); extern void *rts7751r2d_ioremap(unsigned long, unsigned long); extern int rts7751r2d_irq_demux(int irq); -extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, int); +extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t); extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t); /* diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c index 5b92585a38d2..3d9a02c093a3 100644 --- a/arch/sh/cchips/voyagergx/consistent.c +++ b/arch/sh/cchips/voyagergx/consistent.c @@ -31,7 +31,7 @@ static LIST_HEAD(voya_alloc_list); #define OHCI_SRAM_SIZE 0x10000 void *voyagergx_consistent_alloc(struct device *dev, size_t size, - dma_addr_t *handle, int flag) + dma_addr_t *handle, gfp_t flag) { struct list_head *list = &voya_alloc_list; struct voya_alloc_entry *entry; diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c index 83de7ef4e7df..e12418bb1fa5 100644 --- a/arch/sh/drivers/pci/dma-dreamcast.c +++ b/arch/sh/drivers/pci/dma-dreamcast.c @@ -33,7 +33,7 @@ static int gapspci_dma_used = 0; void *dreamcast_consistent_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { unsigned long buf; diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 1f7af0c73cf4..df3a9e452cc5 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -11,7 +11,7 @@ #include #include -void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle) +void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle) { struct page *page, *end, *free; void *ret; diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h index 80d164c1529e..d3fa5c2b889d 100644 --- a/include/asm-sh/dma-mapping.h +++ b/include/asm-sh/dma-mapping.h @@ -9,7 +9,7 @@ extern struct bus_type pci_bus_type; /* arch/sh/mm/consistent.c */ -extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); +extern void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle); extern void consistent_free(void *vaddr, size_t size); extern void consistent_sync(void *vaddr, size_t size, int direction); @@ -26,7 +26,7 @@ static inline int dma_set_mask(struct device *dev, u64 mask) } static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { if (sh_mv.mv_consistent_alloc) { void *ret; diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h index 5771f4baa478..3f18aa180516 100644 --- a/include/asm-sh/machvec.h +++ b/include/asm-sh/machvec.h @@ -64,7 +64,7 @@ struct sh_machine_vector void (*mv_heartbeat)(void); - void *(*mv_consistent_alloc)(struct device *, size_t, dma_addr_t *, int); + void *(*mv_consistent_alloc)(struct device *, size_t, dma_addr_t *, gfp_t); int (*mv_consistent_free)(struct device *, size_t, void *, dma_addr_t); }; From f80aabb03a33702d934fbc3c02fd96471816d82e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:43 -0400 Subject: [PATCH 0884/1939] [PATCH] gfp_t: dma-mapping (amd64) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/pci-gart.c | 4 ++-- arch/x86_64/kernel/pci-nommu.c | 2 +- include/asm-x86_64/dma-mapping.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index cf0a0315d586..88be97c96987 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -187,7 +187,7 @@ static void flush_gart(struct device *dev) /* Allocate DMA memory on node near device */ noinline -static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) +static void *dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order) { struct page *page; int node; @@ -204,7 +204,7 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) */ void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - unsigned gfp) + gfp_t gfp) { void *memory; unsigned long dma_mask = 0; diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c index 67d90b89af0b..5a981dca87ff 100644 --- a/arch/x86_64/kernel/pci-nommu.c +++ b/arch/x86_64/kernel/pci-nommu.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL(iommu_sac_force); */ void *dma_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, unsigned gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; u64 mask; diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h index e784fdc524f1..54a380efed41 100644 --- a/include/asm-x86_64/dma-mapping.h +++ b/include/asm-x86_64/dma-mapping.h @@ -17,7 +17,7 @@ extern dma_addr_t bad_dma_address; (swiotlb ? swiotlb_dma_mapping_error(x) : ((x) == bad_dma_address)) void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - unsigned gfp); + gfp_t gfp); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); From 5fb5cbed6e5ba4cbaf7284a23d42eb878bb7da24 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:48 -0400 Subject: [PATCH 0885/1939] [PATCH] gfp_t: dma-mapping (xtensa) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/xtensa/kernel/pci-dma.c | 2 +- include/asm-xtensa/dma-mapping.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 84fde258cf85..1ff82268e8ea 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -29,7 +29,7 @@ */ void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) { void *ret; diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h index e86a206f1209..c425f10d086a 100644 --- a/include/asm-xtensa/dma-mapping.h +++ b/include/asm-xtensa/dma-mapping.h @@ -28,7 +28,7 @@ extern void consistent_sync(void*, size_t, int); #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag); + dma_addr_t *dma_handle, gfp_t flag); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); From 970a9e73f9036ef89d46b8240f99463f6d244c1d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:53 -0400 Subject: [PATCH 0886/1939] [PATCH] gfp_t: dma-mapping (simple cases) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-generic/dma-mapping-broken.h | 2 +- include/asm-m32r/dma-mapping.h | 2 +- include/asm-sh64/dma-mapping.h | 2 +- include/asm-sparc/dma-mapping.h | 2 +- include/asm-sparc64/dma-mapping.h | 2 +- include/asm-um/dma-mapping.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/asm-generic/dma-mapping-broken.h b/include/asm-generic/dma-mapping-broken.h index fd9de9502dff..a7f1a55ce6b0 100644 --- a/include/asm-generic/dma-mapping-broken.h +++ b/include/asm-generic/dma-mapping-broken.h @@ -6,7 +6,7 @@ static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { BUG(); return NULL; diff --git a/include/asm-m32r/dma-mapping.h b/include/asm-m32r/dma-mapping.h index 3a2db28834b6..a7fa0302bda7 100644 --- a/include/asm-m32r/dma-mapping.h +++ b/include/asm-m32r/dma-mapping.h @@ -8,7 +8,7 @@ static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { return (void *)NULL; } diff --git a/include/asm-sh64/dma-mapping.h b/include/asm-sh64/dma-mapping.h index b8d26fe677f4..cc9a2e86f5b4 100644 --- a/include/asm-sh64/dma-mapping.h +++ b/include/asm-sh64/dma-mapping.h @@ -25,7 +25,7 @@ static inline int dma_set_mask(struct device *dev, u64 mask) } static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { return consistent_alloc(NULL, size, dma_handle); } diff --git a/include/asm-sparc/dma-mapping.h b/include/asm-sparc/dma-mapping.h index 2dc5bb8effa6..d7c3b0f0a901 100644 --- a/include/asm-sparc/dma-mapping.h +++ b/include/asm-sparc/dma-mapping.h @@ -8,7 +8,7 @@ #else static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { BUG(); return NULL; diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index 1c5da41653a4..c7d5804ba76d 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -10,7 +10,7 @@ struct device; static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int flag) + dma_addr_t *dma_handle, gfp_t flag) { BUG(); return NULL; diff --git a/include/asm-um/dma-mapping.h b/include/asm-um/dma-mapping.h index 13e6291f7151..babd29895114 100644 --- a/include/asm-um/dma-mapping.h +++ b/include/asm-um/dma-mapping.h @@ -19,7 +19,7 @@ dma_set_mask(struct device *dev, u64 dma_mask) static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) + gfp_t flag) { BUG(); return((void *) 0); From 55016f10e31bb15b85d8c500f979dfdceb37d548 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:58 -0400 Subject: [PATCH 0887/1939] [PATCH] gfp_t: drivers/usb Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/core/buffer.c | 2 +- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 8 ++++---- drivers/usb/core/message.c | 2 +- drivers/usb/core/urb.c | 4 ++-- drivers/usb/core/usb.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 8 ++++---- drivers/usb/gadget/ether.c | 22 +++++++++++----------- drivers/usb/gadget/goku_udc.c | 6 +++--- drivers/usb/gadget/lh7a40x_udc.c | 12 ++++++------ drivers/usb/gadget/net2280.c | 6 +++--- drivers/usb/gadget/omap_udc.c | 6 +++--- drivers/usb/gadget/pxa2xx_udc.c | 6 +++--- drivers/usb/gadget/serial.c | 16 ++++++++-------- drivers/usb/gadget/zero.c | 8 ++++---- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/ehci-mem.c | 6 +++--- drivers/usb/host/ehci-q.c | 6 +++--- drivers/usb/host/ehci-sched.c | 14 +++++++------- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-mem.c | 4 ++-- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/misc/uss720.c | 6 +++--- drivers/usb/net/asix.c | 2 +- drivers/usb/net/gl620a.c | 2 +- drivers/usb/net/kaweth.c | 6 +++--- drivers/usb/net/net1080.c | 2 +- drivers/usb/net/rndis_host.c | 2 +- drivers/usb/net/usbnet.c | 2 +- drivers/usb/net/usbnet.h | 2 +- drivers/usb/net/zaurus.c | 2 +- drivers/usb/net/zd1201.c | 2 +- include/linux/usb.h | 8 ++++---- include/linux/usb_gadget.h | 12 ++++++------ sound/usb/usbmidi.c | 2 +- 37 files changed, 100 insertions(+), 100 deletions(-) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index fc15b4acc8af..57e800ac3cee 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1017a97a418b..ff19d64041b5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1112,7 +1112,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) +static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index ac451fa7e4d2..1f1ed6211af8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, unsigned mem_flags); + int (*submit_urb) (struct urb *urb, gfp_t mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -200,7 +200,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags); + gfp_t mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -247,7 +247,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - unsigned mem_flags, dma_addr_t *dma); + gfp_t mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f1fb67fe22a8..f9a81e84dbdf 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -321,7 +321,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - unsigned mem_flags + gfp_t mem_flags ) { int i; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c846fefb7386..b32898e0a27d 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) +struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, unsigned mem_flags) +int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int pipe, temp, max; struct usb_device *dev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7d131509e419..4c57f3f649ed 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1147,7 +1147,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 583db7c38cf1..8d9d8ee89554 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) +dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned mem_flags + gfp_t mem_flags ) { char *retval; struct dummy_ep *ep; @@ -541,7 +541,7 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) static int dummy_queue (struct usb_ep *_ep, struct usb_request *_req, - unsigned mem_flags) + gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -999,7 +999,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 49459e33e952..f1024e804d5c 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags); static int -set_ether_config (struct eth_dev *dev, unsigned gfp_flags) +set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1081,7 +1081,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1598,7 +1598,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1724,7 +1724,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, unsigned gfp_flags) + unsigned n, gfp_t gfp_flags) { unsigned i; struct usb_request *req; @@ -1763,7 +1763,7 @@ static int prealloc (struct list_head *list, struct usb_ep *ep, return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags) { int status; @@ -1779,7 +1779,7 @@ static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) return status; } -static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) +static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; @@ -1962,7 +1962,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) * normally just one notification will be queued. */ -static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, gfp_t); static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void @@ -2024,7 +2024,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags) +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); @@ -2092,7 +2092,7 @@ static int eth_stop (struct net_device *net) /*-------------------------------------------------------------------------*/ static struct usb_request * -eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) +eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags) { struct usb_request *req; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index eaab26f4ed37..b0f3cd63e3b9 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) +goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ static void abort_dma(struct goku_ep *ep, int status) /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct goku_request *req; struct goku_ep *ep; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 4842577789c9..012d1e5f1524 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -71,13 +71,13 @@ static char *state_names[] = { static int lh7a40x_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *); static int lh7a40x_ep_disable(struct usb_ep *ep); -static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int); +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t); static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, - int); + gfp_t); static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, unsigned); -static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int); +static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); static int lh7a40x_set_halt(struct usb_ep *ep, int); static int lh7a40x_fifo_status(struct usb_ep *ep); @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, unsigned gfp_flags) + dma_addr_t * dma, gfp_t gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 477fab2e74d1..c32e1f7476da 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ff5533e69560..287c5900fb13 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) +omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -937,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 73f8c9404156..6e545393cfff 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { char *retval; @@ -874,7 +874,7 @@ static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r) /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index c925d9222f53..b35ac6d334f8 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -2091,7 +2091,7 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * usb_request or NULL if there is an error. */ static struct usb_request * -gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) +gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags) { struct usb_request *req; @@ -2132,7 +2132,7 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * endpoint, buffer len, and kmalloc flags. */ static struct gs_req_entry * -gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) { struct gs_req_entry *req; @@ -2173,7 +2173,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags) { int i; struct gs_port *port; @@ -2255,7 +2255,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6890e773b2a2..ec9c424f1d97 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) +source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) +set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) +set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b948ffd94f45..f5eb9e7b5b18 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -983,7 +983,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 5c38ad869485..91c2ab43cbcc 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -45,7 +45,7 @@ static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma) INIT_LIST_HEAD (&qtd->qtd_list); } -static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qtd *qtd; dma_addr_t dma; @@ -79,7 +79,7 @@ static void qh_destroy (struct kref *kref) dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); } -static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qh *qh; dma_addr_t dma; @@ -161,7 +161,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) } /* remember to add cleanup code (above) if you add anything here */ -static int ehci_mem_init (struct ehci_hcd *ehci, int flags) +static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) { int i; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 940d38ca7d91..5bb872c3496d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -477,7 +477,7 @@ qh_urb_transaction ( struct ehci_hcd *ehci, struct urb *urb, struct list_head *head, - int flags + gfp_t flags ) { struct ehci_qtd *qtd, *qtd_prev; dma_addr_t buf; @@ -629,7 +629,7 @@ static struct ehci_qh * qh_make ( struct ehci_hcd *ehci, struct urb *urb, - int flags + gfp_t flags ) { struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); u32 info1 = 0, info2 = 0; @@ -906,7 +906,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ccc7300baa6d..f0c8aa1ccd5d 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -589,7 +589,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { unsigned epnum; unsigned long flags; @@ -634,7 +634,7 @@ static int intr_submit ( /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (unsigned mem_flags) +iso_stream_alloc (gfp_t mem_flags) { struct ehci_iso_stream *stream; @@ -851,7 +851,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, unsigned mem_flags) +iso_sched_alloc (unsigned packets, gfp_t mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -924,7 +924,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_itd *itd; @@ -1418,7 +1418,7 @@ itd_complete ( /*-------------------------------------------------------------------------*/ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1529,7 +1529,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_sitd *sitd; @@ -1779,7 +1779,7 @@ sitd_complete ( static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index e142056b0d2c..2548d94fcd72 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -694,7 +694,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 67c1aa5eb1c1..f8da8c7af7c6 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index fd3c4d3714bd..9fb83dfb1eb4 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -84,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, unsigned mem_flags) +td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) +ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d42a15d10a46..cad858575cea 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -818,7 +818,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index ea0d168a8c67..4e0fbe2c1a9a 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1164,7 +1164,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, unsigned mem_flags) + struct urb *urb, gfp_t mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 03fb70ef2eb3..0592cb5e6c4d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -137,7 +137,7 @@ static void async_complete(struct urb *urb, struct pt_regs *ptregs) static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, __u8 request, __u8 requesttype, __u16 value, __u16 index, - unsigned int mem_flags) + gfp_t mem_flags) { struct usb_device *usbdev; struct uss720_async_request *rq; @@ -204,7 +204,7 @@ static unsigned int kill_all_async_requests_priv(struct parport_uss720_private * /* --------------------------------------------------------------------- */ -static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags) +static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; @@ -238,7 +238,7 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha return -EIO; } -static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags) +static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 861f00a43750..252a34fbb42c 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -753,7 +753,7 @@ static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - unsigned flags) + gfp_t flags) { int padlen; int headroom = skb_headroom(skb); diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index c8763ae33c73..c0f263b202a6 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -301,7 +301,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; int length = skb->len; diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index e04b0ce3611a..c82655d3d448 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -477,13 +477,13 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); /**************************************************************** int_callback *****************************************************************/ -static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, int mf) +static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) { int status; @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - unsigned mem_flags) + gfp_t mem_flags) { int result; diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index a4309c4a491b..cee55f8cf64f 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -500,7 +500,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 2ed2e5fb7778..b5a925dc1beb 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -517,7 +517,7 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { struct rndis_data_hdr *hdr; struct sk_buff *skb2; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6c460918d54f..fce81d738933 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); static void rx_complete (struct urb *urb, struct pt_regs *regs); -static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) +static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 7aa0abd1a9bd..89fc4958eecf 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -107,7 +107,7 @@ struct driver_info { /* fixup tx packet (add framing) */ struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, unsigned flags); + struct sk_buff *skb, gfp_t flags); /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index ee3b892aeabc..5d4b7d55b097 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -62,7 +62,7 @@ */ static struct sk_buff * -zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index c4e479ee926a..2f52261c7cc1 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -521,7 +521,7 @@ static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int int reqlen; char seq=0; struct urb *urb; - unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; + gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; len += 4; /* first 4 are for header */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 4dbe580f9335..8f731e8f2821 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -933,17 +933,17 @@ static inline void usb_fill_int_urb (struct urb *urb, } extern void usb_init_urb(struct urb *urb); -extern struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags); +extern struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags); extern void usb_free_urb(struct urb *urb); #define usb_put_urb usb_free_urb extern struct urb *usb_get_urb(struct urb *urb); -extern int usb_submit_urb(struct urb *urb, unsigned mem_flags); +extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags); extern int usb_unlink_urb(struct urb *urb); extern void usb_kill_urb(struct urb *urb); #define HAVE_USB_BUFFERS void *usb_buffer_alloc (struct usb_device *dev, size_t size, - unsigned mem_flags, dma_addr_t *dma); + gfp_t mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); @@ -1050,7 +1050,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - unsigned mem_flags + gfp_t mem_flags ); void usb_sg_cancel (struct usb_sg_request *io); void usb_sg_wait (struct usb_sg_request *io); diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 71e608607324..ff81117eb733 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -107,18 +107,18 @@ struct usb_ep_ops { int (*disable) (struct usb_ep *ep); struct usb_request *(*alloc_request) (struct usb_ep *ep, - unsigned gfp_flags); + gfp_t gfp_flags); void (*free_request) (struct usb_ep *ep, struct usb_request *req); void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags); + dma_addr_t *dma, gfp_t gfp_flags); void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned bytes); // NOTE: on 2.6, drivers may also use dma_map() and // dma_sync_single_*() to directly manage dma overhead. int (*queue) (struct usb_ep *ep, struct usb_request *req, - unsigned gfp_flags); + gfp_t gfp_flags); int (*dequeue) (struct usb_ep *ep, struct usb_request *req); int (*set_halt) (struct usb_ep *ep, int value); @@ -214,7 +214,7 @@ usb_ep_disable (struct usb_ep *ep) * Returns the request, or null if one could not be allocated. */ static inline struct usb_request * -usb_ep_alloc_request (struct usb_ep *ep, unsigned gfp_flags) +usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) { return ep->ops->alloc_request (ep, gfp_flags); } @@ -254,7 +254,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) */ static inline void * usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma, - unsigned gfp_flags) + gfp_t gfp_flags) { return ep->ops->alloc_buffer (ep, len, dma, gfp_flags); } @@ -330,7 +330,7 @@ usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len) * reported when the usb peripheral is disconnected. */ static inline int -usb_ep_queue (struct usb_ep *ep, struct usb_request *req, unsigned gfp_flags) +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { return ep->ops->queue (ep, req, gfp_flags); } diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index e0d0365453b3..f1a2e2c2e02f 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -163,7 +163,7 @@ static const uint8_t snd_usbmidi_cin_length[] = { /* * Submits the URB, with error handling. */ -static int snd_usbmidi_submit_urb(struct urb* urb, int flags) +static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags) { int err = usb_submit_urb(urb, flags); if (err < 0 && err != -ENODEV) From 9796fdd829da626374458e8706daedcc0e432ddd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:03 -0400 Subject: [PATCH 0888/1939] [PATCH] gfp_t: kernel/* Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/audit.h | 4 ++-- include/linux/suspend.h | 2 +- kernel/audit.c | 6 +++--- kernel/auditsc.c | 2 +- kernel/kexec.c | 7 +++---- kernel/power/swsusp.c | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index b2a2509bd7ea..da3c01955f3d 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -260,11 +260,11 @@ extern int audit_filter_user(struct netlink_skb_parms *cb, int type); #ifdef CONFIG_AUDIT /* These are defined in audit.c */ /* Public API */ -extern void audit_log(struct audit_context *ctx, int gfp_mask, +extern void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...) __attribute__((format(printf,4,5))); -extern struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, int type); +extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type); extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index ad15a54806d8..ba448c760168 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -71,7 +71,7 @@ void restore_processor_state(void); struct saved_context; void __save_processor_state(struct saved_context *ctxt); void __restore_processor_state(struct saved_context *ctxt); -extern unsigned long get_usable_page(unsigned gfp_mask); +extern unsigned long get_usable_page(gfp_t gfp_mask); extern void free_eaten_memory(void); #endif /* _LINUX_SWSUSP_H */ diff --git a/kernel/audit.c b/kernel/audit.c index aefa73a8a586..0c56320d38dc 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -133,7 +133,7 @@ struct audit_buffer { struct list_head list; struct sk_buff *skb; /* formatted skb ready to send */ struct audit_context *ctx; /* NULL or associated context */ - int gfp_mask; + gfp_t gfp_mask; }; static void audit_set_pid(struct audit_buffer *ab, pid_t pid) @@ -647,7 +647,7 @@ static inline void audit_get_stamp(struct audit_context *ctx, * will be written at syscall exit. If there is no associated task, tsk * should be NULL. */ -struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, +struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) { struct audit_buffer *ab = NULL; @@ -879,7 +879,7 @@ void audit_log_end(struct audit_buffer *ab) /* Log an audit record. This is a convenience function that calls * audit_log_start, audit_log_vformat, and audit_log_end. It may be * called in any context. */ -void audit_log(struct audit_context *ctx, int gfp_mask, int type, +void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...) { struct audit_buffer *ab; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 88696f639aab..d8a68509e729 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -803,7 +803,7 @@ static void audit_log_task_info(struct audit_buffer *ab) up_read(&mm->mmap_sem); } -static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask) +static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) { int i; struct audit_buffer *ab; diff --git a/kernel/kexec.c b/kernel/kexec.c index cdd4dcd8fb63..36c5d9cd4cc1 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -90,7 +90,7 @@ int kexec_should_crash(struct task_struct *p) static int kimage_is_destination_range(struct kimage *image, unsigned long start, unsigned long end); static struct page *kimage_alloc_page(struct kimage *image, - unsigned int gfp_mask, + gfp_t gfp_mask, unsigned long dest); static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, @@ -326,8 +326,7 @@ static int kimage_is_destination_range(struct kimage *image, return 0; } -static struct page *kimage_alloc_pages(unsigned int gfp_mask, - unsigned int order) +static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) { struct page *pages; @@ -654,7 +653,7 @@ static kimage_entry_t *kimage_dst_used(struct kimage *image, } static struct page *kimage_alloc_page(struct kimage *image, - unsigned int gfp_mask, + gfp_t gfp_mask, unsigned long destination) { /* diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 2d5c45676442..10bc5ec496d7 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -1095,7 +1095,7 @@ static inline void eat_page(void *page) *eaten_memory = c; } -unsigned long get_usable_page(unsigned gfp_mask) +unsigned long get_usable_page(gfp_t gfp_mask) { unsigned long m; From c53033f6b0bd7cc133b7f433083f0394cf29ac70 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:08 -0400 Subject: [PATCH 0889/1939] [PATCH] gfp_t: drivers/scsi Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/eata.c | 2 +- drivers/scsi/hosts.c | 3 ++- drivers/scsi/lpfc/lpfc_mem.c | 2 +- drivers/scsi/osst.c | 6 ++++-- drivers/scsi/qla2xxx/qla_gbl.h | 4 ++-- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_rscn.c | 2 +- drivers/scsi/scsi.c | 8 ++++---- drivers/scsi/scsi_ioctl.c | 3 ++- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/sg.c | 2 +- drivers/scsi/st.c | 6 ++++-- include/scsi/scsi_cmnd.h | 2 +- include/scsi/scsi_request.h | 2 +- 14 files changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c10e45b94b62..3d13fdee4fc2 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1357,7 +1357,7 @@ static int port_detect(unsigned long port_base, unsigned int j, for (i = 0; i < shost->can_queue; i++) { size_t sz = shost->sg_tablesize *sizeof(struct sg_list); - unsigned int gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; + gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; ha->cp[i].sglist = kmalloc(sz, gfp_mask); if (!ha->cp[i].sglist) { printk diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 02fe371b0ab8..f24d84538fd5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -287,7 +287,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; - int gfp_mask = GFP_KERNEL, rval; + gfp_t gfp_mask = GFP_KERNEL; + int rval; if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 0aba13ceaacf..352df47bcaca 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -39,7 +39,7 @@ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ static void * -lpfc_pool_kmalloc(unsigned int gfp_flags, void *data) +lpfc_pool_kmalloc(gfp_t gfp_flags, void *data) { return kmalloc((unsigned long)data, gfp_flags); } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 3f2f2464fa63..af1133104b3f 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5146,7 +5146,8 @@ static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) { - int i, priority; + int i; + gfp_t priority; struct osst_buffer *tb; if (from_initialization) @@ -5178,7 +5179,8 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (STbuffer->buffer_size >= OS_FRAME_SIZE) return 1; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1ed32e7b5472..e451941ad81d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -52,7 +52,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); extern int qla24xx_load_risc_hotplug(scsi_qla_host_t *, uint32_t *); -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); @@ -277,7 +277,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* * Global Function Prototypes in qla_rscn.c source file. */ -extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *, int); extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 23d095d3817b..fbb6feee40cf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1685,7 +1685,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Returns a pointer to the allocated fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c index 1eba98828636..7534efcc8918 100644 --- a/drivers/scsi/qla2xxx/qla_rscn.c +++ b/drivers/scsi/qla2xxx/qla_rscn.c @@ -1066,7 +1066,7 @@ qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, * Returns a pointer to the allocated RSCN fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1f0ebabf6d47..a5711d545d71 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(scsi_device_types); * Returns: Pointer to request block. */ struct scsi_request *scsi_allocate_request(struct scsi_device *sdev, - int gfp_mask) + gfp_t gfp_mask) { const int offset = ALIGN(sizeof(struct scsi_request), 4); const int size = offset + sizeof(struct request); @@ -196,7 +196,7 @@ struct scsi_host_cmd_pool { unsigned int users; char *name; unsigned int slab_flags; - unsigned int gfp_mask; + gfp_t gfp_mask; }; static struct scsi_host_cmd_pool scsi_cmd_pool = { @@ -213,7 +213,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { static DECLARE_MUTEX(host_cmd_pool_mutex); static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, - int gfp_mask) + gfp_t gfp_mask) { struct scsi_cmnd *cmd; @@ -245,7 +245,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, * * Returns: The allocated scsi command structure. */ -struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) +struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) { struct scsi_cmnd *cmd; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index de7f98cc38fe..6a3f6aae8a97 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -205,7 +205,8 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; - int data_direction, gfp_mask = GFP_KERNEL; + int data_direction; + gfp_t gfp_mask = GFP_KERNEL; if (!sic) return -EINVAL; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0074f28c37b2..3ff538809786 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -677,7 +677,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, int gfp_mask) +static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct scsi_host_sg_pool *sgp; struct scatterlist *sgl; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ad94367df430..fd56b7ec88b6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2644,7 +2644,7 @@ static char * sg_page_malloc(int rqSz, int lowDma, int *retSzp) { char *resp = NULL; - int page_mask; + gfp_t page_mask; int order, a_size; int resSz = rqSz; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index d001c046551b..927d700f0073 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3577,7 +3577,8 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a static struct st_buffer * new_tape_buffer(int from_initialization, int need_dma, int max_sg) { - int i, priority, got = 0, segs = 0; + int i, got = 0, segs = 0; + gfp_t priority; struct st_buffer *tb; if (from_initialization) @@ -3610,7 +3611,8 @@ static struct st_buffer * /* Try to allocate enough space in the tape buffer */ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (new_size <= STbuffer->buffer_size) return 1; diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index bed4b7c9be99..e6b61fab66dd 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -146,7 +146,7 @@ struct scsi_cmnd { #define SCSI_STATE_MLQUEUE 0x100b -extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int); +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); diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h index 6a140020d7cb..2539debb7993 100644 --- a/include/scsi/scsi_request.h +++ b/include/scsi/scsi_request.h @@ -45,7 +45,7 @@ struct scsi_request { level driver) of this request */ }; -extern struct scsi_request *scsi_allocate_request(struct scsi_device *, int); +extern struct scsi_request *scsi_allocate_request(struct scsi_device *, gfp_t); extern void scsi_release_request(struct scsi_request *); extern void scsi_wait_req(struct scsi_request *, const void *cmnd, void *buffer, unsigned bufflen, From 87b750dc4b7109aa744e7d331dc93df3fe5c1c28 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:13 -0400 Subject: [PATCH 0890/1939] [PATCH] gfp_t: drivers/infiniband Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_cmd.c | 2 +- drivers/infiniband/hw/mthca/mthca_cmd.h | 2 +- drivers/infiniband/hw/mthca/mthca_memfree.c | 2 +- drivers/infiniband/hw/mthca/mthca_memfree.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f6a8ac026557..378646b5a1b8 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -524,7 +524,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev) } struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_mailbox *mailbox; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h index 65f976a13e02..18175bec84c2 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.h +++ b/drivers/infiniband/hw/mthca/mthca_cmd.h @@ -248,7 +248,7 @@ void mthca_cmd_event(struct mthca_dev *dev, u16 token, u8 status, u64 out_param); struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox); int mthca_SYS_EN(struct mthca_dev *dev, u8 *status); diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 7bd7a4bec7b4..9ad8b3b6cfef 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -82,7 +82,7 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) } struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_icm *icm; struct mthca_icm_chunk *chunk = NULL; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index bafa51544aa3..29433f295253 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -77,7 +77,7 @@ struct mthca_icm_iter { struct mthca_dev; struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm); struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, From 1ef64e670e3bc27e0c3c83810ca36e19924c35c6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:18 -0400 Subject: [PATCH 0891/1939] [PATCH] gfp_t: sound Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ppc/8xx_io/cs4218.h | 2 +- arch/ppc/8xx_io/cs4218_tdm.c | 4 ++-- include/sound/memalloc.h | 2 +- sound/core/memalloc.c | 4 ++-- sound/core/seq/instr/ainstr_gf1.c | 5 +++-- sound/core/seq/instr/ainstr_iw.c | 4 ++-- sound/core/seq/instr/ainstr_simple.c | 3 ++- sound/oss/dmasound/dmasound.h | 2 +- sound/oss/dmasound/dmasound_atari.c | 4 ++-- sound/oss/dmasound/dmasound_awacs.c | 4 ++-- sound/oss/dmasound/dmasound_paula.c | 4 ++-- sound/oss/dmasound/dmasound_q40.c | 4 ++-- 12 files changed, 22 insertions(+), 20 deletions(-) diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h index a3c38c5a5db2..f1c7392255f8 100644 --- a/arch/ppc/8xx_io/cs4218.h +++ b/arch/ppc/8xx_io/cs4218.h @@ -78,7 +78,7 @@ typedef struct { const char *name2; void (*open)(void); void (*release)(void); - void *(*dma_alloc)(unsigned int, int); + void *(*dma_alloc)(unsigned int, gfp_t); void (*dma_free)(void *, unsigned int); int (*irqinit)(void); #ifdef MODULE diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c index 2ca9ec7ec3a7..532caa388dc2 100644 --- a/arch/ppc/8xx_io/cs4218_tdm.c +++ b/arch/ppc/8xx_io/cs4218_tdm.c @@ -318,7 +318,7 @@ struct cs_sound_settings { static struct cs_sound_settings sound; -static void *CS_Alloc(unsigned int size, int flags); +static void *CS_Alloc(unsigned int size, gfp_t flags); static void CS_Free(void *ptr, unsigned int size); static int CS_IrqInit(void); #ifdef MODULE @@ -959,7 +959,7 @@ static TRANS transCSNormalRead = { /*** Low level stuff *********************************************************/ -static void *CS_Alloc(unsigned int size, int flags) +static void *CS_Alloc(unsigned int size, gfp_t flags) { int order; diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 3a2fd2cc9f19..83489c3abbaf 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -111,7 +111,7 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id); int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id); /* basic memory allocation functions */ -void *snd_malloc_pages(size_t size, unsigned int gfp_flags); +void *snd_malloc_pages(size_t size, gfp_t gfp_flags); void snd_free_pages(void *ptr, size_t size); #endif /* __SOUND_MEMALLOC_H */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index e72cec77f0db..129abab5ce98 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -190,7 +190,7 @@ static void unmark_pages(struct page *page, int order) * * Returns the pointer of the buffer, or NULL if no enoguh memory. */ -void *snd_malloc_pages(size_t size, unsigned int gfp_flags) +void *snd_malloc_pages(size_t size, gfp_t gfp_flags) { int pg; void *res; @@ -235,7 +235,7 @@ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *d { int pg; void *res; - unsigned int gfp_flags; + gfp_t gfp_flags; snd_assert(size > 0, return NULL); snd_assert(dma != NULL, return NULL); diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c index 207c2c54bf1d..0e4df8826eed 100644 --- a/sound/core/seq/instr/ainstr_gf1.c +++ b/sound/core/seq/instr/ainstr_gf1.c @@ -51,7 +51,7 @@ static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t *ops, gf1_wave_t *wp, *prev; gf1_xwave_t xp; int err; - unsigned int gfp_mask; + gfp_t gfp_mask; unsigned int real_size; gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; @@ -144,7 +144,8 @@ static int snd_seq_gf1_put(void *private_data, snd_seq_kinstr_t *instr, snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data; gf1_instrument_t *ip; gf1_xinstrument_t ix; - int err, gfp_mask; + int err; + gfp_t gfp_mask; if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) return -EINVAL; diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c index 67c24c8e8e7b..7c19fbbc5d0f 100644 --- a/sound/core/seq/instr/ainstr_iw.c +++ b/sound/core/seq/instr/ainstr_iw.c @@ -129,7 +129,7 @@ static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops, iwffff_wave_t *wp, *prev; iwffff_xwave_t xp; int err; - unsigned int gfp_mask; + gfp_t gfp_mask; unsigned int real_size; gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; @@ -236,7 +236,7 @@ static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr, iwffff_layer_t *lp, *prev_lp; iwffff_xlayer_t lx; int err; - unsigned int gfp_mask; + gfp_t gfp_mask; if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) return -EINVAL; diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c index 6183d2151034..17ab94e76073 100644 --- a/sound/core/seq/instr/ainstr_simple.c +++ b/sound/core/seq/instr/ainstr_simple.c @@ -57,7 +57,8 @@ static int snd_seq_simple_put(void *private_data, snd_seq_kinstr_t *instr, snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data; simple_instrument_t *ip; simple_xinstrument_t ix; - int err, gfp_mask; + int err; + gfp_t gfp_mask; unsigned int real_size; if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index 9a2f50f0b184..222014cafc1a 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -116,7 +116,7 @@ typedef struct { const char *name; const char *name2; struct module *owner; - void *(*dma_alloc)(unsigned int, int); + void *(*dma_alloc)(unsigned int, gfp_t); void (*dma_free)(void *, unsigned int); int (*irqinit)(void); #ifdef MODULE diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index 8daaf87664ba..59eb53f89318 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -114,7 +114,7 @@ static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount, /*** Low level stuff *********************************************************/ -static void *AtaAlloc(unsigned int size, int flags); +static void *AtaAlloc(unsigned int size, gfp_t flags); static void AtaFree(void *, unsigned int size); static int AtaIrqInit(void); #ifdef MODULE @@ -810,7 +810,7 @@ static TRANS transFalconExpanding = { * Atari (TT/Falcon) */ -static void *AtaAlloc(unsigned int size, int flags) +static void *AtaAlloc(unsigned int size, gfp_t flags) { return atari_stram_alloc(size, "dmasound"); } diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 2ceb46f1d40f..b2bf8bac842d 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -271,7 +271,7 @@ int expand_read_bal; /* Balance factor for expanding reads (not volume!) */ /*** Low level stuff *********************************************************/ -static void *PMacAlloc(unsigned int size, int flags); +static void *PMacAlloc(unsigned int size, gfp_t flags); static void PMacFree(void *ptr, unsigned int size); static int PMacIrqInit(void); #ifdef MODULE @@ -614,7 +614,7 @@ tas_init_frame_rates(unsigned int *prop, unsigned int l) /* * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. */ -static void *PMacAlloc(unsigned int size, int flags) +static void *PMacAlloc(unsigned int size, gfp_t flags) { return kmalloc(size, flags); } diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 558db5311e06..d59f60b26410 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -69,7 +69,7 @@ static int write_sq_block_size_half, write_sq_block_size_quarter; /*** Low level stuff *********************************************************/ -static void *AmiAlloc(unsigned int size, int flags); +static void *AmiAlloc(unsigned int size, gfp_t flags); static void AmiFree(void *obj, unsigned int size); static int AmiIrqInit(void); #ifdef MODULE @@ -317,7 +317,7 @@ static inline void StopDMA(void) enable_heartbeat(); } -static void *AmiAlloc(unsigned int size, int flags) +static void *AmiAlloc(unsigned int size, gfp_t flags) { return amiga_chip_alloc((long)size, "dmasound [Paula]"); } diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index 92c25a0174db..1ddaa6284b08 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c @@ -36,7 +36,7 @@ static int expand_data; /* Data for expanding */ /*** Low level stuff *********************************************************/ -static void *Q40Alloc(unsigned int size, int flags); +static void *Q40Alloc(unsigned int size, gfp_t flags); static void Q40Free(void *, unsigned int); static int Q40IrqInit(void); #ifdef MODULE @@ -358,7 +358,7 @@ static TRANS transQ40Compressing = { /*** Low level stuff *********************************************************/ -static void *Q40Alloc(unsigned int size, int flags) +static void *Q40Alloc(unsigned int size, gfp_t flags) { return kmalloc(size, flags); /* change to vmalloc */ } From 53f9fc93f90a43701d6aaf3919be0614bb088b83 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:24 -0400 Subject: [PATCH 0892/1939] [PATCH] gfp_t: remaining bits of arch/* Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/pci_iommu.c | 2 +- arch/ia64/sn/kernel/xpc.h | 2 +- arch/ppc/mm/pgtable.c | 4 ++-- arch/sparc64/solaris/socksys.c | 2 +- arch/sparc64/solaris/timod.c | 2 +- arch/um/kernel/mem.c | 2 +- arch/um/kernel/process_kern.c | 2 +- include/asm-um/page.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 7cb23f12ecbd..c468e312e5f8 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -397,7 +397,7 @@ pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) { void *cpu_addr; long order = get_order(size); - int gfp = GFP_ATOMIC; + gfp_t gfp = GFP_ATOMIC; try_again: cpu_addr = (void *)__get_free_pages(gfp, order); diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h index d0ee635daf2e..e5f5a4e51f70 100644 --- a/arch/ia64/sn/kernel/xpc.h +++ b/arch/ia64/sn/kernel/xpc.h @@ -939,7 +939,7 @@ xpc_map_bte_errors(bte_result_t error) static inline void * -xpc_kmalloc_cacheline_aligned(size_t size, int flags, void **base) +xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) { /* see if kmalloc will give us cachline aligned memory by default */ *base = kmalloc(size, flags); diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 81a3d7446d37..43505b1fc5d8 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -114,9 +114,9 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) struct page *ptepage; #ifdef CONFIG_HIGHPTE - int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT; + gfp_t flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT; #else - int flags = GFP_KERNEL | __GFP_REPEAT; + gfp_t flags = GFP_KERNEL | __GFP_REPEAT; #endif ptepage = alloc_pages(flags, 0); diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index d7c1c76582cc..fc6669e8dde1 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -49,7 +49,7 @@ IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW, #else -extern void * mykmalloc(size_t s, int gfp); +extern void * mykmalloc(size_t s, gfp_t gfp); extern void mykfree(void *); #endif diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index aaad29c35c83..b84e5456b025 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -39,7 +39,7 @@ static char * page = NULL ; #else -void * mykmalloc(size_t s, int gfp) +void * mykmalloc(size_t s, gfp_t gfp) { static char * page; static size_t free; diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index ea008b031a8f..462cc9d65386 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -252,7 +252,7 @@ void paging_init(void) #endif } -struct page *arch_validate(struct page *page, int mask, int order) +struct page *arch_validate(struct page *page, gfp_t mask, int order) { unsigned long addr, zero = 0; int i; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index ea65db679e9c..0d73ceeece72 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -80,7 +80,7 @@ void free_stack(unsigned long stack, int order) unsigned long alloc_stack(int order, int atomic) { unsigned long page; - int flags = GFP_KERNEL; + gfp_t flags = GFP_KERNEL; if (atomic) flags = GFP_ATOMIC; diff --git a/include/asm-um/page.h b/include/asm-um/page.h index 2c192abe9aeb..0229814af31e 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -115,7 +115,7 @@ extern unsigned long uml_physmem; #define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) -extern struct page *arch_validate(struct page *page, int mask, int order); +extern struct page *arch_validate(struct page *page, gfp_t mask, int order); #define HAVE_ARCH_VALIDATE extern void arch_free_page(struct page *page, int order); From 9e24974db6b01ec067c24de09588282b6a1407f0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:29 -0400 Subject: [PATCH 0893/1939] [PATCH] gfp_t: drivers/net Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/cassini.c | 4 ++-- drivers/net/lance.c | 4 ++-- drivers/net/myri_sbus.c | 2 +- drivers/net/myri_sbus.h | 2 +- drivers/net/sunbmac.c | 3 ++- drivers/net/sunbmac.h | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 2e617424d3fb..50f43dbf31ae 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -489,7 +489,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page) /* local page allocation routines for the receive buffers. jumbo pages * require at least 8K contiguous and 8K aligned buffers. */ -static cas_page_t *cas_page_alloc(struct cas *cp, const int flags) +static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags) { cas_page_t *page; @@ -561,7 +561,7 @@ static void cas_spare_free(struct cas *cp) } /* replenish spares if needed */ -static void cas_spare_recover(struct cas *cp, const int flags) +static void cas_spare_recover(struct cas *cp, const gfp_t flags) { struct list_head list, *elem, *tmp; int needed, i; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index b4929beb33b2..1d75ca0bb939 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -298,7 +298,7 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static void lance_init_ring(struct net_device *dev, int mode); +static void lance_init_ring(struct net_device *dev, gfp_t mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -846,7 +846,7 @@ lance_purge_ring(struct net_device *dev) /* Initialize the LANCE Rx and Tx rings. */ static void -lance_init_ring(struct net_device *dev, int gfp) +lance_init_ring(struct net_device *dev, gfp_t gfp) { struct lance_private *lp = dev->priv; int i; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index f0996ce5c268..6c86dca62e2a 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -277,7 +277,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) struct recvq __iomem *rq = mp->rq; struct myri_rxd __iomem *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; - int gfp_flags = GFP_KERNEL; + gfp_t gfp_flags = GFP_KERNEL; int i; if (from_irq || in_interrupt()) diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 9391e55a5e92..47722f708a41 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -296,7 +296,7 @@ struct myri_eth { /* We use this to acquire receive skb's that we can DMA directly into. */ #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *myri_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *myri_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index f88f5e32b714..cfaf47c63c58 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -214,7 +214,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) { struct bmac_init_block *bb = bp->bmac_block; struct net_device *dev = bp->dev; - int i, gfp_flags = GFP_KERNEL; + int i; + gfp_t gfp_flags = GFP_KERNEL; if (from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index 5674003fc38a..b0dbc5187143 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -339,7 +339,7 @@ struct bigmac { #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; From b4e3ca1ab1ae9ae86134126dcdc88da1caaa32ca Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:34 -0400 Subject: [PATCH 0894/1939] [PATCH] gfp_t: remaining bits of drivers/* Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/loop.c | 2 +- drivers/block/rd.c | 2 +- drivers/char/n_tty.c | 2 +- drivers/ieee1394/eth1394.c | 2 +- drivers/md/bitmap.c | 2 +- drivers/md/dm-crypt.c | 2 +- drivers/s390/net/fsm.c | 2 +- drivers/s390/net/fsm.h | 2 +- include/linux/i2o.h | 4 ++-- include/linux/loop.h | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b35e08876dd4..96c664af8d06 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -881,7 +881,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) { struct file *filp = lo->lo_backing_file; - int gfp = lo->old_gfp_mask; + gfp_t gfp = lo->old_gfp_mask; if (lo->lo_state != Lo_bound) return -ENXIO; diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 145c1fbffe01..68c60a5bcdab 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -348,7 +348,7 @@ static int rd_open(struct inode *inode, struct file *filp) struct block_device *bdev = inode->i_bdev; struct address_space *mapping; unsigned bsize; - int gfp_mask; + gfp_t gfp_mask; inode = igrab(bdev->bd_inode); rd_bdev[unit] = bdev; diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index c9bdf544ed2c..c556f4d3ccd7 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 4802bbbb6dc9..c9e92d85c893 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1630,7 +1630,7 @@ static void ether1394_complete_cb(void *__ptask) /* Transmit a packet (called by kernel) */ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) { - int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct eth1394hdr *eth; struct eth1394_priv *priv = netdev_priv(dev); int proto; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2fba2bbe72d8..01654fcabc52 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -91,7 +91,7 @@ int bitmap_active(struct bitmap *bitmap) #define WRITE_POOL_SIZE 256 /* mempool for queueing pending writes on the bitmap file */ -static void *write_pool_alloc(unsigned int gfp_flags, void *data) +static void *write_pool_alloc(gfp_t gfp_flags, void *data) { return kmalloc(sizeof(struct page_list), gfp_flags); } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b6148f6f7836..28c1a628621f 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -331,7 +331,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size, { struct bio *bio; unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - int gfp_mask = GFP_NOIO | __GFP_HIGHMEM; + gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM; unsigned int i; /* diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index fa09440d82e5..38f50b7129a2 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -16,7 +16,7 @@ MODULE_LICENSE("GPL"); fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, - int nr_events, const fsm_node *tmpl, int tmpl_len, int order) + int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order) { int i; fsm_instance *this; diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h index f9a011001eb6..1b8a7e7c34f3 100644 --- a/drivers/s390/net/fsm.h +++ b/drivers/s390/net/fsm.h @@ -110,7 +110,7 @@ extern fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, int nr_events, const fsm_node *tmpl, - int tmpl_len, int order); + int tmpl_len, gfp_t order); /** * Releases an FSM diff --git a/include/linux/i2o.h b/include/linux/i2o.h index bdc286ec947c..b4af45aad25d 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -492,7 +492,7 @@ static inline int i2o_dma_map_sg(struct i2o_controller *c, * Returns 0 on success or -ENOMEM on failure. */ static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, - size_t len, unsigned int gfp_mask) + size_t len, gfp_t gfp_mask) { struct pci_dev *pdev = to_pci_dev(dev); int dma_64 = 0; @@ -551,7 +551,7 @@ static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr) * Returns the 0 on success or negative error code on failure. */ static inline int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, - size_t len, unsigned int gfp_mask) + size_t len, gfp_t gfp_mask) { i2o_dma_free(dev, addr); diff --git a/include/linux/loop.h b/include/linux/loop.h index 53fa51595443..40f63c9879d2 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -52,7 +52,7 @@ struct loop_device { unsigned lo_blocksize; void *key_data; - int old_gfp_mask; + gfp_t old_gfp_mask; spinlock_t lo_lock; struct bio *lo_bio; From c4cdd038318863e912e9b992489f61497f98b442 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:39 -0400 Subject: [PATCH 0895/1939] [PATCH] gfp_t: reiserfs mapping_set_gfp_mask() use Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/reiserfs/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 87ac9dc8b381..72e120798677 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -453,7 +453,7 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) struct page *page; /* We can deadlock if we try to free dentries, and an unlink/rmdir has just occured - GFP_NOFS avoids this */ - mapping->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS; + mapping_set_gfp_mask(mapping, GFP_NOFS); page = read_cache_page(mapping, n, (filler_t *) mapping->a_ops->readpage, NULL); if (!IS_ERR(page)) { From 260b23674fdb570f3235ce55892246bef1c24c2a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:22:44 -0400 Subject: [PATCH 0896/1939] [PATCH] gfp_t: the rest zone handling, mapping->flags handling Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 2 +- include/linux/pagemap.h | 7 ++++--- mm/highmem.c | 14 +++++++++----- mm/page_alloc.c | 29 +++++++++++++++-------------- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 5ed471b58f4f..7519eb4191e7 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -302,7 +302,7 @@ void get_zone_counts(unsigned long *active, unsigned long *inactive, void build_all_zonelists(void); void wakeup_kswapd(struct zone *zone, int order); int zone_watermark_ok(struct zone *z, int order, unsigned long mark, - int alloc_type, int can_try_harder, int gfp_high); + int alloc_type, int can_try_harder, gfp_t gfp_high); #ifdef CONFIG_HAVE_MEMORY_PRESENT void memory_present(int nid, unsigned long start, unsigned long end); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index efbae53fb078..ba6c310a055f 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -21,16 +21,17 @@ static inline gfp_t mapping_gfp_mask(struct address_space * mapping) { - return mapping->flags & __GFP_BITS_MASK; + return (__force gfp_t)mapping->flags & __GFP_BITS_MASK; } /* * This is non-atomic. Only to be used before the mapping is activated. * Probably needs a barrier... */ -static inline void mapping_set_gfp_mask(struct address_space *m, int mask) +static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) { - m->flags = (m->flags & ~__GFP_BITS_MASK) | mask; + m->flags = (m->flags & ~(__force unsigned long)__GFP_BITS_MASK) | + (__force unsigned long)mask; } /* diff --git a/mm/highmem.c b/mm/highmem.c index 90e1861e2da0..ce2e7e8bbfa7 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -30,11 +30,9 @@ static mempool_t *page_pool, *isa_page_pool; -static void *page_pool_alloc(gfp_t gfp_mask, void *data) +static void *page_pool_alloc_isa(gfp_t gfp_mask, void *data) { - unsigned int gfp = gfp_mask | (unsigned int) (long) data; - - return alloc_page(gfp); + return alloc_page(gfp_mask | GFP_DMA); } static void page_pool_free(void *page, void *data) @@ -51,6 +49,12 @@ static void page_pool_free(void *page, void *data) * n means that there are (n-1) current users of it. */ #ifdef CONFIG_HIGHMEM + +static void *page_pool_alloc(gfp_t gfp_mask, void *data) +{ + return alloc_page(gfp_mask); +} + static int pkmap_count[LAST_PKMAP]; static unsigned int last_pkmap_nr; static __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock); @@ -267,7 +271,7 @@ int init_emergency_isa_pool(void) if (isa_page_pool) return 0; - isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc, page_pool_free, (void *) __GFP_DMA); + isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc_isa, page_pool_free, NULL); if (!isa_page_pool) BUG(); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index aa43ae3ab8c9..94c864eac9c4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -734,7 +734,7 @@ buffered_rmqueue(struct zone *zone, int order, gfp_t gfp_flags) * of the allocation. */ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, - int classzone_idx, int can_try_harder, int gfp_high) + int classzone_idx, int can_try_harder, gfp_t gfp_high) { /* free_pages my go negative - that's OK */ long min = mark, free_pages = z->free_pages - (1 << order) + 1; @@ -777,7 +777,7 @@ struct page * fastcall __alloc_pages(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist) { - const int wait = gfp_mask & __GFP_WAIT; + const gfp_t wait = gfp_mask & __GFP_WAIT; struct zone **zones, *z; struct page *page; struct reclaim_state reclaim_state; @@ -996,7 +996,7 @@ fastcall unsigned long get_zeroed_page(gfp_t gfp_mask) * get_zeroed_page() returns a 32-bit address, which cannot represent * a highmem page */ - BUG_ON(gfp_mask & __GFP_HIGHMEM); + BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0); page = alloc_pages(gfp_mask | __GFP_ZERO, 0); if (page) @@ -1428,6 +1428,16 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli return j; } +static inline int highest_zone(int zone_bits) +{ + int res = ZONE_NORMAL; + if (zone_bits & (__force int)__GFP_HIGHMEM) + res = ZONE_HIGHMEM; + if (zone_bits & (__force int)__GFP_DMA) + res = ZONE_DMA; + return res; +} + #ifdef CONFIG_NUMA #define MAX_NODE_LOAD (num_online_nodes()) static int __initdata node_load[MAX_NUMNODES]; @@ -1524,11 +1534,7 @@ static void __init build_zonelists(pg_data_t *pgdat) zonelist = pgdat->node_zonelists + i; for (j = 0; zonelist->zones[j] != NULL; j++); - k = ZONE_NORMAL; - if (i & __GFP_HIGHMEM) - k = ZONE_HIGHMEM; - if (i & __GFP_DMA) - k = ZONE_DMA; + k = highest_zone(i); j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); zonelist->zones[j] = NULL; @@ -1549,12 +1555,7 @@ static void __init build_zonelists(pg_data_t *pgdat) zonelist = pgdat->node_zonelists + i; j = 0; - k = ZONE_NORMAL; - if (i & __GFP_HIGHMEM) - k = ZONE_HIGHMEM; - if (i & __GFP_DMA) - k = ZONE_DMA; - + k = highest_zone(i); j = build_zonelists_node(pgdat, zonelist, j, k); /* * Now we build the zonelist so that it contains the zones From 0b83f1400fa6e5f0d4afcff033628a16c163862a Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Fri, 28 Oct 2005 16:19:37 +0100 Subject: [PATCH 0897/1939] [ARM] 2918/1: [update] Base port of Comdial MP1000 platfrom Patch from Jon Ringle Updated 2898/1 per comments: - Removed fixup - Moved code in mach-mp1000/ to mach-clps711x/ - Cleaned up code in mp1000-seprom.c. Eliminated code that displayed the contents of the eeprom Please comment. Signed-off-by: Jon Ringle Signed-off-by: Russell King --- arch/arm/Kconfig | 3 +- arch/arm/boot/compressed/head.S | 3 +- arch/arm/configs/mp1000_defconfig | 897 ++++++++++++++++++ arch/arm/mach-clps711x/Kconfig | 11 + arch/arm/mach-clps711x/Makefile | 1 + arch/arm/mach-clps711x/mp1000-mach.c | 49 + arch/arm/mach-clps711x/mp1000-mm.c | 47 + arch/arm/mach-clps711x/mp1000-seprom.c | 195 ++++ drivers/serial/clps711x.c | 9 + include/asm-arm/arch-clps711x/hardware.h | 117 +++ include/asm-arm/arch-clps711x/mp1000-seprom.h | 77 ++ 11 files changed, 1407 insertions(+), 2 deletions(-) create mode 100644 arch/arm/configs/mp1000_defconfig create mode 100644 arch/arm/mach-clps711x/mp1000-mach.c create mode 100644 arch/arm/mach-clps711x/mp1000-mm.c create mode 100644 arch/arm/mach-clps711x/mp1000-seprom.c create mode 100644 include/asm-arm/arch-clps711x/mp1000-seprom.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 11fff042aa81..d885cc48bae1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -687,7 +687,8 @@ source "drivers/acorn/block/Kconfig" if PCMCIA || ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX \ || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \ - || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE + || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \ + || MACH_MP1000 source "drivers/ide/Kconfig" endif diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 7c7f475e213e..a54d2eb64892 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -39,7 +39,8 @@ defined(CONFIG_ARCH_IXP4XX) || \ defined(CONFIG_ARCH_IXP2000) || \ defined(CONFIG_ARCH_LH7A40X) || \ - defined(CONFIG_ARCH_OMAP) + defined(CONFIG_ARCH_OMAP) || \ + defined(CONFIG_MACH_MP1000) .macro loadsp, rb addruart \rb .endm diff --git a/arch/arm/configs/mp1000_defconfig b/arch/arm/configs/mp1000_defconfig new file mode 100644 index 000000000000..d2cbc6fada1d --- /dev/null +++ b/arch/arm/configs/mp1000_defconfig @@ -0,0 +1,897 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.14-rc1 +# Fri Sep 16 15:48:13 2005 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=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_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +CONFIG_ARCH_CLPS711X=y +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CEIVA is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +CONFIG_MACH_MP1000=y +CONFIG_MP1000_90MHZ=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM720T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_LV4T=y +CONFIG_CPU_CACHE_V4=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WT=y +CONFIG_CPU_TLB_V4WT=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_SMP is not set +CONFIG_PREEMPT=y +# CONFIG_NO_IDLE_HZ is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyCL,38400 root=/dev/discs/disc0/part1 ip=any cs89x0_media=rj45" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# 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=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_IPV6_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 +# 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 +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK 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 + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=3 +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2 +CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=m +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=m +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x0000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_EDB7312=m +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_MP1000=y +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# 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_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# 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 is not set +CONFIG_IDE_ARM=y +CONFIG_BLK_DEV_IDE_MP1000=y +# CONFIG_BLK_DEV_IDEDMA 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=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# 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 + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +CONFIG_CS89x0=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN 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 + +# +# 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=y + +# +# 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=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CLPS711X=y +CONFIG_SERIAL_CLPS711X_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +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=y +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY 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=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QUOTACTL=y +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_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_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_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=m +# 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=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_EXPERIMENTAL 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 is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig index 0793dcf54f2e..d5c155045762 100644 --- a/arch/arm/mach-clps711x/Kconfig +++ b/arch/arm/mach-clps711x/Kconfig @@ -69,6 +69,17 @@ config EP72XX_ROM_BOOT You almost surely want to say N here. +config MACH_MP1000 + bool "MACH_MP1000" + help + Say Y if you intend to run the kernel on the Comdial MP1000 platform. + +config MP1000_90MHZ + bool "MP1000_90MHZ" + depends on MACH_MP1000 + help + Say Y if you have the MP1000 configured to be set at 90MHZ rather than 74MHZ + endmenu endif diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile index 4a197315f0cf..8a6dc1ccf8fe 100644 --- a/arch/arm/mach-clps711x/Makefile +++ b/arch/arm/mach-clps711x/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o +obj-$(CONFIG_MACH_MP1000) += mp1000-mach.o mp1000-mm.o mp1000-seprom.o obj-$(CONFIG_ARCH_P720T) += p720t.o leds-$(CONFIG_ARCH_P720T) += p720t-leds.o obj-$(CONFIG_LEDS) += $(leds-y) diff --git a/arch/arm/mach-clps711x/mp1000-mach.c b/arch/arm/mach-clps711x/mp1000-mach.c new file mode 100644 index 000000000000..c2816bcde5e7 --- /dev/null +++ b/arch/arm/mach-clps711x/mp1000-mach.c @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/mach-mp1000/mp1000.c + * + * Copyright (C) 2005 Comdial 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 + */ +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" + +extern void mp1000_map_io(void); + +static void __init mp1000_init(void) +{ + seprom_init(); +} + +MACHINE_START(MP1000, "Comdial MP1000") + /* Maintainer: Jon Ringle */ + .phys_ram = 0xc0000000, + .phys_io = 0x80000000, + .io_pg_offst = ((0xff000000) >> 18) & 0xfffc, + .boot_params = 0xc0015100, + .map_io = mp1000_map_io, + .init_irq = clps711x_init_irq, + .init_machine = mp1000_init, + .timer = &clps711x_timer, +MACHINE_END + diff --git a/arch/arm/mach-clps711x/mp1000-mm.c b/arch/arm/mach-clps711x/mp1000-mm.c new file mode 100644 index 000000000000..20e810b0ec0c --- /dev/null +++ b/arch/arm/mach-clps711x/mp1000-mm.c @@ -0,0 +1,47 @@ +/* + * linux/arch/arm/mach-mp1000/mm.c + * + * Extra MM routines for the MP1000 + * + * Copyright (C) 2005 Comdial 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 + */ +#include +#include + +#include +#include +#include +#include + +#include + +extern void clps711x_map_io(void); + +static struct map_desc mp1000_io_desc[] __initdata = { + { MP1000_EIO_BASE, MP1000_EIO_START, MP1000_EIO_SIZE, MT_DEVICE }, + { MP1000_FIO_BASE, MP1000_FIO_START, MP1000_FIO_SIZE, MT_DEVICE }, + { MP1000_LIO_BASE, MP1000_LIO_START, MP1000_LIO_SIZE, MT_DEVICE }, + { MP1000_NIO_BASE, MP1000_NIO_START, MP1000_NIO_SIZE, MT_DEVICE }, + { MP1000_IDE_BASE, MP1000_IDE_START, MP1000_IDE_SIZE, MT_DEVICE }, + { MP1000_DSP_BASE, MP1000_DSP_START, MP1000_DSP_SIZE, MT_DEVICE } +}; + +void __init mp1000_map_io(void) +{ + clps711x_map_io(); + iotable_init(mp1000_io_desc, ARRAY_SIZE(mp1000_io_desc)); +} diff --git a/arch/arm/mach-clps711x/mp1000-seprom.c b/arch/arm/mach-clps711x/mp1000-seprom.c new file mode 100644 index 000000000000..b22d0bebb851 --- /dev/null +++ b/arch/arm/mach-clps711x/mp1000-seprom.c @@ -0,0 +1,195 @@ +/*` + * mp1000-seprom.c + * + * This file contains the Serial EEPROM code for the MP1000 board + * + * Copyright (C) 2005 Comdial 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 + * + */ + +#include +#include +#include +#include +#include + +/* If SepromInit() can initialize and checksum the seprom successfully, */ +/* then it will point seprom_data_ptr at the shadow copy. */ + +static eeprom_struct seprom_data; /* shadow copy of seprom content */ + +eeprom_struct *seprom_data_ptr = 0; /* 0 => not initialized */ + +/* + * Port D Bit 5 is Chip Select for EEPROM + * Port E Bit 0 is Input, Data out from EEPROM + * Port E Bit 1 is Output, Data in to EEPROM + * Port E Bit 2 is Output, CLK to EEPROM + */ + +static char *port_d_ptr = (char *)(CLPS7111_VIRT_BASE + PDDR); +static char *port_e_ptr = (char *)(CLPS7111_VIRT_BASE + PEDR); + +#define NO_OF_SHORTS 64 // Device is 64 x 16 bits +#define ENABLE_RW 0 +#define DISABLE_RW 1 + +static inline void toggle_seprom_clock(void) +{ + *port_e_ptr |= HwPortESepromCLK; + *port_e_ptr &= ~(HwPortESepromCLK); +} + +static inline void select_eeprom(void) +{ + *port_d_ptr |= HwPortDEECS; + *port_e_ptr &= ~(HwPortESepromCLK); +} + +static inline void deselect_eeprom(void) +{ + *port_d_ptr &= ~(HwPortDEECS); + *port_e_ptr &= ~(HwPortESepromDIn); +} + +/* + * GetSepromDataPtr - returns pointer to shadow (RAM) copy of seprom + * and returns 0 if seprom is not initialized or + * has a checksum error. + */ + +eeprom_struct* get_seprom_ptr(void) +{ + return seprom_data_ptr; +} + +unsigned char* get_eeprom_mac_address(void) +{ + return seprom_data_ptr->variant.eprom_struct.mac_Address; +} + +/* + * ReadSProm, Physically reads data from the Serial PROM + */ +static void read_sprom(short address, int length, eeprom_struct *buffer) +{ + short data = COMMAND_READ | (address & 0x3F); + short bit; + int i; + + select_eeprom(); + + // Clock in 9 bits of the command + for (i = 0, bit = 0x100; i < 9; i++, bit >>= 1) { + if (data & bit) + *port_e_ptr |= HwPortESepromDIn; + else + *port_e_ptr &= ~(HwPortESepromDIn); + + toggle_seprom_clock(); + } + + // + // Now read one or more shorts of data from the Seprom + // + while (length-- > 0) { + data = 0; + + // Read 16 bits at a time + for (i = 0; i < 16; i++) { + data <<= 1; + toggle_seprom_clock(); + data |= *port_e_ptr & HwPortESepromDOut; + + } + + buffer->variant.eprom_short_data[address++] = data; + } + + deselect_eeprom(); + + return; +} + + + +/* + * ReadSerialPROM + * + * Input: Pointer to array of 64 x 16 Bits + * + * Output: if no problem reading data is filled in + */ +static void read_serial_prom(eeprom_struct *data) +{ + read_sprom(0, 64, data); +} + + +// +// Compute Serial EEPROM checksum +// +// Input: Pointer to struct with Eprom data +// +// Output: The computed Eprom checksum +// +static short compute_seprom_checksum(eeprom_struct *data) +{ + short checksum = 0; + int i; + + for (i = 0; i < 126; i++) { + checksum += (short)data->variant.eprom_byte_data[i]; + } + + return((short)(0x5555 - (checksum & 0xFFFF))); +} + +// +// Make sure the data port bits for the SEPROM are correctly initialised +// + +void __init seprom_init(void) +{ + short checksum; + + // Init Port D + *(char *)(CLPS7111_VIRT_BASE + PDDDR) = 0x0; + *(char *)(CLPS7111_VIRT_BASE + PDDR) = 0x15; + + // Init Port E + *(int *)(CLPS7111_VIRT_BASE + PEDDR) = 0x06; + *(int *)(CLPS7111_VIRT_BASE + PEDR) = 0x04; + + // + // Make sure that EEPROM struct size never exceeds 128 bytes + // + if (sizeof(eeprom_struct) > 128) { + panic("Serial PROM struct size > 128, aborting read\n"); + } + + read_serial_prom(&seprom_data); + + checksum = compute_seprom_checksum(&seprom_data); + + if (checksum != seprom_data.variant.eprom_short_data[63]) { + panic("Serial EEPROM checksum failed\n"); + } + + seprom_data_ptr = &seprom_data; +} + diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 87ef368384fb..6a67e8f585b3 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -408,7 +408,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON1, .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 0, @@ -417,7 +421,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON2, .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 1, @@ -551,6 +559,7 @@ console_initcall(clps711xuart_console_init); static struct uart_driver clps711x_reg = { .driver_name = "ttyCL", .dev_name = "ttyCL", + .devfs_name = "ttyCL", .major = SERIAL_CLPS711X_MAJOR, .minor = SERIAL_CLPS711X_MINOR, .nr = UART_NR, diff --git a/include/asm-arm/arch-clps711x/hardware.h b/include/asm-arm/arch-clps711x/hardware.h index 1386871e1a5a..f864c367c934 100644 --- a/include/asm-arm/arch-clps711x/hardware.h +++ b/include/asm-arm/arch-clps711x/hardware.h @@ -235,4 +235,121 @@ #define CEIVA_PB0_BLK_BTN (1<<0) #endif // #if defined (CONFIG_ARCH_CEIVA) +#if defined (CONFIG_MACH_MP1000) +/* NOR FLASH */ +#define MP1000_NIO_BASE 0xf9000000 /* virtual */ +#define MP1000_NIO_START CS0_PHYS_BASE /* physical */ +#define MP1000_NIO_SIZE 0x00400000 + +/* DSP Interface */ +#define MP1000_DSP_BASE 0xfa000000 /* virtual */ +#define MP1000_DSP_START CS1_PHYS_BASE /* physical */ +#define MP1000_DSP_SIZE 0x00100000 + +/* LCD, DAA/DSP, RTC, DAA RW Reg all in CS2 */ +#define MP1000_LIO_BASE 0xfb000000 /* virtual */ +#define MP1000_LIO_START CS2_PHYS_BASE /* physical */ +#define MP1000_LIO_SIZE 0x00100000 + +/* NAND FLASH */ +#define MP1000_FIO_BASE 0xfc000000 /* virtual */ +#define MP1000_FIO_START CS3_PHYS_BASE /* physical */ +#define MP1000_FIO_SIZE 0x00800000 + +/* Ethernet */ +#define MP1000_EIO_BASE 0xfd000000 /* virtual */ +#define MP1000_EIO_START CS4_PHYS_BASE /* physical */ +#define MP1000_EIO_SIZE 0x00100000 + +#define MP1000_LCD_OFFSET 0x00000000 /* LCD offset in CS2 */ +#define MP1000_DDD_OFFSET 0x00001000 /* DAA/DAI/DSP sft reset offst*/ +#define MP1000_RTC_OFFSET 0x00002000 /* RTC offset in CS2 */ +#define MP1000_DAA_OFFSET 0x00003000 /* DAA RW reg offset in CS2 */ + +/* IDE */ +#define MP1000_IDE_BASE 0xfe000000 /* virtual */ +#define MP1000_IDE_START CS5_PHYS_BASE /* physical */ +#define MP1000_IDE_SIZE 0x00100000 /* actually it's only 0x1000 */ + +#define IRQ_HARDDISK IRQ_EINT2 + +/* + * IDE registers definition + */ + +#define IDE_CONTROL_BASE (MP1000_IDE_BASE + 0x1000) +#define IDE_BASE_OFF (MP1000_IDE_BASE) + +#define IDE_WRITE_DEVICE_DATA (IDE_BASE_OFF + 0x0) +#define IDE_FEATURES_REGISTER (IDE_BASE_OFF + 0x2) +#define IDE_SECTOR_COUNT_REGISTER (IDE_BASE_OFF + 0x4) +#define IDE_SECTOR_NUMBER_REGISTER (IDE_BASE_OFF + 0x6) +#define IDE_CYLINDER_LOW_REGISTER (IDE_BASE_OFF + 0x8) +#define IDE_CYLINDER_HIGH_REGISTER (IDE_BASE_OFF + 0xa) +#define IDE_DEVICE_HEAD_REGISTER (IDE_BASE_OFF + 0xc) +#define IDE_COMMAND_DATA_REGISTER (IDE_BASE_OFF + 0xe) +#define IDE_DEVICE_CONTROL_REGISTER (IDE_CONTROL_BASE + 0xc) + +#define IDE_IRQ IRQ_EINT2 + + +#define RTC_PORT(x) (MP1000_LIO_BASE+0x2000 + (x*2)) +#define RTC_ALWAYS_BCD 0 + +/* +// Definitions of the bit fields in the HwPortA register for the +// MP1000 board. +*/ +#define HwPortAKeyboardRow1 0x00000001 +#define HwPortAKeyboardRow2 0x00000002 +#define HwPortAKeyboardRow3 0x00000004 +#define HwPortAKeyboardRow4 0x00000008 +#define HwPortAKeyboardRow5 0x00000010 +#define HwPortAKeyboardRow6 0x00000020 +#define HwPortALCDEnable 0x00000040 +#define HwPortAOffhook 0x00000080 + +/* +// Definitions of the bit fields in the HwPortB register for the +// MP1000 board. +*/ +#define HwPortBL3Mode 0x00000001 +#define HwPortBL3Clk 0x00000002 +#define HwPortBSClk 0x00000001 +#define HwPortBSData 0x00000002 +#define HwPortBL3Data 0x00000004 +#define HwPortBMute 0x00000008 +#define HwPortBQD0 0x00000010 +#define HwPortBQD1 0x00000020 +#define HwPortBQD2 0x00000040 +#define HwPortBQD3 0x00000080 + +/* +// Definitions of the bit fields in the HwPortD register for the +// MP1000 board. +*/ +#define HwPortDLED1 0x00000001 +#define HwPortDLED2 0x00000002 +#define HwPortDLED3 0x00000004 +#define HwPortDLED4 0x00000008 +#define HwPortDLED5 0x00000010 +#define HwPortDEECS 0x00000020 +#define HwPortBRTS 0x00000040 +#define HwPortBRI 0x00000080 + + +/* +// Definitions of the bit fields in the HwPortE register for the +// MP1000 board. +*/ + +#define HwPortECLE 0x00000001 +#define HwPortESepromDOut 0x00000001 +#define HwPortEALE 0x00000002 +#define HwPortESepromDIn 0x00000002 +#define HwPortENANDCS 0x00000004 +#define HwPortESepromCLK 0x00000004 + +#endif // #if defined (CONFIG_MACH_MP1000) + #endif diff --git a/include/asm-arm/arch-clps711x/mp1000-seprom.h b/include/asm-arm/arch-clps711x/mp1000-seprom.h new file mode 100644 index 000000000000..3e5566cf9666 --- /dev/null +++ b/include/asm-arm/arch-clps711x/mp1000-seprom.h @@ -0,0 +1,77 @@ +#ifndef MP1000_SEPROM_H +#define MP1000_SEPROM_H + +/* + * mp1000-seprom.h + * + * + * This file contains the Serial EEPROM definitions for the MP1000 board + * + * Copyright (C) 2005 Comdial 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 + * + */ + +#define COMMAND_ERASE (0x1C0) +#define COMMAND_ERASE_ALL (0x120) +#define COMMAND_WRITE_DISABLE (0x100) +#define COMMAND_WRITE_ENABLE (0x130) +#define COMMAND_READ (0x180) +#define COMMAND_WRITE (0x140) +#define COMMAND_WRITE_ALL (0x110) + +// +// Serial EEPROM data format +// + +#define PACKED __attribute__ ((packed)) + +typedef struct _EEPROM { + union { + unsigned char eprom_byte_data[128]; + unsigned short eprom_short_data[64]; + struct { + unsigned char version PACKED; // EEPROM Version "1" for now + unsigned char box_id PACKED; // Box ID (Standalone, SOHO, embedded, etc) + unsigned char major_hw_version PACKED; // Major Hardware version (Hex) + unsigned char minor_hw_version PACKED; // Minor Hardware Version (Hex) + unsigned char mfg_id[3] PACKED; // Manufacturer ID (3 character Alphabetic) + unsigned char mfg_serial_number[10] PACKED; // Manufacturer Serial number + unsigned char mfg_date[3] PACKED; // Date of Mfg (Formatted YY:MM:DD) + unsigned char country PACKED; // Country of deployment + unsigned char mac_Address[6] PACKED; // MAC Address + unsigned char oem_string[20] PACKED; // OEM ID string + unsigned short feature_bits1 PACKED; // Feature Bits 1 + unsigned short feature_bits2 PACKED; // Feature Bits 2 + unsigned char filler[75] PACKED; // Unused/Undefined “0” initialized + unsigned short checksum PACKED; // byte accumulated short checksum + } eprom_struct; + } variant; +} eeprom_struct; + +/* These settings must be mutually exclusive */ +#define FEATURE_BITS1_DRAMSIZE_16MEG 0x0001 /* 0 signifies 4 MEG system */ +#define FEATURE_BITS1_DRAMSIZE_8MEG 0x0002 /* 1 in bit 1 = 8MEG system */ +#define FEATURE_BITS1_DRAMSIZE_64MEG 0x0004 /* 1 in bit 2 = 64MEG system */ + +#define FEATURE_BITS1_CPUIS90MEG 0x0010 + +extern void seprom_init(void); +extern eeprom_struct* get_seprom_ptr(void); +extern unsigned char* get_eeprom_mac_address(void); + +#endif /* MP1000_SEPROM_H */ + From 917f68f8163eb877a6d71c5b446ee236645c2944 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Fri, 28 Oct 2005 16:19:38 +0100 Subject: [PATCH 0898/1939] [ARM] 2919/1: CS8900A ethernet driver modifications for the Comdial MP1000 Patch from Jon Ringle This patch gives support for the CS8900A ethernet chip on the Comdial MP1000 Signed-off-by: Jon Ringle Signed-off-by: Russell King --- drivers/net/Kconfig | 2 +- drivers/net/cs89x0.c | 14 +++++++++++++- drivers/net/cs89x0.h | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c748b0e16419..3e1e323e3003 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1330,7 +1330,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 || MACH_MP1000 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index a6078ad9b654..bfdae10036ed 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -182,6 +182,10 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0}; static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0}; +#elif defined(CONFIG_MACH_MP1000) +#include +static unsigned int netcard_portlist[] __initdata = {MP1000_EIO_BASE+0x300, 0}; +static unsigned int cs8900_irq_map[] = {IRQ_EINT3,0,0,0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -590,6 +594,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) cnt -= j; } } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + memcpy(dev->dev_addr, get_eeprom_mac_address(), ETH_ALEN); + } else #endif if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == @@ -649,6 +657,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (1) { printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n"); } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + lp->force |= FORCE_RJ45; + } else #endif if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n"); @@ -1231,7 +1243,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) +#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) && !defined(CONFIG_MACH_MP1000) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index decea264f121..f19d1ebe0183 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,7 +16,7 @@ #include -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) +#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) || defined (CONFIG_MACH_MP1000) /* IXDP2401/IXDP2801 uses dword-aligned register addressing */ #define CS89x0_PORT(reg) ((reg) * 2) #else From 80a18573cea2e6d8e95abe4d42bfc5f97761999a Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Fri, 28 Oct 2005 16:25:01 +0100 Subject: [PATCH 0899/1939] [ARM] 2787/2: PXA27x low power modes support Patch from Todd Poynor Add symbols for PXA2xx PWRMODE register M field that selects low-power mode, replace unadorned constants. Honor power mode parameter of pxa_cpu_suspend(mode), no longer force to 3 (sleep). Full Deep Sleep low-power mode support for PXA27x is pending generic PM interfaces to select more than 2 suspend-to-RAM-style power modes, but this is expected soon. This can be hardcoded in the meantime by replacing the pxa_cpu_suspend() parameter value. From David Burrage and Todd Poynor. Try #2 removes one of the register copies and moves the code to save the pxa_cpu_suspend parameter to immediately surround the call that requires the parameter value be preserved. Signed-off-by: Todd Poynor Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mach-pxa/pxa25x.c | 2 +- arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/sleep.S | 7 +++++-- arch/arm/mach-pxa/standby.S | 2 +- include/asm-arm/arch-pxa/pxa-regs.h | 7 +++++++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 7869c3b4e62f..573a5758e781 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -129,7 +129,7 @@ void pxa_cpu_pm_enter(suspend_state_t state) case PM_SUSPEND_MEM: /* set resume return address */ PSPR = virt_to_phys(pxa_cpu_resume); - pxa_cpu_suspend(3); + pxa_cpu_suspend(PWRMODE_SLEEP); break; } } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 9a791b07118d..09a5d593f04b 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -157,7 +157,7 @@ void pxa_cpu_pm_enter(suspend_state_t state) case PM_SUSPEND_MEM: /* set resume return address */ PSPR = virt_to_phys(pxa_cpu_resume); - pxa_cpu_suspend(3); + pxa_cpu_suspend(PWRMODE_SLEEP); break; } } diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 5786ccad938c..c9862688ff3d 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -28,7 +28,9 @@ /* * pxa_cpu_suspend() * - * Forces CPU into sleep state + * Forces CPU into sleep state. + * + * r0 = value for PWRMODE M field for desired sleep state */ ENTRY(pxa_cpu_suspend) @@ -53,6 +55,7 @@ ENTRY(pxa_cpu_suspend) mov r10, sp stmfd sp!, {r3 - r10} + mov r5, r0 @ save sleep mode @ preserve phys address of stack mov r0, sp bl sleep_phys_sp @@ -66,7 +69,7 @@ ENTRY(pxa_cpu_suspend) @ (also workaround for sighting 28071) @ prepare value for sleep mode - mov r1, #3 @ sleep mode + mov r1, r5 @ sleep mode @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S index 8a3f27b76784..6f6dbbd08021 100644 --- a/arch/arm/mach-pxa/standby.S +++ b/arch/arm/mach-pxa/standby.S @@ -21,7 +21,7 @@ ENTRY(pxa_cpu_standby) ldr r0, =PSSR mov r1, #(PSSR_PH | PSSR_STS) - mov r2, #2 + mov r2, #PWRMODE_STANDBY mov r3, #UNCACHED_PHYS_0 @ Read mem context in. ldr ip, [r3] b 1f diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index 3af7165ab0d7..a6a34edec813 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -2282,4 +2282,11 @@ #endif +/* PWRMODE register M field values */ + +#define PWRMODE_IDLE 0x1 +#define PWRMODE_STANDBY 0x2 +#define PWRMODE_SLEEP 0x3 +#define PWRMODE_DEEPSLEEP 0x7 + #endif From d9e29649875df82828167dd45c802d942db863ba Mon Sep 17 00:00:00 2001 From: Matt Reimer Date: Fri, 28 Oct 2005 16:25:02 +0100 Subject: [PATCH 0900/1939] [ARM] 3029/1: Add HWUART support for PXA 255/26x Patch from Matt Reimer Adds support for HWUART on PXA 255 / 26x. This patch originally came from http://svn.rungie.com/svn/gumstix-buildroot/trunk/sources/kernel-patches/000-gumstix-hwuart.patch and has been tweaked by me. Signed-off-by: Matt Reimer Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mach-pxa/generic.c | 18 ++++++++++++++- drivers/serial/pxa.c | 21 ++++++++++++++++- include/asm-arm/arch-pxa/pxa-regs.h | 33 +++++++++++++++++++++++++++ include/asm-arm/arch-pxa/uncompress.h | 1 + 4 files changed, 71 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 719b91e93fa2..218eb9671fa3 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -253,6 +253,10 @@ static struct platform_device stuart_device = { .name = "pxa2xx-uart", .id = 2, }; +static struct platform_device hwuart_device = { + .name = "pxa2xx-uart", + .id = 3, +}; static struct resource i2c_resources[] = { { @@ -310,7 +314,19 @@ static struct platform_device *devices[] __initdata = { static int __init pxa_init(void) { - return platform_add_devices(devices, ARRAY_SIZE(devices)); + int cpuid, ret; + + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + if (ret) + return ret; + + /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ + cpuid = read_cpuid(CPUID_ID); + if (((cpuid >> 4) & 0xfff) == 0x2d0 || + ((cpuid >> 4) & 0xfff) == 0x290) + ret = platform_device_register(&hwuart_device); + + return ret; } subsys_initcall(pxa_init); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 90c2a86c421b..005f027e081a 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -358,6 +358,9 @@ static int serial_pxa_startup(struct uart_port *port) unsigned long flags; int retval; + if (port->line == 3) /* HWUART */ + up->mcr |= UART_MCR_AFE; + else up->mcr = 0; /* @@ -481,8 +484,10 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios, if ((up->port.uartclk / quot) < (2400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; - else + else if ((up->port.uartclk / quot) < (230400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; /* * Ok, we're now changing the port state. Do it with @@ -772,6 +777,20 @@ static struct uart_pxa_port serial_pxa_ports[] = { .ops = &serial_pxa_pops, .line = 2, }, + }, { /* HWUART */ + .name = "HWUART", + .cken = CKEN4_HWUART, + .port = { + .type = PORT_PXA, + .iotype = UPIO_MEM, + .membase = (void *)&HWUART, + .mapbase = __PREG(HWUART), + .irq = IRQ_HWUART, + .uartclk = 921600 * 16, + .fifosize = 64, + .ops = &serial_pxa_pops, + .line = 3, + }, } }; diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index a6a34edec813..75f085dc9894 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -326,6 +326,25 @@ #define STDLL __REG(0x40700000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ #define STDLH __REG(0x40700004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ +/* Hardware UART (HWUART) */ +#define HWUART HWRBR +#define HWRBR __REG(0x41600000) /* Receive Buffer Register (read only) */ +#define HWTHR __REG(0x41600000) /* Transmit Holding Register (write only) */ +#define HWIER __REG(0x41600004) /* Interrupt Enable Register (read/write) */ +#define HWIIR __REG(0x41600008) /* Interrupt ID Register (read only) */ +#define HWFCR __REG(0x41600008) /* FIFO Control Register (write only) */ +#define HWLCR __REG(0x4160000C) /* Line Control Register (read/write) */ +#define HWMCR __REG(0x41600010) /* Modem Control Register (read/write) */ +#define HWLSR __REG(0x41600014) /* Line Status Register (read only) */ +#define HWMSR __REG(0x41600018) /* Modem Status Register (read only) */ +#define HWSPR __REG(0x4160001C) /* Scratch Pad Register (read/write) */ +#define HWISR __REG(0x41600020) /* Infrared Selection Register (read/write) */ +#define HWFOR __REG(0x41600024) /* Receive FIFO Occupancy Register (read only) */ +#define HWABR __REG(0x41600028) /* Auto-Baud Control Register (read/write) */ +#define HWACR __REG(0x4160002C) /* Auto-Baud Count Register (read only) */ +#define HWDLL __REG(0x41600000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ +#define HWDLH __REG(0x41600004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ + #define IER_DMAE (1 << 7) /* DMA Requests Enable */ #define IER_UUE (1 << 6) /* UART Unit Enable */ #define IER_NRZE (1 << 5) /* NRZ coding Enable */ @@ -1250,9 +1269,13 @@ #define GPIO40_FFDTR 40 /* FFUART data terminal Ready */ #define GPIO41_FFRTS 41 /* FFUART request to send */ #define GPIO42_BTRXD 42 /* BTUART receive data */ +#define GPIO42_HWRXD 42 /* HWUART receive data */ #define GPIO43_BTTXD 43 /* BTUART transmit data */ +#define GPIO43_HWTXD 43 /* HWUART transmit data */ #define GPIO44_BTCTS 44 /* BTUART clear to send */ +#define GPIO44_HWCTS 44 /* HWUART clear to send */ #define GPIO45_BTRTS 45 /* BTUART request to send */ +#define GPIO45_HWRTS 45 /* HWUART request to send */ #define GPIO45_AC97_SYSCLK 45 /* AC97 System Clock */ #define GPIO46_ICPRXD 46 /* ICP receive data */ #define GPIO46_STRXD 46 /* STD_UART receive data */ @@ -1378,17 +1401,26 @@ #define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) #define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) #define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) +#define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN) #define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT) +#define GPIO43_HWTXD_MD (43 | GPIO_ALT_FN_3_OUT) #define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN) +#define GPIO44_HWCTS_MD (44 | GPIO_ALT_FN_3_IN) #define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT) +#define GPIO45_HWRTS_MD (45 | GPIO_ALT_FN_3_OUT) #define GPIO45_SYSCLK_AC97_MD (45 | GPIO_ALT_FN_1_OUT) #define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN) #define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN) #define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT) #define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT) #define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT) +#define GPIO48_HWTXD_MD (48 | GPIO_ALT_FN_1_OUT) +#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT) +#define GPIO49_HWRXD_MD (49 | GPIO_ALT_FN_1_IN) #define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT) #define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT) +#define GPIO50_HWCTS_MD (50 | GPIO_ALT_FN_1_IN) +#define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT) #define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) #define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) #define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) @@ -1763,6 +1795,7 @@ #define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */ #define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */ #define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */ +#define CKEN4_HWUART (1 << 4) /* HWUART Unit Clock Enable */ #define CKEN4_SSP3 (1 << 4) /* SSP3 Unit Clock Enable */ #define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */ #define CKEN3_SSP2 (1 << 3) /* SSP2 Unit Clock Enable */ diff --git a/include/asm-arm/arch-pxa/uncompress.h b/include/asm-arm/arch-pxa/uncompress.h index 4428d3eb7432..fe38090444e0 100644 --- a/include/asm-arm/arch-pxa/uncompress.h +++ b/include/asm-arm/arch-pxa/uncompress.h @@ -12,6 +12,7 @@ #define FFUART ((volatile unsigned long *)0x40100000) #define BTUART ((volatile unsigned long *)0x40200000) #define STUART ((volatile unsigned long *)0x40700000) +#define HWUART ((volatile unsigned long *)0x41600000) #define UART FFUART From dd5b295ff880d5a0699a52f84106f16702c298f2 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Fri, 28 Oct 2005 16:27:24 +0100 Subject: [PATCH 0901/1939] [ARM] 2921/1: Support for the RTC / nvram on the Comdial MP1000 Patch from Jon Ringle This adds support for the RTC and nvram on the Comdial MP1000 Signed-off-by: Jon Ringle Signed-off-by: Russell King --- drivers/char/nvram.c | 110 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 1af733d07321..9e24bbd4090c 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -32,9 +32,11 @@ * added changelog * 1.2 Erik Gilling: Cobalt Networks support * Tim Hockin: general cleanup, Cobalt support + * 1.3 Jon Ringle: Comdial MP1000 support + * */ -#define NVRAM_VERSION "1.2" +#define NVRAM_VERSION "1.3" #include #include @@ -45,6 +47,7 @@ #define PC 1 #define ATARI 2 #define COBALT 3 +#define MP1000 4 /* select machine configuration */ #if defined(CONFIG_ATARI) @@ -54,6 +57,9 @@ # if defined(CONFIG_COBALT) # include # define MACH COBALT +# elif defined(CONFIG_MACH_MP1000) +# undef MACH +# define MACH MP1000 # else # define MACH PC # endif @@ -112,6 +118,23 @@ #endif +#if MACH == MP1000 + +/* RTC in a MP1000 */ +#define CHECK_DRIVER_INIT() 1 + +#define MP1000_CKS_RANGE_START 0 +#define MP1000_CKS_RANGE_END 111 +#define MP1000_CKS_LOC 112 + +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) + +#define mach_check_checksum mp1000_check_checksum +#define mach_set_checksum mp1000_set_checksum +#define mach_proc_infos mp1000_proc_infos + +#endif + /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with * rtc_lock held. Due to the index-port/data-port design of the RTC, we * don't want two different things trying to get to it at once. (e.g. the @@ -915,6 +938,91 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len, #endif /* MACH == ATARI */ +#if MACH == MP1000 + +static int +mp1000_check_checksum(void) +{ + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + + expect = __nvram_read_byte(MP1000_CKS_LOC+1)<<8 | + __nvram_read_byte(MP1000_CKS_LOC); + return ((sum & 0xffff) == expect); +} + +static void +mp1000_set_checksum(void) +{ + int i; + unsigned short sum = 0; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + __nvram_write_byte(sum >> 8, MP1000_CKS_LOC + 1); + __nvram_write_byte(sum & 0xff, MP1000_CKS_LOC); +} + +#ifdef CONFIG_PROC_FS + +#define SERVER_N_LEN 32 +#define PATH_N_LEN 32 +#define FILE_N_LEN 32 +#define NVRAM_MAGIC_SIG 0xdead + +typedef struct NvRamImage +{ + unsigned short int magic; + unsigned short int mode; + char fname[FILE_N_LEN]; + char path[PATH_N_LEN]; + char server[SERVER_N_LEN]; + char pad[12]; +} NvRam; + +static int +mp1000_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + int checksum; + NvRam* nv = (NvRam*)nvram; + + spin_lock_irq(&rtc_lock); + checksum = __nvram_check_checksum(); + spin_unlock_irq(&rtc_lock); + + PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + + switch( nv->mode ) + { + case 0 : + PRINT_PROC( "\tMode 0, tftp prompt\n" ); + break; + case 1 : + PRINT_PROC( "\tMode 1, booting from disk\n" ); + break; + case 2 : + PRINT_PROC( "\tMode 2, Alternate boot from disk /boot/%s\n", nv->fname ); + break; + case 3 : + PRINT_PROC( "\tMode 3, Booting from net:\n" ); + PRINT_PROC( "\t\t%s:%s%s\n",nv->server, nv->path, nv->fname ); + break; + default: + PRINT_PROC( "\tInconsistant nvram?\n" ); + break; + } + + return 1; +} +#endif + +#endif /* MACH == MP1000 */ + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(__nvram_read_byte); From 8573b80f020dce7aefa3237f1e932d562b65323d Mon Sep 17 00:00:00 2001 From: Erik Hovland Date: Fri, 28 Oct 2005 16:28:04 +0100 Subject: [PATCH 0902/1939] [ARM] 3031/1: fix typos in comments of mmc.h Patch from Erik Hovland I noticed that the same typo (i before c in associated) showed up twice in the file kernel/include/linux/mmc/mmc.h. This patch fixes both of the instances I found with this mistake. The typos are in comments and should have no affect on working code. E Signed-off-by: Erik Hovland Signed-off-by: Russell King --- include/linux/mmc/mmc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 1ab78e8d6c53..aef6042f8f0b 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -50,7 +50,7 @@ struct mmc_command { #define MMC_ERR_INVALID 5 struct mmc_data *data; /* data segment associated with cmd */ - struct mmc_request *mrq; /* assoicated request */ + struct mmc_request *mrq; /* associated request */ }; struct mmc_data { @@ -68,7 +68,7 @@ struct mmc_data { unsigned int bytes_xfered; struct mmc_command *stop; /* stop command */ - struct mmc_request *mrq; /* assoicated request */ + struct mmc_request *mrq; /* associated request */ unsigned int sg_len; /* size of scatter list */ struct scatterlist *sg; /* I/O scatter list */ From a999cb04b4bfb4a2243383f00d5714b8d7163035 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 28 Oct 2005 16:35:46 +0100 Subject: [PATCH 0903/1939] [ARM] 3035/1: RISCOS compat code fix Patch from Nicolas Pitre From: Daniel Jacobowitz > I also fixed a bug that confused me greatly while trying to debug: one > SIGILL has long been a SIGSEGV because of some broken RISCOS > compatibility code. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/kernel/traps.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index f6de76e0a45d..baa09601a64e 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -345,7 +345,9 @@ static int bad_syscall(int n, struct pt_regs *regs) struct thread_info *thread = current_thread_info(); siginfo_t info; - if (current->personality != PER_LINUX && thread->exec_domain->handler) { + if (current->personality != PER_LINUX && + current->personality != PER_LINUX_32BIT && + thread->exec_domain->handler) { thread->exec_domain->handler(n, regs); return regs->ARM_r0; } From 6f475c0133eb91c7df3b056843dc33d2824368a2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 28 Oct 2005 16:39:33 +0100 Subject: [PATCH 0904/1939] [ARM] 2897/2: PXA2xx IRDA support Patch from Nicolas Pitre This is the PXA2xx common IRDA driver, plus platform support for Lubbock and Mainstone. Signed-off-by: Nicolas Pitre Acked-by: Jean Tourrilhes Signed-off-by: Russell King --- arch/arm/mach-pxa/generic.c | 18 + arch/arm/mach-pxa/lubbock.c | 20 + arch/arm/mach-pxa/mainstone.c | 25 + drivers/net/irda/Kconfig | 10 + drivers/net/irda/Makefile | 1 + drivers/net/irda/pxaficp_ir.c | 871 ++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/irda.h | 17 + include/asm-arm/arch-pxa/pxa-regs.h | 2 - 8 files changed, 962 insertions(+), 2 deletions(-) create mode 100644 drivers/net/irda/pxaficp_ir.c create mode 100644 include/asm-arm/arch-pxa/irda.h diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 218eb9671fa3..3248bc9b9495 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "generic.h" @@ -301,6 +302,22 @@ static struct platform_device i2s_device = { .num_resources = ARRAY_SIZE(i2s_resources), }; +static u64 pxaficp_dmamask = ~(u32)0; + +static struct platform_device pxaficp_device = { + .name = "pxa2xx-ir", + .id = -1, + .dev = { + .dma_mask = &pxaficp_dmamask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) +{ + pxaficp_device.dev.platform_data = info; +} + static struct platform_device *devices[] __initdata = { &pxamci_device, &udc_device, @@ -308,6 +325,7 @@ static struct platform_device *devices[] __initdata = { &ffuart_device, &btuart_device, &stuart_device, + &pxaficp_device, &i2c_device, &i2s_device, }; diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 69abc7f61ed0..beccf455f796 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -237,11 +238,30 @@ static struct pxamci_platform_data lubbock_mci_platform_data = { .init = lubbock_mci_init, }; +static void lubbock_irda_transceiver_mode(struct device *dev, int mode) +{ + unsigned long flags; + + local_irq_save(flags); + if (mode & IR_SIRMODE) { + LUB_MISC_WR &= ~(1 << 4); + } else if (mode & IR_FIRMODE) { + LUB_MISC_WR |= 1 << 4; + } + local_irq_restore(flags); +} + +static struct pxaficp_platform_data lubbock_ficp_platform_data = { + .transceiver_cap = IR_SIRMODE | IR_FIRMODE, + .transceiver_mode = lubbock_irda_transceiver_mode, +}; + static void __init lubbock_init(void) { pxa_set_udc_info(&udc_info); set_pxa_fb_info(&sharp_lm8v31); pxa_set_mci_info(&lubbock_mci_platform_data); + pxa_set_ficp_info(&lubbock_ficp_platform_data); (void) platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 8b4a21623fc0..a48c64026e1f 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "generic.h" @@ -294,6 +295,29 @@ static struct pxamci_platform_data mainstone_mci_platform_data = { .exit = mainstone_mci_exit, }; +static void mainstone_irda_transceiver_mode(struct device *dev, int mode) +{ + unsigned long flags; + + local_irq_save(flags); + if (mode & IR_SIRMODE) { + MST_MSCWR1 &= ~MST_MSCWR1_IRDA_FIR; + } else if (mode & IR_FIRMODE) { + MST_MSCWR1 |= MST_MSCWR1_IRDA_FIR; + } + if (mode & IR_OFF) { + MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_OFF; + } else { + MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_FULL; + } + local_irq_restore(flags); +} + +static struct pxaficp_platform_data mainstone_ficp_platform_data = { + .transceiver_cap = IR_SIRMODE | IR_FIRMODE | IR_OFF, + .transceiver_mode = mainstone_irda_transceiver_mode, +}; + static void __init mainstone_init(void) { /* @@ -313,6 +337,7 @@ static void __init mainstone_init(void) set_pxa_fb_info(&toshiba_ltm035a776c); pxa_set_mci_info(&mainstone_mci_platform_data); + pxa_set_ficp_info(&mainstone_ficp_platform_data); } diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index ca5914091d3a..d54156f11e61 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -400,5 +400,15 @@ config VIA_FIR To compile it as a module, choose M here: the module will be called via-ircc. +config PXA_FICP + tristate "Intel PXA2xx Internal FICP" + depends on ARCH_PXA && IRDA + help + Say Y or M here if you want to build support for the PXA2xx + built-in IRDA interface which can support both SIR and FIR. + This driver relies on platform specific helper routines so + available capabilities may vary from one PXA2xx target to + another. + endmenu diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 29a8bd812b21..e7a8b7f7f5dd 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o obj-$(CONFIG_VIA_FIR) += via-ircc.o +obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o # Old dongle drivers for old SIR drivers obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c new file mode 100644 index 000000000000..aef80f5e7c9c --- /dev/null +++ b/drivers/net/irda/pxaficp_ir.c @@ -0,0 +1,871 @@ +/* + * linux/drivers/net/irda/pxaficp_ir.c + * + * Based on sa1100_ir.c by Russell King + * + * Changes copyright (C) 2003-2005 MontaVista Software, Inc. + * + * 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. + * + * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MACH_MAINSTONE +#include +#endif + +#define IrSR_RXPL_NEG_IS_ZERO (1<<4) +#define IrSR_RXPL_POS_IS_ZERO 0x0 +#define IrSR_TXPL_NEG_IS_ZERO (1<<3) +#define IrSR_TXPL_POS_IS_ZERO 0x0 +#define IrSR_XMODE_PULSE_1_6 (1<<2) +#define IrSR_XMODE_PULSE_3_16 0x0 +#define IrSR_RCVEIR_IR_MODE (1<<1) +#define IrSR_RCVEIR_UART_MODE 0x0 +#define IrSR_XMITIR_IR_MODE (1<<0) +#define IrSR_XMITIR_UART_MODE 0x0 + +#define IrSR_IR_RECEIVE_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_IR_MODE | \ + IrSR_XMITIR_UART_MODE) + +#define IrSR_IR_TRANSMIT_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_UART_MODE | \ + IrSR_XMITIR_IR_MODE) + +struct pxa_irda { + int speed; + int newspeed; + unsigned long last_oscr; + + unsigned char *dma_rx_buff; + unsigned char *dma_tx_buff; + dma_addr_t dma_rx_buff_phy; + dma_addr_t dma_tx_buff_phy; + unsigned int dma_tx_buff_len; + int txdma; + int rxdma; + + struct net_device_stats stats; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct device *dev; + struct pxaficp_platform_data *pdata; +}; + + +#define IS_FIR(si) ((si)->speed >= 4000000) +#define IRDA_FRAME_SIZE_LIMIT 2047 + +inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) +{ + DCSR(si->rxdma) = DCSR_NODESC; + DSADR(si->rxdma) = __PREG(ICDR); + DTADR(si->rxdma) = si->dma_rx_buff_phy; + DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT; + DCSR(si->rxdma) |= DCSR_RUN; +} + +inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) +{ + DCSR(si->txdma) = DCSR_NODESC; + DSADR(si->txdma) = si->dma_tx_buff_phy; + DTADR(si->txdma) = __PREG(ICDR); + DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len; + DCSR(si->txdma) |= DCSR_RUN; +} + +/* + * Set the IrDA communications speed. + */ +static int pxa_irda_set_speed(struct pxa_irda *si, int speed) +{ + unsigned long flags; + unsigned int divisor; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + + /* refer to PXA250/210 Developer's Manual 10-7 */ + /* BaudRate = 14.7456 MHz / (16*Divisor) */ + divisor = 14745600 / (16 * speed); + + local_irq_save(flags); + + if (IS_FIR(si)) { + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + pxa_set_cken(CKEN13_FICP, 0); + + /* set board transceiver to SIR mode */ + si->pdata->transceiver_mode(si->dev, IR_SIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* enable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 1); + } + + /* disable STUART first */ + STIER = 0; + + /* access DLL & DLH */ + STLCR |= LCR_DLAB; + STDLL = divisor & 0xff; + STDLH = divisor >> 8; + STLCR &= ~LCR_DLAB; + + si->speed = speed; + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + + local_irq_restore(flags); + break; + + case 4000000: + local_irq_save(flags); + + /* disable STUART */ + STIER = 0; + STISR = 0; + pxa_set_cken(CKEN5_STUART, 0); + + /* disable FICP first */ + ICCR0 = 0; + + /* set board transceiver to FIR mode */ + si->pdata->transceiver_mode(si->dev, IR_FIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_ICPRXD_MD); + pxa_gpio_mode(GPIO47_ICPTXD_MD); + + /* enable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 1); + + si->speed = speed; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + local_irq_restore(flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* SIR interrupt service routine. */ +static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int iir, lsr, data; + + iir = STIIR; + + switch (iir & 0x0F) { + case 0x06: /* Receiver Line Status */ + lsr = STLSR; + while (lsr & LSR_FIFOE) { + data = STRBR; + if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { + printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); + si->stats.rx_errors++; + if (lsr & LSR_FE) + si->stats.rx_frame_errors++; + if (lsr & LSR_OE) + si->stats.rx_fifo_errors++; + } else { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, data); + } + lsr = STLSR; + } + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x04: /* Received Data Available */ + /* forth through */ + + case 0x0C: /* Character Timeout Indication */ + do { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); + } while (STLSR & LSR_DR); + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x02: /* Transmit FIFO Data Request */ + while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { + STTHR = *si->tx_buff.data++; + si->tx_buff.len -= 1; + } + + if (si->tx_buff.len == 0) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->tx_buff.data - + si->tx_buff.head; + + /* We need to ensure that the transmitter has finished. */ + while ((STLSR & LSR_TEMT) == 0) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * Ok, we've finished transmitting. Now enable + * the receiver. Sometimes we get a receive IRQ + * immediately after a transmit... + */ + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + /* enable IR Receiver, disable IR Transmitter */ + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + /* enable STUART and receive interrupts */ + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + } + /* I'm hungry! */ + netif_wake_queue(dev); + } + break; + } + + return IRQ_HANDLED; +} + +/* FIR Receive DMA interrupt handler */ +static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs) +{ + int dcsr = DCSR(channel); + + DCSR(channel) = dcsr & ~DCSR_RUN; + + printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr); +} + +/* FIR Transmit DMA interrupt handler */ +static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs) +{ + struct net_device *dev = data; + struct pxa_irda *si = netdev_priv(dev); + int dcsr; + + dcsr = DCSR(channel); + DCSR(channel) = dcsr & ~DCSR_RUN; + + if (dcsr & DCSR_ENDINTR) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->dma_tx_buff_len; + } else { + si->stats.tx_errors++; + } + + while (ICSR1 & ICSR1_TBY) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * HACK: It looks like the TBY bit is dropped too soon. + * Without this delay things break. + */ + udelay(120); + + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + } + netif_wake_queue(dev); +} + +/* EIF(Error in FIFO/End in Frame) handler for FIR */ +static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) +{ + unsigned int len, stat, data; + + /* Get the current data position. */ + len = DTADR(si->rxdma) - si->dma_rx_buff_phy; + + do { + /* Read Status, and then Data. */ + stat = ICSR1; + rmb(); + data = ICDR; + + if (stat & (ICSR1_CRE | ICSR1_ROR)) { + si->stats.rx_errors++; + if (stat & ICSR1_CRE) { + printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); + si->stats.rx_crc_errors++; + } + if (stat & ICSR1_ROR) { + printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); + si->stats.rx_frame_errors++; + } + } else { + si->dma_rx_buff[len++] = data; + } + /* If we hit the end of frame, there's no point in continuing. */ + if (stat & ICSR1_EOF) + break; + } while (ICSR0 & ICSR0_EIF); + + if (stat & ICSR1_EOF) { + /* end of frame. */ + struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); + si->stats.rx_dropped++; + return; + } + + /* Align IP header to 20 bytes */ + skb_reserve(skb, 1); + memcpy(skb->data, si->dma_rx_buff, len); + skb_put(skb, len); + + /* Feed it to IrLAP */ + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + + si->stats.rx_packets++; + si->stats.rx_bytes += len; + + dev->last_rx = jiffies; + } +} + +/* FIR interrupt handler */ +static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int icsr0; + + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + si->last_oscr = OSCR; + icsr0 = ICSR0; + + if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { + if (icsr0 & ICSR0_FRE) { + printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); + si->stats.rx_frame_errors++; + } else { + printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); + si->stats.rx_errors++; + } + ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB); + } + + if (icsr0 & ICSR0_EIF) { + /* An error in FIFO occured, or there is a end of frame */ + pxa_irda_fir_irq_eif(si, dev); + } + + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + return IRQ_HANDLED; +} + +/* hard_xmit interface of irda device */ +static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + /* + * Does this packet contain a request to change the interface + * speed? If so, remember it until we complete the transmission + * of this frame. + */ + if (speed != si->speed && speed != -1) + si->newspeed = speed; + + /* + * If this is an empty frame, we can bypass a lot. + */ + if (skb->len == 0) { + if (si->newspeed) { + si->newspeed = 0; + pxa_irda_set_speed(si, speed); + } + dev_kfree_skb(skb); + return 0; + } + + netif_stop_queue(dev); + + if (!IS_FIR(si)) { + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); + + /* Disable STUART interrupts and switch to transmit mode. */ + STIER = 0; + STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6; + + /* enable STUART and transmit interrupts */ + STIER = IER_UUE | IER_TIE; + } else { + unsigned long mtt = irda_get_mtt(skb); + + si->dma_tx_buff_len = skb->len; + memcpy(si->dma_tx_buff, skb->data, skb->len); + + if (mtt) + while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) + cpu_relax(); + + /* stop RX DMA, disable FICP */ + DCSR(si->rxdma) &= ~DCSR_RUN; + ICCR0 = 0; + + pxa_irda_fir_dma_tx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_TXE; + } + + dev_kfree_skb(skb); + dev->trans_start = jiffies; + return 0; +} + +static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct pxa_irda *si = netdev_priv(dev); + int ret; + + switch (cmd) { + case SIOCSBANDWIDTH: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (netif_running(dev)) { + ret = pxa_irda_set_speed(si, + rq->ifr_baudrate); + } else { + printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + ret = 0; + rq->ifr_receiving = IS_FIR(si) ? 0 + : si->rx_buff.state != OUTSIDE_FRAME; + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *pxa_irda_stats(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + return &si->stats; +} + +static void pxa_irda_startup(struct pxa_irda *si) +{ + /* Disable STUART interrupts */ + STIER = 0; + /* enable STUART interrupt to the processor */ + STMCR = MCR_OUT2; + /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ + STLCR = LCR_WLS0 | LCR_WLS1; + /* enable FIFO, we use FIFO to improve performance */ + STFCR = FCR_TRFIFOE | FCR_ITL_32; + + /* disable FICP */ + ICCR0 = 0; + /* configure FICP ICCR2 */ + ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; + + /* configure DMAC */ + DRCMR17 = si->rxdma | DRCMR_MAPVLD; + DRCMR18 = si->txdma | DRCMR_MAPVLD; + + /* force SIR reinitialization */ + si->speed = 4000000; + pxa_irda_set_speed(si, 9600); + + printk(KERN_DEBUG "pxa_ir: irda startup\n"); +} + +static void pxa_irda_shutdown(struct pxa_irda *si) +{ + unsigned long flags; + + local_irq_save(flags); + + /* disable STUART and interrupt */ + STIER = 0; + /* disable STUART SIR mode */ + STISR = 0; + /* disable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 0); + + /* disable DMA */ + DCSR(si->txdma) &= ~DCSR_RUN; + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + /* disable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 0); + + DRCMR17 = 0; + DRCMR18 = 0; + + local_irq_restore(flags); + + /* power off board transceiver */ + si->pdata->transceiver_mode(si->dev, IR_OFF); + + printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); +} + +static int pxa_irda_start(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int err; + + si->speed = 9600; + + err = request_irq(IRQ_STUART, pxa_irda_sir_irq, 0, dev->name, dev); + if (err) + goto err_irq1; + + err = request_irq(IRQ_ICP, pxa_irda_fir_irq, 0, dev->name, dev); + if (err) + goto err_irq2; + + /* + * The interrupt must remain disabled for now. + */ + disable_irq(IRQ_STUART); + disable_irq(IRQ_ICP); + + err = -EBUSY; + si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev); + if (si->rxdma < 0) + goto err_rx_dma; + + si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev); + if (si->txdma < 0) + goto err_tx_dma; + + err = -ENOMEM; + si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_rx_buff_phy, GFP_KERNEL ); + if (!si->dma_rx_buff) + goto err_dma_rx_buff; + + si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_tx_buff_phy, GFP_KERNEL ); + if (!si->dma_tx_buff) + goto err_dma_tx_buff; + + /* Setup the serial port for the initial speed. */ + pxa_irda_startup(si); + + /* + * Open a new IrLAP layer instance. + */ + si->irlap = irlap_open(dev, &si->qos, "pxa"); + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + /* + * Now enable the interrupt and start the queue + */ + enable_irq(IRQ_STUART); + enable_irq(IRQ_ICP); + netif_start_queue(dev); + + printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); + + return 0; + +err_irlap: + pxa_irda_shutdown(si); + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); +err_dma_tx_buff: + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); +err_dma_rx_buff: + pxa_free_dma(si->txdma); +err_tx_dma: + pxa_free_dma(si->rxdma); +err_rx_dma: + free_irq(IRQ_ICP, dev); +err_irq2: + free_irq(IRQ_STUART, dev); +err_irq1: + + return err; +} + +static int pxa_irda_stop(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + + netif_stop_queue(dev); + + pxa_irda_shutdown(si); + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + free_irq(IRQ_STUART, dev); + free_irq(IRQ_ICP, dev); + + pxa_free_dma(si->rxdma); + pxa_free_dma(si->txdma); + + if (si->dma_rx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); + if (si->dma_tx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); + + printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); + return 0; +} + +static int pxa_irda_suspend(struct device *_dev, pm_message_t state, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; + + if (netif_running(dev)) { + si = netdev_priv(dev); + netif_device_detach(dev); + pxa_irda_shutdown(si); + } + + return 0; +} + +static int pxa_irda_resume(struct device *_dev, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (!dev || level != RESUME_ENABLE) + return 0; + + if (netif_running(dev)) { + si = netdev_priv(dev); + pxa_irda_startup(si); + netif_device_attach(dev); + netif_wake_queue(dev); + } + + return 0; +} + + +static int pxa_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int pxa_irda_probe(struct device *_dev) +{ + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct pxa_irda *si; + unsigned int baudrate_mask; + int err; + + if (!pdev->dev.platform_data) + return -ENODEV; + + err = request_mem_region(__PREG(STUART), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + + err = request_mem_region(__PREG(FICP), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + + dev = alloc_irdadev(sizeof(struct pxa_irda)); + if (!dev) + goto err_mem_3; + + si = netdev_priv(dev); + si->dev = &pdev->dev; + si->pdata = pdev->dev.platform_data; + + /* + * Initialise the SIR buffers + */ + err = pxa_irda_init_iobuf(&si->rx_buff, 14384); + if (err) + goto err_mem_4; + err = pxa_irda_init_iobuf(&si->tx_buff, 4000); + if (err) + goto err_mem_5; + + dev->hard_start_xmit = pxa_irda_hard_xmit; + dev->open = pxa_irda_start; + dev->stop = pxa_irda_stop; + dev->do_ioctl = pxa_irda_ioctl; + dev->get_stats = pxa_irda_stats; + + irda_init_max_qos_capabilies(&si->qos); + + baudrate_mask = 0; + if (si->pdata->transceiver_cap & IR_SIRMODE) + baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + if (si->pdata->transceiver_cap & IR_FIRMODE) + baudrate_mask |= IR_4000000 << 8; + + si->qos.baud_rate.bits &= baudrate_mask; + si->qos.min_turn_time.bits = 7; /* 1ms or more */ + + irda_qos_bits_to_value(&si->qos); + + err = register_netdev(dev); + + if (err == 0) + dev_set_drvdata(&pdev->dev, dev); + + if (err) { + kfree(si->tx_buff.head); +err_mem_5: + kfree(si->rx_buff.head); +err_mem_4: + free_netdev(dev); +err_mem_3: + release_mem_region(__PREG(FICP), 0x1c); +err_mem_2: + release_mem_region(__PREG(STUART), 0x24); + } +err_mem_1: + return err; +} + +static int pxa_irda_remove(struct device *_dev) +{ + struct net_device *dev = dev_get_drvdata(_dev); + + if (dev) { + struct pxa_irda *si = netdev_priv(dev); + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(STUART), 0x24); + release_mem_region(__PREG(FICP), 0x1c); + + return 0; +} + +static struct device_driver pxa_ir_driver = { + .name = "pxa2xx-ir", + .bus = &platform_bus_type, + .probe = pxa_irda_probe, + .remove = pxa_irda_remove, + .suspend = pxa_irda_suspend, + .resume = pxa_irda_resume, +}; + +static int __init pxa_irda_init(void) +{ + return driver_register(&pxa_ir_driver); +} + +static void __exit pxa_irda_exit(void) +{ + driver_unregister(&pxa_ir_driver); +} + +module_init(pxa_irda_init); +module_exit(pxa_irda_exit); + +MODULE_LICENSE("GPL"); diff --git a/include/asm-arm/arch-pxa/irda.h b/include/asm-arm/arch-pxa/irda.h new file mode 100644 index 000000000000..748406f384c2 --- /dev/null +++ b/include/asm-arm/arch-pxa/irda.h @@ -0,0 +1,17 @@ +#ifndef ASMARM_ARCH_IRDA_H +#define ASMARM_ARCH_IRDA_H + +/* board specific transceiver capabilities */ + +#define IR_OFF 1 +#define IR_SIRMODE 2 +#define IR_FIRMODE 4 + +struct pxaficp_platform_data { + int transceiver_cap; + void (*transceiver_mode)(struct device *dev, int mode); +}; + +extern void pxa_set_ficp_info(struct pxaficp_platform_data *info); + +#endif diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index 75f085dc9894..a75a2470f4f5 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -1032,14 +1032,12 @@ #define ICCR0_LBM (1 << 1) /* Loopback mode */ #define ICCR0_ITR (1 << 0) /* IrDA transmission */ -#ifdef CONFIG_PXA27x #define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */ #define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */ #define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */ #define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */ #define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */ #define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */ -#endif #ifdef CONFIG_PXA27x #define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */ From 13b1d677d2c872e2d05ef6241b499b6e1f6f91ba Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:40 +0100 Subject: [PATCH 0905/1939] [ARM] 3036/1: AAEC-2000 - Add defines for GPIO registers Patch from Bellido Nicolas Add defines for GPIO registers on the AAEC-2000 processor. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/aaec2000.h | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/asm-arm/arch-aaec2000/aaec2000.h b/include/asm-arm/arch-aaec2000/aaec2000.h index 0e9b7e18af05..7472f9e5523f 100644 --- a/include/asm-arm/arch-aaec2000/aaec2000.h +++ b/include/asm-arm/arch-aaec2000/aaec2000.h @@ -17,6 +17,13 @@ #error You must include hardware.h not this file #endif /* __ASM_ARCH_HARDWARE_H */ +/* Chip selects */ +#define AAEC_CS0 0x00000000 +#define AAEC_CS1 0x10000000 +#define AAEC_CS2 0x20000000 +#define AAEC_CS3 0x30000000 + + /* Interrupt controller */ #define IRQ_BASE __REG(0x80000500) #define IRQ_INTSR __REG(0x80000500) /* Int Status Register */ @@ -148,4 +155,47 @@ #define POWER_STFCLR __REG(0x8000041c) /* NbFlg, RSTFlg, PFFlg, CLDFlg Clear */ #define POWER_CLKSET __REG(0x80000420) /* Clock Speed Control */ +/* GPIO Registers */ +#define AAEC_GPIO_PHYS 0x80000e00 + +#define AAEC_GPIO_PADR __REG(AAEC_GPIO_PHYS + 0x00) +#define AAEC_GPIO_PBDR __REG(AAEC_GPIO_PHYS + 0x04) +#define AAEC_GPIO_PCDR __REG(AAEC_GPIO_PHYS + 0x08) +#define AAEC_GPIO_PDDR __REG(AAEC_GPIO_PHYS + 0x0c) +#define AAEC_GPIO_PADDR __REG(AAEC_GPIO_PHYS + 0x10) +#define AAEC_GPIO_PBDDR __REG(AAEC_GPIO_PHYS + 0x14) +#define AAEC_GPIO_PCDDR __REG(AAEC_GPIO_PHYS + 0x18) +#define AAEC_GPIO_PDDDR __REG(AAEC_GPIO_PHYS + 0x1c) +#define AAEC_GPIO_PEDR __REG(AAEC_GPIO_PHYS + 0x20) +#define AAEC_GPIO_PEDDR __REG(AAEC_GPIO_PHYS + 0x24) +#define AAEC_GPIO_KSCAN __REG(AAEC_GPIO_PHYS + 0x28) +#define AAEC_GPIO_PINMUX __REG(AAEC_GPIO_PHYS + 0x2c) +#define AAEC_GPIO_PFDR __REG(AAEC_GPIO_PHYS + 0x30) +#define AAEC_GPIO_PFDDR __REG(AAEC_GPIO_PHYS + 0x34) +#define AAEC_GPIO_PGDR __REG(AAEC_GPIO_PHYS + 0x38) +#define AAEC_GPIO_PGDDR __REG(AAEC_GPIO_PHYS + 0x3c) +#define AAEC_GPIO_PHDR __REG(AAEC_GPIO_PHYS + 0x40) +#define AAEC_GPIO_PHDDR __REG(AAEC_GPIO_PHYS + 0x44) +#define AAEC_GPIO_RAZ __REG(AAEC_GPIO_PHYS + 0x48) +#define AAEC_GPIO_INTTYPE1 __REG(AAEC_GPIO_PHYS + 0x4c) +#define AAEC_GPIO_INTTYPE2 __REG(AAEC_GPIO_PHYS + 0x50) +#define AAEC_GPIO_FEOI __REG(AAEC_GPIO_PHYS + 0x54) +#define AAEC_GPIO_INTEN __REG(AAEC_GPIO_PHYS + 0x58) +#define AAEC_GPIO_INTSTATUS __REG(AAEC_GPIO_PHYS + 0x5c) +#define AAEC_GPIO_RAWINTSTATUS __REG(AAEC_GPIO_PHYS + 0x60) +#define AAEC_GPIO_DB __REG(AAEC_GPIO_PHYS + 0x64) +#define AAEC_GPIO_PAPINDR __REG(AAEC_GPIO_PHYS + 0x68) +#define AAEC_GPIO_PBPINDR __REG(AAEC_GPIO_PHYS + 0x6c) +#define AAEC_GPIO_PCPINDR __REG(AAEC_GPIO_PHYS + 0x70) +#define AAEC_GPIO_PDPINDR __REG(AAEC_GPIO_PHYS + 0x74) +#define AAEC_GPIO_PEPINDR __REG(AAEC_GPIO_PHYS + 0x78) +#define AAEC_GPIO_PFPINDR __REG(AAEC_GPIO_PHYS + 0x7c) +#define AAEC_GPIO_PGPINDR __REG(AAEC_GPIO_PHYS + 0x80) +#define AAEC_GPIO_PHPINDR __REG(AAEC_GPIO_PHYS + 0x84) + +#define AAEC_GPIO_PINMUX_PE0CON (1 << 0) +#define AAEC_GPIO_PINMUX_PD0CON (1 << 1) +#define AAEC_GPIO_PINMUX_CODECON (1 << 2) +#define AAEC_GPIO_PINMUX_UART3CON (1 << 3) + #endif /* __ARM_ARCH_AAEC2000_H */ From 4028ef4cc1fea245906a2dbd4df1ac9f0353ef5f Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:40 +0100 Subject: [PATCH 0906/1939] [ARM] 3037/1: AAED-2000 - Add defines for GPIO registers on external port. Patch from Bellido Nicolas The AAED-2000 board has GPIO pins on an external port. This patch adds the defines, and do the necessary mapping. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/aaed2000.c | 7 +++++ include/asm-arm/arch-aaec2000/aaed2000.h | 40 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 include/asm-arm/arch-aaec2000/aaed2000.h diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c index c9d899886648..7b0a1c7d64a9 100644 --- a/arch/arm/mach-aaec2000/aaed2000.c +++ b/arch/arm/mach-aaec2000/aaed2000.c @@ -27,6 +27,8 @@ #include #include +#include + #include "core.h" static void __init aaed2000_init_irq(void) @@ -34,9 +36,14 @@ static void __init aaed2000_init_irq(void) aaec2000_init_irq(); } +static struct map_desc aaed2000_io_desc[] __initdata = { + { EXT_GPIO_VBASE, EXT_GPIO_PBASE, EXT_GPIO_LENGTH, MT_DEVICE }, /* Ext GPIO */ +}; + static void __init aaed2000_map_io(void) { aaec2000_map_io(); + iotable_init(aaed2000_io_desc, ARRAY_SIZE(aaed2000_io_desc)); } MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform") diff --git a/include/asm-arm/arch-aaec2000/aaed2000.h b/include/asm-arm/arch-aaec2000/aaed2000.h new file mode 100644 index 000000000000..bc76d2badb91 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/aaed2000.h @@ -0,0 +1,40 @@ +/* + * linux/include/asm-arm/arch-aaec2000/aaed2000.h + * + * AAED-2000 specific bits definition + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * 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 __ASM_ARCH_AAED2000_H +#define __ASM_ARCH_AAED2000_H + +/* External GPIOs. */ + +#define EXT_GPIO_PBASE AAEC_CS3 +#define EXT_GPIO_VBASE 0xf8100000 +#define EXT_GPIO_LENGTH 0x00001000 + +#define __ext_gpio_p2v(x) ((x) - EXT_GPIO_PBASE + EXT_GPIO_VBASE) +#define __ext_gpio_v2p(x) ((x) + EXT_GPIO_PBASE - EXT_GPIO_VBASE) + +#define __EXT_GPIO_REG(x) (*((volatile u32 *)__ext_gpio_p2v(x))) +#define __EXT_GPIO_PREG(x) (__ext_gpio_v2p((u32)&(x))) + +#define AAED_EXT_GPIO __EXT_GPIO_REG(EXT_GPIO_PBASE) + +#define AAED_EGPIO_KBD_SCAN 0x00003fff /* Keyboard scan data */ +#define AAED_EGPIO_PWR_INT 0x00008fff /* Smart battery charger interrupt */ +#define AAED_EGPIO_SWITCHED 0x000f0000 /* DIP Switches */ +#define AAED_EGPIO_USB_VBUS 0x00400000 /* USB Vbus sense */ +#define AAED_EGPIO_LCD_PWR_EN 0x02000000 /* LCD and backlight PWR enable */ +#define AAED_EGPIO_nLED0 0x20000000 /* LED 0 */ +#define AAED_EGPIO_nLED1 0x20000000 /* LED 1 */ +#define AAED_EGPIO_nLED2 0x20000000 /* LED 2 */ + + +#endif /* __ARM_ARCH_AAED2000_H */ From f0904e29369a940080487fece700e59295196d79 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:41 +0100 Subject: [PATCH 0907/1939] [ARM] 3038/1: AAEC-2000 - Proper includes in hardware.h Patch from Bellido Nicolas linux/config.h is not necessary in hardware.h, while asm/sizes.h and asm/arch//aaec2000.h will be used later. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/hardware.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/asm-arm/arch-aaec2000/hardware.h b/include/asm-arm/arch-aaec2000/hardware.h index 4c37219e030e..153506fd06ed 100644 --- a/include/asm-arm/arch-aaec2000/hardware.h +++ b/include/asm-arm/arch-aaec2000/hardware.h @@ -11,7 +11,8 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#include +#include +#include /* The kernel is loaded at physical address 0xf8000000. * We map the IO space a bit after From 4a91ca2eb6eff14bb23f709e6ebf189fdbcdaa22 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:42 +0100 Subject: [PATCH 0908/1939] [ARM] 3039/1: AAEC-2000 - Add MTD support Patch from Bellido Nicolas This adds platform code for MTD devices on AAEC-2000. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/core.c | 31 ++++++++++++++++++++++++ include/asm-arm/arch-aaec2000/aaec2000.h | 3 +++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 9be6c3213254..86c5149b1721 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ #include #include +#include #include #include #include @@ -163,3 +165,32 @@ struct sys_timer aaec2000_timer = { .offset = aaec2000_gettimeoffset, }; +static struct flash_platform_data aaec2000_flash_data = { + .map_name = "cfi_probe", + .width = 4, +}; + +static struct resource aaec2000_flash_resource = { + .start = AAEC_FLASH_BASE, + .end = AAEC_FLASH_BASE + AAEC_FLASH_SIZE, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device aaec2000_flash_device = { + .name = "armflash", + .id = 0, + .dev = { + .platform_data = &aaec2000_flash_data, + }, + .num_resources = 1, + .resource = &aaec2000_flash_resource, +}; + +static int __init aaec2000_init(void) +{ + platform_device_register(&aaec2000_flash_device); + + return 0; +}; +arch_initcall(aaec2000_init); + diff --git a/include/asm-arm/arch-aaec2000/aaec2000.h b/include/asm-arm/arch-aaec2000/aaec2000.h index 7472f9e5523f..dfb09389ebc1 100644 --- a/include/asm-arm/arch-aaec2000/aaec2000.h +++ b/include/asm-arm/arch-aaec2000/aaec2000.h @@ -23,6 +23,9 @@ #define AAEC_CS2 0x20000000 #define AAEC_CS3 0x30000000 +/* Flash */ +#define AAEC_FLASH_BASE AAEC_CS0 +#define AAEC_FLASH_SIZE SZ_64M /* Interrupt controller */ #define IRQ_BASE __REG(0x80000500) From 4224b67c9a1d6cbf47b073970bd2db5a89557f92 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:43 +0100 Subject: [PATCH 0909/1939] [ARM] 3040/1: AAEC-2000 - Preliminary clock interface support Patch from Bellido Nicolas Here is a preliminary clock interface support for the AAEC-2000. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/Makefile | 2 +- arch/arm/mach-aaec2000/clock.c | 110 ++++++++++++++++++++++++++++++++ arch/arm/mach-aaec2000/clock.h | 23 +++++++ 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-aaec2000/clock.c create mode 100644 arch/arm/mach-aaec2000/clock.h diff --git a/arch/arm/mach-aaec2000/Makefile b/arch/arm/mach-aaec2000/Makefile index 20ec83896c37..a8e462f58bc9 100644 --- a/arch/arm/mach-aaec2000/Makefile +++ b/arch/arm/mach-aaec2000/Makefile @@ -3,7 +3,7 @@ # # Common support (must be linked before board specific support) -obj-y += core.o +obj-y += core.o clock.o # Specific board support obj-$(CONFIG_MACH_AAED2000) += aaed2000.o diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c new file mode 100644 index 000000000000..99e019169dda --- /dev/null +++ b/arch/arm/mach-aaec2000/clock.c @@ -0,0 +1,110 @@ +/* + * linux/arch/arm/mach-aaec2000/clock.c + * + * Copyright (C) 2005 Nicolas Bellido Y Ortega + * + * Based on linux/arch/arm/mach-integrator/clock.c + * + * 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 +#include +#include + +#include +#include + +#include "clock.h" + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +int clk_use(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_use); + +void clk_unuse(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_unuse); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_register(struct clk *clk) +{ + down(&clocks_sem); + list_add(&clk->node, &clocks); + up(&clocks_sem); + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + down(&clocks_sem); + list_del(&clk->node); + up(&clocks_sem); +} +EXPORT_SYMBOL(clk_unregister); + +static int __init clk_init(void) +{ + return 0; +} +arch_initcall(clk_init); diff --git a/arch/arm/mach-aaec2000/clock.h b/arch/arm/mach-aaec2000/clock.h new file mode 100644 index 000000000000..d4bb74ff613f --- /dev/null +++ b/arch/arm/mach-aaec2000/clock.h @@ -0,0 +1,23 @@ +/* + * linux/arch/arm/mach-aaec2000/clock.h + * + * Copyright (C) 2005 Nicolas Bellido Y Ortega + * + * Based on linux/arch/arm/mach-integrator/clock.h + * + * 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. + */ +struct module; + +struct clk { + struct list_head node; + unsigned long rate; + struct module *owner; + const char *name; + void *data; +}; + +int clk_register(struct clk *clk); +void clk_unregister(struct clk *clk); From 049eb3298a832a63c55bc8d8ea4cc881ab99f84b Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:44 +0100 Subject: [PATCH 0910/1939] [ARM] 3041/1: AAEC-2000 - CLCD controller platform glue Patch from Bellido Nicolas The AAEC-2000 has an ARM PrimeCell PL110 Color LCD Controller. This patch contains the platform glue that will be used by specific boards. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + arch/arm/mach-aaec2000/core.c | 90 ++++++++++++++++++++++++ arch/arm/mach-aaec2000/core.h | 11 +++ include/asm-arm/arch-aaec2000/aaec2000.h | 3 + 4 files changed, 105 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d885cc48bae1..682367bd0f65 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -204,6 +204,7 @@ config ARCH_H720X config ARCH_AAEC2000 bool "Agilent AAEC-2000 based" + select ARM_AMBA help This enables support for systems based on the Agilent AAEC-2000 diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 86c5149b1721..0c53dab80905 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -16,18 +16,24 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include "core.h" +#include "clock.h" + /* * Common I/O mapping: * @@ -165,6 +171,81 @@ struct sys_timer aaec2000_timer = { .offset = aaec2000_gettimeoffset, }; +static struct clcd_panel mach_clcd_panel; + +static int aaec2000_clcd_setup(struct clcd_fb *fb) +{ + dma_addr_t dma; + + fb->panel = &mach_clcd_panel; + + fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, SZ_1M, + &dma, GFP_KERNEL); + + if (!fb->fb.screen_base) { + printk(KERN_ERR "CLCD: unable to map framebuffer\n"); + return -ENOMEM; + } + + fb->fb.fix.smem_start = dma; + fb->fb.fix.smem_len = SZ_1M; + + return 0; +} + +static int aaec2000_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + return dma_mmap_writecombine(&fb->dev->dev, vma, + fb->fb.screen_base, + fb->fb.fix.smem_start, + fb->fb.fix.smem_len); +} + +static void aaec2000_clcd_remove(struct clcd_fb *fb) +{ + dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +} + +static struct clcd_board clcd_plat_data = { + .name = "AAEC-2000", + .check = clcdfb_check, + .decode = clcdfb_decode, + .setup = aaec2000_clcd_setup, + .mmap = aaec2000_clcd_mmap, + .remove = aaec2000_clcd_remove, +}; + +static struct amba_device clcd_device = { + .dev = { + .bus_id = "mb:16", + .coherent_dma_mask = ~0, + .platform_data = &clcd_plat_data, + }, + .res = { + .start = AAEC_CLCD_PHYS, + .end = AAEC_CLCD_PHYS + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { INT_LCD, NO_IRQ }, + .periphid = 0x41110, +}; + +static struct amba_device *amba_devs[] __initdata = { + &clcd_device, +}; + +static struct clk aaec2000_clcd_clk = { + .name = "CLCDCLK", +}; + +void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *clcd) +{ + clcd_plat_data.enable = clcd->enable; + clcd_plat_data.disable = clcd->disable; + memcpy(&mach_clcd_panel, &clcd->panel, sizeof(struct clcd_panel)); +} + static struct flash_platform_data aaec2000_flash_data = { .map_name = "cfi_probe", .width = 4, @@ -188,6 +269,15 @@ static struct platform_device aaec2000_flash_device = { static int __init aaec2000_init(void) { + int i; + + clk_register(&aaec2000_clcd_clk); + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + platform_device_register(&aaec2000_flash_device); return 0; diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h index 91893d848c16..daefc0ea14a1 100644 --- a/arch/arm/mach-aaec2000/core.h +++ b/arch/arm/mach-aaec2000/core.h @@ -9,8 +9,19 @@ * */ +#include + struct sys_timer; extern struct sys_timer aaec2000_timer; extern void __init aaec2000_map_io(void); extern void __init aaec2000_init_irq(void); + +struct aaec2000_clcd_info { + struct clcd_panel panel; + void (*disable)(struct clcd_fb *); + void (*enable)(struct clcd_fb *); +}; + +extern void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *); + diff --git a/include/asm-arm/arch-aaec2000/aaec2000.h b/include/asm-arm/arch-aaec2000/aaec2000.h index dfb09389ebc1..002227924b9f 100644 --- a/include/asm-arm/arch-aaec2000/aaec2000.h +++ b/include/asm-arm/arch-aaec2000/aaec2000.h @@ -201,4 +201,7 @@ #define AAEC_GPIO_PINMUX_CODECON (1 << 2) #define AAEC_GPIO_PINMUX_UART3CON (1 << 3) +/* LCD Controller */ +#define AAEC_CLCD_PHYS 0x80003000 + #endif /* __ARM_ARCH_AAEC2000_H */ From 50f4c001bc1534db77663592496204ceba151e97 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Fri, 28 Oct 2005 16:51:44 +0100 Subject: [PATCH 0911/1939] [ARM] 3042/1: AAED-2000 - LCD panel informations Patch from Bellido Nicolas The AAED-2000 is equiped with an 640x480 LCD. This adds the parameters that will be passed to the AAEC-2000 platform code. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/aaed2000.c | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c index 7b0a1c7d64a9..f5ef69702296 100644 --- a/arch/arm/mach-aaec2000/aaed2000.c +++ b/arch/arm/mach-aaec2000/aaed2000.c @@ -31,11 +31,53 @@ #include "core.h" +static void aaed2000_clcd_disable(struct clcd_fb *fb) +{ + AAED_EXT_GPIO &= ~AAED_EGPIO_LCD_PWR_EN; +} + +static void aaed2000_clcd_enable(struct clcd_fb *fb) +{ + AAED_EXT_GPIO |= AAED_EGPIO_LCD_PWR_EN; +} + +struct aaec2000_clcd_info clcd_info = { + .enable = aaed2000_clcd_enable, + .disable = aaed2000_clcd_disable, + .panel = { + .mode = { + .name = "Sharp", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 20, + .right_margin = 44, + .upper_margin = 21, + .lower_margin = 34, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_IVS | TIM2_IHS, + .cntl = CNTL_LCDTFT, + .bpp = 16, + }, +}; + static void __init aaed2000_init_irq(void) { aaec2000_init_irq(); } +static void __init aaed2000_init(void) +{ + aaec2000_set_clcd_plat_data(&clcd_info); +} + static struct map_desc aaed2000_io_desc[] __initdata = { { EXT_GPIO_VBASE, EXT_GPIO_PBASE, EXT_GPIO_LENGTH, MT_DEVICE }, /* Ext GPIO */ }; @@ -54,4 +96,5 @@ MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform") .map_io = aaed2000_map_io, .init_irq = aaed2000_init_irq, .timer = &aaec2000_timer, + .init_machine = aaed2000_init, MACHINE_END From 475172fb18853c31c24a8519b06a3bd5712b2cfe Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Thu, 29 Sep 2005 12:47:40 -0400 Subject: [PATCH 0912/1939] [PATCH] aoe: use get_unaligned for accesses in ATA id buffer Signed-off-by: "Ed L. Cashin" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Use get_unaligned for possibly-unaligned multi-byte accesses to the ATA device identify response buffer. --- drivers/block/aoe/aoecmd.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index b5be4b7d7b5b..5c9c7c1a3d4c 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "aoe.h" #define TIMERTICK (HZ / 10) @@ -311,16 +312,16 @@ ataid_complete(struct aoedev *d, unsigned char *id) u16 n; /* word 83: command set supported */ - n = le16_to_cpup((__le16 *) &id[83<<1]); + n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1])); /* word 86: command set/feature enabled */ - n |= le16_to_cpup((__le16 *) &id[86<<1]); + n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1])); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = le64_to_cpup((__le64 *) &id[100<<1]); + ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1])); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -331,12 +332,12 @@ ataid_complete(struct aoedev *d, unsigned char *id) d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = le32_to_cpup((__le32 *) &id[60<<1]); + ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1])); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = le16_to_cpup((__le16 *) &id[54<<1]); - d->geo.heads = le16_to_cpup((__le16 *) &id[55<<1]); - d->geo.sectors = le16_to_cpup((__le16 *) &id[56<<1]); + d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1])); + d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); + d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); } d->ssize = ssize; d->geo.start = 0; From 3dc7c555636e46bb64b4da3570a345f4b247eaf0 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Thu, 29 Sep 2005 12:47:55 -0400 Subject: [PATCH 0913/1939] [PATCH] aoe: update to version 14 Signed-off-by: "Ed L. Cashin" Signed-off-by: Greg Kroah-Hartman Update driver version number to 14. --- drivers/block/aoe/aoe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 0e9e586e9ba3..881c48d941b7 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "12" +#define VERSION "14" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" From d5dee80ad69439ad8dccf8fa4d7fed0068aec9cf Mon Sep 17 00:00:00 2001 From: Will Dyson Date: Fri, 16 Sep 2005 02:55:07 -0700 Subject: [PATCH 0914/1939] [PATCH] add sysfs support for ide tape I was recently given an old Travan tape drive and asked to do something useful with it. The ide-scsi + st (+serverworks ide controller) combo results in a hard lockup of the machine which I have not had the energy to debug, so I turned to ide-tape (which seems to work). The system in question debian stable, using udev to manage /dev. The following patch to ide-tape.c allows udev to create the cdev nodes for my drive. Cc: Gadi Oxman Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/ide/ide-tape.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index ee38e6b143a4..95abe981530d 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1013,6 +1013,8 @@ typedef struct ide_tape_obj { static DECLARE_MUTEX(idetape_ref_sem); +static struct class *idetape_sysfs_class; + #define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref) #define ide_tape_g(disk) \ @@ -4704,6 +4706,10 @@ static void ide_tape_release(struct kref *kref) drive->dsc_overlap = 0; drive->driver_data = NULL; + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor)); + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor + 128)); devfs_remove("%s/mt", drive->devfs_name); devfs_remove("%s/mtn", drive->devfs_name); devfs_unregister_tape(g->number); @@ -4878,6 +4884,11 @@ static int ide_tape_probe(struct device *dev) idetape_setup(drive, tape, minor); + class_device_create(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name); + class_device_create(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name); + devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor), S_IFCHR | S_IRUGO | S_IWUGO, "%s/mt", drive->devfs_name); @@ -4903,6 +4914,7 @@ MODULE_LICENSE("GPL"); static void __exit idetape_exit (void) { driver_unregister(&idetape_driver.gen_driver); + class_destroy(idetape_sysfs_class); unregister_chrdev(IDETAPE_MAJOR, "ht"); } @@ -4911,11 +4923,33 @@ static void __exit idetape_exit (void) */ static int idetape_init (void) { + int error = 1; + idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape"); + if (IS_ERR(idetape_sysfs_class)) { + idetape_sysfs_class = NULL; + printk(KERN_ERR "Unable to create sysfs class for ide tapes\n"); + error = -EBUSY; + goto out; + } + if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); - return -EBUSY; + error = -EBUSY; + goto out_free_class; } - return driver_register(&idetape_driver.gen_driver); + + error = driver_register(&idetape_driver.gen_driver); + if (error) + goto out_free_driver; + + return 0; + +out_free_driver: + driver_unregister(&idetape_driver.gen_driver); +out_free_class: + class_destroy(idetape_sysfs_class); +out: + return error; } module_init(idetape_init); From 4ed17dccd69c4fc13b9d2118001f5e58ea16ebea Mon Sep 17 00:00:00 2001 From: Erik Hovland Date: Thu, 6 Oct 2005 10:45:30 -0700 Subject: [PATCH 0915/1939] [PATCH] kobject_uevent.c has a typo in a comment This patch changes trough to through in a comment in kobject_uevent.c. Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 04ca4429ddfa..a318330d254a 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -54,7 +54,7 @@ static char *action_to_string(enum kobject_action action) static struct sock *uevent_sock; /** - * send_uevent - notify userspace by sending event trough netlink socket + * send_uevent - notify userspace by sending event through netlink socket * * @signal: signal name * @obj: object path (kobject) From 2a7ff1feda9f5cd6463744239ec5e661ee7d5f01 Mon Sep 17 00:00:00 2001 From: Erik Hovland Date: Thu, 6 Oct 2005 10:47:49 -0700 Subject: [PATCH 0916/1939] [PATCH] changes device to driver in porting.txt The document porting.txt in Documentation/driver-model says: When a device is successfully bound to a device I think it should say: When a device is successfully bound to a driver Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/porting.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-model/porting.txt b/Documentation/driver-model/porting.txt index ff2fef2107f0..98b233cb8b36 100644 --- a/Documentation/driver-model/porting.txt +++ b/Documentation/driver-model/porting.txt @@ -350,7 +350,7 @@ When a driver is registered, the bus's list of devices is iterated over. bus->match() is called for each device that is not already claimed by a driver. -When a device is successfully bound to a device, device->driver is +When a device is successfully bound to a driver, device->driver is set, the device is added to a per-driver list of devices, and a symlink is created in the driver's sysfs directory that points to the device's physical directory: From 0ac85241ebc7bf6b86ab498960cc121d53ef69ae Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 12 Sep 2005 19:39:34 -0700 Subject: [PATCH 0917/1939] [PATCH] driver model wakeup flags This is a refresh of an earlier patch to add "wakeup" support to the PM core model. This provides per-device bus-neutral control of the use of wakeup events. * "struct device_pm_info" has two bits that are initialized as part of setting up the enclosing struct device: - "can_wakeup", reflecting hardware capabilities - "may_wakeup", the policy setting (when CONFIG_PM) * There's a writeable sysfs "wakeup" file, with one of two values: - "enabled", when the policy is to allow wakeup - "disabled", when the policy is not to allow it - "" if the device can't currently issue wakeups By default, wakeup is enabled on all devices that support it. If its driver doesn't support it ... treat it as a bug. :) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 1 + drivers/base/power/sysfs.c | 73 ++++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 26 +++++++++++++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 6ab73f5c799a..31109193e2c4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -225,6 +225,7 @@ void device_initialize(struct device *dev) klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); + device_init_wakeup(dev, 0); } /** diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 8d04fb435c17..89c57875f3e5 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -48,8 +48,81 @@ static ssize_t state_store(struct device * dev, struct device_attribute *attr, c static DEVICE_ATTR(state, 0644, state_show, state_store); +/* + * wakeup - Report/change current wakeup option for device + * + * Some devices support "wakeup" events, which are hardware signals + * used to activate devices from suspended or low power states. Such + * devices have one of three values for the sysfs power/wakeup file: + * + * + "enabled\n" to issue the events; + * + "disabled\n" not to do so; or + * + "\n" for temporary or permanent inability to issue wakeup. + * + * (For example, unconfigured USB devices can't issue wakeups.) + * + * Familiar examples of devices that can issue wakeup events include + * keyboards and mice (both PS2 and USB styles), power buttons, modems, + * "Wake-On-LAN" Ethernet links, GPIO lines, and more. Some events + * will wake the entire system from a suspend state; others may just + * wake up the device (if the system as a whole is already active). + * Some wakeup events use normal IRQ lines; other use special out + * of band signaling. + * + * It is the responsibility of device drivers to enable (or disable) + * wakeup signaling as part of changing device power states, respecting + * the policy choices provided through the driver model. + * + * Devices may not be able to generate wakeup events from all power + * states. Also, the events may be ignored in some configurations; + * for example, they might need help from other devices that aren't + * active, or which may have wakeup disabled. Some drivers rely on + * wakeup events internally (unless they are disabled), keeping + * their hardware in low power modes whenever they're unused. This + * saves runtime power, without requiring system-wide sleep states. + */ + +static const char enabled[] = "enabled"; +static const char disabled[] = "disabled"; + +static ssize_t +wake_show(struct device * dev, struct device_attribute *attr, char * buf) +{ + return sprintf(buf, "%s\n", device_can_wakeup(dev) + ? (device_may_wakeup(dev) ? enabled : disabled) + : ""); +} + +static ssize_t +wake_store(struct device * dev, struct device_attribute *attr, + const char * buf, size_t n) +{ + char *cp; + int len = n; + + if (!device_can_wakeup(dev)) + return -EINVAL; + + cp = memchr(buf, '\n', n); + if (cp) + len = cp - buf; + if (len == sizeof enabled - 1 + && strncmp(buf, enabled, sizeof enabled - 1) == 0) + device_set_wakeup_enable(dev, 1); + else if (len == sizeof disabled - 1 + && strncmp(buf, disabled, sizeof disabled - 1) == 0) + device_set_wakeup_enable(dev, 0); + else + return -EINVAL; + return n; +} + +static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); + + static struct attribute * power_attrs[] = { &dev_attr_state.attr, + &dev_attr_wakeup.attr, NULL, }; static struct attribute_group pm_attr_group = { diff --git a/include/linux/pm.h b/include/linux/pm.h index 5cfb07648eca..7897cf500c51 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -219,7 +219,9 @@ typedef struct pm_message { struct dev_pm_info { pm_message_t power_state; + unsigned can_wakeup:1; #ifdef CONFIG_PM + unsigned should_wakeup:1; pm_message_t prev_state; void * saved_state; atomic_t pm_users; @@ -236,13 +238,35 @@ extern void device_resume(void); #ifdef CONFIG_PM extern int device_suspend(pm_message_t state); -#else + +#define device_set_wakeup_enable(dev,val) \ + ((dev)->power.should_wakeup = !!(val)) +#define device_may_wakeup(dev) \ + (device_can_wakeup(dev) && (dev)->power.should_wakeup) + +#else /* !CONFIG_PM */ + static inline int device_suspend(pm_message_t state) { return 0; } + +#define device_set_wakeup_enable(dev,val) do{}while(0) +#define device_may_wakeup(dev) (0) + #endif +/* changes to device_may_wakeup take effect on the next pm state change. + * by default, devices should wakeup if they can. + */ +#define device_can_wakeup(dev) \ + ((dev)->power.can_wakeup) +#define device_init_wakeup(dev,val) \ + do { \ + device_can_wakeup(dev) = !!(val); \ + device_set_wakeup_enable(dev,val); \ + } while(0) + #endif /* __KERNEL__ */ #endif /* _LINUX_PM_H */ From b94dc6b58667a73eeaf5cfd9c9e90dcd98743c5b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 12 Sep 2005 19:39:39 -0700 Subject: [PATCH 0918/1939] [PATCH] usb device wakeup flags This patch teaches "usb_device" about the new driver model wakeup support: - It updates device wakeup capabilities when entering a configuration with the WAKEUP attribute; - During suspend processing it consults the policy bit to see whether it should enable wakeup for that device. (This resolves a FIXME to not assume the answer is always "yes"; some devices lie about supporting remote wakeup.) Support for root hubs and the HCDs is separate (and more complex). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a12cab5314e9..c3e2024c4347 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1020,9 +1020,15 @@ void usb_set_device_state(struct usb_device *udev, spin_lock_irqsave(&device_state_lock, flags); if (udev->state == USB_STATE_NOTATTACHED) ; /* do nothing */ - else if (new_state != USB_STATE_NOTATTACHED) + else if (new_state != USB_STATE_NOTATTACHED) { udev->state = new_state; - else + if (new_state == USB_STATE_CONFIGURED) + device_init_wakeup(&udev->dev, + (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP)); + else if (new_state != USB_STATE_SUSPENDED) + device_init_wakeup(&udev->dev, 0); + } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } @@ -1546,11 +1552,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * NOTE: OTG devices may issue remote wakeup (or SRP) even when * we don't explicitly enable it here. */ - if (udev->actconfig - // && FIXME (remote wakeup enabled on this bus) - // ... currently assuming it's always appropriate - && (udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP) != 0) { + if (device_may_wakeup(&udev->dev)) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP, 0, From dbe9035d4f690c44b55d3d0f1bc193e2c3fc57fa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:37 -0500 Subject: [PATCH 0919/1939] [PATCH] Driver core: send hotplug event before adding class interfaces Move call to kobject_hotplug() above code that adds interfaces to a class device, otherwise children's hotplug events may reach userspace first. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index ce23dc8c18c5..8df58c57dd25 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -524,6 +524,8 @@ int class_device_add(struct class_device *class_dev) class_name); } + kobject_hotplug(&class_dev->kobj, KOBJ_ADD); + /* notify any interfaces this device is now here */ if (parent) { down(&parent->sem); @@ -533,7 +535,6 @@ int class_device_add(struct class_device *class_dev) class_intf->add(class_dev); up(&parent->sem); } - kobject_hotplug(&class_dev->kobj, KOBJ_ADD); register_done: if (error && parent) From 4f5ca09e0b854a29b17401f59487664ae3b21aa4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:32 -0500 Subject: [PATCH 0920/1939] [PATCH] I2O: remove class interface I2O: remove i2o_device_class_interface misuse The intent of class interfaces was to provide different 'views' at the same object, not just run some code every time a new class device is registered. Kill interface structure, make class core register default attributes and set up sysfs links right when registering class devices. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/message/i2o/device.c | 255 +++++++++++++++++------------------ 1 file changed, 122 insertions(+), 133 deletions(-) diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 21f16ba3ac38..551d582e2887 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -45,10 +45,10 @@ static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, writel(type, &msg->body[0]); return i2o_msg_post_wait(dev->iop, m, 60); -}; +} /** - * i2o_device_claim - claim a device for use by an OSM + * i2o_device_claim - claim a device for use by an OSM * @dev: I2O device to claim * @drv: I2O driver which wants to claim the device * @@ -73,7 +73,7 @@ int i2o_device_claim(struct i2o_device *dev) up(&dev->lock); return rc; -}; +} /** * i2o_device_claim_release - release a device that the OSM is using @@ -119,7 +119,8 @@ int i2o_device_claim_release(struct i2o_device *dev) up(&dev->lock); return rc; -}; +} + /** * i2o_device_release - release the memory for a I2O device @@ -135,39 +136,62 @@ static void i2o_device_release(struct device *dev) pr_debug("i2o: device %s released\n", dev->bus_id); kfree(i2o_dev); -}; +} /** - * i2o_device_class_release - Remove I2O device attributes + * i2o_device_class_release - I2O class device release function * @cd: I2O class device which is added to the I2O device class * - * Removes attributes from the I2O device again. Also search each device - * on the controller for I2O devices which refert to this device as parent - * or user and remove this links also. + * The function is just a stub - memory will be freed when + * associated I2O device is released. */ static void i2o_device_class_release(struct class_device *cd) { - struct i2o_device *i2o_dev, *tmp; - struct i2o_controller *c; + /* empty */ +} - i2o_dev = to_i2o_device(cd->dev); - c = i2o_dev->iop; +/** + * i2o_device_class_show_class_id - Displays class id of I2O device + * @cd: class device of which the class id should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_class_id(struct class_device *cd, + char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); - sysfs_remove_link(&i2o_dev->device.kobj, "parent"); - sysfs_remove_link(&i2o_dev->device.kobj, "user"); + sprintf(buf, "0x%03x\n", dev->lct_data.class_id); + return strlen(buf) + 1; +} - list_for_each_entry(tmp, &c->devices, list) { - if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) - sysfs_remove_link(&tmp->device.kobj, "parent"); - if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) - sysfs_remove_link(&tmp->device.kobj, "user"); - } +/** + * i2o_device_class_show_tid - Displays TID of I2O device + * @cd: class device of which the TID should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) +{ + struct i2o_device *dev = to_i2o_device(cd->dev); + + sprintf(buf, "0x%03x\n", dev->lct_data.tid); + return strlen(buf) + 1; +} + +static struct class_device_attribute i2o_device_class_attrs[] = { + __ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, NULL), + __ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL), + __ATTR_NULL }; /* I2O device class */ static struct class i2o_device_class = { - .name = "i2o_device", - .release = i2o_device_class_release + .name = "i2o_device", + .release = i2o_device_class_release, + .class_dev_attrs = i2o_device_class_attrs, }; /** @@ -197,7 +221,67 @@ static struct i2o_device *i2o_device_alloc(void) dev->classdev.dev = &dev->device; return dev; -}; +} + +/** + * i2o_setup_sysfs_links - Adds attributes to the I2O device + * @cd: I2O class device which is added to the I2O device class + * + * This function get called when a I2O device is added to the class. It + * creates the attributes for each device and creates user/parent symlink + * if necessary. + * + * Returns 0 on success or negative error code on failure. + */ +static void i2o_setup_sysfs_links(struct i2o_device *i2o_dev) +{ + struct i2o_controller *c = i2o_dev->iop; + struct i2o_device *tmp; + + /* create user entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); + if (tmp && tmp != i2o_dev) + sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "user"); + + /* create user entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid && + tmp != i2o_dev) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "user"); + + /* create parent entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); + if (tmp && tmp != i2o_dev) + sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "parent"); + + /* create parent entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid && + tmp != i2o_dev) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "parent"); +} + +static void i2o_remove_sysfs_links(struct i2o_device *i2o_dev) +{ + struct i2o_controller *c = i2o_dev->iop; + struct i2o_device *tmp; + + sysfs_remove_link(&i2o_dev->device.kobj, "parent"); + sysfs_remove_link(&i2o_dev->device.kobj, "user"); + + list_for_each_entry(tmp, &c->devices, list) { + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "parent"); + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "user"); + } +} + + /** * i2o_device_add - allocate a new I2O device and add it to the IOP @@ -222,6 +306,7 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, } dev->lct_data = *entry; + dev->iop = c; snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, dev->lct_data.tid); @@ -229,7 +314,6 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, dev->lct_data.tid); - dev->iop = c; dev->device.parent = &c->device; device_register(&dev->device); @@ -238,12 +322,14 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, class_device_register(&dev->classdev); + i2o_setup_sysfs_links(dev); + i2o_driver_notify_device_add_all(dev); pr_debug("i2o: device %s added\n", dev->device.bus_id); return dev; -}; +} /** * i2o_device_remove - remove an I2O device from the I2O core @@ -256,10 +342,11 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, void i2o_device_remove(struct i2o_device *i2o_dev) { i2o_driver_notify_device_remove_all(i2o_dev); + i2o_remove_sysfs_links(i2o_dev); class_device_unregister(&i2o_dev->classdev); list_del(&i2o_dev->list); device_unregister(&i2o_dev->device); -}; +} /** * i2o_device_parse_lct - Parse a previously fetched LCT and create devices @@ -337,99 +424,8 @@ int i2o_device_parse_lct(struct i2o_controller *c) up(&c->lct_lock); return 0; -}; +} -/** - * i2o_device_class_show_class_id - Displays class id of I2O device - * @cd: class device of which the class id should be displayed - * @buf: buffer into which the class id should be printed - * - * Returns the number of bytes which are printed into the buffer. - */ -static ssize_t i2o_device_class_show_class_id(struct class_device *cd, - char *buf) -{ - struct i2o_device *dev = to_i2o_device(cd->dev); - - sprintf(buf, "0x%03x\n", dev->lct_data.class_id); - return strlen(buf) + 1; -}; - -/** - * i2o_device_class_show_tid - Displays TID of I2O device - * @cd: class device of which the TID should be displayed - * @buf: buffer into which the class id should be printed - * - * Returns the number of bytes which are printed into the buffer. - */ -static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) -{ - struct i2o_device *dev = to_i2o_device(cd->dev); - - sprintf(buf, "0x%03x\n", dev->lct_data.tid); - return strlen(buf) + 1; -}; - -/* I2O device class attributes */ -static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, - NULL); -static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL); - -/** - * i2o_device_class_add - Adds attributes to the I2O device - * @cd: I2O class device which is added to the I2O device class - * - * This function get called when a I2O device is added to the class. It - * creates the attributes for each device and creates user/parent symlink - * if necessary. - * - * Returns 0 on success or negative error code on failure. - */ -static int i2o_device_class_add(struct class_device *cd) -{ - struct i2o_device *i2o_dev, *tmp; - struct i2o_controller *c; - - i2o_dev = to_i2o_device(cd->dev); - c = i2o_dev->iop; - - class_device_create_file(cd, &class_device_attr_class_id); - class_device_create_file(cd, &class_device_attr_tid); - - /* create user entries for this device */ - tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "user"); - - /* create user entries refering to this device */ - list_for_each_entry(tmp, &c->devices, list) - if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "user"); - - /* create parent entries for this device */ - tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "parent"); - - /* create parent entries refering to this device */ - list_for_each_entry(tmp, &c->devices, list) - if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "parent"); - - return 0; -}; - -/* I2O device class interface */ -static struct class_interface i2o_device_class_interface = { - .class = &i2o_device_class, - .add = i2o_device_class_add -}; /* * Run time support routines @@ -553,11 +549,11 @@ int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field, } /* - * if oper == I2O_PARAMS_TABLE_GET, get from all rows - * if fieldcount == -1 return all fields + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields * ibuf and ibuflen are unused (use NULL, 0) - * else return specific fields - * ibuf contains fieldindexes + * else return specific fields + * ibuf contains fieldindexes * * if oper == I2O_PARAMS_LIST_GET, get from specific rows * if fieldcount == -1 return all fields @@ -611,14 +607,8 @@ int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, */ int i2o_device_init(void) { - int rc; - - rc = class_register(&i2o_device_class); - if (rc) - return rc; - - return class_interface_register(&i2o_device_class_interface); -}; + return class_register(&i2o_device_class); +} /** * i2o_device_exit - I2O devices exit function @@ -627,9 +617,8 @@ int i2o_device_init(void) */ void i2o_device_exit(void) { - class_interface_register(&i2o_device_class_interface); class_unregister(&i2o_device_class); -}; +} EXPORT_SYMBOL(i2o_device_claim); EXPORT_SYMBOL(i2o_device_claim_release); From 607cf4d9aa1d766890f42fc892d39d48cf6d6c16 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0921/1939] [PATCH] I2O: Clean up some pretty bad driver model abuses in the i2o code Signed-off-by: Greg Kroah-Hartman --- drivers/message/i2o/iop.c | 22 ++++++++++------------ include/linux/i2o.h | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 42f8b810d6e5..15deb45ce995 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -833,6 +833,7 @@ void i2o_iop_remove(struct i2o_controller *c) list_for_each_entry_safe(dev, tmp, &c->devices, list) i2o_device_remove(dev); + class_device_unregister(c->classdev); device_del(&c->device); /* Ask the IOP to switch to RESET state */ @@ -1077,9 +1078,7 @@ static void i2o_iop_release(struct device *dev) }; /* I2O controller class */ -static struct class i2o_controller_class = { - .name = "i2o_controller", -}; +static struct class *i2o_controller_class; /** * i2o_iop_alloc - Allocate and initialize a i2o_controller struct @@ -1110,14 +1109,10 @@ struct i2o_controller *i2o_iop_alloc(void) sprintf(c->name, "iop%d", c->unit); device_initialize(&c->device); - class_device_initialize(&c->classdev); c->device.release = &i2o_iop_release; - c->classdev.class = &i2o_controller_class; - c->classdev.dev = &c->device; snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit); - snprintf(c->classdev.class_id, BUS_ID_SIZE, "iop%d", c->unit); #if BITS_PER_LONG == 64 spin_lock_init(&c->context_list_lock); @@ -1146,7 +1141,9 @@ int i2o_iop_add(struct i2o_controller *c) goto iop_reset; } - if ((rc = class_device_add(&c->classdev))) { + c->classdev = class_device_create(i2o_controller_class, 0, + &c->device, "iop%d", c->unit); + if (IS_ERR(c->classdev)) { osm_err("%s: could not add controller class\n", c->name); goto device_del; } @@ -1184,7 +1181,7 @@ int i2o_iop_add(struct i2o_controller *c) return 0; class_del: - class_device_del(&c->classdev); + class_device_unregister(c->classdev); device_del: device_del(&c->device); @@ -1250,7 +1247,8 @@ static int __init i2o_iop_init(void) if (rc) goto exit; - if ((rc = class_register(&i2o_controller_class))) { + i2o_controller_class = class_create(THIS_MODULE, "i2o_controller"); + if (IS_ERR(i2o_controller_class)) { osm_err("can't register class i2o_controller\n"); goto device_exit; } @@ -1273,7 +1271,7 @@ static int __init i2o_iop_init(void) i2o_driver_exit(); class_exit: - class_unregister(&i2o_controller_class); + class_destroy(i2o_controller_class); device_exit: i2o_device_exit(); @@ -1292,7 +1290,7 @@ static void __exit i2o_iop_exit(void) i2o_pci_exit(); i2o_exec_exit(); i2o_driver_exit(); - class_unregister(&i2o_controller_class); + class_destroy(i2o_controller_class); i2o_device_exit(); }; diff --git a/include/linux/i2o.h b/include/linux/i2o.h index bdc286ec947c..694ea298d4bc 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -194,7 +194,7 @@ struct i2o_controller { struct resource mem_resource; /* Mem resource allocated to the IOP */ struct device device; - struct class_device classdev; /* I2O controller class */ + struct class_device *classdev; /* I2O controller class device */ struct i2o_device *exec; /* Executive */ #if BITS_PER_LONG == 64 spinlock_t context_list_lock; /* lock for context_list */ From 7bd7b091429705eb281d60c553cc643aada8045a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 29 Sep 2005 00:40:07 -0500 Subject: [PATCH 0922/1939] [PATCH] I2O: remove i2o_device_class I2O: cleanup - remove i2o_device_class I2O devices reside on their own bus so there should be no reason to also have i2c_device class that mirros i2o bus. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/message/i2o/core.h | 3 -- drivers/message/i2o/device.c | 71 +++++++----------------------------- drivers/message/i2o/driver.c | 3 ++ drivers/message/i2o/iop.c | 10 +---- include/linux/i2o.h | 2 - 5 files changed, 17 insertions(+), 72 deletions(-) diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index c5bcfd70f711..9eefedb16211 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h @@ -36,9 +36,6 @@ extern void __exit i2o_pci_exit(void); extern void i2o_device_remove(struct i2o_device *); extern int i2o_device_parse_lct(struct i2o_controller *); -extern int i2o_device_init(void); -extern void i2o_device_exit(void); - /* IOP */ extern struct i2o_controller *i2o_iop_alloc(void); extern void i2o_iop_free(struct i2o_controller *); diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 551d582e2887..d9879965eb50 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -138,17 +138,6 @@ static void i2o_device_release(struct device *dev) kfree(i2o_dev); } -/** - * i2o_device_class_release - I2O class device release function - * @cd: I2O class device which is added to the I2O device class - * - * The function is just a stub - memory will be freed when - * associated I2O device is released. - */ -static void i2o_device_class_release(struct class_device *cd) -{ - /* empty */ -} /** * i2o_device_class_show_class_id - Displays class id of I2O device @@ -157,12 +146,13 @@ static void i2o_device_class_release(struct class_device *cd) * * Returns the number of bytes which are printed into the buffer. */ -static ssize_t i2o_device_class_show_class_id(struct class_device *cd, - char *buf) +static ssize_t i2o_device_show_class_id(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct i2o_device *dev = to_i2o_device(cd->dev); + struct i2o_device *i2o_dev = to_i2o_device(dev); - sprintf(buf, "0x%03x\n", dev->lct_data.class_id); + sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id); return strlen(buf) + 1; } @@ -173,27 +163,22 @@ static ssize_t i2o_device_class_show_class_id(struct class_device *cd, * * Returns the number of bytes which are printed into the buffer. */ -static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) +static ssize_t i2o_device_show_tid(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct i2o_device *dev = to_i2o_device(cd->dev); + struct i2o_device *i2o_dev = to_i2o_device(dev); - sprintf(buf, "0x%03x\n", dev->lct_data.tid); + sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid); return strlen(buf) + 1; } -static struct class_device_attribute i2o_device_class_attrs[] = { - __ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, NULL), - __ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL), +struct device_attribute i2o_device_attrs[] = { + __ATTR(class_id, S_IRUGO, i2o_device_show_class_id, NULL), + __ATTR(tid, S_IRUGO, i2o_device_show_tid, NULL), __ATTR_NULL }; -/* I2O device class */ -static struct class i2o_device_class = { - .name = "i2o_device", - .release = i2o_device_class_release, - .class_dev_attrs = i2o_device_class_attrs, -}; - /** * i2o_device_alloc - Allocate a I2O device and initialize it * @@ -217,8 +202,6 @@ static struct i2o_device *i2o_device_alloc(void) dev->device.bus = &i2o_bus_type; dev->device.release = &i2o_device_release; - dev->classdev.class = &i2o_device_class; - dev->classdev.dev = &dev->device; return dev; } @@ -311,17 +294,12 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, dev->lct_data.tid); - snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, - dev->lct_data.tid); - dev->device.parent = &c->device; device_register(&dev->device); list_add_tail(&dev->list, &c->devices); - class_device_register(&dev->classdev); - i2o_setup_sysfs_links(dev); i2o_driver_notify_device_add_all(dev); @@ -343,7 +321,6 @@ void i2o_device_remove(struct i2o_device *i2o_dev) { i2o_driver_notify_device_remove_all(i2o_dev); i2o_remove_sysfs_links(i2o_dev); - class_device_unregister(&i2o_dev->classdev); list_del(&i2o_dev->list); device_unregister(&i2o_dev->device); } @@ -598,28 +575,6 @@ int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, return size; } -/** - * i2o_device_init - Initialize I2O devices - * - * Registers the I2O device class. - * - * Returns 0 on success or negative error code on failure. - */ -int i2o_device_init(void) -{ - return class_register(&i2o_device_class); -} - -/** - * i2o_device_exit - I2O devices exit function - * - * Unregisters the I2O device class. - */ -void i2o_device_exit(void) -{ - class_unregister(&i2o_device_class); -} - EXPORT_SYMBOL(i2o_device_claim); EXPORT_SYMBOL(i2o_device_claim_release); EXPORT_SYMBOL(i2o_parm_field_get); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 739bfdef0c6d..0079a4be0af2 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -58,9 +58,12 @@ static int i2o_bus_match(struct device *dev, struct device_driver *drv) }; /* I2O bus type */ +extern struct device_attribute i2o_device_attrs[]; + struct bus_type i2o_bus_type = { .name = "i2o", .match = i2o_bus_match, + .dev_attrs = i2o_device_attrs, }; /** diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 15deb45ce995..176fb573ea26 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -1243,14 +1243,10 @@ static int __init i2o_iop_init(void) printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); - rc = i2o_device_init(); - if (rc) - goto exit; - i2o_controller_class = class_create(THIS_MODULE, "i2o_controller"); if (IS_ERR(i2o_controller_class)) { osm_err("can't register class i2o_controller\n"); - goto device_exit; + goto exit; } if ((rc = i2o_driver_init())) @@ -1273,9 +1269,6 @@ static int __init i2o_iop_init(void) class_exit: class_destroy(i2o_controller_class); - device_exit: - i2o_device_exit(); - exit: return rc; } @@ -1291,7 +1284,6 @@ static void __exit i2o_iop_exit(void) i2o_exec_exit(); i2o_driver_exit(); class_destroy(i2o_controller_class); - i2o_device_exit(); }; module_init(i2o_iop_init); diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 694ea298d4bc..84db8f6ae7e5 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -66,8 +66,6 @@ struct i2o_device { struct device device; struct semaphore lock; /* device lock */ - - struct class_device classdev; /* i2o device class */ }; /* From d8539d81aeee4dbdc0624a798321e822fb2df7ae Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:36 -0500 Subject: [PATCH 0923/1939] [PATCH] Driver core: pass interface to class interface methods Driver core: pass interface to class intreface methods Pass interface as argument to add() and remove() class interface methods. This way a subsystem can implement generic add/remove handlers and then call interface-specific ones. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 8 ++++---- drivers/pcmcia/ds.c | 6 ++++-- drivers/pcmcia/rsrc_nonstatic.c | 6 ++++-- drivers/pcmcia/socket_sysfs.c | 6 ++++-- drivers/scsi/sg.c | 8 ++++---- include/linux/device.h | 4 ++-- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index 8df58c57dd25..73d44cf53db0 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -532,7 +532,7 @@ int class_device_add(struct class_device *class_dev) list_add_tail(&class_dev->node, &parent->children); list_for_each_entry(class_intf, &parent->interfaces, node) if (class_intf->add) - class_intf->add(class_dev); + class_intf->add(class_dev, class_intf); up(&parent->sem); } @@ -612,7 +612,7 @@ void class_device_del(struct class_device *class_dev) list_del_init(&class_dev->node); list_for_each_entry(class_intf, &parent->interfaces, node) if (class_intf->remove) - class_intf->remove(class_dev); + class_intf->remove(class_dev, class_intf); up(&parent->sem); } @@ -729,7 +729,7 @@ int class_interface_register(struct class_interface *class_intf) list_add_tail(&class_intf->node, &parent->interfaces); if (class_intf->add) { list_for_each_entry(class_dev, &parent->children, node) - class_intf->add(class_dev); + class_intf->add(class_dev, class_intf); } up(&parent->sem); @@ -748,7 +748,7 @@ void class_interface_unregister(struct class_interface *class_intf) list_del_init(&class_intf->node); if (class_intf->remove) { list_for_each_entry(class_dev, &parent->children, node) - class_intf->remove(class_dev); + class_intf->remove(class_dev, class_intf); } up(&parent->sem); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 080608c7381a..39d096b52926 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1157,7 +1157,8 @@ static struct pcmcia_callback pcmcia_bus_callback = { .requery = pcmcia_bus_rescan, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) +static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); int ret; @@ -1192,7 +1193,8 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev) +static void pcmcia_bus_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index f9a5c70284b5..fc87e7e2b6b8 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -994,7 +994,8 @@ static struct class_device_attribute *pccard_rsrc_attributes[] = { NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; @@ -1011,7 +1012,8 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 1040a6c1a8a4..4a3150a7854c 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -341,7 +341,8 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; int ret = 0; @@ -357,7 +358,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ad94367df430..f0d8b4eda5ad 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -104,8 +104,8 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF; #define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */ -static int sg_add(struct class_device *); -static void sg_remove(struct class_device *); +static int sg_add(struct class_device *, struct class_interface *); +static void sg_remove(struct class_device *, struct class_interface *); static Scsi_Request *dummy_cmdp; /* only used for sizeof */ @@ -1506,7 +1506,7 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) } static int -sg_add(struct class_device *cl_dev) +sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); struct gendisk *disk; @@ -1582,7 +1582,7 @@ sg_add(struct class_device *cl_dev) } static void -sg_remove(struct class_device *cl_dev) +sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); Sg_device *sdp = NULL; diff --git a/include/linux/device.h b/include/linux/device.h index 95d607a48f06..a53a822c4d16 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -251,8 +251,8 @@ struct class_interface { struct list_head node; struct class *class; - int (*add) (struct class_device *); - void (*remove) (struct class_device *); + int (*add) (struct class_device *, struct class_interface *); + void (*remove) (struct class_device *, struct class_interface *); }; extern int class_interface_register(struct class_interface *); From a7fd67062efc5b0fc9a61368c607fa92d1d57f9e Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 1 Oct 2005 14:49:43 +0200 Subject: [PATCH 0924/1939] [PATCH] add sysfs attr to re-emit device hotplug event A "coldplug + udevstart" can be simple like this: for i in /sys/block/*/*/uevent; do echo 1 > $i; done for i in /sys/class/*/*/uevent; do echo 1 > $i; done for i in /sys/bus/*/devices/*/uevent; do echo 1 > $i; done Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 16 ++++++++++-- drivers/base/core.c | 16 ++++++++++++ drivers/block/genhd.c | 25 ++++++++++++++++++ fs/partitions/check.c | 27 +++++++++++++++++++- include/linux/device.h | 57 +++++++++++++++++++++--------------------- include/linux/genhd.h | 1 + 6 files changed, 110 insertions(+), 32 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index 73d44cf53db0..3cf6eb36f3d8 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -442,6 +442,13 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) return print_dev_t(buf, class_dev->devt); } +static ssize_t store_uevent(struct class_device *class_dev, + const char *buf, size_t count) +{ + kobject_hotplug(&class_dev->kobj, KOBJ_ADD); + return count; +} + void class_device_initialize(struct class_device *class_dev) { kobj_set_kset_s(class_dev, class_obj_subsys); @@ -497,6 +504,12 @@ int class_device_add(struct class_device *class_dev) goto register_done; /* add the needed attributes to this device */ + class_dev->uevent_attr.attr.name = "uevent"; + class_dev->uevent_attr.attr.mode = S_IWUSR; + class_dev->uevent_attr.attr.owner = parent->owner; + class_dev->uevent_attr.store = store_uevent; + class_device_create_file(class_dev, &class_dev->uevent_attr); + if (MAJOR(class_dev->devt)) { struct class_device_attribute *attr; attr = kzalloc(sizeof(*attr), GFP_KERNEL); @@ -505,12 +518,10 @@ int class_device_add(struct class_device *class_dev) kobject_del(&class_dev->kobj); goto register_done; } - attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; attr->attr.owner = parent->owner; attr->show = show_dev; - attr->store = NULL; class_device_create_file(class_dev, attr); class_dev->devt_attr = attr; } @@ -621,6 +632,7 @@ void class_device_del(struct class_device *class_dev) sysfs_remove_link(&class_dev->kobj, "device"); sysfs_remove_link(&class_dev->dev->kobj, class_name); } + class_device_remove_file(class_dev, &class_dev->uevent_attr); if (class_dev->devt_attr) class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_attrs(class_dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index 31109193e2c4..ac4b5fdd95f5 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -154,6 +154,13 @@ static struct kset_hotplug_ops device_hotplug_ops = { .hotplug = dev_hotplug, }; +static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + kobject_hotplug(&dev->kobj, KOBJ_ADD); + return count; +} + /** * device_subsys - structure to be registered with kobject core. */ @@ -259,6 +266,14 @@ int device_add(struct device *dev) if ((error = kobject_add(&dev->kobj))) goto Error; + + dev->uevent_attr.attr.name = "uevent"; + dev->uevent_attr.attr.mode = S_IWUSR; + if (dev->driver) + dev->uevent_attr.attr.owner = dev->driver->owner; + dev->uevent_attr.store = store_uevent; + device_create_file(dev, &dev->uevent_attr); + kobject_hotplug(&dev->kobj, KOBJ_ADD); if ((error = device_pm_add(dev))) goto PMError; @@ -350,6 +365,7 @@ void device_del(struct device * dev) if (parent) klist_del(&dev->knode_parent); + device_remove_file(dev, &dev->uevent_attr); /* Notify the platform of the removal, in case they * need to do anything... diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index d42840cc0d1d..486ce1fdeb8c 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -337,10 +337,30 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, return ret; } +static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr, + const char *page, size_t count) +{ + struct gendisk *disk = to_disk(kobj); + struct disk_attribute *disk_attr = + container_of(attr,struct disk_attribute,attr); + ssize_t ret = 0; + + if (disk_attr->store) + ret = disk_attr->store(disk, page, count); + return ret; +} + static struct sysfs_ops disk_sysfs_ops = { .show = &disk_attr_show, + .store = &disk_attr_store, }; +static ssize_t disk_uevent_store(struct gendisk * disk, + const char *buf, size_t count) +{ + kobject_hotplug(&disk->kobj, KOBJ_ADD); + return count; +} static ssize_t disk_dev_read(struct gendisk * disk, char *page) { dev_t base = MKDEV(disk->major, disk->first_minor); @@ -382,6 +402,10 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); } +static struct disk_attribute disk_attr_uevent = { + .attr = {.name = "uevent", .mode = S_IWUSR }, + .store = disk_uevent_store +}; static struct disk_attribute disk_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, .show = disk_dev_read @@ -404,6 +428,7 @@ static struct disk_attribute disk_attr_stat = { }; static struct attribute * default_attrs[] = { + &disk_attr_uevent.attr, &disk_attr_dev.attr, &disk_attr_range.attr, &disk_attr_removable.attr, diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 77e178f13162..d95a110293fa 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -192,6 +192,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev) struct part_attribute { struct attribute attr; ssize_t (*show)(struct hd_struct *,char *); + ssize_t (*store)(struct hd_struct *,const char *, size_t); }; static ssize_t @@ -201,14 +202,33 @@ part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); ssize_t ret = 0; if (part_attr->show) - ret = part_attr->show(p,page); + ret = part_attr->show(p, page); + return ret; +} +static ssize_t +part_attr_store(struct kobject * kobj, struct attribute * attr, + const char *page, size_t count) +{ + struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); + struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); + ssize_t ret = 0; + + if (part_attr->store) + ret = part_attr->store(p, page, count); return ret; } static struct sysfs_ops part_sysfs_ops = { .show = part_attr_show, + .store = part_attr_store, }; +static ssize_t part_uevent_store(struct hd_struct * p, + const char *page, size_t count) +{ + kobject_hotplug(&p->kobj, KOBJ_ADD); + return count; +} static ssize_t part_dev_read(struct hd_struct * p, char *page) { struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); @@ -229,6 +249,10 @@ static ssize_t part_stat_read(struct hd_struct * p, char *page) p->reads, (unsigned long long)p->read_sectors, p->writes, (unsigned long long)p->write_sectors); } +static struct part_attribute part_attr_uevent = { + .attr = {.name = "uevent", .mode = S_IWUSR }, + .store = part_uevent_store +}; static struct part_attribute part_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, .show = part_dev_read @@ -247,6 +271,7 @@ static struct part_attribute part_attr_stat = { }; static struct attribute * default_attrs[] = { + &part_attr_uevent.attr, &part_attr_dev.attr, &part_attr_start.attr, &part_attr_size.attr, diff --git a/include/linux/device.h b/include/linux/device.h index a53a822c4d16..e86a580b72e1 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -190,6 +190,18 @@ struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int class_create_file(struct class *, const struct class_attribute *); extern void class_remove_file(struct class *, const struct class_attribute *); +struct class_device_attribute { + struct attribute attr; + ssize_t (*show)(struct class_device *, char * buf); + ssize_t (*store)(struct class_device *, const char * buf, size_t count); +}; + +#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ +struct class_device_attribute class_device_attr_##_name = \ + __ATTR(_name,_mode,_show,_store) + +extern int class_device_create_file(struct class_device *, + const struct class_device_attribute *); struct class_device { struct list_head node; @@ -198,6 +210,7 @@ struct class_device { struct class * class; /* required */ dev_t devt; /* dev_t, creates the sysfs "dev" */ struct class_device_attribute *devt_attr; + struct class_device_attribute uevent_attr; struct device * dev; /* not necessary, but nice to have */ void * class_data; /* class-specific data */ @@ -228,18 +241,6 @@ extern int class_device_rename(struct class_device *, char *); extern struct class_device * class_device_get(struct class_device *); extern void class_device_put(struct class_device *); -struct class_device_attribute { - struct attribute attr; - ssize_t (*show)(struct class_device *, char * buf); - ssize_t (*store)(struct class_device *, const char * buf, size_t count); -}; - -#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ -struct class_device_attribute class_device_attr_##_name = \ - __ATTR(_name,_mode,_show,_store) - -extern int class_device_create_file(struct class_device *, - const struct class_device_attribute *); extern void class_device_remove_file(struct class_device *, const struct class_device_attribute *); extern int class_device_create_bin_file(struct class_device *, @@ -266,6 +267,20 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt, extern void class_device_destroy(struct class *cls, dev_t devt); +/* interface for exporting device attributes */ +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +}; + +#define DEVICE_ATTR(_name,_mode,_show,_store) \ +struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) + +extern int device_create_file(struct device *device, struct device_attribute * entry); +extern void device_remove_file(struct device * dev, struct device_attribute * attr); struct device { struct klist klist_children; struct klist_node knode_parent; /* node in sibling list */ @@ -275,6 +290,7 @@ struct device { struct kobject kobj; char bus_id[BUS_ID_SIZE]; /* position on parent bus */ + struct device_attribute uevent_attr; struct semaphore sem; /* semaphore to synchronize calls to * its driver. @@ -343,23 +359,6 @@ extern int device_attach(struct device * dev); extern void driver_attach(struct device_driver * drv); -/* driverfs interface for exporting device attributes */ - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf); - ssize_t (*store)(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -}; - -#define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) - - -extern int device_create_file(struct device *device, struct device_attribute * entry); -extern void device_remove_file(struct device * dev, struct device_attribute * attr); - /* * Platform "fixup" functions - allow the platform to have their say * about devices and actions that the general device layer doesn't diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 01796c41c951..78af34840c69 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -132,6 +132,7 @@ struct gendisk { struct disk_attribute { struct attribute attr; ssize_t (*show)(struct gendisk *, char *); + ssize_t (*store)(struct gendisk *, const char *, size_t); }; /* From 51d172d5f3a193e4b8f76179b2e55d7a36b94117 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0925/1939] [PATCH] Driver Core: add the ability for class_device structures to be nested This patch allows struct class_device to be nested, so that another struct class_device can be the parent of a new one, instead of only having the struct class be the parent. This will allow us to (hopefully) fix up the input and video class subsystem mess. But please people, don't go crazy and start making huge trees of class devices, you should only need 2 levels deep to get everything to work (remember to use a class_interface to get notification of a new class device being added to the system.) Oh, this also allows us to have the possibility of potentially, someday, moving /sys/block into /sys/class. The main hindrance is that pesky /dev numberspace issue... Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 125 ++++++++++++++++++++++++++--------------- include/linux/device.h | 13 ++++- 2 files changed, 91 insertions(+), 47 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index 3cf6eb36f3d8..c3e569730afe 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -99,7 +99,8 @@ struct class * class_get(struct class * cls) void class_put(struct class * cls) { - subsys_put(&cls->subsys); + if (cls) + subsys_put(&cls->subsys); } @@ -165,14 +166,25 @@ void class_unregister(struct class * cls) static void class_create_release(struct class *cls) { + pr_debug("%s called for %s\n", __FUNCTION__, cls->name); kfree(cls); } static void class_device_create_release(struct class_device *class_dev) { + pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); kfree(class_dev); } +/* needed to allow these devices to have parent class devices */ +static int class_device_create_hotplug(struct class_device *class_dev, + char **envp, int num_envp, + char *buffer, int buffer_size) +{ + pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); + return 0; +} + /** * class_create - create a struct class structure * @owner: pointer to the module that is to "own" this struct class @@ -301,10 +313,12 @@ static void class_dev_release(struct kobject * kobj) kfree(cd->devt_attr); cd->devt_attr = NULL; - if (cls->release) + if (cd->release) + cd->release(cd); + else if (cls->release) cls->release(cd); else { - printk(KERN_ERR "Device class '%s' does not have a release() function, " + printk(KERN_ERR "Class Device '%s' does not have a release() function, " "it is broken and must be fixed.\n", cd->class_id); WARN_ON(1); @@ -382,14 +396,18 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp, buffer = &buffer[length]; buffer_size -= length; - if (class_dev->class->hotplug) { - /* have the bus specific function add its stuff */ - retval = class_dev->class->hotplug (class_dev, envp, num_envp, - buffer, buffer_size); - if (retval) { - pr_debug ("%s - hotplug() returned %d\n", - __FUNCTION__, retval); - } + if (class_dev->hotplug) { + /* have the class device specific function add its stuff */ + retval = class_dev->hotplug(class_dev, envp, num_envp, + buffer, buffer_size); + if (retval) + pr_debug("class_dev->hotplug() returned %d\n", retval); + } else if (class_dev->class->hotplug) { + /* have the class specific function add its stuff */ + retval = class_dev->class->hotplug(class_dev, envp, num_envp, + buffer, buffer_size); + if (retval) + pr_debug("class->hotplug() returned %d\n", retval); } return retval; @@ -476,37 +494,42 @@ static char *make_class_name(struct class_device *class_dev) int class_device_add(struct class_device *class_dev) { - struct class * parent = NULL; - struct class_interface * class_intf; + struct class *parent_class = NULL; + struct class_device *parent_class_dev = NULL; + struct class_interface *class_intf; char *class_name = NULL; - int error; + int error = -EINVAL; class_dev = class_device_get(class_dev); if (!class_dev) return -EINVAL; - if (!strlen(class_dev->class_id)) { - error = -EINVAL; + if (!strlen(class_dev->class_id)) goto register_done; - } - parent = class_get(class_dev->class); + parent_class = class_get(class_dev->class); + if (!parent_class) + goto register_done; + parent_class_dev = class_device_get(class_dev->parent); pr_debug("CLASS: registering class device: ID = '%s'\n", class_dev->class_id); /* first, register with generic layer. */ kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); - if (parent) - class_dev->kobj.parent = &parent->subsys.kset.kobj; + if (parent_class_dev) + class_dev->kobj.parent = &parent_class_dev->kobj; + else + class_dev->kobj.parent = &parent_class->subsys.kset.kobj; - if ((error = kobject_add(&class_dev->kobj))) + error = kobject_add(&class_dev->kobj); + if (error) goto register_done; /* add the needed attributes to this device */ class_dev->uevent_attr.attr.name = "uevent"; class_dev->uevent_attr.attr.mode = S_IWUSR; - class_dev->uevent_attr.attr.owner = parent->owner; + class_dev->uevent_attr.attr.owner = parent_class->owner; class_dev->uevent_attr.store = store_uevent; class_device_create_file(class_dev, &class_dev->uevent_attr); @@ -520,7 +543,7 @@ int class_device_add(struct class_device *class_dev) } attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; - attr->attr.owner = parent->owner; + attr->attr.owner = parent_class->owner; attr->show = show_dev; class_device_create_file(class_dev, attr); class_dev->devt_attr = attr; @@ -538,18 +561,20 @@ int class_device_add(struct class_device *class_dev) kobject_hotplug(&class_dev->kobj, KOBJ_ADD); /* notify any interfaces this device is now here */ - if (parent) { - down(&parent->sem); - list_add_tail(&class_dev->node, &parent->children); - list_for_each_entry(class_intf, &parent->interfaces, node) + if (parent_class) { + down(&parent_class->sem); + list_add_tail(&class_dev->node, &parent_class->children); + list_for_each_entry(class_intf, &parent_class->interfaces, node) if (class_intf->add) class_intf->add(class_dev, class_intf); - up(&parent->sem); + up(&parent_class->sem); } register_done: - if (error && parent) - class_put(parent); + if (error) { + class_put(parent_class); + class_device_put(parent_class_dev); + } class_device_put(class_dev); kfree(class_name); return error; @@ -564,21 +589,28 @@ int class_device_register(struct class_device *class_dev) /** * class_device_create - creates a class 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 class_device of this new device, if any. * @dev: the dev_t for the char device to be added. * @device: a pointer to a struct device that is assiociated with this class device. * @fmt: string for the class device's name * * This function can be used by char device classes. A struct * class_device will be created in sysfs, registered to the specified - * class. A "dev" file will be created, showing the dev_t for the - * device. The pointer to the struct class_device will be returned from - * the call. Any further sysfs files that might be required can be - * created using this pointer. + * 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 class_device is passed in, the newly + * created struct class_device will be a child of that device in sysfs. + * The pointer to the struct class_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 class_device *class_device_create(struct class *cls, dev_t devt, +struct class_device *class_device_create(struct class *cls, + struct class_device *parent, + dev_t devt, struct device *device, char *fmt, ...) { va_list args; @@ -597,6 +629,9 @@ struct class_device *class_device_create(struct class *cls, dev_t devt, class_dev->devt = devt; class_dev->dev = device; class_dev->class = cls; + class_dev->parent = parent; + class_dev->release = class_device_create_release; + class_dev->hotplug = class_device_create_hotplug; va_start(args, fmt); vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); @@ -614,17 +649,18 @@ struct class_device *class_device_create(struct class *cls, dev_t devt, void class_device_del(struct class_device *class_dev) { - struct class * parent = class_dev->class; - struct class_interface * class_intf; + struct class *parent_class = class_dev->class; + struct class_device *parent_device = class_dev->parent; + struct class_interface *class_intf; char *class_name = NULL; - if (parent) { - down(&parent->sem); + if (parent_class) { + down(&parent_class->sem); list_del_init(&class_dev->node); - list_for_each_entry(class_intf, &parent->interfaces, node) + list_for_each_entry(class_intf, &parent_class->interfaces, node) if (class_intf->remove) class_intf->remove(class_dev, class_intf); - up(&parent->sem); + up(&parent_class->sem); } if (class_dev->dev) { @@ -640,8 +676,8 @@ void class_device_del(struct class_device *class_dev) kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); kobject_del(&class_dev->kobj); - if (parent) - class_put(parent); + class_device_put(parent_device); + class_put(parent_class); kfree(class_name); } @@ -721,7 +757,8 @@ struct class_device * class_device_get(struct class_device *class_dev) void class_device_put(struct class_device *class_dev) { - kobject_put(&class_dev->kobj); + if (class_dev) + kobject_put(&class_dev->kobj); } diff --git a/include/linux/device.h b/include/linux/device.h index e86a580b72e1..226e550ae2ea 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -213,7 +213,11 @@ struct class_device { struct class_device_attribute uevent_attr; struct device * dev; /* not necessary, but nice to have */ void * class_data; /* class-specific data */ + struct class_device *parent; /* parent of this child device, if there is one */ + void (*release)(struct class_device *dev); + int (*hotplug)(struct class_device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); char class_id[BUS_ID_SIZE]; /* unique to this class */ }; @@ -261,9 +265,12 @@ extern void class_interface_unregister(struct class_interface *); extern struct class *class_create(struct module *owner, char *name); extern void class_destroy(struct class *cls); -extern struct class_device *class_device_create(struct class *cls, dev_t devt, - struct device *device, char *fmt, ...) - __attribute__((format(printf,4,5))); +extern struct class_device *class_device_create(struct class *cls, + struct class_device *parent, + dev_t devt, + struct device *device, + char *fmt, ...) + __attribute__((format(printf,5,6))); extern void class_device_destroy(struct class *cls, dev_t devt); From 53f4654272df7c51064825024340554b39c9efba Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0926/1939] [PATCH] Driver Core: fix up all callers of class_device_create() The previous patch adding the ability to nest struct class_device changed the paramaters to the call class_device_create(). This patch fixes up all in-kernel users of the function. Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/cpuid.c | 2 +- arch/i386/kernel/msr.c | 2 +- drivers/block/aoe/aoechr.c | 2 +- drivers/block/paride/pg.c | 2 +- drivers/block/paride/pt.c | 4 ++-- drivers/char/dsp56k.c | 2 +- drivers/char/ftape/zftape/zftape-init.c | 12 ++++++------ drivers/char/ip2main.c | 10 ++++++---- drivers/char/ipmi/ipmi_devintf.c | 2 +- drivers/char/istallion.c | 3 ++- drivers/char/lp.c | 2 +- drivers/char/mem.c | 3 ++- drivers/char/misc.c | 2 +- drivers/char/ppdev.c | 2 +- drivers/char/raw.c | 4 ++-- drivers/char/snsc.c | 2 +- drivers/char/stallion.c | 4 +++- drivers/char/tipar.c | 2 +- drivers/char/tty_io.c | 10 +++++----- drivers/char/vc_screen.c | 10 ++++++---- drivers/char/viotape.c | 4 ++-- drivers/hwmon/hwmon.c | 2 +- drivers/ide/ide-tape.c | 4 ++-- drivers/ieee1394/dv1394.c | 2 +- drivers/ieee1394/raw1394.c | 2 +- drivers/ieee1394/video1394.c | 2 +- drivers/infiniband/core/ucm.c | 2 +- drivers/input/evdev.c | 2 +- drivers/input/joydev.c | 2 +- drivers/input/mousedev.c | 4 ++-- drivers/input/tsdev.c | 2 +- drivers/isdn/capi/capi.c | 2 +- drivers/macintosh/adb.c | 2 +- drivers/media/dvb/dvb-core/dvbdev.c | 2 +- drivers/message/i2o/iop.c | 2 +- drivers/mtd/mtdchar.c | 4 ++-- drivers/net/ppp_generic.c | 2 +- drivers/net/wan/cosa.c | 2 +- drivers/s390/char/tape_class.c | 1 + drivers/s390/char/vmlogrdr.c | 1 + drivers/scsi/ch.c | 2 +- drivers/scsi/osst.c | 2 +- drivers/scsi/sg.c | 2 +- drivers/scsi/st.c | 2 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/file.c | 4 +++- drivers/usb/core/hcd.c | 3 ++- drivers/video/fbmem.c | 2 +- fs/coda/psdev.c | 4 ++-- sound/core/sound.c | 2 +- sound/oss/soundcard.c | 4 ++-- sound/sound_core.c | 2 +- 52 files changed, 86 insertions(+), 73 deletions(-) diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 4647db4ad6de..13bae799e626 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -163,7 +163,7 @@ static int cpuid_class_device_create(int i) int err = 0; struct class_device *class_err; - class_err = class_device_create(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); + class_err = class_device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); if (IS_ERR(class_err)) err = PTR_ERR(class_err); return err; diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index 03100d6fc5d6..44470fea4309 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -246,7 +246,7 @@ static int msr_class_device_create(int i) int err = 0; struct class_device *class_err; - class_err = class_device_create(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); + class_err = class_device_create(msr_class, NULL, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); if (IS_ERR(class_err)) err = PTR_ERR(class_err); return err; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 45a243096187..41ae0ede619a 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -224,7 +224,7 @@ aoechr_init(void) return PTR_ERR(aoe_class); } for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_create(aoe_class, + class_device_create(aoe_class, NULL, MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, chardevs[i].name); diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index b3982395f22b..82f2d6d2eeef 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -674,7 +674,7 @@ static int __init pg_init(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) { - class_device_create(pg_class, MKDEV(major, unit), + class_device_create(pg_class, NULL, MKDEV(major, unit), NULL, "pg%u", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index d8d35233cf49..686c95573452 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -971,7 +971,7 @@ static int __init pt_init(void) devfs_mk_dir("pt"); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_create(pt_class, MKDEV(major, unit), + class_device_create(pt_class, NULL, MKDEV(major, unit), NULL, "pt%d", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, @@ -980,7 +980,7 @@ static int __init pt_init(void) class_device_destroy(pt_class, MKDEV(major, unit)); goto out_class; } - class_device_create(pt_class, MKDEV(major, unit + 128), + class_device_create(pt_class, NULL, MKDEV(major, unit + 128), NULL, "pt%dn", unit); err = devfs_mk_cdev(MKDEV(major, unit + 128), S_IFCHR | S_IRUSR | S_IWUSR, diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 26271e3ca823..8693835cb2d5 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -515,7 +515,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index 5745b74044ec..821357ce7e0e 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -331,27 +331,27 @@ KERN_INFO zft_class = class_create(THIS_MODULE, "zft"); for (i = 0; i < 4; i++) { - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "qft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), S_IFCHR | S_IRUSR | S_IWUSR, "nqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), S_IFCHR | S_IRUSR | S_IWUSR, "zqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), S_IFCHR | S_IRUSR | S_IWUSR, "nzqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), S_IFCHR | S_IRUSR | S_IWUSR, "rawqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), S_IFCHR | S_IRUSR | S_IWUSR, "nrawqft%i", i); diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 9e4e26aef94e..d815d197dc3e 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -721,8 +721,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, - 4 * i), NULL, "ipl%d", i); + class_device_create(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i), + NULL, "ipl%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/ipl%d", i); @@ -732,8 +733,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) goto out_class; } - class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, - 4 * i + 1), NULL, "stat%d", i); + class_device_create(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1), + NULL, "stat%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/stat%d", i); diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index a09ff1080687..7c0684deea06 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -798,7 +798,7 @@ static void ipmi_new_smi(int if_num) devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "ipmidev/%d", if_num); - class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num); + class_device_create(ipmi_class, NULL, dev, NULL, "ipmi%d", if_num); } static void ipmi_smi_gone(int if_num) diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 9c19e5435a11..e3ddbdb85a2f 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -5246,7 +5246,8 @@ int __init stli_init(void) devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "staliomem/%d", i); - class_device_create(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), + class_device_create(istallion_class, NULL, + MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 2afb9038dbc5..e57260525293 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -805,7 +805,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL, "lp%d", nr); devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, "printers/%d", nr); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f182752fe918..38be4b0dbd1c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -920,7 +920,8 @@ static int __init chr_dev_init(void) mem_class = class_create(THIS_MODULE, "mem"); for (i = 0; i < ARRAY_SIZE(devlist); i++) { - class_device_create(mem_class, MKDEV(MEM_MAJOR, devlist[i].minor), + class_device_create(mem_class, NULL, + MKDEV(MEM_MAJOR, devlist[i].minor), NULL, devlist[i].name); devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), S_IFCHR | devlist[i].mode, devlist[i].name); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 0c8375165e29..3e4c0414a01a 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -234,7 +234,7 @@ int misc_register(struct miscdevice * misc) } dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_device_create(misc_class, dev, misc->dev, + misc->class = class_device_create(misc_class, NULL, dev, misc->dev, "%s", misc->name); if (IS_ERR(misc->class)) { err = PTR_ERR(misc->class); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 0e22880432bc..306ee0f091a4 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -752,7 +752,7 @@ static struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - class_device_create(ppdev_class, MKDEV(PP_MAJOR, port->number), + class_device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), NULL, "parport%d", port->number); } diff --git a/drivers/char/raw.c b/drivers/char/raw.c index f13e5de02207..30e4cbe16bb0 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -128,7 +128,7 @@ raw_ioctl(struct inode *inode, struct file *filp, static void bind_device(struct raw_config_request *rq) { class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); - class_device_create(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), + class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, "raw%d", rq->raw_minor); } @@ -307,7 +307,7 @@ static int __init raw_init(void) unregister_chrdev_region(dev, MAX_RAW_MINORS); goto error; } - class_device_create(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 261a41bf6d02..1758a83327e5 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -437,7 +437,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, dev, NULL, + class_device_create(snsc_class, NULL, dev, NULL, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 951545a6ef2d..1c686414e0a1 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -3095,7 +3095,9 @@ static int __init stl_init(void) devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "staliomem/%d", i); - class_device_create(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); + class_device_create(stallion_class, NULL, + MKDEV(STL_SIOMEMMAJOR, i), NULL, + "staliomem%d", i); } stl_serial->owner = THIS_MODULE; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index ec78d2f161f7..41a94bc79f67 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -436,7 +436,7 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, MKDEV(TIPAR_MAJOR, + class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), NULL, "par%d", nr); /* Use devfs, tree: /dev/ticables/par/[0..2] */ err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e5953f3433f3..f5649a337743 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2728,7 +2728,7 @@ 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, dev, device, name); + class_device_create(tty_class, NULL, dev, device, "%s", name); } /** @@ -2983,14 +2983,14 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); @@ -2998,7 +2998,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -3007,7 +3007,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 79c2928a8817..f66c7ad6fd38 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -484,8 +484,10 @@ void vcs_make_devfs(struct tty_struct *tty) devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); - class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); - class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), + NULL, "vcs%u", tty->index + 1); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), + NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { @@ -503,7 +505,7 @@ int __init vcs_init(void) devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); - class_device_create(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - class_device_create(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 0aff45fac2e6..a5e104f428f8 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -956,9 +956,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, + class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, "iseries!vt%d", i); - class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), + class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "iseries/vt%d", i); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9b41c9bd805f..6f48579799b5 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -45,7 +45,7 @@ struct class_device *hwmon_device_register(struct device *dev) return ERR_PTR(-ENOMEM); id = id & MAX_ID_MASK; - cdev = class_device_create(hwmon_class, MKDEV(0,0), dev, + cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, HWMON_ID_FORMAT, id); if (IS_ERR(cdev)) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 95abe981530d..47f2b832555f 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -4884,9 +4884,9 @@ static int ide_tape_probe(struct device *dev) idetape_setup(drive, tape, minor); - class_device_create(idetape_sysfs_class, + class_device_create(idetape_sysfs_class, NULL, MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name); - class_device_create(idetape_sysfs_class, + class_device_create(idetape_sysfs_class, NULL, MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name); devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor), diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index e34730c7a874..cbbbe14b8849 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2361,7 +2361,7 @@ static void dv1394_add_host (struct hpsb_host *host) ohci = (struct ti_ohci *)host->hostdata; - class_device_create(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), NULL, "dv1394-%d", id); devfs_mk_dir("ieee1394/dv/host%d", id); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 0470f77a9cd1..24411e666b21 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2912,7 +2912,7 @@ static int __init init_raw1394(void) hpsb_register_highlevel(&raw1394_highlevel); - if (IS_ERR(class_device_create(hpsb_protocol_class, MKDEV( + if (IS_ERR(class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), NULL, RAW1394_DEVICE_NAME))) { ret = -EFAULT; diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 11be9c9c82a8..23911da50154 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -1370,7 +1370,7 @@ static void video1394_add_host (struct hpsb_host *host) hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; - class_device_create(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, minor), NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id); devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index d0f0b0a2edd3..021b8f1d36d3 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1300,7 +1300,7 @@ static int __init ib_ucm_init(void) goto err_class; } - class_device_create(ib_ucm_class, IB_UCM_DEV, NULL, "ucm"); + class_device_create(ib_ucm_class, NULL, IB_UCM_DEV, NULL, "ucm"); idr_init(&ctx_id_table); init_MUTEX(&ctx_id_mutex); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 3738d173f9a6..83b694cb8507 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -689,7 +689,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); - class_device_create(input_class, + class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), dev->dev, "event%d", minor); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index e0938d1d3ad7..c696fb2a6f99 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -516,7 +516,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); - class_device_create(input_class, + class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), dev->dev, "js%d", minor); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index c6194a9dd174..d7144e1a9ae3 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -651,7 +651,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); - class_device_create(input_class, + class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), dev->dev, "mouse%d", minor); @@ -740,7 +740,7 @@ static int __init mousedev_init(void) devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); - class_device_create(input_class, + class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 50c63a155156..fbb35c97551b 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -414,7 +414,7 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); - class_device_create(input_class, + class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 04fb606b5ddd..11ae0fddea04 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1505,7 +1505,7 @@ static int __init capi_init(void) return PTR_ERR(capi_class); } - class_device_create(capi_class, MKDEV(capi_major, 0), NULL, "capi"); + class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, "isdn/capi20"); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index c0dc1e3fa58b..d2ead1776c16 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -905,5 +905,5 @@ adbdev_init(void) adb_dev_class = class_create(THIS_MODULE, "adb"); if (IS_ERR(adb_dev_class)) return; - class_device_create(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); } diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 4b7adca3e286..477b4fa56430 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -235,7 +235,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, S_IFCHR | S_IRUSR | S_IWUSR, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - class_device_create(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), NULL, "dvb%d.%s%d", adap->num, dnames[type], id); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 176fb573ea26..361da8d1d5e7 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -1141,7 +1141,7 @@ int i2o_iop_add(struct i2o_controller *c) goto iop_reset; } - c->classdev = class_device_create(i2o_controller_class, 0, + c->classdev = class_device_create(i2o_controller_class, NULL, MKDEV(0,0), &c->device, "iop%d", c->unit); if (IS_ERR(c->classdev)) { osm_err("%s: could not add controller class\n", c->name); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 1ed602a0f24c..c534fd5d95cb 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -24,10 +24,10 @@ static void mtd_notify_add(struct mtd_info* mtd) if (!mtd) return; - class_device_create(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), + class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), NULL, "mtd%d", mtd->index); - class_device_create(mtd_class, + class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), NULL, "mtd%dro", mtd->index); } diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0df7e92b0bf8..d3c9958b00d0 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -863,7 +863,7 @@ static int __init ppp_init(void) err = PTR_ERR(ppp_class); goto out_chrdev; } - class_device_create(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); if (err) diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7ff814fd65d0..ace68e5bc6c9 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -400,7 +400,7 @@ static int __init cosa_init(void) goto out_chrdev; } for (i=0; iclass_device = class_device_create( tape_class, + NULL, tcd->char_device->dev, device, "%s", tcd->device_name diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 491f00c032e8..a107fec4457a 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -787,6 +787,7 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { return ret; } priv->class_device = class_device_create( + NULL, vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num), dev, diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index da6e51c7fe69..540147cb51ce 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -936,7 +936,7 @@ static int ch_probe(struct device *dev) if (init) ch_init_elem(ch); - class_device_create(ch_sysfs_class, + class_device_create(ch_sysfs_class, NULL, MKDEV(SCSI_CHANGER_MAJOR,ch->minor), dev, "s%s", ch->name); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 3f2f2464fa63..0bb60de0bded 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5627,7 +5627,7 @@ static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * if (!osst_sysfs_valid) return; - osst_class_member = class_device_create(osst_sysfs_class, dev, device, "%s", name); + osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name); if (IS_ERR(osst_class_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); return; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f0d8b4eda5ad..40886e1c9616 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1550,7 +1550,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) if (sg_sysfs_valid) { struct class_device * sg_class_member; - sg_class_member = class_device_create(sg_sysfs_class, + sg_class_member = class_device_create(sg_sysfs_class, NULL, MKDEV(SCSI_GENERIC_MAJOR, k), cl_dev->dev, "%s", disk->disk_name); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index d001c046551b..d45ba4832162 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4375,7 +4375,7 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) snprintf(name, 10, "%s%s%s", rew ? "n" : "", STp->disk->disk_name, st_formats[i]); st_class_member = - class_device_create(st_sysfs_class, + class_device_create(st_sysfs_class, NULL, MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew)), &STp->device->sdev_gendev, "%s", name); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 487ff672b104..befe0c7f63d1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1509,7 +1509,7 @@ 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, + dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 65ca131cc44c..78cb4be9529f 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -172,7 +172,9 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); + intf->class_dev = class_device_create(usb_class, NULL, + MKDEV(USB_MAJOR, minor), + &intf->dev, "%s", temp); if (IS_ERR(intf->class_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1017a97a418b..c3eb66f5a1a4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -782,7 +782,8 @@ static int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum); + bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), + bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 70be7009f8af..9073be4221a8 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1031,7 +1031,7 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - fb_info->class_device = class_device_create(fb_class, MKDEV(FB_MAJOR, i), + fb_info->class_device = class_device_create(fb_class, NULL, MKDEV(FB_MAJOR, i), fb_info->device, "fb%d", i); if (IS_ERR(fb_info->class_device)) { /* Not fatal */ diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 3d1cce3653b8..6a3df88accfe 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -370,8 +370,8 @@ static int init_coda_psdev(void) } devfs_mk_dir ("coda"); for (i = 0; i < MAX_CODADEVS; i++) { - class_device_create(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), - NULL, "cfs%d", i); + class_device_create(coda_psdev_class, NULL, + MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i); err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); if (err) diff --git a/sound/core/sound.c b/sound/core/sound.c index 9e76bddb2c0b..b57519a3e3d9 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -231,7 +231,7 @@ int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); if (card) device = card->dev; - class_device_create(sound_class, MKDEV(major, minor), device, "%s", name); + class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name); up(&sound_mutex); return 0; diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 95fa81e26de2..d33bb464f70e 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -567,7 +567,7 @@ static int __init oss_init(void) devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), S_IFCHR | dev_list[i].mode, "sound/%s", dev_list[i].name); - class_device_create(sound_class, + class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, dev_list[i].minor), NULL, "%s", dev_list[i].name); @@ -579,7 +579,7 @@ static int __init oss_init(void) dev_list[i].minor + (j*0x10)), S_IFCHR | dev_list[i].mode, "sound/%s%d", dev_list[i].name, j); - class_device_create(sound_class, + class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), NULL, "%s%d", dev_list[i].name, j); } diff --git a/sound/sound_core.c b/sound/sound_core.c index 954f994592ab..394b53e20cb8 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -174,7 +174,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), S_IFCHR | mode, s->name); - class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), + class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, s->unit_minor), dev, s->name+6); return r; From 74be227f728ed68bfc270153665b43fc1f0fa845 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0927/1939] [PATCH] Driver Core: document struct class_device properly Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/device.h b/include/linux/device.h index 226e550ae2ea..10ab7807f8ea 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -203,6 +203,30 @@ struct class_device_attribute class_device_attr_##_name = \ extern int class_device_create_file(struct class_device *, const struct class_device_attribute *); +/** + * struct class_device - class devices + * @class: pointer to the parent class for this class device. This is required. + * @devt: for internal use by the driver core only. + * @node: for internal use by the driver core only. + * @kobj: for internal use by the driver core only. + * @devt_attr: for internal use by the driver core only. + * @dev: if set, a symlink to the struct device is created in the sysfs + * directory for this struct class device. + * @class_data: pointer to whatever you want to store here for this struct + * class_device. Use class_get_devdata() and class_set_devdata() to get and + * set this pointer. + * @parent: pointer to a struct class_device that is the parent of this struct + * class_device. If NULL, this class_device will show up at the root of the + * struct class in sysfs (which is probably what you want to have happen.) + * @release: pointer to a release function for this struct class_device. If + * set, this will be called instead of the class specific release function. + * Only use this if you want to override the default release function, like + * when you are nesting class_device structures. + * @hotplug: pointer to a hotplug function for this struct class_device. If + * set, this will be called instead of the class specific hotplug function. + * Only use this if you want to override the default hotplug function, like + * when you are nesting class_device structures. + */ struct class_device { struct list_head node; From 4f00469c16b86a3dd6ed66b28c605c8430d58eeb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:38 -0500 Subject: [PATCH 0928/1939] [PATCH] Input: kill devfs references Input: remove references to devfs from input subsystem Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/evdev.c | 4 ---- drivers/input/input.c | 7 ------- drivers/input/joydev.c | 4 ---- drivers/input/mousedev.c | 9 +-------- drivers/input/tsdev.c | 7 ------- 5 files changed, 1 insertion(+), 30 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 83b694cb8507..14ea57f963bb 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -20,7 +20,6 @@ #include #include #include -#include #include struct evdev { @@ -687,8 +686,6 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), dev->dev, "event%d", minor); @@ -703,7 +700,6 @@ static void evdev_disconnect(struct input_handle *handle) class_device_destroy(input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); - devfs_remove("input/event%d", evdev->minor); evdev->exist = 0; if (evdev->open) { diff --git a/drivers/input/input.c b/drivers/input/input.c index 14ae5583e198..072bbf528151 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -22,7 +22,6 @@ #include #include #include -#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input core"); @@ -770,13 +769,8 @@ static int __init input_init(void) goto fail2; } - err = devfs_mk_dir("input"); - if (err) - goto fail3; - return 0; - fail3: unregister_chrdev(INPUT_MAJOR, "input"); fail2: input_proc_exit(); fail1: class_destroy(input_class); return err; @@ -785,7 +779,6 @@ static int __init input_init(void) static void __exit input_exit(void) { input_proc_exit(); - devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); class_destroy(input_class); } diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index c696fb2a6f99..40d2b46cbc79 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -26,7 +26,6 @@ #include #include #include -#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Joystick device interfaces"); @@ -514,8 +513,6 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), dev->dev, "js%d", minor); @@ -529,7 +526,6 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev_list *list; class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); - devfs_remove("input/js%d", joydev->minor); joydev->exist = 0; if (joydev->open) { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index d7144e1a9ae3..89c3e496f1ed 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -9,7 +9,7 @@ * the Free Software Foundation. */ -#define MOUSEDEV_MINOR_BASE 32 +#define MOUSEDEV_MINOR_BASE 32 #define MOUSEDEV_MINORS 32 #define MOUSEDEV_MIX 31 @@ -24,7 +24,6 @@ #include #include #include -#include #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #include #endif @@ -649,8 +648,6 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev_table[minor] = mousedev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), dev->dev, "mouse%d", minor); @@ -665,7 +662,6 @@ static void mousedev_disconnect(struct input_handle *handle) class_device_destroy(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); - devfs_remove("input/mouse%d", mousedev->minor); mousedev->exist = 0; if (mousedev->open) { @@ -738,8 +734,6 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), - S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); @@ -759,7 +753,6 @@ static void __exit mousedev_exit(void) if (psaux_registered) misc_deregister(&psaux_mouse); #endif - devfs_remove("input/mice"); class_device_destroy(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index fbb35c97551b..2d45e4df4163 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -53,7 +53,6 @@ #include #include #include -#include #ifndef CONFIG_INPUT_TSDEV_SCREEN_X #define CONFIG_INPUT_TSDEV_SCREEN_X 240 @@ -410,10 +409,6 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); - devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), - S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); class_device_create(input_class, NULL, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); @@ -428,8 +423,6 @@ static void tsdev_disconnect(struct input_handle *handle) class_device_destroy(input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); - devfs_remove("input/ts%d", tsdev->minor); - devfs_remove("input/tsraw%d", tsdev->minor); tsdev->exist = 0; if (tsdev->open) { From d19fbe8a763634395d4bef40fc88cdb61c4a6274 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:39 -0500 Subject: [PATCH 0929/1939] [PATCH] Input: prepare to sysfs integration Input: prepare to sysfs integration Add struct class_device to input_dev; add input_allocate_dev() to dynamically allocate input devices; dynamically allocated devices are automatically registered with sysfs. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 77 ++++++++++++++++++++++++++++++++++++++++--- include/linux/input.h | 24 +++++++++++++- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 072bbf528151..0e2e890c0988 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -27,6 +27,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(input_allocate_device); EXPORT_SYMBOL(input_register_device); EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_register_handler); @@ -605,6 +606,56 @@ static inline int input_proc_init(void) { return 0; } static inline void input_proc_exit(void) { } #endif +static void input_dev_release(struct class_device *class_dev) +{ + struct input_dev *dev = to_input_dev(class_dev); + + kfree(dev); + module_put(THIS_MODULE); +} + +static struct class input_dev_class = { + .name = "input_dev", + .release = input_dev_release, +}; + +struct input_dev *input_allocate_device(void) +{ + struct input_dev *dev; + + dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); + if (dev) { + dev->dynalloc = 1; + dev->cdev.class = &input_dev_class; + class_device_initialize(&dev->cdev); + INIT_LIST_HEAD(&dev->h_list); + INIT_LIST_HEAD(&dev->node); + } + + return dev; +} + +static void input_register_classdevice(struct input_dev *dev) +{ + static atomic_t input_no = ATOMIC_INIT(0); + const char *path; + + __module_get(THIS_MODULE); + + dev->dev = dev->cdev.dev; + + snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), + "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); + + path = kobject_get_path(&dev->cdev.class->subsys.kset.kobj, GFP_KERNEL); + printk(KERN_INFO "input: %s/%s as %s\n", + dev->name ? dev->name : "Unspecified device", + path ? path : "", dev->cdev.class_id); + kfree(path); + + class_device_add(&dev->cdev); +} + void input_register_device(struct input_dev *dev) { struct input_handle *handle; @@ -637,6 +688,10 @@ void input_register_device(struct input_dev *dev) if ((handle = handler->connect(handler, dev, id))) input_link_handle(handle); + + if (dev->dynalloc) + input_register_classdevice(dev); + #ifdef CONFIG_HOTPLUG input_call_hotplug("add", dev); #endif @@ -665,6 +720,9 @@ void input_unregister_device(struct input_dev *dev) list_del_init(&dev->node); + if (dev->dynalloc) + class_device_unregister(&dev->cdev); + input_wakeup_procfs_readers(); } @@ -753,26 +811,34 @@ static int __init input_init(void) { int err; + err = class_register(&input_dev_class); + if (err) { + printk(KERN_ERR "input: unable to register input_dev class\n"); + return err; + } + input_class = class_create(THIS_MODULE, "input"); if (IS_ERR(input_class)) { printk(KERN_ERR "input: unable to register input class\n"); - return PTR_ERR(input_class); + err = PTR_ERR(input_class); + goto fail1; } err = input_proc_init(); if (err) - goto fail1; + goto fail2; err = register_chrdev(INPUT_MAJOR, "input", &input_fops); if (err) { printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); - goto fail2; + goto fail3; } return 0; - fail2: input_proc_exit(); - fail1: class_destroy(input_class); + fail3: input_proc_exit(); + fail2: class_destroy(input_class); + fail1: class_unregister(&input_dev_class); return err; } @@ -781,6 +847,7 @@ static void __exit input_exit(void) input_proc_exit(); unregister_chrdev(INPUT_MAJOR, "input"); class_destroy(input_class); + class_unregister(&input_dev_class); } subsys_initcall(input_init); diff --git a/include/linux/input.h b/include/linux/input.h index e8c296ff6257..3defa29a17d3 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -12,6 +12,7 @@ #ifdef __KERNEL__ #include #include +#include #else #include #include @@ -889,11 +890,15 @@ struct input_dev { struct semaphore sem; /* serializes open and close operations */ unsigned int users; - struct device *dev; + struct class_device cdev; + struct device *dev; /* will be removed soon */ + + int dynalloc; /* temporarily */ struct list_head h_list; struct list_head node; }; +#define to_input_dev(d) container_of(d, struct input_dev, cdev) /* * Structure for hotplug & device<->driver matching. @@ -984,6 +989,23 @@ static inline void init_input_dev(struct input_dev *dev) INIT_LIST_HEAD(&dev->node); } +struct input_dev *input_allocate_device(void); + +static inline void input_free_device(struct input_dev *dev) +{ + kfree(dev); +} + +static inline struct input_dev *input_get_device(struct input_dev *dev) +{ + return to_input_dev(class_device_get(&dev->cdev)); +} + +static inline void input_put_device(struct input_dev *dev) +{ + class_device_put(&dev->cdev); +} + void input_register_device(struct input_dev *); void input_unregister_device(struct input_dev *); From 2e5b636bb5f8dacbb91d08544e2c41ebcad5dace Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:44 -0500 Subject: [PATCH 0930/1939] [PATCH] drivers/input/mouse: convert to dynamic input_dev allocation Input: convert drivers/input/mouse to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/alps.c | 63 +++++++++-------- drivers/input/mouse/alps.h | 2 +- drivers/input/mouse/amimouse.c | 49 +++++++------ drivers/input/mouse/inport.c | 106 +++++++++++++++-------------- drivers/input/mouse/lifebook.c | 16 +++-- drivers/input/mouse/logibm.c | 88 ++++++++++++------------ drivers/input/mouse/logips2pp.c | 20 +++--- drivers/input/mouse/maplemouse.c | 10 +-- drivers/input/mouse/pc110pad.c | 64 +++++++++-------- drivers/input/mouse/psmouse-base.c | 99 ++++++++++++++------------- drivers/input/mouse/psmouse.h | 2 +- drivers/input/mouse/rpcmouse.c | 43 ++++++------ drivers/input/mouse/sermouse.c | 82 +++++++++++----------- drivers/input/mouse/synaptics.c | 6 +- drivers/input/mouse/vsxxxaa.c | 84 +++++++++++------------ 15 files changed, 368 insertions(+), 366 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index b20783f9748a..4acc7fd4cd0f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -79,8 +79,8 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) { struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; - struct input_dev *dev = &psmouse->dev; - struct input_dev *dev2 = &priv->dev2; + struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; int x, y, z, ges, fin, left, right, middle; int back = 0, forward = 0; @@ -379,20 +379,24 @@ static int alps_reconnect(struct psmouse *psmouse) static void alps_disconnect(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + psmouse_reset(psmouse); - input_unregister_device(&priv->dev2); + input_unregister_device(priv->dev2); kfree(priv); } int alps_init(struct psmouse *psmouse) { struct alps_data *priv; + struct input_dev *dev1 = psmouse->dev, *dev2; int version; - psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL); - if (!priv) + psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); + dev2 = input_allocate_device(); + if (!priv || !dev2) goto init_fail; - memset(priv, 0, sizeof(struct alps_data)); + + priv->dev2 = dev2; if (!(priv->i = alps_get_model(psmouse, &version))) goto init_fail; @@ -411,41 +415,39 @@ int alps_init(struct psmouse *psmouse) if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) goto init_fail; - psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY); - psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); - psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); - psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + dev1->evbit[LONG(EV_KEY)] |= BIT(EV_KEY); + dev1->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); + dev1->keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); + dev1->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS); - input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0); + dev1->evbit[LONG(EV_ABS)] |= BIT(EV_ABS); + input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); + input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); + input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); if (priv->i->flags & ALPS_WHEEL) { - psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL); - psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); + dev1->evbit[LONG(EV_REL)] |= BIT(EV_REL); + dev1->relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); } if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); - psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); + dev1->keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); + dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); } sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys); - priv->dev2.phys = priv->phys; - priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; - priv->dev2.id.bustype = BUS_I8042; - priv->dev2.id.vendor = 0x0002; - priv->dev2.id.product = PSMOUSE_ALPS; - priv->dev2.id.version = 0x0000; + dev2->phys = priv->phys; + dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; + dev2->id.bustype = BUS_I8042; + dev2->id.vendor = 0x0002; + dev2->id.product = PSMOUSE_ALPS; + dev2->id.version = 0x0000; - priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); - priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); + dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - input_register_device(&priv->dev2); - - printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys); + input_register_device(priv->dev2); psmouse->protocol_handler = alps_process_byte; psmouse->disconnect = alps_disconnect; @@ -455,6 +457,7 @@ int alps_init(struct psmouse *psmouse) return 0; init_fail: + input_free_device(dev2); kfree(priv); return -1; } diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index aba103dd65b7..e428f8d5d12e 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -22,7 +22,7 @@ struct alps_model_info { }; struct alps_data { - struct input_dev dev2; /* Relative device */ + struct input_dev *dev2; /* Relative device */ char name[32]; /* Name */ char phys[32]; /* Phys */ struct alps_model_info *i; /* Info */ diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index e994849efb8f..d13d4c8fe3c5 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -34,10 +34,7 @@ MODULE_DESCRIPTION("Amiga mouse driver"); MODULE_LICENSE("GPL"); static int amimouse_lastx, amimouse_lasty; -static struct input_dev amimouse_dev; - -static char *amimouse_name = "Amiga mouse"; -static char *amimouse_phys = "amimouse/input0"; +static struct input_dev *amimouse_dev; static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) { @@ -62,16 +59,16 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) potgor = custom.potgor; - input_regs(&amimouse_dev, fp); + input_regs(amimouse_dev, fp); - input_report_rel(&amimouse_dev, REL_X, dx); - input_report_rel(&amimouse_dev, REL_Y, dy); + input_report_rel(amimouse_dev, REL_X, dx); + input_report_rel(amimouse_dev, REL_Y, dy); - input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); - input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); - input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); + input_report_key(amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); + input_report_key(amimouse_dev, BTN_MIDDLE, potgor & 0x0100); + input_report_key(amimouse_dev, BTN_RIGHT, potgor & 0x0400); - input_sync(&amimouse_dev); + input_sync(amimouse_dev); return IRQ_HANDLED; } @@ -103,28 +100,30 @@ static int __init amimouse_init(void) if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) return -ENODEV; - amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - amimouse_dev.open = amimouse_open; - amimouse_dev.close = amimouse_close; + if (!(amimouse_dev = input_allocate_device())) + return -ENOMEM; - amimouse_dev.name = amimouse_name; - amimouse_dev.phys = amimouse_phys; - amimouse_dev.id.bustype = BUS_AMIGA; - amimouse_dev.id.vendor = 0x0001; - amimouse_dev.id.product = 0x0002; - amimouse_dev.id.version = 0x0100; + amimouse_dev->name = "Amiga mouse"; + amimouse_dev->phys = "amimouse/input0"; + amimouse_dev->id.bustype = BUS_AMIGA; + amimouse_dev->id.vendor = 0x0001; + amimouse_dev->id.product = 0x0002; + amimouse_dev->id.version = 0x0100; - input_register_device(&amimouse_dev); + amimouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + amimouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + amimouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + amimouse_dev->open = amimouse_open; + amimouse_dev->close = amimouse_close; + + input_register_device(amimouse_dev); - printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name); return 0; } static void __exit amimouse_exit(void) { - input_unregister_device(&amimouse_dev); + input_unregister_device(amimouse_dev); } module_init(amimouse_init); diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 1f62c0134010..afc66f56df43 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -87,7 +87,36 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)"); __obsolete_setup("inport_irq="); -static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct input_dev *inport_dev; + +static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char buttons; + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + input_regs(inport_dev, regs); + + outb(INPORT_REG_X, INPORT_CONTROL_PORT); + input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_Y, INPORT_CONTROL_PORT); + input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); + buttons = inb(INPORT_DATA_PORT); + + input_report_key(inport_dev, BTN_MIDDLE, buttons & 1); + input_report_key(inport_dev, BTN_LEFT, buttons & 2); + input_report_key(inport_dev, BTN_RIGHT, buttons & 4); + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + input_sync(inport_dev); + return IRQ_HANDLED; +} static int inport_open(struct input_dev *dev) { @@ -106,54 +135,9 @@ static void inport_close(struct input_dev *dev) free_irq(inport_irq, NULL); } -static struct input_dev inport_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .open = inport_open, - .close = inport_close, - .name = INPORT_NAME, - .phys = "isa023c/input0", - .id = { - .bustype = BUS_ISA, - .vendor = INPORT_VENDOR, - .product = 0x0001, - .version = 0x0100, - }, -}; - -static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned char buttons; - - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - input_regs(&inport_dev, regs); - - outb(INPORT_REG_X, INPORT_CONTROL_PORT); - input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT)); - - outb(INPORT_REG_Y, INPORT_CONTROL_PORT); - input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT)); - - outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); - buttons = inb(INPORT_DATA_PORT); - - input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1); - input_report_key(&inport_dev, BTN_LEFT, buttons & 2); - input_report_key(&inport_dev, BTN_RIGHT, buttons & 4); - - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - input_sync(&inport_dev); - return IRQ_HANDLED; -} - static int __init inport_init(void) { - unsigned char a,b,c; + unsigned char a, b, c; if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) { printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE); @@ -163,26 +147,44 @@ static int __init inport_init(void) a = inb(INPORT_SIGNATURE_PORT); b = inb(INPORT_SIGNATURE_PORT); c = inb(INPORT_SIGNATURE_PORT); - if (( a == b ) || ( a != c )) { + if (a == b || a != c) { release_region(INPORT_BASE, INPORT_EXTENT); printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE); return -ENODEV; } + if (!(inport_dev = input_allocate_device())) { + printk(KERN_ERR "inport.c: Not enough memory for input device\n"); + release_region(INPORT_BASE, INPORT_EXTENT); + return -ENOMEM; + } + + inport_dev->name = INPORT_NAME; + inport_dev->phys = "isa023c/input0"; + inport_dev->id.bustype = BUS_ISA; + inport_dev->id.vendor = INPORT_VENDOR; + inport_dev->id.product = 0x0001; + inport_dev->id.version = 0x0100; + + inport_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + inport_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + inport_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + inport_dev->open = inport_open; + inport_dev->close = inport_close; + outb(INPORT_RESET, INPORT_CONTROL_PORT); outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_BASE, INPORT_DATA_PORT); - input_register_device(&inport_dev); - - printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq); + input_register_device(inport_dev); return 0; } static void __exit inport_exit(void) { - input_unregister_device(&inport_dev); + input_unregister_device(inport_dev); release_region(INPORT_BASE, INPORT_EXTENT); } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index bd9df9b28325..55991424ac91 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -34,7 +34,7 @@ static struct dmi_system_id lifebook_dmi_table[] = { static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { unsigned char *packet = psmouse->packet; - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; if (psmouse->pktcnt != 3) return PSMOUSE_GOOD_DATA; @@ -113,15 +113,17 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) int lifebook_init(struct psmouse *psmouse) { + struct input_dev *input_dev = psmouse->dev; + if (lifebook_absolute_mode(psmouse)) return -1; - psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); - psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0); + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0); psmouse->protocol_handler = lifebook_process_byte; psmouse->set_resolution = lifebook_set_resolution; diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c index 8b5243167227..9c7ce38806d7 100644 --- a/drivers/input/mouse/logibm.c +++ b/drivers/input/mouse/logibm.c @@ -77,39 +77,7 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)"); __obsolete_setup("logibm_irq="); -static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static int logibm_open(struct input_dev *dev) -{ - if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { - printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); - return -EBUSY; - } - outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); - return 0; -} - -static void logibm_close(struct input_dev *dev) -{ - outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - free_irq(logibm_irq, NULL); -} - -static struct input_dev logibm_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .open = logibm_open, - .close = logibm_close, - .name = "Logitech bus mouse", - .phys = "isa023c/input0", - .id = { - .bustype = BUS_ISA, - .vendor = 0x0003, - .product = 0x0001, - .version = 0x0100, - }, -}; +static struct input_dev *logibm_dev; static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -127,18 +95,34 @@ static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) dy |= (buttons & 0xf) << 4; buttons = ~buttons >> 5; - input_regs(&logibm_dev, regs); - input_report_rel(&logibm_dev, REL_X, dx); - input_report_rel(&logibm_dev, REL_Y, dy); - input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1); - input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2); - input_report_key(&logibm_dev, BTN_LEFT, buttons & 4); - input_sync(&logibm_dev); + input_regs(logibm_dev, regs); + input_report_rel(logibm_dev, REL_X, dx); + input_report_rel(logibm_dev, REL_Y, dy); + input_report_key(logibm_dev, BTN_RIGHT, buttons & 1); + input_report_key(logibm_dev, BTN_MIDDLE, buttons & 2); + input_report_key(logibm_dev, BTN_LEFT, buttons & 4); + input_sync(logibm_dev); outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); return IRQ_HANDLED; } +static int logibm_open(struct input_dev *dev) +{ + if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { + printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); + return -EBUSY; + } + outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); + return 0; +} + +static void logibm_close(struct input_dev *dev) +{ + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + free_irq(logibm_irq, NULL); +} + static int __init logibm_init(void) { if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { @@ -159,16 +143,34 @@ static int __init logibm_init(void) outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - input_register_device(&logibm_dev); + if (!(logibm_dev = input_allocate_device())) { + printk(KERN_ERR "logibm.c: Not enough memory for input device\n"); + release_region(LOGIBM_BASE, LOGIBM_EXTENT); + return -ENOMEM; + } - printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); + logibm_dev->name = "Logitech bus mouse"; + logibm_dev->phys = "isa023c/input0"; + logibm_dev->id.bustype = BUS_ISA; + logibm_dev->id.vendor = 0x0003; + logibm_dev->id.product = 0x0001; + logibm_dev->id.version = 0x0100; + + logibm_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + logibm_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + logibm_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + logibm_dev->open = logibm_open; + logibm_dev->close = logibm_close; + + input_register_device(logibm_dev); return 0; } static void __exit logibm_exit(void) { - input_unregister_device(&logibm_dev); + input_unregister_device(logibm_dev); release_region(LOGIBM_BASE, LOGIBM_EXTENT); } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 7df96525222e..0f69ff46c1ae 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -40,7 +40,7 @@ struct ps2pp_info { static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; if (psmouse->pktcnt < 3) @@ -257,25 +257,27 @@ static struct ps2pp_info *get_model_info(unsigned char model) static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, int using_ps2pp) { + struct input_dev *input_dev = psmouse->dev; + if (model_info->features & PS2PP_SIDE_BTN) - set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_SIDE, input_dev->keybit); if (model_info->features & PS2PP_EXTRA_BTN) - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_EXTRA, input_dev->keybit); if (model_info->features & PS2PP_TASK_BTN) - set_bit(BTN_TASK, psmouse->dev.keybit); + set_bit(BTN_TASK, input_dev->keybit); if (model_info->features & PS2PP_NAV_BTN) { - set_bit(BTN_FORWARD, psmouse->dev.keybit); - set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, input_dev->keybit); + set_bit(BTN_BACK, input_dev->keybit); } if (model_info->features & PS2PP_WHEEL) - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_WHEEL, input_dev->relbit); if (model_info->features & PS2PP_HWHEEL) - set_bit(REL_HWHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, input_dev->relbit); switch (model_info->kind) { case PS2PP_KIND_WHEEL: @@ -387,7 +389,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) } if (buttons < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + clear_bit(BTN_MIDDLE, psmouse->dev->keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index e90c60cbbf05..b5b34fe4fee8 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -41,13 +41,12 @@ static int dc_mouse_connect(struct maple_device *dev) unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct input_dev *input_dev; - if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL))) - return -1; + dev->private_data = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; dev->private_data = input_dev; - memset(input_dev, 0, sizeof(struct dc_mouse)); - init_input_dev(input_dev); input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); @@ -59,8 +58,6 @@ static int dc_mouse_connect(struct maple_device *dev) maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); - printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name); - return 0; } @@ -70,7 +67,6 @@ static void dc_mouse_disconnect(struct maple_device *dev) struct input_dev *input_dev = dev->private_data; input_unregister_device(input_dev); - kfree(input_dev); } diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 93393d5c0078..d284ea712151 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -53,13 +53,10 @@ MODULE_LICENSE("GPL"); static int pc110pad_irq = 10; static int pc110pad_io = 0x15e0; -static struct input_dev pc110pad_dev; +static struct input_dev *pc110pad_dev; static int pc110pad_data[3]; static int pc110pad_count; -static char *pc110pad_name = "IBM PC110 TouchPad"; -static char *pc110pad_phys = "isa15e0/input0"; - static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) { int value = inb_p(pc110pad_io); @@ -74,14 +71,14 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) if (pc110pad_count < 3) return IRQ_HANDLED; - input_regs(&pc110pad_dev, regs); - input_report_key(&pc110pad_dev, BTN_TOUCH, + input_regs(pc110pad_dev, regs); + input_report_key(pc110pad_dev, BTN_TOUCH, pc110pad_data[0] & 0x01); - input_report_abs(&pc110pad_dev, ABS_X, + input_report_abs(pc110pad_dev, ABS_X, pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); - input_report_abs(&pc110pad_dev, ABS_Y, + input_report_abs(pc110pad_dev, ABS_Y, pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); - input_sync(&pc110pad_dev); + input_sync(pc110pad_dev); pc110pad_count = 0; return IRQ_HANDLED; @@ -94,9 +91,9 @@ static void pc110pad_close(struct input_dev *dev) static int pc110pad_open(struct input_dev *dev) { - pc110pad_interrupt(0,NULL,NULL); - pc110pad_interrupt(0,NULL,NULL); - pc110pad_interrupt(0,NULL,NULL); + pc110pad_interrupt(0, NULL, NULL); + pc110pad_interrupt(0, NULL, NULL); + pc110pad_interrupt(0, NULL, NULL); outb(PC110PAD_ON, pc110pad_io + 2); pc110pad_count = 0; @@ -127,45 +124,46 @@ static int __init pc110pad_init(void) outb(PC110PAD_OFF, pc110pad_io + 2); - if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) - { + if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) { release_region(pc110pad_io, 4); printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); return -EBUSY; } - pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + if (!(pc110pad_dev = input_allocate_device())) { + free_irq(pc110pad_irq, NULL); + release_region(pc110pad_io, 4); + printk(KERN_ERR "pc110pad: Not enough memory.\n"); + return -ENOMEM; + } - pc110pad_dev.absmax[ABS_X] = 0x1ff; - pc110pad_dev.absmax[ABS_Y] = 0x0ff; + pc110pad_dev->name = "IBM PC110 TouchPad"; + pc110pad_dev->phys = "isa15e0/input0"; + pc110pad_dev->id.bustype = BUS_ISA; + pc110pad_dev->id.vendor = 0x0003; + pc110pad_dev->id.product = 0x0001; + pc110pad_dev->id.version = 0x0100; - pc110pad_dev.open = pc110pad_open; - pc110pad_dev.close = pc110pad_close; + pc110pad_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + pc110pad_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + pc110pad_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - pc110pad_dev.name = pc110pad_name; - pc110pad_dev.phys = pc110pad_phys; - pc110pad_dev.id.bustype = BUS_ISA; - pc110pad_dev.id.vendor = 0x0003; - pc110pad_dev.id.product = 0x0001; - pc110pad_dev.id.version = 0x0100; + pc110pad_dev->absmax[ABS_X] = 0x1ff; + pc110pad_dev->absmax[ABS_Y] = 0x0ff; - input_register_device(&pc110pad_dev); + pc110pad_dev->open = pc110pad_open; + pc110pad_dev->close = pc110pad_close; - printk(KERN_INFO "input: %s at %#x irq %d\n", - pc110pad_name, pc110pad_io, pc110pad_irq); + input_register_device(pc110pad_dev); return 0; } static void __exit pc110pad_exit(void) { - input_unregister_device(&pc110pad_dev); - outb(PC110PAD_OFF, pc110pad_io + 2); - free_irq(pc110pad_irq, NULL); + input_unregister_device(pc110pad_dev); release_region(pc110pad_io, 4); } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index af24313ff5bb..6ee9999a2eaa 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -114,7 +114,7 @@ struct psmouse_protocol { static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; if (psmouse->pktcnt < psmouse->pktsize) @@ -333,12 +333,11 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev.keybit); - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); + set_bit(BTN_SIDE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); psmouse->vendor = "Genius"; - psmouse->name = "Wheel Mouse"; psmouse->pktsize = 4; } @@ -365,8 +364,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(BTN_MIDDLE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Wheel Mouse"; @@ -398,10 +397,10 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_MIDDLE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); + set_bit(BTN_SIDE, psmouse->dev->keybit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Explorer Mouse"; @@ -433,7 +432,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; psmouse->name = "ThinkingMouse"; @@ -839,9 +838,9 @@ static void psmouse_disconnect(struct serio *serio) psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_unregister_device(&psmouse->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(psmouse->dev); kfree(psmouse); if (parent) @@ -852,16 +851,14 @@ static void psmouse_disconnect(struct serio *serio) static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) { - memset(&psmouse->dev, 0, sizeof(struct input_dev)); + struct input_dev *input_dev = psmouse->dev; - init_input_dev(&psmouse->dev); + input_dev->private = psmouse; + input_dev->cdev.dev = &psmouse->ps2dev.serio->dev; - psmouse->dev.private = psmouse; - psmouse->dev.dev = &psmouse->ps2dev.serio->dev; - - psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; @@ -883,12 +880,12 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto sprintf(psmouse->devname, "%s %s %s", psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); - psmouse->dev.name = psmouse->devname; - psmouse->dev.phys = psmouse->phys; - psmouse->dev.id.bustype = BUS_I8042; - psmouse->dev.id.vendor = 0x0002; - psmouse->dev.id.product = psmouse->type; - psmouse->dev.id.version = psmouse->model; + input_dev->name = psmouse->devname; + input_dev->phys = psmouse->phys; + input_dev->id.bustype = BUS_I8042; + input_dev->id.vendor = 0x0002; + input_dev->id.product = psmouse->type; + input_dev->id.version = psmouse->model; return 0; } @@ -900,7 +897,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto static int psmouse_connect(struct serio *serio, struct serio_driver *drv) { struct psmouse *psmouse, *parent = NULL; - int retval; + struct input_dev *input_dev; + int retval = -ENOMEM; down(&psmouse_sem); @@ -913,12 +911,13 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_deactivate(parent); } - if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) { - retval = -ENOMEM; + psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!psmouse || !input_dev) goto out; - } ps2_init(&psmouse->ps2dev, serio); + psmouse->dev = input_dev; sprintf(psmouse->phys, "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -926,16 +925,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) serio_set_drvdata(serio, psmouse); retval = serio_open(serio, drv); - if (retval) { - serio_set_drvdata(serio, NULL); - kfree(psmouse); + if (retval) goto out; - } if (psmouse_probe(psmouse) < 0) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(psmouse); retval = -ENODEV; goto out; } @@ -947,13 +941,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_switch_protocol(psmouse, NULL); - input_register_device(&psmouse->dev); - printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); + input_register_device(psmouse->dev); + if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -964,6 +956,12 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) retval = 0; out: + if (retval) { + serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(psmouse); + } + /* If this is a pass-through port the parent needs to be re-activated */ if (parent) psmouse_activate(parent); @@ -1161,6 +1159,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co { struct serio *serio = psmouse->ps2dev.serio; struct psmouse *parent = NULL; + struct input_dev *new_dev; struct psmouse_protocol *proto; int retry = 0; @@ -1170,9 +1169,13 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (psmouse->type == proto->type) return count; + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + while (serio->child) { if (++retry > 3) { printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); + input_free_device(new_dev); return -EIO; } @@ -1182,11 +1185,15 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co serio_pin_driver_uninterruptible(serio); down(&psmouse_sem); - if (serio->drv != &psmouse_drv) + if (serio->drv != &psmouse_drv) { + input_free_device(new_dev); return -ENODEV; + } - if (psmouse->type == proto->type) + if (psmouse->type == proto->type) { + input_free_device(new_dev); return count; /* switched by other thread */ + } } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { @@ -1199,8 +1206,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse->disconnect(psmouse); psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_unregister_device(&psmouse->dev); + input_unregister_device(psmouse->dev); + psmouse->dev = new_dev; psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); if (psmouse_switch_protocol(psmouse, proto) < 0) { @@ -1212,8 +1220,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse_initialize(psmouse); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - input_register_device(&psmouse->dev); - printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + input_register_device(psmouse->dev); if (parent && parent->pt_activate) parent->pt_activate(parent); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 45d2bd774f00..7c4192bd1279 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -36,7 +36,7 @@ typedef enum { struct psmouse { void *private; - struct input_dev dev; + struct input_dev *dev; struct ps2dev ps2dev; char *vendor; char *name; diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index 8fe1212b8fd7..09b6ffdb7582 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -34,20 +34,7 @@ MODULE_DESCRIPTION("Acorn RiscPC mouse driver"); MODULE_LICENSE("GPL"); static short rpcmouse_lastx, rpcmouse_lasty; - -static struct input_dev rpcmouse_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .name = "Acorn RiscPC Mouse", - .phys = "rpcmouse/input0", - .id = { - .bustype = BUS_HOST, - .vendor = 0x0005, - .product = 0x0001, - .version = 0x0100, - }, -}; +static struct input_dev *rpcmouse_dev; static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) { @@ -78,29 +65,41 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } + static int __init rpcmouse_init(void) { - init_input_dev(&rpcmouse_dev); + if (!(rpcmouse_dev = input_allocate_device())) + return -ENOMEM; + + rpcmouse_dev->name = "Acorn RiscPC Mouse"; + rpcmouse_dev->phys = "rpcmouse/input0"; + rpcmouse_dev->id.bustype = BUS_HOST; + rpcmouse_dev->id.vendor = 0x0005; + rpcmouse_dev->id.product = 0x0001; + rpcmouse_dev->id.version = 0x0100; + + rpcmouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + rpcmouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + rpcmouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX); rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY); - if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) { + if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", rpcmouse_dev)) { printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n"); - return -1; + input_free_device(rpcmouse_dev); + return -EBUSY; } - input_register_device(&rpcmouse_dev); - - printk(KERN_INFO "input: Acorn RiscPC mouse\n"); + input_register_device(rpcmouse_dev); return 0; } static void __exit rpcmouse_exit(void) { - input_unregister_device(&rpcmouse_dev); - free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev); + free_irq(IRQ_VSYNCPULSE, rpcmouse_dev); + input_unregister_device(rpcmouse_dev); } module_init(rpcmouse_init); diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index d12b93ae3900..4bf584364d28 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -48,7 +48,7 @@ static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse" "Logitech MZ++ Mouse"}; struct sermouse { - struct input_dev dev; + struct input_dev *dev; signed char buf[8]; unsigned char count; unsigned char type; @@ -64,7 +64,7 @@ struct sermouse { static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) { - struct input_dev *dev = &sermouse->dev; + struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; input_regs(dev, regs); @@ -107,7 +107,7 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data, st static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) { - struct input_dev *dev = &sermouse->dev; + struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; if (data & 0x40) sermouse->count = 0; @@ -230,9 +230,9 @@ static void sermouse_disconnect(struct serio *serio) { struct sermouse *sermouse = serio_get_drvdata(serio); - input_unregister_device(&sermouse->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(sermouse->dev); kfree(sermouse); } @@ -244,56 +244,52 @@ static void sermouse_disconnect(struct serio *serio) static int sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; - unsigned char c; - int err; + struct input_dev *input_dev; + unsigned char c = serio->id.extra; + int err = -ENOMEM; - if (!serio->id.proto || serio->id.proto > SERIO_MZPP) - return -ENODEV; - - if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) - return -ENOMEM; - - memset(sermouse, 0, sizeof(struct sermouse)); - - init_input_dev(&sermouse->dev); - sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); - sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - sermouse->dev.private = sermouse; - - sermouse->type = serio->id.proto; - c = serio->id.extra; - - if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit); - if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit); - if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit); - if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit); - if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit); + sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sermouse || !input_dev) + goto fail; + sermouse->dev = input_dev; sprintf(sermouse->phys, "%s/input0", serio->phys); + sermouse->type = serio->id.proto; - sermouse->dev.name = sermouse_protocols[sermouse->type]; - sermouse->dev.phys = sermouse->phys; - sermouse->dev.id.bustype = BUS_RS232; - sermouse->dev.id.vendor = sermouse->type; - sermouse->dev.id.product = c; - sermouse->dev.id.version = 0x0100; - sermouse->dev.dev = &serio->dev; + input_dev->name = sermouse_protocols[sermouse->type]; + input_dev->phys = sermouse->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = sermouse->type; + input_dev->id.product = c; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->private = sermouse; + + if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit); + if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit); + if (c & 0x04) set_bit(BTN_EXTRA, input_dev->keybit); + if (c & 0x10) set_bit(REL_WHEEL, input_dev->relbit); + if (c & 0x20) set_bit(REL_HWHEEL, input_dev->relbit); serio_set_drvdata(serio, sermouse); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(sermouse); - return err; - } + if (err) + goto fail; - input_register_device(&sermouse->dev); - - printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); + input_register_device(sermouse->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(sermouse); + return err; } static struct serio_device_id sermouse_serio_ids[] = { diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 029309422409..97cdfd6acaca 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -342,7 +342,7 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data */ static void synaptics_process_packet(struct psmouse *psmouse) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; struct synaptics_hw_state hw; int num_fingers; @@ -473,7 +473,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; input_regs(dev, regs); @@ -645,7 +645,7 @@ int synaptics_init(struct psmouse *psmouse) SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), priv->model_id, priv->capabilities, priv->ext_cap); - set_input_params(&psmouse->dev, priv); + set_input_params(psmouse->dev, priv); psmouse->protocol_handler = synaptics_process_byte; psmouse->set_rate = synaptics_set_rate; diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index f024be9b44d2..36e9442a16b2 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -112,7 +112,7 @@ MODULE_LICENSE ("GPL"); struct vsxxxaa { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; #define BUFLEN 15 /* At least 5 is needed for a full tablet packet */ unsigned char buf[BUFLEN]; @@ -211,7 +211,7 @@ vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t le static void vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right; int dx, dy; @@ -269,7 +269,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) static void vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right, touch; int x, y; @@ -323,7 +323,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) static void vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right; unsigned char error; @@ -483,9 +483,9 @@ vsxxxaa_disconnect (struct serio *serio) { struct vsxxxaa *mouse = serio_get_drvdata (serio); - input_unregister_device (&mouse->dev); serio_close (serio); serio_set_drvdata (serio, NULL); + input_unregister_device (mouse->dev); kfree (mouse); } @@ -493,61 +493,57 @@ static int vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL))) - return -ENOMEM; - - memset (mouse, 0, sizeof (struct vsxxxaa)); - - init_input_dev (&mouse->dev); - set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ - set_bit (EV_REL, mouse->dev.evbit); - set_bit (EV_ABS, mouse->dev.evbit); - set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ - set_bit (BTN_MIDDLE, mouse->dev.keybit); - set_bit (BTN_RIGHT, mouse->dev.keybit); - set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */ - set_bit (REL_X, mouse->dev.relbit); - set_bit (REL_Y, mouse->dev.relbit); - set_bit (ABS_X, mouse->dev.absbit); - set_bit (ABS_Y, mouse->dev.absbit); - - mouse->dev.absmin[ABS_X] = 0; - mouse->dev.absmax[ABS_X] = 1023; - mouse->dev.absmin[ABS_Y] = 0; - mouse->dev.absmax[ABS_Y] = 1023; - - mouse->dev.private = mouse; + mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL); + input_dev = input_allocate_device (); + if (!mouse || !input_dev) + goto fail; + mouse->dev = input_dev; + mouse->serio = serio; sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer"); sprintf (mouse->phys, "%s/input0", serio->phys); - mouse->dev.name = mouse->name; - mouse->dev.phys = mouse->phys; - mouse->dev.id.bustype = BUS_RS232; - mouse->dev.dev = &serio->dev; - mouse->serio = serio; + + input_dev->name = mouse->name; + input_dev->phys = mouse->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->cdev.dev = &serio->dev; + input_dev->private = mouse; + + set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ + set_bit (EV_REL, input_dev->evbit); + set_bit (EV_ABS, input_dev->evbit); + set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ + set_bit (BTN_MIDDLE, input_dev->keybit); + set_bit (BTN_RIGHT, input_dev->keybit); + set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ + set_bit (REL_X, input_dev->relbit); + set_bit (REL_Y, input_dev->relbit); + input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0); + input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0); serio_set_drvdata (serio, mouse); err = serio_open (serio, drv); - if (err) { - serio_set_drvdata (serio, NULL); - kfree (mouse); - return err; - } + if (err) + goto fail; /* * Request selftest. Standard packet format and differential * mode will be requested after the device ID'ed successfully. */ - mouse->serio->write (mouse->serio, 'T'); /* Test */ + serio->write (serio, 'T'); /* Test */ - input_register_device (&mouse->dev); - - printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); + input_register_device (input_dev); return 0; + + fail: serio_set_drvdata (serio, NULL); + input_free_device (input_dev); + kfree (mouse); + return err; } static struct serio_device_id vsxxaa_serio_ids[] = { From 3c42f0c3dde8feb59fc87df45cadb847d5511c0a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:45 -0500 Subject: [PATCH 0931/1939] [PATCH] drivers/input/keyboard: convert to dynamic input_dev allocation Input: convert drivers/input/keyboard to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/keyboard/amikbd.c | 57 +++++---- drivers/input/keyboard/atkbd.c | 188 +++++++++++++++------------- drivers/input/keyboard/corgikbd.c | 76 +++++------ drivers/input/keyboard/lkkbd.c | 126 +++++++++---------- drivers/input/keyboard/maple_keyb.c | 72 +++++------ drivers/input/keyboard/newtonkbd.c | 83 ++++++------ drivers/input/keyboard/spitzkbd.c | 77 +++++++----- drivers/input/keyboard/sunkbd.c | 117 +++++++++-------- drivers/input/keyboard/xtkbd.c | 82 ++++++------ 9 files changed, 448 insertions(+), 430 deletions(-) diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 4e8e8ea214ab..3d63bc1ad322 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -155,10 +155,7 @@ static const char *amikbd_messages[8] = { [7] = KERN_WARNING "amikbd: keyboard interrupt\n" }; -static struct input_dev amikbd_dev; - -static char *amikbd_name = "Amiga keyboard"; -static char *amikbd_phys = "amikbd/input0"; +static struct input_dev *amikbd_dev; static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) { @@ -176,16 +173,16 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) scancode = amikbd_keycode[scancode]; - input_regs(&amikbd_dev, fp); + input_regs(amikbd_dev, fp); if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ - input_report_key(&amikbd_dev, scancode, 1); - input_report_key(&amikbd_dev, scancode, 0); - input_sync(&amikbd_dev); + input_report_key(amikbd_dev, scancode, 1); + input_report_key(amikbd_dev, scancode, 0); } else { - input_report_key(&amikbd_dev, scancode, down); - input_sync(&amikbd_dev); + input_report_key(amikbd_dev, scancode, down); } + + input_sync(amikbd_dev); } else /* scancodes >= 0x78 are error codes */ printk(amikbd_messages[scancode - 0x78]); @@ -202,39 +199,41 @@ static int __init amikbd_init(void) if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) return -EBUSY; - init_input_dev(&amikbd_dev); + amikbd_dev = input_dev_allocate(); + if (!amikbd_dev) { + printk(KERN_ERR "amikbd: not enough memory for input device\n"); + release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100); + return -ENOMEM; + } - amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - amikbd_dev.keycode = amikbd_keycode; - amikbd_dev.keycodesize = sizeof(unsigned char); - amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode); + amikbd_dev->name = "Amiga Keyboard"; + amikbd_dev->phys = "amikbd/input0"; + amikbd_dev->id.bustype = BUS_AMIGA; + amikbd_dev->id.vendor = 0x0001; + amikbd_dev->id.product = 0x0001; + amikbd_dev->id.version = 0x0100; + + amikbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + amikbd_dev->keycode = amikbd_keycode; + amikbd_dev->keycodesize = sizeof(unsigned char); + amikbd_dev->keycodemax = ARRAY_SIZE(amikbd_keycode); for (i = 0; i < 0x78; i++) if (amikbd_keycode[i]) - set_bit(amikbd_keycode[i], amikbd_dev.keybit); + set_bit(amikbd_keycode[i], amikbd_dev->keybit); ciaa.cra &= ~0x41; /* serial data in, turn off TA */ request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt); - amikbd_dev.name = amikbd_name; - amikbd_dev.phys = amikbd_phys; - amikbd_dev.id.bustype = BUS_AMIGA; - amikbd_dev.id.vendor = 0x0001; - amikbd_dev.id.product = 0x0001; - amikbd_dev.id.version = 0x0100; - - input_register_device(&amikbd_dev); - - printk(KERN_INFO "input: %s\n", amikbd_name); - + input_register_device(amikbd_dev); return 0; } static void __exit amikbd_exit(void) { - input_unregister_device(&amikbd_dev); free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); - release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); + input_unregister_device(amikbd_dev); + release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100); } module_init(amikbd_init); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 1ad8c2ee7dbf..820c7fd9a604 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -185,12 +185,12 @@ static struct { struct atkbd { - struct ps2dev ps2dev; + struct ps2dev ps2dev; + struct input_dev *dev; /* Written only during init */ char name[64]; char phys[32]; - struct input_dev dev; unsigned short id; unsigned char keycode[512]; @@ -290,7 +290,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (!atkbd->enabled) goto out; - input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + input_event(atkbd->dev, EV_MSC, MSC_RAW, code); if (atkbd->translated) { @@ -326,10 +326,10 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->release = 1; goto out; case ATKBD_RET_HANGUEL: - atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3); + atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3); goto out; case ATKBD_RET_HANJA: - atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3); + atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3); goto out; case ATKBD_RET_ERR: printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); @@ -345,7 +345,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, } if (atkbd->keycode[code] != ATKBD_KEY_NULL) - input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + input_event(atkbd->dev, EV_MSC, MSC_SCAN, code); switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: @@ -365,7 +365,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, "to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); } - input_sync(&atkbd->dev); + input_sync(atkbd->dev); break; case ATKBD_SCR_1: scroll = 1 - atkbd->release * 2; @@ -390,7 +390,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; default: value = atkbd->release ? 0 : - (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); + (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key))); switch (value) { /* Workaround Toshiba laptop multiple keypress */ case 0: @@ -398,7 +398,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; case 1: atkbd->last = code; - atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2; + atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2; break; case 2: if (!time_after(jiffies, atkbd->time) && atkbd->last == code) @@ -406,16 +406,16 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; } - atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); + atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value); } if (atkbd->scroll) { - input_regs(&atkbd->dev, regs); + input_regs(atkbd->dev, regs); if (click != -1) - input_report_key(&atkbd->dev, BTN_MIDDLE, click); - input_report_rel(&atkbd->dev, REL_WHEEL, scroll); - input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll); - input_sync(&atkbd->dev); + input_report_key(atkbd->dev, BTN_MIDDLE, click); + input_report_rel(atkbd->dev, REL_WHEEL, scroll); + input_report_rel(atkbd->dev, REL_HWHEEL, hscroll); + input_sync(atkbd->dev); } atkbd->release = 0; @@ -463,7 +463,6 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co return 0; - case EV_REP: if (atkbd->softrepeat) return 0; @@ -693,7 +692,7 @@ static void atkbd_disconnect(struct serio *serio) device_remove_file(&serio->dev, &atkbd_attr_softrepeat); device_remove_file(&serio->dev, &atkbd_attr_softraw); - input_unregister_device(&atkbd->dev); + input_unregister_device(atkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(atkbd); @@ -701,7 +700,7 @@ static void atkbd_disconnect(struct serio *serio) /* - * atkbd_set_device_attrs() initializes keyboard's keycode table + * atkbd_set_keycode_table() initializes keyboard's keycode table * according to the selected scancode set */ @@ -737,53 +736,58 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) static void atkbd_set_device_attrs(struct atkbd *atkbd) { + struct input_dev *input_dev = atkbd->dev; int i; - memset(&atkbd->dev, 0, sizeof(struct input_dev)); + if (atkbd->extra) + sprintf(atkbd->name, "AT Set 2 Extra keyboard"); + else + sprintf(atkbd->name, "AT %s Set %d keyboard", + atkbd->translated ? "Translated" : "Raw", atkbd->set); - init_input_dev(&atkbd->dev); + sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys); - atkbd->dev.name = atkbd->name; - atkbd->dev.phys = atkbd->phys; - atkbd->dev.id.bustype = BUS_I8042; - atkbd->dev.id.vendor = 0x0001; - atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set; - atkbd->dev.id.version = atkbd->id; - atkbd->dev.event = atkbd_event; - atkbd->dev.private = atkbd; - atkbd->dev.dev = &atkbd->ps2dev.serio->dev; + input_dev->name = atkbd->name; + input_dev->phys = atkbd->phys; + input_dev->id.bustype = BUS_I8042; + input_dev->id.vendor = 0x0001; + input_dev->id.product = atkbd->translated ? 1 : atkbd->set; + input_dev->id.version = atkbd->id; + input_dev->event = atkbd_event; + input_dev->private = atkbd; + input_dev->cdev.dev = &atkbd->ps2dev.serio->dev; - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); if (atkbd->write) { - atkbd->dev.evbit[0] |= BIT(EV_LED); - atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + input_dev->evbit[0] |= BIT(EV_LED); + input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); } if (atkbd->extra) - atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | + input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); if (!atkbd->softrepeat) { - atkbd->dev.rep[REP_DELAY] = 250; - atkbd->dev.rep[REP_PERIOD] = 33; + input_dev->rep[REP_DELAY] = 250; + input_dev->rep[REP_PERIOD] = 33; } - atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); + input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (atkbd->scroll) { - atkbd->dev.evbit[0] |= BIT(EV_REL); - atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); - set_bit(BTN_MIDDLE, atkbd->dev.keybit); + input_dev->evbit[0] |= BIT(EV_REL); + input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); + set_bit(BTN_MIDDLE, input_dev->keybit); } - atkbd->dev.keycode = atkbd->keycode; - atkbd->dev.keycodesize = sizeof(unsigned char); - atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode); + input_dev->keycode = atkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) - set_bit(atkbd->keycode[i], atkbd->dev.keybit); + set_bit(atkbd->keycode[i], input_dev->keybit); } /* @@ -796,13 +800,15 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) static int atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; - int err; + struct input_dev *dev; + int err = -ENOMEM; - if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) - return - ENOMEM; - - memset(atkbd, 0, sizeof(struct atkbd)); + atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); + dev = input_allocate_device(); + if (!atkbd || !dev) + goto fail; + atkbd->dev = dev; ps2_init(&atkbd->ps2dev, serio); switch (serio->id.type) { @@ -828,19 +834,15 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) serio_set_drvdata(serio, atkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(atkbd); - return err; - } + if (err) + goto fail; if (atkbd->write) { if (atkbd_probe(atkbd)) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(atkbd); - return -ENODEV; + err = -ENODEV; + goto fail; } atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); @@ -851,19 +853,9 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->id = 0xab00; } - if (atkbd->extra) - sprintf(atkbd->name, "AT Set 2 Extra keyboard"); - else - sprintf(atkbd->name, "AT %s Set %d keyboard", - atkbd->translated ? "Translated" : "Raw", atkbd->set); - - sprintf(atkbd->phys, "%s/input0", serio->phys); - atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); - device_create_file(&serio->dev, &atkbd_attr_extra); device_create_file(&serio->dev, &atkbd_attr_scroll); device_create_file(&serio->dev, &atkbd_attr_set); @@ -872,9 +864,14 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd_enable(atkbd); - printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); + input_register_device(atkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(dev); + kfree(atkbd); + return err; } /* @@ -896,9 +893,9 @@ static int atkbd_reconnect(struct serio *serio) atkbd_disable(atkbd); if (atkbd->write) { - param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) - | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) - | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); + param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0) + | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0) + | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0); if (atkbd_probe(atkbd)) return -1; @@ -1008,6 +1005,7 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1019,12 +1017,19 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return -EINVAL; if (atkbd->extra != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + /* + * Since device's properties will change we need to + * unregister old device. But allocate new one first + * to make sure we have it. + */ + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); atkbd_activate(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1036,6 +1041,7 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1044,12 +1050,14 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou return -EINVAL; if (atkbd->scroll != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->scroll = value; atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1061,6 +1069,7 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1072,13 +1081,15 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) return -EINVAL; if (atkbd->set != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); atkbd_activate(atkbd); atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1090,6 +1101,7 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1101,15 +1113,16 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t return -EINVAL; if (atkbd->softrepeat != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->softrepeat = value; if (atkbd->softrepeat) atkbd->softraw = 1; atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } - return count; } @@ -1121,6 +1134,7 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1129,11 +1143,13 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co return -EINVAL; if (atkbd->softraw != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->softraw = value; atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index cd4b6e795013..564bb365f6fc 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -70,8 +70,7 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = { struct corgikbd { unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)]; - struct input_dev input; - char phys[32]; + struct input_dev *input; spinlock_t lock; struct timer_list timer; @@ -147,7 +146,7 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs spin_lock_irqsave(&corgikbd_data->lock, flags); if (regs) - input_regs(&corgikbd_data->input, regs); + input_regs(corgikbd_data->input, regs); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { @@ -169,14 +168,14 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); - input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); + input_report_key(corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); if (pressed) num_pressed++; if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) { - input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); + input_event(corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); corgikbd_data->suspend_jiffies=jiffies; } } @@ -185,7 +184,7 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs corgikbd_activate_all(); - input_sync(&corgikbd_data->input); + input_sync(corgikbd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) @@ -249,9 +248,9 @@ static void corgikbd_hinge_timer(unsigned long data) if (hinge_count >= HINGE_STABLE_COUNT) { spin_lock_irqsave(&corgikbd_data->lock, flags); - input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); - input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); - input_sync(&corgikbd_data->input); + input_report_switch(corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); + input_report_switch(corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); + input_sync(corgikbd_data->input); spin_unlock_irqrestore(&corgikbd_data->lock, flags); } @@ -287,16 +286,21 @@ static int corgikbd_resume(struct device *dev, uint32_t level) static int __init corgikbd_probe(struct device *dev) { - int i; struct corgikbd *corgikbd; + struct input_dev *input_dev; + int i; corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL); - if (!corgikbd) + input_dev = input_allocate_device(); + if (!corgikbd || !input_dev) { + kfree(corgikbd); + input_free_device(input_dev); return -ENOMEM; + } - dev_set_drvdata(dev,corgikbd); - strcpy(corgikbd->phys, "corgikbd/input0"); + dev_set_drvdata(dev, corgikbd); + corgikbd->input = input_dev; spin_lock_init(&corgikbd->lock); /* Init Keyboard rescan timer */ @@ -311,28 +315,30 @@ static int __init corgikbd_probe(struct device *dev) corgikbd->suspend_jiffies=jiffies; - init_input_dev(&corgikbd->input); - corgikbd->input.private = corgikbd; - corgikbd->input.name = "Corgi Keyboard"; - corgikbd->input.dev = dev; - corgikbd->input.phys = corgikbd->phys; - corgikbd->input.id.bustype = BUS_HOST; - corgikbd->input.id.vendor = 0x0001; - corgikbd->input.id.product = 0x0001; - corgikbd->input.id.version = 0x0100; - corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); - corgikbd->input.keycode = corgikbd->keycode; - corgikbd->input.keycodesize = sizeof(unsigned char); - corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode); - memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode)); - for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) - set_bit(corgikbd->keycode[i], corgikbd->input.keybit); - clear_bit(0, corgikbd->input.keybit); - set_bit(SW_0, corgikbd->input.swbit); - set_bit(SW_1, corgikbd->input.swbit); - input_register_device(&corgikbd->input); + input_dev->name = "Corgi Keyboard"; + input_dev->phys = "corgikbd/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = dev; + input_dev->private = corgikbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + input_dev->keycode = corgikbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(corgikbd_keycode); + + for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) + set_bit(corgikbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + set_bit(SW_0, input_dev->swbit); + set_bit(SW_1, input_dev->swbit); + + input_register_device(corgikbd->input); + mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ @@ -349,8 +355,6 @@ static int __init corgikbd_probe(struct device *dev) for (i = 0; i < CORGI_KEY_STROBE_NUM; i++) pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); - printk(KERN_INFO "input: Corgi Keyboard Registered\n"); - return 0; } @@ -365,7 +369,7 @@ static int corgikbd_remove(struct device *dev) del_timer_sync(&corgikbd->htimer); del_timer_sync(&corgikbd->timer); - input_unregister_device(&corgikbd->input); + input_unregister_device(corgikbd->input); kfree(corgikbd); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 098963c7cdd6..7f06780a437f 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -102,7 +102,7 @@ static int ctrlclick_volume = 100; /* % */ module_param (ctrlclick_volume, int, 0); MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); -static int lk201_compose_is_alt = 0; +static int lk201_compose_is_alt; module_param (lk201_compose_is_alt, int, 0); MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " "will act as an Alt key"); @@ -274,7 +274,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { }; #define CHECK_LED(LED, BITS) do { \ - if (test_bit (LED, lk->dev.led)) \ + if (test_bit (LED, lk->dev->led)) \ leds_on |= BITS; \ else \ leds_off |= BITS; \ @@ -287,7 +287,7 @@ struct lkkbd { lk_keycode_t keycode[LK_NUM_KEYCODES]; int ignore_bytes; unsigned char id[LK_NUM_IGNORE_BYTES]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; struct work_struct tq; char name[64]; @@ -423,8 +423,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, DBG (KERN_INFO "Got byte 0x%02x\n", data); if (lk->ignore_bytes > 0) { - DBG (KERN_INFO "Ignoring a byte on %s\n", - lk->name); + DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; if (lk->ignore_bytes == 0) @@ -435,14 +434,14 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, switch (data) { case LK_ALL_KEYS_UP: - input_regs (&lk->dev, regs); + input_regs (lk->dev, regs); for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) if (lk->keycode[i] != KEY_RESERVED) - input_report_key (&lk->dev, lk->keycode[i], 0); - input_sync (&lk->dev); + input_report_key (lk->dev, lk->keycode[i], 0); + input_sync (lk->dev); break; case LK_METRONOME: - DBG (KERN_INFO "Got LK_METRONOME and don't " + DBG (KERN_INFO "Got %#d and don't " "know how to handle...\n"); break; case LK_OUTPUT_ERROR: @@ -482,12 +481,12 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, default: if (lk->keycode[data] != KEY_RESERVED) { - input_regs (&lk->dev, regs); - if (!test_bit (lk->keycode[data], lk->dev.key)) - input_report_key (&lk->dev, lk->keycode[data], 1); + input_regs (lk->dev, regs); + if (!test_bit (lk->keycode[data], lk->dev->key)) + input_report_key (lk->dev, lk->keycode[data], 1); else - input_report_key (&lk->dev, lk->keycode[data], 0); - input_sync (&lk->dev); + input_report_key (lk->dev, lk->keycode[data], 0); + input_sync (lk->dev); } else printk (KERN_WARNING "%s: Unknown key with " "scancode 0x%02x on %s.\n", @@ -605,7 +604,7 @@ lkkbd_reinit (void *data) lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ - if (test_bit (SND_CLICK, lk->dev.snd)) { + if (test_bit (SND_CLICK, lk->dev->snd)) { lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); @@ -616,7 +615,7 @@ lkkbd_reinit (void *data) } /* Sound the bell if needed */ - if (test_bit (SND_BELL, lk->dev.snd)) + if (test_bit (SND_BELL, lk->dev->snd)) lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); } @@ -627,71 +626,70 @@ static int lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; + struct input_dev *input_dev; int i; int err; - if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) - return -ENOMEM; - - memset (lk, 0, sizeof (struct lkkbd)); - - init_input_dev (&lk->dev); - set_bit (EV_KEY, lk->dev.evbit); - set_bit (EV_LED, lk->dev.evbit); - set_bit (EV_SND, lk->dev.evbit); - set_bit (EV_REP, lk->dev.evbit); - set_bit (LED_CAPSL, lk->dev.ledbit); - set_bit (LED_SLEEP, lk->dev.ledbit); - set_bit (LED_COMPOSE, lk->dev.ledbit); - set_bit (LED_SCROLLL, lk->dev.ledbit); - set_bit (SND_BELL, lk->dev.sndbit); - set_bit (SND_CLICK, lk->dev.sndbit); + lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); + input_dev = input_allocate_device (); + if (!lk || !input_dev) { + err = -ENOMEM; + goto fail; + } lk->serio = serio; - + lk->dev = input_dev; INIT_WORK (&lk->tq, lkkbd_reinit, lk); - lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; + memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); - lk->dev.keycode = lk->keycode; - lk->dev.keycodesize = sizeof (lk_keycode_t); - lk->dev.keycodemax = LK_NUM_KEYCODES; + strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name)); + snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); - lk->dev.event = lkkbd_event; - lk->dev.private = lk; + input_dev->name = lk->name; + input_dev->phys = lk->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_LKKBD; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->event = lkkbd_event; + input_dev->private = lk; + + set_bit (EV_KEY, input_dev->evbit); + set_bit (EV_LED, input_dev->evbit); + set_bit (EV_SND, input_dev->evbit); + set_bit (EV_REP, input_dev->evbit); + set_bit (LED_CAPSL, input_dev->ledbit); + set_bit (LED_SLEEP, input_dev->ledbit); + set_bit (LED_COMPOSE, input_dev->ledbit); + set_bit (LED_SCROLLL, input_dev->ledbit); + set_bit (SND_BELL, input_dev->sndbit); + set_bit (SND_CLICK, input_dev->sndbit); + + input_dev->keycode = lk->keycode; + input_dev->keycodesize = sizeof (lk_keycode_t); + input_dev->keycodemax = LK_NUM_KEYCODES; + for (i = 0; i < LK_NUM_KEYCODES; i++) + set_bit (lk->keycode[i], input_dev->keybit); serio_set_drvdata (serio, lk); err = serio_open (serio, drv); - if (err) { - serio_set_drvdata (serio, NULL); - kfree (lk); - return err; - } + if (err) + goto fail; - sprintf (lk->name, "DEC LK keyboard"); - sprintf (lk->phys, "%s/input0", serio->phys); - - memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); - for (i = 0; i < LK_NUM_KEYCODES; i++) - set_bit (lk->keycode[i], lk->dev.keybit); - - lk->dev.name = lk->name; - lk->dev.phys = lk->phys; - lk->dev.id.bustype = BUS_RS232; - lk->dev.id.vendor = SERIO_LKKBD; - lk->dev.id.product = 0; - lk->dev.id.version = 0x0100; - lk->dev.dev = &serio->dev; - - input_register_device (&lk->dev); - - printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); + input_register_device (lk->dev); lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; + + fail: serio_set_drvdata (serio, NULL); + input_free_device (input_dev); + kfree (lk); + return err; } /* @@ -702,9 +700,11 @@ lkkbd_disconnect (struct serio *serio) { struct lkkbd *lk = serio_get_drvdata (serio); - input_unregister_device (&lk->dev); + input_get_device (lk->dev); + input_unregister_device (lk->dev); serio_close (serio); serio_set_drvdata (serio, NULL); + input_put_device (lk->dev); kfree (lk); } diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index eecbde294f1f..cc6aaf9e85be 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -37,7 +37,7 @@ static unsigned char dc_kbd_keycode[256] = { struct dc_kbd { - struct input_dev dev; + struct input_dev *dev; unsigned char new[8]; unsigned char old[8]; }; @@ -46,30 +46,24 @@ struct dc_kbd { static void dc_scan_kbd(struct dc_kbd *kbd) { int i; - struct input_dev *dev = &kbd->dev; + struct input_dev *dev = kbd->dev; - for(i=0; i<8; i++) - input_report_key(dev, - dc_kbd_keycode[i+224], - (kbd->new[0]>>i)&1); + for (i = 0; i < 8; i++) + input_report_key(dev, dc_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); - for(i=2; i<8; i++) { + for (i = 2; i < 8; i++) { - if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { - if(dc_kbd_keycode[kbd->old[i]]) - input_report_key(dev, - dc_kbd_keycode[kbd->old[i]], - 0); + if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == NULL) { + if (dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, dc_kbd_keycode[kbd->old[i]], 0); else printk("Unknown key (scancode %#x) released.", kbd->old[i]); } - if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { + if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) != NULL) { if(dc_kbd_keycode[kbd->new[i]]) - input_report_key(dev, - dc_kbd_keycode[kbd->new[i]], - 1); + input_report_key(dev, dc_kbd_keycode[kbd->new[i]], 1); else printk("Unknown key (scancode %#x) pressed.", kbd->new[i]); @@ -89,43 +83,39 @@ static void dc_kbd_callback(struct mapleq *mq) unsigned long *buf = mq->recvbuf; if (buf[1] == mapledev->function) { - memcpy(kbd->new, buf+2, 8); + memcpy(kbd->new, buf + 2, 8); dc_scan_kbd(kbd); } } static int dc_kbd_connect(struct maple_device *dev) { - int i; - unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct dc_kbd *kbd; + struct input_dev *input_dev; + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + int i; - if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) - return -1; - memset(kbd, 0, sizeof(struct dc_kbd)); + dev->private_data = kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbd || !input_dev) { + kfree(kbd); + input_free_device(input_dev); + return -ENOMEM; + } - dev->private_data = kbd; + kbd->dev = input_dev; - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->name = dev->product_name; + input_dev->id.bustype = BUS_MAPLE; + input_dev->private = kbd; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + for (i = 0; i < 255; i++) + set_bit(dc_kbd_keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); - init_input_dev(&kbd->dev); - - for (i=0; i<255; i++) - set_bit(dc_kbd_keycode[i], kbd->dev.keybit); - - clear_bit(0, kbd->dev.keybit); - - kbd->dev.private = kbd; - - kbd->dev.name = dev->product_name; - kbd->dev.id.bustype = BUS_MAPLE; - - input_register_device(&kbd->dev); + input_register_device(kbd->dev); maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); - - printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name); - return 0; } @@ -134,7 +124,7 @@ static void dc_kbd_disconnect(struct maple_device *dev) { struct dc_kbd *kbd = dev->private_data; - input_unregister_device(&kbd->dev); + input_unregister_device(kbd->dev); kfree(kbd); } diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 2e8ce1613eec..d10983c521e6 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -57,11 +57,9 @@ static unsigned char nkbd_keycode[128] = { KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 }; -static char *nkbd_name = "Newton Keyboard"; - struct nkbd { unsigned char keycode[128]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; char phys[32]; }; @@ -73,13 +71,13 @@ static irqreturn_t nkbd_interrupt(struct serio *serio, /* invalid scan codes are probably the init sequence, so we ignore them */ if (nkbd->keycode[data & NKBD_KEY]) { - input_regs(&nkbd->dev, regs); - input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); - input_sync(&nkbd->dev); + input_regs(nkbd->dev, regs); + input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); + input_sync(nkbd->dev); } else if (data == 0xe7) /* end of init sequence */ - printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); + printk(KERN_INFO "input: %s on %s\n", nkbd->dev->name, serio->phys); return IRQ_HANDLED; } @@ -87,62 +85,59 @@ static irqreturn_t nkbd_interrupt(struct serio *serio, static int nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL))) - return -ENOMEM; - - memset(nkbd, 0, sizeof(struct nkbd)); - - nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!nkbd || !input_dev) + goto fail; nkbd->serio = serio; + nkbd->dev = input_dev; + sprintf(nkbd->phys, "%s/input0", serio->phys); + memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); - init_input_dev(&nkbd->dev); - nkbd->dev.keycode = nkbd->keycode; - nkbd->dev.keycodesize = sizeof(unsigned char); - nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode); - nkbd->dev.private = nkbd; + input_dev->name = "Newton Keyboard"; + input_dev->phys = nkbd->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_NEWTON; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = nkbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->keycode = nkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode); + for (i = 0; i < 128; i++) + set_bit(nkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); serio_set_drvdata(serio, nkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(nkbd); - return err; - } - - memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); - for (i = 0; i < 128; i++) - set_bit(nkbd->keycode[i], nkbd->dev.keybit); - clear_bit(0, nkbd->dev.keybit); - - sprintf(nkbd->phys, "%s/input0", serio->phys); - - nkbd->dev.name = nkbd_name; - nkbd->dev.phys = nkbd->phys; - nkbd->dev.id.bustype = BUS_RS232; - nkbd->dev.id.vendor = SERIO_NEWTON; - nkbd->dev.id.product = 0x0001; - nkbd->dev.id.version = 0x0100; - nkbd->dev.dev = &serio->dev; - - input_register_device(&nkbd->dev); - - printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); + if (err) + goto fail; + input_register_device(nkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(nkbd); + return err; } static void nkbd_disconnect(struct serio *serio) { struct nkbd *nkbd = serio_get_drvdata(serio); - input_unregister_device(&nkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(nkbd->dev); kfree(nkbd); } diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 344f46005401..732fb310e487 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -85,7 +85,7 @@ static int spitz_senses[] = { struct spitzkbd { unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)]; - struct input_dev input; + struct input_dev *input; char phys[32]; spinlock_t lock; @@ -187,8 +187,7 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs spin_lock_irqsave(&spitzkbd_data->lock, flags); - if (regs) - input_regs(&spitzkbd_data->input, regs); + input_regs(spitzkbd_data->input, regs); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { @@ -210,7 +209,7 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); - input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); + input_report_key(spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); if (pressed) num_pressed++; @@ -220,15 +219,15 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs spitzkbd_activate_all(); - input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); - input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey); + input_report_key(spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); + input_report_key(spitzkbd_data->input, KEY_SUSPEND, pwrkey); if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) { - input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); + input_event(spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); spitzkbd_data->suspend_jiffies = jiffies; } - input_sync(&spitzkbd_data->input); + input_sync(spitzkbd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) @@ -259,6 +258,7 @@ static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *reg static void spitzkbd_timer_callback(unsigned long data) { struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + spitzkbd_scankeyboard(spitzkbd_data, NULL); } @@ -298,9 +298,9 @@ static void spitzkbd_hinge_timer(unsigned long data) if (hinge_count >= HINGE_STABLE_COUNT) { spin_lock_irqsave(&spitzkbd_data->lock, flags); - input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); - input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); - input_sync(&spitzkbd_data->input); + input_report_switch(spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); + input_report_switch(spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); + input_sync(spitzkbd_data->input); spin_unlock_irqrestore(&spitzkbd_data->lock, flags); } else { @@ -346,14 +346,21 @@ static int spitzkbd_resume(struct device *dev, uint32_t level) static int __init spitzkbd_probe(struct device *dev) { - int i; struct spitzkbd *spitzkbd; + struct input_dev *input_dev; + int i; spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL); if (!spitzkbd) return -ENOMEM; - dev_set_drvdata(dev,spitzkbd); + input_dev = input_allocate_device(); + if (!input_dev) { + kfree(spitzkbd); + return -ENOMEM; + } + + dev_set_drvdata(dev, spitzkbd); strcpy(spitzkbd->phys, "spitzkbd/input0"); spin_lock_init(&spitzkbd->lock); @@ -368,30 +375,34 @@ static int __init spitzkbd_probe(struct device *dev) spitzkbd->htimer.function = spitzkbd_hinge_timer; spitzkbd->htimer.data = (unsigned long) spitzkbd; - spitzkbd->suspend_jiffies=jiffies; + spitzkbd->suspend_jiffies = jiffies; - init_input_dev(&spitzkbd->input); - spitzkbd->input.private = spitzkbd; - spitzkbd->input.name = "Spitz Keyboard"; - spitzkbd->input.dev = dev; - spitzkbd->input.phys = spitzkbd->phys; - spitzkbd->input.id.bustype = BUS_HOST; - spitzkbd->input.id.vendor = 0x0001; - spitzkbd->input.id.product = 0x0001; - spitzkbd->input.id.version = 0x0100; - spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); - spitzkbd->input.keycode = spitzkbd->keycode; - spitzkbd->input.keycodesize = sizeof(unsigned char); - spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode); + spitzkbd->input = input_dev; + + input_dev->private = spitzkbd; + input_dev->name = "Spitz Keyboard"; + input_dev->phys = spitzkbd->phys; + input_dev->cdev.dev = dev; + + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + input_dev->keycode = spitzkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode); memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) - set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit); - clear_bit(0, spitzkbd->input.keybit); - set_bit(SW_0, spitzkbd->input.swbit); - set_bit(SW_1, spitzkbd->input.swbit); + set_bit(spitzkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + set_bit(SW_0, input_dev->swbit); + set_bit(SW_1, input_dev->swbit); + + input_register_device(input_dev); - input_register_device(&spitzkbd->input); mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ @@ -444,7 +455,7 @@ static int spitzkbd_remove(struct device *dev) del_timer_sync(&spitzkbd->htimer); del_timer_sync(&spitzkbd->timer); - input_unregister_device(&spitzkbd->input); + input_unregister_device(spitzkbd->input); kfree(spitzkbd); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 4bae5d89348d..b15b6d8d4f83 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -76,13 +76,14 @@ static unsigned char sunkbd_keycode[128] = { struct sunkbd { unsigned char keycode[128]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; struct work_struct tq; wait_queue_head_t wait; char name[64]; char phys[32]; char type; + unsigned char enabled; volatile s8 reset; volatile s8 layout; }; @@ -124,10 +125,13 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, break; default: + if (!sunkbd->enabled) + break; + if (sunkbd->keycode[data & SUNKBD_KEY]) { - input_regs(&sunkbd->dev, regs); - input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); - input_sync(&sunkbd->dev); + input_regs(sunkbd->dev, regs); + input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); + input_sync(sunkbd->dev); } else { printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); @@ -184,7 +188,7 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) sunkbd->reset = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - if (sunkbd->reset <0) + if (sunkbd->reset < 0) return -1; sunkbd->type = sunkbd->reset; @@ -213,10 +217,17 @@ static void sunkbd_reinit(void *data) sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | - (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); +} + +static void sunkbd_enable(struct sunkbd *sunkbd, int enable) +{ + serio_pause_rx(sunkbd->serio); + sunkbd->enabled = 1; + serio_continue_rx(sunkbd->serio); } /* @@ -226,70 +237,64 @@ static void sunkbd_reinit(void *data) static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) - return -ENOMEM; - - memset(sunkbd, 0, sizeof(struct sunkbd)); - - init_input_dev(&sunkbd->dev); - init_waitqueue_head(&sunkbd->wait); - - sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); - sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); - sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sunkbd || !input_dev) + goto fail; sunkbd->serio = serio; - + sunkbd->dev = input_dev; + init_waitqueue_head(&sunkbd->wait); INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); - - sunkbd->dev.keycode = sunkbd->keycode; - sunkbd->dev.keycodesize = sizeof(unsigned char); - sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode); - - sunkbd->dev.event = sunkbd_event; - sunkbd->dev.private = sunkbd; + snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys); serio_set_drvdata(serio, sunkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return err; - } + if (err) + goto fail; if (sunkbd_initialize(sunkbd) < 0) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return -ENODEV; + goto fail; } sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); - memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); + + input_dev->name = sunkbd->name; + input_dev->phys = sunkbd->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SUNKBD; + input_dev->id.product = sunkbd->type; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = sunkbd; + input_dev->event = sunkbd_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); + input_dev->sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + + input_dev->keycode = sunkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode); for (i = 0; i < 128; i++) - set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); - clear_bit(0, sunkbd->dev.keybit); - - sprintf(sunkbd->phys, "%s/input0", serio->phys); - - sunkbd->dev.name = sunkbd->name; - sunkbd->dev.phys = sunkbd->phys; - sunkbd->dev.id.bustype = BUS_RS232; - sunkbd->dev.id.vendor = SERIO_SUNKBD; - sunkbd->dev.id.product = sunkbd->type; - sunkbd->dev.id.version = 0x0100; - sunkbd->dev.dev = &serio->dev; - - input_register_device(&sunkbd->dev); - - printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); + set_bit(sunkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + sunkbd_enable(sunkbd, 1); + input_register_device(sunkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(sunkbd); + return err; } /* @@ -299,7 +304,9 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio_get_drvdata(serio); - input_unregister_device(&sunkbd->dev); + + sunkbd_enable(sunkbd, 0); + input_unregister_device(sunkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(sunkbd); diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 19eaec7789d1..4135e3e16c51 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -56,11 +56,9 @@ static unsigned char xtkbd_keycode[256] = { 106 }; -static char *xtkbd_name = "XT Keyboard"; - struct xtkbd { unsigned char keycode[256]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; char phys[32]; }; @@ -77,9 +75,9 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio, default: if (xtkbd->keycode[data & XTKBD_KEY]) { - input_regs(&xtkbd->dev, regs); - input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); - input_sync(&xtkbd->dev); + input_regs(xtkbd->dev, regs); + input_report_key(xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); + input_sync(xtkbd->dev); } else { printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); @@ -91,62 +89,60 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio, static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) - return -ENOMEM; - - memset(xtkbd, 0, sizeof(struct xtkbd)); - - xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!xtkbd || !input_dev) + goto fail; xtkbd->serio = serio; + xtkbd->dev = input_dev; + sprintf(xtkbd->phys, "%s/input0", serio->phys); + memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); - init_input_dev(&xtkbd->dev); - xtkbd->dev.keycode = xtkbd->keycode; - xtkbd->dev.keycodesize = sizeof(unsigned char); - xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode); - xtkbd->dev.private = xtkbd; + input_dev->name = "XT Keyboard"; + input_dev->phys = xtkbd->phys; + input_dev->id.bustype = BUS_XTKBD; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = xtkbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->keycode = xtkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(xtkbd_keycode); + + for (i = 0; i < 255; i++) + set_bit(xtkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); serio_set_drvdata(serio, xtkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(xtkbd); - return err; - } - - memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); - for (i = 0; i < 255; i++) - set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); - clear_bit(0, xtkbd->dev.keybit); - - sprintf(xtkbd->phys, "%s/input0", serio->phys); - - xtkbd->dev.name = xtkbd_name; - xtkbd->dev.phys = xtkbd->phys; - xtkbd->dev.id.bustype = BUS_XTKBD; - xtkbd->dev.id.vendor = 0x0001; - xtkbd->dev.id.product = 0x0001; - xtkbd->dev.id.version = 0x0100; - xtkbd->dev.dev = &serio->dev; - - input_register_device(&xtkbd->dev); - - printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); + if (err) + goto fail; + input_register_device(xtkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(xtkbd); + return err; } static void xtkbd_disconnect(struct serio *serio) { struct xtkbd *xtkbd = serio_get_drvdata(serio); - input_unregister_device(&xtkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(xtkbd->dev); kfree(xtkbd); } From c5b7c7c395a34f12cdf246d66c1feeff2933d584 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:47 -0500 Subject: [PATCH 0932/1939] [PATCH] drivers/usb/input: convert to dynamic input_dev allocation Input: convert drivers/iusb/input to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/acecad.c | 76 +++++----- drivers/usb/input/aiptek.c | 209 +++++++++++++--------------- drivers/usb/input/appletouch.c | 130 +++++++++--------- drivers/usb/input/ati_remote.c | 175 +++++++++++------------ drivers/usb/input/hid-core.c | 49 +++---- drivers/usb/input/hid-input.c | 58 ++++---- drivers/usb/input/hid-lgff.c | 17 +-- drivers/usb/input/hid-tmff.c | 11 +- drivers/usb/input/hid.h | 2 +- drivers/usb/input/itmtouch.c | 70 ++++++---- drivers/usb/input/kbtab.c | 88 ++++++------ drivers/usb/input/keyspan_remote.c | 214 ++++++++++++----------------- drivers/usb/input/mtouchusb.c | 111 ++++++++------- drivers/usb/input/pid.c | 12 +- drivers/usb/input/powermate.c | 136 +++++++++--------- drivers/usb/input/touchkitusb.c | 116 ++++++++-------- drivers/usb/input/usbkbd.c | 105 +++++++------- drivers/usb/input/usbmouse.c | 97 +++++++------ drivers/usb/input/wacom.c | 142 +++++++++---------- drivers/usb/input/xpad.c | 133 +++++++++--------- drivers/usb/input/yealink.c | 66 ++++----- 21 files changed, 988 insertions(+), 1029 deletions(-) diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index 74f8760d7c07..a32558b4048e 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -53,7 +53,7 @@ struct usb_acecad { char name[128]; char phys[64]; struct usb_device *usbdev; - struct input_dev dev; + struct input_dev *input; struct urb *irq; signed char *data; @@ -64,7 +64,7 @@ static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) { struct usb_acecad *acecad = urb->context; unsigned char *data = acecad->data; - struct input_dev *dev = &acecad->dev; + struct input_dev *dev = acecad->input; int prox, status; switch (urb->status) { @@ -135,8 +135,8 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct usb_acecad *acecad; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; if (interface->desc.bNumEndpoints != 1) return -ENODEV; @@ -153,8 +153,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL); - if (!acecad) - return -ENOMEM; + input_dev = input_allocate_device(); + if (!acecad || !input_dev) + goto fail1; acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); if (!acecad->data) @@ -164,6 +165,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ if (!acecad->irq) goto fail2; + acecad->usbdev = dev; + acecad->input = input_dev; + if (dev->manufacturer) strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name)); @@ -173,48 +177,48 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ strlcat(acecad->name, dev->product, sizeof(acecad->name)); } - usb_make_path(dev, path, sizeof(path)); - snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path); + usb_make_path(dev, acecad->phys, sizeof(acecad->phys)); + strlcat(acecad->phys, "/input0", sizeof(acecad->phys)); - acecad->usbdev = dev; + input_dev->name = acecad->name; + input_dev->phys = acecad->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = acecad; - acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); + input_dev->open = usb_acecad_open; + input_dev->close = usb_acecad_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); switch (id->driver_info) { case 0: - acecad->dev.absmax[ABS_X] = 5000; - acecad->dev.absmax[ABS_Y] = 3750; - acecad->dev.absmax[ABS_PRESSURE] = 512; + input_dev->absmax[ABS_X] = 5000; + input_dev->absmax[ABS_Y] = 3750; + input_dev->absmax[ABS_PRESSURE] = 512; if (!strlen(acecad->name)) snprintf(acecad->name, sizeof(acecad->name), "USB Acecad Flair Tablet %04x:%04x", - dev->descriptor.idVendor, dev->descriptor.idProduct); + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); break; case 1: - acecad->dev.absmax[ABS_X] = 3000; - acecad->dev.absmax[ABS_Y] = 2250; - acecad->dev.absmax[ABS_PRESSURE] = 1024; + input_dev->absmax[ABS_X] = 3000; + input_dev->absmax[ABS_Y] = 2250; + input_dev->absmax[ABS_PRESSURE] = 1024; if (!strlen(acecad->name)) snprintf(acecad->name, sizeof(acecad->name), "USB Acecad 302 Tablet %04x:%04x", - dev->descriptor.idVendor, dev->descriptor.idProduct); + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); break; } - acecad->dev.absfuzz[ABS_X] = 4; - acecad->dev.absfuzz[ABS_Y] = 4; - - acecad->dev.private = acecad; - acecad->dev.open = usb_acecad_open; - acecad->dev.close = usb_acecad_close; - - acecad->dev.name = acecad->name; - acecad->dev.phys = acecad->phys; - usb_to_input_id(dev, &acecad->dev.id); - acecad->dev.dev = &intf->dev; + input_dev->absfuzz[ABS_X] = 4; + input_dev->absfuzz[ABS_Y] = 4; usb_fill_int_urb(acecad->irq, dev, pipe, acecad->data, maxp > 8 ? 8 : maxp, @@ -222,17 +226,15 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ acecad->irq->transfer_dma = acecad->data_dma; acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&acecad->dev); - - printk(KERN_INFO "input: %s with packet size %d on %s\n", - acecad->name, maxp, path); + input_register_device(acecad->input); usb_set_intfdata(intf, acecad); return 0; fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma); - fail1: kfree(acecad); + fail1: input_free_device(input_dev); + kfree(acecad); return -ENOMEM; } @@ -243,7 +245,7 @@ static void usb_acecad_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (acecad) { usb_kill_urb(acecad->irq); - input_unregister_device(&acecad->dev); + input_unregister_device(acecad->input); usb_free_urb(acecad->irq); usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); kfree(acecad); diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index cd0cbfe20723..1c5205321d83 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -317,7 +317,7 @@ struct aiptek_settings { }; struct aiptek { - struct input_dev inputdev; /* input device struct */ + struct input_dev *inputdev; /* input device struct */ struct usb_device *usbdev; /* usb device struct */ struct urb *urb; /* urb for incoming reports */ dma_addr_t data_dma; /* our dma stuffage */ @@ -402,7 +402,7 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) { struct aiptek *aiptek = urb->context; unsigned char *data = aiptek->data; - struct input_dev *inputdev = &aiptek->inputdev; + struct input_dev *inputdev = aiptek->inputdev; int jitterable = 0; int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck; @@ -955,20 +955,20 @@ static int aiptek_program_tablet(struct aiptek *aiptek) /* Query getXextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0) return ret; - aiptek->inputdev.absmin[ABS_X] = 0; - aiptek->inputdev.absmax[ABS_X] = ret - 1; + aiptek->inputdev->absmin[ABS_X] = 0; + aiptek->inputdev->absmax[ABS_X] = ret - 1; /* Query getYextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0) return ret; - aiptek->inputdev.absmin[ABS_Y] = 0; - aiptek->inputdev.absmax[ABS_Y] = ret - 1; + aiptek->inputdev->absmin[ABS_Y] = 0; + aiptek->inputdev->absmax[ABS_Y] = ret - 1; /* Query getPressureLevels */ if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0) return ret; - aiptek->inputdev.absmin[ABS_PRESSURE] = 0; - aiptek->inputdev.absmax[ABS_PRESSURE] = ret - 1; + aiptek->inputdev->absmin[ABS_PRESSURE] = 0; + aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1; /* Depending on whether we are in absolute or relative mode, we will * do a switchToTablet(absolute) or switchToMouse(relative) command. @@ -1025,8 +1025,8 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr return 0; return snprintf(buf, PAGE_SIZE, "%dx%d\n", - aiptek->inputdev.absmax[ABS_X] + 1, - aiptek->inputdev.absmax[ABS_Y] + 1); + aiptek->inputdev->absmax[ABS_X] + 1, + aiptek->inputdev->absmax[ABS_Y] + 1); } /* These structs define the sysfs files, param #1 is the name of the @@ -1048,7 +1048,7 @@ static ssize_t show_tabletProductId(struct device *dev, struct device_attribute return 0; return snprintf(buf, PAGE_SIZE, "0x%04x\n", - aiptek->inputdev.id.product); + aiptek->inputdev->id.product); } static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); @@ -1063,7 +1063,7 @@ static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute * if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev.id.vendor); + return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); } static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); @@ -1977,7 +1977,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) struct input_dev *inputdev; struct input_handle *inputhandle; struct list_head *node, *next; - char path[64 + 1]; int i; int speeds[] = { 0, AIPTEK_PROGRAMMABLE_DELAY_50, @@ -1996,24 +1995,26 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) */ speeds[0] = programmableDelay; - if ((aiptek = kmalloc(sizeof(struct aiptek), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(aiptek, 0, sizeof(struct aiptek)); + aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); + inputdev = input_allocate_device(); + if (!aiptek || !inputdev) + goto fail1; aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, SLAB_ATOMIC, &aiptek->data_dma); - if (aiptek->data == NULL) { - kfree(aiptek); - return -ENOMEM; - } + if (!aiptek->data) + goto fail1; aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); - if (aiptek->urb == NULL) { - usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, - aiptek->data_dma); - kfree(aiptek); - return -ENOMEM; - } + if (!aiptek->urb) + goto fail2; + + aiptek->inputdev = inputdev; + aiptek->usbdev = usbdev; + aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; + aiptek->inDelay = 0; + aiptek->endDelay = 0; + aiptek->previousJitterable = 0; /* Set up the curSettings struct. Said struct contains the current * programmable parameters. The newSetting struct contains changes @@ -2036,31 +2037,48 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Both structs should have equivalent settings */ - memcpy(&aiptek->newSetting, &aiptek->curSetting, - sizeof(struct aiptek_settings)); + aiptek->newSetting = aiptek->curSetting; + + /* Determine the usb devices' physical path. + * Asketh not why we always pretend we're using "../input0", + * but I suspect this will have to be refactored one + * day if a single USB device can be a keyboard & a mouse + * & a tablet, and the inputX number actually will tell + * us something... + */ + usb_make_path(usbdev, aiptek->features.usbPath, + sizeof(aiptek->features.usbPath)); + strlcat(aiptek->features.usbPath, "/input0", + sizeof(aiptek->features.usbPath)); + + /* Set up client data, pointers to open and close routines + * for the input device. + */ + inputdev->name = "Aiptek"; + inputdev->phys = aiptek->features.usbPath; + usb_to_input_id(usbdev, &inputdev->id); + inputdev->cdev.dev = &intf->dev; + inputdev->private = aiptek; + inputdev->open = aiptek_open; + inputdev->close = aiptek_close; /* Now program the capacities of the tablet, in terms of being * an input device. */ - aiptek->inputdev.evbit[0] |= BIT(EV_KEY) + inputdev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL) | BIT(EV_MSC); - aiptek->inputdev.absbit[0] |= - (BIT(ABS_X) | - BIT(ABS_Y) | - BIT(ABS_PRESSURE) | - BIT(ABS_TILT_X) | - BIT(ABS_TILT_Y) | BIT(ABS_WHEEL) | BIT(ABS_MISC)); + inputdev->absbit[0] |= BIT(ABS_MISC); - aiptek->inputdev.relbit[0] |= + inputdev->relbit[0] |= (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); - aiptek->inputdev.keybit[LONG(BTN_LEFT)] |= + inputdev->keybit[LONG(BTN_LEFT)] |= (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); - aiptek->inputdev.keybit[LONG(BTN_DIGI)] |= + inputdev->keybit[LONG(BTN_DIGI)] |= (BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_PENCIL) | @@ -2070,70 +2088,26 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) BIT(BTN_TOOL_LENS) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); - aiptek->inputdev.mscbit[0] = BIT(MSC_SERIAL); + inputdev->mscbit[0] = BIT(MSC_SERIAL); /* Programming the tablet macro keys needs to be done with a for loop * as the keycodes are discontiguous. */ for (i = 0; i < sizeof(macroKeyEvents) / sizeof(macroKeyEvents[0]); ++i) - set_bit(macroKeyEvents[i], aiptek->inputdev.keybit); + set_bit(macroKeyEvents[i], inputdev->keybit); - /* Set up client data, pointers to open and close routines - * for the input device. - */ - aiptek->inputdev.private = aiptek; - aiptek->inputdev.open = aiptek_open; - aiptek->inputdev.close = aiptek_close; - - /* Determine the usb devices' physical path. - * Asketh not why we always pretend we're using "../input0", - * but I suspect this will have to be refactored one - * day if a single USB device can be a keyboard & a mouse - * & a tablet, and the inputX number actually will tell - * us something... - */ - if (usb_make_path(usbdev, path, 64) > 0) - sprintf(aiptek->features.usbPath, "%s/input0", path); - - /* Program the input device coordinate capacities. We do not yet + /* + * Program the input device coordinate capacities. We do not yet * know what maximum X, Y, and Z values are, so we're putting fake * values in. Later, we'll ask the tablet to put in the correct * values. */ - aiptek->inputdev.absmin[ABS_X] = 0; - aiptek->inputdev.absmax[ABS_X] = 2999; - aiptek->inputdev.absmin[ABS_Y] = 0; - aiptek->inputdev.absmax[ABS_Y] = 2249; - aiptek->inputdev.absmin[ABS_PRESSURE] = 0; - aiptek->inputdev.absmax[ABS_PRESSURE] = 511; - aiptek->inputdev.absmin[ABS_TILT_X] = AIPTEK_TILT_MIN; - aiptek->inputdev.absmax[ABS_TILT_X] = AIPTEK_TILT_MAX; - aiptek->inputdev.absmin[ABS_TILT_Y] = AIPTEK_TILT_MIN; - aiptek->inputdev.absmax[ABS_TILT_Y] = AIPTEK_TILT_MAX; - aiptek->inputdev.absmin[ABS_WHEEL] = AIPTEK_WHEEL_MIN; - aiptek->inputdev.absmax[ABS_WHEEL] = AIPTEK_WHEEL_MAX - 1; - aiptek->inputdev.absfuzz[ABS_X] = 0; - aiptek->inputdev.absfuzz[ABS_Y] = 0; - aiptek->inputdev.absfuzz[ABS_PRESSURE] = 0; - aiptek->inputdev.absfuzz[ABS_TILT_X] = 0; - aiptek->inputdev.absfuzz[ABS_TILT_Y] = 0; - aiptek->inputdev.absfuzz[ABS_WHEEL] = 0; - aiptek->inputdev.absflat[ABS_X] = 0; - aiptek->inputdev.absflat[ABS_Y] = 0; - aiptek->inputdev.absflat[ABS_PRESSURE] = 0; - aiptek->inputdev.absflat[ABS_TILT_X] = 0; - aiptek->inputdev.absflat[ABS_TILT_Y] = 0; - aiptek->inputdev.absflat[ABS_WHEEL] = 0; - aiptek->inputdev.name = "Aiptek"; - aiptek->inputdev.phys = aiptek->features.usbPath; - usb_to_input_id(usbdev, &aiptek->inputdev.id); - aiptek->inputdev.dev = &intf->dev; - - aiptek->usbdev = usbdev; - aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; - aiptek->inDelay = 0; - aiptek->endDelay = 0; - aiptek->previousJitterable = 0; + input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0); + input_set_abs_params(inputdev, ABS_X, 0, 2249, 0, 0); + input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); + input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); endpoint = &intf->altsetting[0].endpoint[0].desc; @@ -2150,28 +2124,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) aiptek->urb->transfer_dma = aiptek->data_dma; aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - /* Register the tablet as an Input Device - */ - input_register_device(&aiptek->inputdev); - - /* We now will look for the evdev device which is mapped to - * the tablet. The partial name is kept in the link list of - * input_handles associated with this input device. - * What identifies an evdev input_handler is that it begins - * with 'event', continues with a digit, and that in turn - * is mapped to /{devfs}/input/eventN. - */ - inputdev = &aiptek->inputdev; - list_for_each_safe(node, next, &inputdev->h_list) { - inputhandle = to_handle(node); - if (strncmp(inputhandle->name, "event", 5) == 0) { - strcpy(aiptek->features.inputPath, inputhandle->name); - break; - } - } - - info("input: Aiptek on %s (%s)\n", path, aiptek->features.inputPath); - /* Program the tablet. This sets the tablet up in the mode * specified in newSetting, and also queries the tablet's * physical capacities. @@ -2186,13 +2138,32 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) for (i = 0; i < sizeof(speeds) / sizeof(speeds[0]); ++i) { aiptek->curSetting.programmableDelay = speeds[i]; (void)aiptek_program_tablet(aiptek); - if (aiptek->inputdev.absmax[ABS_X] > 0) { + if (aiptek->inputdev->absmax[ABS_X] > 0) { info("input: Aiptek using %d ms programming speed\n", aiptek->curSetting.programmableDelay); break; } } + /* Register the tablet as an Input Device + */ + input_register_device(aiptek->inputdev); + + /* We now will look for the evdev device which is mapped to + * the tablet. The partial name is kept in the link list of + * input_handles associated with this input device. + * What identifies an evdev input_handler is that it begins + * with 'event', continues with a digit, and that in turn + * is mapped to /{devfs}/input/eventN. + */ + list_for_each_safe(node, next, &inputdev->h_list) { + inputhandle = to_handle(node); + if (strncmp(inputhandle->name, "event", 5) == 0) { + strcpy(aiptek->features.inputPath, inputhandle->name); + break; + } + } + /* Associate this driver's struct with the usb interface. */ usb_set_intfdata(intf, aiptek); @@ -2207,6 +2178,12 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) info("aiptek: error loading 'evdev' module"); return 0; + +fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, + aiptek->data_dma); +fail1: input_free_device(inputdev); + kfree(aiptek); + return -ENOMEM; } /* Forward declaration */ @@ -2234,7 +2211,7 @@ static void aiptek_disconnect(struct usb_interface *intf) /* Free & unhook everything from the system. */ usb_kill_urb(aiptek->urb); - input_unregister_device(&aiptek->inputdev); + input_unregister_device(aiptek->inputdev); aiptek_delete_files(&intf->dev); usb_free_urb(aiptek->urb); usb_buffer_free(interface_to_usbdev(intf), diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index e03c1c567a14..15840db092a5 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -39,7 +39,7 @@ #define APPLE_VENDOR_ID 0x05AC #define ATP_DEVICE(prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ .idVendor = APPLE_VENDOR_ID, \ @@ -78,9 +78,9 @@ MODULE_DEVICE_TABLE (usb, atp_table); * We try to keep the touchpad aspect ratio while still doing only simple * arithmetics. * The factors below give coordinates like: - * 0 <= x < 960 on 12" and 15" Powerbooks - * 0 <= x < 1600 on 17" Powerbooks - * 0 <= y < 646 + * 0 <= x < 960 on 12" and 15" Powerbooks + * 0 <= x < 1600 on 17" Powerbooks + * 0 <= y < 646 */ #define ATP_XFACT 64 #define ATP_YFACT 43 @@ -93,11 +93,12 @@ MODULE_DEVICE_TABLE (usb, atp_table); /* Structure to hold all of our device specific stuff */ struct atp { + char phys[64]; struct usb_device * udev; /* usb device */ struct urb * urb; /* usb request block */ signed char * data; /* transferred data */ int open; /* non-zero if opened */ - struct input_dev input; /* input dev */ + struct input_dev *input; /* input dev */ int valid; /* are the sensors valid ? */ int x_old; /* last reported x/y, */ int y_old; /* used for smoothing */ @@ -114,11 +115,11 @@ struct atp { int i; \ printk("appletouch: %s %lld", msg, (long long)jiffies); \ for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ - printk(" %02x", tab[i]); \ - printk("\n"); \ + printk(" %02x", tab[i]); \ + printk("\n"); \ } -#define dprintk(format, a...) \ +#define dprintk(format, a...) \ do { \ if (debug) printk(format, ##a); \ } while (0) @@ -219,8 +220,8 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) for (i = 16; i < ATP_XSENSORS; i++) if (dev->xy_cur[i]) { printk("appletouch: 17\" model detected.\n"); - input_set_abs_params(&dev->input, ABS_X, 0, - (ATP_XSENSORS - 1) * + input_set_abs_params(dev->input, ABS_X, 0, + (ATP_XSENSORS - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); break; @@ -260,12 +261,12 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) "Xz: %3d Yz: %3d\n", x, y, x_z, y_z); - input_report_key(&dev->input, BTN_TOUCH, 1); - input_report_abs(&dev->input, ABS_X, x); - input_report_abs(&dev->input, ABS_Y, y); - input_report_abs(&dev->input, ABS_PRESSURE, + input_report_key(dev->input, BTN_TOUCH, 1); + input_report_abs(dev->input, ABS_X, x); + input_report_abs(dev->input, ABS_Y, y); + input_report_abs(dev->input, ABS_PRESSURE, min(ATP_PRESSURE, x_z + y_z)); - atp_report_fingers(&dev->input, max(x_f, y_f)); + atp_report_fingers(dev->input, max(x_f, y_f)); } dev->x_old = x; dev->y_old = y; @@ -273,17 +274,17 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) else if (!x && !y) { dev->x_old = dev->y_old = -1; - input_report_key(&dev->input, BTN_TOUCH, 0); - input_report_abs(&dev->input, ABS_PRESSURE, 0); - atp_report_fingers(&dev->input, 0); + input_report_key(dev->input, BTN_TOUCH, 0); + input_report_abs(dev->input, ABS_PRESSURE, 0); + atp_report_fingers(dev->input, 0); /* reset the accumulator on release */ memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); } - input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]); + input_report_key(dev->input, BTN_LEFT, !!dev->data[80]); - input_sync(&dev->input); + input_sync(dev->input); exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); @@ -314,21 +315,14 @@ static void atp_close(struct input_dev *input) static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) { - struct atp *dev = NULL; + struct atp *dev; + struct input_dev *input_dev; + struct usb_device *udev = interface_to_usbdev(iface); struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int int_in_endpointAddr = 0; int i, retval = -ENOMEM; - /* allocate memory for our device state and initialize it */ - dev = kmalloc(sizeof(struct atp), GFP_KERNEL); - if (dev == NULL) { - err("Out of memory"); - goto err_kmalloc; - } - memset(dev, 0, sizeof(struct atp)); - - dev->udev = interface_to_usbdev(iface); /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ @@ -345,70 +339,82 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id } } if (!int_in_endpointAddr) { - retval = -EIO; err("Could not find int-in endpoint"); - goto err_endpoint; + return -EIO; } - /* save our data pointer in this interface device */ - usb_set_intfdata(iface, dev); + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(struct atp), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!dev || !input_dev) { + err("Out of memory"); + goto err_free_devs; + } + + dev->udev = udev; + dev->input = input_dev; dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) { retval = -ENOMEM; - goto err_usballoc; + goto err_free_devs; } + dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->data) { retval = -ENOMEM; - goto err_usbbufalloc; + goto err_free_urb; } - usb_fill_int_urb(dev->urb, dev->udev, - usb_rcvintpipe(dev->udev, int_in_endpointAddr), + + usb_fill_int_urb(dev->urb, udev, + usb_rcvintpipe(udev, int_in_endpointAddr), dev->data, ATP_DATASIZE, atp_complete, dev, 1); - init_input_dev(&dev->input); - dev->input.name = "appletouch"; - dev->input.dev = &iface->dev; - dev->input.private = dev; - dev->input.open = atp_open; - dev->input.close = atp_close; + usb_make_path(udev, dev->phys, sizeof(dev->phys)); + strlcat(dev->phys, "/input0", sizeof(dev->phys)); - usb_to_input_id(dev->udev, &dev->input.id); + input_dev->name = "appletouch"; + input_dev->phys = dev->phys; + usb_to_input_id(dev->udev, &input_dev->id); + input_dev->cdev.dev = &iface->dev; - set_bit(EV_ABS, dev->input.evbit); + input_dev->private = dev; + input_dev->open = atp_open; + input_dev->close = atp_close; + + set_bit(EV_ABS, input_dev->evbit); /* * 12" and 15" Powerbooks only have 16 x sensors, * 17" models are detected later. */ - input_set_abs_params(&dev->input, ABS_X, 0, + input_set_abs_params(input_dev, ABS_X, 0, (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); - input_set_abs_params(&dev->input, ABS_Y, 0, + input_set_abs_params(input_dev, ABS_Y, 0, (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); - input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); - set_bit(EV_KEY, dev->input.evbit); - set_bit(BTN_TOUCH, dev->input.keybit); - set_bit(BTN_TOOL_FINGER, dev->input.keybit); - set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit); - set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit); - set_bit(BTN_LEFT, dev->input.keybit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(BTN_TOUCH, input_dev->keybit); + set_bit(BTN_TOOL_FINGER, input_dev->keybit); + set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); + set_bit(BTN_LEFT, input_dev->keybit); - input_register_device(&dev->input); + input_register_device(dev->input); - printk(KERN_INFO "input: appletouch connected\n"); + /* save our data pointer in this interface device */ + usb_set_intfdata(iface, dev); return 0; -err_usbbufalloc: + err_free_urb: usb_free_urb(dev->urb); -err_usballoc: + err_free_devs: usb_set_intfdata(iface, NULL); -err_endpoint: kfree(dev); -err_kmalloc: + input_free_device(input_dev); return retval; } @@ -419,7 +425,7 @@ static void atp_disconnect(struct usb_interface *iface) usb_set_intfdata(iface, NULL); if (dev) { usb_kill_urb(dev->urb); - input_unregister_device(&dev->input); + input_unregister_device(dev->input); usb_free_urb(dev->urb); usb_buffer_free(dev->udev, ATP_DATASIZE, dev->data, dev->urb->transfer_dma); diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index fd99681ee483..9a2a47db9494 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -112,7 +112,6 @@ #define NAME_BUFSIZE 80 /* size of product name, path buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */ -#define ATI_INPUTNUM 1 /* Which input device to register as */ static unsigned long channel_mask; module_param(channel_mask, ulong, 0444); @@ -162,7 +161,7 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; static DECLARE_MUTEX(disconnect_sem); struct ati_remote { - struct input_dev idev; + struct input_dev *idev; struct usb_device *udev; struct usb_interface *interface; @@ -198,15 +197,13 @@ struct ati_remote { #define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ /* Translation table from hardware messages to input events. */ -static struct -{ +static struct { short kind; unsigned char data1, data2; int type; unsigned int code; int value; -} ati_remote_tbl[] = -{ +} ati_remote_tbl[] = { /* Directional control pad axes */ {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ @@ -286,7 +283,6 @@ static struct /* Local function prototypes */ static void ati_remote_dump (unsigned char *data, unsigned int actual_length); -static void ati_remote_delete (struct ati_remote *dev); static int ati_remote_open (struct input_dev *inputdev); static void ati_remote_close (struct input_dev *inputdev); static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); @@ -428,7 +424,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) { struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; - struct input_dev *dev = &ati_remote->idev; + struct input_dev *dev = ati_remote->idev; int index, acc; int remote_num; @@ -587,17 +583,42 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) } /* - * ati_remote_delete + * ati_remote_alloc_buffers */ -static void ati_remote_delete(struct ati_remote *ati_remote) +static int ati_remote_alloc_buffers(struct usb_device *udev, + struct ati_remote *ati_remote) +{ + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + return -1; + + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + return -1; + + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + return -1; + + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + return -1; + + return 0; +} + +/* + * ati_remote_free_buffers + */ +static void ati_remote_free_buffers(struct ati_remote *ati_remote) { if (ati_remote->irq_urb) - usb_kill_urb(ati_remote->irq_urb); + usb_free_urb(ati_remote->irq_urb); if (ati_remote->out_urb) - usb_kill_urb(ati_remote->out_urb); - - input_unregister_device(&ati_remote->idev); + usb_free_urb(ati_remote->out_urb); if (ati_remote->inbuf) usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, @@ -605,20 +626,12 @@ static void ati_remote_delete(struct ati_remote *ati_remote) if (ati_remote->outbuf) usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->outbuf, ati_remote->outbuf_dma); - - if (ati_remote->irq_urb) - usb_free_urb(ati_remote->irq_urb); - - if (ati_remote->out_urb) - usb_free_urb(ati_remote->out_urb); - - kfree(ati_remote); + ati_remote->inbuf, ati_remote->outbuf_dma); } static void ati_remote_input_init(struct ati_remote *ati_remote) { - struct input_dev *idev = &(ati_remote->idev); + struct input_dev *idev = ati_remote->idev; int i; idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); @@ -637,7 +650,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->phys = ati_remote->phys; usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev = &ati_remote->udev->dev; + idev->cdev.dev = &ati_remote->udev->dev; } static int ati_remote_initialize(struct ati_remote *ati_remote) @@ -674,7 +687,7 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { dev_err(&ati_remote->interface->dev, "Initializing ati_remote hardware failed.\n"); - return 1; + return -EIO; } return 0; @@ -686,95 +699,83 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); - struct ati_remote *ati_remote = NULL; - struct usb_host_interface *iface_host; - int retval = -ENOMEM; - char path[64]; + struct usb_host_interface *iface_host = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; + struct ati_remote *ati_remote; + struct input_dev *input_dev; + int err = -ENOMEM; - /* Allocate and clear an ati_remote struct */ - if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL))) - return -ENOMEM; - memset(ati_remote, 0x00, sizeof (struct ati_remote)); - - iface_host = interface->cur_altsetting; if (iface_host->desc.bNumEndpoints != 2) { err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - ati_remote->endpoint_in = &(iface_host->endpoint[0].desc); - ati_remote->endpoint_out = &(iface_host->endpoint[1].desc); - ati_remote->udev = udev; - ati_remote->interface = interface; + endpoint_in = &iface_host->endpoint[0].desc; + endpoint_out = &iface_host->endpoint[1].desc; - if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) { + if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) { err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) { + if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - if (le16_to_cpu(ati_remote->endpoint_in->wMaxPacketSize) == 0) { + if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { err("%s: endpoint_in message size==0? \n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } + ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ati_remote || !input_dev) + goto fail1; + /* Allocate URB buffers, URBs */ - ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, - &ati_remote->inbuf_dma); - if (!ati_remote->inbuf) - goto error; + if (ati_remote_alloc_buffers(udev, ati_remote)) + goto fail2; - ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, - &ati_remote->outbuf_dma); - if (!ati_remote->outbuf) - goto error; + ati_remote->endpoint_in = endpoint_in; + ati_remote->endpoint_out = endpoint_out; + ati_remote->udev = udev; + ati_remote->idev = input_dev; + ati_remote->interface = interface; - ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->irq_urb) - goto error; + usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); + strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); - ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->out_urb) - goto error; - - usb_make_path(udev, path, NAME_BUFSIZE); - sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM); if (udev->manufacturer) - strcat(ati_remote->name, udev->manufacturer); + strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); if (udev->product) - sprintf(ati_remote->name, "%s %s", ati_remote->name, udev->product); + snprintf(ati_remote->name, sizeof(ati_remote->name), + "%s %s", ati_remote->name, udev->product); if (!strlen(ati_remote->name)) - sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", + snprintf(ati_remote->name, sizeof(ati_remote->name), + DRIVER_DESC "(%04x,%04x)", le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idProduct)); + ati_remote_input_init(ati_remote); + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ - retval = ati_remote_initialize(ati_remote); - if (retval) - goto error; + err = ati_remote_initialize(ati_remote); + if (err) + goto fail3; /* Set up and register input device */ - ati_remote_input_init(ati_remote); - input_register_device(&ati_remote->idev); - - dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", - ati_remote->name, path); + input_register_device(ati_remote->idev); usb_set_intfdata(interface, ati_remote); + return 0; -error: - if (retval) - ati_remote_delete(ati_remote); - - return retval; +fail3: usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); +fail2: ati_remote_free_buffers(ati_remote); +fail1: input_free_device(input_dev); + kfree(ati_remote); + return err; } /* @@ -791,7 +792,11 @@ static void ati_remote_disconnect(struct usb_interface *interface) return; } - ati_remote_delete(ati_remote); + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + input_unregister_device(ati_remote->idev); + ati_remote_free_buffers(ati_remote); + kfree(ati_remote); } /* diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 41f92b924761..411a0645a7a3 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1619,8 +1619,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) struct hid_descriptor *hdesc; struct hid_device *hid; unsigned quirks = 0, rsize = 0; - char *buf, *rdesc; - int n, insize = 0; + char *rdesc; + int n, len, insize = 0; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && @@ -1630,10 +1630,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (quirks & HID_QUIRK_IGNORE) return NULL; - if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->desc.bNumEndpoints) || - usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { - dbg("class descriptor not present\n"); - return NULL; + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && + (!interface->desc.bNumEndpoints || + usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { + dbg("class descriptor not present\n"); + return NULL; } for (n = 0; n < hdesc->bNumDescriptors; n++) @@ -1749,32 +1750,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->name[0] = 0; - if (!(buf = kmalloc(64, GFP_KERNEL))) - goto fail; + if (dev->manufacturer) + strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); - if (dev->manufacturer) { - strcat(hid->name, dev->manufacturer); - if (dev->product) - snprintf(hid->name, 64, "%s %s", hid->name, dev->product); - } else if (dev->product) { - snprintf(hid->name, 128, "%s", dev->product); - } else - snprintf(hid->name, 128, "%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + if (dev->product) { + if (dev->manufacturer) + strlcat(hid->name, " ", sizeof(hid->name)); + strlcat(hid->name, dev->product, sizeof(hid->name)); + } - usb_make_path(dev, buf, 64); - snprintf(hid->phys, 64, "%s/input%d", buf, - intf->altsetting[0].desc.bInterfaceNumber); + if (!strlen(hid->name)) + snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + usb_make_path(dev, hid->phys, sizeof(hid->phys)); + strlcat(hid->phys, "/input", sizeof(hid->phys)); + len = strlen(hid->phys); + if (len < sizeof(hid->phys) - 1) + snprintf(hid->phys + len, sizeof(hid->phys) - len, + "%d", intf->altsetting[0].desc.bInterfaceNumber); if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; - kfree(buf); - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); if (!hid->urbctrl) goto fail; + usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 0b6452248a39..9ff25eb520a6 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -76,8 +76,8 @@ static struct { static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) { - struct input_dev *input = &hidinput->input; - struct hid_device *device = hidinput->input.private; + struct input_dev *input = hidinput->input; + struct hid_device *device = input->private; int max = 0, code; unsigned long *bit = NULL; @@ -461,7 +461,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct if (!field->hidinput) return; - input = &field->hidinput->input; + + input = field->hidinput->input; input_regs(input, regs); @@ -533,13 +534,10 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { - struct list_head *lh; struct hid_input *hidinput; - list_for_each (lh, &hid->inputs) { - hidinput = list_entry(lh, struct hid_input, list); - input_sync(&hidinput->input); - } + list_for_each_entry(hidinput, &hid->inputs, list) + input_sync(hidinput->input); } static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) @@ -604,6 +602,7 @@ int hidinput_connect(struct hid_device *hid) struct usb_device *dev = hid->dev; struct hid_report *report; struct hid_input *hidinput = NULL; + struct input_dev *input_dev; int i, j, k; INIT_LIST_HEAD(&hid->inputs); @@ -624,25 +623,28 @@ int hidinput_connect(struct hid_device *hid) continue; if (!hidinput) { - hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); - if (!hidinput) { + hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!hidinput || !input_dev) { + kfree(hidinput); + input_free_device(input_dev); err("Out of memory during hid input probe"); return -1; } - memset(hidinput, 0, sizeof(*hidinput)); + input_dev->private = hid; + input_dev->event = hidinput_input_event; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; + + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->uniq = hid->uniq; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &hid->intf->dev; + + hidinput->input = input_dev; list_add_tail(&hidinput->list, &hid->inputs); - - hidinput->input.private = hid; - hidinput->input.event = hidinput_input_event; - hidinput->input.open = hidinput_open; - hidinput->input.close = hidinput_close; - - hidinput->input.name = hid->name; - hidinput->input.phys = hid->phys; - hidinput->input.uniq = hid->uniq; - usb_to_input_id(dev, &hidinput->input.id); - hidinput->input.dev = &hid->intf->dev; } for (i = 0; i < report->maxfield; i++) @@ -657,7 +659,7 @@ int hidinput_connect(struct hid_device *hid) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; - input_register_device(&hidinput->input); + input_register_device(hidinput->input); hidinput = NULL; } } @@ -667,7 +669,7 @@ int hidinput_connect(struct hid_device *hid) * only useful in this case, and not for multi-input quirks. */ if (hidinput) { hid_ff_init(hid); - input_register_device(&hidinput->input); + input_register_device(hidinput->input); } return 0; @@ -675,13 +677,11 @@ int hidinput_connect(struct hid_device *hid) void hidinput_disconnect(struct hid_device *hid) { - struct list_head *lh, *next; - struct hid_input *hidinput; + struct hid_input *hidinput, *next; - list_for_each_safe(lh, next, &hid->inputs) { - hidinput = list_entry(lh, struct hid_input, list); - input_unregister_device(&hidinput->input); + list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { list_del(&hidinput->list); + input_unregister_device(hidinput->input); kfree(hidinput); } } diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 0c4c77aa31ea..f82c9c9e5d51 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -255,22 +255,19 @@ static void hid_lgff_input_init(struct hid_device* hid) u16 idVendor = le16_to_cpu(hid->dev->descriptor.idVendor); u16 idProduct = le16_to_cpu(hid->dev->descriptor.idProduct); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) dev++; - ff = dev->ff; + for (ff = dev->ff; *ff >= 0; ff++) + set_bit(*ff, input_dev->ffbit); - while (*ff >= 0) { - set_bit(*ff, hidinput->input.ffbit); - ++ff; - } + input_dev->upload_effect = hid_lgff_upload_effect; + input_dev->flush = hid_lgff_flush; - hidinput->input.upload_effect = hid_lgff_upload_effect; - hidinput->input.flush = hid_lgff_flush; - - set_bit(EV_FF, hidinput->input.evbit); - hidinput->input.ff_effects_max = LGFF_EFFECTS; + set_bit(EV_FF, input_dev->evbit); + input_dev->ff_effects_max = LGFF_EFFECTS; } static void hid_lgff_exit(struct hid_device* hid) diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 8f6a0a6f94a9..023fd5ac31c8 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -111,6 +111,7 @@ int hid_tmff_init(struct hid_device *hid) struct tmff_device *private; struct list_head *pos; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!private) @@ -155,7 +156,7 @@ int hid_tmff_init(struct hid_device *hid) private->report = report; private->rumble = field; - set_bit(FF_RUMBLE, hidinput->input.ffbit); + set_bit(FF_RUMBLE, input_dev->ffbit); break; default: @@ -164,11 +165,11 @@ int hid_tmff_init(struct hid_device *hid) } /* Fallthrough to here only when a valid usage is found */ - hidinput->input.upload_effect = hid_tmff_upload_effect; - hidinput->input.flush = hid_tmff_flush; + input_dev->upload_effect = hid_tmff_upload_effect; + input_dev->flush = hid_tmff_flush; - set_bit(EV_FF, hidinput->input.evbit); - hidinput->input.ff_effects_max = TMFF_EFFECTS; + set_bit(EV_FF, input_dev->evbit); + input_dev->ff_effects_max = TMFF_EFFECTS; } } diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index ec2412c42f1e..ee48a2276104 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -371,7 +371,7 @@ struct hid_control_fifo { struct hid_input { struct list_head list; struct hid_report *report; - struct input_dev input; + struct input_dev *input; }; struct hid_device { /* device report descriptor */ diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index becb87efb869..3b581853cf10 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -73,7 +73,7 @@ MODULE_LICENSE( DRIVER_LICENSE ); struct itmtouch_dev { struct usb_device *usbdev; /* usb device */ - struct input_dev inputdev; /* input device */ + struct input_dev *inputdev; /* input device */ struct urb *readurb; /* urb */ char rbuf[ITM_BUFSIZE]; /* data */ int users; @@ -88,9 +88,9 @@ static struct usb_device_id itmtouch_ids [] = { static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) { - struct itmtouch_dev * itmtouch = urb->context; + struct itmtouch_dev *itmtouch = urb->context; unsigned char *data = urb->transfer_buffer; - struct input_dev *dev = &itmtouch->inputdev; + struct input_dev *dev = itmtouch->inputdev; int retval; switch (urb->status) { @@ -156,49 +156,62 @@ static void itmtouch_close(struct input_dev *input) static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct itmtouch_dev *itmtouch; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); unsigned int pipe; unsigned int maxp; - char path[PATH_SIZE]; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) { + itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!itmtouch || !input_dev) { err("%s - Out of memory.", __FUNCTION__); - return -ENOMEM; + goto fail; } itmtouch->usbdev = udev; + itmtouch->inputdev = input_dev; - itmtouch->inputdev.private = itmtouch; - itmtouch->inputdev.open = itmtouch_open; - itmtouch->inputdev.close = itmtouch_close; + if (udev->manufacturer) + strlcpy(itmtouch->name, udev->manufacturer, sizeof(itmtouch->name)); - usb_make_path(udev, path, PATH_SIZE); - - itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - itmtouch->inputdev.name = itmtouch->name; - itmtouch->inputdev.phys = itmtouch->phys; - usb_to_input_id(udev, &itmtouch->inputdev.id); - itmtouch->inputdev.dev = &intf->dev; + if (udev->product) { + if (udev->manufacturer) + strlcat(itmtouch->name, " ", sizeof(itmtouch->name)); + strlcat(itmtouch->name, udev->product, sizeof(itmtouch->name)); + } if (!strlen(itmtouch->name)) sprintf(itmtouch->name, "USB ITM touchscreen"); + usb_make_path(udev, itmtouch->phys, sizeof(itmtouch->phys)); + strlcpy(itmtouch->phys, "/input0", sizeof(itmtouch->phys)); + + input_dev->name = itmtouch->name; + input_dev->phys = itmtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = itmtouch; + + input_dev->open = itmtouch_open; + input_dev->close = itmtouch_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + /* device limits */ /* as specified by the ITM datasheet, X and Y are 12bit, * Z (pressure) is 8 bit. However, the fields are defined up * to 14 bits for future possible expansion. */ - input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0); - input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0); - input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0); + input_set_abs_params(input_dev, ABS_X, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFF, 2, 0); /* initialise the URB so we can read from the transport stream */ pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); @@ -208,22 +221,23 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id maxp = ITM_BUFSIZE; itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!itmtouch->readurb) { dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); - kfree(itmtouch); - return -ENOMEM; + goto fail; } usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf, maxp, itmtouch_irq, itmtouch, endpoint->bInterval); - input_register_device(&itmtouch->inputdev); + input_register_device(itmtouch->inputdev); - printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path); usb_set_intfdata(intf, itmtouch); return 0; + + fail: input_free_device(input_dev); + kfree(itmtouch); + return -ENOMEM; } static void itmtouch_disconnect(struct usb_interface *intf) @@ -233,7 +247,7 @@ static void itmtouch_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (itmtouch) { - input_unregister_device(&itmtouch->inputdev); + input_unregister_device(itmtouch->inputdev); usb_kill_urb(itmtouch->readurb); usb_free_urb(itmtouch->readurb); kfree(itmtouch); diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index b6f6ac8d9c2f..a248664b5d1d 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { signed char *data; dma_addr_t data_dma; - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; struct urb *irq; int x, y; @@ -48,7 +48,7 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) { struct kbtab *kbtab = urb->context; unsigned char *data = kbtab->data; - struct input_dev *dev = &kbtab->dev; + struct input_dev *dev = kbtab->dev; int retval; switch (urb->status) { @@ -124,53 +124,43 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct kbtab *kbtab; - char path[64]; + struct input_dev *input_dev; - if (!(kbtab = kmalloc(sizeof(struct kbtab), GFP_KERNEL))) - return -ENOMEM; - memset(kbtab, 0, sizeof(struct kbtab)); + kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbtab || !input_dev) + goto fail1; kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma); - if (!kbtab->data) { - kfree(kbtab); - return -ENOMEM; - } + if (!kbtab->data) + goto fail1; kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!kbtab->irq) { - usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); - kfree(kbtab); - return -ENOMEM; - } + if (!kbtab->irq) + goto fail2; - kbtab->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); - kbtab->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - - kbtab->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - - kbtab->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH); - - kbtab->dev.mscbit[0] |= BIT(MSC_SERIAL); - - kbtab->dev.absmax[ABS_X] = 0x2000; - kbtab->dev.absmax[ABS_Y] = 0x1750; - kbtab->dev.absmax[ABS_PRESSURE] = 0xff; - - kbtab->dev.absfuzz[ABS_X] = 4; - kbtab->dev.absfuzz[ABS_Y] = 4; - - kbtab->dev.private = kbtab; - kbtab->dev.open = kbtab_open; - kbtab->dev.close = kbtab_close; - - usb_make_path(dev, path, 64); - sprintf(kbtab->phys, "%s/input0", path); - - kbtab->dev.name = "KB Gear Tablet"; - kbtab->dev.phys = kbtab->phys; - usb_to_input_id(dev, &kbtab->dev.id); - kbtab->dev.dev = &intf->dev; kbtab->usbdev = dev; + kbtab->dev = input_dev; + + usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); + strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); + + input_dev->name = "KB Gear Tablet"; + input_dev->phys = kbtab->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = kbtab; + + input_dev->open = kbtab_open; + input_dev->close = kbtab_close; + + input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH); + input_dev->mscbit[0] |= BIT(MSC_SERIAL); + input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); + input_set_abs_params(input_dev, ABS_X, 0, 0x1750, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); endpoint = &intf->cur_altsetting->endpoint[0].desc; @@ -181,23 +171,25 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->irq->transfer_dma = kbtab->data_dma; kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&kbtab->dev); - - printk(KERN_INFO "input: KB Gear Tablet on %s\n", path); + input_register_device(kbtab->dev); usb_set_intfdata(intf, kbtab); - return 0; + +fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); +fail1: input_free_device(input_dev); + kfree(kbtab); + return -ENOMEM; } static void kbtab_disconnect(struct usb_interface *intf) { - struct kbtab *kbtab = usb_get_intfdata (intf); + struct kbtab *kbtab = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); if (kbtab) { usb_kill_urb(kbtab->irq); - input_unregister_device(&kbtab->dev); + input_unregister_device(kbtab->dev); usb_free_urb(kbtab->irq); usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); kfree(kbtab); diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 99de1b33c07d..5b8d65f62abf 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Michael Downey " @@ -75,7 +76,7 @@ struct usb_keyspan { char name[128]; char phys[64]; struct usb_device* udev; - struct input_dev input; + struct input_dev *input; struct usb_interface* interface; struct usb_endpoint_descriptor* in_endpoint; struct urb* irq_urb; @@ -136,12 +137,11 @@ static struct usb_driver keyspan_driver; */ static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ { - char codes[4*RECV_SIZE]; + char codes[4 * RECV_SIZE]; int i; - for (i = 0; i < RECV_SIZE; i++) { - snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); - } + for (i = 0; i < RECV_SIZE; i++) + snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]); dev_info(&dev->udev->dev, "%s\n", codes); } @@ -153,7 +153,7 @@ static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) { if (dev->data.bits_left >= bits_needed) - return(0); + return 0; /* * Somehow we've missed the last message. The message will be repeated @@ -162,7 +162,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) if (dev->data.pos >= dev->data.len) { dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", __FUNCTION__, dev->data.pos, dev->data.len); - return(-1); + return -1; } /* Load as much as we can into the tester. */ @@ -172,7 +172,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) dev->data.bits_left += 8; } - return(0); + return 0; } /* @@ -311,10 +311,10 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) __FUNCTION__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { - input_regs(&remote->input, regs); - input_report_key(&remote->input, keyspan_key_table[message.button], 1); - input_report_key(&remote->input, keyspan_key_table[message.button], 0); - input_sync(&remote->input); + input_regs(remote->input, regs); + input_report_key(remote->input, keyspan_key_table[message.button], 1); + input_report_key(remote->input, keyspan_key_table[message.button], 0); + input_sync(remote->input); remote->toggle = message.toggle; } @@ -397,14 +397,9 @@ static int keyspan_open(struct input_dev *dev) { struct usb_keyspan *remote = dev->private; - if (remote->open++) - return 0; - remote->irq_urb->dev = remote->udev; - if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { - remote->open--; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) return -EIO; - } return 0; } @@ -413,8 +408,26 @@ static void keyspan_close(struct input_dev *dev) { struct usb_keyspan *remote = dev->private; - if (!--remote->open) - usb_kill_urb(remote->irq_urb); + usb_kill_urb(remote->irq_urb); +} + +static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface) +{ + + struct usb_endpoint_descriptor *endpoint; + int i; + + for (i = 0; i < iface->desc.bNumEndpoints; ++i) { + endpoint = &iface->endpoint[i].desc; + + if ((endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + return endpoint; + } + } + + return NULL; } /* @@ -422,110 +435,78 @@ static void keyspan_close(struct input_dev *dev) */ static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int i; - int retval = -ENOMEM; - char path[64]; - char *buf; - struct usb_keyspan *remote = NULL; - struct usb_host_interface *iface_desc; + struct usb_device *udev = interface_to_usbdev(interface); struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + struct usb_keyspan *remote; + struct input_dev *input_dev; + int i, retval; - /* allocate memory for our device state and initialize it */ - remote = kmalloc(sizeof(*remote), GFP_KERNEL); - if (remote == NULL) { - err("Out of memory\n"); - goto error; + endpoint = keyspan_get_in_endpoint(interface->cur_altsetting); + if (!endpoint) + return -ENODEV; + + remote = kzalloc(sizeof(*remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!remote || !input_dev) { + retval = -ENOMEM; + goto fail1; } - memset(remote, 0x00, sizeof(*remote)); remote->udev = udev; + remote->input = input_dev; remote->interface = interface; + remote->in_endpoint = endpoint; remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ - /* set up the endpoint information */ - /* use only the first in interrupt endpoint */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!remote->in_endpoint && - (endpoint->bEndpointAddress & USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { - /* we found our interrupt in endpoint */ - remote->in_endpoint = endpoint; - - remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); - if (!remote->in_buffer) { - retval = -ENOMEM; - goto error; - } - } - } - - if (!remote->in_endpoint) { - err("Could not find interrupt input endpoint.\n"); - retval = -ENODEV; - goto error; + remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto fail1; } remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if (!remote->irq_urb) { - err("Failed to allocate urb.\n"); retval = -ENOMEM; - goto error; + goto fail2; } - retval = keyspan_setup(remote->udev); + retval = keyspan_setup(udev); if (retval) { - err("Failed to setup device.\n"); retval = -ENODEV; - goto error; + goto fail3; } - /* - * Setup the input system with the bits we are going to be reporting - */ - remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ - for (i = 0; i < 32; ++i) { - if (keyspan_key_table[i] != KEY_RESERVED) { - set_bit(keyspan_key_table[i], remote->input.keybit); - } + if (udev->manufacturer) + strlcpy(remote->name, udev->manufacturer, sizeof(remote->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(remote->name, " ", sizeof(remote->name)); + strlcat(remote->name, udev->product, sizeof(remote->name)); } - remote->input.private = remote; - remote->input.open = keyspan_open; - remote->input.close = keyspan_close; - - usb_make_path(remote->udev, path, 64); - sprintf(remote->phys, "%s/input0", path); - - remote->input.name = remote->name; - remote->input.phys = remote->phys; - remote->input.id.bustype = BUS_USB; - remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); - remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); - remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); - - if (!(buf = kmalloc(63, GFP_KERNEL))) { - usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); - kfree(remote); - return -ENOMEM; - } - - if (remote->udev->descriptor.iManufacturer && - usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) - strcat(remote->name, buf); - - if (remote->udev->descriptor.iProduct && - usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) - sprintf(remote->name, "%s %s", remote->name, buf); - if (!strlen(remote->name)) - sprintf(remote->name, "USB Keyspan Remote %04x:%04x", - remote->input.id.vendor, remote->input.id.product); + snprintf(remote->name, sizeof(remote->name), + "USB Keyspan Remote %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); - kfree(buf); + usb_make_path(udev, remote->phys, sizeof(remote->phys)); + strlcat(remote->phys, "/input0", sizeof(remote->phys)); + + input_dev->name = remote->name; + input_dev->phys = remote->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &interface->dev; + + input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) + if (keyspan_key_table[i] != KEY_RESERVED) + set_bit(keyspan_key_table[i], input_dev->keybit); + + input_dev->private = remote; + input_dev->open = keyspan_open; + input_dev->close = keyspan_close; /* * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() @@ -538,27 +519,17 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* we can register the device now, as it is ready */ - input_register_device(&remote->input); + input_register_device(remote->input); /* save our data pointer in this interface device */ usb_set_intfdata(interface, remote); - /* let the user know what node this device is now attached to */ - info("connected: %s on %s", remote->name, path); return 0; -error: - /* - * In case of error we need to clean up any allocated buffers - */ - if (remote->irq_urb) - usb_free_urb(remote->irq_urb); - - if (remote->in_buffer) - usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); - - if (remote) - kfree(remote); + fail3: usb_free_urb(remote->irq_urb); + fail2: usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + fail1: kfree(remote); + input_free_device(input_dev); return retval; } @@ -570,23 +541,16 @@ static void keyspan_disconnect(struct usb_interface *interface) { struct usb_keyspan *remote; - /* prevent keyspan_open() from racing keyspan_disconnect() */ - lock_kernel(); - remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ - input_unregister_device(&remote->input); + input_unregister_device(remote->input); usb_kill_urb(remote->irq_urb); usb_free_urb(remote->irq_urb); - usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); kfree(remote); } - - unlock_kernel(); - - info("USB Keyspan now disconnected"); } /* diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index ff9275057a18..7fce526560ca 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -98,7 +98,7 @@ struct mtouch_usb { dma_addr_t data_dma; struct urb *irq; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; char name[128]; char phys[64]; }; @@ -135,14 +135,14 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_regs(&mtouch->input, regs); - input_report_key(&mtouch->input, BTN_TOUCH, + input_regs(mtouch->input, regs); + input_report_key(mtouch->input, BTN_TOUCH, MTOUCHUSB_GET_TOUCHED(mtouch->data)); - input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); - input_report_abs(&mtouch->input, ABS_Y, + input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(mtouch->input, ABS_Y, (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) - MTOUCHUSB_GET_YC(mtouch->data)); - input_sync(&mtouch->input); + input_sync(mtouch->input); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -195,10 +195,10 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct mtouch_usb *mtouch; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); - char path[64]; int nRet; dbg("%s - called", __FUNCTION__); @@ -209,57 +209,55 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i dbg("%s - setting endpoint", __FUNCTION__); endpoint = &interface->endpoint[0].desc; - if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) { + mtouch = kzalloc(sizeof(struct mtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mtouch || !input_dev) { err("%s - Out of memory.", __FUNCTION__); - return -ENOMEM; + goto fail1; } - memset(mtouch, 0, sizeof(struct mtouch_usb)); - mtouch->udev = udev; - dbg("%s - allocating buffers", __FUNCTION__); - if (mtouchusb_alloc_buffers(udev, mtouch)) { - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; - } + if (mtouchusb_alloc_buffers(udev, mtouch)) + goto fail2; - mtouch->input.private = mtouch; - mtouch->input.open = mtouchusb_open; - mtouch->input.close = mtouchusb_close; - - usb_make_path(udev, path, 64); - sprintf(mtouch->phys, "%s/input0", path); - - mtouch->input.name = mtouch->name; - mtouch->input.phys = mtouch->phys; - usb_to_input_id(udev, &mtouch->input.id); - mtouch->input.dev = &intf->dev; - - mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - /* Used to Scale Compensated Data and Flip Y */ - mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; - mtouch->input.absmax[ABS_X] = raw_coordinates ? - MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; - mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; - mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; - mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; - mtouch->input.absmax[ABS_Y] = raw_coordinates ? - MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; - mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; - mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; + mtouch->udev = udev; + mtouch->input = input_dev; if (udev->manufacturer) - strcat(mtouch->name, udev->manufacturer); - if (udev->product) - sprintf(mtouch->name, "%s %s", mtouch->name, udev->product); + strlcpy(mtouch->name, udev->manufacturer, sizeof(mtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(mtouch->name, " ", sizeof(mtouch->name)); + strlcat(mtouch->name, udev->product, sizeof(mtouch->name)); + } if (!strlen(mtouch->name)) - sprintf(mtouch->name, "USB Touchscreen %04x:%04x", - mtouch->input.id.vendor, mtouch->input.id.product); + snprintf(mtouch->name, sizeof(mtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, mtouch->phys, sizeof(mtouch->phys)); + strlcpy(mtouch->phys, "/input0", sizeof(mtouch->phys)); + + input_dev->name = mtouch->name; + input_dev->phys = mtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = mtouch; + + input_dev->open = mtouchusb_open; + input_dev->close = mtouchusb_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, MTOUCHUSB_MIN_XC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC, + MTOUCHUSB_XC_FUZZ, MTOUCHUSB_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, MTOUCHUSB_MIN_YC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC, + MTOUCHUSB_YC_FUZZ, MTOUCHUSB_YC_FLAT); nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_RESET, @@ -272,9 +270,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); if (!mtouch->irq) { dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; + goto fail2; } dbg("%s - usb_fill_int_urb", __FUNCTION__); @@ -284,7 +280,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i mtouchusb_irq, mtouch, endpoint->bInterval); dbg("%s - input_register_device", __FUNCTION__); - input_register_device(&mtouch->input); + input_register_device(mtouch->input); nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_ASYNC_REPORT, @@ -293,10 +289,13 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", __FUNCTION__, nRet); - printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); usb_set_intfdata(intf, mtouch); - return 0; + +fail2: mtouchusb_free_buffers(udev, mtouch); +fail1: input_free_device(input_dev); + kfree(mtouch); + return -ENOMEM; } static void mtouchusb_disconnect(struct usb_interface *intf) @@ -308,7 +307,7 @@ static void mtouchusb_disconnect(struct usb_interface *intf) if (mtouch) { dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); usb_kill_urb(mtouch->irq); - input_unregister_device(&mtouch->input); + input_unregister_device(mtouch->input); usb_free_urb(mtouch->irq); mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); kfree(mtouch); diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c index acc71ec560e9..a00672c96644 100644 --- a/drivers/usb/input/pid.c +++ b/drivers/usb/input/pid.c @@ -262,6 +262,7 @@ int hid_pid_init(struct hid_device *hid) { struct hid_ff_pid *private; struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); if (!private) @@ -281,11 +282,12 @@ int hid_pid_init(struct hid_device *hid) usb_fill_control_urb(private->urbffout, hid->dev, 0, (void *)&private->ffcr, private->ctrl_buffer, 8, hid_pid_ctrl_out, hid); - hidinput->input.upload_effect = hid_pid_upload_effect; - hidinput->input.flush = hid_pid_flush; - hidinput->input.ff_effects_max = 8; // A random default - set_bit(EV_FF, hidinput->input.evbit); - set_bit(EV_FF_STATUS, hidinput->input.evbit); + + input_dev->upload_effect = hid_pid_upload_effect; + input_dev->flush = hid_pid_flush; + input_dev->ff_effects_max = 8; // A random default + set_bit(EV_FF, input_dev->evbit); + set_bit(EV_FF_STATUS, input_dev->evbit); spin_lock_init(&private->lock); diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index ad4afe7e5897..b7476233ef5d 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -68,7 +68,7 @@ struct powermate_device { struct usb_ctrlrequest *configcr; dma_addr_t configcr_dma; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; spinlock_t lock; int static_brightness; int pulse_speed; @@ -106,10 +106,10 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) } /* handle updates to device state */ - input_regs(&pm->input, regs); - input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); - input_report_rel(&pm->input, REL_DIAL, pm->data[1]); - input_sync(&pm->input); + input_regs(pm->input, regs); + input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); + input_report_rel(pm->input, REL_DIAL, pm->data[1]); + input_sync(pm->input); exit: retval = usb_submit_urb (urb, GFP_ATOMIC); @@ -153,10 +153,10 @@ static void powermate_sync_state(struct powermate_device *pm) Only values of 'arg' quite close to 255 are particularly useful/spectacular. */ - if (pm->pulse_speed < 255){ + if (pm->pulse_speed < 255) { op = 0; // divide arg = 255 - pm->pulse_speed; - } else if (pm->pulse_speed > 255){ + } else if (pm->pulse_speed > 255) { op = 2; // multiply arg = pm->pulse_speed - 255; } else { @@ -166,11 +166,11 @@ static void powermate_sync_state(struct powermate_device *pm) pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); pm->requires_update &= ~UPDATE_PULSE_MODE; - }else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ + } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) { pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; - }else{ + } else { printk(KERN_ERR "powermate: unknown update required"); pm->requires_update = 0; /* fudge the bug */ return; @@ -228,19 +228,19 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne spin_lock_irqsave(&pm->lock, flags); /* mark state updates which are required */ - if (static_brightness != pm->static_brightness){ + if (static_brightness != pm->static_brightness) { pm->static_brightness = static_brightness; pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; } - if (pulse_asleep != pm->pulse_asleep){ + if (pulse_asleep != pm->pulse_asleep) { pm->pulse_asleep = pulse_asleep; pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); } - if (pulse_awake != pm->pulse_awake){ + if (pulse_awake != pm->pulse_awake) { pm->pulse_awake = pulse_awake; pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); } - if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ + if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) { pm->pulse_speed = pulse_speed; pm->pulse_table = pulse_table; pm->requires_update |= UPDATE_PULSE_MODE; @@ -283,6 +283,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev SLAB_ATOMIC, &pm->data_dma); if (!pm->data) return -1; + pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), SLAB_ATOMIC, &pm->configcr_dma); if (!pm->configcr) @@ -308,8 +309,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct powermate_device *pm; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; + int err = -ENOMEM; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; @@ -323,42 +325,61 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i 0, interface->desc.bInterfaceNumber, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL))) - return -ENOMEM; + pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pm || !input_dev) + goto fail1; - memset(pm, 0, sizeof(struct powermate_device)); - pm->udev = udev; - - if (powermate_alloc_buffers(udev, pm)) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (powermate_alloc_buffers(udev, pm)) + goto fail2; pm->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!pm->irq) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (!pm->irq) + goto fail2; pm->config = usb_alloc_urb(0, GFP_KERNEL); - if (!pm->config) { - usb_free_urb(pm->irq); - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (!pm->config) + goto fail3; + + pm->udev = udev; + pm->input = input_dev; + + usb_make_path(udev, pm->phys, sizeof(pm->phys)); + strlcpy(pm->phys, "/input0", sizeof(pm->phys)); spin_lock_init(&pm->lock); - init_input_dev(&pm->input); + + switch (le16_to_cpu(udev->descriptor.idProduct)) { + case POWERMATE_PRODUCT_NEW: + input_dev->name = pm_name_powermate; + break; + case POWERMATE_PRODUCT_OLD: + input_dev->name = pm_name_soundknob; + break; + default: + input_dev->name = pm_name_soundknob; + printk(KERN_WARNING "powermate: unknown product id %04x\n", + le16_to_cpu(udev->descriptor.idProduct)); + } + + input_dev->phys = pm->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = pm; + + input_dev->event = powermate_input_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); + input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); + input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); + input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); /* get a handle to the interrupt data pipe */ pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if(maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX){ - printk("powermate: Expected payload of %d--%d bytes, found %d bytes!\n", + if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { + printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); maxp = POWERMATE_PAYLOAD_SIZE_MAX; } @@ -371,35 +392,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i /* register our interrupt URB with the USB system */ if (usb_submit_urb(pm->irq, GFP_KERNEL)) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -EIO; /* failure */ + err = -EIO; + goto fail4; } - switch (le16_to_cpu(udev->descriptor.idProduct)) { - case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; - case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; - default: - pm->input.name = pm_name_soundknob; - printk(KERN_WARNING "powermate: unknown product id %04x\n", - le16_to_cpu(udev->descriptor.idProduct)); - } - - pm->input.private = pm; - pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); - pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); - pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); - pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); - usb_to_input_id(udev, &pm->input.id); - pm->input.event = powermate_input_event; - pm->input.dev = &intf->dev; - pm->input.phys = pm->phys; - - input_register_device(&pm->input); - - usb_make_path(udev, path, 64); - snprintf(pm->phys, 64, "%s/input0", path); - printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); + input_register_device(pm->input); /* force an update of everything */ pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; @@ -407,6 +404,13 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i usb_set_intfdata(intf, pm); return 0; + +fail4: usb_free_urb(pm->config); +fail3: usb_free_urb(pm->irq); +fail2: powermate_free_buffers(udev, pm); +fail1: input_free_device(input_dev); + kfree(pm); + return err; } /* Called when a USB device we've accepted ownership of is removed */ @@ -418,7 +422,7 @@ static void powermate_disconnect(struct usb_interface *intf) if (pm) { pm->requires_update = 0; usb_kill_urb(pm->irq); - input_unregister_device(&pm->input); + input_unregister_device(pm->input); usb_free_urb(pm->irq); usb_free_urb(pm->config); powermate_free_buffers(interface_to_usbdev(intf), pm); diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 4276c24a5080..3766ccc271be 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -68,7 +68,7 @@ struct touchkit_usb { dma_addr_t data_dma; struct urb *irq; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; char name[128]; char phys[64]; }; @@ -115,12 +115,12 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs) y = TOUCHKIT_GET_Y(touchkit->data); } - input_regs(&touchkit->input, regs); - input_report_key(&touchkit->input, BTN_TOUCH, + input_regs(touchkit->input, regs); + input_report_key(touchkit->input, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(touchkit->data)); - input_report_abs(&touchkit->input, ABS_X, x); - input_report_abs(&touchkit->input, ABS_Y, y); - input_sync(&touchkit->input); + input_report_abs(touchkit->input, ABS_X, x); + input_report_abs(touchkit->input, ABS_Y, y); + input_sync(touchkit->input); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -171,87 +171,81 @@ static void touchkit_free_buffers(struct usb_device *udev, static int touchkit_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int ret; struct touchkit_usb *touchkit; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); - char path[64]; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - touchkit = kmalloc(sizeof(struct touchkit_usb), GFP_KERNEL); - if (!touchkit) - return -ENOMEM; - - memset(touchkit, 0, sizeof(struct touchkit_usb)); - touchkit->udev = udev; - - if (touchkit_alloc_buffers(udev, touchkit)) { - ret = -ENOMEM; + touchkit = kzalloc(sizeof(struct touchkit_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!touchkit || !input_dev) goto out_free; - } - touchkit->input.private = touchkit; - touchkit->input.open = touchkit_open; - touchkit->input.close = touchkit_close; - - usb_make_path(udev, path, 64); - sprintf(touchkit->phys, "%s/input0", path); - - touchkit->input.name = touchkit->name; - touchkit->input.phys = touchkit->phys; - usb_to_input_id(udev, &touchkit->input.id); - touchkit->input.dev = &intf->dev; - - touchkit->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - touchkit->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - touchkit->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - /* Used to Scale Compensated Data */ - touchkit->input.absmin[ABS_X] = TOUCHKIT_MIN_XC; - touchkit->input.absmax[ABS_X] = TOUCHKIT_MAX_XC; - touchkit->input.absfuzz[ABS_X] = TOUCHKIT_XC_FUZZ; - touchkit->input.absflat[ABS_X] = TOUCHKIT_XC_FLAT; - touchkit->input.absmin[ABS_Y] = TOUCHKIT_MIN_YC; - touchkit->input.absmax[ABS_Y] = TOUCHKIT_MAX_YC; - touchkit->input.absfuzz[ABS_Y] = TOUCHKIT_YC_FUZZ; - touchkit->input.absflat[ABS_Y] = TOUCHKIT_YC_FLAT; - - if (udev->manufacturer) - strcat(touchkit->name, udev->manufacturer); - if (udev->product) - sprintf(touchkit->name, "%s %s", touchkit->name, udev->product); - - if (!strlen(touchkit->name)) - sprintf(touchkit->name, "USB Touchscreen %04x:%04x", - touchkit->input.id.vendor, touchkit->input.id.product); + if (touchkit_alloc_buffers(udev, touchkit)) + goto out_free; touchkit->irq = usb_alloc_urb(0, GFP_KERNEL); if (!touchkit->irq) { dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__); - ret = -ENOMEM; goto out_free_buffers; } + touchkit->udev = udev; + touchkit->input = input_dev; + + if (udev->manufacturer) + strlcpy(touchkit->name, udev->manufacturer, sizeof(touchkit->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(touchkit->name, " ", sizeof(touchkit->name)); + strlcat(touchkit->name, udev->product, sizeof(touchkit->name)); + } + + if (!strlen(touchkit->name)) + snprintf(touchkit->name, sizeof(touchkit->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, touchkit->phys, sizeof(touchkit->phys)); + strlcpy(touchkit->phys, "/input0", sizeof(touchkit->phys)); + + input_dev->name = touchkit->name; + input_dev->phys = touchkit->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = touchkit; + input_dev->open = touchkit_open; + input_dev->close = touchkit_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, TOUCHKIT_MIN_XC, TOUCHKIT_MAX_XC, + TOUCHKIT_XC_FUZZ, TOUCHKIT_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, TOUCHKIT_MIN_YC, TOUCHKIT_MAX_YC, + TOUCHKIT_YC_FUZZ, TOUCHKIT_YC_FLAT); + usb_fill_int_urb(touchkit->irq, touchkit->udev, - usb_rcvintpipe(touchkit->udev, 0x81), - touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, - touchkit_irq, touchkit, endpoint->bInterval); + usb_rcvintpipe(touchkit->udev, 0x81), + touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, + touchkit_irq, touchkit, endpoint->bInterval); - input_register_device(&touchkit->input); + input_register_device(touchkit->input); - printk(KERN_INFO "input: %s on %s\n", touchkit->name, path); usb_set_intfdata(intf, touchkit); - return 0; out_free_buffers: touchkit_free_buffers(udev, touchkit); out_free: + input_free_device(input_dev); kfree(touchkit); - return ret; + return -ENOMEM; } static void touchkit_disconnect(struct usb_interface *intf) @@ -265,8 +259,8 @@ static void touchkit_disconnect(struct usb_interface *intf) dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__); usb_set_intfdata(intf, NULL); - input_unregister_device(&touchkit->input); usb_kill_urb(touchkit->irq); + input_unregister_device(touchkit->input); usb_free_urb(touchkit->irq); touchkit_free_buffers(interface_to_usbdev(intf), touchkit); kfree(touchkit); diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 28987f15eeee..226b6f90a907 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -66,7 +66,7 @@ static unsigned char usb_kbd_keycode[256] = { }; struct usb_kbd { - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; unsigned char old[8]; struct urb *irq, *led; @@ -99,29 +99,29 @@ static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; } - input_regs(&kbd->dev, regs); + input_regs(kbd->dev, regs); for (i = 0; i < 8; i++) - input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); + input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); for (i = 2; i < 8; i++) { if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { if (usb_kbd_keycode[kbd->old[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); + input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); else info("Unknown key (scancode %#x) released.", kbd->old[i]); } if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); + input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else info("Unknown key (scancode %#x) pressed.", kbd->new[i]); } } - input_sync(&kbd->dev); + input_sync(kbd->dev); memcpy(kbd->old, kbd->new, 8); @@ -227,12 +227,12 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id) { - struct usb_device * dev = interface_to_usbdev(iface); + struct usb_device *dev = interface_to_usbdev(iface); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_kbd *kbd; + struct input_dev *input_dev; int i, pipe, maxp; - char path[64]; interface = iface->cur_altsetting; @@ -240,37 +240,59 @@ static int usb_kbd_probe(struct usb_interface *iface, return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) - return -ENOMEM; - memset(kbd, 0, sizeof(struct usb_kbd)); + kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbd || !input_dev) + goto fail1; - if (usb_kbd_alloc_mem(dev, kbd)) { - usb_kbd_free_mem(dev, kbd); - kfree(kbd); - return -ENOMEM; - } + if (usb_kbd_alloc_mem(dev, kbd)) + goto fail2; kbd->usbdev = dev; + kbd->dev = input_dev; - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); + if (dev->manufacturer) + strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(kbd->name, " ", sizeof(kbd->name)); + strlcat(kbd->name, dev->product, sizeof(kbd->name)); + } + + if (!strlen(kbd->name)) + snprintf(kbd->name, sizeof(kbd->name), + "USB HIDBP Keyboard %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); + strlcpy(kbd->phys, "/input0", sizeof(kbd->phys)); + + input_dev->name = kbd->name; + input_dev->phys = kbd->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &iface->dev; + input_dev->private = kbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); for (i = 0; i < 255; i++) - set_bit(usb_kbd_keycode[i], kbd->dev.keybit); - clear_bit(0, kbd->dev.keybit); + set_bit(usb_kbd_keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); - kbd->dev.private = kbd; - kbd->dev.event = usb_kbd_event; - kbd->dev.open = usb_kbd_open; - kbd->dev.close = usb_kbd_close; + input_dev->event = usb_kbd_event; + input_dev->open = usb_kbd_open; + input_dev->close = usb_kbd_close; usb_fill_int_urb(kbd->irq, dev, pipe, kbd->new, (maxp > 8 ? 8 : maxp), @@ -284,37 +306,22 @@ static int usb_kbd_probe(struct usb_interface *iface, kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); kbd->cr->wLength = cpu_to_le16(1); - usb_make_path(dev, path, 64); - sprintf(kbd->phys, "%s/input0", path); - - kbd->dev.name = kbd->name; - kbd->dev.phys = kbd->phys; - usb_to_input_id(dev, &kbd->dev.id); - kbd->dev.dev = &iface->dev; - - if (dev->manufacturer) - strcat(kbd->name, dev->manufacturer); - if (dev->product) - sprintf(kbd->name, "%s %s", kbd->name, dev->product); - - if (!strlen(kbd->name)) - sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x", - kbd->dev.id.vendor, kbd->dev.id.product); - usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), (void *) kbd->cr, kbd->leds, 1, usb_kbd_led, kbd); kbd->led->setup_dma = kbd->cr_dma; kbd->led->transfer_dma = kbd->leds_dma; - kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); + kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - input_register_device(&kbd->dev); - - printk(KERN_INFO "input: %s on %s\n", kbd->name, path); + input_register_device(kbd->dev); usb_set_intfdata(iface, kbd); return 0; + +fail2: usb_kbd_free_mem(dev, kbd); +fail1: input_free_device(input_dev); + kfree(kbd); + return -ENOMEM; } static void usb_kbd_disconnect(struct usb_interface *intf) @@ -324,7 +331,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (kbd) { usb_kill_urb(kbd->irq); - input_unregister_device(&kbd->dev); + input_unregister_device(kbd->dev); usb_kbd_free_mem(interface_to_usbdev(intf), kbd); kfree(kbd); } diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 4104dec847fb..230f6b1b314a 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -50,7 +50,7 @@ struct usb_mouse { char name[128]; char phys[64]; struct usb_device *usbdev; - struct input_dev dev; + struct input_dev *dev; struct urb *irq; signed char *data; @@ -61,7 +61,7 @@ static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs) { struct usb_mouse *mouse = urb->context; signed char *data = mouse->data; - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; int status; switch (urb->status) { @@ -115,14 +115,14 @@ static void usb_mouse_close(struct input_dev *dev) usb_kill_urb(mouse->irq); } -static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) +static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device * dev = interface_to_usbdev(intf); + struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_mouse *mouse; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; interface = intf->cur_altsetting; @@ -130,59 +130,62 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) - return -ENOMEM; - memset(mouse, 0, sizeof(struct usb_mouse)); + mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mouse || !input_dev) + goto fail1; mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); - if (!mouse->data) { - kfree(mouse); - return -ENOMEM; - } + if (!mouse->data) + goto fail1; mouse->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!mouse->irq) { - usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); - kfree(mouse); - return -ENODEV; - } + if (!mouse->irq) + goto fail2; mouse->usbdev = dev; - - mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); - mouse->dev.relbit[0] |= BIT(REL_WHEEL); - - mouse->dev.private = mouse; - mouse->dev.open = usb_mouse_open; - mouse->dev.close = usb_mouse_close; - - usb_make_path(dev, path, 64); - sprintf(mouse->phys, "%s/input0", path); - - mouse->dev.name = mouse->name; - mouse->dev.phys = mouse->phys; - usb_to_input_id(dev, &mouse->dev.id); - mouse->dev.dev = &intf->dev; + mouse->dev = input_dev; if (dev->manufacturer) - strcat(mouse->name, dev->manufacturer); - if (dev->product) - sprintf(mouse->name, "%s %s", mouse->name, dev->product); + strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(mouse->name, " ", sizeof(mouse->name)); + strlcat(mouse->name, dev->product, sizeof(mouse->name)); + } if (!strlen(mouse->name)) - sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x", - mouse->dev.id.vendor, mouse->dev.id.product); + snprintf(mouse->name, sizeof(mouse->name), + "USB HIDBP Mouse %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); + strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); + + input_dev->name = mouse->name; + input_dev->phys = mouse->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + input_dev->relbit[0] |= BIT(REL_WHEEL); + + input_dev->private = mouse; + input_dev->open = usb_mouse_open; + input_dev->close = usb_mouse_close; usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), @@ -190,11 +193,15 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ mouse->irq->transfer_dma = mouse->data_dma; mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&mouse->dev); - printk(KERN_INFO "input: %s on %s\n", mouse->name, path); + input_register_device(mouse->dev); usb_set_intfdata(intf, mouse); return 0; + +fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); +fail1: input_free_device(input_dev); + kfree(mouse); + return -ENOMEM; } static void usb_mouse_disconnect(struct usb_interface *intf) @@ -204,7 +211,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (mouse) { usb_kill_urb(mouse->irq); - input_unregister_device(&mouse->dev); + input_unregister_device(mouse->dev); usb_free_urb(mouse->irq); usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); kfree(mouse); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 3b266af3048a..ea0f75773ae1 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -111,7 +111,7 @@ struct wacom_features { struct wacom { signed char *data; dma_addr_t data_dma; - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; struct urb *irq; struct wacom_features *features; @@ -135,7 +135,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int prox, pressure; int retval; @@ -225,7 +225,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int retval; switch (urb->status) { @@ -275,7 +275,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int retval; switch (urb->status) { @@ -318,7 +318,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int x, y; int retval; @@ -397,7 +397,7 @@ static int wacom_intuos_inout(struct urb *urb) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int idx; /* tool number */ @@ -479,7 +479,7 @@ static void wacom_intuos_general(struct urb *urb) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; unsigned int t; /* general pen packet */ @@ -509,7 +509,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; unsigned int t; int idx; int retval; @@ -738,95 +738,83 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i { struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; - char rep_data[2] = {0x02, 0x02}; struct wacom *wacom; - char path[64]; + struct input_dev *input_dev; + char rep_data[2] = {0x02, 0x02}; - if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) - return -ENOMEM; - memset(wacom, 0, sizeof(struct wacom)); + wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!wacom || !input_dev) + goto fail1; wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); - if (!wacom->data) { - kfree(wacom); - return -ENOMEM; - } + if (!wacom->data) + goto fail1; wacom->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!wacom->irq) { - usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); - kfree(wacom); - return -ENOMEM; - } + if (!wacom->irq) + goto fail2; + + wacom->usbdev = dev; + wacom->dev = input_dev; + usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); + strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom->features = wacom_features + (id - wacom_ids); + if (wacom->features->pktlen > 10) + BUG(); - wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); - wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); + input_dev->name = wacom->features->name; + usb_to_input_id(dev, &input_dev->id); + + input_dev->cdev.dev = &intf->dev; + input_dev->private = wacom; + input_dev->open = wacom_open; + input_dev->close = wacom_close; + + input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); + input_set_abs_params(input_dev, ABS_X, 0, wacom->features->y_max, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0); switch (wacom->features->type) { case GRAPHIRE: - wacom->dev.evbit[0] |= BIT(EV_REL); - wacom->dev.relbit[0] |= BIT(REL_WHEEL); - wacom->dev.absbit[0] |= BIT(ABS_DISTANCE); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); + input_dev->evbit[0] |= BIT(EV_REL); + input_dev->relbit[0] |= BIT(REL_WHEEL); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0); break; case INTUOS3: case CINTIQ: - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); - wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); /* fall through */ case INTUOS: - wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); - wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); - wacom->dev.relbit[0] |= BIT(REL_WHEEL); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) + input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); + input_dev->mscbit[0] |= BIT(MSC_SERIAL); + input_dev->relbit[0] |= BIT(REL_WHEEL); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); - wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); + input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); break; case PL: - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); break; } - wacom->dev.absmax[ABS_X] = wacom->features->x_max; - wacom->dev.absmax[ABS_Y] = wacom->features->y_max; - wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max; - wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max; - wacom->dev.absmax[ABS_TILT_X] = 127; - wacom->dev.absmax[ABS_TILT_Y] = 127; - wacom->dev.absmax[ABS_WHEEL] = 1023; - - wacom->dev.absmax[ABS_RX] = 4097; - wacom->dev.absmax[ABS_RY] = 4097; - wacom->dev.absmin[ABS_RZ] = -900; - wacom->dev.absmax[ABS_RZ] = 899; - wacom->dev.absmin[ABS_THROTTLE] = -1023; - wacom->dev.absmax[ABS_THROTTLE] = 1023; - - wacom->dev.absfuzz[ABS_X] = 4; - wacom->dev.absfuzz[ABS_Y] = 4; - - wacom->dev.private = wacom; - wacom->dev.open = wacom_open; - wacom->dev.close = wacom_close; - - usb_make_path(dev, path, 64); - sprintf(wacom->phys, "%s/input0", path); - - wacom->dev.name = wacom->features->name; - wacom->dev.phys = wacom->phys; - usb_to_input_id(dev, &wacom->dev.id); - wacom->dev.dev = &intf->dev; - wacom->usbdev = dev; - endpoint = &intf->cur_altsetting->endpoint[0].desc; if (wacom->features->pktlen > 10) @@ -839,18 +827,20 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&wacom->dev); + input_register_device(wacom->dev); /* ask the tablet to report tablet data */ usb_set_report(intf, 3, 2, rep_data, 2); /* repeat once (not sure why the first call often fails) */ usb_set_report(intf, 3, 2, rep_data, 2); - printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path); - usb_set_intfdata(intf, wacom); - return 0; + +fail2: usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); +fail1: input_free_device(input_dev); + kfree(wacom); + return -ENOMEM; } static void wacom_disconnect(struct usb_interface *intf) @@ -860,7 +850,7 @@ static void wacom_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (wacom) { usb_kill_urb(wacom->irq); - input_unregister_device(&wacom->dev); + input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma); kfree(wacom); diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index 18125e0bffa2..43112f040b6d 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -103,7 +103,7 @@ static struct usb_device_id xpad_table [] = { MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { - struct input_dev dev; /* input device interface */ + struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct urb *irq_in; /* urb for interrupt in report */ @@ -125,7 +125,7 @@ struct usb_xpad { static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs) { - struct input_dev *dev = &xpad->dev; + struct input_dev *dev = xpad->dev; input_regs(dev, regs); @@ -214,9 +214,9 @@ static void xpad_close (struct input_dev *dev) static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev (intf); - struct usb_xpad *xpad = NULL; + struct usb_xpad *xpad; + struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; - char path[64]; int i; for (i = 0; xpad_device[i].idVendor; i++) { @@ -225,29 +225,63 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id break; } - if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) { - err("cannot allocate memory for new pad"); - return -ENOMEM; - } - memset(xpad, 0, sizeof(struct usb_xpad)); + xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!xpad || !input_dev) + goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, SLAB_ATOMIC, &xpad->idata_dma); - if (!xpad->idata) { - kfree(xpad); - return -ENOMEM; - } + if (!xpad->idata) + goto fail1; xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); - if (!xpad->irq_in) { - err("cannot allocate memory for new pad irq urb"); - usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); - kfree(xpad); - return -ENOMEM; - } + if (!xpad->irq_in) + goto fail2; + + xpad->udev = udev; + xpad->dev = input_dev; + usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); + strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); + + input_dev->name = xpad_device[i].name; + input_dev->phys = xpad->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = xpad; + input_dev->open = xpad_open; + input_dev->close = xpad_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; xpad_btn[i] >= 0; i++) + set_bit(xpad_btn[i], input_dev->keybit); + + for (i = 0; xpad_abs[i] >= 0; i++) { + + signed short t = xpad_abs[i]; + + set_bit(t, input_dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); + break; + case ABS_Z: + case ABS_RZ: /* the triggers */ + input_set_abs_params(input_dev, t, 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad */ + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + break; + } + } ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), xpad->idata, XPAD_PKT_LEN, xpad_irq_in, @@ -255,59 +289,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - xpad->udev = udev; - - usb_to_input_id(udev, &xpad->dev.id); - xpad->dev.dev = &intf->dev; - xpad->dev.private = xpad; - xpad->dev.name = xpad_device[i].name; - xpad->dev.phys = xpad->phys; - xpad->dev.open = xpad_open; - xpad->dev.close = xpad_close; - - usb_make_path(udev, path, 64); - snprintf(xpad->phys, 64, "%s/input0", path); - - xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (i = 0; xpad_btn[i] >= 0; i++) - set_bit(xpad_btn[i], xpad->dev.keybit); - - for (i = 0; xpad_abs[i] >= 0; i++) { - - signed short t = xpad_abs[i]; - - set_bit(t, xpad->dev.absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - xpad->dev.absmax[t] = 32767; - xpad->dev.absmin[t] = -32768; - xpad->dev.absflat[t] = 128; - xpad->dev.absfuzz[t] = 16; - break; - case ABS_Z: - case ABS_RZ: /* the triggers */ - xpad->dev.absmax[t] = 255; - xpad->dev.absmin[t] = 0; - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - xpad->dev.absmax[t] = 1; - xpad->dev.absmin[t] = -1; - break; - } - } - - input_register_device(&xpad->dev); - - printk(KERN_INFO "input: %s on %s", xpad->dev.name, path); + input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; + +fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +fail1: input_free_device(input_dev); + kfree(xpad); + return -ENOMEM; + } static void xpad_disconnect(struct usb_interface *intf) @@ -317,7 +308,7 @@ static void xpad_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); - input_unregister_device(&xpad->dev); + input_unregister_device(xpad->dev); usb_free_urb(xpad->irq_in); usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); kfree(xpad); diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 58a176ef96a5..f526aebea502 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "map_to_7segment.h" #include "yealink.h" @@ -101,12 +102,12 @@ static const struct lcd_segment_map { }; struct yealink_dev { - struct input_dev idev; /* input device */ + struct input_dev *idev; /* input device */ struct usb_device *udev; /* usb device */ /* irq input channel */ struct yld_ctl_packet *irq_data; - dma_addr_t irq_dma; + dma_addr_t irq_dma; struct urb *urb_irq; /* control output channel */ @@ -237,7 +238,7 @@ static int map_p1k_to_key(int scancode) */ static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs) { - struct input_dev *idev = &yld->idev; + struct input_dev *idev = yld->idev; input_regs(idev, regs); if (yld->key_code >= 0) { @@ -809,8 +810,12 @@ static int usb_cleanup(struct yealink_dev *yld, int err) } if (yld->urb_ctl) usb_free_urb(yld->urb_ctl); - if (yld->idev.dev) - input_unregister_device(&yld->idev); + if (yld->idev) { + if (err) + input_free_device(yld->idev); + else + input_unregister_device(yld->idev); + } if (yld->ctl_req) usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), yld->ctl_req, yld->ctl_req_dma); @@ -857,7 +862,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct yealink_dev *yld; - char path[64]; + struct input_dev *input_dev; int ret, pipe, i; i = usb_match(udev); @@ -866,17 +871,21 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -EIO; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -EIO; - if ((yld = kmalloc(sizeof(struct yealink_dev), GFP_KERNEL)) == NULL) + yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL); + if (!yld) return -ENOMEM; - memset(yld, 0, sizeof(*yld)); yld->udev = udev; + yld->idev = input_dev = input_allocate_device(); + if (!input_dev) + return usb_cleanup(yld, -ENOMEM); + /* allocate usb buffers */ yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, SLAB_ATOMIC, &yld->irq_dma); @@ -935,42 +944,37 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) yld->urb_ctl->dev = udev; /* find out the physical bus location */ - if (usb_make_path(udev, path, sizeof(path)) > 0) - snprintf(yld->phys, sizeof(yld->phys)-1, "%s/input0", path); + usb_make_path(udev, yld->phys, sizeof(yld->phys)); + strlcat(yld->phys, "/input0", sizeof(yld->phys)); /* register settings for the input device */ - init_input_dev(&yld->idev); - yld->idev.private = yld; - yld->idev.id.bustype = BUS_USB; - yld->idev.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - yld->idev.id.product = le16_to_cpu(udev->descriptor.idProduct); - yld->idev.id.version = le16_to_cpu(udev->descriptor.bcdDevice); - yld->idev.dev = &intf->dev; - yld->idev.name = yld_device[i].name; - yld->idev.phys = yld->phys; - /* yld->idev.event = input_ev; TODO */ - yld->idev.open = input_open; - yld->idev.close = input_close; + input_dev->name = yld_device[i].name; + input_dev->phys = yld->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + + input_dev->private = yld; + input_dev->open = input_open; + input_dev->close = input_close; + /* input_dev->event = input_ev; TODO */ /* register available key events */ - yld->idev.evbit[0] = BIT(EV_KEY); + input_dev->evbit[0] = BIT(EV_KEY); for (i = 0; i < 256; i++) { int k = map_p1k_to_key(i); if (k >= 0) { - set_bit(k & 0xff, yld->idev.keybit); + set_bit(k & 0xff, input_dev->keybit); if (k >> 8) - set_bit(k >> 8, yld->idev.keybit); + set_bit(k >> 8, input_dev->keybit); } } - printk(KERN_INFO "input: %s on %s\n", yld->idev.name, path); - - input_register_device(&yld->idev); + input_register_device(yld->idev); usb_set_intfdata(intf, yld); /* clear visible elements */ - for (i=0; i Date: Thu, 15 Sep 2005 02:01:48 -0500 Subject: [PATCH 0933/1939] [PATCH] Input: convert ucb1x00-ts to dynamic input_dev allocation Input: convert ucb1x00-ts to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/ucb1x00-ts.c | 43 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index a260f83bcb02..585cded3d365 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -40,7 +40,7 @@ struct ucb1x00_ts { - struct input_dev idev; + struct input_dev *idev; struct ucb1x00 *ucb; wait_queue_head_t irq_wait; @@ -56,16 +56,16 @@ static int adcsync; static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) { - input_report_abs(&ts->idev, ABS_X, x); - input_report_abs(&ts->idev, ABS_Y, y); - input_report_abs(&ts->idev, ABS_PRESSURE, pressure); - input_sync(&ts->idev); + input_report_abs(ts->idev, ABS_X, x); + input_report_abs(ts->idev, ABS_Y, y); + input_report_abs(ts->idev, ABS_PRESSURE, pressure); + input_sync(ts->idev); } static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) { - input_report_abs(&ts->idev, ABS_PRESSURE, 0); - input_sync(&ts->idev); + input_report_abs(ts->idev, ABS_PRESSURE, 0); + input_sync(ts->idev); } /* @@ -341,26 +341,30 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) { struct ucb1x00_ts *ts; - ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); + ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); if (!ts) return -ENOMEM; - memset(ts, 0, sizeof(struct ucb1x00_ts)); + ts->idev = input_allocate_device(); + if (!ts->idev) { + kfree(ts); + return -ENOMEM; + } ts->ucb = dev->ucb; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; - ts->idev.name = "Touchscreen panel"; - ts->idev.id.product = ts->ucb->id; - ts->idev.open = ucb1x00_ts_open; - ts->idev.close = ucb1x00_ts_close; + ts->idev->name = "Touchscreen panel"; + ts->idev->id.product = ts->ucb->id; + ts->idev->open = ucb1x00_ts_open; + ts->idev->close = ucb1x00_ts_close; - __set_bit(EV_ABS, ts->idev.evbit); - __set_bit(ABS_X, ts->idev.absbit); - __set_bit(ABS_Y, ts->idev.absbit); - __set_bit(ABS_PRESSURE, ts->idev.absbit); + __set_bit(EV_ABS, ts->idev->evbit); + __set_bit(ABS_X, ts->idev->absbit); + __set_bit(ABS_Y, ts->idev->absbit); + __set_bit(ABS_PRESSURE, ts->idev->absbit); - input_register_device(&ts->idev); + input_register_device(ts->idev); dev->priv = ts; @@ -370,7 +374,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) { struct ucb1x00_ts *ts = dev->priv; - input_unregister_device(&ts->idev); + + input_unregister_device(ts->idev); kfree(ts); } From eca1ed196cd5b523c1057204cd3672555ad58dfe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:46 -0500 Subject: [PATCH 0934/1939] [PATCH] drivers/input/touchscreen: convert to dynamic input_dev allocation Input: convert drivers/input/touchscreen to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/corgi_ts.c | 89 ++++++------ drivers/input/touchscreen/elo.c | 91 +++++++------ drivers/input/touchscreen/gunze.c | 66 ++++----- drivers/input/touchscreen/h3600_ts_input.c | 149 ++++++++------------- drivers/input/touchscreen/hp680_ts_input.c | 50 +++---- drivers/input/touchscreen/mk712.c | 82 ++++++------ drivers/input/touchscreen/mtouch.c | 64 ++++----- 7 files changed, 281 insertions(+), 310 deletions(-) diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 4c7fbe550365..40ae183ba1cd 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -41,8 +41,7 @@ struct ts_event { }; struct corgi_ts { - char phys[32]; - struct input_dev input; + struct input_dev *input; struct timer_list timer; struct ts_event tc; int pendown; @@ -182,14 +181,12 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0) return; - if (regs) - input_regs(&corgi_ts->input, regs); - - input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x); - input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y); - input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure); - input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0)); - input_sync(&corgi_ts->input); + input_regs(corgi_ts->input, regs); + input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x); + input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y); + input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure); + input_report_key(corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0)); + input_sync(corgi_ts->input); } static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs) @@ -273,39 +270,44 @@ static int __init corgits_probe(struct device *dev) { struct corgi_ts *corgi_ts; struct platform_device *pdev = to_platform_device(dev); + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL))) - return -ENOMEM; + corgi_ts = kzalloc(sizeof(struct corgi_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!corgi_ts || !input_dev) + goto fail; dev_set_drvdata(dev, corgi_ts); - memset(corgi_ts, 0, sizeof(struct corgi_ts)); - corgi_ts->machinfo = dev->platform_data; corgi_ts->irq_gpio = platform_get_irq(pdev, 0); if (corgi_ts->irq_gpio < 0) { - kfree(corgi_ts); - return -ENODEV; + err = -ENODEV; + goto fail; } - init_input_dev(&corgi_ts->input); - corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); - input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); - input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); + corgi_ts->input = input_dev; - strcpy(corgi_ts->phys, "corgits/input0"); + init_timer(&corgi_ts->timer); + corgi_ts->timer.data = (unsigned long) corgi_ts; + corgi_ts->timer.function = corgi_ts_timer; - corgi_ts->input.private = corgi_ts; - corgi_ts->input.name = "Corgi Touchscreen"; - corgi_ts->input.dev = dev; - corgi_ts->input.phys = corgi_ts->phys; - corgi_ts->input.id.bustype = BUS_HOST; - corgi_ts->input.id.vendor = 0x0001; - corgi_ts->input.id.product = 0x0002; - corgi_ts->input.id.version = 0x0100; + input_dev->name = "Corgi Touchscreen"; + input_dev->phys = "corgits/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = dev; + input_dev->private = corgi_ts; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN); @@ -319,25 +321,24 @@ static int __init corgits_probe(struct device *dev) corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS); mdelay(5); - init_timer(&corgi_ts->timer); - corgi_ts->timer.data = (unsigned long) corgi_ts; - corgi_ts->timer.function = corgi_ts_timer; - - input_register_device(&corgi_ts->input); - corgi_ts->power_mode = PWR_MODE_ACTIVE; - if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { - input_unregister_device(&corgi_ts->input); - kfree(corgi_ts); - return -EBUSY; + err = -EBUSY; + goto fail; } + input_register_device(corgi_ts->input); + + corgi_ts->power_mode = PWR_MODE_ACTIVE; + /* Enable Falling Edge */ set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); - printk(KERN_INFO "input: Corgi Touchscreen Registered\n"); - return 0; + + fail: input_free_device(input_dev); + kfree(corgi_ts); + return err; + } static int corgits_remove(struct device *dev) @@ -347,7 +348,7 @@ static int corgits_remove(struct device *dev) free_irq(corgi_ts->irq_gpio, NULL); del_timer_sync(&corgi_ts->timer); corgi_ts->machinfo->put_hsync(); - input_unregister_device(&corgi_ts->input); + input_unregister_device(corgi_ts->input); kfree(corgi_ts); return 0; } diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 3cdc9cab688d..c86a2eb310fd 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -36,14 +36,12 @@ MODULE_LICENSE("GPL"); #define ELO_MAX_LENGTH 10 -static char *elo_name = "Elo Serial TouchScreen"; - /* * Per-touchscreen data. */ struct elo { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int id; int idx; @@ -54,7 +52,7 @@ struct elo { static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->csum += elo->data[elo->idx] = data; @@ -80,7 +78,7 @@ static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_r input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); - input_report_key(dev, BTN_TOUCH, elo->data[2] & 3); + input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); input_sync(dev); } elo->idx = 0; @@ -91,7 +89,7 @@ static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_r static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->data[elo->idx] = data; @@ -129,7 +127,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re case 5: if ((data & 0xf0) == 0) { input_report_abs(dev, ABS_PRESSURE, elo->data[5]); - input_report_key(dev, BTN_TOUCH, elo->data[5]); + input_report_key(dev, BTN_TOUCH, !!elo->data[5]); } input_sync(dev); elo->idx = 0; @@ -139,7 +137,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->data[elo->idx] = data; @@ -191,7 +189,7 @@ static void elo_disconnect(struct serio *serio) { struct elo* elo = serio_get_drvdata(serio); - input_unregister_device(&elo->dev); + input_unregister_device(elo->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(elo); @@ -206,67 +204,68 @@ static void elo_disconnect(struct serio *serio) static int elo_connect(struct serio *serio, struct serio_driver *drv) { struct elo *elo; + struct input_dev *input_dev; int err; - if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL))) - return -ENOMEM; - - memset(elo, 0, sizeof(struct elo)); - - init_input_dev(&elo->dev); - elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + elo = kzalloc(sizeof(struct elo), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!elo || !input_dev) { + err = -ENOMEM; + goto fail; + } + elo->serio = serio; elo->id = serio->id.id; + elo->dev = input_dev; + snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); + + input_dev->private = elo; + input_dev->name = "Elo Serial TouchScreen"; + input_dev->phys = elo->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_ELO; + input_dev->id.product = elo->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); switch (elo->id) { case 0: /* 10-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); break; case 1: /* 6-byte protocol */ - input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); case 2: /* 4-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); break; case 3: /* 3-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); break; } - elo->serio = serio; - - sprintf(elo->phys, "%s/input0", serio->phys); - - elo->dev.private = elo; - elo->dev.name = elo_name; - elo->dev.phys = elo->phys; - elo->dev.id.bustype = BUS_RS232; - elo->dev.id.vendor = SERIO_ELO; - elo->dev.id.product = elo->id; - elo->dev.id.version = 0x0100; - serio_set_drvdata(serio, elo); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(elo); - return err; - } - - input_register_device(&elo->dev); - - printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys); + if (err) + goto fail; + input_register_device(elo->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(elo); + return err; } /* diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 53a27e43dd23..466da190ceec 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -48,14 +48,12 @@ MODULE_LICENSE("GPL"); #define GUNZE_MAX_LENGTH 10 -static char *gunze_name = "Gunze AHL-51S TouchScreen"; - /* * Per-touchscreen data. */ struct gunze { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int idx; unsigned char data[GUNZE_MAX_LENGTH]; @@ -64,7 +62,7 @@ struct gunze { static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) { - struct input_dev *dev = &gunze->dev; + struct input_dev *dev = gunze->dev; if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { @@ -100,11 +98,13 @@ static irqreturn_t gunze_interrupt(struct serio *serio, static void gunze_disconnect(struct serio *serio) { - struct gunze* gunze = serio_get_drvdata(serio); + struct gunze *gunze = serio_get_drvdata(serio); - input_unregister_device(&gunze->dev); + input_get_device(gunze->dev); + input_unregister_device(gunze->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(gunze->dev); kfree(gunze); } @@ -117,45 +117,45 @@ static void gunze_disconnect(struct serio *serio) static int gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; + struct input_dev *input_dev; int err; - if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL))) - return -ENOMEM; - - memset(gunze, 0, sizeof(struct gunze)); - - init_input_dev(&gunze->dev); - gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(&gunze->dev, ABS_X, 24, 1000, 0, 0); - input_set_abs_params(&gunze->dev, ABS_Y, 24, 1000, 0, 0); + gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!gunze || !input_dev) { + err = -ENOMEM; + goto fail; + } gunze->serio = serio; - + gunze->dev = input_dev; sprintf(gunze->phys, "%s/input0", serio->phys); - gunze->dev.private = gunze; - gunze->dev.name = gunze_name; - gunze->dev.phys = gunze->phys; - gunze->dev.id.bustype = BUS_RS232; - gunze->dev.id.vendor = SERIO_GUNZE; - gunze->dev.id.product = 0x0051; - gunze->dev.id.version = 0x0100; + input_dev->private = gunze; + input_dev->name = "Gunze AHL-51S TouchScreen"; + input_dev->phys = gunze->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_GUNZE; + input_dev->id.product = 0x0051; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0); serio_set_drvdata(serio, gunze); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(gunze); - return err; - } - - input_register_device(&gunze->dev); - - printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys); + if (err) + goto fail; + input_register_device(gunze->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(gunze); + return err; } /* diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index bcfa1e36f957..a18d56bdafd9 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -39,7 +39,6 @@ #include #include #include -#include /* SA1100 serial defines */ #include @@ -93,16 +92,12 @@ MODULE_LICENSE("GPL"); #define H3600_SCANCODE_LEFT 8 /* 8 -> left */ #define H3600_SCANCODE_DOWN 9 /* 9 -> down */ -static char *h3600_name = "H3600 TouchScreen"; - /* * Per-touchscreen data. */ struct h3600_dev { - struct input_dev dev; - struct pm_dev *pm_dev; + struct input_dev *dev; struct serio *serio; - struct pm_dev *pm_dev; unsigned char event; /* event ID from packet */ unsigned char chksum; unsigned char len; @@ -163,33 +158,6 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) return 0; } -static int suspended = 0; -static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, - void *data) -{ - struct input_dev *dev = (struct input_dev *) data; - - switch (req) { - case PM_SUSPEND: /* enter D1-D3 */ - suspended = 1; - h3600_flite_power(dev, FLITE_PWR_OFF); - break; - case PM_BLANK: - if (!suspended) - h3600_flite_power(dev, FLITE_PWR_OFF); - break; - case PM_RESUME: /* enter D0 */ - /* same as unblank */ - case PM_UNBLANK: - if (suspended) { - //initSerial(); - suspended = 0; - } - h3600_flite_power(dev, FLITE_PWR_ON); - break; - } - return 0; -} #endif /* @@ -199,7 +167,7 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, */ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) { - struct input_dev *dev = &ts->dev; + struct input_dev *dev = ts->dev; static int touched = 0; int key, down = 0; @@ -295,6 +263,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) static int h3600ts_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { +#if 0 struct h3600_dev *ts = dev->private; switch (type) { @@ -304,6 +273,8 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, } } return -1; +#endif + return 0; } /* @@ -380,14 +351,48 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; + struct input_dev *input_dev; int err; - if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL))) - return -ENOMEM; + ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ts || !input_dev) { + err = -ENOMEM; + goto fail1; + } - memset(ts, 0, sizeof(struct h3600_dev)); + ts->serio = serio; + ts->dev = input_dev; + sprintf(ts->phys, "%s/input0", serio->phys); - init_input_dev(&ts->dev); + input_dev->name = "H3600 TouchScreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_H3600; + input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */ + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = ts; + + input_dev->event = h3600ts_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); + input_dev->ledbit[0] = BIT(LED_SLEEP); + input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0); + + set_bit(KEY_RECORD, input_dev->keybit); + set_bit(KEY_Q, input_dev->keybit); + set_bit(KEY_PROG1, input_dev->keybit); + set_bit(KEY_PROG2, input_dev->keybit); + set_bit(KEY_PROG3, input_dev->keybit); + set_bit(KEY_UP, input_dev->keybit); + set_bit(KEY_RIGHT, input_dev->keybit); + set_bit(KEY_LEFT, input_dev->keybit); + set_bit(KEY_DOWN, input_dev->keybit); + set_bit(KEY_ENTER, input_dev->keybit); + set_bit(KEY_SUSPEND, input_dev->keybit); + set_bit(BTN_TOUCH, input_dev->keybit); /* Device specific stuff */ set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES); @@ -397,73 +402,35 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); - kfree(ts); - return -EBUSY; + err = -EBUSY; + goto fail2; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_suspend", &ts->dev)) { - free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); - kfree(ts); - return -EBUSY; + err = -EBUSY; + goto fail3; } - /* Now we have things going we setup our input device */ - ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); - ts->dev.ledbit[0] = BIT(LED_SLEEP); - input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0); - input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0); - - set_bit(KEY_RECORD, ts->dev.keybit); - set_bit(KEY_Q, ts->dev.keybit); - set_bit(KEY_PROG1, ts->dev.keybit); - set_bit(KEY_PROG2, ts->dev.keybit); - set_bit(KEY_PROG3, ts->dev.keybit); - set_bit(KEY_UP, ts->dev.keybit); - set_bit(KEY_RIGHT, ts->dev.keybit); - set_bit(KEY_LEFT, ts->dev.keybit); - set_bit(KEY_DOWN, ts->dev.keybit); - set_bit(KEY_ENTER, ts->dev.keybit); - ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); - ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); - - ts->serio = serio; - - sprintf(ts->phys, "%s/input0", serio->phys); - - ts->dev.event = h3600ts_event; - ts->dev.private = ts; - ts->dev.name = h3600_name; - ts->dev.phys = ts->phys; - ts->dev.id.bustype = BUS_RS232; - ts->dev.id.vendor = SERIO_H3600; - ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ - ts->dev.id.version = 0x0100; - serio_set_drvdata(serio, ts); err = serio_open(serio, drv); - if (err) { - free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); - free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); - serio_set_drvdata(serio, NULL); - kfree(ts); + if (err) return err; - } //h3600_flite_control(1, 25); /* default brightness */ -#ifdef CONFIG_PM - ts->pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, - h3600ts_pm_callback); - printk("registered pm callback\n"); -#endif - input_register_device(&ts->dev); - - printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys); + input_register_device(ts->dev); return 0; + +fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); +fail1: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(ts); + return err; } /* @@ -476,9 +443,11 @@ static void h3600ts_disconnect(struct serio *serio) free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev); - input_unregister_device(&ts->dev); + input_get_device(ts->dev); + input_unregister_device(ts->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(ts->dev); kfree(ts); } diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index 7e1404441eca..957dd5a1b15e 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -21,10 +21,8 @@ static void do_softint(void *data); -static struct input_dev hp680_ts_dev; +static struct input_dev *hp680_ts_dev; static DECLARE_WORK(work, do_softint, 0); -static char *hp680_ts_name = "HP Jornada touchscreen"; -static char *hp680_ts_phys = "input0"; static void do_softint(void *data) { @@ -58,14 +56,14 @@ static void do_softint(void *data) } if (touched) { - input_report_key(&hp680_ts_dev, BTN_TOUCH, 1); - input_report_abs(&hp680_ts_dev, ABS_X, absx); - input_report_abs(&hp680_ts_dev, ABS_Y, absy); + input_report_key(hp680_ts_dev, BTN_TOUCH, 1); + input_report_abs(hp680_ts_dev, ABS_X, absx); + input_report_abs(hp680_ts_dev, ABS_Y, absy); } else { - input_report_key(&hp680_ts_dev, BTN_TOUCH, 0); + input_report_key(hp680_ts_dev, BTN_TOUCH, 0); } - input_sync(&hp680_ts_dev); + input_sync(hp680_ts_dev); enable_irq(HP680_TS_IRQ); } @@ -92,27 +90,29 @@ static int __init hp680_ts_init(void) scpcr |= SCPCR_TS_ENABLE; ctrl_outw(scpcr, SCPCR); - memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev)); - init_input_dev(&hp680_ts_dev); + hp680_ts_dev = input_allocate_device(); + if (!hp680_ts_dev) + return -ENOMEM; - hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + hp680_ts_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + hp680_ts_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + hp680_ts_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN; - hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN; - hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX; - hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX; + hp680_ts_dev->absmin[ABS_X] = HP680_TS_ABS_X_MIN; + hp680_ts_dev->absmin[ABS_Y] = HP680_TS_ABS_Y_MIN; + hp680_ts_dev->absmax[ABS_X] = HP680_TS_ABS_X_MAX; + hp680_ts_dev->absmax[ABS_Y] = HP680_TS_ABS_Y_MAX; - hp680_ts_dev.name = hp680_ts_name; - hp680_ts_dev.phys = hp680_ts_phys; - input_register_device(&hp680_ts_dev); + hp680_ts_dev->name = "HP Jornada touchscreen"; + hp680_ts_dev->phys = "hp680_ts/input0"; - if (request_irq - (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) { - printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n", + input_register_device(hp680_ts_dev); + + if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt, + SA_INTERRUPT, MODNAME, 0) < 0) { + printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n", HP680_TS_IRQ); - input_unregister_device(&hp680_ts_dev); + input_unregister_device(hp680_ts_dev); return -EBUSY; } @@ -124,7 +124,7 @@ static void __exit hp680_ts_exit(void) free_irq(HP680_TS_IRQ, 0); cancel_delayed_work(&work); flush_scheduled_work(); - input_unregister_device(&hp680_ts_dev); + input_unregister_device(hp680_ts_dev); } module_init(hp680_ts_init); diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c index afaaebe5225b..4844d250a5eb 100644 --- a/drivers/input/touchscreen/mk712.c +++ b/drivers/input/touchscreen/mk712.c @@ -77,7 +77,7 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller"); #define MK712_READ_ONE_POINT 0x20 #define MK712_POWERUP 0x40 -static struct input_dev mk712_dev; +static struct input_dev *mk712_dev; static DEFINE_SPINLOCK(mk712_lock); static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -88,7 +88,7 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) static unsigned short last_y; spin_lock(&mk712_lock); - input_regs(&mk712_dev, regs); + input_regs(mk712_dev, regs); status = inb(mk712_io + MK712_STATUS); @@ -100,7 +100,7 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (~status & MK712_STATUS_TOUCH) { debounce = 1; - input_report_key(&mk712_dev, BTN_TOUCH, 0); + input_report_key(mk712_dev, BTN_TOUCH, 0); goto end; } @@ -110,15 +110,15 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) goto end; } - input_report_key(&mk712_dev, BTN_TOUCH, 1); - input_report_abs(&mk712_dev, ABS_X, last_x); - input_report_abs(&mk712_dev, ABS_Y, last_y); + input_report_key(mk712_dev, BTN_TOUCH, 1); + input_report_abs(mk712_dev, ABS_X, last_x); + input_report_abs(mk712_dev, ABS_Y, last_y); end: last_x = inw(mk712_io + MK712_X) & 0x0fff; last_y = inw(mk712_io + MK712_Y) & 0x0fff; - input_sync(&mk712_dev); + input_sync(mk712_dev); spin_unlock(&mk712_lock); return IRQ_HANDLED; } @@ -154,30 +154,11 @@ static void mk712_close(struct input_dev *dev) spin_unlock_irqrestore(&mk712_lock, flags); } -static struct input_dev mk712_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, - .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, - .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, - .open = mk712_open, - .close = mk712_close, - .name = "ICS MicroClock MK712 TouchScreen", - .phys = "isa0260/input0", - .absmin = { [ABS_X] = 0, [ABS_Y] = 0 }, - .absmax = { [ABS_X] = 0xfff, [ABS_Y] = 0xfff }, - .absfuzz = { [ABS_X] = 88, [ABS_Y] = 88 }, - .id = { - .bustype = BUS_ISA, - .vendor = 0x0005, - .product = 0x0001, - .version = 0x0100, - }, -}; - int __init mk712_init(void) { + int err; - if(!request_region(mk712_io, 8, "mk712")) - { + if (!request_region(mk712_io, 8, "mk712")) { printk(KERN_WARNING "mk712: unable to get IO region\n"); return -ENODEV; } @@ -188,28 +169,49 @@ int __init mk712_init(void) (inw(mk712_io + MK712_Y) & 0xf000) || (inw(mk712_io + MK712_STATUS) & 0xf333)) { printk(KERN_WARNING "mk712: device not present\n"); - release_region(mk712_io, 8); - return -ENODEV; + err = -ENODEV; + goto fail; } - if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712", &mk712_dev)) - { + if (!(mk712_dev = input_allocate_device())) { + printk(KERN_ERR "mk712: not enough memory\n"); + err = -ENOMEM; + goto fail; + } + + mk712_dev->name = "ICS MicroClock MK712 TouchScreen"; + mk712_dev->phys = "isa0260/input0"; + mk712_dev->id.bustype = BUS_ISA; + mk712_dev->id.vendor = 0x0005; + mk712_dev->id.product = 0x0001; + mk712_dev->id.version = 0x0100; + + mk712_dev->open = mk712_open; + mk712_dev->close = mk712_close; + + mk712_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mk712_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0); + input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0); + + if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) { printk(KERN_WARNING "mk712: unable to get IRQ\n"); - release_region(mk712_io, 8); - return -EBUSY; + err = -EBUSY; + goto fail; } - input_register_device(&mk712_dev); - - printk(KERN_INFO "input: ICS MicroClock MK712 TouchScreen at %#x irq %d\n", mk712_io, mk712_irq); - + input_register_device(mk712_dev); return 0; + + fail: input_free_device(mk712_dev); + release_region(mk712_io, 8); + return err; } static void __exit mk712_exit(void) { - input_unregister_device(&mk712_dev); - free_irq(mk712_irq, &mk712_dev); + input_unregister_device(mk712_dev); + free_irq(mk712_irq, mk712_dev); release_region(mk712_io, 8); } diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index aa8ee7842179..1d0d37eeef6e 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -51,14 +51,12 @@ MODULE_LICENSE("GPL"); #define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3]) #define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0]) -static char *mtouch_name = "MicroTouch Serial TouchScreen"; - /* * Per-touchscreen data. */ struct mtouch { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int idx; unsigned char data[MTOUCH_MAX_LENGTH]; @@ -67,7 +65,7 @@ struct mtouch { static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs) { - struct input_dev *dev = &mtouch->dev; + struct input_dev *dev = mtouch->dev; if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) { input_regs(dev, regs); @@ -116,9 +114,11 @@ static void mtouch_disconnect(struct serio *serio) { struct mtouch* mtouch = serio_get_drvdata(serio); - input_unregister_device(&mtouch->dev); + input_get_device(mtouch->dev); + input_unregister_device(mtouch->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(mtouch->dev); kfree(mtouch); } @@ -131,46 +131,46 @@ static void mtouch_disconnect(struct serio *serio) static int mtouch_connect(struct serio *serio, struct serio_driver *drv) { struct mtouch *mtouch; + struct input_dev *input_dev; int err; - if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL))) - return -ENOMEM; - - memset(mtouch, 0, sizeof(*mtouch)); - - init_input_dev(&mtouch->dev); - mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); - input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); + mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mtouch || !input_dev) { + err = -ENOMEM; + goto fail; + } mtouch->serio = serio; - + mtouch->dev = input_dev; sprintf(mtouch->phys, "%s/input0", serio->phys); - mtouch->dev.private = mtouch; - mtouch->dev.name = mtouch_name; - mtouch->dev.phys = mtouch->phys; - mtouch->dev.id.bustype = BUS_RS232; - mtouch->dev.id.vendor = SERIO_MICROTOUCH; - mtouch->dev.id.product = 0; - mtouch->dev.id.version = 0x0100; + input_dev->private = mtouch; + input_dev->name = "MicroTouch Serial TouchScreen"; + input_dev->phys = mtouch->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_MICROTOUCH; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); + input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); serio_set_drvdata(serio, mtouch); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(mtouch); - return err; - } + if (err) + goto fail; - input_register_device(&mtouch->dev); - - printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys); + input_register_device(mtouch->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(mtouch); + return err; } /* From b416f2e452b6c0f5075145bb7301f7f3d44d8ed5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:50 -0500 Subject: [PATCH 0935/1939] [PATCH] Input: convert sonypi to dynamic input_dev allocation Input: convert sonypi to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/char/sonypi.c | 92 +++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 36ae9ad2598c..a4873684f22c 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -424,10 +424,6 @@ static struct sonypi_eventtypes { #define SONYPI_BUF_SIZE 128 -/* The name of the devices for the input device drivers */ -#define SONYPI_JOG_INPUTNAME "Sony Vaio Jogdial" -#define SONYPI_KEY_INPUTNAME "Sony Vaio Keys" - /* Correspondance table between sonypi events and input layer events */ static struct { int sonypiev; @@ -490,8 +486,8 @@ static struct sonypi_device { struct fasync_struct *fifo_async; int open_count; int model; - struct input_dev input_jog_dev; - struct input_dev input_key_dev; + struct input_dev *input_jog_dev; + struct input_dev *input_key_dev; struct work_struct input_work; struct kfifo *input_fifo; spinlock_t input_fifo_lock; @@ -779,8 +775,8 @@ static void input_keyrelease(void *data) static void sonypi_report_input_event(u8 event) { - struct input_dev *jog_dev = &sonypi_device.input_jog_dev; - struct input_dev *key_dev = &sonypi_device.input_key_dev; + struct input_dev *jog_dev = sonypi_device.input_jog_dev; + struct input_dev *key_dev = sonypi_device.input_key_dev; struct sonypi_keypress kp = { NULL }; int i; @@ -1203,6 +1199,47 @@ static struct device_driver sonypi_driver = { .shutdown = sonypi_shutdown, }; +static int __devinit sonypi_create_input_devices(void) +{ + struct input_dev *jog_dev; + struct input_dev *key_dev; + int i; + + sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); + if (!jog_dev) + return -ENOMEM; + + jog_dev->name = "Sony Vaio Jogdial"; + jog_dev->id.bustype = BUS_ISA; + jog_dev->id.vendor = PCI_VENDOR_ID_SONY; + + jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE); + jog_dev->relbit[0] = BIT(REL_WHEEL); + + sonypi_device.input_key_dev = key_dev = input_allocate_device(); + if (!key_dev) { + input_free_device(jog_dev); + sonypi_device.input_jog_dev = NULL; + return -ENOMEM; + } + + key_dev->name = "Sony Vaio Keys"; + key_dev->id.bustype = BUS_ISA; + key_dev->id.vendor = PCI_VENDOR_ID_SONY; + + /* Initialize the Input Drivers: special keys */ + key_dev->evbit[0] = BIT(EV_KEY); + for (i = 0; sonypi_inputkeys[i].sonypiev; i++) + if (sonypi_inputkeys[i].inputev) + set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); + + input_register_device(jog_dev); + input_register_device(key_dev); + + return 0; +} + static int __devinit sonypi_probe(void) { int i, ret; @@ -1298,34 +1335,10 @@ static int __devinit sonypi_probe(void) } if (useinput) { - /* Initialize the Input Drivers: jogdial */ - int i; - sonypi_device.input_jog_dev.evbit[0] = - BIT(EV_KEY) | BIT(EV_REL); - sonypi_device.input_jog_dev.keybit[LONG(BTN_MOUSE)] = - BIT(BTN_MIDDLE); - sonypi_device.input_jog_dev.relbit[0] = BIT(REL_WHEEL); - sonypi_device.input_jog_dev.name = SONYPI_JOG_INPUTNAME; - sonypi_device.input_jog_dev.id.bustype = BUS_ISA; - sonypi_device.input_jog_dev.id.vendor = PCI_VENDOR_ID_SONY; - input_register_device(&sonypi_device.input_jog_dev); - printk(KERN_INFO "%s input method installed.\n", - sonypi_device.input_jog_dev.name); - - /* Initialize the Input Drivers: special keys */ - sonypi_device.input_key_dev.evbit[0] = BIT(EV_KEY); - for (i = 0; sonypi_inputkeys[i].sonypiev; i++) - if (sonypi_inputkeys[i].inputev) - set_bit(sonypi_inputkeys[i].inputev, - sonypi_device.input_key_dev.keybit); - sonypi_device.input_key_dev.name = SONYPI_KEY_INPUTNAME; - sonypi_device.input_key_dev.id.bustype = BUS_ISA; - sonypi_device.input_key_dev.id.vendor = PCI_VENDOR_ID_SONY; - - input_register_device(&sonypi_device.input_key_dev); - printk(KERN_INFO "%s input method installed.\n", - sonypi_device.input_key_dev.name); + ret = sonypi_create_input_devices(); + if (ret) + goto out_inputdevices; spin_lock_init(&sonypi_device.input_fifo_lock); sonypi_device.input_fifo = @@ -1375,8 +1388,9 @@ static int __devinit sonypi_probe(void) out_platformdev: kfifo_free(sonypi_device.input_fifo); out_infifo: - input_unregister_device(&sonypi_device.input_key_dev); - input_unregister_device(&sonypi_device.input_jog_dev); + input_unregister_device(sonypi_device.input_key_dev); + input_unregister_device(sonypi_device.input_jog_dev); +out_inputdevices: free_irq(sonypi_device.irq, sonypi_irq); out_reqirq: release_region(sonypi_device.ioport1, sonypi_device.region_size); @@ -1402,8 +1416,8 @@ static void __devexit sonypi_remove(void) platform_device_unregister(sonypi_device.pdev); if (useinput) { - input_unregister_device(&sonypi_device.input_key_dev); - input_unregister_device(&sonypi_device.input_jog_dev); + input_unregister_device(sonypi_device.input_key_dev); + input_unregister_device(sonypi_device.input_jog_dev); kfifo_free(sonypi_device.input_fifo); } From 88789672424375882166df86adde9dd77ead630e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:43 -0500 Subject: [PATCH 0936/1939] [PATCH] Input: convert onetouch to dynamic input_dev allocation Input: convert onetouch to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/onetouch.c | 105 +++++++++++++++++---------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 2c9402dc702b..89401a59f952 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -5,7 +5,7 @@ * Copyright (c) 2005 Nick Sillik * * Initial work by: - * Copyright (c) 2003 Erik Thyren + * Copyright (c) 2003 Erik Thyren * * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann) * @@ -46,7 +46,7 @@ void onetouch_release_input(void *onetouch_); struct usb_onetouch { char name[128]; char phys[64]; - struct input_dev dev; /* input device interface */ + struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct urb *irq; /* urb for interrupt in report */ @@ -58,7 +58,7 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) { struct usb_onetouch *onetouch = urb->context; signed char *data = onetouch->data; - struct input_dev *dev = &onetouch->dev; + struct input_dev *dev = onetouch->dev; int status; switch (urb->status) { @@ -74,11 +74,9 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) } input_regs(dev, regs); - - input_report_key(&onetouch->dev, ONETOUCH_BUTTON, - data[0] & 0x02); - + input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); input_sync(dev); + resubmit: status = usb_submit_urb (urb, SLAB_ATOMIC); if (status) @@ -113,8 +111,8 @@ int onetouch_connect_input(struct us_data *ss) struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_onetouch *onetouch; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; interface = ss->pusb_intf->cur_altsetting; @@ -122,62 +120,62 @@ int onetouch_connect_input(struct us_data *ss) return -ENODEV; endpoint = &interface->endpoint[2].desc; - if(!(endpoint->bEndpointAddress & USB_DIR_IN)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if (!(onetouch = kcalloc(1, sizeof(struct usb_onetouch), GFP_KERNEL))) - return -ENOMEM; + onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!onetouch || !input_dev) + goto fail1; onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, SLAB_ATOMIC, &onetouch->data_dma); - if (!onetouch->data){ - kfree(onetouch); - return -ENOMEM; - } + if (!onetouch->data) + goto fail1; onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!onetouch->irq){ - kfree(onetouch); - usb_buffer_free(udev, ONETOUCH_PKT_LEN, - onetouch->data, onetouch->data_dma); - return -ENODEV; - } - + if (!onetouch->irq) + goto fail2; onetouch->udev = udev; - - set_bit(EV_KEY, onetouch->dev.evbit); - set_bit(ONETOUCH_BUTTON, onetouch->dev.keybit); - clear_bit(0, onetouch->dev.keybit); - - onetouch->dev.private = onetouch; - onetouch->dev.open = usb_onetouch_open; - onetouch->dev.close = usb_onetouch_close; - - usb_make_path(udev, path, sizeof(path)); - sprintf(onetouch->phys, "%s/input0", path); - - onetouch->dev.name = onetouch->name; - onetouch->dev.phys = onetouch->phys; - - usb_to_input_id(udev, &onetouch->dev.id); - - onetouch->dev.dev = &udev->dev; + onetouch->dev = input_dev; if (udev->manufacturer) - strcat(onetouch->name, udev->manufacturer); - if (udev->product) - sprintf(onetouch->name, "%s %s", onetouch->name, - udev->product); + strlcpy(onetouch->name, udev->manufacturer, + sizeof(onetouch->name)); + if (udev->product) { + if (udev->manufacturer) + strlcat(onetouch->name, " ", sizeof(onetouch->name)); + strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); + } + if (!strlen(onetouch->name)) - sprintf(onetouch->name, "Maxtor Onetouch %04x:%04x", - onetouch->dev.id.vendor, onetouch->dev.id.product); + snprintf(onetouch->name, sizeof(onetouch->name), + "Maxtor Onetouch %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); + strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); + + input_dev->name = onetouch->name; + input_dev->phys = onetouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &udev->dev; + + set_bit(EV_KEY, input_dev->evbit); + set_bit(ONETOUCH_BUTTON, input_dev->keybit); + clear_bit(0, input_dev->keybit); + + input_dev->private = onetouch; + input_dev->open = usb_onetouch_open; + input_dev->close = usb_onetouch_close; usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, (maxp > 8 ? 8 : maxp), @@ -188,10 +186,15 @@ int onetouch_connect_input(struct us_data *ss) ss->extra_destructor = onetouch_release_input; ss->extra = onetouch; - input_register_device(&onetouch->dev); - printk(KERN_INFO "usb-input: %s on %s\n", onetouch->dev.name, path); + input_register_device(onetouch->dev); return 0; + + fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN, + onetouch->data, onetouch->data_dma); + fail1: kfree(onetouch); + input_free_device(input_dev); + return -ENOMEM; } void onetouch_release_input(void *onetouch_) @@ -200,11 +203,9 @@ void onetouch_release_input(void *onetouch_) if (onetouch) { usb_kill_urb(onetouch->irq); - input_unregister_device(&onetouch->dev); + input_unregister_device(onetouch->dev); usb_free_urb(onetouch->irq); usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, onetouch->data, onetouch->data_dma); - printk(KERN_INFO "usb-input: deregistering %s\n", - onetouch->dev.name); } } From 76b7cddfd576331761e945a508254abad11039e9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:51 -0500 Subject: [PATCH 0937/1939] [PATCH] Input: convert driver/input/misc to dynamic input_dev allocation Input: convert driver/input/misc to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/m68kspkr.c | 36 +++++++++++++-------------- drivers/input/misc/pcspkr.c | 30 +++++++++++------------ drivers/input/misc/sparcspkr.c | 45 +++++++++++++++++----------------- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 64abdd98d482..04489ad7702a 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -24,9 +24,7 @@ MODULE_AUTHOR("Richard Zidlicky "); MODULE_DESCRIPTION("m68k beeper driver"); MODULE_LICENSE("GPL"); -static char m68kspkr_name[] = "m68k beeper"; -static char m68kspkr_phys[] = "m68k/generic"; -static struct input_dev m68kspkr_dev; +static struct input_dev *m68kspkr_dev; static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -51,32 +49,34 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int static int __init m68kspkr_init(void) { - if (!mach_beep){ - printk("%s: no lowlevel beep support\n", m68kspkr_name); - return -1; + if (!mach_beep) { + printk(KERN_INFO "m68kspkr: no lowlevel beep support\n"); + return -ENODEV; } - m68kspkr_dev.evbit[0] = BIT(EV_SND); - m68kspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - m68kspkr_dev.event = m68kspkr_event; + m68kspkr_dev = input_allocate_device(); + if (!m68kspkr_dev) + return -ENOMEM; - m68kspkr_dev.name = m68kspkr_name; - m68kspkr_dev.phys = m68kspkr_phys; - m68kspkr_dev.id.bustype = BUS_HOST; - m68kspkr_dev.id.vendor = 0x001f; - m68kspkr_dev.id.product = 0x0001; - m68kspkr_dev.id.version = 0x0100; + m68kspkr_dev->name = "m68k beeper"; + m68kspkr_dev->phys = "m68k/generic"; + m68kspkr_dev->id.bustype = BUS_HOST; + m68kspkr_dev->id.vendor = 0x001f; + m68kspkr_dev->id.product = 0x0001; + m68kspkr_dev->id.version = 0x0100; - input_register_device(&m68kspkr_dev); + m68kspkr_dev->evbit[0] = BIT(EV_SND); + m68kspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + m68kspkr_dev->event = m68kspkr_event; - printk(KERN_INFO "input: %s\n", m68kspkr_name); + input_register_device(m68kspkr_dev); return 0; } static void __exit m68kspkr_exit(void) { - input_unregister_device(&m68kspkr_dev); + input_unregister_device(m68kspkr_dev); } module_init(m68kspkr_init); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 3013194f462b..e34633c37fdd 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -23,9 +23,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); -static char pcspkr_name[] = "PC Speaker"; -static char pcspkr_phys[] = "isa0061/input0"; -static struct input_dev pcspkr_dev; +static struct input_dev *pcspkr_dev; static DEFINE_SPINLOCK(i8253_beep_lock); @@ -68,27 +66,29 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c static int __init pcspkr_init(void) { - pcspkr_dev.evbit[0] = BIT(EV_SND); - pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - pcspkr_dev.event = pcspkr_event; + pcspkr_dev = input_allocate_device(); + if (!pcspkr_dev) + return -ENOMEM; - pcspkr_dev.name = pcspkr_name; - pcspkr_dev.phys = pcspkr_phys; - pcspkr_dev.id.bustype = BUS_ISA; - pcspkr_dev.id.vendor = 0x001f; - pcspkr_dev.id.product = 0x0001; - pcspkr_dev.id.version = 0x0100; + pcspkr_dev->name = "PC Speaker"; + pcspkr_dev->name = "isa0061/input0"; + pcspkr_dev->id.bustype = BUS_ISA; + pcspkr_dev->id.vendor = 0x001f; + pcspkr_dev->id.product = 0x0001; + pcspkr_dev->id.version = 0x0100; - input_register_device(&pcspkr_dev); + pcspkr_dev->evbit[0] = BIT(EV_SND); + pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + pcspkr_dev->event = pcspkr_event; - printk(KERN_INFO "input: %s\n", pcspkr_name); + input_register_device(pcspkr_dev); return 0; } static void __exit pcspkr_exit(void) { - input_unregister_device(&pcspkr_dev); + input_unregister_device(pcspkr_dev); /* turn off the speaker */ pcspkr_event(NULL, EV_SND, SND_BELL, 0); } diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index cdc3fb3d5f46..5778220a18d2 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -17,28 +17,24 @@ #endif MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("PC Speaker beeper driver"); +MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); static unsigned long beep_iobase; - -static char *sparcspkr_isa_name = "Sparc ISA Speaker"; -static char *sparcspkr_ebus_name = "Sparc EBUS Speaker"; -static char *sparcspkr_phys = "sparc/input0"; -static struct input_dev sparcspkr_dev; +static struct input_dev *sparcspkr_dev; DEFINE_SPINLOCK(beep_lock); static void __init init_sparcspkr_struct(void) { - sparcspkr_dev.evbit[0] = BIT(EV_SND); - sparcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + sparcspkr_dev->evbit[0] = BIT(EV_SND); + sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - sparcspkr_dev.phys = sparcspkr_phys; - sparcspkr_dev.id.bustype = BUS_ISA; - sparcspkr_dev.id.vendor = 0x001f; - sparcspkr_dev.id.product = 0x0001; - sparcspkr_dev.id.version = 0x0100; + sparcspkr_dev->phys = "sparc/input0"; + sparcspkr_dev->id.bustype = BUS_ISA; + sparcspkr_dev->id.vendor = 0x001f; + sparcspkr_dev->id.product = 0x0001; + sparcspkr_dev->id.version = 0x0100; } static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -84,14 +80,15 @@ static int __init init_ebus_beep(struct linux_ebus_device *edev) { beep_iobase = edev->resource[0].start; - init_sparcspkr_struct(); + sparcspkr_dev = input_allocate_device(); + if (!sparcspkr_dev) + return -ENOMEM; - sparcspkr_dev.name = sparcspkr_ebus_name; - sparcspkr_dev.event = ebus_spkr_event; + sparcspkr_dev->name = "Sparc EBUS Speaker"; + sparcspkr_dev->event = ebus_spkr_event; - input_register_device(&sparcspkr_dev); + input_register_device(sparcspkr_dev); - printk(KERN_INFO "input: %s\n", sparcspkr_ebus_name); return 0; } @@ -137,15 +134,17 @@ static int __init init_isa_beep(struct sparc_isa_device *isa_dev) { beep_iobase = isa_dev->resource.start; + sparcspkr_dev = input_allocate_device(); + if (!sparcspkr_dev) + return -ENOMEM; + init_sparcspkr_struct(); - sparcspkr_dev.name = sparcspkr_isa_name; - sparcspkr_dev.event = isa_spkr_event; - sparcspkr_dev.id.bustype = BUS_ISA; + sparcspkr_dev->name = "Sparc ISA Speaker"; + sparcspkr_dev->event = isa_spkr_event; input_register_device(&sparcspkr_dev); - printk(KERN_INFO "input: %s\n", sparcspkr_isa_name); return 0; } #endif @@ -182,7 +181,7 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - input_unregister_device(&sparcspkr_dev); + input_unregister_device(sparcspkr_dev); } module_init(sparcspkr_init); From b7df3910c1298fee8ed7b9dfd2da74b85df5539c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:53 -0500 Subject: [PATCH 0938/1939] [PATCH] drivers/media: convert to dynamic input_dev allocation Input: convert drivers/media to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/media/common/ir-common.c | 1 - drivers/media/dvb/cinergyT2/cinergyT2.c | 108 +++++++++++++------- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 50 +++++---- drivers/media/dvb/dvb-usb/dvb-usb.h | 3 +- drivers/media/dvb/ttpci/av7110_ir.c | 37 ++++--- drivers/media/dvb/ttpci/budget-ci.c | 24 +++-- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 51 +++++---- drivers/media/video/bttvp.h | 2 +- drivers/media/video/cx88/cx88-input.c | 58 ++++++----- drivers/media/video/ir-kbd-gpio.c | 52 +++++----- drivers/media/video/ir-kbd-i2c.c | 33 +++--- drivers/media/video/saa7134/saa7134-input.c | 39 +++---- drivers/media/video/saa7134/saa7134.h | 2 +- 13 files changed, 268 insertions(+), 192 deletions(-) diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index a0e700d7a4a4..06f4d4686a6c 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -252,7 +252,6 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, if (ir_codes) memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); - init_input_dev(dev); dev->keycode = ir->ir_codes; dev->keycodesize = sizeof(IR_KEYTAB_TYPE); dev->keycodemax = IR_KEYTAB_SIZE; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 6db0929ef53d..a1607e7d6d6b 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -137,7 +137,8 @@ struct cinergyt2 { struct urb *stream_urb [STREAM_URB_COUNT]; #ifdef ENABLE_RC - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char phys[64]; struct work_struct rc_query_work; int rc_input_event; u32 rc_last_code; @@ -683,6 +684,7 @@ static struct dvb_device cinergyt2_fe_template = { }; #ifdef ENABLE_RC + static void cinergyt2_query_rc (void *data) { struct cinergyt2 *cinergyt2 = data; @@ -703,7 +705,7 @@ static void cinergyt2_query_rc (void *data) /* stop key repeat */ if (cinergyt2->rc_input_event != KEY_MAX) { dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); cinergyt2->rc_input_event = KEY_MAX; } @@ -722,7 +724,7 @@ static void cinergyt2_query_rc (void *data) /* keyrepeat bit -> just repeat last rc_input_event */ } else { cinergyt2->rc_input_event = KEY_MAX; - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) { + for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) { if (rc_keys[i + 0] == rc_events[n].type && rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { cinergyt2->rc_input_event = rc_keys[i + 2]; @@ -736,11 +738,11 @@ static void cinergyt2_query_rc (void *data) cinergyt2->rc_last_code != ~0) { /* emit a key-up so the double event is recognized */ dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); } dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1); cinergyt2->rc_last_code = rc_events[n].value; } @@ -752,7 +754,59 @@ static void cinergyt2_query_rc (void *data) up(&cinergyt2->sem); } -#endif + +static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) +{ + struct input_dev *input_dev; + int i; + + cinergyt2->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys)); + strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); + cinergyt2->rc_input_event = KEY_MAX; + cinergyt2->rc_last_code = ~0; + INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); + + input_dev->name = DRIVER_NAME " remote control"; + input_dev->phys = cinergyt2->phys; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + for (i = 0; ARRAY_SIZE(rc_keys); i += 3) + set_bit(rc_keys[i + 2], input_dev->keybit); + input_dev->keycodesize = 0; + input_dev->keycodemax = 0; + + input_register_device(cinergyt2->rc_input_dev); + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +} + +static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); + flush_scheduled_work(); + input_unregister_device(cinergyt2->rc_input_dev); +} + +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); +} + +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) +{ + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +} + +#else + +static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; } +static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } + +#endif /* ENABLE_RC */ static void cinergyt2_query (void *data) { @@ -789,9 +843,6 @@ static int cinergyt2_probe (struct usb_interface *intf, { struct cinergyt2 *cinergyt2; int err; -#ifdef ENABLE_RC - int i; -#endif if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { dprintk(1, "out of memory?!?\n"); @@ -846,30 +897,17 @@ static int cinergyt2_probe (struct usb_interface *intf, &cinergyt2_fe_template, cinergyt2, DVB_DEVICE_FRONTEND); -#ifdef ENABLE_RC - cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - cinergyt2->rc_input_dev.keycodesize = 0; - cinergyt2->rc_input_dev.keycodemax = 0; - cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; + err = cinergyt2_register_rc(cinergyt2); + if (err) + goto bailout; - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) - set_bit(rc_keys[i + 2], cinergyt2->rc_input_dev.keybit); - - input_register_device(&cinergyt2->rc_input_dev); - - cinergyt2->rc_input_event = KEY_MAX; - cinergyt2->rc_last_code = ~0; - - INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif return 0; bailout: dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_adapter (&cinergyt2->adapter); - cinergyt2_free_stream_urbs (cinergyt2); + dvb_unregister_adapter(&cinergyt2->adapter); + cinergyt2_free_stream_urbs(cinergyt2); kfree(cinergyt2); return -ENOMEM; } @@ -881,11 +919,7 @@ static void cinergyt2_disconnect (struct usb_interface *intf) if (down_interruptible(&cinergyt2->sem)) return; -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); - flush_scheduled_work(); - input_unregister_device(&cinergyt2->rc_input_dev); -#endif + cinergyt2_unregister_rc(cinergyt2); cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); dvb_net_release(&cinergyt2->dvbnet); @@ -908,9 +942,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) if (state.event > PM_EVENT_ON) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); -#endif + + cinergyt2_suspend_rc(cinergyt2); cancel_delayed_work(&cinergyt2->query_work); if (cinergyt2->streaming) cinergyt2_stop_stream_xfer(cinergyt2); @@ -938,9 +971,8 @@ static int cinergyt2_resume (struct usb_interface *intf) schedule_delayed_work(&cinergyt2->query_work, HZ/2); } -#ifdef ENABLE_RC - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif + cinergyt2_resume_rc(cinergyt2); + up(&cinergyt2->sem); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index fc7800f1743e..e5c6d9835e06 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -39,9 +39,9 @@ static void dvb_usb_read_remote_control(void *data) d->last_event = event; case REMOTE_KEY_REPEAT: deb_rc("key repeated\n"); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); break; default: break; @@ -53,8 +53,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("NO KEY PRESSED\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("releasing event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); } d->last_state = REMOTE_NO_KEY_PRESSED; d->last_event = 0; @@ -63,8 +63,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY PRESSED\n"); deb_rc("pressing event %d\n",event); - input_event(&d->rc_input_dev, EV_KEY, event, 1); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); d->last_event = event; d->last_state = REMOTE_KEY_PRESSED; @@ -73,8 +73,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY_REPEAT\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("repeating event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); d->last_state = REMOTE_KEY_REPEAT; } default: @@ -89,24 +89,30 @@ static void dvb_usb_read_remote_control(void *data) int dvb_usb_remote_init(struct dvb_usb_device *d) { int i; + if (d->props.rc_key_map == NULL || d->props.rc_query == NULL || dvb_usb_disable_rc_polling) return 0; - /* Initialise the remote-control structures.*/ - init_input_dev(&d->rc_input_dev); + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - d->rc_input_dev.evbit[0] = BIT(EV_KEY); - d->rc_input_dev.keycodesize = sizeof(unsigned char); - d->rc_input_dev.keycodemax = KEY_MAX; - d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev = input_allocate_device(); + if (!d->rc_input_dev) + return -ENOMEM; + + d->rc_input_dev->evbit[0] = BIT(EV_KEY); + d->rc_input_dev->keycodesize = sizeof(unsigned char); + d->rc_input_dev->keycodemax = KEY_MAX; + d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev->phys = d->rc_phys; /* set the bits for the keys */ - deb_rc("key map size: %d\n",d->props.rc_key_map_size); + deb_rc("key map size: %d\n", d->props.rc_key_map_size); for (i = 0; i < d->props.rc_key_map_size; i++) { deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i); - set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit); + set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit); } /* Start the remote-control polling. */ @@ -114,14 +120,14 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) d->props.rc_interval = 100; /* default */ /* setting these two values to non-zero, we have to manage key repeats */ - d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval; - d->rc_input_dev.rep[REP_DELAY] = d->props.rc_interval + 150; + d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval; + d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; - input_register_device(&d->rc_input_dev); + input_register_device(d->rc_input_dev); INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); - info("schedule remote query interval to %d msecs.",d->props.rc_interval); + info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); d->state |= DVB_USB_STATE_REMOTE; @@ -134,7 +140,7 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) if (d->state & DVB_USB_STATE_REMOTE) { cancel_delayed_work(&d->rc_query_work); flush_scheduled_work(); - input_unregister_device(&d->rc_input_dev); + input_unregister_device(d->rc_input_dev); } d->state &= ~DVB_USB_STATE_REMOTE; return 0; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 0e4f1035b0dd..b4a1a98006c7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -300,7 +300,8 @@ struct dvb_usb_device { int (*fe_init) (struct dvb_frontend *); /* remote control */ - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; struct work_struct rc_query_work; u32 last_event; int last_state; diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 357a3728ec68..f5e59fc924af 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -15,7 +15,7 @@ static int av_cnt; static struct av7110 *av_list[4]; -static struct input_dev input_dev; +static struct input_dev *input_dev; static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, @@ -43,10 +43,10 @@ static u16 key_map [256] = { static void av7110_emit_keyup(unsigned long data) { - if (!data || !test_bit(data, input_dev.key)) + if (!data || !test_bit(data, input_dev->key)) return; - input_event(&input_dev, EV_KEY, data, !!0); + input_event(input_dev, EV_KEY, data, !!0); } @@ -112,13 +112,13 @@ static void av7110_emit_key(unsigned long parm) if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); if (keyup_timer.data != keycode || new_toggle != old_toggle) { - input_event(&input_dev, EV_KEY, keyup_timer.data, !!0); - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keyup_timer.data, !!0); + input_event(input_dev, EV_KEY, keycode, !0); } else - input_event(&input_dev, EV_KEY, keycode, 2); + input_event(input_dev, EV_KEY, keycode, 2); } else - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keycode, !0); keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.data = keycode; @@ -132,13 +132,13 @@ static void input_register_keys(void) { int i; - memset(input_dev.keybit, 0, sizeof(input_dev.keybit)); + memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - for (i = 0; i < sizeof(key_map) / sizeof(key_map[0]); i++) { + for (i = 0; i < ARRAY_SIZE(key_map); i++) { if (key_map[i] > KEY_MAX) key_map[i] = 0; else if (key_map[i] > KEY_RESERVED) - set_bit(key_map[i], input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); } } @@ -216,12 +216,17 @@ int __init av7110_ir_init(struct av7110 *av7110) init_timer(&keyup_timer); keyup_timer.data = 0; - input_dev.name = "DVB on-card IR receiver"; - set_bit(EV_KEY, input_dev.evbit); - set_bit(EV_REP, input_dev.evbit); + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "DVB on-card IR receiver"; + + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_REP, input_dev->evbit); input_register_keys(); - input_register_device(&input_dev); - input_dev.timer.function = input_repeat_key; + input_register_device(input_dev); + input_dev->timer.function = input_repeat_key; e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); if (e) { @@ -256,7 +261,7 @@ void __exit av7110_ir_exit(struct av7110 *av7110) if (av_cnt == 1) { del_timer_sync(&keyup_timer); remove_proc_entry("av7110_ir", NULL); - input_unregister_device(&input_dev); + input_unregister_device(input_dev); } av_cnt--; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 2980db3ef22f..51c30ba68140 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -64,7 +64,7 @@ struct budget_ci { struct budget budget; - struct input_dev input_dev; + struct input_dev *input_dev; struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct ciintf_irq_tasklet; int slot_status; @@ -145,7 +145,7 @@ static void msp430_ir_debounce(unsigned long data) static void msp430_ir_interrupt(unsigned long data) { struct budget_ci *budget_ci = (struct budget_ci *) data; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; unsigned int code = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; @@ -181,25 +181,27 @@ static void msp430_ir_interrupt(unsigned long data) static int msp430_ir_init(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; + struct input_dev *input_dev; int i; - memset(&budget_ci->input_dev, 0, sizeof(struct input_dev)); + budget_ci->input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name); - budget_ci->input_dev.name = budget_ci->ir_dev_name; - set_bit(EV_KEY, budget_ci->input_dev.evbit); + input_dev->name = budget_ci->ir_dev_name; - for (i = 0; i < sizeof(key_map) / sizeof(*key_map); i++) + set_bit(EV_KEY, input_dev->evbit); + for (i = 0; i < ARRAY_SIZE(key_map); i++) if (key_map[i]) - set_bit(key_map[i], budget_ci->input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); - input_register_device(&budget_ci->input_dev); + input_register_device(budget_ci->input_dev); - budget_ci->input_dev.timer.function = msp430_ir_debounce; + input_dev->timer.function = msp430_ir_debounce; saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); return 0; @@ -208,7 +210,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) static void msp430_ir_deinit(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 3d08fc83a754..832d179f26fa 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -152,7 +152,8 @@ struct ttusb_dec { struct list_head filter_info_list; spinlock_t filter_info_list_lock; - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; int active; /* Loaded successfully */ }; @@ -235,9 +236,9 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs) * this should/could be added later ... * for now lets report each signal as a key down and up*/ dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0); - input_sync(&dec->rc_input_dev); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); + input_sync(dec->rc_input_dev); } exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -1181,29 +1182,38 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) (unsigned long)dec); } -static void ttusb_init_rc( struct ttusb_dec *dec) +static int ttusb_init_rc(struct ttusb_dec *dec) { + struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; int i; - init_input_dev(&dec->rc_input_dev); + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); - dec->rc_input_dev.name = "ttusb_dec remote control"; - dec->rc_input_dev.evbit[0] = BIT(EV_KEY); - dec->rc_input_dev.keycodesize = sizeof(u16); - dec->rc_input_dev.keycodemax = 0x1a; - dec->rc_input_dev.keycode = rc_keys; + dec->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; - for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) - set_bit(rc_keys[i], dec->rc_input_dev.keybit); + input_dev->name = "ttusb_dec remote control"; + input_dev->phys = dec->rc_phys; + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keycodesize = sizeof(u16); + input_dev->keycodemax = 0x1a; + input_dev->keycode = rc_keys; - input_register_device(&dec->rc_input_dev); + for (i = 0; i < ARRAY_SIZE(rc_keys); i++) + set_bit(rc_keys[i], input_dev->keybit); - if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) { + input_register_device(input_dev); + + if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); - } + /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); + + return 0; } static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) @@ -1513,7 +1523,7 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) * As the irq is submitted after the interface is changed, * this is the best method i figured out. * Any others?*/ - if(dec->interface == TTUSB_DEC_INTERFACE_IN) + if (dec->interface == TTUSB_DEC_INTERFACE_IN) usb_kill_urb(dec->irq_urb); usb_free_urb(dec->irq_urb); @@ -1521,7 +1531,10 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) usb_buffer_free(dec->udev,IRQ_PACKET_SIZE, dec->irq_buffer, dec->irq_dma_handle); - input_unregister_device(&dec->rc_input_dev); + if (dec->rc_input_dev) { + input_unregister_device(dec->rc_input_dev); + dec->rc_input_dev = NULL; + } } @@ -1659,7 +1672,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); - if(enable_rc) + if (enable_rc) ttusb_init_rc(dec); return 0; diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 7a312f79340a..e0e7c7a84bc5 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -240,7 +240,7 @@ struct bttv_pll_info { /* for gpio-connected remote control */ struct bttv_input { - struct input_dev dev; + struct input_dev *dev; struct ir_input_state ir; char name[32]; char phys[32]; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d81b21d6e05d..c27fe4c36f69 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -260,7 +260,7 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { struct cx88_IR { struct cx88_core *core; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; char name[32]; char phys[32]; @@ -315,23 +315,23 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else { /* can't distinguish keydown/up :-/ */ - ir_input_keydown(&ir->input, &ir->ir, data, data); - ir_input_nokey(&ir->input, &ir->ir); + ir_input_keydown(ir->input, &ir->ir, data, data); + ir_input_nokey(ir->input, &ir->ir); } } @@ -357,13 +357,19 @@ static void cx88_ir_work(void *data) int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) { struct cx88_IR *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir), GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir, 0, sizeof(*ir)); + } + + ir->input = input_dev; /* detect & configure */ switch (core->board) { @@ -425,6 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) if (NULL == ir_codes) { kfree(ir); + input_free_device(input_dev); return -ENODEV; } @@ -433,19 +440,19 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) cx88_boards[core->board].name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); - ir->input.name = ir->name; - ir->input.phys = ir->phys; - ir->input.id.bustype = BUS_PCI; - ir->input.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (pci->subsystem_vendor) { - ir->input.id.vendor = pci->subsystem_vendor; - ir->input.id.product = pci->subsystem_device; + input_dev->id.vendor = pci->subsystem_vendor; + input_dev->id.product = pci->subsystem_device; } else { - ir->input.id.vendor = pci->vendor; - ir->input.id.product = pci->device; + input_dev->id.vendor = pci->vendor; + input_dev->id.product = pci->device; } - ir->input.dev = &pci->dev; + input_dev->cdev.dev = &pci->dev; /* record handles to ourself */ ir->core = core; @@ -465,8 +472,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } /* all done */ - input_register_device(&ir->input); - printk("%s: registered IR remote control\n", core->name); + input_register_device(ir->input); return 0; } @@ -484,7 +490,7 @@ int cx88_ir_fini(struct cx88_core *core) flush_scheduled_work(); } - input_unregister_device(&ir->input); + input_unregister_device(ir->input); kfree(ir); /* done */ @@ -515,7 +521,7 @@ void cx88_ir_irq(struct cx88_core *core) if (!ir->scount) { /* nothing to sample */ if (ir->ir.keypressed && time_after(jiffies, ir->release)) - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); return; } @@ -557,7 +563,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); - ir_input_keydown(&ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); + ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); ir->release = jiffies + msecs_to_jiffies(120); break; case CX88_BOARD_HAUPPAUGE: @@ -566,7 +572,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) break; - ir_input_keydown(&ir->input, &ir->ir, ircode & 0x3f, ircode); + ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f, ircode); ir->release = jiffies + msecs_to_jiffies(120); break; } diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index cf292da8fdd5..234151e48edc 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -158,7 +158,7 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = { struct IR { struct bttv_sub_device *sub; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; char name[32]; char phys[32]; @@ -217,23 +217,23 @@ static void ir_handle_key(struct IR *ir) if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else { /* can't disturgissh keydown/up :-/ */ - ir_input_keydown(&ir->input,&ir->ir,data,data); - ir_input_nokey(&ir->input,&ir->ir); + ir_input_keydown(ir->input, &ir->ir, data, data); + ir_input_nokey(ir->input, &ir->ir); } } @@ -268,13 +268,17 @@ static int ir_probe(struct device *dev) { struct bttv_sub_device *sub = to_bttv_sub_dev(dev); struct IR *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir),GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } /* detect & configure */ switch (sub->core->type) { @@ -328,6 +332,7 @@ static int ir_probe(struct device *dev) } if (NULL == ir_codes) { kfree(ir); + input_free_device(input_dev); return -ENODEV; } @@ -341,19 +346,19 @@ static int ir_probe(struct device *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(sub->core->pci)); - ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); - ir->input.name = ir->name; - ir->input.phys = ir->phys; - ir->input.id.bustype = BUS_PCI; - ir->input.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (sub->core->pci->subsystem_vendor) { - ir->input.id.vendor = sub->core->pci->subsystem_vendor; - ir->input.id.product = sub->core->pci->subsystem_device; + input_dev->id.vendor = sub->core->pci->subsystem_vendor; + input_dev->id.product = sub->core->pci->subsystem_device; } else { - ir->input.id.vendor = sub->core->pci->vendor; - ir->input.id.product = sub->core->pci->device; + input_dev->id.vendor = sub->core->pci->vendor; + input_dev->id.product = sub->core->pci->device; } - ir->input.dev = &sub->core->pci->dev; + input_dev->cdev.dev = &sub->core->pci->dev; if (ir->polling) { INIT_WORK(&ir->work, ir_work, ir); @@ -364,9 +369,8 @@ static int ir_probe(struct device *dev) } /* all done */ - dev_set_drvdata(dev,ir); - input_register_device(&ir->input); - printk(DEVNAME ": %s detected at %s\n",ir->input.name,ir->input.phys); + dev_set_drvdata(dev, ir); + input_register_device(ir->input); return 0; } @@ -380,7 +384,7 @@ static int ir_remove(struct device *dev) flush_scheduled_work(); } - input_unregister_device(&ir->input); + input_unregister_device(ir->input); kfree(ir); return 0; } diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 67105b9804a2..9703d3d351f9 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -121,10 +121,9 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { }; -struct IR; struct IR { struct i2c_client c; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; struct work_struct work; @@ -271,9 +270,9 @@ static void ir_key_poll(struct IR *ir) } if (0 == rc) { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } else { - ir_input_keydown(&ir->input,&ir->ir, ir_key, ir_raw); + ir_input_keydown(ir->input, &ir->ir, ir_key, ir_raw); } } @@ -318,11 +317,18 @@ static int ir_attach(struct i2c_adapter *adap, int addr, char *name; int ir_type; struct IR *ir; + struct input_dev *input_dev; - if (NULL == (ir = kmalloc(sizeof(struct IR),GFP_KERNEL))) + ir = kzalloc(sizeof(struct IR), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } + ir->c = client_template; + ir->input = input_dev; i2c_set_clientdata(&ir->c, ir); ir->c.adapter = adap; @@ -375,13 +381,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->c.dev.bus_id); /* init + register input device */ - ir_input_init(&ir->input,&ir->ir,ir_type,ir_codes); - ir->input.id.bustype = BUS_I2C; - ir->input.name = ir->c.name; - ir->input.phys = ir->phys; - input_register_device(&ir->input); - printk(DEVNAME ": %s detected at %s [%s]\n", - ir->input.name,ir->input.phys,adap->name); + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->id.bustype = BUS_I2C; + input_dev->name = ir->c.name; + input_dev->phys = ir->phys; + + input_register_device(ir->input); /* start polling via eventd */ INIT_WORK(&ir->work, ir_work, ir); @@ -402,7 +407,7 @@ static int ir_detach(struct i2c_client *client) flush_scheduled_work(); /* unregister devices */ - input_unregister_device(&ir->input); + input_unregister_device(ir->input); i2c_detach_client(&ir->c); /* free memory */ diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 1f456c4d76f2..242cb235cf92 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -425,9 +425,9 @@ static int build_key(struct saa7134_dev *dev) if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - ir_input_keydown(&ir->dev,&ir->ir,data,data); + ir_input_keydown(ir->dev, &ir->ir, data, data); } else { - ir_input_nokey(&ir->dev,&ir->ir); + ir_input_nokey(ir->dev, &ir->ir); } return 0; } @@ -456,6 +456,7 @@ static void saa7134_input_timer(unsigned long data) int saa7134_input_init1(struct saa7134_dev *dev) { struct saa7134_ir *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; u32 mask_keycode = 0; u32 mask_keydown = 0; @@ -535,10 +536,13 @@ int saa7134_input_init1(struct saa7134_dev *dev) return -ENODEV; } - ir = kmalloc(sizeof(*ir),GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } /* init hardware-specific stuff */ ir->mask_keycode = mask_keycode; @@ -552,19 +556,19 @@ int saa7134_input_init1(struct saa7134_dev *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); - ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes); - ir->dev.name = ir->name; - ir->dev.phys = ir->phys; - ir->dev.id.bustype = BUS_PCI; - ir->dev.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (dev->pci->subsystem_vendor) { - ir->dev.id.vendor = dev->pci->subsystem_vendor; - ir->dev.id.product = dev->pci->subsystem_device; + input_dev->id.vendor = dev->pci->subsystem_vendor; + input_dev->id.product = dev->pci->subsystem_device; } else { - ir->dev.id.vendor = dev->pci->vendor; - ir->dev.id.product = dev->pci->device; + input_dev->id.vendor = dev->pci->vendor; + input_dev->id.product = dev->pci->device; } - ir->dev.dev = &dev->pci->dev; + input_dev->cdev.dev = &dev->pci->dev; /* all done */ dev->remote = ir; @@ -576,8 +580,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) add_timer(&ir->timer); } - input_register_device(&dev->remote->dev); - printk("%s: registered input device for IR\n",dev->name); + input_register_device(ir->dev); return 0; } @@ -586,9 +589,9 @@ void saa7134_input_fini(struct saa7134_dev *dev) if (NULL == dev->remote) return; - input_unregister_device(&dev->remote->dev); if (dev->remote->polling) del_timer_sync(&dev->remote->timer); + input_unregister_device(dev->remote->dev); kfree(dev->remote); dev->remote = NULL; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3ea09142ec9c..860b89530e2a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -351,7 +351,7 @@ struct saa7134_oss { /* IR input */ struct saa7134_ir { - struct input_dev dev; + struct input_dev *dev; struct ir_input_state ir; char name[32]; char phys[32]; From c7f7a569d9b4ea7c53ab6fcd1377895312d8372b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:41 -0500 Subject: [PATCH 0939/1939] [PATCH] Input: convert drivers/macintosh to dynamic input_dev allocation Input: convert drivers/macntosh to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/macintosh/adbhid.c | 218 +++++++++++++++++++----------------- drivers/macintosh/mac_hid.c | 40 ++++--- 2 files changed, 136 insertions(+), 122 deletions(-) diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index db654e8bd67e..cdb6d0283195 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -206,7 +206,7 @@ u8 adb_to_linux_keycodes[128] = { }; struct adbhid { - struct input_dev input; + struct input_dev *input; int id; int default_id; int original_handler_id; @@ -291,10 +291,10 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) switch (keycode) { case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ - input_regs(&ahid->input, regs); - input_report_key(&ahid->input, KEY_CAPSLOCK, 1); - input_report_key(&ahid->input, KEY_CAPSLOCK, 0); - input_sync(&ahid->input); + input_regs(ahid->input, regs); + input_report_key(ahid->input, KEY_CAPSLOCK, 1); + input_report_key(ahid->input, KEY_CAPSLOCK, 0); + input_sync(ahid->input); return; #ifdef CONFIG_PPC_PMAC case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ @@ -347,10 +347,10 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) } if (adbhid[id]->keycode[keycode]) { - input_regs(&adbhid[id]->input, regs); - input_report_key(&adbhid[id]->input, + input_regs(adbhid[id]->input, regs); + input_report_key(adbhid[id]->input, adbhid[id]->keycode[keycode], !up_flag); - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } else printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, up_flag ? "released" : "pressed"); @@ -441,20 +441,20 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo break; } - input_regs(&adbhid[id]->input, regs); + input_regs(adbhid[id]->input, regs); - input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); - input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD) - input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); - input_report_rel(&adbhid[id]->input, REL_X, + input_report_rel(adbhid[id]->input, REL_X, ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); - input_report_rel(&adbhid[id]->input, REL_Y, + input_report_rel(adbhid[id]->input, REL_Y, ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } static void @@ -467,7 +467,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto return; } - input_regs(&adbhid[id]->input, regs); + input_regs(adbhid[id]->input, regs); switch (adbhid[id]->original_handler_id) { default: @@ -477,19 +477,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto switch (data[1] & 0x0f) { case 0x0: /* microphone */ - input_report_key(&adbhid[id]->input, KEY_SOUND, down); + input_report_key(adbhid[id]->input, KEY_SOUND, down); break; case 0x1: /* mute */ - input_report_key(&adbhid[id]->input, KEY_MUTE, down); + input_report_key(adbhid[id]->input, KEY_MUTE, down); break; case 0x2: /* volume decrease */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down); break; case 0x3: /* volume increase */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down); break; default: @@ -513,19 +513,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto switch (data[1] & 0x0f) { case 0x8: /* mute */ - input_report_key(&adbhid[id]->input, KEY_MUTE, down); + input_report_key(adbhid[id]->input, KEY_MUTE, down); break; case 0x7: /* volume decrease */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down); break; case 0x6: /* volume increase */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down); break; case 0xb: /* eject */ - input_report_key(&adbhid[id]->input, KEY_EJECTCD, down); + input_report_key(adbhid[id]->input, KEY_EJECTCD, down); break; case 0xa: /* brightness decrease */ @@ -539,7 +539,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto } } #endif /* CONFIG_PMAC_BACKLIGHT */ - input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); + input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); break; case 0x9: /* brightness increase */ @@ -553,19 +553,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto } } #endif /* CONFIG_PMAC_BACKLIGHT */ - input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down); + input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down); break; case 0xc: /* videomode switch */ - input_report_key(&adbhid[id]->input, KEY_SWITCHVIDEOMODE, down); + input_report_key(adbhid[id]->input, KEY_SWITCHVIDEOMODE, down); break; case 0xd: /* keyboard illumination toggle */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMTOGGLE, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMTOGGLE, down); break; case 0xe: /* keyboard illumination decrease */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMDOWN, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMDOWN, down); break; case 0xf: @@ -573,7 +573,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0x8f: case 0x0f: /* keyboard illumination increase */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMUP, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMUP, down); break; case 0x7f: @@ -596,7 +596,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto break; } - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } static struct adb_request led_request; @@ -683,7 +683,7 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) int i; for (i = 1; i < 16; i++) { if (adbhid[i]) - del_timer_sync(&adbhid[i]->input.timer); + del_timer_sync(&adbhid[i]->input->timer); } } @@ -699,153 +699,163 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) return NOTIFY_DONE; } -static void +static int adbhid_input_register(int id, int default_id, int original_handler_id, int current_handler_id, int mouse_kind) { + struct adbhid *hid; + struct input_dev *input_dev; + int err; int i; if (adbhid[id]) { printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); - return; + return -EEXIST; } - if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) - return; + adbhid[id] = hid = kzalloc(sizeof(struct adbhid), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!hid || !input_dev) { + err = -ENOMEM; + goto fail; - memset(adbhid[id], 0, sizeof(struct adbhid)); - sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); + } - init_input_dev(&adbhid[id]->input); + sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); - adbhid[id]->id = default_id; - adbhid[id]->original_handler_id = original_handler_id; - adbhid[id]->current_handler_id = current_handler_id; - adbhid[id]->mouse_kind = mouse_kind; - adbhid[id]->flags = 0; - adbhid[id]->input.private = adbhid[id]; - adbhid[id]->input.name = adbhid[id]->name; - adbhid[id]->input.phys = adbhid[id]->phys; - adbhid[id]->input.id.bustype = BUS_ADB; - adbhid[id]->input.id.vendor = 0x0001; - adbhid[id]->input.id.product = (id << 12) | (default_id << 8) | original_handler_id; - adbhid[id]->input.id.version = 0x0100; + hid->id = default_id; + hid->original_handler_id = original_handler_id; + hid->current_handler_id = current_handler_id; + hid->mouse_kind = mouse_kind; + hid->flags = 0; + input_dev->private = hid; + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->id.bustype = BUS_ADB; + input_dev->id.vendor = 0x0001; + input_dev->id.product = (id << 12) | (default_id << 8) | original_handler_id; + input_dev->id.version = 0x0100; switch (default_id) { case ADB_KEYBOARD: - if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { - kfree(adbhid[id]); - return; + hid->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL); + if (!hid->keycode) { + err = -ENOMEM; + goto fail; } - sprintf(adbhid[id]->name, "ADB keyboard"); + sprintf(hid->name, "ADB keyboard"); - memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + memcpy(hid->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); printk(KERN_INFO "Detected ADB keyboard, type "); switch (original_handler_id) { default: printk(".\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_UNKNOWN; + input_dev->id.version = ADB_KEYBOARD_UNKNOWN; break; case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: case 0xC0: case 0xC3: case 0xC6: printk("ANSI.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_ANSI; + input_dev->id.version = ADB_KEYBOARD_ANSI; break; case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: case 0xC4: case 0xC7: printk("ISO, swapping keys.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_ISO; - i = adbhid[id]->keycode[10]; - adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; - adbhid[id]->keycode[50] = i; + input_dev->id.version = ADB_KEYBOARD_ISO; + i = hid->keycode[10]; + hid->keycode[10] = hid->keycode[50]; + hid->keycode[50] = i; break; case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: printk("JIS.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_JIS; + input_dev->id.version = ADB_KEYBOARD_JIS; break; } for (i = 0; i < 128; i++) - if (adbhid[id]->keycode[i]) - set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); + if (hid->keycode[i]) + set_bit(hid->keycode[i], input_dev->keybit); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); - adbhid[id]->input.event = adbhid_kbd_event; - adbhid[id]->input.keycodemax = 127; - adbhid[id]->input.keycodesize = 1; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + input_dev->event = adbhid_kbd_event; + input_dev->keycodemax = 127; + input_dev->keycodesize = 1; break; case ADB_MOUSE: - sprintf(adbhid[id]->name, "ADB mouse"); + sprintf(hid->name, "ADB mouse"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); break; case ADB_MISC: switch (original_handler_id) { case 0x02: /* Adjustable keyboard button device */ - sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - set_bit(KEY_SOUND, adbhid[id]->input.keybit); - set_bit(KEY_MUTE, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + sprintf(hid->name, "ADB adjustable keyboard buttons"); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_SOUND, input_dev->keybit); + set_bit(KEY_MUTE, input_dev->keybit); + set_bit(KEY_VOLUMEUP, input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, input_dev->keybit); break; case 0x1f: /* Powerbook button device */ - sprintf(adbhid[id]->name, "ADB Powerbook buttons"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - set_bit(KEY_MUTE, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); - set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit); - set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit); - set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); - set_bit(KEY_SWITCHVIDEOMODE, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMTOGGLE, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMDOWN, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMUP, adbhid[id]->input.keybit); + sprintf(hid->name, "ADB Powerbook buttons"); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_MUTE, input_dev->keybit); + set_bit(KEY_VOLUMEUP, input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, input_dev->keybit); + set_bit(KEY_BRIGHTNESSUP, input_dev->keybit); + set_bit(KEY_BRIGHTNESSDOWN, input_dev->keybit); + set_bit(KEY_EJECTCD, input_dev->keybit); + set_bit(KEY_SWITCHVIDEOMODE, input_dev->keybit); + set_bit(KEY_KBDILLUMTOGGLE, input_dev->keybit); + set_bit(KEY_KBDILLUMDOWN, input_dev->keybit); + set_bit(KEY_KBDILLUMUP, input_dev->keybit); break; } - if (adbhid[id]->name[0]) + if (hid->name[0]) break; /* else fall through */ default: printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); - kfree(adbhid[id]); - return; + err = -ENODEV; + goto fail; } - adbhid[id]->input.keycode = adbhid[id]->keycode; + input_dev->keycode = hid->keycode; - input_register_device(&adbhid[id]->input); - - printk(KERN_INFO "input: %s on %s\n", - adbhid[id]->name, adbhid[id]->phys); + input_register_device(input_dev); if (default_id == ADB_KEYBOARD) { /* HACK WARNING!! This should go away as soon there is an utility * to control that for event devices. */ - adbhid[id]->input.rep[REP_DELAY] = 500; /* input layer default: 250 */ - adbhid[id]->input.rep[REP_PERIOD] = 66; /* input layer default: 33 */ + input_dev->rep[REP_DELAY] = 500; /* input layer default: 250 */ + input_dev->rep[REP_PERIOD] = 66; /* input layer default: 33 */ } + + return 0; + + fail: input_free_device(input_dev); + kfree(hid); + adbhid[id] = NULL; + return err; } static void adbhid_input_unregister(int id) { - input_unregister_device(&adbhid[id]->input); + input_unregister_device(adbhid[id]->input); if (adbhid[id]->keycode) kfree(adbhid[id]->keycode); kfree(adbhid[id]); @@ -858,7 +868,7 @@ adbhid_input_reregister(int id, int default_id, int org_handler_id, int cur_handler_id, int mk) { if (adbhid[id]) { - if (adbhid[id]->input.id.product != + if (adbhid[id]->input->id.product != ((id << 12)|(default_id << 8)|org_handler_id)) { adbhid_input_unregister(id); adbhid_input_register(id, default_id, org_handler_id, diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 5ad3a5a9eb7f..a66636116f0b 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -16,8 +16,8 @@ #include -static struct input_dev emumousebtn; -static void emumousebtn_input_register(void); +static struct input_dev *emumousebtn; +static int emumousebtn_input_register(void); static int mouse_emulate_buttons = 0; static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ @@ -90,10 +90,10 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) && (keycode == mouse_button2_keycode || keycode == mouse_button3_keycode)) { if (mouse_emulate_buttons == 1) { - input_report_key(&emumousebtn, + input_report_key(emumousebtn, keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, down); - input_sync(&emumousebtn); + input_sync(emumousebtn); return 1; } mouse_last_keycode = down ? keycode : 0; @@ -105,30 +105,34 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons); -static void emumousebtn_input_register(void) +static int emumousebtn_input_register(void) { - emumousebtn.name = "Macintosh mouse button emulation"; + emumousebtn = input_allocate_device(); + if (!emumousebtn) + return -ENOMEM; - init_input_dev(&emumousebtn); + emumousebtn->name = "Macintosh mouse button emulation"; + emumousebtn->id.bustype = BUS_ADB; + emumousebtn->id.vendor = 0x0001; + emumousebtn->id.product = 0x0001; + emumousebtn->id.version = 0x0100; - emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + emumousebtn->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn->relbit[0] = BIT(REL_X) | BIT(REL_Y); - emumousebtn.id.bustype = BUS_ADB; - emumousebtn.id.vendor = 0x0001; - emumousebtn.id.product = 0x0001; - emumousebtn.id.version = 0x0100; + input_register_device(emumousebtn); - input_register_device(&emumousebtn); - - printk(KERN_INFO "input: Macintosh mouse button emulation\n"); + return 0; } int __init mac_hid_init(void) { + int err; - emumousebtn_input_register(); + err = emumousebtn_input_register(); + if (err) + return err; #if defined(CONFIG_SYSCTL) mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); From 0259567ad60df13a55583b84d2cddb5526705907 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:42 -0500 Subject: [PATCH 0940/1939] [PATCH] Input: convert konicawc to dynamic input_dev allocation Input: convert konicawc to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/konicawc.c | 89 ++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c index 20ac9e1069d4..9fe2c2710d13 100644 --- a/drivers/usb/media/konicawc.c +++ b/drivers/usb/media/konicawc.c @@ -119,7 +119,7 @@ struct konicawc { int yplanesz; /* Number of bytes in the Y plane */ unsigned int buttonsts:1; #ifdef CONFIG_INPUT - struct input_dev input; + struct input_dev *input; char input_physname[64]; #endif }; @@ -218,6 +218,57 @@ static void konicawc_adjust_picture(struct uvd *uvd) konicawc_camera_on(uvd); } +#ifdef CONFIG_INPUT + +static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) +{ + struct input_dev *input_dev; + + usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); + strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); + + cam->input = input_dev = input_allocate_device(); + if (!input_dev) { + warn("Not enough memory for camera's input device\n"); + return; + } + + input_dev->name = "Konicawc snapshot button"; + input_dev->phys = cam->input_physname; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &dev->dev; + + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); + + input_dev->private = cam; + + input_register_device(cam->input); +} + +static void konicawc_unregister_input(struct konicawc *cam) +{ + if (cam->input) { + input_unregister_device(cam->input); + cam->input = NULL; + } +} + +static void konicawc_report_buttonstat(struct konicawc *cam) +{ + if (cam->input) { + input_report_key(cam->input, BTN_0, cam->buttonsts); + input_sync(cam->input); + } +} + +#else + +static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { } +static inline void konicawc_unregister_input(struct konicawc *cam) { } +static inline void konicawc_report_buttonstat(struct konicawc *cam) { } + +#endif /* CONFIG_INPUT */ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) { @@ -273,10 +324,7 @@ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct ur if(button != cam->buttonsts) { DEBUG(2, "button: %sclicked", button ? "" : "un"); cam->buttonsts = button; -#ifdef CONFIG_INPUT - input_report_key(&cam->input, BTN_0, cam->buttonsts); - input_sync(&cam->input); -#endif + konicawc_report_buttonstat(cam); } if(sts == 0x01) { /* drop frame */ @@ -645,9 +693,9 @@ static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) RingQueue_Flush(&uvd->dp); cam->lastframe = -2; if(uvd->curframe != -1) { - uvd->frame[uvd->curframe].curline = 0; - uvd->frame[uvd->curframe].seqRead_Length = 0; - uvd->frame[uvd->curframe].seqRead_Index = 0; + uvd->frame[uvd->curframe].curline = 0; + uvd->frame[uvd->curframe].seqRead_Length = 0; + uvd->frame[uvd->curframe].seqRead_Index = 0; } konicawc_start_data(uvd); @@ -718,7 +766,6 @@ static void konicawc_configure_video(struct uvd *uvd) DEBUG(1, "setting initial values"); } - static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) { struct usb_device *dev = interface_to_usbdev(intf); @@ -839,21 +886,8 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id err("usbvideo_RegisterVideoDevice() failed."); uvd = NULL; } -#ifdef CONFIG_INPUT - /* Register input device for button */ - memset(&cam->input, 0, sizeof(struct input_dev)); - cam->input.name = "Konicawc snapshot button"; - cam->input.private = cam; - cam->input.evbit[0] = BIT(EV_KEY); - cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0); - usb_to_input_id(dev, &cam->input.id); - input_register_device(&cam->input); - - usb_make_path(dev, cam->input_physname, 56); - strcat(cam->input_physname, "/input0"); - cam->input.phys = cam->input_physname; - info("konicawc: %s on %s\n", cam->input.name, cam->input.phys); -#endif + + konicawc_register_input(cam, dev); } if (uvd) { @@ -869,10 +903,9 @@ static void konicawc_free_uvd(struct uvd *uvd) int i; struct konicawc *cam = (struct konicawc *)uvd->user_data; -#ifdef CONFIG_INPUT - input_unregister_device(&cam->input); -#endif - for (i=0; i < USBVIDEO_NUMSBUF; i++) { + konicawc_unregister_input(cam); + + for (i = 0; i < USBVIDEO_NUMSBUF; i++) { usb_free_urb(cam->sts_urb[i]); cam->sts_urb[i] = NULL; } From 17dd3f0f7aa729a042af5d3318ff9b3e7781b45b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:52 -0500 Subject: [PATCH 0941/1939] [PATCH] drivers/input/joystick: convert to dynamic input_dev allocation Input: convert drivers/input/joystick to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/adi.c | 93 ++-- drivers/input/joystick/amijoy.c | 89 ++-- drivers/input/joystick/analog.c | 96 ++--- drivers/input/joystick/cobra.c | 74 ++-- drivers/input/joystick/db9.c | 288 ++++++++----- drivers/input/joystick/gamecon.c | 408 ++++++++++-------- drivers/input/joystick/gf2k.c | 69 +-- drivers/input/joystick/grip.c | 91 ++-- drivers/input/joystick/grip_mp.c | 149 ++++--- drivers/input/joystick/guillemot.c | 51 ++- drivers/input/joystick/iforce/iforce-main.c | 106 +++-- .../input/joystick/iforce/iforce-packets.c | 5 +- drivers/input/joystick/iforce/iforce-serio.c | 10 +- drivers/input/joystick/iforce/iforce-usb.c | 22 +- drivers/input/joystick/iforce/iforce.h | 2 +- drivers/input/joystick/interact.c | 53 +-- drivers/input/joystick/magellan.c | 75 ++-- drivers/input/joystick/sidewinder.c | 70 +-- drivers/input/joystick/spaceball.c | 82 ++-- drivers/input/joystick/spaceorb.c | 82 ++-- drivers/input/joystick/stinger.c | 73 ++-- drivers/input/joystick/tmdc.c | 324 ++++++++------ drivers/input/joystick/turbografx.c | 229 ++++++---- drivers/input/joystick/twidjoy.c | 120 +++--- drivers/input/joystick/warrior.c | 81 ++-- 25 files changed, 1486 insertions(+), 1256 deletions(-) diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index cf35ae638a0d..9d95459f4bcb 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL"); #define ADI_MIN_LENGTH 8 #define ADI_MIN_LEN_LENGTH 10 #define ADI_MIN_ID_LENGTH 66 -#define ADI_MAX_NAME_LENGTH 48 +#define ADI_MAX_NAME_LENGTH 64 #define ADI_MAX_CNAME_LENGTH 16 #define ADI_MAX_PHYS_LENGTH 64 @@ -106,7 +106,7 @@ static struct { */ struct adi { - struct input_dev dev; + struct input_dev *dev; int length; int ret; int idx; @@ -215,7 +215,7 @@ static inline int adi_get_bits(struct adi *adi, int count) static int adi_decode(struct adi *adi) { - struct input_dev *dev = &adi->dev; + struct input_dev *dev = adi->dev; char *abs = adi->abs; short *key = adi->key; int i, t; @@ -318,7 +318,8 @@ static void adi_init_digital(struct gameport *gameport) for (i = 0; seq[i]; i++) { gameport_trigger(gameport); - if (seq[i] > 0) msleep(seq[i]); + if (seq[i] > 0) + msleep(seq[i]); if (seq[i] < 0) { mdelay(-seq[i]); udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ @@ -397,42 +398,46 @@ static void adi_id_decode(struct adi *adi, struct adi_port *port) } } -static void adi_init_input(struct adi *adi, struct adi_port *port, int half) +static int adi_init_input(struct adi *adi, struct adi_port *port, int half) { - int i, t; + struct input_dev *input_dev; char buf[ADI_MAX_NAME_LENGTH]; + int i, t; - if (!adi->length) return; - - init_input_dev(&adi->dev); + adi->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); - snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf); + snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s [%s]", buf, adi->cname); snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); adi->abs = adi_abs[t]; adi->key = adi_key[t]; - adi->dev.open = adi_open; - adi->dev.close = adi_close; + input_dev->name = adi->name; + input_dev->phys = adi->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; + input_dev->id.product = adi->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &port->gameport->dev; + input_dev->private = port; - adi->dev.name = adi->name; - adi->dev.phys = adi->phys; - adi->dev.id.bustype = BUS_GAMEPORT; - adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; - adi->dev.id.product = adi->id; - adi->dev.id.version = 0x0100; + input_dev->open = adi_open; + input_dev->close = adi_close; - adi->dev.private = port; - adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) - set_bit(adi->abs[i], adi->dev.absbit); + set_bit(adi->abs[i], input_dev->absbit); for (i = 0; i < adi->buttons; i++) - set_bit(adi->key[i], adi->dev.keybit); + set_bit(adi->key[i], input_dev->keybit); + + return 0; } static void adi_init_center(struct adi *adi) @@ -445,17 +450,17 @@ static void adi_init_center(struct adi *adi) for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { t = adi->abs[i]; - x = adi->dev.abs[t]; + x = adi->dev->abs[t]; if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) x = i < adi->axes10 ? 512 : 128; if (i < adi->axes10) - input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16); + input_set_abs_params(adi->dev, t, 64, x * 2 - 64, 2, 16); else if (i < adi->axes10 + adi->axes8) - input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16); + input_set_abs_params(adi->dev, t, 48, x * 2 - 48, 1, 16); else - input_set_abs_params(&adi->dev, t, -1, 1, 0, 0); + input_set_abs_params(adi->dev, t, -1, 1, 0, 0); } } @@ -469,7 +474,8 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL))) + port = kzalloc(sizeof(struct adi_port), GFP_KERNEL); + if (!port) return -ENOMEM; port->gameport = gameport; @@ -477,10 +483,8 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_drvdata(gameport, port); err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); - if (err) { - kfree(port); - return err; - } + if (err) + goto fail1; adi_init_digital(gameport); adi_read_packet(port); @@ -490,13 +494,18 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < 2; i++) { adi_id_decode(port->adi + i, port); - adi_init_input(port->adi + i, port, i); + + if (!port->adi[i].length) + continue; + + err = adi_init_input(port->adi + i, port, i); + if (err) + goto fail2; } if (!port->adi[0].length && !port->adi[1].length) { - gameport_close(gameport); - kfree(port); - return -ENODEV; + err = -ENODEV; + goto fail2; } gameport_set_poll_handler(gameport, adi_poll); @@ -511,12 +520,18 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < 2; i++) if (port->adi[i].length > 0) { adi_init_center(port->adi + i); - input_register_device(&port->adi[i].dev); - printk(KERN_INFO "input: %s [%s] on %s\n", - port->adi[i].name, port->adi[i].cname, gameport->phys); + input_register_device(port->adi[i].dev); } return 0; + + fail2: for (i = 0; i < 2; i++) + if (port->adi[i].dev) + input_free_device(port->adi[i].dev); + gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + kfree(port); + return err; } static void adi_disconnect(struct gameport *gameport) @@ -526,7 +541,7 @@ static void adi_disconnect(struct gameport *gameport) for (i = 0; i < 2; i++) if (port->adi[i].length > 0) - input_unregister_device(&port->adi[i].dev); + input_unregister_device(port->adi[i].dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(port); diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index e996183c5b06..8558a99f6635 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -53,11 +53,9 @@ __obsolete_setup("amijoy="); static int amijoy_used; static DECLARE_MUTEX(amijoy_sem); -static struct input_dev amijoy_dev[2]; +static struct input_dev *amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; -static char *amijoy_name = "Amiga joystick"; - static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) { int i, data = 0, button = 0; @@ -70,15 +68,15 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; } - input_regs(amijoy_dev + i, fp); + input_regs(amijoy_dev[i], fp); - input_report_key(amijoy_dev + i, BTN_TRIGGER, button); + input_report_key(amijoy_dev[i], BTN_TRIGGER, button); - input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); + input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); data = ~(data ^ (data << 1)); - input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); + input_report_abs(amijoy_dev[i], ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); - input_sync(amijoy_dev + i); + input_sync(amijoy_dev[i]); } return IRQ_HANDLED; } @@ -114,39 +112,52 @@ static void amijoy_close(struct input_dev *dev) static int __init amijoy_init(void) { int i, j; + int err; - for (i = 0; i < 2; i++) - if (amijoy[i]) { - if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2, - "amijoy [Denise]")) { - if (i == 1 && amijoy[0]) { - input_unregister_device(amijoy_dev); - release_mem_region(CUSTOM_PHYSADDR+10, 2); - } - return -EBUSY; - } + for (i = 0; i < 2; i++) { + if (!amijoy[i]) + continue; - amijoy_dev[i].open = amijoy_open; - amijoy_dev[i].close = amijoy_close; - amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - for (j = 0; j < 2; j++) { - amijoy_dev[i].absmin[ABS_X + j] = -1; - amijoy_dev[i].absmax[ABS_X + j] = 1; - } - - amijoy_dev[i].name = amijoy_name; - amijoy_dev[i].phys = amijoy_phys[i]; - amijoy_dev[i].id.bustype = BUS_AMIGA; - amijoy_dev[i].id.vendor = 0x0001; - amijoy_dev[i].id.product = 0x0003; - amijoy_dev[i].id.version = 0x0100; - - input_register_device(amijoy_dev + i); - printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); + amijoy_dev[i] = input_allocate_device(); + if (!amijoy_dev[i]) { + err = -ENOMEM; + goto fail; } + + if (!request_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2, "amijoy [Denise]")) { + input_free_device(amijoy_dev[i]); + err = -EBUSY; + goto fail; + } + + amijoy_dev[i]->name = "Amiga joystick"; + amijoy_dev[i]->phys = amijoy_phys[i]; + amijoy_dev[i]->id.bustype = BUS_AMIGA; + amijoy_dev[i]->id.vendor = 0x0001; + amijoy_dev[i]->id.product = 0x0003; + amijoy_dev[i]->id.version = 0x0100; + + amijoy_dev[i]->open = amijoy_open; + amijoy_dev[i]->close = amijoy_close; + + amijoy_dev[i]->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + amijoy_dev[i]->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + amijoy_dev[i]->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + for (j = 0; j < 2; j++) { + amijoy_dev[i]->absmin[ABS_X + j] = -1; + amijoy_dev[i]->absmax[ABS_X + j] = 1; + } + + input_register_device(amijoy_dev[i]); + } return 0; + + fail: while (--i >= 0) + if (amijoy[i]) { + input_unregister_device(amijoy_dev[i]); + release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); + } + return err; } static void __exit amijoy_exit(void) @@ -155,8 +166,8 @@ static void __exit amijoy_exit(void) for (i = 0; i < 2; i++) if (amijoy[i]) { - input_unregister_device(amijoy_dev + i); - release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2); + input_unregister_device(amijoy_dev[i]); + release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); } } diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 64b1313a3c66..c75ac6eb1ffb 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -111,7 +111,7 @@ static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 }; struct analog { - struct input_dev dev; + struct input_dev *dev; int mask; short *buttons; char name[ANALOG_MAX_NAME_LENGTH]; @@ -182,7 +182,7 @@ static unsigned long analog_faketime = 0; static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons) { - struct input_dev *dev = &analog->dev; + struct input_dev *dev = analog->dev; int i, j; if (analog->mask & ANALOG_HAT_FCS) @@ -428,27 +428,30 @@ static void analog_name(struct analog *analog) * analog_init_device() */ -static void analog_init_device(struct analog_port *port, struct analog *analog, int index) +static int analog_init_device(struct analog_port *port, struct analog *analog, int index) { + struct input_dev *input_dev; int i, j, t, v, w, x, y, z; analog_name(analog); sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; - init_input_dev(&analog->dev); + analog->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; - analog->dev.name = analog->name; - analog->dev.phys = analog->phys; - analog->dev.id.bustype = BUS_GAMEPORT; - analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG; - analog->dev.id.product = analog->mask >> 4; - analog->dev.id.version = 0x0100; + input_dev->name = analog->name; + input_dev->phys = analog->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG; + input_dev->id.product = analog->mask >> 4; + input_dev->id.version = 0x0100; - analog->dev.open = analog_open; - analog->dev.close = analog_close; - analog->dev.private = port; - analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->open = analog_open; + input_dev->close = analog_close; + input_dev->private = port; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = j = 0; i < 4; i++) if (analog->mask & (1 << i)) { @@ -461,8 +464,6 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, v = (x >> 3); w = (x >> 3); - set_bit(t, analog->dev.absbit); - if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3))) x = y; @@ -472,11 +473,7 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, w = (x >> 4); } - analog->dev.absmax[t] = (x << 1) - v; - analog->dev.absmin[t] = v; - analog->dev.absfuzz[t] = port->fuzz; - analog->dev.absflat[t] = w; - + input_set_abs_params(input_dev, t, v, (x << 1) - v, port->fuzz, w); j++; } @@ -484,41 +481,30 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, if (analog->mask & analog_exts[i]) for (x = 0; x < 2; x++) { t = analog_hats[j++]; - set_bit(t, analog->dev.absbit); - analog->dev.absmax[t] = 1; - analog->dev.absmin[t] = -1; + input_set_abs_params(input_dev, t, -1, 1, 0, 0); } for (i = j = 0; i < 4; i++) if (analog->mask & (0x10 << i)) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); if (analog->mask & ANALOG_BTNS_CHF) for (i = 0; i < 2; i++) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); if (analog->mask & ANALOG_HBTN_CHF) for (i = 0; i < 4; i++) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); for (i = 0; i < 4; i++) if (analog->mask & (ANALOG_BTN_TL << i)) - set_bit(analog_pads[i], analog->dev.keybit); + set_bit(analog_pads[i], input_dev->keybit); analog_decode(analog, port->axes, port->initial, port->buttons); - input_register_device(&analog->dev); + input_register_device(analog->dev); - printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys); - - if (port->cooked) - printk(" [ADC port]\n"); - else - printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME, - port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, - port->speed > 10000 ? "M" : "k", - port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000) - : (port->loop * 1000000) / port->speed); + return 0; } /* @@ -659,37 +645,41 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv return - ENOMEM; err = analog_init_port(gameport, drv, port); - if (err) { - kfree(port); - return err; - } + if (err) + goto fail1; err = analog_init_masks(port); - if (err) { - gameport_close(gameport); - gameport_set_drvdata(gameport, NULL); - kfree(port); - return err; - } + if (err) + goto fail2; gameport_set_poll_handler(gameport, analog_poll); gameport_set_poll_interval(gameport, 10); for (i = 0; i < 2; i++) - if (port->analog[i].mask) - analog_init_device(port, port->analog + i, i); + if (port->analog[i].mask) { + err = analog_init_device(port, port->analog + i, i); + if (err) + goto fail3; + } return 0; + + fail3: while (--i >= 0) + input_unregister_device(port->analog[i].dev); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + kfree(port); + return err; } static void analog_disconnect(struct gameport *gameport) { - int i; struct analog_port *port = gameport_get_drvdata(gameport); + int i; for (i = 0; i < 2; i++) if (port->analog[i].mask) - input_unregister_device(&port->analog[i].dev); + input_unregister_device(port->analog[i].dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n", diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 0b2e9fa26579..9a3dfc724a41 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -44,13 +44,11 @@ MODULE_LICENSE("GPL"); #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ #define COBRA_LENGTH 36 -static char* cobra_name = "Creative Labs Blaster GamePad Cobra"; - static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; struct cobra { struct gameport *gameport; - struct input_dev dev[2]; + struct input_dev *dev[2]; int reads; int bads; unsigned char exists; @@ -128,7 +126,7 @@ static void cobra_poll(struct gameport *gameport) for (i = 0; i < 2; i++) if (cobra->exists & r & (1 << i)) { - dev = cobra->dev + i; + dev = cobra->dev[i]; input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); @@ -159,11 +157,13 @@ static void cobra_close(struct input_dev *dev) static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) { struct cobra *cobra; + struct input_dev *input_dev; unsigned int data[2]; int i, j; int err; - if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL))) + cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL); + if (!cobra) return -ENOMEM; cobra->gameport = gameport; @@ -191,38 +191,46 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, cobra_poll); gameport_set_poll_interval(gameport, 20); - for (i = 0; i < 2; i++) - if ((cobra->exists >> i) & 1) { + for (i = 0; i < 2; i++) { + if (~(cobra->exists >> i) & 1) + continue; - sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); - - cobra->dev[i].private = cobra; - cobra->dev[i].open = cobra_open; - cobra->dev[i].close = cobra_close; - - cobra->dev[i].name = cobra_name; - cobra->dev[i].phys = cobra->phys[i]; - cobra->dev[i].id.bustype = BUS_GAMEPORT; - cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; - cobra->dev[i].id.product = 0x0008; - cobra->dev[i].id.version = 0x0100; - - cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - input_set_abs_params(&cobra->dev[i], ABS_X, -1, 1, 0, 0); - input_set_abs_params(&cobra->dev[i], ABS_Y, -1, 1, 0, 0); - - for (j = 0; cobra_btn[j]; j++) - set_bit(cobra_btn[j], cobra->dev[i].keybit); - - input_register_device(&cobra->dev[i]); - printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys); + cobra->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; } + sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); + + input_dev->name = "Creative Labs Blaster GamePad Cobra"; + input_dev->phys = cobra->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; + input_dev->id.product = 0x0008; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = cobra; + + input_dev->open = cobra_open; + input_dev->close = cobra_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); + for (j = 0; cobra_btn[j]; j++) + set_bit(cobra_btn[j], input_dev->keybit); + + input_register_device(cobra->dev[i]); + } + return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: for (i = 0; i < 2; i++) + if (cobra->dev[i]) + input_unregister_device(cobra->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(cobra); return err; } @@ -234,7 +242,7 @@ static void cobra_disconnect(struct gameport *gameport) for (i = 0; i < 2; i++) if ((cobra->exists >> i) & 1) - input_unregister_device(cobra->dev + i); + input_unregister_device(cobra->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(cobra); diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 2a3e4bb2da50..499344c72756 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -43,25 +43,28 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); MODULE_LICENSE("GPL"); -static int db9[] __initdata = { -1, 0 }; -static int db9_nargs __initdata = 0; -module_param_array_named(dev, db9, int, &db9_nargs, 0); +struct db9_config { + int args[2]; + int nargs; +}; + +#define DB9_MAX_PORTS 3 +static struct db9_config db9[DB9_MAX_PORTS] __initdata; + +module_param_array_named(dev, db9[0].args, int, &db9[0].nargs, 0); MODULE_PARM_DESC(dev, "Describes first attached device (,)"); - -static int db9_2[] __initdata = { -1, 0 }; -static int db9_nargs_2 __initdata = 0; -module_param_array_named(dev2, db9_2, int, &db9_nargs_2, 0); +module_param_array_named(dev2, db9[1].args, int, &db9[0].nargs, 0); MODULE_PARM_DESC(dev2, "Describes second attached device (,)"); - -static int db9_3[] __initdata = { -1, 0 }; -static int db9_nargs_3 __initdata = 0; -module_param_array_named(dev3, db9_3, int, &db9_nargs_3, 0); +module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0); MODULE_PARM_DESC(dev3, "Describes third attached device (,)"); __obsolete_setup("db9="); __obsolete_setup("db9_2="); __obsolete_setup("db9_3="); +#define DB9_ARG_PARPORT 0 +#define DB9_ARG_MODE 1 + #define DB9_MULTI_STICK 0x01 #define DB9_MULTI2_STICK 0x02 #define DB9_GENESIS_PAD 0x03 @@ -87,40 +90,53 @@ __obsolete_setup("db9_3="); #define DB9_NORMAL 0x0a #define DB9_NOSELECT 0x08 -#define DB9_MAX_DEVICES 2 - #define DB9_GENESIS6_DELAY 14 #define DB9_REFRESH_TIME HZ/100 +#define DB9_MAX_DEVICES 2 + +struct db9_mode_data { + const char *name; + const short *buttons; + int n_buttons; + int n_pads; + int n_axis; + int bidirectional; + int reverse; +}; + struct db9 { - struct input_dev dev[DB9_MAX_DEVICES]; + struct input_dev *dev[DB9_MAX_DEVICES]; struct timer_list timer; struct pardevice *pd; int mode; int used; struct semaphore sem; - char phys[2][32]; + char phys[DB9_MAX_DEVICES][32]; }; static struct db9 *db9_base[3]; -static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; -static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; -static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; - -static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 }; -static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, - db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn, - db9_cd32_btn, db9_cd32_btn }; -static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", - NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", - "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" }; - -static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 }; -static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 }; +static const short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; +static const short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; +static const short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 }; -static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 }; + +static const struct db9_mode_data db9_modes[] = { + { NULL, NULL, 0, 0, 0, 0, 0 }, + { "Multisystem joystick", db9_multi_btn, 1, 1, 2, 1, 1 }, + { "Multisystem joystick (2 fire)", db9_multi_btn, 2, 1, 2, 1, 1 }, + { "Genesis pad", db9_genesis_btn, 4, 1, 2, 1, 1 }, + { NULL, NULL, 0, 0, 0, 0, 0 }, + { "Genesis 5 pad", db9_genesis_btn, 6, 1, 2, 1, 1 }, + { "Genesis 6 pad", db9_genesis_btn, 8, 1, 2, 1, 1 }, + { "Saturn pad", db9_cd32_btn, 9, 6, 7, 0, 1 }, + { "Multisystem (0.8.0.2) joystick", db9_multi_btn, 1, 1, 2, 1, 1 }, + { "Multisystem (0.8.0.2-dual) joystick", db9_multi_btn, 1, 2, 2, 1, 1 }, + { "Amiga CD-32 pad", db9_cd32_btn, 7, 1, 2, 1, 1 }, + { "Saturn dpp", db9_cd32_btn, 9, 6, 7, 0, 0 }, + { "Saturn dpp dual", db9_cd32_btn, 9, 12, 7, 0, 0 }, +}; /* * Saturn controllers @@ -342,7 +358,7 @@ static int db9_saturn(int mode, struct parport *port, struct input_dev *dev) default: return -1; } - max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES); + max_pads = min(db9_modes[mode].n_pads, DB9_MAX_DEVICES); for (tmp = 0, i = 0; i < n; i++) { id = db9_saturn_read_packet(port, data, type + i, 1); tmp = db9_saturn_report(id, data, dev, tmp, max_pads); @@ -354,17 +370,18 @@ static void db9_timer(unsigned long private) { struct db9 *db9 = (void *) private; struct parport *port = db9->pd->port; - struct input_dev *dev = db9->dev; + struct input_dev *dev = db9->dev[0]; + struct input_dev *dev2 = db9->dev[1]; int data, i; - switch(db9->mode) { + switch (db9->mode) { case DB9_MULTI_0802_2: data = parport_read_data(port) >> 3; - input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); - input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); - input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1); + input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev2, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1); case DB9_MULTI_0802: @@ -405,7 +422,7 @@ static void db9_timer(unsigned long private) input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_START, ~data & DB9_FIRE2); @@ -414,7 +431,7 @@ static void db9_timer(unsigned long private) case DB9_GENESIS5_PAD: parport_write_control(port, DB9_NOSELECT); - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -422,7 +439,7 @@ static void db9_timer(unsigned long private) input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_X, ~data & DB9_FIRE2); @@ -434,7 +451,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NOSELECT); /* 1 */ udelay(DB9_GENESIS6_DELAY); - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -443,7 +460,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_START, ~data & DB9_FIRE2); @@ -477,7 +494,7 @@ static void db9_timer(unsigned long private) case DB9_CD32_PAD: - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -489,7 +506,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, 0x02); parport_write_control(port, 0x0a); input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); - } + } parport_write_control(port, 0x00); break; @@ -513,7 +530,7 @@ static int db9_open(struct input_dev *dev) if (!db9->used++) { parport_claim(db9->pd); parport_write_data(port, 0xff); - if (db9_reverse[db9->mode]) { + if (db9_modes[db9->mode].reverse) { parport_data_reverse(port); parport_write_control(port, DB9_NORMAL); } @@ -539,117 +556,160 @@ static void db9_close(struct input_dev *dev) up(&db9->sem); } -static struct db9 __init *db9_probe(int *config, int nargs) +static struct db9 __init *db9_probe(int parport, int mode) { struct db9 *db9; + const struct db9_mode_data *db9_mode; struct parport *pp; + struct pardevice *pd; + struct input_dev *input_dev; int i, j; + int err; - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "db9.c: Device type must be specified.\n"); - return NULL; + if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) { + printk(KERN_ERR "db9.c: Bad device type %d\n", mode); + err = -EINVAL; + goto err_out; } - if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { - printk(KERN_ERR "db9.c: bad config\n"); - return NULL; - } + db9_mode = &db9_modes[mode]; - pp = parport_find_number(config[0]); + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "db9.c: no such parport\n"); - return NULL; + err = -ENODEV; + goto err_out; } - if (db9_bidirectional[config[1]]) { - if (!(pp->modes & PARPORT_MODE_TRISTATE)) { - printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); - parport_put_port(pp); - return NULL; - } + if (db9_mode[mode].bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) { + printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); + err = -EINVAL; + goto err_put_pp; } - if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; + } + + db9 = kzalloc(sizeof(struct db9), GFP_KERNEL); + if (!db9) { + printk(KERN_ERR "db9.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } init_MUTEX(&db9->sem); - db9->mode = config[1]; + db9->pd = pd; + db9->mode = mode; init_timer(&db9->timer); db9->timer.data = (long) db9; db9->timer.function = db9_timer; - db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - parport_put_port(pp); + for (i = 0; i < (min(db9_mode->n_pads, DB9_MAX_DEVICES)); i++) { - if (!db9->pd) { - printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); - kfree(db9); - return NULL; - } - - for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) { + db9->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "db9.c: Not enough memory for input device\n"); + err = -ENOMEM; + goto err_free_devs; + } sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i); - db9->dev[i].private = db9; - db9->dev[i].open = db9_open; - db9->dev[i].close = db9_close; + input_dev->name = db9_mode->name; + input_dev->phys = db9->phys[i]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0002; + input_dev->id.product = mode; + input_dev->id.version = 0x0100; + input_dev->private = db9; - db9->dev[i].name = db9_name[db9->mode]; - db9->dev[i].phys = db9->phys[i]; - db9->dev[i].id.bustype = BUS_PARPORT; - db9->dev[i].id.vendor = 0x0002; - db9->dev[i].id.product = config[1]; - db9->dev[i].id.version = 0x0100; + input_dev->open = db9_open; + input_dev->close = db9_close; - db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (j = 0; j < db9_buttons[db9->mode]; j++) - set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); - for (j = 0; j < db9_num_axis[db9->mode]; j++) { - set_bit(db9_abs[j], db9->dev[i].absbit); - if (j < 2) { - db9->dev[i].absmin[db9_abs[j]] = -1; - db9->dev[i].absmax[db9_abs[j]] = 1; - } else { - db9->dev[i].absmin[db9_abs[j]] = 1; - db9->dev[i].absmax[db9_abs[j]] = 255; - db9->dev[i].absflat[db9_abs[j]] = 0; - } + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + for (j = 0; j < db9_mode->n_buttons; j++) + set_bit(db9_mode->buttons[j], input_dev->keybit); + for (j = 0; j < db9_mode->n_axis; j++) { + if (j < 2) + input_set_abs_params(input_dev, db9_abs[j], -1, 1, 0, 0); + else + input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0); } - input_register_device(db9->dev + i); - printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name); + + input_register_device(input_dev); } + parport_put_port(pp); return db9; + + err_free_devs: + while (--i >= 0) + input_unregister_device(db9->dev[i]); + kfree(db9); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} + +static void __exit db9_remove(struct db9 *db9) +{ + int i; + + for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++) + input_unregister_device(db9->dev[i]); + parport_unregister_device(db9->pd); + kfree(db9); } static int __init db9_init(void) { - db9_base[0] = db9_probe(db9, db9_nargs); - db9_base[1] = db9_probe(db9_2, db9_nargs_2); - db9_base[2] = db9_probe(db9_3, db9_nargs_3); + int i; + int have_dev = 0; + int err = 0; - if (db9_base[0] || db9_base[1] || db9_base[2]) - return 0; + for (i = 0; i < DB9_MAX_PORTS; i++) { + if (db9[i].nargs == 0 || db9[i].args[DB9_ARG_PARPORT] < 0) + continue; - return -ENODEV; + if (db9[i].nargs < 2) { + printk(KERN_ERR "db9.c: Device type must be specified.\n"); + err = -EINVAL; + break; + } + + db9_base[i] = db9_probe(db9[i].args[DB9_ARG_PARPORT], + db9[i].args[DB9_ARG_MODE]); + if (IS_ERR(db9_base[i])) { + err = PTR_ERR(db9_base[i]); + break; + } + + have_dev = 1; + } + + if (err) { + while (--i >= 0) + db9_remove(db9_base[i]); + return err; + } + + return have_dev ? 0 : -ENODEV; } static void __exit db9_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (db9_base[i]) { - for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++) - input_unregister_device(db9_base[i]->dev + j); - parport_unregister_device(db9_base[i]->pd); - } + for (i = 0; i < DB9_MAX_PORTS; i++) + if (db9_base[i]) + db9_remove(db9_base[i]); } module_init(db9_init); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 5427bf9fc862..7df2d82f2c83 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -41,20 +41,22 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); MODULE_LICENSE("GPL"); -static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs __initdata = 0; -module_param_array_named(map, gc, int, &gc_nargs, 0); -MODULE_PARM_DESC(map, "Describers first set of devices (,,,..)"); +#define GC_MAX_PORTS 3 +#define GC_MAX_DEVICES 5 -static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs_2 __initdata = 0; -module_param_array_named(map2, gc_2, int, &gc_nargs_2, 0); -MODULE_PARM_DESC(map2, "Describers second set of devices"); +struct gc_config { + int args[GC_MAX_DEVICES + 1]; + int nargs; +}; -static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs_3 __initdata = 0; -module_param_array_named(map3, gc_3, int, &gc_nargs_3, 0); -MODULE_PARM_DESC(map3, "Describers third set of devices"); +static struct gc_config gc[GC_MAX_PORTS] __initdata; + +module_param_array_named(map, gc[0].args, int, &gc[0].nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (,,,..)"); +module_param_array_named(map2, gc[1].args, int, &gc[1].nargs, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); +module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0); +MODULE_PARM_DESC(map3, "Describes third set of devices"); __obsolete_setup("gc="); __obsolete_setup("gc_2="); @@ -77,12 +79,12 @@ __obsolete_setup("gc_3="); struct gc { struct pardevice *pd; - struct input_dev dev[5]; + struct input_dev *dev[GC_MAX_DEVICES]; struct timer_list timer; unsigned char pads[GC_MAX + 1]; int used; struct semaphore sem; - char phys[5][32]; + char phys[GC_MAX_DEVICES][32]; }; static struct gc *gc_base[3]; @@ -330,7 +332,6 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_BYTES static void gc_timer(unsigned long private) { struct gc *gc = (void *) private; - struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; unsigned char data_psx[5][GC_PSX_BYTES]; int i, j, s; @@ -357,16 +358,16 @@ static void gc_timer(unsigned long private) if (data[31 - j] & s) axes[1] |= 1 << j; } - input_report_abs(dev + i, ABS_X, axes[0]); - input_report_abs(dev + i, ABS_Y, -axes[1]); + input_report_abs(gc->dev[i], ABS_X, axes[0]); + input_report_abs(gc->dev[i], ABS_Y, -axes[1]); - input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7])); - input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); + input_report_abs(gc->dev[i], ABS_HAT0X, !(s & data[6]) - !(s & data[7])); + input_report_abs(gc->dev[i], ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); for (j = 0; j < 10; j++) - input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); + input_report_key(gc->dev[i], gc_n64_btn[j], s & data[gc_n64_bytes[j]]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } } @@ -384,19 +385,19 @@ static void gc_timer(unsigned long private) s = gc_status_bit[i]; if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { - input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7])); - input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5])); + input_report_abs(gc->dev[i], ABS_X, !(s & data[6]) - !(s & data[7])); + input_report_abs(gc->dev[i], ABS_Y, !(s & data[4]) - !(s & data[5])); } if (s & gc->pads[GC_NES]) for (j = 0; j < 4; j++) - input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]); + input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_nes_bytes[j]]); if (s & gc->pads[GC_SNES]) for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_snes_bytes[j]]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } @@ -413,15 +414,15 @@ static void gc_timer(unsigned long private) s = gc_status_bit[i]; if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { - input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3])); - input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1])); - input_report_key(dev + i, BTN_TRIGGER, s & data[4]); + input_report_abs(gc->dev[i], ABS_X, !(s & data[2]) - !(s & data[3])); + input_report_abs(gc->dev[i], ABS_Y, !(s & data[0]) - !(s & data[1])); + input_report_key(gc->dev[i], BTN_TRIGGER, s & data[4]); } if (s & gc->pads[GC_MULTI2]) - input_report_key(dev + i, BTN_THUMB, s & data[5]); + input_report_key(gc->dev[i], BTN_THUMB, s & data[5]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } @@ -438,44 +439,44 @@ static void gc_timer(unsigned long private) case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); + input_report_key(gc->dev[i], BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(gc->dev[i], BTN_THUMBR, ~data_psx[i][0] & 0x02); case GC_PSX_NEGCON: case GC_PSX_ANALOG: - if(gc->pads[GC_DDR] & gc_status_bit[i]) { + if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) - input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); + input_report_abs(gc->dev[i], gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); } for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); + input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); + input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(gc->dev[i]); break; case GC_PSX_NORMAL: - if(gc->pads[GC_DDR] & gc_status_bit[i]) { + if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) - input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { - input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); /* for some reason if the extra axes are left unset they drift */ /* for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j+2], 128); + input_report_abs(gc->dev[i], gc_psx_abs[j+2], 128); * This needs to be debugged properly, * maybe fuzz processing needs to be done in input_sync() * --vojtech @@ -483,12 +484,12 @@ static void gc_timer(unsigned long private) } for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); + input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); + input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(gc->dev[i]); break; @@ -533,177 +534,212 @@ static void gc_close(struct input_dev *dev) up(&gc->sem); } -static struct gc __init *gc_probe(int *config, int nargs) +static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) +{ + struct input_dev *input_dev; + int i; + + if (!pad_type) + return 0; + + if (pad_type < 1 || pad_type > GC_MAX) { + printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type); + return -EINVAL; + } + + gc->dev[idx] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "gamecon.c: Not enough memory for input device\n"); + return -ENOMEM; + } + + input_dev->name = gc_names[pad_type]; + input_dev->phys = gc->phys[idx]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0001; + input_dev->id.product = pad_type; + input_dev->id.version = 0x0100; + input_dev->private = gc; + + input_dev->open = gc_open; + input_dev->close = gc_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 2; i++) + input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); + + gc->pads[0] |= gc_status_bit[idx]; + gc->pads[pad_type] |= gc_status_bit[idx]; + + switch (pad_type) { + + case GC_N64: + for (i = 0; i < 10; i++) + set_bit(gc_n64_btn[i], input_dev->keybit); + + for (i = 0; i < 2; i++) { + input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2); + input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); + } + + break; + + case GC_SNES: + for (i = 4; i < 8; i++) + set_bit(gc_snes_btn[i], input_dev->keybit); + case GC_NES: + for (i = 0; i < 4; i++) + set_bit(gc_snes_btn[i], input_dev->keybit); + break; + + case GC_MULTI2: + set_bit(BTN_THUMB, input_dev->keybit); + case GC_MULTI: + set_bit(BTN_TRIGGER, input_dev->keybit); + break; + + case GC_PSX: + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2); + for (i = 0; i < 12; i++) + set_bit(gc_psx_btn[i], input_dev->keybit); + + break; + + case GC_DDR: + for (i = 0; i < 4; i++) + set_bit(gc_psx_ddr_btn[i], input_dev->keybit); + for (i = 0; i < 12; i++) + set_bit(gc_psx_btn[i], input_dev->keybit); + + break; + } + + return 0; +} + +static struct gc __init *gc_probe(int parport, int *pads, int n_pads) { struct gc *gc; struct parport *pp; - int i, j; - - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); - return NULL; - } - - pp = parport_find_number(config[0]); + struct pardevice *pd; + int i; + int err; + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "gamecon.c: no such parport\n"); - return NULL; + err = -EINVAL; + goto err_out; } - if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; + } + + gc = kzalloc(sizeof(struct gc), GFP_KERNEL); + if (!gc) { + printk(KERN_ERR "gamecon.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } init_MUTEX(&gc->sem); - - gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - - parport_put_port(pp); - - if (!gc->pd) { - printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); - kfree(gc); - return NULL; - } - - parport_claim(gc->pd); - + gc->pd = pd; init_timer(&gc->timer); gc->timer.data = (long) gc; gc->timer.function = gc_timer; - for (i = 0; i < nargs - 1; i++) { - - if (!config[i + 1]) + for (i = 0; i < n_pads; i++) { + if (!pads[i]) continue; - if (config[i + 1] < 1 || config[i + 1] > GC_MAX) { - printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]); - continue; - } - - gc->dev[i].private = gc; - gc->dev[i].open = gc_open; - gc->dev[i].close = gc_close; - - gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (j = 0; j < 2; j++) { - set_bit(ABS_X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_X + j] = -1; - gc->dev[i].absmax[ABS_X + j] = 1; - } - - gc->pads[0] |= gc_status_bit[i]; - gc->pads[config[i + 1]] |= gc_status_bit[i]; - - switch(config[i + 1]) { - - case GC_N64: - for (j = 0; j < 10; j++) - set_bit(gc_n64_btn[j], gc->dev[i].keybit); - - for (j = 0; j < 2; j++) { - set_bit(ABS_X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_X + j] = -127; - gc->dev[i].absmax[ABS_X + j] = 126; - gc->dev[i].absflat[ABS_X + j] = 2; - set_bit(ABS_HAT0X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_HAT0X + j] = -1; - gc->dev[i].absmax[ABS_HAT0X + j] = 1; - } - - break; - - case GC_SNES: - for (j = 4; j < 8; j++) - set_bit(gc_snes_btn[j], gc->dev[i].keybit); - case GC_NES: - for (j = 0; j < 4; j++) - set_bit(gc_snes_btn[j], gc->dev[i].keybit); - break; - - case GC_MULTI2: - set_bit(BTN_THUMB, gc->dev[i].keybit); - case GC_MULTI: - set_bit(BTN_TRIGGER, gc->dev[i].keybit); - break; - - case GC_PSX: - case GC_DDR: - if(config[i + 1] == GC_DDR) { - for (j = 0; j < 4; j++) - set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); - } else { - for (j = 0; j < 6; j++) { - set_bit(gc_psx_abs[j], gc->dev[i].absbit); - gc->dev[i].absmin[gc_psx_abs[j]] = 4; - gc->dev[i].absmax[gc_psx_abs[j]] = 252; - gc->dev[i].absflat[gc_psx_abs[j]] = 2; - } - } - - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - - break; - } - sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); + err = gc_setup_pad(gc, i, pads[i]); + if (err) + goto err_free_devs; - gc->dev[i].name = gc_names[config[i + 1]]; - gc->dev[i].phys = gc->phys[i]; - gc->dev[i].id.bustype = BUS_PARPORT; - gc->dev[i].id.vendor = 0x0001; - gc->dev[i].id.product = config[i + 1]; - gc->dev[i].id.version = 0x0100; + input_register_device(gc->dev[i]); } - parport_release(gc->pd); - if (!gc->pads[0]) { - parport_unregister_device(gc->pd); - kfree(gc); - return NULL; + printk(KERN_ERR "gamecon.c: No valid devices specified\n"); + err = -EINVAL; + goto err_free_gc; } - for (i = 0; i < 5; i++) - if (gc->pads[0] & gc_status_bit[i]) { - input_register_device(gc->dev + i); - printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); - } - + parport_put_port(pp); return gc; + + err_free_devs: + while (--i >= 0) + input_unregister_device(gc->dev[i]); + err_free_gc: + kfree(gc); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} + +static void __exit gc_remove(struct gc *gc) +{ + int i; + + for (i = 0; i < GC_MAX_DEVICES; i++) + if (gc->dev[i]) + input_unregister_device(gc->dev[i]); + parport_unregister_device(gc->pd); + kfree(gc); } static int __init gc_init(void) { - gc_base[0] = gc_probe(gc, gc_nargs); - gc_base[1] = gc_probe(gc_2, gc_nargs_2); - gc_base[2] = gc_probe(gc_3, gc_nargs_3); + int i; + int have_dev = 0; + int err = 0; - if (gc_base[0] || gc_base[1] || gc_base[2]) - return 0; + for (i = 0; i < GC_MAX_PORTS; i++) { + if (gc[i].nargs == 0 || gc[i].args[0] < 0) + continue; - return -ENODEV; + if (gc[i].nargs < 2) { + printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); + err = -EINVAL; + break; + } + + gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1); + if (IS_ERR(gc_base[i])) { + err = PTR_ERR(gc_base[i]); + break; + } + + have_dev = 1; + } + + if (err) { + while (--i >= 0) + gc_remove(gc_base[i]); + return err; + } + + return have_dev ? 0 : -ENODEV; } static void __exit gc_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (gc_base[i]) { - for (j = 0; j < 5; j++) - if (gc_base[i]->pads[0] & gc_status_bit[j]) - input_unregister_device(gc_base[i]->dev + j); - parport_unregister_device(gc_base[i]->pd); - } + for (i = 0; i < GC_MAX_PORTS; i++) + if (gc_base[i]) + gc_remove(gc_base[i]); } module_init(gc_init); diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 8e4f92b115e6..e151f8c5bcb9 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -81,7 +81,7 @@ static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; struct gf2k { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int reads; int bads; unsigned char id; @@ -175,7 +175,7 @@ static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) static void gf2k_read(struct gf2k *gf2k, unsigned char *data) { - struct input_dev *dev = &gf2k->dev; + struct input_dev *dev = gf2k->dev; int i, t; for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) @@ -239,13 +239,19 @@ static void gf2k_close(struct input_dev *dev) static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) { struct gf2k *gf2k; + struct input_dev *input_dev; unsigned char data[GF2K_LENGTH]; int i, err; - if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL))) - return -ENOMEM; + gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!gf2k || !input_dev) { + err = -ENOMEM; + goto fail1; + } gf2k->gameport = gameport; + gf2k->dev = input_dev; gameport_set_drvdata(gameport, gf2k); @@ -295,53 +301,52 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) gf2k->length = gf2k_lens[gf2k->id]; - init_input_dev(&gf2k->dev); + input_dev->name = gf2k_names[gf2k->id]; + input_dev->phys = gf2k->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; + input_dev->id.product = gf2k->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = gf2k; - gf2k->dev.private = gf2k; - gf2k->dev.open = gf2k_open; - gf2k->dev.close = gf2k_close; - gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - gf2k->dev.name = gf2k_names[gf2k->id]; - gf2k->dev.phys = gf2k->phys; - gf2k->dev.id.bustype = BUS_GAMEPORT; - gf2k->dev.id.vendor = GAMEPORT_ID_VENDOR_GENIUS; - gf2k->dev.id.product = gf2k->id; - gf2k->dev.id.version = 0x0100; + input_dev->open = gf2k_open; + input_dev->close = gf2k_close; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < gf2k_axes[gf2k->id]; i++) - set_bit(gf2k_abs[i], gf2k->dev.absbit); + set_bit(gf2k_abs[i], input_dev->absbit); for (i = 0; i < gf2k_hats[gf2k->id]; i++) { - set_bit(ABS_HAT0X + i, gf2k->dev.absbit); - gf2k->dev.absmin[ABS_HAT0X + i] = -1; - gf2k->dev.absmax[ABS_HAT0X + i] = 1; + set_bit(ABS_HAT0X + i, input_dev->absbit); + input_dev->absmin[ABS_HAT0X + i] = -1; + input_dev->absmax[ABS_HAT0X + i] = 1; } for (i = 0; i < gf2k_joys[gf2k->id]; i++) - set_bit(gf2k_btn_joy[i], gf2k->dev.keybit); + set_bit(gf2k_btn_joy[i], input_dev->keybit); for (i = 0; i < gf2k_pads[gf2k->id]; i++) - set_bit(gf2k_btn_pad[i], gf2k->dev.keybit); + set_bit(gf2k_btn_pad[i], input_dev->keybit); gf2k_read_packet(gameport, gf2k->length, data); gf2k_read(gf2k, data); for (i = 0; i < gf2k_axes[gf2k->id]; i++) { - gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 : - gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; - gf2k->dev.absmin[gf2k_abs[i]] = 32; - gf2k->dev.absfuzz[gf2k_abs[i]] = 8; - gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; + input_dev->absmax[gf2k_abs[i]] = (i < 2) ? input_dev->abs[gf2k_abs[i]] * 2 - 32 : + input_dev->abs[gf2k_abs[0]] + input_dev->abs[gf2k_abs[1]] - 32; + input_dev->absmin[gf2k_abs[i]] = 32; + input_dev->absfuzz[gf2k_abs[i]] = 8; + input_dev->absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; } - input_register_device(&gf2k->dev); - printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys); + input_register_device(gf2k->dev); return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(gf2k); return err; } @@ -350,7 +355,7 @@ static void gf2k_disconnect(struct gameport *gameport) { struct gf2k *gf2k = gameport_get_drvdata(gameport); - input_unregister_device(&gf2k->dev); + input_unregister_device(gf2k->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(gf2k); diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index 9d3f910dd568..e206bb56e53c 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -55,7 +55,7 @@ MODULE_LICENSE("GPL"); struct grip { struct gameport *gameport; - struct input_dev dev[2]; + struct input_dev *dev[2]; unsigned char mode[2]; int reads; int bads; @@ -190,7 +190,7 @@ static void grip_poll(struct gameport *gameport) for (i = 0; i < 2; i++) { - dev = grip->dev + i; + dev = grip->dev[i]; grip->reads++; switch (grip->mode[i]) { @@ -297,6 +297,7 @@ static void grip_close(struct input_dev *dev) static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) { struct grip *grip; + struct input_dev *input_dev; unsigned int data[GRIP_LENGTH_XT]; int i, j, t; int err; @@ -339,48 +340,56 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, grip_poll); gameport_set_poll_interval(gameport, 20); - for (i = 0; i < 2; i++) - if (grip->mode[i]) { + for (i = 0; i < 2; i++) { + if (!grip->mode[i]) + continue; - sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); - - grip->dev[i].private = grip; - - grip->dev[i].open = grip_open; - grip->dev[i].close = grip_close; - - grip->dev[i].name = grip_name[grip->mode[i]]; - grip->dev[i].phys = grip->phys[i]; - grip->dev[i].id.bustype = BUS_GAMEPORT; - grip->dev[i].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; - grip->dev[i].id.product = grip->mode[i]; - grip->dev[i].id.version = 0x0100; - - grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { - - if (j < grip_cen[grip->mode[i]]) - input_set_abs_params(&grip->dev[i], t, 14, 52, 1, 2); - else if (j < grip_anx[grip->mode[i]]) - input_set_abs_params(&grip->dev[i], t, 3, 57, 1, 0); - else - input_set_abs_params(&grip->dev[i], t, -1, 1, 0, 0); - } - - for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) - if (t > 0) - set_bit(t, grip->dev[i].keybit); - - printk(KERN_INFO "input: %s on %s\n", - grip_name[grip->mode[i]], gameport->phys); - input_register_device(grip->dev + i); + grip->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; } + sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); + + input_dev->name = grip_name[grip->mode[i]]; + input_dev->phys = grip->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + input_dev->id.product = grip->mode[i]; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = grip; + + input_dev->open = grip_open; + input_dev->close = grip_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { + + if (j < grip_cen[grip->mode[i]]) + input_set_abs_params(input_dev, t, 14, 52, 1, 2); + else if (j < grip_anx[grip->mode[i]]) + input_set_abs_params(input_dev, t, 3, 57, 1, 0); + else + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + } + + for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) + if (t > 0) + set_bit(t, input_dev->keybit); + + input_register_device(grip->dev[i]); + } + return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: for (i = 0; i < 2; i++) + if (grip->dev[i]) + input_unregister_device(grip->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(grip); return err; } @@ -391,8 +400,8 @@ static void grip_disconnect(struct gameport *gameport) int i; for (i = 0; i < 2; i++) - if (grip->mode[i]) - input_unregister_device(grip->dev + i); + if (grip->dev[i]) + input_unregister_device(grip->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(grip); diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index da17eee6f574..a0ba93ccac72 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -32,23 +32,37 @@ MODULE_LICENSE("GPL"); #define dbg(format, arg...) do {} while (0) #endif +#define GRIP_MAX_PORTS 4 /* * Grip multiport state */ +struct grip_port { + struct input_dev *dev; + int mode; + int registered; + + /* individual gamepad states */ + int buttons; + int xaxes; + int yaxes; + int dirty; /* has the state been updated? */ +}; + struct grip_mp { struct gameport *gameport; - struct input_dev dev[4]; - int mode[4]; - int registered[4]; + struct grip_port *port[GRIP_MAX_PORTS]; +// struct input_dev *dev[4]; +// int mode[4]; +// int registered[4]; int reads; int bads; /* individual gamepad states */ - int buttons[4]; - int xaxes[4]; - int yaxes[4]; - int dirty[4]; /* has the state been updated? */ +// int buttons[4]; +// int xaxes[4]; +// int yaxes[4]; +// int dirty[4]; /* has the state been updated? */ }; /* @@ -85,16 +99,16 @@ struct grip_mp { #define GRIP_MODE_GP 2 #define GRIP_MODE_C64 3 -static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; -static int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; +static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; +static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; -static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; -static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; +static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; +static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; -static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; -static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; +static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; +static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; -static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; +static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; static const int init_seq[] = { 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, @@ -104,9 +118,9 @@ static const int init_seq[] = { /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ -static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; +static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; -static void register_slot(int i, struct grip_mp *grip); +static int register_slot(int i, struct grip_mp *grip); /* * Returns whether an odd or even number of bits are on in pkt. @@ -353,9 +367,10 @@ static int dig_mode_start(struct gameport *gameport, u32 *packet) static int get_and_decode_packet(struct grip_mp *grip, int flags) { + struct grip_port *port; u32 packet; int joytype = 0; - int slot = 0; + int slot; /* Get a packet and check for validity */ @@ -377,6 +392,8 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) if ((slot < 0) || (slot > 3)) return flags; + port = grip->port[slot]; + /* * Handle "reset" packets, which occur at startup, and when gamepads * are removed or plugged in. May contain configuration of a new gamepad. @@ -385,14 +402,14 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) joytype = (packet >> 16) & 0x1f; if (!joytype) { - if (grip->registered[slot]) { + if (port->registered) { printk(KERN_INFO "grip_mp: removing %s, slot %d\n", - grip_name[grip->mode[slot]], slot); - input_unregister_device(grip->dev + slot); - grip->registered[slot] = 0; + grip_name[port->mode], slot); + input_unregister_device(port->dev); + port->registered = 0; } dbg("Reset: grip multiport slot %d\n", slot); - grip->mode[slot] = GRIP_MODE_RESET; + port->mode = GRIP_MODE_RESET; flags |= IO_SLOT_CHANGE; return flags; } @@ -402,17 +419,17 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) if (joytype == 0x1f) { int dir = (packet >> 8) & 0xf; /* eight way directional value */ - grip->buttons[slot] = (~packet) & 0xff; - grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1; - grip->xaxes[slot] = (axis_map[dir] & 3) - 1; - grip->dirty[slot] = 1; + port->buttons = (~packet) & 0xff; + port->yaxes = ((axis_map[dir] >> 2) & 3) - 1; + port->xaxes = (axis_map[dir] & 3) - 1; + port->dirty = 1; - if (grip->mode[slot] == GRIP_MODE_RESET) + if (port->mode == GRIP_MODE_RESET) flags |= IO_SLOT_CHANGE; - grip->mode[slot] = GRIP_MODE_GP; + port->mode = GRIP_MODE_GP; - if (!grip->registered[slot]) { + if (!port->registered) { dbg("New Grip pad in multiport slot %d.\n", slot); register_slot(slot, grip); } @@ -445,9 +462,9 @@ static int slots_valid(struct grip_mp *grip) return 0; for (slot = 0; slot < 4; slot++) { - if (grip->mode[slot] == GRIP_MODE_RESET) + if (grip->port[slot]->mode == GRIP_MODE_RESET) invalid = 1; - if (grip->mode[slot] != GRIP_MODE_NONE) + if (grip->port[slot]->mode != GRIP_MODE_NONE) active = 1; } @@ -484,7 +501,7 @@ static int multiport_init(struct grip_mp *grip) /* Get packets, store multiport state, and check state's validity */ for (tries = 0; tries < 4096; tries++) { - if ( slots_valid(grip) ) { + if (slots_valid(grip)) { initialized = 1; break; } @@ -499,24 +516,24 @@ static int multiport_init(struct grip_mp *grip) static void report_slot(struct grip_mp *grip, int slot) { - struct input_dev *dev = &(grip->dev[slot]); - int i, buttons = grip->buttons[slot]; + struct grip_port *port = grip->port[slot]; + int i; /* Store button states with linux input driver */ for (i = 0; i < 8; i++) - input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1); + input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1); /* Store axis states with linux driver */ - input_report_abs(dev, ABS_X, grip->xaxes[slot]); - input_report_abs(dev, ABS_Y, grip->yaxes[slot]); + input_report_abs(port->dev, ABS_X, port->xaxes); + input_report_abs(port->dev, ABS_Y, port->yaxes); /* Tell the receiver of the events to process them */ - input_sync(dev); + input_sync(port->dev); - grip->dirty[slot] = 0; + port->dirty = 0; } /* @@ -540,7 +557,7 @@ static void grip_poll(struct gameport *gameport) } for (i = 0; i < 4; i++) - if (grip->dirty[i]) + if (grip->port[i]->dirty) report_slot(grip, i); } @@ -571,35 +588,43 @@ static void grip_close(struct input_dev *dev) * Tell the linux input layer about a newly plugged-in gamepad. */ -static void register_slot(int slot, struct grip_mp *grip) +static int register_slot(int slot, struct grip_mp *grip) { + struct grip_port *port = grip->port[slot]; + struct input_dev *input_dev; int j, t; - grip->dev[slot].private = grip; - grip->dev[slot].open = grip_open; - grip->dev[slot].close = grip_close; - grip->dev[slot].name = grip_name[grip->mode[slot]]; - grip->dev[slot].id.bustype = BUS_GAMEPORT; - grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; - grip->dev[slot].id.product = 0x0100 + grip->mode[slot]; - grip->dev[slot].id.version = 0x0100; - grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + port->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; - for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) - input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0); + input_dev->name = grip_name[port->mode]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + input_dev->id.product = 0x0100 + port->mode; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &grip->gameport->dev; + input_dev->private = grip; - for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++) + input_dev->open = grip_open; + input_dev->close = grip_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++) + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + + for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++) if (t > 0) - set_bit(t, grip->dev[slot].keybit); + set_bit(t, input_dev->keybit); - input_register_device(grip->dev + slot); - grip->registered[slot] = 1; + input_register_device(port->dev); + port->registered = 1; - if (grip->dirty[slot]) /* report initial state, if any */ + if (port->dirty) /* report initial state, if any */ report_slot(grip, slot); - printk(KERN_INFO "grip_mp: added %s, slot %d\n", - grip_name[grip->mode[slot]], slot); + return 0; } static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) @@ -626,7 +651,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) goto fail2; } - if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) { + if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) { /* nothing plugged in */ err = -ENODEV; goto fail2; @@ -646,8 +671,8 @@ static void grip_disconnect(struct gameport *gameport) int i; for (i = 0; i < 4; i++) - if (grip->registered[i]) - input_unregister_device(grip->dev + i); + if (grip->port[i]->registered) + input_unregister_device(grip->port[i]->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(grip); diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 6a70ec429f06..c528473c09d8 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -67,7 +67,7 @@ struct guillemot_type { struct guillemot { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int bads; int reads; struct guillemot_type *type; @@ -123,7 +123,7 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data) static void guillemot_poll(struct gameport *gameport) { struct guillemot *guillemot = gameport_get_drvdata(gameport); - struct input_dev *dev = &guillemot->dev; + struct input_dev *dev = guillemot->dev; u8 data[GUILLEMOT_MAX_LENGTH]; int i; @@ -179,14 +179,20 @@ static void guillemot_close(struct input_dev *dev) static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) { struct guillemot *guillemot; + struct input_dev *input_dev; u8 data[GUILLEMOT_MAX_LENGTH]; int i, t; int err; - if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL))) - return -ENOMEM; + guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!guillemot || !input_dev) { + err = -ENOMEM; + goto fail1; + } guillemot->gameport = gameport; + guillemot->dev = input_dev; gameport_set_drvdata(gameport, guillemot); @@ -216,41 +222,40 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * gameport_set_poll_interval(gameport, 20); sprintf(guillemot->phys, "%s/input0", gameport->phys); - guillemot->type = guillemot_type + i; - guillemot->dev.private = guillemot; - guillemot->dev.open = guillemot_open; - guillemot->dev.close = guillemot_close; + input_dev->name = guillemot_type[i].name; + input_dev->phys = guillemot->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; + input_dev->id.product = guillemot_type[i].id; + input_dev->id.version = (int)data[14] << 8 | data[15]; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = guillemot; - guillemot->dev.name = guillemot_type[i].name; - guillemot->dev.phys = guillemot->phys; - guillemot->dev.id.bustype = BUS_GAMEPORT; - guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; - guillemot->dev.id.product = guillemot_type[i].id; - guillemot->dev.id.version = (int)data[14] << 8 | data[15]; + input_dev->open = guillemot_open; + input_dev->close = guillemot_close; - guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) - input_set_abs_params(&guillemot->dev, t, 0, 255, 0, 0); + input_set_abs_params(input_dev, t, 0, 255, 0, 0); if (guillemot->type->hat) { - input_set_abs_params(&guillemot->dev, ABS_HAT0X, -1, 1, 0, 0); - input_set_abs_params(&guillemot->dev, ABS_HAT0Y, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0); } for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) - set_bit(t, guillemot->dev.keybit); + set_bit(t, input_dev->keybit); - input_register_device(&guillemot->dev); - printk(KERN_INFO "input: %s ver %d.%02d on %s\n", - guillemot->type->name, data[14], data[15], gameport->phys); + input_register_device(guillemot->dev); return 0; fail2: gameport_close(gameport); fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(guillemot); return err; } @@ -260,7 +265,7 @@ static void guillemot_disconnect(struct gameport *gameport) struct guillemot *guillemot = gameport_get_drvdata(gameport); printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); - input_unregister_device(&guillemot->dev); + input_unregister_device(guillemot->dev); gameport_close(gameport); kfree(guillemot); } diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index e31b7b93fde2..64b9c31c47fc 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -144,7 +144,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) int is_update; /* Check this effect type is supported by this device */ - if (!test_bit(effect->type, iforce->dev.ffbit)) + if (!test_bit(effect->type, iforce->dev->ffbit)) return -EINVAL; /* @@ -152,30 +152,31 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) */ if (effect->id == -1) { - for (id=0; id < FF_EFFECTS_MAX; ++id) - if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; + for (id = 0; id < FF_EFFECTS_MAX; ++id) + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) + break; - if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) + if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max) return -ENOMEM; effect->id = id; iforce->core_effects[id].owner = current->pid; - iforce->core_effects[id].flags[0] = (1<core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */ is_update = FALSE; } else { /* We want to update an effect */ - if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; + if (!CHECK_OWNERSHIP(effect->id, iforce)) + return -EACCES; /* Parameter type cannot be updated */ if (effect->type != iforce->core_effects[effect->id].effect.type) return -EINVAL; /* Check the effect is not already being updated */ - if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) return -EAGAIN; - } is_update = TRUE; } @@ -339,15 +340,19 @@ void iforce_delete_device(struct iforce *iforce) int iforce_init_device(struct iforce *iforce) { + struct input_dev *input_dev; unsigned char c[] = "CEOV"; int i; + input_dev = input_allocate_device(); + if (input_dev) + return -ENOMEM; + init_waitqueue_head(&iforce->wait); spin_lock_init(&iforce->xmit_lock); init_MUTEX(&iforce->mem_mutex); iforce->xmit.buf = iforce->xmit_data; - - iforce->dev.ff_effects_max = 10; + iforce->dev = input_dev; /* * Input device fields. @@ -356,26 +361,27 @@ int iforce_init_device(struct iforce *iforce) switch (iforce->bus) { #ifdef CONFIG_JOYSTICK_IFORCE_USB case IFORCE_USB: - iforce->dev.id.bustype = BUS_USB; - iforce->dev.dev = &iforce->usbdev->dev; + input_dev->id.bustype = BUS_USB; + input_dev->cdev.dev = &iforce->usbdev->dev; break; #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 case IFORCE_232: - iforce->dev.id.bustype = BUS_RS232; - iforce->dev.dev = &iforce->serio->dev; + input_dev->id.bustype = BUS_RS232; + input_dev->cdev.dev = &iforce->serio->dev; break; #endif } - iforce->dev.private = iforce; - iforce->dev.name = "Unknown I-Force device"; - iforce->dev.open = iforce_open; - iforce->dev.close = iforce_release; - iforce->dev.flush = iforce_flush; - iforce->dev.event = iforce_input_event; - iforce->dev.upload_effect = iforce_upload_effect; - iforce->dev.erase_effect = iforce_erase_effect; + input_dev->private = iforce; + input_dev->name = "Unknown I-Force device"; + input_dev->open = iforce_open; + input_dev->close = iforce_release; + input_dev->flush = iforce_flush; + input_dev->event = iforce_input_event; + input_dev->upload_effect = iforce_upload_effect; + input_dev->erase_effect = iforce_erase_effect; + input_dev->ff_effects_max = 10; /* * On-device memory allocation. @@ -399,7 +405,8 @@ int iforce_init_device(struct iforce *iforce) if (i == 20) { /* 5 seconds */ printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); - return -1; + input_free_device(input_dev); + return -ENODEV; } /* @@ -407,12 +414,12 @@ int iforce_init_device(struct iforce *iforce) */ if (!iforce_get_id_packet(iforce, "M")) - iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; + input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); if (!iforce_get_id_packet(iforce, "P")) - iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1]; + input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); @@ -422,15 +429,15 @@ int iforce_init_device(struct iforce *iforce) printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); if (!iforce_get_id_packet(iforce, "N")) - iforce->dev.ff_effects_max = iforce->edata[1]; + iforce->dev->ff_effects_max = iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); /* Check if the device can store more effects than the driver can really handle */ - if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { + if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) { printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", - iforce->dev.ff_effects_max, FF_EFFECTS_MAX); - iforce->dev.ff_effects_max = FF_EFFECTS_MAX; + iforce->dev->ff_effects_max, FF_EFFECTS_MAX); + iforce->dev->ff_effects_max = FF_EFFECTS_MAX; } /* @@ -453,29 +460,28 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; iforce_device[i].idvendor; i++) - if (iforce_device[i].idvendor == iforce->dev.id.vendor && - iforce_device[i].idproduct == iforce->dev.id.product) + if (iforce_device[i].idvendor == input_dev->id.vendor && + iforce_device[i].idproduct == input_dev->id.product) break; iforce->type = iforce_device + i; - iforce->dev.name = iforce->type->name; + input_dev->name = iforce->type->name; /* * Set input device bitfields and ranges. */ - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); for (i = 0; iforce->type->btn[i] >= 0; i++) { signed short t = iforce->type->btn[i]; - set_bit(t, iforce->dev.keybit); + set_bit(t, input_dev->keybit); } - set_bit(BTN_DEAD, iforce->dev.keybit); + set_bit(BTN_DEAD, input_dev->keybit); for (i = 0; iforce->type->abs[i] >= 0; i++) { signed short t = iforce->type->abs[i]; - set_bit(t, iforce->dev.absbit); switch (t) { @@ -483,52 +489,42 @@ int iforce_init_device(struct iforce *iforce) case ABS_Y: case ABS_WHEEL: - iforce->dev.absmax[t] = 1920; - iforce->dev.absmin[t] = -1920; - iforce->dev.absflat[t] = 128; - iforce->dev.absfuzz[t] = 16; - - set_bit(t, iforce->dev.ffbit); + input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); + set_bit(t, input_dev->ffbit); break; case ABS_THROTTLE: case ABS_GAS: case ABS_BRAKE: - iforce->dev.absmax[t] = 255; - iforce->dev.absmin[t] = 0; + input_set_abs_params(input_dev, t, 0, 255, 0, 0); break; case ABS_RUDDER: - iforce->dev.absmax[t] = 127; - iforce->dev.absmin[t] = -128; + input_set_abs_params(input_dev, t, -128, 127, 0, 0); break; case ABS_HAT0X: case ABS_HAT0Y: case ABS_HAT1X: case ABS_HAT1Y: - iforce->dev.absmax[t] = 1; - iforce->dev.absmin[t] = -1; + + input_set_abs_params(input_dev, t, -1, 1, 0, 0); break; } } for (i = 0; iforce->type->ff[i] >= 0; i++) - set_bit(iforce->type->ff[i], iforce->dev.ffbit); + set_bit(iforce->type->ff[i], input_dev->ffbit); /* * Register input device. */ - input_register_device(&iforce->dev); + input_register_device(iforce->dev); - printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); - - printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", - iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end); + printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open); return 0; } diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index e5a31e55d3e2..4a2629243e19 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -139,7 +139,8 @@ printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) { int i; - for (i=0; idev.ff_effects_max; ++i) { + + for (i = 0; i < iforce->dev->ff_effects_max; ++i) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && (iforce->core_effects[i].mod1_chunk.start == addr || iforce->core_effects[i].mod2_chunk.start == addr)) { @@ -153,7 +154,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs) { - struct input_dev *dev = &iforce->dev; + struct input_dev *dev = iforce->dev; int i; static int being_used = 0; diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 11f51905cba7..64a78c515484 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -131,11 +131,10 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) struct iforce *iforce; int err; - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) + iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); + if (!iforce) return -ENOMEM; - memset(iforce, 0, sizeof(struct iforce)); - iforce->bus = IFORCE_232; iforce->serio = serio; @@ -148,7 +147,8 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) return err; } - if (iforce_init_device(iforce)) { + err = iforce_init_device(iforce); + if (err) { serio_close(serio); serio_set_drvdata(serio, NULL); kfree(iforce); @@ -162,7 +162,7 @@ static void iforce_serio_disconnect(struct serio *serio) { struct iforce *iforce = serio_get_drvdata(serio); - input_unregister_device(&iforce->dev); + input_unregister_device(iforce->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(iforce); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 58600f91eff5..64b4a3080985 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -135,28 +135,24 @@ static int iforce_usb_probe(struct usb_interface *intf, struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; + int err = -ENOMEM; interface = intf->cur_altsetting; epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) + if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) goto fail; - memset(iforce, 0, sizeof(struct iforce)); - - if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } - if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } - if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } iforce->bus = IFORCE_USB; iforce->usbdev = dev; @@ -174,7 +170,9 @@ static int iforce_usb_probe(struct usb_interface *intf, usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); - if (iforce_init_device(iforce)) goto fail; + err = iforce_init_device(iforce); + if (err) + goto fail; usb_set_intfdata(intf, iforce); return 0; @@ -187,7 +185,7 @@ static int iforce_usb_probe(struct usb_interface *intf, kfree(iforce); } - return -ENODEV; + return err; } /* Called by iforce_delete() */ @@ -211,7 +209,7 @@ static void iforce_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (iforce) { iforce->usbdev = NULL; - input_unregister_device(&iforce->dev); + input_unregister_device(iforce->dev); if (!open) { iforce_delete_device(iforce); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index bce247bc300b..146f406b8f8a 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -117,7 +117,7 @@ struct iforce_device { }; struct iforce { - struct input_dev dev; /* Input device interface */ + struct input_dev *dev; /* Input device interface */ struct iforce_device *type; int bus; diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index d7b3472bd686..8511ee7bb263 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL"); struct interact { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int bads; int reads; unsigned char type; @@ -130,7 +130,7 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data static void interact_poll(struct gameport *gameport) { struct interact *interact = gameport_get_drvdata(gameport); - struct input_dev *dev = &interact->dev; + struct input_dev *dev = interact->dev; u32 data[3]; int i; @@ -208,14 +208,20 @@ static void interact_close(struct input_dev *dev) static int interact_connect(struct gameport *gameport, struct gameport_driver *drv) { struct interact *interact; + struct input_dev *input_dev; __u32 data[3]; int i, t; int err; - if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL))) - return -ENOMEM; + interact = kzalloc(sizeof(struct interact), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!interact || !input_dev) { + err = -ENOMEM; + goto fail1; + } interact->gameport = gameport; + interact->dev = input_dev; gameport_set_drvdata(gameport, interact); @@ -249,41 +255,40 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d interact->type = i; interact->length = interact_type[i].length; - interact->dev.private = interact; - interact->dev.open = interact_open; - interact->dev.close = interact_close; + input_dev->name = interact_type[i].name; + input_dev->phys = interact->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT; + input_dev->id.product = interact_type[i].id; + input_dev->id.version = 0x0100; + input_dev->private = interact; - interact->dev.name = interact_type[i].name; - interact->dev.phys = interact->phys; - interact->dev.id.bustype = BUS_GAMEPORT; - interact->dev.id.vendor = GAMEPORT_ID_VENDOR_INTERACT; - interact->dev.id.product = interact_type[i].id; - interact->dev.id.version = 0x0100; + input_dev->open = interact_open; + input_dev->close = interact_close; - interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { - set_bit(t, interact->dev.absbit); + set_bit(t, input_dev->absbit); if (i < interact_type[interact->type].b8) { - interact->dev.absmin[t] = 0; - interact->dev.absmax[t] = 255; + input_dev->absmin[t] = 0; + input_dev->absmax[t] = 255; } else { - interact->dev.absmin[t] = -1; - interact->dev.absmax[t] = 1; + input_dev->absmin[t] = -1; + input_dev->absmax[t] = 1; } } for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) - set_bit(t, interact->dev.keybit); + set_bit(t, input_dev->keybit); - input_register_device(&interact->dev); - printk(KERN_INFO "input: %s on %s\n", - interact_type[interact->type].name, gameport->phys); + input_register_device(interact->dev); return 0; fail2: gameport_close(gameport); fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(interact); return err; } @@ -292,7 +297,7 @@ static void interact_disconnect(struct gameport *gameport) { struct interact *interact = gameport_get_drvdata(gameport); - input_unregister_device(&interact->dev); + input_unregister_device(interact->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(interact); diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 1ba503627242..ca3cc2319d6a 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -49,14 +49,13 @@ MODULE_LICENSE("GPL"); static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; -static char *magellan_name = "LogiCad3D Magellan / SpaceMouse"; /* * Per-Magellan data. */ struct magellan { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[MAGELLAN_MAX_LENGTH]; char phys[32]; @@ -85,7 +84,7 @@ static int magellan_crunch_nibbles(unsigned char *data, int count) static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs) { - struct input_dev *dev = &magellan->dev; + struct input_dev *dev = magellan->dev; unsigned char *data = magellan->data; int i, t; @@ -138,9 +137,9 @@ static void magellan_disconnect(struct serio *serio) { struct magellan* magellan = serio_get_drvdata(serio); - input_unregister_device(&magellan->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(magellan->dev); kfree(magellan); } @@ -153,52 +152,48 @@ static void magellan_disconnect(struct serio *serio) static int magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; - int i, t; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; + int i; - if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL))) - return -ENOMEM; - - memset(magellan, 0, sizeof(struct magellan)); - - magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (i = 0; i < 9; i++) - set_bit(magellan_buttons[i], magellan->dev.keybit); - - for (i = 0; i < 6; i++) { - t = magellan_axes[i]; - set_bit(t, magellan->dev.absbit); - magellan->dev.absmin[t] = -360; - magellan->dev.absmax[t] = 360; - } + magellan = kzalloc(sizeof(struct magellan), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!magellan || !input_dev) + goto fail; + magellan->dev = input_dev; sprintf(magellan->phys, "%s/input0", serio->phys); - init_input_dev(&magellan->dev); - magellan->dev.private = magellan; - magellan->dev.name = magellan_name; - magellan->dev.phys = magellan->phys; - magellan->dev.id.bustype = BUS_RS232; - magellan->dev.id.vendor = SERIO_MAGELLAN; - magellan->dev.id.product = 0x0001; - magellan->dev.id.version = 0x0100; - magellan->dev.dev = &serio->dev; + input_dev->name = "LogiCad3D Magellan / SpaceMouse"; + input_dev->phys = magellan->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_MAGELLAN; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = magellan; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 9; i++) + set_bit(magellan_buttons[i], input_dev->keybit); + + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, magellan_axes[i], -360, 360, 0, 0); serio_set_drvdata(serio, magellan); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(magellan); - return err; - } - - input_register_device(&magellan->dev); - - printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys); + if (err) + goto fail; + input_register_device(magellan->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(magellan); + return err; } /* diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 9e0353721a35..eaaad45cc750 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -113,7 +113,7 @@ static struct { struct sw { struct gameport *gameport; - struct input_dev dev[4]; + struct input_dev *dev[4]; char name[64]; char phys[4][32]; int length; @@ -301,7 +301,7 @@ static int sw_check(__u64 t) static int sw_parse(unsigned char *buf, struct sw *sw) { int hat, i, j; - struct input_dev *dev = sw->dev; + struct input_dev *dev; switch (sw->type) { @@ -310,6 +310,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1; + dev = sw->dev[0]; + input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); @@ -335,13 +337,13 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (sw_parity(GB(i*15,15))) return -1; - input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); - input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); + input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); + input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) - input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); - input_sync(dev + i); + input_sync(sw->dev[i]); } return 0; @@ -352,6 +354,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_X, GB( 9,10)); input_report_abs(dev, ABS_Y, GB(19,10)); input_report_abs(dev, ABS_RZ, GB(36, 6)); @@ -372,6 +375,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_X, GB( 0,10)); input_report_abs(dev, ABS_Y, GB(16,10)); input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); @@ -396,6 +400,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,33))) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_RX, GB( 0,10)); input_report_abs(dev, ABS_RUDDER, GB(10, 6)); input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); @@ -581,6 +586,7 @@ static int sw_guess_mode(unsigned char *buf, int len) static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) { struct sw *sw; + struct input_dev *input_dev; int i, j, k, l; int err; unsigned char *buf = NULL; /* [SW_LENGTH] */ @@ -729,42 +735,50 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); - sw->dev[i].private = sw; + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; + } - sw->dev[i].open = sw_open; - sw->dev[i].close = sw_close; + input_dev->name = sw->name; + input_dev->phys = sw->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; + input_dev->id.product = sw->type; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = sw; - sw->dev[i].name = sw->name; - sw->dev[i].phys = sw->phys[i]; - sw->dev[i].id.bustype = BUS_GAMEPORT; - sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; - sw->dev[i].id.product = sw->type; - sw->dev[i].id.version = 0x0100; + input_dev->open = sw_open; + input_dev->close = sw_close; - sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (j = 0; (bits = sw_bit[sw->type][j]); j++) { code = sw_abs[sw->type][j]; - set_bit(code, sw->dev[i].absbit); - sw->dev[i].absmax[code] = (1 << bits) - 1; - sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0; - sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; + set_bit(code, input_dev->absbit); + input_dev->absmax[code] = (1 << bits) - 1; + input_dev->absmin[code] = (bits == 1) ? -1 : 0; + input_dev->absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; if (code != ABS_THROTTLE) - sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; + input_dev->absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; } for (j = 0; (code = sw_btn[sw->type][j]); j++) - set_bit(code, sw->dev[i].keybit); + set_bit(code, input_dev->keybit); - input_register_device(sw->dev + i); - printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n", - sw->name, comment, gameport->phys, m, l, k); + dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); + + input_register_device(sw->dev[i]); } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: while (--i >= 0) + input_unregister_device(sw->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(sw); kfree(buf); kfree(idbuf); @@ -777,7 +791,7 @@ static void sw_disconnect(struct gameport *gameport) int i; for (i = 0; i < sw->number; i++) - input_unregister_device(sw->dev + i); + input_unregister_device(sw->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(sw); diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index a436f2220856..d6f8db8ec3fd 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -70,8 +70,7 @@ static char *spaceball_names[] = { */ struct spaceball { - struct input_dev dev; - struct serio *serio; + struct input_dev *dev; int idx; int escape; unsigned char data[SPACEBALL_MAX_LENGTH]; @@ -85,7 +84,7 @@ struct spaceball { static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs) { - struct input_dev *dev = &spaceball->dev; + struct input_dev *dev = spaceball->dev; unsigned char *data = spaceball->data; int i; @@ -193,9 +192,9 @@ static void spaceball_disconnect(struct serio *serio) { struct spaceball* spaceball = serio_get_drvdata(serio); - input_unregister_device(&spaceball->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(spaceball->dev); kfree(spaceball); } @@ -208,69 +207,62 @@ static void spaceball_disconnect(struct serio *serio) static int spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; - int i, t, id; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; + int i, id; if ((id = serio->id.id) > SPACEBALL_MAX_ID) return -ENODEV; - if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) - return - ENOMEM; + spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!spaceball || !input_dev) + goto fail; - memset(spaceball, 0, sizeof(struct spaceball)); + spaceball->dev = input_dev; + sprintf(spaceball->phys, "%s/input0", serio->phys); - spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->name = spaceball_names[id]; + input_dev->phys = spaceball->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SPACEBALL; + input_dev->id.product = id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceball; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); switch (id) { case SPACEBALL_4000FLX: case SPACEBALL_4000FLX_L: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); - spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_9); + input_dev->keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); default: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); case SPACEBALL_3003C: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); } - for (i = 0; i < 6; i++) { - t = spaceball_axes[i]; - set_bit(t, spaceball->dev.absbit); - spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; - spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; - spaceball->dev.absflat[t] = i < 3 ? 40 : 8; - spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; + for (i = 0; i < 3; i++) { + input_set_abs_params(input_dev, ABS_X + i, -8000, 8000, 8, 40); + input_set_abs_params(input_dev, ABS_RX + i, -1600, 1600, 2, 8); } - spaceball->serio = serio; - spaceball->dev.private = spaceball; - - sprintf(spaceball->phys, "%s/input0", serio->phys); - - init_input_dev(&spaceball->dev); - spaceball->dev.name = spaceball_names[id]; - spaceball->dev.phys = spaceball->phys; - spaceball->dev.id.bustype = BUS_RS232; - spaceball->dev.id.vendor = SERIO_SPACEBALL; - spaceball->dev.id.product = id; - spaceball->dev.id.version = 0x0100; - spaceball->dev.dev = &serio->dev; - serio_set_drvdata(serio, spaceball); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(spaceball); - return err; - } - - input_register_device(&spaceball->dev); - - printk(KERN_INFO "input: %s on serio%s\n", - spaceball_names[id], serio->phys); + if (err) + goto fail; + input_register_device(spaceball->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(spaceball); + return err; } /* diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 01fd2e4791ae..7c123a01c58e 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -52,15 +52,13 @@ MODULE_LICENSE("GPL"); static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A }; static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; -static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger"; /* * Per-Orb data. */ struct spaceorb { - struct input_dev dev; - struct serio *serio; + struct input_dev *dev; int idx; unsigned char data[SPACEORB_MAX_LENGTH]; char phys[32]; @@ -78,7 +76,7 @@ static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs) { - struct input_dev *dev = &spaceorb->dev; + struct input_dev *dev = spaceorb->dev; unsigned char *data = spaceorb->data; unsigned char c = 0; int axes[6]; @@ -95,8 +93,8 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r case 'R': /* Reset packet */ spaceorb->data[spaceorb->idx - 1] = 0; for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); - printk(KERN_INFO "input: %s [%s] on %s\n", - spaceorb_name, spaceorb->data + i, spaceorb->serio->phys); + printk(KERN_INFO "input: %s [%s] is %s\n", + dev->name, spaceorb->data + i, spaceorb->phys); break; case 'D': /* Ball + button data */ @@ -123,7 +121,7 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r case 'E': /* Error packet */ if (spaceorb->idx != 4) return; - printk(KERN_ERR "joy-spaceorb: Device error. [ "); + printk(KERN_ERR "spaceorb: Device error. [ "); for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]); printk("]\n"); break; @@ -154,9 +152,9 @@ static void spaceorb_disconnect(struct serio *serio) { struct spaceorb* spaceorb = serio_get_drvdata(serio); - input_unregister_device(&spaceorb->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(spaceorb->dev); kfree(spaceorb); } @@ -169,52 +167,48 @@ static void spaceorb_disconnect(struct serio *serio) static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; - int i, t; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; + int i; - if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL))) - return -ENOMEM; - - memset(spaceorb, 0, sizeof(struct spaceorb)); - - spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (i = 0; i < 6; i++) - set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); - - for (i = 0; i < 6; i++) { - t = spaceorb_axes[i]; - set_bit(t, spaceorb->dev.absbit); - spaceorb->dev.absmin[t] = -508; - spaceorb->dev.absmax[t] = 508; - } - - spaceorb->serio = serio; - spaceorb->dev.private = spaceorb; + spaceorb = kzalloc(sizeof(struct spaceorb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!spaceorb || !input_dev) + goto fail; + spaceorb->dev = input_dev; sprintf(spaceorb->phys, "%s/input0", serio->phys); - init_input_dev(&spaceorb->dev); - spaceorb->dev.name = spaceorb_name; - spaceorb->dev.phys = spaceorb->phys; - spaceorb->dev.id.bustype = BUS_RS232; - spaceorb->dev.id.vendor = SERIO_SPACEORB; - spaceorb->dev.id.product = 0x0001; - spaceorb->dev.id.version = 0x0100; - spaceorb->dev.dev = &serio->dev; + input_dev->name = "SpaceTec SpaceOrb 360 / Avenger"; + input_dev->phys = spaceorb->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SPACEORB; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceorb; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 6; i++) + set_bit(spaceorb_buttons[i], input_dev->keybit); + + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, spaceorb_axes[i], -508, 508, 0, 0); serio_set_drvdata(serio, spaceorb); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(spaceorb); - return err; - } - - input_register_device(&spaceorb->dev); + if (err) + goto fail; + input_register_device(spaceorb->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(spaceorb); + return err; } /* diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 6f6e6753d590..0a9ed1d30636 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -48,14 +48,12 @@ MODULE_LICENSE("GPL"); #define STINGER_MAX_LENGTH 8 -static char *stinger_name = "Gravis Stinger"; - /* * Per-Stinger data. */ struct stinger { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[STINGER_MAX_LENGTH]; char phys[32]; @@ -68,7 +66,7 @@ struct stinger { static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs) { - struct input_dev *dev = &stinger->dev; + struct input_dev *dev = stinger->dev; unsigned char *data = stinger->data; if (!stinger->idx) return; @@ -126,9 +124,9 @@ static void stinger_disconnect(struct serio *serio) { struct stinger *stinger = serio_get_drvdata(serio); - input_unregister_device(&stinger->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(stinger->dev); kfree(stinger); } @@ -141,53 +139,46 @@ static void stinger_disconnect(struct serio *serio) static int stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; - int i; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) - return -ENOMEM; - - memset(stinger, 0, sizeof(struct stinger)); - - stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ - BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ - BIT(BTN_START) | BIT(BTN_SELECT); - stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!stinger || !input_dev) + goto fail; + stinger->dev = input_dev; sprintf(stinger->phys, "%s/serio0", serio->phys); - init_input_dev(&stinger->dev); - stinger->dev.name = stinger_name; - stinger->dev.phys = stinger->phys; - stinger->dev.id.bustype = BUS_RS232; - stinger->dev.id.vendor = SERIO_STINGER; - stinger->dev.id.product = 0x0001; - stinger->dev.id.version = 0x0100; - stinger->dev.dev = &serio->dev; + input_dev->name = "Gravis Stinger"; + input_dev->phys = stinger->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_STINGER; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = stinger; - for (i = 0; i < 2; i++) { - stinger->dev.absmax[ABS_X+i] = 64; - stinger->dev.absmin[ABS_X+i] = -64; - stinger->dev.absflat[ABS_X+i] = 4; - } - - stinger->dev.private = stinger; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | + BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | + BIT(BTN_START) | BIT(BTN_SELECT); + input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 4); + input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 4); serio_set_drvdata(serio, stinger); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(stinger); - return err; - } - - input_register_device(&stinger->dev); - - printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys); + if (err) + goto fail; + input_register_device(stinger->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(stinger); + return err; } /* diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 7431efc4330e..3a7d1bb46472 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -63,37 +63,70 @@ MODULE_LICENSE("GPL"); #define TMDC_ABS_HAT 4 #define TMDC_BTN 16 -static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; -static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; +static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; +static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; -static signed char tmdc_abs[TMDC_ABS] = +static const signed char tmdc_abs[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; -static signed char tmdc_abs_hat[TMDC_ABS_HAT] = +static const signed char tmdc_abs_hat[TMDC_ABS_HAT] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static signed char tmdc_abs_at[TMDC_ABS] = +static const signed char tmdc_abs_at[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; -static signed char tmdc_abs_fm[TMDC_ABS] = +static const signed char tmdc_abs_fm[TMDC_ABS] = { ABS_RX, ABS_RY, ABS_X, ABS_Y }; -static short tmdc_btn_pad[TMDC_BTN] = +static const short tmdc_btn_pad[TMDC_BTN] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; -static short tmdc_btn_joy[TMDC_BTN] = +static const short tmdc_btn_joy[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; -static short tmdc_btn_fm[TMDC_BTN] = +static const short tmdc_btn_fm[TMDC_BTN] = { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; -static short tmdc_btn_at[TMDC_BTN] = +static const short tmdc_btn_at[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, BTN_BASE3, BTN_BASE2, BTN_BASE }; -static struct { +static const struct { int x; int y; } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; +static const struct tmdc_model { + unsigned char id; + const char *name; + char abs; + char hats; + char btnc[4]; + char btno[4]; + const signed char *axes; + const short *buttons; +} tmdc_models[] = { + { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, + { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, + { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy } +}; + + +struct tmdc_port { + struct input_dev *dev; + char name[64]; + char phys[32]; + int mode; + const signed char *abs; + const short *btn; + unsigned char absc; + unsigned char btnc[4]; + unsigned char btno[4]; +}; + struct tmdc { struct gameport *gameport; - struct input_dev dev[2]; + struct tmdc_port *port[2]; +#if 0 + struct input_dev *dev[2]; char name[2][64]; char phys[2][32]; int mode[2]; @@ -102,6 +135,7 @@ struct tmdc { unsigned char absc[2]; unsigned char btnc[2][4]; unsigned char btno[2][4]; +#endif int reads; int bads; unsigned char exists; @@ -156,6 +190,50 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); } +static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data) +{ + int i, k, l; + + if (data[TMDC_BYTE_ID] != port->mode) + return -1; + + for (i = 0; i < port->absc; i++) { + if (port->abs[i] < 0) + return 0; + + input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]); + } + + switch (port->mode) { + + case TMDC_MODE_M3DI: + + i = tmdc_byte_d[0]; + input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1)); + input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i] & 1)); + break; + + case TMDC_MODE_AT: + + i = tmdc_byte_a[3]; + input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x); + input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y); + break; + + } + + for (k = l = 0; k < 4; k++) { + for (i = 0; i < port->btnc[k]; i++) + input_report_key(port->dev, port->btn[i + l], + ((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1)); + l += port->btnc[k]; + } + + input_sync(port->dev); + + return 0; +} + /* * tmdc_poll() reads and analyzes ThrustMaster joystick data. */ @@ -164,57 +242,21 @@ static void tmdc_poll(struct gameport *gameport) { unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc = gameport_get_drvdata(gameport); - struct input_dev *dev; unsigned char r, bad = 0; - int i, j, k, l; + int i; tmdc->reads++; if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) bad = 1; - else + else { + for (i = 0; i < 2; i++) { + if (r & (1 << i) & tmdc->exists) { - for (j = 0; j < 2; j++) - if (r & (1 << j) & tmdc->exists) { - - if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { - bad = 1; - continue; + if (tmdc_parse_packet(tmdc->port[i], data[i])) + bad = 1; } - - dev = tmdc->dev + j; - - for (i = 0; i < tmdc->absc[j]; i++) { - if (tmdc->abs[j][i] < 0) continue; - input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); - } - - switch (tmdc->mode[j]) { - - case TMDC_MODE_M3DI: - - i = tmdc_byte_d[0]; - input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); - input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); - break; - - case TMDC_MODE_AT: - - i = tmdc_byte_a[3]; - input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); - input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); - break; - - } - - for (k = l = 0; k < 4; k++) { - for (i = 0; i < tmdc->btnc[j][k]; i++) - input_report_key(dev, tmdc->btn[j][i + l], - ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); - l += tmdc->btnc[j][k]; - } - - input_sync(dev); + } } tmdc->bads += bad; @@ -235,31 +277,89 @@ static void tmdc_close(struct input_dev *dev) gameport_stop_polling(tmdc->gameport); } +static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) +{ + const struct tmdc_model *model; + struct tmdc_port *port; + struct input_dev *input_dev; + int i, j, b = 0; + + tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!port || !input_dev) { + kfree(port); + input_free_device(input_dev); + return -ENOMEM; + } + + port->mode = data[TMDC_BYTE_ID]; + + for (model = tmdc_models; model->id && model->id != port->mode; model++) + /* empty */; + + port->abs = model->axes; + port->btn = model->buttons; + + if (!model->id) { + port->absc = data[TMDC_BYTE_DEF] >> 4; + for (i = 0; i < 4; i++) + port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0; + } else { + port->absc = model->abs; + for (i = 0; i < 4; i++) + port->btnc[i] = model->btnc[i]; + } + + for (i = 0; i < 4; i++) + port->btno[i] = model->btno[i]; + + snprintf(port->name, sizeof(port->name), model->name, + port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode); + snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i); + + port->dev = input_dev; + + input_dev->name = port->name; + input_dev->phys = port->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; + input_dev->id.product = model->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &tmdc->gameport->dev; + input_dev->private = tmdc; + + input_dev->open = tmdc_open; + input_dev->close = tmdc_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < port->absc && i < TMDC_ABS; i++) + if (port->abs[i] >= 0) + input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4); + + for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++) + input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0); + + for (i = 0; i < 4; i++) { + for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++) + set_bit(port->btn[j + b], input_dev->keybit); + b += port->btnc[i]; + } + + input_register_device(port->dev); + + return 0; +} + /* * tmdc_probe() probes for ThrustMaster type joysticks. */ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) { - static struct models { - unsigned char id; - char *name; - char abs; - char hats; - char btnc[4]; - char btno[4]; - signed char *axes; - short *buttons; - } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, - { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, - { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, - { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, - { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, - { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; - unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc; - int i, j, k, l, m; + int i; int err; if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL))) @@ -281,68 +381,25 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, tmdc_poll); gameport_set_poll_interval(gameport, 20); - for (j = 0; j < 2; j++) - if (tmdc->exists & (1 << j)) { + for (i = 0; i < 2; i++) { + if (tmdc->exists & (1 << i)) { - tmdc->mode[j] = data[j][TMDC_BYTE_ID]; - - for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); - - tmdc->abs[j] = models[m].axes; - tmdc->btn[j] = models[m].buttons; - - if (!models[m].id) { - models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; - for (k = 0; k < 4; k++) - models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; - } - - tmdc->absc[j] = models[m].abs; - for (k = 0; k < 4; k++) { - tmdc->btnc[j][k] = models[m].btnc[k]; - tmdc->btno[j][k] = models[m].btno[k]; - } - - sprintf(tmdc->name[j], models[m].name, models[m].abs, - (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); - - sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j); - - tmdc->dev[j].private = tmdc; - tmdc->dev[j].open = tmdc_open; - tmdc->dev[j].close = tmdc_close; - - tmdc->dev[j].name = tmdc->name[j]; - tmdc->dev[j].phys = tmdc->phys[j]; - tmdc->dev[j].id.bustype = BUS_GAMEPORT; - tmdc->dev[j].id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; - tmdc->dev[j].id.product = models[m].id; - tmdc->dev[j].id.version = 0x0100; - - tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) - if (tmdc->abs[j][i] >= 0) - input_set_abs_params(&tmdc->dev[j], tmdc->abs[j][i], 8, 248, 2, 4); - - for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) - input_set_abs_params(&tmdc->dev[j], tmdc_abs_hat[i], -1, 1, 0, 0); - - - for (k = l = 0; k < 4; k++) { - for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) - set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); - l += models[m].btnc[k]; - } - - input_register_device(tmdc->dev + j); - printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys); + err = tmdc_setup_port(tmdc, i, data[i]); + if (err) + goto fail3; } + } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: while (--i >= 0) { + if (tmdc->port[i]) { + input_unregister_device(tmdc->port[i]->dev); + kfree(tmdc->port[i]); + } + } + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(tmdc); return err; } @@ -352,9 +409,12 @@ static void tmdc_disconnect(struct gameport *gameport) struct tmdc *tmdc = gameport_get_drvdata(gameport); int i; - for (i = 0; i < 2; i++) - if (tmdc->exists & (1 << i)) - input_unregister_device(tmdc->dev + i); + for (i = 0; i < 2; i++) { + if (tmdc->port[i]) { + input_unregister_device(tmdc->port[i]->dev); + kfree(tmdc->port[i]); + } + } gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(tmdc); diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 0c5b9c8297cd..7e9764937d06 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -42,19 +42,21 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); -static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs __initdata = 0; -module_param_array_named(map, tgfx, int, &tgfx_nargs, 0); +#define TGFX_MAX_PORTS 3 +#define TGFX_MAX_DEVICES 7 + +struct tgfx_config { + int args[TGFX_MAX_DEVICES + 1]; + int nargs; +}; + +static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata; + +module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0); MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); - -static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_2 __initdata = 0; -module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0); +module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0); MODULE_PARM_DESC(map2, "Describes second set of devices"); - -static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_3 __initdata = 0; -module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0); +module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); __obsolete_setup("tgfx="); @@ -75,17 +77,17 @@ __obsolete_setup("tgfx_3="); #define TGFX_TOP2 0x08 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; -static char *tgfx_name = "TurboGraFX Multisystem joystick"; static struct tgfx { struct pardevice *pd; struct timer_list timer; - struct input_dev dev[7]; - char phys[7][32]; + struct input_dev *dev[TGFX_MAX_DEVICES]; + char name[TGFX_MAX_DEVICES][64]; + char phys[TGFX_MAX_DEVICES][32]; int sticks; int used; struct semaphore sem; -} *tgfx_base[3]; +} *tgfx_base[TGFX_MAX_PORTS]; /* * tgfx_timer() reads and analyzes TurboGraFX joystick data. @@ -100,7 +102,7 @@ static void tgfx_timer(unsigned long private) for (i = 0; i < 7; i++) if (tgfx->sticks & (1 << i)) { - dev = tgfx->dev + i; + dev = tgfx->dev[i]; parport_write_data(tgfx->pd->port, ~(1 << i)); data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; @@ -153,118 +155,165 @@ static void tgfx_close(struct input_dev *dev) up(&tgfx->sem); } + + /* * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int *config, int nargs) +static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) { struct tgfx *tgfx; + struct input_dev *input_dev; struct parport *pp; + struct pardevice *pd; int i, j; + int err; - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); - return NULL; - } - - pp = parport_find_number(config[0]); - + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "turbografx.c: no such parport\n"); - return NULL; + err = -EINVAL; + goto err_out; } - if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; + } + + tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL); + if (!tgfx) { + printk(KERN_ERR "turbografx.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } init_MUTEX(&tgfx->sem); - - tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - - parport_put_port(pp); - - if (!tgfx->pd) { - printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); - kfree(tgfx); - return NULL; - } - + tgfx->pd = pd; init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; tgfx->timer.function = tgfx_timer; - tgfx->sticks = 0; + for (i = 0; i < n_devs; i++) { + if (n_buttons[i] < 1) + continue; - for (i = 0; i < nargs - 1; i++) - if (config[i+1] > 0 && config[i+1] < 6) { - - tgfx->sticks |= (1 << i); - - tgfx->dev[i].private = tgfx; - tgfx->dev[i].open = tgfx_open; - tgfx->dev[i].close = tgfx_close; - - sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); - - tgfx->dev[i].name = tgfx_name; - tgfx->dev[i].phys = tgfx->phys[i]; - tgfx->dev[i].id.bustype = BUS_PARPORT; - tgfx->dev[i].id.vendor = 0x0003; - tgfx->dev[i].id.product = config[i+1]; - tgfx->dev[i].id.version = 0x0100; - - tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - - for (j = 0; j < config[i+1]; j++) - set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); - - tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; - tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; - - input_register_device(tgfx->dev + i); - printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", - config[i+1], tgfx->pd->port->name); + if (n_buttons[i] > 6) { + printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); + err = -EINVAL; + goto err_free_devs; } + tgfx->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "turbografx.c: Not enough memory for input device\n"); + err = -ENOMEM; + goto err_free_devs; + } + + tgfx->sticks |= (1 << i); + snprintf(tgfx->name[i], sizeof(tgfx->name[i]), + "TurboGraFX %d-button Multisystem joystick", n_buttons[i]); + snprintf(tgfx->phys[i], sizeof(tgfx->phys[i]), + "%s/input%d", tgfx->pd->port->name, i); + + input_dev->name = tgfx->name[i]; + input_dev->phys = tgfx->phys[i]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0003; + input_dev->id.product = n_buttons[i]; + input_dev->id.version = 0x0100; + + input_dev->private = tgfx; + input_dev->open = tgfx_open; + input_dev->close = tgfx_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); + + for (j = 0; j < n_buttons[i]; j++) + set_bit(tgfx_buttons[j], input_dev->keybit); + + input_register_device(tgfx->dev[i]); + } + if (!tgfx->sticks) { - parport_unregister_device(tgfx->pd); - kfree(tgfx); - return NULL; + printk(KERN_ERR "turbografx.c: No valid devices specified\n"); + err = -EINVAL; + goto err_free_tgfx; } return tgfx; + + err_free_devs: + while (--i >= 0) + input_unregister_device(tgfx->dev[i]); + err_free_tgfx: + kfree(tgfx); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} + +static void __exit tgfx_remove(struct tgfx *tgfx) +{ + int i; + + for (i = 0; i < TGFX_MAX_DEVICES; i++) + if (tgfx->dev[i]) + input_unregister_device(tgfx->dev[i]); + parport_unregister_device(tgfx->pd); + kfree(tgfx); } static int __init tgfx_init(void) { - tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); - tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); - tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); + int i; + int have_dev = 0; + int err = 0; - if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) - return 0; + for (i = 0; i < TGFX_MAX_PORTS; i++) { + if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0) + continue; - return -ENODEV; + if (tgfx[i].nargs < 2) { + printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); + err = -EINVAL; + break; + } + + tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1); + if (IS_ERR(tgfx_base[i])) { + err = PTR_ERR(tgfx_base[i]); + break; + } + + have_dev = 1; + } + + if (err) { + while (--i >= 0) + tgfx_remove(tgfx_base[i]); + return err; + } + + return have_dev ? 0 : -ENODEV; } static void __exit tgfx_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (tgfx_base[i]) { - for (j = 0; j < 7; j++) - if (tgfx_base[i]->sticks & (1 << j)) - input_unregister_device(tgfx_base[i]->dev + j); - parport_unregister_device(tgfx_base[i]->pd); - } + for (i = 0; i < TGFX_MAX_PORTS; i++) + if (tgfx_base[i]) + tgfx_remove(tgfx_base[i]); } module_init(tgfx_init); diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 0379bc166525..cd3a1e742a30 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -69,8 +69,6 @@ MODULE_LICENSE("GPL"); #define TWIDJOY_MAX_LENGTH 5 -static char *twidjoy_name = "Handykey Twiddler"; - static struct twidjoy_button_spec { int bitshift; int bitmask; @@ -95,7 +93,7 @@ twidjoy_buttons[] = { */ struct twidjoy { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[TWIDJOY_MAX_LENGTH]; char phys[32]; @@ -108,37 +106,33 @@ struct twidjoy { static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs) { - if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { - struct input_dev *dev = &twidjoy->dev; - unsigned char *data = twidjoy->data; - struct twidjoy_button_spec *bp; - int button_bits, abs_x, abs_y; + struct input_dev *dev = twidjoy->dev; + unsigned char *data = twidjoy->data; + struct twidjoy_button_spec *bp; + int button_bits, abs_x, abs_y; - button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); + button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); - input_regs(dev, regs); + input_regs(dev, regs); - for (bp = twidjoy_buttons; bp->bitmask; bp++) { - int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; - int i; + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; + int i; - for (i = 0; i < bp->bitmask; i++) - input_report_key(dev, bp->buttons[i], i+1 == value); - } - - abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); - if (data[4] & 0x08) abs_x -= 256; - - abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); - if (data[3] & 0x02) abs_y -= 256; - - input_report_abs(dev, ABS_X, -abs_x); - input_report_abs(dev, ABS_Y, +abs_y); - - input_sync(dev); + for (i = 0; i < bp->bitmask; i++) + input_report_key(dev, bp->buttons[i], i+1 == value); } - return; + abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); + if (data[4] & 0x08) abs_x -= 256; + + abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); + if (data[3] & 0x02) abs_y -= 256; + + input_report_abs(dev, ABS_X, -abs_x); + input_report_abs(dev, ABS_Y, +abs_y); + + input_sync(dev); } /* @@ -179,9 +173,9 @@ static void twidjoy_disconnect(struct serio *serio) { struct twidjoy *twidjoy = serio_get_drvdata(serio); - input_unregister_device(&twidjoy->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(twidjoy->dev); kfree(twidjoy); } @@ -195,59 +189,49 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) - return -ENOMEM; - - memset(twidjoy, 0, sizeof(struct twidjoy)); + twidjoy = kzalloc(sizeof(struct twidjoy), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!twidjoy || !input_dev) + goto fail; + twidjoy->dev = input_dev; sprintf(twidjoy->phys, "%s/input0", serio->phys); - init_input_dev(&twidjoy->dev); - twidjoy->dev.name = twidjoy_name; - twidjoy->dev.phys = twidjoy->phys; - twidjoy->dev.id.bustype = BUS_RS232; - twidjoy->dev.id.vendor = SERIO_TWIDJOY; - twidjoy->dev.id.product = 0x0001; - twidjoy->dev.id.version = 0x0100; - twidjoy->dev.dev = &serio->dev; + input_dev->name = "Handykey Twiddler"; + input_dev->phys = twidjoy->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TWIDJOY; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = twidjoy; - twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4); + input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4); - for (bp = twidjoy_buttons; bp->bitmask; bp++) { + for (bp = twidjoy_buttons; bp->bitmask; bp++) for (i = 0; i < bp->bitmask; i++) - set_bit(bp->buttons[i], twidjoy->dev.keybit); - } - - twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - - for (i = 0; i < 2; i++) { - twidjoy->dev.absmax[ABS_X+i] = 50; - twidjoy->dev.absmin[ABS_X+i] = -50; - - /* TODO: arndt 20010708: Are these values appropriate? */ - twidjoy->dev.absfuzz[ABS_X+i] = 4; - twidjoy->dev.absflat[ABS_X+i] = 4; - } - - twidjoy->dev.private = twidjoy; + set_bit(bp->buttons[i], input_dev->keybit); serio_set_drvdata(serio, twidjoy); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(twidjoy); - return err; - } - - input_register_device(&twidjoy->dev); - - printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); + if (err) + goto fail; + input_register_device(twidjoy->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(twidjoy); + return err; } /* diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 6976a219504c..99a642d2a1fe 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -47,14 +47,13 @@ MODULE_LICENSE("GPL"); #define WARRIOR_MAX_LENGTH 16 static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; -static char *warrior_name = "Logitech WingMan Warrior"; /* * Per-Warrior data. */ struct warrior { - struct input_dev dev; + struct input_dev *dev; int idx, len; unsigned char data[WARRIOR_MAX_LENGTH]; char phys[32]; @@ -67,7 +66,7 @@ struct warrior { static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs) { - struct input_dev *dev = &warrior->dev; + struct input_dev *dev = warrior->dev; unsigned char *data = warrior->data; if (!warrior->idx) return; @@ -131,9 +130,9 @@ static void warrior_disconnect(struct serio *serio) { struct warrior *warrior = serio_get_drvdata(serio); - input_unregister_device(&warrior->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(warrior->dev); kfree(warrior); } @@ -146,60 +145,48 @@ static void warrior_disconnect(struct serio *serio) static int warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; - int i; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL))) - return -ENOMEM; - - memset(warrior, 0, sizeof(struct warrior)); - - warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); - warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); - warrior->dev.relbit[0] = BIT(REL_DIAL); - warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); + warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!warrior || !input_dev) + goto fail; + warrior->dev = input_dev; sprintf(warrior->phys, "%s/input0", serio->phys); - init_input_dev(&warrior->dev); - warrior->dev.name = warrior_name; - warrior->dev.phys = warrior->phys; - warrior->dev.id.bustype = BUS_RS232; - warrior->dev.id.vendor = SERIO_WARRIOR; - warrior->dev.id.product = 0x0001; - warrior->dev.id.version = 0x0100; - warrior->dev.dev = &serio->dev; + input_dev->name = "Logitech WingMan Warrior"; + input_dev->phys = warrior->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_WARRIOR; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = warrior; - for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_X+i] = -64; - warrior->dev.absmin[ABS_X+i] = 64; - warrior->dev.absflat[ABS_X+i] = 8; - } - - warrior->dev.absmax[ABS_THROTTLE] = -112; - warrior->dev.absmin[ABS_THROTTLE] = 112; - - for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_HAT0X+i] = -1; - warrior->dev.absmin[ABS_HAT0X+i] = 1; - } - - warrior->dev.private = warrior; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); + input_dev->relbit[0] = BIT(REL_DIAL); + input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 8); + input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8); + input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); serio_set_drvdata(serio, warrior); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(warrior); - return err; - } - - input_register_device(&warrior->dev); - - printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys); + if (err) + goto fail; + input_register_device(warrior->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(warrior); + return err; } /* From 34abf91f4036c01669e298e649b7ba85cadf82eb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:40 -0500 Subject: [PATCH 0942/1939] [PATCH] Input: convert net/bluetooth to dynamic input_dev allocation Input: convert net/bluetooth to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hidp/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index de8af5f42394..860444a7fc0f 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -520,7 +520,7 @@ static int hidp_session(void *arg) if (session->input) { input_unregister_device(session->input); - kfree(session->input); + session->input = NULL; } up_write(&hidp_session_sem); @@ -536,6 +536,8 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co input->private = session; + input->name = "Bluetooth HID Boot Protocol Device"; + input->id.bustype = BUS_BLUETOOTH; input->id.vendor = req->vendor; input->id.product = req->product; @@ -582,16 +584,15 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, return -ENOTUNIQ; session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); - if (!session) + if (!session) return -ENOMEM; memset(session, 0, sizeof(struct hidp_session)); - session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL); + session->input = input_allocate_device(); if (!session->input) { kfree(session); return -ENOMEM; } - memset(session->input, 0, sizeof(struct input_dev)); down_write(&hidp_session_sem); @@ -651,8 +652,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, __hidp_unlink_session(session); - if (session->input) + if (session->input) { input_unregister_device(session->input); + session->input = NULL; /* don't try to free it here */ + } failed: up_write(&hidp_session_sem); From 5ebdcbc2fc4f192c5e685565c9c853a9e01a5eeb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:49 -0500 Subject: [PATCH 0943/1939] [PATCH] Input: convert sound/ppc/beep to dynamic input_dev allocation Input: convert sound/ppc/beep to dynamic input_dev allocation This is required for input_dev sysfs integration Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- sound/ppc/beep.c | 66 +++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 31ea7a4c069f..1681ee13efbb 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -31,14 +31,14 @@ #include "pmac.h" struct snd_pmac_beep { - int running; /* boolean */ - int volume; /* mixer volume: 0-100 */ + int running; /* boolean */ + int volume; /* mixer volume: 0-100 */ int volume_play; /* currently playing volume */ int hz; int nsamples; short *buf; /* allocated wave buffer */ dma_addr_t addr; /* physical address of buffer */ - struct input_dev dev; + struct input_dev *dev; }; /* @@ -212,47 +212,55 @@ static snd_kcontrol_new_t snd_pmac_beep_mixer = { int __init snd_pmac_attach_beep(pmac_t *chip) { pmac_beep_t *beep; - int err; + struct input_dev *input_dev; + void *dmabuf; + int err = -ENOMEM; - beep = kmalloc(sizeof(*beep), GFP_KERNEL); - if (! beep) - return -ENOMEM; - - memset(beep, 0, sizeof(*beep)); - beep->buf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, - &beep->addr, GFP_KERNEL); - - beep->dev.evbit[0] = BIT(EV_SND); - beep->dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - beep->dev.event = snd_pmac_beep_event; - beep->dev.private = chip; + beep = kzalloc(sizeof(*beep), GFP_KERNEL); + dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, + &beep->addr, GFP_KERNEL); + input_dev = input_allocate_device(); + if (!beep || !dmabuf || !input_dev) + goto fail; /* FIXME: set more better values */ - beep->dev.name = "PowerMac Beep"; - beep->dev.phys = "powermac/beep"; - beep->dev.id.bustype = BUS_ADB; - beep->dev.id.vendor = 0x001f; - beep->dev.id.product = 0x0001; - beep->dev.id.version = 0x0100; + input_dev->name = "PowerMac Beep"; + input_dev->phys = "powermac/beep"; + input_dev->id.bustype = BUS_ADB; + input_dev->id.vendor = 0x001f; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_SND); + input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + input_dev->event = snd_pmac_beep_event; + input_dev->private = chip; + input_dev->cdev.dev = &chip->pdev->dev; + + beep->dev = input_dev; + beep->buf = dmabuf; beep->volume = BEEP_VOLUME; beep->running = 0; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip))) < 0) { - kfree(beep->buf); - kfree(beep); - return err; - } + + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip)); + if (err < 0) + goto fail; chip->beep = beep; - input_register_device(&beep->dev); + input_register_device(beep->dev); return 0; + + fail: input_free_device(input_dev); + kfree(dmabuf); + kfree(beep); + return err; } void snd_pmac_detach_beep(pmac_t *chip) { if (chip->beep) { - input_unregister_device(&chip->beep->dev); + input_unregister_device(chip->beep->dev); dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, chip->beep->buf, chip->beep->addr); kfree(chip->beep); From 051b2feaa4a92592d160dcb8715cc4a5faaaa52f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:54 -0500 Subject: [PATCH 0944/1939] [PATCH] Input: show sysfs path in /proc/bus/input/devices Input: show sysfs path in /proc/bus/input/devices Show that sysfs and phys path are different objects. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/input/input.c b/drivers/input/input.c index 0e2e890c0988..ceaed631d49f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -475,17 +475,21 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int { struct input_dev *dev; struct input_handle *handle; + const char *path; off_t at = 0; int i, len, cnt = 0; list_for_each_entry(dev, &input_dev_list, node) { + path = dev->dynalloc ? kobject_get_path(&dev->cdev.kobj, GFP_KERNEL) : NULL; + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + len += sprintf(buf + len, "S: Sysfs=%s\n", path ? path : ""); len += sprintf(buf + len, "H: Handlers="); list_for_each_entry(handle, &dev->h_list, d_node) @@ -516,6 +520,8 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int if (cnt >= count) break; } + + kfree(path); } if (&dev->node == &input_dev_list) From 5c1e9a6a6ab2f4c60462cecb7773860a62d86e39 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:55 -0500 Subject: [PATCH 0945/1939] [PATCH] Input: export input_dev data via sysfs attributes Input: export various input device attributes via sysfs The following structure is exported: input0/ |-- name |-- phys |-- uniq |-- id/{bustype|vendor|product|version} `-- capabilities/{ev|abs|rel|key|led|msc|ff|sw} Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 156 +++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 23 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index ceaed631d49f..57fbfd907157 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -434,6 +434,23 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) #endif +static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) +{ + int i; + int len = 0; + + for (i = NBITS(max) - 1; i > 0; i--) + if (bitmap[i]) + break; + + for (; i >= 0; i--) + len += sprintf(buf + len, "%lx%s", bitmap[i], i > 0 ? " " : ""); + + len += sprintf(buf + len, "\n"); + + return len; +} + #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -455,20 +472,17 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) return 0; } -#define SPRINTF_BIT_B(bit, name, max) \ - do { \ - len += sprintf(buf + len, "B: %s", name); \ - for (i = NBITS(max) - 1; i >= 0; i--) \ - if (dev->bit[i]) break; \ - for (; i >= 0; i--) \ - len += sprintf(buf + len, "%lx ", dev->bit[i]); \ - len += sprintf(buf + len, "\n"); \ +#define SPRINTF_BIT_B(ev, bm) \ + do { \ + len += sprintf(buf + len, "B: %s=", #ev); \ + len += input_print_bitmap(buf + len, \ + dev->bm##bit, ev##_MAX); \ } while (0) -#define SPRINTF_BIT_B2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_B(bit, name, max); \ +#define SPRINTF_BIT_B2(ev, bm) \ + do { \ + if (test_bit(EV_##ev, dev->evbit)) \ + SPRINTF_BIT_B(ev, bm); \ } while (0) static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) @@ -478,7 +492,7 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int const char *path; off_t at = 0; - int i, len, cnt = 0; + int len, cnt = 0; list_for_each_entry(dev, &input_dev_list, node) { @@ -497,15 +511,15 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int len += sprintf(buf + len, "\n"); - SPRINTF_BIT_B(evbit, "EV=", EV_MAX); - SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); - SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW); + SPRINTF_BIT_B(EV, ev); + SPRINTF_BIT_B2(KEY, key); + SPRINTF_BIT_B2(REL, rel); + SPRINTF_BIT_B2(ABS, abs); + SPRINTF_BIT_B2(MSC, msc); + SPRINTF_BIT_B2(LED, led); + SPRINTF_BIT_B2(SND, snd); + SPRINTF_BIT_B2(FF, ff); + SPRINTF_BIT_B2(SW, sw); len += sprintf(buf + len, "\n"); @@ -612,6 +626,96 @@ static inline int input_proc_init(void) { return 0; } static inline void input_proc_exit(void) { } #endif +#define INPUT_DEV_STRING_ATTR_SHOW(name) \ +static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + int retval; \ + \ + retval = down_interruptible(&input_dev->sem); \ + if (retval) \ + return retval; \ + \ + retval = sprintf(buf, "%s\n", input_dev->name ? input_dev->name : ""); \ + \ + up(&input_dev->sem); \ + \ + return retval; \ +} + +INPUT_DEV_STRING_ATTR_SHOW(name); +INPUT_DEV_STRING_ATTR_SHOW(phys); +INPUT_DEV_STRING_ATTR_SHOW(uniq); + +static struct class_device_attribute input_dev_attrs[] = { + __ATTR(name, S_IRUGO, input_dev_show_name, NULL), + __ATTR(phys, S_IRUGO, input_dev_show_phys, NULL), + __ATTR(uniq, S_IRUGO, input_dev_show_uniq, NULL), + __ATTR_NULL +}; + +#define INPUT_DEV_ID_ATTR(name) \ +static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + return sprintf(buf, "%04x\n", input_dev->id.name); \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL); + +INPUT_DEV_ID_ATTR(bustype); +INPUT_DEV_ID_ATTR(vendor); +INPUT_DEV_ID_ATTR(product); +INPUT_DEV_ID_ATTR(version); + +static struct attribute *input_dev_id_attrs[] = { + &class_device_attr_bustype.attr, + &class_device_attr_vendor.attr, + &class_device_attr_product.attr, + &class_device_attr_version.attr, + NULL +}; + +static struct attribute_group input_dev_id_attr_group = { + .name = "id", + .attrs = input_dev_id_attrs, +}; + +#define INPUT_DEV_CAP_ATTR(ev, bm) \ +static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + return input_print_bitmap(buf, input_dev->bm##bit, ev##_MAX); \ +} \ +static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); + +INPUT_DEV_CAP_ATTR(EV, ev); +INPUT_DEV_CAP_ATTR(KEY, key); +INPUT_DEV_CAP_ATTR(REL, rel); +INPUT_DEV_CAP_ATTR(ABS, abs); +INPUT_DEV_CAP_ATTR(MSC, msc); +INPUT_DEV_CAP_ATTR(LED, led); +INPUT_DEV_CAP_ATTR(SND, snd); +INPUT_DEV_CAP_ATTR(FF, ff); +INPUT_DEV_CAP_ATTR(SW, sw); + +static struct attribute *input_dev_caps_attrs[] = { + &class_device_attr_ev.attr, + &class_device_attr_key.attr, + &class_device_attr_rel.attr, + &class_device_attr_abs.attr, + &class_device_attr_msc.attr, + &class_device_attr_led.attr, + &class_device_attr_snd.attr, + &class_device_attr_ff.attr, + &class_device_attr_sw.attr, + NULL +}; + +static struct attribute_group input_dev_caps_attr_group = { + .name = "capabilities", + .attrs = input_dev_caps_attrs, +}; + static void input_dev_release(struct class_device *class_dev) { struct input_dev *dev = to_input_dev(class_dev); @@ -623,6 +727,7 @@ static void input_dev_release(struct class_device *class_dev) static struct class input_dev_class = { .name = "input_dev", .release = input_dev_release, + .class_dev_attrs = input_dev_attrs, }; struct input_dev *input_allocate_device(void) @@ -660,6 +765,8 @@ static void input_register_classdevice(struct input_dev *dev) kfree(path); class_device_add(&dev->cdev); + sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group); + sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); } void input_register_device(struct input_dev *dev) @@ -726,8 +833,11 @@ void input_unregister_device(struct input_dev *dev) list_del_init(&dev->node); - if (dev->dynalloc) + if (dev->dynalloc) { + sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); class_device_unregister(&dev->cdev); + } input_wakeup_procfs_readers(); } From 102040204f1949562406b72007c14a2a241cb0d9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0946/1939] [PATCH] INPUT: register the input class device sooner This is needed so we can actually use the class device within the input handlers. Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 57fbfd907157..03c2ca404f20 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -795,6 +795,9 @@ void input_register_device(struct input_dev *dev) INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node, &input_dev_list); + if (dev->dynalloc) + input_register_classdevice(dev); + list_for_each_entry(handler, &input_handler_list, node) if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if ((id = input_match_device(handler->id_table, dev))) @@ -802,9 +805,6 @@ void input_register_device(struct input_dev *dev) input_link_handle(handle); - if (dev->dynalloc) - input_register_classdevice(dev); - #ifdef CONFIG_HOTPLUG input_call_hotplug("add", dev); #endif From 23d50901617c2a8bdef509279a42d2e90f523db9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0947/1939] [PATCH] INPUT: export input_dev_class so that input drivers can use it. Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 3 ++- include/linux/input.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 03c2ca404f20..b0ede4cc72b7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -40,6 +40,7 @@ EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); EXPORT_SYMBOL(input_class); +EXPORT_SYMBOL_GPL(input_dev_class); #define INPUT_DEVICES 256 @@ -724,7 +725,7 @@ static void input_dev_release(struct class_device *class_dev) module_put(THIS_MODULE); } -static struct class input_dev_class = { +struct class input_dev_class = { .name = "input_dev", .release = input_dev_release, .class_dev_attrs = input_dev_attrs, diff --git a/include/linux/input.h b/include/linux/input.h index 3defa29a17d3..5de844157fa9 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1075,6 +1075,7 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min } extern struct class *input_class; +extern struct class input_dev_class; #endif #endif From 967ca692161d8c4e894932599592af8d62c0a895 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0948/1939] [PATCH] INPUT: move the input class devices under their new input_dev devices Signed-off-by: Greg Kroah-Hartman --- drivers/input/evdev.c | 6 +++--- drivers/input/joydev.c | 6 +++--- drivers/input/mousedev.c | 10 +++++----- drivers/input/tsdev.c | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 14ea57f963bb..579041ded4be 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -686,9 +686,9 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - class_device_create(input_class, NULL, + class_device_create(&input_dev_class, &dev->cdev, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->dev, "event%d", minor); + dev->cdev.dev, "event%d", minor); return &evdev->handle; } @@ -698,7 +698,7 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; - class_device_destroy(input_class, + class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); evdev->exist = 0; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 40d2b46cbc79..9c17d1add260 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -513,9 +513,9 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - class_device_create(input_class, NULL, + class_device_create(&input_dev_class, &dev->cdev, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->dev, "js%d", minor); + dev->cdev.dev, "js%d", minor); return &joydev->handle; } @@ -525,7 +525,7 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev *joydev = handle->private; struct joydev_list *list; - class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); + class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; if (joydev->open) { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 89c3e496f1ed..5ec6291e967f 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -648,9 +648,9 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev_table[minor] = mousedev; - class_device_create(input_class, NULL, + class_device_create(&input_dev_class, &dev->cdev, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->dev, "mouse%d", minor); + dev->cdev.dev, "mouse%d", minor); return &mousedev->handle; } @@ -660,7 +660,7 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; - class_device_destroy(input_class, + class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev->exist = 0; @@ -734,7 +734,7 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - class_device_create(input_class, NULL, + class_device_create(&input_dev_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX @@ -753,7 +753,7 @@ static void __exit mousedev_exit(void) if (psaux_registered) misc_deregister(&psaux_mouse); #endif - class_device_destroy(input_class, + class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); } diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 2d45e4df4163..0581edb9a560 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -409,9 +409,9 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - class_device_create(input_class, NULL, + class_device_create(&input_dev_class, &dev->cdev, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->dev, "ts%d", minor); + dev->cdev.dev, "ts%d", minor); return &tsdev->handle; } @@ -421,7 +421,7 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; - class_device_destroy(input_class, + class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); tsdev->exist = 0; From 629b77a42c39c8b3c42a8cf5f5680f0406f8d43f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0949/1939] [PATCH] INPUT: Fix oops when accessing sysfs files of nested input devices Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index b0ede4cc72b7..0d570cf92dc2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -642,17 +642,22 @@ static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ up(&input_dev->sem); \ \ return retval; \ -} +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL); INPUT_DEV_STRING_ATTR_SHOW(name); INPUT_DEV_STRING_ATTR_SHOW(phys); INPUT_DEV_STRING_ATTR_SHOW(uniq); -static struct class_device_attribute input_dev_attrs[] = { - __ATTR(name, S_IRUGO, input_dev_show_name, NULL), - __ATTR(phys, S_IRUGO, input_dev_show_phys, NULL), - __ATTR(uniq, S_IRUGO, input_dev_show_uniq, NULL), - __ATTR_NULL +static struct attribute *input_dev_attrs[] = { + &class_device_attr_name.attr, + &class_device_attr_phys.attr, + &class_device_attr_uniq.attr, + NULL +}; + +static struct attribute_group input_dev_group = { + .attrs = input_dev_attrs, }; #define INPUT_DEV_ID_ATTR(name) \ @@ -728,7 +733,6 @@ static void input_dev_release(struct class_device *class_dev) struct class input_dev_class = { .name = "input_dev", .release = input_dev_release, - .class_dev_attrs = input_dev_attrs, }; struct input_dev *input_allocate_device(void) @@ -766,6 +770,7 @@ static void input_register_classdevice(struct input_dev *dev) kfree(path); class_device_add(&dev->cdev); + sysfs_create_group(&dev->cdev.kobj, &input_dev_group); sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group); sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); } From b0fdfebb205fcbf394c3db39679a766b8fc4f07d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0950/1939] [PATCH] INPUT: remove the input_class structure, as it is unused. Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 18 +++--------------- include/linux/input.h | 1 - 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 0d570cf92dc2..5c9044dbf00e 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -39,7 +39,6 @@ EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); -EXPORT_SYMBOL(input_class); EXPORT_SYMBOL_GPL(input_dev_class); #define INPUT_DEVICES 256 @@ -927,8 +926,6 @@ static struct file_operations input_fops = { .open = input_open_file, }; -struct class *input_class; - static int __init input_init(void) { int err; @@ -939,27 +936,19 @@ static int __init input_init(void) return err; } - input_class = class_create(THIS_MODULE, "input"); - if (IS_ERR(input_class)) { - printk(KERN_ERR "input: unable to register input class\n"); - err = PTR_ERR(input_class); - goto fail1; - } - err = input_proc_init(); if (err) - goto fail2; + goto fail1; err = register_chrdev(INPUT_MAJOR, "input", &input_fops); if (err) { printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); - goto fail3; + goto fail2; } return 0; - fail3: input_proc_exit(); - fail2: class_destroy(input_class); + fail2: input_proc_exit(); fail1: class_unregister(&input_dev_class); return err; } @@ -968,7 +957,6 @@ static void __exit input_exit(void) { input_proc_exit(); unregister_chrdev(INPUT_MAJOR, "input"); - class_destroy(input_class); class_unregister(&input_dev_class); } diff --git a/include/linux/input.h b/include/linux/input.h index 5de844157fa9..256e88755f12 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1074,7 +1074,6 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min dev->absbit[LONG(axis)] |= BIT(axis); } -extern struct class *input_class; extern struct class input_dev_class; #endif From ea9f240bd819f9299703283e5326da606bbb4b05 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0951/1939] [PATCH] INPUT: rename input_dev_class to input_class to be correct. Signed-off-by: Greg Kroah-Hartman --- drivers/input/evdev.c | 4 ++-- drivers/input/input.c | 14 +++++++------- drivers/input/joydev.c | 4 ++-- drivers/input/mousedev.c | 8 ++++---- drivers/input/tsdev.c | 4 ++-- include/linux/input.h | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 579041ded4be..2a96b260a2a8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -686,7 +686,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - class_device_create(&input_dev_class, &dev->cdev, + class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), dev->cdev.dev, "event%d", minor); @@ -698,7 +698,7 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; - class_device_destroy(&input_dev_class, + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); evdev->exist = 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 5c9044dbf00e..a8f65fa7e17a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); -EXPORT_SYMBOL_GPL(input_dev_class); +EXPORT_SYMBOL_GPL(input_class); #define INPUT_DEVICES 256 @@ -729,8 +729,8 @@ static void input_dev_release(struct class_device *class_dev) module_put(THIS_MODULE); } -struct class input_dev_class = { - .name = "input_dev", +struct class input_class = { + .name = "input", .release = input_dev_release, }; @@ -741,7 +741,7 @@ struct input_dev *input_allocate_device(void) dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); if (dev) { dev->dynalloc = 1; - dev->cdev.class = &input_dev_class; + dev->cdev.class = &input_class; class_device_initialize(&dev->cdev); INIT_LIST_HEAD(&dev->h_list); INIT_LIST_HEAD(&dev->node); @@ -930,7 +930,7 @@ static int __init input_init(void) { int err; - err = class_register(&input_dev_class); + err = class_register(&input_class); if (err) { printk(KERN_ERR "input: unable to register input_dev class\n"); return err; @@ -949,7 +949,7 @@ static int __init input_init(void) return 0; fail2: input_proc_exit(); - fail1: class_unregister(&input_dev_class); + fail1: class_unregister(&input_class); return err; } @@ -957,7 +957,7 @@ static void __exit input_exit(void) { input_proc_exit(); unregister_chrdev(INPUT_MAJOR, "input"); - class_unregister(&input_dev_class); + class_unregister(&input_class); } subsys_initcall(input_init); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9c17d1add260..25f7eba4761f 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -513,7 +513,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - class_device_create(&input_dev_class, &dev->cdev, + class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), dev->cdev.dev, "js%d", minor); @@ -525,7 +525,7 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev *joydev = handle->private; struct joydev_list *list; - class_device_destroy(&input_dev_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; if (joydev->open) { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 5ec6291e967f..de2808fc85b3 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -648,7 +648,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev_table[minor] = mousedev; - class_device_create(&input_dev_class, &dev->cdev, + class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), dev->cdev.dev, "mouse%d", minor); @@ -660,7 +660,7 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; - class_device_destroy(&input_dev_class, + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev->exist = 0; @@ -734,7 +734,7 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - class_device_create(&input_dev_class, NULL, + class_device_create(&input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX @@ -753,7 +753,7 @@ static void __exit mousedev_exit(void) if (psaux_registered) misc_deregister(&psaux_mouse); #endif - class_device_destroy(&input_dev_class, + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); } diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 0581edb9a560..75e165736655 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -409,7 +409,7 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - class_device_create(&input_dev_class, &dev->cdev, + class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->cdev.dev, "ts%d", minor); @@ -421,7 +421,7 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; - class_device_destroy(&input_dev_class, + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); tsdev->exist = 0; diff --git a/include/linux/input.h b/include/linux/input.h index 256e88755f12..e3d9c08b5cbe 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1074,7 +1074,7 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min dev->absbit[LONG(axis)] |= BIT(axis); } -extern struct class input_dev_class; +extern struct class input_class; #endif #endif From c9bcd582dfeec845b83bc948a430c9958bf839e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0952/1939] [PATCH] INPUT: Create symlinks for backwards compatibility This creates symlinks in /sys/class/input/ to the nested class devices to help userspace cope with the nesting. Unfortunatly udev still needs to be updated as it can't handle symlinks properly here :( Signed-off-by: Greg Kroah-Hartman --- drivers/input/evdev.c | 10 ++++++++-- drivers/input/joydev.c | 10 ++++++++-- drivers/input/mousedev.c | 10 ++++++++-- drivers/input/tsdev.c | 10 ++++++++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2a96b260a2a8..a4696cd0978c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -661,6 +661,7 @@ static struct file_operations evdev_fops = { static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct evdev *evdev; + struct class_device *cdev; int minor; for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); @@ -686,9 +687,13 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - class_device_create(&input_class, &dev->cdev, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->cdev.dev, "event%d", minor); + dev->cdev.dev, evdev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + evdev->name); return &evdev->handle; } @@ -698,6 +703,7 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); evdev->exist = 0; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 25f7eba4761f..20e2972b9204 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -448,6 +448,7 @@ static struct file_operations joydev_fops = { static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct joydev *joydev; + struct class_device *cdev; int i, j, t, minor; for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); @@ -513,9 +514,13 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - class_device_create(&input_class, &dev->cdev, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->cdev.dev, "js%d", minor); + dev->cdev.dev, joydev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + joydev->name); return &joydev->handle; } @@ -525,6 +530,7 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev *joydev = handle->private; struct joydev_list *list; + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index de2808fc85b3..2d0af44ac4b9 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -620,6 +620,7 @@ static struct file_operations mousedev_fops = { static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct mousedev *mousedev; + struct class_device *cdev; int minor = 0; for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); @@ -648,9 +649,13 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev_table[minor] = mousedev; - class_device_create(&input_class, &dev->cdev, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->cdev.dev, "mouse%d", minor); + dev->cdev.dev, mousedev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + mousedev->name); return &mousedev->handle; } @@ -660,6 +665,7 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev->exist = 0; diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 75e165736655..ca1547929d62 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -368,6 +368,7 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_device_id *id) { struct tsdev *tsdev; + struct class_device *cdev; int minor, delta; for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; @@ -409,9 +410,13 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - class_device_create(&input_class, &dev->cdev, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->cdev.dev, "ts%d", minor); + dev->cdev.dev, tsdev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + tsdev->name); return &tsdev->handle; } @@ -421,6 +426,7 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); tsdev->exist = 0; From a7fadbe10ccf430e7a8add8b45c561d864087343 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Sep 2005 02:01:57 -0500 Subject: [PATCH 0953/1939] [PATCH] input core: remove custom-made hotplug handler Input: remove custom-made hotplug handler Now that all input devices are registered with sysfs we can remove old custom-made hotplug handler and crate a standard one. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 249 ++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 145 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index a8f65fa7e17a..3b1685ff9d10 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -316,125 +316,7 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st return NULL; } - -/* - * Input hotplugging interface - loading event handlers based on - * device bitfields. - */ - -#ifdef CONFIG_HOTPLUG - -/* - * Input hotplugging invokes what /proc/sys/kernel/hotplug says - * (normally /sbin/hotplug) when input devices get added or removed. - * - * This invokes a user mode policy agent, typically helping to load driver - * or other modules, configure the device, and more. Drivers can provide - * a MODULE_DEVICE_TABLE to help with module loading subtasks. - * - */ - -#define SPRINTF_BIT_A(bit, name, max) \ - do { \ - envp[i++] = scratch; \ - scratch += sprintf(scratch, name); \ - for (j = NBITS(max) - 1; j >= 0; j--) \ - if (dev->bit[j]) break; \ - for (; j >= 0; j--) \ - scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ - scratch++; \ - } while (0) - -#define SPRINTF_BIT_A2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_A(bit, name, max); \ - } while (0) - -static void input_call_hotplug(char *verb, struct input_dev *dev) -{ - char *argv[3], **envp, *buf, *scratch; - int i = 0, j, value; - - if (!hotplug_path[0]) { - printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n"); - return; - } - if (in_interrupt()) { - printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); - return; - } - if (!current->fs->root) { - printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); - return; - } - if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { - printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); - return; - } - if (!(buf = kmalloc(1024, GFP_KERNEL))) { - kfree (envp); - printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); - return; - } - - argv[0] = hotplug_path; - argv[1] = "input"; - argv[2] = NULL; - - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - - scratch = buf; - - envp[i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", verb) + 1; - - envp[i++] = scratch; - scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; - - if (dev->name) { - envp[i++] = scratch; - scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; - } - - if (dev->phys) { - envp[i++] = scratch; - scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; - } - - SPRINTF_BIT_A(evbit, "EV=", EV_MAX); - SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); - SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW); - - envp[i++] = NULL; - -#ifdef INPUT_DEBUG - printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", - argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); -#endif - - value = call_usermodehelper(argv [0], argv, envp, 0); - - kfree(buf); - kfree(envp); - -#ifdef INPUT_DEBUG - if (value != 0) - printk(KERN_DEBUG "input.c: hotplug returned %d\n", value); -#endif -} - -#endif - -static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) +static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, int max) { int i; int len = 0; @@ -444,10 +326,8 @@ static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) break; for (; i >= 0; i--) - len += sprintf(buf + len, "%lx%s", bitmap[i], i > 0 ? " " : ""); - - len += sprintf(buf + len, "\n"); - + len += snprintf(buf + len, max(buf_size - len, 0), + "%lx%s", bitmap[i], i > 0 ? " " : ""); return len; } @@ -472,17 +352,18 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) return 0; } -#define SPRINTF_BIT_B(ev, bm) \ +#define SPRINTF_BIT(ev, bm) \ do { \ len += sprintf(buf + len, "B: %s=", #ev); \ - len += input_print_bitmap(buf + len, \ + len += input_print_bitmap(buf + len, INT_MAX, \ dev->bm##bit, ev##_MAX); \ + len += sprintf(buf + len, "\n"); \ } while (0) -#define SPRINTF_BIT_B2(ev, bm) \ +#define TEST_AND_SPRINTF_BIT(ev, bm) \ do { \ if (test_bit(EV_##ev, dev->evbit)) \ - SPRINTF_BIT_B(ev, bm); \ + SPRINTF_BIT(ev, bm); \ } while (0) static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) @@ -511,15 +392,15 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int len += sprintf(buf + len, "\n"); - SPRINTF_BIT_B(EV, ev); - SPRINTF_BIT_B2(KEY, key); - SPRINTF_BIT_B2(REL, rel); - SPRINTF_BIT_B2(ABS, abs); - SPRINTF_BIT_B2(MSC, msc); - SPRINTF_BIT_B2(LED, led); - SPRINTF_BIT_B2(SND, snd); - SPRINTF_BIT_B2(FF, ff); - SPRINTF_BIT_B2(SW, sw); + SPRINTF_BIT(EV, ev); + TEST_AND_SPRINTF_BIT(KEY, key); + TEST_AND_SPRINTF_BIT(REL, rel); + TEST_AND_SPRINTF_BIT(ABS, abs); + TEST_AND_SPRINTF_BIT(MSC, msc); + TEST_AND_SPRINTF_BIT(LED, led); + TEST_AND_SPRINTF_BIT(SND, snd); + TEST_AND_SPRINTF_BIT(FF, ff); + TEST_AND_SPRINTF_BIT(SW, sw); len += sprintf(buf + len, "\n"); @@ -689,7 +570,7 @@ static struct attribute_group input_dev_id_attr_group = { static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ { \ struct input_dev *input_dev = to_input_dev(dev); \ - return input_print_bitmap(buf, input_dev->bm##bit, ev##_MAX); \ + return input_print_bitmap(buf, PAGE_SIZE, input_dev->bm##bit, ev##_MAX);\ } \ static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); @@ -729,9 +610,95 @@ static void input_dev_release(struct class_device *class_dev) module_put(THIS_MODULE); } +/* + * Input hotplugging interface - loading event handlers based on + * device bitfields. + */ +static int input_add_hotplug_bm_var(char **envp, int num_envp, int *cur_index, + char *buffer, int buffer_size, int *cur_len, + const char *name, unsigned long *bitmap, int max) +{ + if (*cur_index >= num_envp - 1) + return -ENOMEM; + + envp[*cur_index] = buffer + *cur_len; + + *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); + if (*cur_len > buffer_size) + return -ENOMEM; + + *cur_len += input_print_bitmap(buffer + *cur_len, + max(buffer_size - *cur_len, 0), + bitmap, max) + 1; + if (*cur_len > buffer_size) + return -ENOMEM; + + (*cur_index)++; + return 0; +} + +#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ + do { \ + int err = add_hotplug_env_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + fmt, val); \ + if (err) \ + return err; \ + } while (0) + +#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ + do { \ + int err = input_add_hotplug_bm_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + name, bm, max); \ + if (err) \ + return err; \ + } while (0) + +static int input_dev_hotplug(struct class_device *cdev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct input_dev *dev = to_input_dev(cdev); + int i = 0; + int len = 0; + + INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", + dev->id.bustype, dev->id.vendor, + dev->id.product, dev->id.version); + if (dev->name) + INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name); + if (dev->phys) + INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys); + if (dev->phys) + INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq); + + INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX); + if (test_bit(EV_KEY, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX); + if (test_bit(EV_REL, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX); + if (test_bit(EV_ABS, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX); + if (test_bit(EV_MSC, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX); + if (test_bit(EV_LED, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("LED=", dev->ledbit, LED_MAX); + if (test_bit(EV_SND, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("SND=", dev->sndbit, SND_MAX); + if (test_bit(EV_FF, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("FF=", dev->ffbit, FF_MAX); + if (test_bit(EV_SW, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX); + + envp[i] = NULL; + + return 0; +} + struct class input_class = { .name = "input", .release = input_dev_release, + .hotplug = input_dev_hotplug, }; struct input_dev *input_allocate_device(void) @@ -810,10 +777,6 @@ void input_register_device(struct input_dev *dev) input_link_handle(handle); -#ifdef CONFIG_HOTPLUG - input_call_hotplug("add", dev); -#endif - input_wakeup_procfs_readers(); } @@ -832,10 +795,6 @@ void input_unregister_device(struct input_dev *dev) handle->handler->disconnect(handle); } -#ifdef CONFIG_HOTPLUG - input_call_hotplug("remove", dev); -#endif - list_del_init(&dev->node); if (dev->dynalloc) { From a1bdc7aad8b557176ccecff1da137ebe3090871e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 13 Oct 2005 17:54:41 +0100 Subject: [PATCH 0954/1939] [PATCH] drivers/base - fix sparse warnings There are a number of sparse warnings from the latest sparse snapshot being generated from the drivers/base build. The main culprits are due to the initialisation functions not being declared in a header file. Also, the firmware.c file should include to get the prototype of firmware_register() and firmware_unregister(). This patch moves the init function declerations from the init.c file to the base.h, and ensures it is included in all the relevant c sources. It also adds to the included headers for firmware.c. The patch does not solve all the sparse errors generated, but reduces the count significantly. drivers/base/core.c:161:1: warning: symbol 'devices_subsys' was not declared. Should it be static? drivers/base/core.c:417:12: warning: symbol 'devices_init' was not declared. Should it be static? drivers/base/sys.c:253:6: warning: symbol 'sysdev_shutdown' was not declared. Should it be static? drivers/base/sys.c:326:5: warning: symbol 'sysdev_suspend' was not declared. Should it be static? drivers/base/sys.c:428:5: warning: symbol 'sysdev_resume' was not declared. Should it be static? drivers/base/sys.c:450:12: warning: symbol 'system_bus_init' was not declared. Should it be static? drivers/base/bus.c:133:1: warning: symbol 'bus_subsys' was not declared. Should it be static? drivers/base/bus.c:667:12: warning: symbol 'buses_init' was not declared. Should it be static? drivers/base/class.c:759:12: warning: symbol 'classes_init' was not declared. Should it be static? drivers/base/platform.c:313:12: warning: symbol 'platform_bus_init' was not declared. Should it be static? drivers/base/cpu.c:110:12: warning: symbol 'cpu_dev_init' was not declared. Should it be static? drivers/base/firmware.c:17:5: warning: symbol 'firmware_register' was not declared. Should it be static? drivers/base/firmware.c:23:6: warning: symbol 'firmware_unregister' was not declared. Should it be static? drivers/base/firmware.c:28:12: warning: symbol 'firmware_init' was not declared. Should it be static? drivers/base/init.c:28:13: warning: symbol 'driver_init' was not declared. Should it be static? drivers/base/dmapool.c:174:10: warning: implicit cast from nocast type drivers/base/attribute_container.c:439:1: warning: symbol 'attribute_container_init' was not declared. Should it be static? drivers/base/power/runtime.c:76:6: warning: symbol 'dpm_set_power_state' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/base/attribute_container.c | 2 ++ drivers/base/base.h | 12 ++++++++++++ drivers/base/cpu.c | 1 + drivers/base/firmware.c | 3 +++ drivers/base/init.c | 10 ++-------- drivers/base/platform.c | 2 ++ 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 6b2eb6f39b4d..2a7d7ae83e1e 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -19,6 +19,8 @@ #include #include +#include "base.h" + /* This is a private structure used to tie the classdev and the * container .. it should never be visible outside this file */ struct internal_container { diff --git a/drivers/base/base.h b/drivers/base/base.h index 783752b68a9a..e3b548d46cff 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,3 +1,15 @@ + +/* initialisation functions */ + +extern int devices_init(void); +extern int buses_init(void); +extern int classes_init(void); +extern int firmware_init(void); +extern int platform_bus_init(void); +extern int system_bus_init(void); +extern int cpu_dev_init(void); +extern int attribute_container_init(void); + extern int bus_add_device(struct device * dev); extern void bus_remove_device(struct device * dev); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index b79badd0f158..081c927b1ed8 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -9,6 +9,7 @@ #include #include +#include "base.h" struct sysdev_class cpu_sysdev_class = { set_kset_name("cpu"), diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 88ab044932f2..cb1b98ae0d58 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -11,6 +11,9 @@ #include #include #include +#include + +#include "base.h" static decl_subsys(firmware, NULL, NULL); diff --git a/drivers/base/init.c b/drivers/base/init.c index a76ae5a221f3..84e604e25c4f 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -10,14 +10,8 @@ #include #include -extern int devices_init(void); -extern int buses_init(void); -extern int classes_init(void); -extern int firmware_init(void); -extern int platform_bus_init(void); -extern int system_bus_init(void); -extern int cpu_dev_init(void); -extern int attribute_container_init(void); +#include "base.h" + /** * driver_init - initialize driver model. * diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 361e204209eb..a1a56ff65b76 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -17,6 +17,8 @@ #include #include +#include "base.h" + struct device platform_bus = { .bus_id = "platform", }; From ad7e14a55ed7648d02a4df8e460e291d80a18c98 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2005 22:25:43 -0700 Subject: [PATCH 0955/1939] [PATCH] update required version of udev The 071 release is needed to handle the input changes. Older versions will work properly with module-based systems, but not for users that build input stuff into the kernel. Signed-off-by: Greg Kroah-Hartman --- Documentation/Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Changes b/Documentation/Changes index 27232be26e1a..783ddc3ce4e8 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -65,7 +65,7 @@ o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version o nfs-utils 1.0.5 # showmount --version o procps 3.2.0 # ps --version o oprofile 0.9 # oprofiled --version -o udev 058 # udevinfo -V +o udev 071 # udevinfo -V Kernel compilation ================== From a3a3395e487abc4c1371fe319a8ecbb3913a70a4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 13 Oct 2005 21:31:08 +0200 Subject: [PATCH 0956/1939] [PATCH] Driver Core: Big kfree NULL check cleanup - Documentation This is the Documentation/ part of the big kfree cleanup patch. Remove pointless checks for NULL prior to calling kfree() in example code in Documentation/. Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/writing_usb_driver.tmpl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl index 51f3bfb6fb6e..008a341234d0 100644 --- a/Documentation/DocBook/writing_usb_driver.tmpl +++ b/Documentation/DocBook/writing_usb_driver.tmpl @@ -345,8 +345,7 @@ if (!retval) { static inline void skel_delete (struct usb_skel *dev) { - if (dev->bulk_in_buffer != NULL) - kfree (dev->bulk_in_buffer); + kfree (dev->bulk_in_buffer); if (dev->bulk_out_buffer != NULL) usb_buffer_free (dev->udev, dev->bulk_out_size, dev->bulk_out_buffer, From 9480e307cd88ef09ec9294c7d97ebec18e6d2221 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 28 Oct 2005 09:52:56 -0700 Subject: [PATCH 0957/1939] [PATCH] DRIVER MODEL: Get rid of the obsolete tri-level suspend/resume callbacks In PM v1, all devices were called at SUSPEND_DISABLE level. Then all devices were called at SUSPEND_SAVE_STATE level, and finally SUSPEND_POWER_DOWN level. However, with PM v2, to maintain compatibility for platform devices, I arranged for the PM v2 suspend/resume callbacks to call the old PM v1 suspend/resume callbacks three times with each level in order so that existing drivers continued to work. Since this is obsolete infrastructure which is no longer necessary, we can remove it. Here's an (untested) patch to do exactly that. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/driver.txt | 60 +-------------------------- arch/arm/common/locomo.c | 10 +---- arch/arm/common/sa1111.c | 11 +---- arch/arm/common/scoop.c | 24 +++++------ arch/arm/mach-pxa/corgi_ssp.c | 24 +++++------ arch/arm/mach-sa1100/neponset.c | 28 +++++-------- drivers/base/platform.c | 20 +++------ drivers/char/s3c2410-rtc.c | 20 ++++----- drivers/char/sonypi.c | 14 +++---- drivers/char/watchdog/s3c2410_wdt.c | 30 ++++++-------- drivers/hwmon/hdaps.c | 6 +-- drivers/i2c/busses/i2c-s3c2410.c | 8 ++-- drivers/i2c/i2c-core.c | 4 +- drivers/ieee1394/nodemgr.c | 4 +- drivers/input/keyboard/corgikbd.c | 22 +++++----- drivers/input/keyboard/spitzkbd.c | 38 ++++++++--------- drivers/input/serio/i8042.c | 13 ++---- drivers/input/touchscreen/corgi_ts.c | 38 ++++++++--------- drivers/media/video/msp3400.c | 8 ++-- drivers/media/video/tda9887.c | 4 +- drivers/media/video/tuner-core.c | 4 +- drivers/mfd/mcp-sa11x0.c | 20 ++++----- drivers/mmc/pxamci.c | 8 ++-- drivers/mmc/wbsd.c | 4 +- drivers/mtd/maps/sa1100-flash.c | 8 ++-- drivers/net/dm9000.c | 8 ++-- drivers/net/irda/sa1100_ir.c | 8 ++-- drivers/net/irda/smsc-ircc2.c | 12 +++--- drivers/net/phy/mdio_bus.c | 20 +++------ drivers/net/smc91x.c | 8 ++-- drivers/pci/pcie/portdrv_core.c | 4 +- drivers/pcmcia/au1000_generic.c | 21 +--------- drivers/pcmcia/hd64465_ss.c | 20 +-------- drivers/pcmcia/i82365.c | 20 +-------- drivers/pcmcia/m32r_cfc.c | 21 +--------- drivers/pcmcia/m32r_pcc.c | 21 +--------- drivers/pcmcia/omap_cf.c | 18 +------- drivers/pcmcia/pxa2xx_base.c | 24 +++-------- drivers/pcmcia/sa1100_generic.c | 20 +-------- drivers/pcmcia/tcic.c | 20 +-------- drivers/pcmcia/vrc4171_card.c | 24 +---------- drivers/serial/8250.c | 10 +---- drivers/serial/imx.c | 8 ++-- drivers/serial/mpc52xx_uart.c | 8 ++-- drivers/serial/pxa.c | 8 ++-- drivers/serial/s3c2410.c | 9 ++-- drivers/serial/sa1100.c | 8 ++-- drivers/serial/vr41xx_siu.c | 10 +---- drivers/usb/gadget/dummy_hcd.c | 22 ++-------- drivers/usb/gadget/omap_udc.c | 9 +--- drivers/usb/gadget/pxa2xx_udc.c | 17 ++++---- drivers/usb/host/isp116x-hcd.c | 14 ++----- drivers/usb/host/ohci-omap.c | 10 +---- drivers/usb/host/ohci-pxa27x.c | 4 +- drivers/usb/host/sl811-hcd.c | 10 +---- drivers/video/backlight/corgi_bl.c | 10 ++--- drivers/video/imxfb.c | 10 ++--- drivers/video/pxafb.c | 10 ++--- drivers/video/s1d13xxxfb.c | 7 +--- drivers/video/s3c2410fb.c | 27 +++++------- drivers/video/sa1100fb.c | 10 ++--- drivers/video/w100fb.c | 44 ++++++++++---------- include/linux/device.h | 17 +------- sound/arm/pxa2xx-ac97.c | 8 ++-- sound/core/init.c | 14 ++----- sound/pci/ac97/ac97_bus.c | 6 ++- 66 files changed, 321 insertions(+), 688 deletions(-) diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt index fabaca1ab1b0..7c26bfae4ba0 100644 --- a/Documentation/driver-model/driver.txt +++ b/Documentation/driver-model/driver.txt @@ -196,67 +196,11 @@ it into a supported low-power state. int (*suspend) (struct device * dev, pm_message_t state, u32 level); -suspend is called to put the device in a low power state. There are -several stages to successfully suspending a device, which is denoted in -the @level parameter. Breaking the suspend transition into several -stages affords the platform flexibility in performing device power -management based on the requirements of the system and the -user-defined policy. - -SUSPEND_NOTIFY notifies the device that a suspend transition is about -to happen. This happens on system power state transitions to verify -that all devices can successfully suspend. - -A driver may choose to fail on this call, which should cause the -entire suspend transition to fail. A driver should fail only if it -knows that the device will not be able to be resumed properly when the -system wakes up again. It could also fail if it somehow determines it -is in the middle of an operation too important to stop. - -SUSPEND_DISABLE tells the device to stop I/O transactions. When it -stops transactions, or what it should do with unfinished transactions -is a policy of the driver. After this call, the driver should not -accept any other I/O requests. - -SUSPEND_SAVE_STATE tells the device to save the context of the -hardware. This includes any bus-specific hardware state and -device-specific hardware state. A pointer to this saved state can be -stored in the device's saved_state field. - -SUSPEND_POWER_DOWN tells the driver to place the device in the low -power state requested. - -Whether suspend is called with a given level is a policy of the -platform. Some levels may be omitted; drivers must not assume the -reception of any level. However, all levels must be called in the -order above; i.e. notification will always come before disabling; -disabling the device will come before suspending the device. - -All calls are made with interrupts enabled, except for the -SUSPEND_POWER_DOWN level. +suspend is called to put the device in a low power state. int (*resume) (struct device * dev, u32 level); -Resume is used to bring a device back from a low power state. Like the -suspend transition, it happens in several stages. - -RESUME_POWER_ON tells the driver to set the power state to the state -before the suspend call (The device could have already been in a low -power state before the suspend call to put in a lower power state). - -RESUME_RESTORE_STATE tells the driver to restore the state saved by -the SUSPEND_SAVE_STATE suspend call. - -RESUME_ENABLE tells the driver to start accepting I/O transactions -again. Depending on driver policy, the device may already have pending -I/O requests. - -RESUME_POWER_ON is called with interrupts disabled. The other resume -levels are called with interrupts enabled. - -As with the various suspend stages, the driver must not assume that -any other resume calls have been or will be made. Each call should be -self-contained and not dependent on any external state. +Resume is used to bring a device back from a low power state. Attributes diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index e8053d16829b..5cdb4122f057 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -550,15 +550,12 @@ struct locomo_save_data { u16 LCM_SPIMD; }; -static int locomo_suspend(struct device *dev, pm_message_t state, u32 level) +static int locomo_suspend(struct device *dev, pm_message_t state) { struct locomo *lchip = dev_get_drvdata(dev); struct locomo_save_data *save; unsigned long flags; - if (level != SUSPEND_DISABLE) - return 0; - save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL); if (!save) return -ENOMEM; @@ -597,16 +594,13 @@ static int locomo_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int locomo_resume(struct device *dev, u32 level) +static int locomo_resume(struct device *dev) { struct locomo *lchip = dev_get_drvdata(dev); struct locomo_save_data *save; unsigned long r; unsigned long flags; - if (level != RESUME_ENABLE) - return 0; - save = (struct locomo_save_data *) dev->power.saved_state; if (!save) return 0; diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 1a47fbf9cbbc..21e2a518ad3a 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -801,7 +801,7 @@ struct sa1111_save_data { #ifdef CONFIG_PM -static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level) +static int sa1111_suspend(struct device *dev, pm_message_t state) { struct sa1111 *sachip = dev_get_drvdata(dev); struct sa1111_save_data *save; @@ -809,9 +809,6 @@ static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level) unsigned int val; void __iomem *base; - if (level != SUSPEND_DISABLE) - return 0; - save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); if (!save) return -ENOMEM; @@ -856,23 +853,19 @@ static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level) /* * sa1111_resume - Restore the SA1111 device state. * @dev: device to restore - * @level: resume level * * Restore the general state of the SA1111; clock control and * interrupt controller. Other parts of the SA1111 must be * restored by their respective drivers, and must be called * via LDM after this function. */ -static int sa1111_resume(struct device *dev, u32 level) +static int sa1111_resume(struct device *dev) { struct sa1111 *sachip = dev_get_drvdata(dev); struct sa1111_save_data *save; unsigned long flags, id; void __iomem *base; - if (level != RESUME_ENABLE) - return 0; - save = (struct sa1111_save_data *)dev->power.saved_state; if (!save) return 0; diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 9e5245c702de..e8356b76d7c6 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -102,26 +102,24 @@ static void check_scoop_reg(struct scoop_dev *sdev) } #ifdef CONFIG_PM -static int scoop_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int scoop_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct scoop_dev *sdev = dev_get_drvdata(dev); + struct scoop_dev *sdev = dev_get_drvdata(dev); + + check_scoop_reg(sdev); + sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR); + SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set; - check_scoop_reg(sdev); - sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR); - SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set; - } return 0; } -static int scoop_resume(struct device *dev, uint32_t level) +static int scoop_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct scoop_dev *sdev = dev_get_drvdata(dev); + struct scoop_dev *sdev = dev_get_drvdata(dev); + + check_scoop_reg(sdev); + SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr; - check_scoop_reg(sdev); - SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr; - } return 0; } #else diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 0ef428287055..136c269db0b7 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -222,24 +222,22 @@ static int corgi_ssp_remove(struct device *dev) return 0; } -static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level) +static int corgi_ssp_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - ssp_flush(&corgi_ssp_dev); - ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state); - } + ssp_flush(&corgi_ssp_dev); + ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state); + return 0; } -static int corgi_ssp_resume(struct device *dev, u32 level) +static int corgi_ssp_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - 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*/ - ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state); - ssp_enable(&corgi_ssp_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*/ + ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state); + ssp_enable(&corgi_ssp_dev); + return 0; } diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index fc061641b7be..7609d69cf1cc 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -178,33 +178,27 @@ static int neponset_probe(struct device *dev) /* * LDM power management. */ -static int neponset_suspend(struct device *dev, pm_message_t state, u32 level) +static int neponset_suspend(struct device *dev, pm_message_t state) { /* * Save state. */ - if (level == SUSPEND_SAVE_STATE || - level == SUSPEND_DISABLE || - level == SUSPEND_POWER_DOWN) { - if (!dev->power.saved_state) - dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL); - if (!dev->power.saved_state) - return -ENOMEM; + if (!dev->power.saved_state) + dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL); + if (!dev->power.saved_state) + return -ENOMEM; - *(unsigned int *)dev->power.saved_state = NCR_0; - } + *(unsigned int *)dev->power.saved_state = NCR_0; return 0; } -static int neponset_resume(struct device *dev, u32 level) +static int neponset_resume(struct device *dev) { - if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) { - if (dev->power.saved_state) { - NCR_0 = *(unsigned int *)dev->power.saved_state; - kfree(dev->power.saved_state); - dev->power.saved_state = NULL; - } + if (dev->power.saved_state) { + NCR_0 = *(unsigned int *)dev->power.saved_state; + kfree(dev->power.saved_state); + dev->power.saved_state = NULL; } return 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a1a56ff65b76..75ce8711bca5 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -281,13 +281,9 @@ static int platform_suspend(struct device * dev, pm_message_t state) { int ret = 0; - if (dev->driver && dev->driver->suspend) { - ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE); - if (ret == 0) - ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE); - if (ret == 0) - ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN); - } + if (dev->driver && dev->driver->suspend) + ret = dev->driver->suspend(dev, state); + return ret; } @@ -295,13 +291,9 @@ static int platform_resume(struct device * dev) { int ret = 0; - if (dev->driver && dev->driver->resume) { - ret = dev->driver->resume(dev, RESUME_POWER_ON); - if (ret == 0) - ret = dev->driver->resume(dev, RESUME_RESTORE_STATE); - if (ret == 0) - ret = dev->driver->resume(dev, RESUME_ENABLE); - } + if (dev->driver && dev->driver->resume) + ret = dev->driver->resume(dev); + return ret; } diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index e1a90d9a8756..887b8b2d7882 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -519,30 +519,28 @@ static struct timespec s3c2410_rtc_delta; static int ticnt_save; -static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state) { struct rtc_time tm; struct timespec time; time.tv_nsec = 0; - if (level == SUSPEND_POWER_DOWN) { - /* save TICNT for anyone using periodic interrupts */ + /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(S3C2410_TICNT); + ticnt_save = readb(S3C2410_TICNT); - /* calculate time delta for suspend */ + /* calculate time delta for suspend */ - s3c2410_rtc_gettime(&tm); - rtc_tm_to_time(&tm, &time.tv_sec); - save_time_delta(&s3c2410_rtc_delta, &time); - s3c2410_rtc_enable(dev, 0); - } + s3c2410_rtc_gettime(&tm); + rtc_tm_to_time(&tm, &time.tv_sec); + save_time_delta(&s3c2410_rtc_delta, &time); + s3c2410_rtc_enable(dev, 0); return 0; } -static int s3c2410_rtc_resume(struct device *dev, u32 level) +static int s3c2410_rtc_resume(struct device *dev) { struct rtc_time tm; struct timespec time; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index a4873684f22c..f86c15587238 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1167,19 +1167,17 @@ static int sonypi_disable(void) #ifdef CONFIG_PM static int old_camera_power; -static int sonypi_suspend(struct device *dev, pm_message_t state, u32 level) +static int sonypi_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_DISABLE) { - old_camera_power = sonypi_device.camera_power; - sonypi_disable(); - } + old_camera_power = sonypi_device.camera_power; + sonypi_disable(); + return 0; } -static int sonypi_resume(struct device *dev, u32 level) +static int sonypi_resume(struct device *dev) { - if (level == RESUME_ENABLE) - sonypi_enable(old_camera_power); + sonypi_enable(old_camera_power); return 0; } #endif diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 3625b2601b42..b732020acadb 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -464,32 +464,28 @@ static void s3c2410wdt_shutdown(struct device *dev) static unsigned long wtcon_save; static unsigned long wtdat_save; -static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410wdt_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - /* Save watchdog state, and turn it off. */ - wtcon_save = readl(wdt_base + S3C2410_WTCON); - wtdat_save = readl(wdt_base + S3C2410_WTDAT); + /* Save watchdog state, and turn it off. */ + wtcon_save = readl(wdt_base + S3C2410_WTCON); + wtdat_save = readl(wdt_base + S3C2410_WTDAT); - /* Note that WTCNT doesn't need to be saved. */ - s3c2410wdt_stop(); - } + /* Note that WTCNT doesn't need to be saved. */ + s3c2410wdt_stop(); return 0; } -static int s3c2410wdt_resume(struct device *dev, u32 level) +static int s3c2410wdt_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - /* Restore watchdog state. */ + /* Restore watchdog state. */ - writel(wtdat_save, wdt_base + S3C2410_WTDAT); - writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ - writel(wtcon_save, wdt_base + S3C2410_WTCON); + writel(wtdat_save, wdt_base + S3C2410_WTDAT); + writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ + writel(wtcon_save, wdt_base + S3C2410_WTCON); - printk(KERN_INFO PFX "watchdog %sabled\n", - (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); - } + printk(KERN_INFO PFX "watchdog %sabled\n", + (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); return 0; } diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 7f0107613827..0015da5668a1 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -296,11 +296,9 @@ static int hdaps_probe(struct device *dev) return 0; } -static int hdaps_resume(struct device *dev, u32 level) +static int hdaps_resume(struct device *dev) { - if (level == RESUME_ENABLE) - return hdaps_device_init(); - return 0; + return hdaps_device_init(); } static struct device_driver hdaps_driver = { diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 73a092fb0e7e..69fa282df2d5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -879,14 +879,12 @@ static int s3c24xx_i2c_remove(struct device *dev) } #ifdef CONFIG_PM -static int s3c24xx_i2c_resume(struct device *dev, u32 level) +static int s3c24xx_i2c_resume(struct device *dev) { struct s3c24xx_i2c *i2c = dev_get_drvdata(dev); - - if (i2c != NULL && level == RESUME_ENABLE) { - dev_dbg(dev, "resume: level %d\n", level); + + if (i2c != NULL) s3c24xx_i2c_init(i2c); - } return 0; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dda472e5e8be..45aa0e54e297 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,7 +48,7 @@ static int i2c_bus_suspend(struct device * dev, pm_message_t state) int rc = 0; if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev,state,0); + rc = dev->driver->suspend(dev, state); return rc; } @@ -57,7 +57,7 @@ static int i2c_bus_resume(struct device * dev) int rc = 0; if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev,0); + rc = dev->driver->resume(dev); return rc; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 347ece6b583c..7fff5a1d2ea4 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1292,7 +1292,7 @@ static void nodemgr_suspend_ne(struct node_entry *ne) if (ud->device.driver && (!ud->device.driver->suspend || - ud->device.driver->suspend(&ud->device, PMSG_SUSPEND, 0))) + ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) device_release_driver(&ud->device); } up_write(&ne->device.bus->subsys.rwsem); @@ -1315,7 +1315,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) continue; if (ud->device.driver && ud->device.driver->resume) - ud->device.driver->resume(&ud->device, 0); + ud->device.driver->resume(&ud->device); } up_read(&ne->device.bus->subsys.rwsem); diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 564bb365f6fc..3210d298b3bc 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -259,24 +259,22 @@ static void corgikbd_hinge_timer(unsigned long data) } #ifdef CONFIG_PM -static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int corgikbd_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct corgikbd *corgikbd = dev_get_drvdata(dev); - corgikbd->suspended = 1; - } + struct corgikbd *corgikbd = dev_get_drvdata(dev); + corgikbd->suspended = 1; + return 0; } -static int corgikbd_resume(struct device *dev, uint32_t level) +static int corgikbd_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct corgikbd *corgikbd = dev_get_drvdata(dev); + struct corgikbd *corgikbd = dev_get_drvdata(dev); + + /* Upon resume, ignore the suspend key for a short while */ + corgikbd->suspend_jiffies=jiffies; + corgikbd->suspended = 0; - /* Upon resume, ignore the suspend key for a short while */ - corgikbd->suspend_jiffies=jiffies; - corgikbd->suspended = 0; - } return 0; } #else diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 732fb310e487..cee9c734a048 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -309,34 +309,32 @@ static void spitzkbd_hinge_timer(unsigned long data) } #ifdef CONFIG_PM -static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int spitzkbd_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - int i; - struct spitzkbd *spitzkbd = dev_get_drvdata(dev); - spitzkbd->suspended = 1; + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + spitzkbd->suspended = 1; + + /* Set Strobe lines as inputs - *except* strobe line 0 leave this + enabled so we can detect a power button press for resume */ + for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); - /* Set Strobe lines as inputs - *except* strobe line 0 leave this - enabled so we can detect a power button press for resume */ - for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) - pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); - } return 0; } -static int spitzkbd_resume(struct device *dev, uint32_t level) +static int spitzkbd_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - int i; - struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); - for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) - pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + /* Upon resume, ignore the suspend key for a short while */ + spitzkbd->suspend_jiffies = jiffies; + spitzkbd->suspended = 0; - /* Upon resume, ignore the suspend key for a short while */ - spitzkbd->suspend_jiffies = jiffies; - spitzkbd->suspended = 0; - } return 0; } #else diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 40d451ce07ff..4bc40f159996 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -911,12 +911,10 @@ static long i8042_panic_blink(long count) * Here we try to restore the original BIOS settings */ -static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) +static int i8042_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_DISABLE) { - del_timer_sync(&i8042_timer); - i8042_controller_reset(); - } + del_timer_sync(&i8042_timer); + i8042_controller_reset(); return 0; } @@ -926,13 +924,10 @@ static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) * Here we try to reset everything back to a state in which suspended */ -static int i8042_resume(struct device *dev, u32 level) +static int i8042_resume(struct device *dev) { int i; - if (level != RESUME_ENABLE) - return 0; - if (i8042_ctl_test()) return -1; diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 40ae183ba1cd..0ba3e6562bff 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -231,34 +231,32 @@ static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs) } #ifdef CONFIG_PM -static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int corgits_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct corgi_ts *corgi_ts = dev_get_drvdata(dev); + struct corgi_ts *corgi_ts = dev_get_drvdata(dev); - if (corgi_ts->pendown) { - del_timer_sync(&corgi_ts->timer); - corgi_ts->tc.pressure = 0; - new_data(corgi_ts, NULL); - corgi_ts->pendown = 0; - } - corgi_ts->power_mode = PWR_MODE_SUSPEND; - - corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + if (corgi_ts->pendown) { + del_timer_sync(&corgi_ts->timer); + corgi_ts->tc.pressure = 0; + new_data(corgi_ts, NULL); + corgi_ts->pendown = 0; } + corgi_ts->power_mode = PWR_MODE_SUSPEND; + + corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + return 0; } -static int corgits_resume(struct device *dev, uint32_t level) +static int corgits_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct corgi_ts *corgi_ts = dev_get_drvdata(dev); + struct corgi_ts *corgi_ts = dev_get_drvdata(dev); + + corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + /* Enable Falling Edge */ + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); + corgi_ts->power_mode = PWR_MODE_ACTIVE; - corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); - /* Enable Falling Edge */ - set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); - corgi_ts->power_mode = PWR_MODE_ACTIVE; - } return 0; } #else diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index f0d43fc2632f..262890cb20a7 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -1420,8 +1420,8 @@ static int msp_detach(struct i2c_client *client); static int msp_probe(struct i2c_adapter *adap); static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); -static int msp_suspend(struct device * dev, pm_message_t state, u32 level); -static int msp_resume(struct device * dev, u32 level); +static int msp_suspend(struct device * dev, pm_message_t state); +static int msp_resume(struct device * dev); static void msp_wake_thread(struct i2c_client *client); @@ -1821,7 +1821,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int msp_suspend(struct device * dev, pm_message_t state, u32 level) +static int msp_suspend(struct device * dev, pm_message_t state) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); @@ -1830,7 +1830,7 @@ static int msp_suspend(struct device * dev, pm_message_t state, u32 level) return 0; } -static int msp_resume(struct device * dev, u32 level) +static int msp_resume(struct device * dev) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 0456dda2624d..94053f149ddf 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -784,13 +784,13 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level) +static int tda9887_suspend(struct device * dev, pm_message_t state) { dprintk("tda9887: suspend\n"); return 0; } -static int tda9887_resume(struct device * dev, u32 level) +static int tda9887_resume(struct device * dev) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); struct tda9887 *t = i2c_get_clientdata(c); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 05572020af4d..ad85bef1c3d5 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -697,7 +697,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tuner_suspend(struct device *dev, pm_message_t state, u32 level) +static int tuner_suspend(struct device *dev, pm_message_t state) { struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); @@ -707,7 +707,7 @@ static int tuner_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int tuner_resume(struct device *dev, u32 level) +static int tuner_resume(struct device *dev) { struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index e9806fbbe696..720e7a326308 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -219,26 +219,24 @@ static int mcp_sa11x0_remove(struct device *dev) return 0; } -static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state, u32 level) +static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state) { struct mcp *mcp = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE) { - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; - } + priv(mcp)->mccr0 = Ser4MCCR0; + priv(mcp)->mccr1 = Ser4MCCR1; + Ser4MCCR0 &= ~MCCR0_MCE; + return 0; } -static int mcp_sa11x0_resume(struct device *dev, u32 level) +static int mcp_sa11x0_resume(struct device *dev) { struct mcp *mcp = dev_get_drvdata(dev); - if (level == RESUME_RESTORE_STATE) { - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; - } + Ser4MCCR1 = priv(mcp)->mccr1; + Ser4MCCR0 = priv(mcp)->mccr0; + return 0; } diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index b53af57074e3..8eba373d42d7 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -571,23 +571,23 @@ static int pxamci_remove(struct device *dev) } #ifdef CONFIG_PM -static int pxamci_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxamci_suspend(struct device *dev, pm_message_t state) { struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; - if (mmc && level == SUSPEND_DISABLE) + if (mmc) ret = mmc_suspend_host(mmc, state); return ret; } -static int pxamci_resume(struct device *dev, u32 level) +static int pxamci_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; - if (mmc && level == RESUME_ENABLE) + if (mmc) ret = mmc_resume_host(mmc); return ret; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 3cbca7cbea80..25f7ce7b3bc0 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1955,14 +1955,14 @@ static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) */ #ifdef CONFIG_PM -static int wbsd_suspend(struct device *dev, pm_message_t state, u32 level) +static int wbsd_suspend(struct device *dev, pm_message_t state) { DBGF("Not yet supported\n"); return 0; } -static int wbsd_resume(struct device *dev, u32 level) +static int wbsd_resume(struct device *dev) { DBGF("Not yet supported\n"); diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 8dcaa357b4bb..55f21ddec3df 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -402,21 +402,21 @@ static int __exit sa1100_mtd_remove(struct device *dev) } #ifdef CONFIG_PM -static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level) +static int sa1100_mtd_suspend(struct device *dev, pm_message_t state) { struct sa_info *info = dev_get_drvdata(dev); int ret = 0; - if (info && level == SUSPEND_SAVE_STATE) + if (info) ret = info->mtd->suspend(info->mtd); return ret; } -static int sa1100_mtd_resume(struct device *dev, u32 level) +static int sa1100_mtd_resume(struct device *dev) { struct sa_info *info = dev_get_drvdata(dev); - if (info && level == RESUME_RESTORE_STATE) + if (info) info->mtd->resume(info->mtd); return 0; } diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index e54fc10f6846..abce1f730d00 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1140,11 +1140,11 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) } static int -dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level) +dm9000_drv_suspend(struct device *dev, pm_message_t state) { struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == SUSPEND_DISABLE) { + if (ndev) { if (netif_running(ndev)) { netif_device_detach(ndev); dm9000_shutdown(ndev); @@ -1154,12 +1154,12 @@ dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level) } static int -dm9000_drv_resume(struct device *dev, u32 level) +dm9000_drv_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); board_info_t *db = (board_info_t *) ndev->priv; - if (ndev && level == RESUME_ENABLE) { + if (ndev) { if (netif_running(ndev)) { dm9000_reset(db); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 8d34ac60d906..06883309916d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -291,12 +291,12 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) /* * Suspend the IrDA interface. */ -static int sa1100_irda_suspend(struct device *_dev, pm_message_t state, u32 level) +static int sa1100_irda_suspend(struct device *_dev, pm_message_t state) { struct net_device *dev = dev_get_drvdata(_dev); struct sa1100_irda *si; - if (!dev || level != SUSPEND_DISABLE) + if (!dev) return 0; si = dev->priv; @@ -316,12 +316,12 @@ static int sa1100_irda_suspend(struct device *_dev, pm_message_t state, u32 leve /* * Resume the IrDA interface. */ -static int sa1100_irda_resume(struct device *_dev, u32 level) +static int sa1100_irda_resume(struct device *_dev) { struct net_device *dev = dev_get_drvdata(_dev); struct sa1100_irda *si; - if (!dev || level != RESUME_ENABLE) + if (!dev) return 0; si = dev->priv; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index dd89bda1f131..bbac720cca63 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -213,8 +213,8 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); /* Power Management */ -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level); -static int smsc_ircc_resume(struct device *dev, u32 level); +static int smsc_ircc_suspend(struct device *dev, pm_message_t state); +static int smsc_ircc_resume(struct device *dev); static struct device_driver smsc_ircc_driver = { .name = SMSC_IRCC2_DRIVER_NAME, @@ -1646,13 +1646,13 @@ static int smsc_ircc_net_close(struct net_device *dev) return 0; } -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level) +static int smsc_ircc_suspend(struct device *dev, pm_message_t state) { struct smsc_ircc_cb *self = dev_get_drvdata(dev); IRDA_MESSAGE("%s, Suspending\n", driver_name); - if (level == SUSPEND_DISABLE && !self->io.suspended) { + if (!self->io.suspended) { smsc_ircc_net_close(self->netdev); self->io.suspended = 1; } @@ -1660,11 +1660,11 @@ static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int smsc_ircc_resume(struct device *dev, u32 level) +static int smsc_ircc_resume(struct device *dev) { struct smsc_ircc_cb *self = dev_get_drvdata(dev); - if (level == RESUME_ENABLE && self->io.suspended) { + if (self->io.suspended) { smsc_ircc_net_open(self->netdev); self->io.suspended = 0; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 90630672703d..ad93b0da87f0 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -133,13 +133,9 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state) int ret = 0; struct device_driver *drv = dev->driver; - if (drv && drv->suspend) { - ret = drv->suspend(dev, state, SUSPEND_DISABLE); - if (ret == 0) - ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); - if (ret == 0) - ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); - } + if (drv && drv->suspend) + ret = drv->suspend(dev, state); + return ret; } @@ -148,13 +144,9 @@ static int mdio_bus_resume(struct device * dev) int ret = 0; struct device_driver *drv = dev->driver; - if (drv && drv->resume) { - ret = drv->resume(dev, RESUME_POWER_ON); - if (ret == 0) - ret = drv->resume(dev, RESUME_RESTORE_STATE); - if (ret == 0) - ret = drv->resume(dev, RESUME_ENABLE); - } + if (drv && drv->resume) + ret = drv->resume(dev); + return ret; } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 1438fdd20826..0ddaa611cc61 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2291,11 +2291,11 @@ static int smc_drv_remove(struct device *dev) return 0; } -static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level) +static int smc_drv_suspend(struct device *dev, pm_message_t state) { struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == SUSPEND_DISABLE) { + if (ndev) { if (netif_running(ndev)) { netif_device_detach(ndev); smc_shutdown(ndev); @@ -2305,12 +2305,12 @@ static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int smc_drv_resume(struct device *dev, u32 level) +static int smc_drv_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == RESUME_ENABLE) { + if (ndev) { struct smc_local *lp = netdev_priv(ndev); smc_enable_device(pdev); if (netif_running(ndev)) { diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 393e0cee91a9..14f05d22bb70 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -61,7 +61,7 @@ static int pcie_port_remove_service(struct device *dev) static void pcie_port_shutdown_service(struct device *dev) {} -static int pcie_port_suspend_service(struct device *dev, pm_message_t state, u32 level) +static int pcie_port_suspend_service(struct device *dev, pm_message_t state) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; @@ -76,7 +76,7 @@ static int pcie_port_suspend_service(struct device *dev, pm_message_t state, u32 return 0; } -static int pcie_port_resume_service(struct device *dev, u32 level) +static int pcie_port_resume_service(struct device *dev) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 470ef756252e..d90a634cebf5 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -519,30 +519,13 @@ static int au1x00_drv_pcmcia_probe(struct device *dev) } -static int au1x00_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int au1x00_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver au1x00_pcmcia_driver = { .probe = au1x00_drv_pcmcia_probe, .remove = au1x00_drv_pcmcia_remove, .name = "au1x00-pcmcia", .bus = &platform_bus_type, - .suspend = au1x00_drv_pcmcia_suspend, - .resume = au1x00_drv_pcmcia_resume + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device au1x00_device = { diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 316f8bcc878b..b57a0b98b4d6 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -844,27 +844,11 @@ static void hs_exit_socket(hs_socket_t *sp) local_irq_restore(flags); } -static int hd64465_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int hd64465_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver hd64465_driver = { .name = "hd64465-pcmcia", .bus = &platform_bus_type, - .suspend = hd64465_suspend, - .resume = hd64465_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device hd64465_device = { diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index a713015e8228..4a41f67d185d 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1332,27 +1332,11 @@ static struct pccard_operations pcic_operations = { /*====================================================================*/ -static int i82365_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int i82365_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver i82365_driver = { .name = "i82365", .bus = &platform_bus_type, - .suspend = i82365_suspend, - .resume = i82365_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device i82365_device = { diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 65f3ee3d4d3c..c6ed70ea4812 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -731,28 +731,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "cfc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 7b14d7efd68c..3397ff28de6a 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -695,28 +695,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "pcc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 94be9e51654e..2558c3cc91ec 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -329,27 +329,13 @@ static int __devexit omap_cf_remove(struct device *dev) return 0; } -static int omap_cf_suspend(struct device *dev, pm_message_t mesg, u32 level) -{ - if (level != SUSPEND_SAVE_STATE) - return 0; - return pcmcia_socket_dev_suspend(dev, mesg); -} - -static int omap_cf_resume(struct device *dev, u32 level) -{ - if (level != RESUME_RESTORE_STATE) - return 0; - return pcmcia_socket_dev_resume(dev); -} - static struct device_driver omap_cf_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = omap_cf_probe, .remove = __devexit_p(omap_cf_remove), - .suspend = omap_cf_suspend, - .resume = omap_cf_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 325c992f7d8f..c2a12d53f6c7 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -205,32 +205,20 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) } EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); -static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxa2xx_drv_pcmcia_resume(struct device *dev) { - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} + struct pcmcia_low_level *ops = dev->platform_data; + int nr = ops ? ops->nr : 0; -static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - { - struct pcmcia_low_level *ops = dev->platform_data; - int nr = ops ? ops->nr : 0; + MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); - MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); - ret = pcmcia_socket_dev_resume(dev); - } - return ret; + return pcmcia_socket_dev_resume(dev); } static struct device_driver pxa2xx_pcmcia_driver = { .probe = pxa2xx_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, - .suspend = pxa2xx_drv_pcmcia_suspend, + .suspend = pcmcia_socket_dev_suspend, .resume = pxa2xx_drv_pcmcia_resume, .name = "pxa2xx-pcmcia", .bus = &platform_bus_type, diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index d4ed508b38be..b768fa81f043 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -74,29 +74,13 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev) return ret; } -static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver sa11x0_pcmcia_driver = { .probe = sa11x0_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, .name = "sa11x0-pcmcia", .bus = &platform_bus_type, - .suspend = sa11x0_drv_pcmcia_suspend, - .resume = sa11x0_drv_pcmcia_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index d5a61eae6119..f158b67f6610 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -372,27 +372,11 @@ static int __init get_tcic_id(void) /*====================================================================*/ -static int tcic_drv_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int tcic_drv_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver tcic_driver = { .name = "tcic-pcmcia", .bus = &platform_bus_type, - .suspend = tcic_drv_suspend, - .resume = tcic_drv_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device tcic_device = { diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 17bb2da6752b..3d2dca675e02 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -774,31 +774,11 @@ static int __devinit vrc4171_card_setup(char *options) __setup("vrc4171_card=", vrc4171_card_setup); -static int vrc4171_card_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int retval = 0; - - if (level == SUSPEND_SAVE_STATE) - retval = pcmcia_socket_dev_suspend(dev, state); - - return retval; -} - -static int vrc4171_card_resume(struct device *dev, u32 level) -{ - int retval = 0; - - if (level == RESUME_RESTORE_STATE) - retval = pcmcia_socket_dev_resume(dev); - - return retval; -} - static struct device_driver vrc4171_card_driver = { .name = vrc4171_card_name, .bus = &platform_bus_type, - .suspend = vrc4171_card_suspend, - .resume = vrc4171_card_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __devinit vrc4171_card_init(void) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 4d75cdfa0a0a..afb7ddf200e0 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2358,13 +2358,10 @@ static int __devexit serial8250_remove(struct device *dev) return 0; } -static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level) +static int serial8250_suspend(struct device *dev, pm_message_t state) { int i; - if (level != SUSPEND_DISABLE) - return 0; - for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; @@ -2375,13 +2372,10 @@ static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int serial8250_resume(struct device *dev, u32 level) +static int serial8250_resume(struct device *dev) { int i; - if (level != RESUME_ENABLE) - return 0; - for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index bdb4e454b8b0..5b3933b0c997 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -921,21 +921,21 @@ static struct uart_driver imx_reg = { .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct device *_dev, pm_message_t state, u32 level) +static int serial_imx_suspend(struct device *_dev, pm_message_t state) { struct imx_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&imx_reg, &sport->port); return 0; } -static int serial_imx_resume(struct device *_dev, u32 level) +static int serial_imx_resume(struct device *_dev) { struct imx_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&imx_reg, &sport->port); return 0; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 0585ab27ffde..8a79968f8ce1 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -781,22 +781,22 @@ mpc52xx_uart_remove(struct device *dev) #ifdef CONFIG_PM static int -mpc52xx_uart_suspend(struct device *dev, pm_message_t state, u32 level) +mpc52xx_uart_suspend(struct device *dev, pm_message_t state) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&mpc52xx_uart_driver, port); return 0; } static int -mpc52xx_uart_resume(struct device *dev, u32 level) +mpc52xx_uart_resume(struct device *dev) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); - if (port && level == RESUME_ENABLE) + if (port) uart_resume_port(&mpc52xx_uart_driver, port); return 0; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 90c2a86c421b..7999686d7b47 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -786,21 +786,21 @@ static struct uart_driver serial_pxa_reg = { .cons = PXA_CONSOLE, }; -static int serial_pxa_suspend(struct device *_dev, pm_message_t state, u32 level) +static int serial_pxa_suspend(struct device *_dev, pm_message_t state) { struct uart_pxa_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&serial_pxa_reg, &sport->port); return 0; } -static int serial_pxa_resume(struct device *_dev, u32 level) +static int serial_pxa_resume(struct device *_dev) { struct uart_pxa_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&serial_pxa_reg, &sport->port); return 0; diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 52692aa345ec..06a17dff1a73 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1134,23 +1134,22 @@ static int s3c24xx_serial_remove(struct device *_dev) #ifdef CONFIG_PM -static int s3c24xx_serial_suspend(struct device *dev, pm_message_t state, - u32 level) +static int s3c24xx_serial_suspend(struct device *dev, pm_message_t state) { struct uart_port *port = s3c24xx_dev_to_port(dev); - if (port && level == SUSPEND_DISABLE) + if (port) uart_suspend_port(&s3c24xx_uart_drv, port); return 0; } -static int s3c24xx_serial_resume(struct device *dev, u32 level) +static int s3c24xx_serial_resume(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); - if (port && level == RESUME_ENABLE) { + if (port) { clk_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); clk_disable(ourport->clk); diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index dd8aed242357..c4a789e6af44 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -834,21 +834,21 @@ static struct uart_driver sa1100_reg = { .cons = SA1100_CONSOLE, }; -static int sa1100_serial_suspend(struct device *_dev, pm_message_t state, u32 level) +static int sa1100_serial_suspend(struct device *_dev, pm_message_t state) { struct sa1100_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&sa1100_reg, &sport->port); return 0; } -static int sa1100_serial_resume(struct device *_dev, u32 level) +static int sa1100_serial_resume(struct device *_dev) { struct sa1100_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&sa1100_reg, &sport->port); return 0; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 0c5d65a08f6e..2b623ab0e36e 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -976,14 +976,11 @@ static int siu_remove(struct device *dev) return 0; } -static int siu_suspend(struct device *dev, pm_message_t state, u32 level) +static int siu_suspend(struct device *dev, pm_message_t state) { struct uart_port *port; int i; - if (level != SUSPEND_DISABLE) - return 0; - for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || @@ -995,14 +992,11 @@ static int siu_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int siu_resume(struct device *dev, u32 level) +static int siu_resume(struct device *dev) { struct uart_port *port; int i; - if (level != RESUME_ENABLE) - return 0; - for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 583db7c38cf1..f2bdf4e1eb80 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -935,14 +935,10 @@ static int dummy_udc_remove (struct device *dev) return 0; } -static int dummy_udc_suspend (struct device *dev, pm_message_t state, - u32 level) +static int dummy_udc_suspend (struct device *dev, pm_message_t state) { struct dummy *dum = dev_get_drvdata(dev); - if (level != SUSPEND_DISABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); spin_lock_irq (&dum->lock); dum->udc_suspended = 1; @@ -954,13 +950,10 @@ static int dummy_udc_suspend (struct device *dev, pm_message_t state, return 0; } -static int dummy_udc_resume (struct device *dev, u32 level) +static int dummy_udc_resume (struct device *dev) { struct dummy *dum = dev_get_drvdata(dev); - if (level != RESUME_ENABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); spin_lock_irq (&dum->lock); dum->udc_suspended = 0; @@ -1936,14 +1929,10 @@ static int dummy_hcd_remove (struct device *dev) return 0; } -static int dummy_hcd_suspend (struct device *dev, pm_message_t state, - u32 level) +static int dummy_hcd_suspend (struct device *dev, pm_message_t state) { struct usb_hcd *hcd; - if (level != SUSPEND_DISABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); hcd = dev_get_drvdata (dev); @@ -1958,13 +1947,10 @@ static int dummy_hcd_suspend (struct device *dev, pm_message_t state, return 0; } -static int dummy_hcd_resume (struct device *dev, u32 level) +static int dummy_hcd_resume (struct device *dev) { struct usb_hcd *hcd; - if (level != RESUME_ENABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); hcd = dev_get_drvdata (dev); hcd->state = HC_STATE_RUNNING; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ff5533e69560..58b3ec97fb9a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2909,12 +2909,10 @@ static int __exit omap_udc_remove(struct device *dev) * may involve talking to an external transceiver (e.g. isp1301). */ -static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) +static int omap_udc_suspend(struct device *dev, pm_message_t message) { u32 devstat; - if (level != SUSPEND_POWER_DOWN) - return 0; devstat = UDC_DEVSTAT_REG; /* we're requesting 48 MHz clock if the pullup is enabled @@ -2931,11 +2929,8 @@ static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) return 0; } -static int omap_udc_resume(struct device *dev, u32 level) +static int omap_udc_resume(struct device *dev) { - if (level != RESUME_POWER_ON) - return 0; - DBG("resume + wakeup/SRP\n"); omap_pullup(&udc->gadget, 1); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 73f8c9404156..00dfe42d7a86 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -2602,24 +2602,23 @@ static int __exit pxa2xx_udc_remove(struct device *_dev) * VBUS IRQs should probably be ignored so that the PXA device just acts * "dead" to USB hosts until system resume. */ -static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state) { struct pxa2xx_udc *udc = dev_get_drvdata(dev); - if (level == SUSPEND_POWER_DOWN) { - if (!udc->mach->udc_command) - WARN("USB host won't detect disconnect!\n"); - pullup(udc, 0); - } + if (!udc->mach->udc_command) + WARN("USB host won't detect disconnect!\n"); + pullup(udc, 0); + return 0; } -static int pxa2xx_udc_resume(struct device *dev, u32 level) +static int pxa2xx_udc_resume(struct device *dev) { struct pxa2xx_udc *udc = dev_get_drvdata(dev); - if (level == RESUME_POWER_ON) - pullup(udc, 1); + pullup(udc, 1); + return 0; } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index e142056b0d2c..0f6183a829c4 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1774,15 +1774,12 @@ static int __init isp116x_probe(struct device *dev) /* Suspend of platform device */ -static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) +static int isp116x_suspend(struct device *dev, pm_message_t state) { int ret = 0; struct usb_hcd *hcd = dev_get_drvdata(dev); - VDBG("%s: state %x, phase %x\n", __func__, state, phase); - - if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN) - return 0; + VDBG("%s: state %x\n", __func__, state); ret = usb_suspend_device(hcd->self.root_hub, state); if (!ret) { @@ -1797,15 +1794,12 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) /* Resume platform device */ -static int isp116x_resume(struct device *dev, u32 phase) +static int isp116x_resume(struct device *dev) { int ret = 0; struct usb_hcd *hcd = dev_get_drvdata(dev); - VDBG("%s: state %x, phase %x\n", __func__, dev->power.power_state, - phase); - if (phase != RESUME_POWER_ON) - return 0; + VDBG("%s: state %x\n", __func__, dev->power.power_state); ret = usb_resume_device(hcd->self.root_hub); if (!ret) { diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index d8f3ba7ad52e..a574216625a0 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -455,14 +455,11 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) #ifdef CONFIG_PM -static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level) +static int ohci_omap_suspend(struct device *dev, pm_message_t message) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; - if (level != SUSPEND_POWER_DOWN) - return 0; - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); status = ohci_hub_suspend(ohci_to_hcd(ohci)); if (status == 0) { @@ -476,14 +473,11 @@ static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level return status; } -static int ohci_omap_resume(struct device *dev, u32 level) +static int ohci_omap_resume(struct device *dev) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = 0; - if (level != RESUME_POWER_ON) - return 0; - if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2fdb262d4726..f042261ecb8e 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -309,7 +309,7 @@ static int ohci_hcd_pxa27x_drv_remove(struct device *dev) return 0; } -static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u32 level) +static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state) { // struct platform_device *pdev = to_platform_device(dev); // struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -318,7 +318,7 @@ static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u return 0; } -static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 level) +static int ohci_hcd_pxa27x_drv_resume(struct device *dev) { // struct platform_device *pdev = to_platform_device(dev); // struct usb_hcd *hcd = dev_get_drvdata(dev); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d42a15d10a46..03cf6accfe64 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1784,15 +1784,12 @@ sl811h_probe(struct device *dev) */ static int -sl811h_suspend(struct device *dev, pm_message_t state, u32 phase) +sl811h_suspend(struct device *dev, pm_message_t state) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); int retval = 0; - if (phase != SUSPEND_POWER_DOWN) - return retval; - if (state.event == PM_EVENT_FREEZE) retval = sl811h_hub_suspend(hcd); else if (state.event == PM_EVENT_SUSPEND) @@ -1803,14 +1800,11 @@ sl811h_suspend(struct device *dev, pm_message_t state, u32 phase) } static int -sl811h_resume(struct device *dev, u32 phase) +sl811h_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); - if (phase != RESUME_POWER_ON) - return 0; - /* with no "check to see if VBUS is still powered" board hook, * let's assume it'd only be powered to enable remote wakeup. */ diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 3c72c627e65e..1991fdb32dfb 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -73,17 +73,15 @@ static void corgibl_blank(int blank) } #ifdef CONFIG_PM -static int corgibl_suspend(struct device *dev, pm_message_t state, u32 level) +static int corgibl_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) - corgibl_blank(FB_BLANK_POWERDOWN); + corgibl_blank(FB_BLANK_POWERDOWN); return 0; } -static int corgibl_resume(struct device *dev, u32 level) +static int corgibl_resume(struct device *dev) { - if (level == RESUME_POWER_ON) - corgibl_blank(FB_BLANK_UNBLANK); + corgibl_blank(FB_BLANK_UNBLANK); return 0; } #else diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 1d54d3d6960b..0b9301facbd3 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -424,23 +424,21 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int imxfb_suspend(struct device *dev, pm_message_t state, u32 level) +static int imxfb_suspend(struct device *dev, pm_message_t state) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - imxfb_disable_controller(fbi); + imxfb_disable_controller(fbi); return 0; } -static int imxfb_resume(struct device *dev, u32 level) +static int imxfb_resume(struct device *dev) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); - if (level == RESUME_ENABLE) - imxfb_enable_controller(fbi); + imxfb_enable_controller(fbi); return 0; } #else diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 194eed0a238c..6206da9dd5da 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -981,21 +981,19 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int pxafb_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxafb_suspend(struct device *dev, pm_message_t state) { struct pxafb_info *fbi = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - set_ctrlr_state(fbi, C_DISABLE_PM); + set_ctrlr_state(fbi, C_DISABLE_PM); return 0; } -static int pxafb_resume(struct device *dev, u32 level) +static int pxafb_resume(struct device *dev) { struct pxafb_info *fbi = dev_get_drvdata(dev); - if (level == RESUME_ENABLE) - set_ctrlr_state(fbi, C_ENABLE_PM); + set_ctrlr_state(fbi, C_ENABLE_PM); return 0; } #else diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index fa98d91c42eb..cb2f7a1de947 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -655,7 +655,7 @@ s1d13xxxfb_probe(struct device *dev) } #ifdef CONFIG_PM -static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level) +static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state) { struct fb_info *info = dev_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; @@ -702,15 +702,12 @@ static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int s1d13xxxfb_resume(struct device *dev, u32 level) +static int s1d13xxxfb_resume(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; struct s1d13xxxfb_pdata *pdata = NULL; - if (level != RESUME_ENABLE) - return 0; - /* awaken the chip */ s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 5ab79afb53b7..3862d3cb1fb2 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -847,37 +847,32 @@ static int s3c2410fb_remove(struct device *dev) /* suspend and resume support for the lcd controller */ -static int s3c2410fb_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410fb_suspend(struct device *dev, pm_message_t state) { struct fb_info *fbinfo = dev_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) { - s3c2410fb_stop_lcd(); + s3c2410fb_stop_lcd(); - /* sleep before disabling the clock, we need to ensure - * the LCD DMA engine is not going to get back on the bus - * before the clock goes off again (bjd) */ + /* sleep before disabling the clock, we need to ensure + * the LCD DMA engine is not going to get back on the bus + * before the clock goes off again (bjd) */ - msleep(1); - clk_disable(info->clk); - } + msleep(1); + clk_disable(info->clk); return 0; } -static int s3c2410fb_resume(struct device *dev, u32 level) +static int s3c2410fb_resume(struct device *dev) { struct fb_info *fbinfo = dev_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - if (level == RESUME_ENABLE) { - clk_enable(info->clk); - msleep(1); + clk_enable(info->clk); + msleep(1); - s3c2410fb_init_registers(info); - - } + s3c2410fb_init_registers(info); return 0; } diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 8000890e4271..78e5f194b0df 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -1309,21 +1309,19 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int sa1100fb_suspend(struct device *dev, pm_message_t state, u32 level) +static int sa1100fb_suspend(struct device *dev, pm_message_t state) { struct sa1100fb_info *fbi = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - set_ctrlr_state(fbi, C_DISABLE_PM); + set_ctrlr_state(fbi, C_DISABLE_PM); return 0; } -static int sa1100fb_resume(struct device *dev, u32 level) +static int sa1100fb_resume(struct device *dev) { struct sa1100fb_info *fbi = dev_get_drvdata(dev); - if (level == RESUME_ENABLE) - set_ctrlr_state(fbi, C_ENABLE_PM); + set_ctrlr_state(fbi, C_ENABLE_PM); return 0; } #else diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 0030c071da8f..752bf88906a9 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -438,36 +438,34 @@ static void w100fb_restore_vidmem(struct w100fb_par *par) } } -static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int w100fb_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + struct w100_tg_info *tg = par->mach->tg; + + w100fb_save_vidmem(par); + if(tg && tg->suspend) + tg->suspend(par); + w100_suspend(W100_SUSPEND_ALL); + par->blanked = 1; - w100fb_save_vidmem(par); - if(tg && tg->suspend) - tg->suspend(par); - w100_suspend(W100_SUSPEND_ALL); - par->blanked = 1; - } return 0; } -static int w100fb_resume(struct device *dev, uint32_t level) +static int w100fb_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + struct w100_tg_info *tg = par->mach->tg; + + w100_hw_init(par); + w100fb_activate_var(par); + w100fb_restore_vidmem(par); + if(tg && tg->resume) + tg->resume(par); + par->blanked = 0; - w100_hw_init(par); - w100fb_activate_var(par); - w100fb_restore_vidmem(par); - if(tg && tg->resume) - tg->resume(par); - par->blanked = 0; - } return 0; } #else diff --git a/include/linux/device.h b/include/linux/device.h index 10ab7807f8ea..a9e72ac3fb9f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -28,19 +28,6 @@ #define BUS_ID_SIZE KOBJ_NAME_LEN -enum { - SUSPEND_NOTIFY, - SUSPEND_SAVE_STATE, - SUSPEND_DISABLE, - SUSPEND_POWER_DOWN, -}; - -enum { - RESUME_POWER_ON, - RESUME_RESTORE_STATE, - RESUME_ENABLE, -}; - struct device; struct device_driver; struct class; @@ -115,8 +102,8 @@ struct device_driver { int (*probe) (struct device * dev); int (*remove) (struct device * dev); void (*shutdown) (struct device * dev); - int (*suspend) (struct device * dev, pm_message_t state, u32 level); - int (*resume) (struct device * dev, u32 level); + int (*suspend) (struct device * dev, pm_message_t state); + int (*resume) (struct device * dev); }; diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 38b20efc9c0b..877bb00d3295 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -275,23 +275,23 @@ static int pxa2xx_ac97_do_resume(snd_card_t *card) return 0; } -static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state, u32 level) +static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state) { snd_card_t *card = dev_get_drvdata(_dev); int ret = 0; - if (card && level == SUSPEND_DISABLE) + if (card) ret = pxa2xx_ac97_do_suspend(card, PMSG_SUSPEND); return ret; } -static int pxa2xx_ac97_resume(struct device *_dev, u32 level) +static int pxa2xx_ac97_resume(struct device *_dev) { snd_card_t *card = dev_get_drvdata(_dev); int ret = 0; - if (card && level == RESUME_ENABLE) + if (card) ret = pxa2xx_ac97_do_resume(card); return ret; diff --git a/sound/core/init.c b/sound/core/init.c index c72a79115cca..59202de1d2ce 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -676,8 +676,8 @@ struct snd_generic_device { #define SND_GENERIC_NAME "snd_generic" #ifdef CONFIG_PM -static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level); -static int snd_generic_resume(struct device *dev, u32 level); +static int snd_generic_suspend(struct device *dev, pm_message_t state); +static int snd_generic_resume(struct device *dev); #endif /* initialized in sound.c */ @@ -818,13 +818,10 @@ int snd_card_set_pm_callback(snd_card_t *card, #ifdef CONFIG_SND_GENERIC_DRIVER /* suspend/resume callbacks for snd_generic platform device */ -static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level) +static int snd_generic_suspend(struct device *dev, pm_message_t state) { snd_card_t *card; - if (level != SUSPEND_DISABLE) - return 0; - card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; @@ -834,13 +831,10 @@ static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level return 0; } -static int snd_generic_resume(struct device *dev, u32 level) +static int snd_generic_resume(struct device *dev) { snd_card_t *card; - if (level != RESUME_ENABLE) - return 0; - card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D0) return 0; diff --git a/sound/pci/ac97/ac97_bus.c b/sound/pci/ac97/ac97_bus.c index becbc420ba41..ec70fadde7d9 100644 --- a/sound/pci/ac97/ac97_bus.c +++ b/sound/pci/ac97/ac97_bus.c @@ -31,7 +31,8 @@ static int ac97_bus_suspend(struct device *dev, pm_message_t state) int ret = 0; if (dev->driver && dev->driver->suspend) - ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN); + ret = dev->driver->suspend(dev, state); + return ret; } @@ -40,7 +41,8 @@ static int ac97_bus_resume(struct device *dev) int ret = 0; if (dev->driver && dev->driver->resume) - ret = dev->driver->resume(dev, RESUME_POWER_ON); + ret = dev->driver->resume(dev); + return ret; } From c41455fbac06712992da491844449775cf9a8c80 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 23 Oct 2005 11:59:14 -0700 Subject: [PATCH 0958/1939] [PATCH] kernel-doc: drivers/base fixes driver/base: add missing function parameters; eliminate all warnings. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ++-- drivers/base/driver.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index ac4b5fdd95f5..8615b42b517a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -407,11 +407,11 @@ static struct device * next_device(struct klist_iter * i) /** * device_for_each_child - device child iterator. - * @dev: parent struct device. + * @parent: parent struct device. * @data: data for the callback. * @fn: function to be called for each device. * - * Iterate over @dev's child devices, and call @fn for each, + * Iterate over @parent's child devices, and call @fn for each, * passing it @data. * * We check the return of @fn each time. If it returns anything diff --git a/drivers/base/driver.c b/drivers/base/driver.c index ef3fe513e398..161f3a390d90 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -28,6 +28,7 @@ static struct device * next_device(struct klist_iter * i) /** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. + * @start: Device to begin with * @data: Data to pass to the callback. * @fn: Function to call for each device. * @@ -57,7 +58,7 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); /** * driver_find_device - device iterator for locating a particular device. - * @driver: The device's driver + * @drv: The device's driver * @start: Device to begin with * @data: Data to pass to match function * @match: Callback function to check device From 1a222bca26ca691e83be1b08f5e96ae96d0d8cae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Oct 2005 16:45:34 +0200 Subject: [PATCH 0959/1939] [PATCH] Fix documentation of driver suspend/resume callbacks Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/driver.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt index 7c26bfae4ba0..59806c9761f7 100644 --- a/Documentation/driver-model/driver.txt +++ b/Documentation/driver-model/driver.txt @@ -14,8 +14,8 @@ struct device_driver { int (*probe) (struct device * dev); int (*remove) (struct device * dev); - int (*suspend) (struct device * dev, pm_message_t state, u32 level); - int (*resume) (struct device * dev, u32 level); + int (*suspend) (struct device * dev, pm_message_t state); + int (*resume) (struct device * dev); }; @@ -194,11 +194,11 @@ device; i.e. anything in the device's driver_data field. If the device is still present, it should quiesce the device and place it into a supported low-power state. - int (*suspend) (struct device * dev, pm_message_t state, u32 level); + int (*suspend) (struct device * dev, pm_message_t state); suspend is called to put the device in a low power state. - int (*resume) (struct device * dev, u32 level); + int (*resume) (struct device * dev); Resume is used to bring a device back from a low power state. From 408c1ce2716c7a004851c93f9f9dcf3d763bc240 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:36 +0200 Subject: [PATCH 0960/1939] [Bluetooth] Move CRC table into RFCOMM core This patch moves rfcomm_crc_table[] into the RFCOMM core, because there is no need to keep it in a separate file. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 3 -- net/bluetooth/rfcomm/Makefile | 2 +- net/bluetooth/rfcomm/core.c | 43 ++++++++++++++++++++ net/bluetooth/rfcomm/crc.c | 71 ---------------------------------- 4 files changed, 44 insertions(+), 75 deletions(-) delete mode 100644 net/bluetooth/rfcomm/crc.c diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index fbe557f7ea1d..e656be7c001a 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -275,9 +275,6 @@ static inline void rfcomm_session_hold(struct rfcomm_session *s) atomic_inc(&s->refcnt); } -/* ---- RFCOMM chechsum ---- */ -extern u8 rfcomm_crc_table[]; - /* ---- RFCOMM sockets ---- */ struct sockaddr_rc { sa_family_t rc_family; diff --git a/net/bluetooth/rfcomm/Makefile b/net/bluetooth/rfcomm/Makefile index aecec45ec68d..fe07988a3705 100644 --- a/net/bluetooth/rfcomm/Makefile +++ b/net/bluetooth/rfcomm/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm.o -rfcomm-y := core.o sock.o crc.o +rfcomm-y := core.o sock.o rfcomm-$(CONFIG_BT_RFCOMM_TTY) += tty.o diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 35adce6482b6..c3d56ead840c 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -133,6 +133,49 @@ static inline void rfcomm_session_put(struct rfcomm_session *s) /* ---- RFCOMM FCS computation ---- */ +/* reversed, 8-bit, poly=0x07 */ +static unsigned char rfcomm_crc_table[256] = { + 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, + 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, + 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, + 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, + + 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, + 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, + 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, + 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, + + 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, + 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, + 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, + 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, + + 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, + 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, + 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, + 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, + + 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, + 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, + 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, + 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, + + 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, + 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, + 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, + 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, + + 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, + 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, + 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, + 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, + + 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, + 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, + 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, + 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf +}; + /* CRC on 2 bytes */ #define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) diff --git a/net/bluetooth/rfcomm/crc.c b/net/bluetooth/rfcomm/crc.c deleted file mode 100644 index 1011bc4a8692..000000000000 --- a/net/bluetooth/rfcomm/crc.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - RFCOMM implementation for Linux Bluetooth stack (BlueZ). - Copyright (C) 2002 Maxim Krasnyansky - Copyright (C) 2002 Marcel Holtmann - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * RFCOMM FCS calculation. - * - * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $ - */ - -/* reversed, 8-bit, poly=0x07 */ -unsigned char rfcomm_crc_table[256] = { - 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, - 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, - 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, - 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, - - 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, - 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, - 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, - 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, - - 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, - 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, - 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, - 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, - - 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, - 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, - 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, - 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, - - 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, - 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, - 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, - 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, - - 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, - 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, - 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, - 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, - - 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, - 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, - 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, - 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, - - 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, - 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, - 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, - 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf -}; From 20dd6f59d6ea5fe47397c5254606c76b1d047727 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:40 +0200 Subject: [PATCH 0961/1939] [Bluetooth] Remove TXCRC compile option for BCSP driver The TXCRC compile option is not really useful and thus change it into a module parameter. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 8 ------- drivers/bluetooth/hci_bcsp.c | 42 +++++++++++++++++++---------------- drivers/bluetooth/hci_bcsp.h | 1 + drivers/bluetooth/hci_ldisc.c | 2 +- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 543f93e0f23f..b9fbe6e7f9ae 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -55,14 +55,6 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. -config BT_HCIUART_BCSP_TXCRC - bool "Transmit CRC with every BCSP packet" - depends on BT_HCIUART_BCSP - help - If you say Y here, a 16-bit CRC checksum will be transmitted along with - every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. - This increases reliability, but slightly reduces efficiency. - config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 0ee324e1265d..91bd293d7a0a 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -28,7 +28,7 @@ * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ */ -#define VERSION "0.2" +#define VERSION "0.3" #include #include @@ -60,6 +60,7 @@ #define BT_DBG( A... ) #endif +static int txcrc = 1; static int hciextn = 1; /* ---- BCSP CRC calculation ---- */ @@ -173,11 +174,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, { struct sk_buff *nskb; u8 hdr[4], chan; - int rel, i; - -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC u16 BCSP_CRC_INIT(bcsp_txmsg_crc); -#endif + int rel, i; switch (pkt_type) { case HCI_ACLDATA_PKT: @@ -240,9 +238,9 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; } -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - hdr[0] |= 0x40; -#endif + + if (bcsp->use_crc) + hdr[0] |= 0x40; hdr[1] = ((len << 4) & 0xff) | chan; hdr[2] = len >> 4; @@ -251,25 +249,25 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, /* Put BCSP header */ for (i = 0; i < 4; i++) { bcsp_slip_one_byte(nskb, hdr[i]); -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); -#endif + + if (bcsp->use_crc) + bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); } /* Put payload */ for (i = 0; i < len; i++) { bcsp_slip_one_byte(nskb, data[i]); -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - bcsp_crc_update(&bcsp_txmsg_crc, data[i]); -#endif + + if (bcsp->use_crc) + bcsp_crc_update(&bcsp_txmsg_crc, data[i]); } -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC /* Put CRC */ - bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); - bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); - bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); -#endif + if (bcsp->use_crc) { + bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); + bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); + bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); + } bcsp_slip_msgdelim(nskb); return nskb; @@ -698,6 +696,9 @@ static int bcsp_open(struct hci_uart *hu) bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + if (txcrc) + bcsp->use_crc = 1; + return 0; } @@ -743,5 +744,8 @@ int bcsp_deinit(void) return hci_uart_unregister_proto(&bcsp); } +module_param(txcrc, bool, 0644); +MODULE_PARM_DESC(txcrc, "Transmit CRC with every BCSP packet"); + module_param(hciextn, bool, 0644); MODULE_PARM_DESC(hciextn, "Convert HCI Extensions into BCSP packets"); diff --git a/drivers/bluetooth/hci_bcsp.h b/drivers/bluetooth/hci_bcsp.h index a2b3bb92274b..01bbc664db74 100644 --- a/drivers/bluetooth/hci_bcsp.h +++ b/drivers/bluetooth/hci_bcsp.h @@ -60,6 +60,7 @@ struct bcsp_struct { BCSP_ESCSTATE_ESC } rx_esc_state; + u8 use_crc; u16 message_crc; u8 txack_req; /* Do we need to send ack's to the peer? */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index aed80cc22890..8c9317bcd53c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -27,7 +27,7 @@ * * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ */ -#define VERSION "2.1" +#define VERSION "2.2" #include #include From 0372a6627f862f90a2c43772befeecef508cfd7b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:45 +0200 Subject: [PATCH 0962/1939] [Bluetooth] Cleanup of the HCI UART driver This patch contains the big cleanup of the HCI UART driver. The uneeded header files are removed and their structure declarations are moved into the protocol implementations. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcsp.c | 120 ++++++++++++++++++---------- drivers/bluetooth/hci_bcsp.h | 71 ----------------- drivers/bluetooth/hci_h4.c | 101 +++++++++++++++--------- drivers/bluetooth/hci_h4.h | 44 ----------- drivers/bluetooth/hci_ldisc.c | 144 +++++++++++++++++----------------- drivers/bluetooth/hci_uart.h | 84 ++++++++++---------- 6 files changed, 258 insertions(+), 306 deletions(-) delete mode 100644 drivers/bluetooth/hci_bcsp.h delete mode 100644 drivers/bluetooth/hci_h4.h diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 91bd293d7a0a..0a4761415ac3 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -1,35 +1,27 @@ -/* - BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). - Copyright 2002 by Fabrizio Gennari - - Based on - hci_h4.c by Maxim Krasnyansky - ABCSP by Carl Orsborn - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2002-2003 Fabrizio Gennari + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * 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 + * */ -#define VERSION "0.3" - #include #include @@ -52,17 +44,56 @@ #include #include + #include "hci_uart.h" -#include "hci_bcsp.h" #ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif +#define VERSION "0.3" + static int txcrc = 1; static int hciextn = 1; +#define BCSP_TXWINSIZE 4 + +#define BCSP_ACK_PKT 0x05 +#define BCSP_LE_PKT 0x06 + +struct bcsp_struct { + struct sk_buff_head unack; /* Unack'ed packets queue */ + struct sk_buff_head rel; /* Reliable packets queue */ + struct sk_buff_head unrel; /* Unreliable packets queue */ + + unsigned long rx_count; + struct sk_buff *rx_skb; + u8 rxseq_txack; /* rxseq == txack. */ + u8 rxack; /* Last packet sent by us that the peer ack'ed */ + struct timer_list tbcsp; + + enum { + BCSP_W4_PKT_DELIMITER, + BCSP_W4_PKT_START, + BCSP_W4_BCSP_HDR, + BCSP_W4_DATA, + BCSP_W4_CRC + } rx_state; + + enum { + BCSP_ESCSTATE_NOESC, + BCSP_ESCSTATE_ESC + } rx_esc_state; + + u8 use_crc; + u16 message_crc; + u8 txack_req; /* Do we need to send ack's to the peer? */ + + /* Reliable packet sequence number - used to assign seq to each rel pkt. */ + u8 msgq_txseq; +}; + /* ---- BCSP CRC calculation ---- */ /* Table for calculating CRC for polynomial 0x1021, LSB processed first, @@ -112,6 +143,7 @@ static u16 bcsp_crc_reverse(u16 crc) rev |= (crc & 1); crc = crc >> 1; } + return (rev); } @@ -120,6 +152,7 @@ static u16 bcsp_crc_reverse(u16 crc) static void bcsp_slip_msgdelim(struct sk_buff *skb) { const char pkt_delim = 0xc0; + memcpy(skb_put(skb, 1), &pkt_delim, 1); } @@ -315,7 +348,6 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) spin_unlock_irqrestore(&bcsp->unack.lock, flags); - /* We could not send a reliable packet, either because there are none or because there are too many unack'ed pkts. Did we receive any packets we have not acknowledged yet ? */ @@ -361,7 +393,7 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) BT_ERR("Peer acked invalid packet"); BT_DBG("Removing %u pkts out of %u, up to seqno %u", - pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); + pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed && skb != (struct sk_buff *) &bcsp->unack; i++) { @@ -372,8 +404,10 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) kfree_skb(skb); skb = nskb; } + if (bcsp->unack.qlen == 0) del_timer(&bcsp->tbcsp); + spin_unlock_irqrestore(&bcsp->unack.lock, flags); if (i != pkts_to_be_removed) @@ -528,6 +562,7 @@ static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) hci_recv_frame(bcsp->rx_skb); } + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_skb = NULL; } @@ -596,8 +631,8 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) BT_ERR ("Checksum failed: computed %04x received %04x", bcsp_crc_reverse(bcsp->message_crc), - (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + - bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); + (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + + bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); kfree_skb(bcsp->rx_skb); bcsp->rx_state = BCSP_W4_PKT_DELIMITER; @@ -631,7 +666,7 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) bcsp->rx_count = 4; bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; BCSP_CRC_INIT(bcsp->message_crc); - + /* Do not increment ptr or decrement count * Allocate packet. Max len of a BCSP pkt= * 0xFFF (payload) +4 (header) +2 (crc) */ @@ -719,18 +754,19 @@ static int bcsp_close(struct hci_uart *hu) } static struct hci_uart_proto bcsp = { - .id = HCI_UART_BCSP, - .open = bcsp_open, - .close = bcsp_close, - .enqueue = bcsp_enqueue, - .dequeue = bcsp_dequeue, - .recv = bcsp_recv, - .flush = bcsp_flush + .id = HCI_UART_BCSP, + .open = bcsp_open, + .close = bcsp_close, + .enqueue = bcsp_enqueue, + .dequeue = bcsp_dequeue, + .recv = bcsp_recv, + .flush = bcsp_flush }; int bcsp_init(void) { int err = hci_uart_register_proto(&bcsp); + if (!err) BT_INFO("HCI BCSP protocol initialized"); else diff --git a/drivers/bluetooth/hci_bcsp.h b/drivers/bluetooth/hci_bcsp.h deleted file mode 100644 index 01bbc664db74..000000000000 --- a/drivers/bluetooth/hci_bcsp.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). - Copyright 2002 by Fabrizio Gennari - - Based on - hci_h4.c by Maxim Krasnyansky - ABCSP by Carl Orsborn - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $ - */ - -#ifndef __HCI_BCSP_H__ -#define __HCI_BCSP_H__ - -#define BCSP_TXWINSIZE 4 - -#define BCSP_ACK_PKT 0x05 -#define BCSP_LE_PKT 0x06 - -struct bcsp_struct { - struct sk_buff_head unack; /* Unack'ed packets queue */ - struct sk_buff_head rel; /* Reliable packets queue */ - struct sk_buff_head unrel; /* Unreliable packets queue */ - - unsigned long rx_count; - struct sk_buff *rx_skb; - u8 rxseq_txack; /* rxseq == txack. */ - u8 rxack; /* Last packet sent by us that the peer ack'ed */ - struct timer_list tbcsp; - - enum { - BCSP_W4_PKT_DELIMITER, - BCSP_W4_PKT_START, - BCSP_W4_BCSP_HDR, - BCSP_W4_DATA, - BCSP_W4_CRC - } rx_state; - - enum { - BCSP_ESCSTATE_NOESC, - BCSP_ESCSTATE_ESC - } rx_esc_state; - - u8 use_crc; - u16 message_crc; - u8 txack_req; /* Do we need to send ack's to the peer? */ - - /* Reliable packet sequence number - used to assign seq to each rel pkt. */ - u8 msgq_txseq; -}; - -#endif /* __HCI_BCSP_H__ */ diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index cf8a22d58d96..12e369a66fc2 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -1,33 +1,27 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * Bluetooth HCI UART(H4) protocol. * - * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $ + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * 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 + * */ -#define VERSION "1.2" #include #include @@ -51,24 +45,41 @@ #include #include + #include "hci_uart.h" -#include "hci_h4.h" #ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif +#define VERSION "1.2" + +struct h4_struct { + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + struct sk_buff_head txq; +}; + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE 0 +#define H4_W4_EVENT_HDR 1 +#define H4_W4_ACL_HDR 2 +#define H4_W4_SCO_HDR 3 +#define H4_W4_DATA 4 + /* Initialize protocol */ static int h4_open(struct hci_uart *hu) { struct h4_struct *h4; - + BT_DBG("hu %p", hu); - + h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); if (!h4) return -ENOMEM; + memset(h4, 0, sizeof(*h4)); skb_queue_head_init(&h4->txq); @@ -83,7 +94,9 @@ static int h4_flush(struct hci_uart *hu) struct h4_struct *h4 = hu->priv; BT_DBG("hu %p", hu); + skb_queue_purge(&h4->txq); + return 0; } @@ -91,16 +104,19 @@ static int h4_flush(struct hci_uart *hu) static int h4_close(struct hci_uart *hu) { struct h4_struct *h4 = hu->priv; + hu->priv = NULL; BT_DBG("hu %p", hu); skb_queue_purge(&h4->txq); + if (h4->rx_skb) kfree_skb(h4->rx_skb); hu->priv = NULL; kfree(h4); + return 0; } @@ -114,6 +130,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&h4->txq, skb); + return 0; } @@ -122,6 +139,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) register int room = skb_tailroom(h4->rx_skb); BT_DBG("len %d room %d", len, room); + if (!len) { hci_recv_frame(h4->rx_skb); } else if (len > room) { @@ -136,6 +154,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_skb = NULL; h4->rx_count = 0; + return 0; } @@ -228,6 +247,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) ptr++; count--; continue; }; + ptr++; count--; /* Allocate packet */ @@ -238,9 +258,11 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) h4->rx_count = 0; return 0; } + h4->rx_skb->dev = (void *) hu->hdev; bt_cb(h4->rx_skb)->pkt_type = type; } + return count; } @@ -251,23 +273,24 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) } static struct hci_uart_proto h4p = { - .id = HCI_UART_H4, - .open = h4_open, - .close = h4_close, - .recv = h4_recv, - .enqueue = h4_enqueue, - .dequeue = h4_dequeue, - .flush = h4_flush, + .id = HCI_UART_H4, + .open = h4_open, + .close = h4_close, + .recv = h4_recv, + .enqueue = h4_enqueue, + .dequeue = h4_dequeue, + .flush = h4_flush, }; - + int h4_init(void) { int err = hci_uart_register_proto(&h4p); + if (!err) BT_INFO("HCI H4 protocol initialized"); else BT_ERR("HCI H4 protocol registration failed"); - + return err; } diff --git a/drivers/bluetooth/hci_h4.h b/drivers/bluetooth/hci_h4.h deleted file mode 100644 index b95ff54bfd47..000000000000 --- a/drivers/bluetooth/hci_h4.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ - */ - -#ifdef __KERNEL__ -struct h4_struct { - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; - struct sk_buff_head txq; -}; - -/* H4 receiver States */ -#define H4_W4_PACKET_TYPE 0 -#define H4_W4_EVENT_HDR 1 -#define H4_W4_ACL_HDR 2 -#define H4_W4_SCO_HDR 3 -#define H4_W4_DATA 4 - -#endif /* __KERNEL__ */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 8c9317bcd53c..4a775f6ea390 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -1,33 +1,27 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * Bluetooth HCI UART driver. * - * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * 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 + * */ -#define VERSION "2.2" #include #include @@ -59,6 +53,8 @@ #define BT_DBG( A... ) #endif +#define VERSION "2.2" + static int reset = 0; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; @@ -72,6 +68,7 @@ int hci_uart_register_proto(struct hci_uart_proto *p) return -EEXIST; hup[p->id] = p; + return 0; } @@ -84,6 +81,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p) return -EINVAL; hup[p->id] = NULL; + return 0; } @@ -91,13 +89,14 @@ static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) { if (id >= HCI_UART_MAX_PROTO) return NULL; + return hup[id]; } static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) { struct hci_dev *hdev = hu->hdev; - + /* Update HCI stat counters */ switch (pkt_type) { case HCI_COMMAND_PKT: @@ -117,10 +116,12 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) { struct sk_buff *skb = hu->tx_skb; + if (!skb) skb = hu->proto->dequeue(hu); else hu->tx_skb = NULL; + return skb; } @@ -129,7 +130,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) struct tty_struct *tty = hu->tty; struct hci_dev *hdev = hu->hdev; struct sk_buff *skb; - + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -142,7 +143,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) while ((skb = hci_uart_dequeue(hu))) { int len; - + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); len = tty->driver->write(tty, skb->data, skb->len); hdev->stat.byte_tx += len; @@ -152,11 +153,11 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) hu->tx_skb = skb; break; } - + hci_uart_tx_complete(hu, bt_cb(skb)->pkt_type); kfree_skb(skb); - } - + } + if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) goto restart; @@ -173,6 +174,7 @@ static int hci_uart_open(struct hci_dev *hdev) /* Nothing to do for UART driver */ set_bit(HCI_RUNNING, &hdev->flags); + return 0; } @@ -234,6 +236,7 @@ static int hci_uart_send_frame(struct sk_buff *skb) hu->proto->enqueue(hu, skb); hci_uart_tx_wakeup(hu); + return 0; } @@ -241,7 +244,8 @@ static void hci_uart_destruct(struct hci_dev *hdev) { struct hci_uart *hu; - if (!hdev) return; + if (!hdev) + return; BT_DBG("%s", hdev->name); @@ -272,6 +276,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) BT_ERR("Can't allocate controll structure"); return -ENFILE; } + memset(hu, 0, sizeof(struct hci_uart)); tty->disc_data = hu; @@ -280,8 +285,10 @@ static int hci_uart_tty_open(struct tty_struct *tty) spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline. */ + /* FIXME: why is this needed. Note don't use ldisc_ref here as the open path is before the ldisc is referencable */ + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); @@ -372,13 +379,13 @@ static int hci_uart_tty_room (struct tty_struct *tty) static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) { struct hci_uart *hu = (void *)tty->disc_data; - + if (!hu || tty != hu->tty) return; if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) return; - + spin_lock(&hu->rx_lock); hu->proto->recv(hu, (void *) data, count); hu->hdev->stat.byte_rx += count; @@ -429,8 +436,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) static int hci_uart_set_proto(struct hci_uart *hu, int id) { struct hci_uart_proto *p; - int err; - + int err; + p = hci_uart_get_proto(id); if (!p) return -EPROTONOSUPPORT; @@ -446,6 +453,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) p->close(hu); return err; } + return 0; } @@ -463,7 +471,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) * Return Value: Command dependent */ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct hci_uart *hu = (void *)tty->disc_data; int err = 0; @@ -483,14 +491,14 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, return err; } tty->low_latency = 1; - } else + } else return -EBUSY; case HCIUARTGETPROTO: if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) return hu->proto->id; return -EUNATCH; - + default: err = n_tty_ioctl(tty, file, cmd, arg); break; @@ -502,27 +510,23 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, /* * We don't provide read/write/poll interface for user space. */ -static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) -{ - return 0; -} -static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) -{ - return 0; -} -static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) { return 0; } -#ifdef CONFIG_BT_HCIUART_H4 -int h4_init(void); -int h4_deinit(void); -#endif -#ifdef CONFIG_BT_HCIUART_BCSP -int bcsp_init(void); -int bcsp_deinit(void); -#endif +static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, + const unsigned char *data, size_t count) +{ + return 0; +} + +static unsigned int hci_uart_tty_poll(struct tty_struct *tty, + struct file *filp, poll_table *wait) +{ + return 0; +} static int __init hci_uart_init(void) { @@ -534,18 +538,18 @@ static int __init hci_uart_init(void) /* Register the tty discipline */ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); - hci_uart_ldisc.magic = TTY_LDISC_MAGIC; - hci_uart_ldisc.name = "n_hci"; - hci_uart_ldisc.open = hci_uart_tty_open; - hci_uart_ldisc.close = hci_uart_tty_close; - hci_uart_ldisc.read = hci_uart_tty_read; - hci_uart_ldisc.write = hci_uart_tty_write; - hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; - hci_uart_ldisc.poll = hci_uart_tty_poll; - hci_uart_ldisc.receive_room= hci_uart_tty_room; - hci_uart_ldisc.receive_buf = hci_uart_tty_receive; - hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; - hci_uart_ldisc.owner = THIS_MODULE; + hci_uart_ldisc.magic = TTY_LDISC_MAGIC; + hci_uart_ldisc.name = "n_hci"; + hci_uart_ldisc.open = hci_uart_tty_open; + hci_uart_ldisc.close = hci_uart_tty_close; + hci_uart_ldisc.read = hci_uart_tty_read; + hci_uart_ldisc.write = hci_uart_tty_write; + hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.poll = hci_uart_tty_poll; + hci_uart_ldisc.receive_room = hci_uart_tty_room; + hci_uart_ldisc.receive_buf = hci_uart_tty_receive; + hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; + hci_uart_ldisc.owner = THIS_MODULE; if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { BT_ERR("HCI line discipline registration failed. (%d)", err); diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 0a57d72790ec..b250e6789dee 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -1,32 +1,29 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * 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 N_HCI +#ifndef N_HCI #define N_HCI 15 #endif @@ -42,7 +39,6 @@ #define HCI_UART_3WIRE 2 #define HCI_UART_H4DS 3 -#ifdef __KERNEL__ struct hci_uart; struct hci_uart_proto { @@ -56,27 +52,35 @@ struct hci_uart_proto { }; struct hci_uart { - struct tty_struct *tty; - struct hci_dev *hdev; - unsigned long flags; + struct tty_struct *tty; + struct hci_dev *hdev; + unsigned long flags; - struct hci_uart_proto *proto; - void *priv; - - struct sk_buff *tx_skb; - unsigned long tx_state; - spinlock_t rx_lock; + struct hci_uart_proto *proto; + void *priv; + + struct sk_buff *tx_skb; + unsigned long tx_state; + spinlock_t rx_lock; }; /* HCI_UART flag bits */ -#define HCI_UART_PROTO_SET 0 +#define HCI_UART_PROTO_SET 0 /* TX states */ -#define HCI_UART_SENDING 1 -#define HCI_UART_TX_WAKEUP 2 +#define HCI_UART_SENDING 1 +#define HCI_UART_TX_WAKEUP 2 int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); -#endif /* __KERNEL__ */ +#ifdef CONFIG_BT_HCIUART_H4 +int h4_init(void); +int h4_deinit(void); +#endif + +#ifdef CONFIG_BT_HCIUART_BCSP +int bcsp_init(void); +int bcsp_deinit(void); +#endif From 6516455d3b42b33759a33a8102c1b8b48af4d9c9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:48 +0200 Subject: [PATCH 0963/1939] [Bluetooth] Make more functions static This patch makes another bunch of functions static. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 6 ++++++ net/bluetooth/af_bluetooth.c | 6 ------ net/bluetooth/hci_core.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 210458624840..e42d728b1620 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -171,4 +171,10 @@ static inline int skb_frags_no(struct sk_buff *skb) int bt_err(__u16 code); +extern int hci_sock_init(void); +extern int hci_sock_cleanup(void); + +extern int bt_sysfs_init(void); +extern void bt_sysfs_cleanup(void); + #endif /* __BLUETOOTH_H */ diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 12b43345b54f..03532062a46a 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -308,12 +308,6 @@ static struct net_proto_family bt_sock_family_ops = { .create = bt_sock_create, }; -extern int hci_sock_init(void); -extern int hci_sock_cleanup(void); - -extern int bt_sysfs_init(void); -extern int bt_sysfs_cleanup(void); - static int __init bt_init(void) { BT_INFO("Core ver %s", VERSION); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55dc42eac92c..cf0df1c8c933 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -87,7 +87,7 @@ int hci_unregister_notifier(struct notifier_block *nb) return notifier_chain_unregister(&hci_notifier, nb); } -void hci_notify(struct hci_dev *hdev, int event) +static void hci_notify(struct hci_dev *hdev, int event) { notifier_call_chain(&hci_notifier, event, hdev); } @@ -1347,7 +1347,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); } -void hci_rx_task(unsigned long arg) +static void hci_rx_task(unsigned long arg) { struct hci_dev *hdev = (struct hci_dev *) arg; struct sk_buff *skb; From dd7f5527b3e68a7b2f715ae1a21164383f418013 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:53 +0200 Subject: [PATCH 0964/1939] [Bluetooth] Update security filter for Extended Inquiry Response This patch updates the HCI security filter with support for the Extended Inquiry Response (EIR) feature. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 32ef7975a139..799e448750ad 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -66,20 +66,20 @@ static struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, /* Events */ - { 0x1000d9fe, 0x0000300c }, + { 0x1000d9fe, 0x0000b00c }, /* Commands */ { { 0x0 }, /* OGF_LINK_CTL */ - { 0xbe000006, 0x00000001, 0x0000, 0x00 }, + { 0xbe000006, 0x00000001, 0x000000, 0x00 }, /* OGF_LINK_POLICY */ - { 0x00005200, 0x00000000, 0x0000, 0x00 }, + { 0x00005200, 0x00000000, 0x000000, 0x00 }, /* OGF_HOST_CTL */ - { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 }, + { 0xaab00200, 0x2b402aaa, 0x020154, 0x00 }, /* OGF_INFO_PARAM */ - { 0x000002be, 0x00000000, 0x0000, 0x00 }, + { 0x000002be, 0x00000000, 0x000000, 0x00 }, /* OGF_STATUS_PARAM */ - { 0x000000ea, 0x00000000, 0x0000, 0x00 } + { 0x000000ea, 0x00000000, 0x000000, 0x00 } } }; From 245dc3d19b6ff7db42c9f3cca9006c8db59e2dee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 28 Oct 2005 19:20:57 +0200 Subject: [PATCH 0965/1939] [Bluetooth] Ignore additional interfaces of BPA 100/105 devices If a BPA 100/105 device contains more then one interface then ignore the additional interfaces, because they are unused. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bpa10x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 4fa85234d8b5..0db0400519c9 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -550,6 +550,9 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * if (ignore) return -ENODEV; + if (intf->cur_altsetting->desc.bInterfaceNumber > 0) + return -ENODEV; + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) { BT_ERR("Can't allocate data structure"); From 7038f1cbac899654cf0515e60dbe3e44d58271de Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 28 Oct 2005 13:27:40 -0500 Subject: [PATCH 0966/1939] JFS: make sure right-most xtree pages have header.next set to zero The xtTruncate code was only doing this for leaf pages. When a file is horribly fragmented, we may truncate a file leaving an internal page with an invalid head.next field, which may cause a stale page to be referenced. Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_xtree.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index a7fe2f2b969f..e72f4ebb6e9c 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -3516,16 +3516,10 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) /* process entries backward from last index */ index = le16_to_cpu(p->header.nextindex) - 1; - if (p->header.flag & BT_INTERNAL) - goto getChild; - /* - * leaf page - */ - - /* Since this is the rightmost leaf, and we may have already freed - * a page that was formerly to the right, let's make sure that the - * next pointer is zero. + /* Since this is the rightmost page at this level, and we may have + * already freed a page that was formerly to the right, let's make + * sure that the next pointer is zero. */ if (p->header.next) { if (log) @@ -3539,6 +3533,12 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) p->header.next = 0; } + if (p->header.flag & BT_INTERNAL) + goto getChild; + + /* + * leaf page + */ freed = 0; /* does region covered by leaf page precede Teof ? */ From e89e9cf539a28df7d0eb1d0a545368e9920b34ac Mon Sep 17 00:00:00 2001 From: Ananda Raju Date: Tue, 18 Oct 2005 15:46:41 -0700 Subject: [PATCH 0967/1939] [IPv4/IPv6]: UFO Scatter-gather approach Attached is kernel patch for UDP Fragmentation Offload (UFO) feature. 1. This patch incorporate the review comments by Jeff Garzik. 2. Renamed USO as UFO (UDP Fragmentation Offload) 3. udp sendfile support with UFO This patches uses scatter-gather feature of skb to generate large UDP datagram. Below is a "how-to" on changes required in network device driver to use the UFO interface. UDP Fragmentation Offload (UFO) Interface: ------------------------------------------- UFO is a feature wherein the Linux kernel network stack will offload the IP fragmentation functionality of large UDP datagram to hardware. This will reduce the overhead of stack in fragmenting the large UDP datagram to MTU sized packets 1) Drivers indicate their capability of UFO using dev->features |= NETIF_F_UFO | NETIF_F_HW_CSUM | NETIF_F_SG NETIF_F_HW_CSUM is required for UFO over ipv6. 2) UFO packet will be submitted for transmission using driver xmit routine. UFO packet will have a non-zero value for "skb_shinfo(skb)->ufo_size" skb_shinfo(skb)->ufo_size will indicate the length of data part in each IP fragment going out of the adapter after IP fragmentation by hardware. skb->data will contain MAC/IP/UDP header and skb_shinfo(skb)->frags[] contains the data payload. The skb->ip_summed will be set to CHECKSUM_HW indicating that hardware has to do checksum calculation. Hardware should compute the UDP checksum of complete datagram and also ip header checksum of each fragmented IP packet. For IPV6 the UFO provides the fragment identification-id in skb_shinfo(skb)->ip6_frag_id. The adapter should use this ID for generating IPv6 fragments. Signed-off-by: Ananda Raju Signed-off-by: Rusty Russell (forwarded) Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/ethtool.h | 8 ++++ include/linux/netdevice.h | 1 + include/linux/skbuff.h | 7 ++++ net/core/dev.c | 14 +++++++ net/core/ethtool.c | 53 +++++++++++++++++++++++++ net/core/skbuff.c | 75 +++++++++++++++++++++++++++++++++++ net/ipv4/ip_output.c | 83 ++++++++++++++++++++++++++++++++++++--- net/ipv6/ip6_output.c | 71 ++++++++++++++++++++++++++++++++- 8 files changed, 306 insertions(+), 6 deletions(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ed1440ea4c91..d2c390eff1b2 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -269,6 +269,8 @@ u32 ethtool_op_get_tso(struct net_device *dev); int ethtool_op_set_tso(struct net_device *dev, u32 data); int ethtool_op_get_perm_addr(struct net_device *dev, struct ethtool_perm_addr *addr, u8 *data); +u32 ethtool_op_get_ufo(struct net_device *dev); +int ethtool_op_set_ufo(struct net_device *dev, u32 data); /** * ðtool_ops - Alter and report network device settings @@ -298,6 +300,8 @@ int ethtool_op_get_perm_addr(struct net_device *dev, * set_sg: Turn scatter-gather on or off * get_tso: Report whether TCP segmentation offload is enabled * set_tso: Turn TCP segmentation offload on or off + * get_ufo: Report whether UDP fragmentation offload is enabled + * set_ufo: Turn UDP fragmentation offload on or off * self_test: Run specified self-tests * get_strings: Return a set of strings that describe the requested objects * phys_id: Identify the device @@ -364,6 +368,8 @@ struct ethtool_ops { int (*get_perm_addr)(struct net_device *, struct ethtool_perm_addr *, u8 *); int (*begin)(struct net_device *); void (*complete)(struct net_device *); + u32 (*get_ufo)(struct net_device *); + int (*set_ufo)(struct net_device *, u32); }; /* CMDs currently supported */ @@ -400,6 +406,8 @@ struct ethtool_ops { #define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ #define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ #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) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a9281b24c40b..c6efce4a04a4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -308,6 +308,7 @@ struct net_device #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*/ struct net_device *next_sched; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b756935da9c8..4286d832166f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -137,6 +137,8 @@ struct skb_shared_info { unsigned int nr_frags; unsigned short tso_size; unsigned short tso_segs; + unsigned short ufo_size; + unsigned int ip6_frag_id; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; }; @@ -341,6 +343,11 @@ extern void skb_over_panic(struct sk_buff *skb, int len, extern void skb_under_panic(struct sk_buff *skb, int len, void *here); +extern int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + int getfrag(void *from, char *to, int offset, + int len,int odd, struct sk_buff *skb), + void *from, int length); + struct skb_seq_state { __u32 lower_offset; diff --git a/net/core/dev.c b/net/core/dev.c index a44eeef24edf..8d1541595277 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2717,6 +2717,20 @@ int register_netdevice(struct net_device *dev) dev->name); dev->features &= ~NETIF_F_TSO; } + if (dev->features & NETIF_F_UFO) { + if (!(dev->features & NETIF_F_HW_CSUM)) { + printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no " + "NETIF_F_HW_CSUM feature.\n", + dev->name); + dev->features &= ~NETIF_F_UFO; + } + if (!(dev->features & NETIF_F_SG)) { + printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no " + "NETIF_F_SG feature.\n", + dev->name); + dev->features &= ~NETIF_F_UFO; + } + } /* * nil rebuild_header routine, diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 404b761e82ce..0350586e9195 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -93,6 +93,20 @@ int ethtool_op_get_perm_addr(struct net_device *dev, struct ethtool_perm_addr *a } +u32 ethtool_op_get_ufo(struct net_device *dev) +{ + return (dev->features & NETIF_F_UFO) != 0; +} + +int ethtool_op_set_ufo(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_UFO; + else + dev->features &= ~NETIF_F_UFO; + return 0; +} + /* Handlers for each ethtool command */ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) @@ -483,6 +497,11 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data) return err; } + if (!data && dev->ethtool_ops->set_ufo) { + err = dev->ethtool_ops->set_ufo(dev, 0); + if (err) + return err; + } return dev->ethtool_ops->set_sg(dev, data); } @@ -569,6 +588,32 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_tso(dev, edata.data); } +static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GTSO }; + + if (!dev->ethtool_ops->get_ufo) + return -EOPNOTSUPP; + edata.data = dev->ethtool_ops->get_ufo(dev); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} +static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (!dev->ethtool_ops->set_ufo) + return -EOPNOTSUPP; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.data && !(dev->features & NETIF_F_SG)) + return -EINVAL; + if (edata.data && !(dev->features & NETIF_F_HW_CSUM)) + return -EINVAL; + return dev->ethtool_ops->set_ufo(dev, edata.data); +} + static int ethtool_self_test(struct net_device *dev, char __user *useraddr) { struct ethtool_test test; @@ -854,6 +899,12 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_GPERMADDR: rc = ethtool_get_perm_addr(dev, useraddr); break; + case ETHTOOL_GUFO: + rc = ethtool_get_ufo(dev, useraddr); + break; + case ETHTOOL_SUFO: + rc = ethtool_set_ufo(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } @@ -882,3 +933,5 @@ EXPORT_SYMBOL(ethtool_op_set_sg); EXPORT_SYMBOL(ethtool_op_set_tso); EXPORT_SYMBOL(ethtool_op_set_tx_csum); EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); +EXPORT_SYMBOL(ethtool_op_set_ufo); +EXPORT_SYMBOL(ethtool_op_get_ufo); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ef9d46b91eb9..95501e40100e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -176,6 +176,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, skb_shinfo(skb)->tso_size = 0; skb_shinfo(skb)->tso_segs = 0; skb_shinfo(skb)->frag_list = NULL; + skb_shinfo(skb)->ufo_size = 0; + skb_shinfo(skb)->ip6_frag_id = 0; out: return skb; nodata: @@ -1696,6 +1698,78 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, return textsearch_find(config, state); } +/** + * skb_append_datato_frags: - append the user data to a skb + * @sk: sock structure + * @skb: skb structure to be appened with user data. + * @getfrag: call back function to be used for getting the user data + * @from: pointer to user message iov + * @length: length of the iov message + * + * Description: This procedure append the user data in the fragment part + * of the skb if any page alloc fails user this procedure returns -ENOMEM + */ +int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + int getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb), + void *from, int length) +{ + int frg_cnt = 0; + skb_frag_t *frag = NULL; + struct page *page = NULL; + int copy, left; + int offset = 0; + int ret; + + do { + /* Return error if we don't have space for new frag */ + frg_cnt = skb_shinfo(skb)->nr_frags; + if (frg_cnt >= MAX_SKB_FRAGS) + return -EFAULT; + + /* allocate a new page for next frag */ + page = alloc_pages(sk->sk_allocation, 0); + + /* If alloc_page fails just return failure and caller will + * free previous allocated pages by doing kfree_skb() + */ + if (page == NULL) + return -ENOMEM; + + /* initialize the next frag */ + sk->sk_sndmsg_page = page; + sk->sk_sndmsg_off = 0; + skb_fill_page_desc(skb, frg_cnt, page, 0, 0); + skb->truesize += PAGE_SIZE; + atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc); + + /* get the new initialized frag */ + frg_cnt = skb_shinfo(skb)->nr_frags; + frag = &skb_shinfo(skb)->frags[frg_cnt - 1]; + + /* copy the user data to page */ + left = PAGE_SIZE - frag->page_offset; + copy = (length > left)? left : length; + + ret = getfrag(from, (page_address(frag->page) + + frag->page_offset + frag->size), + offset, copy, 0, skb); + if (ret < 0) + return -EFAULT; + + /* copy was successful so update the size parameters */ + sk->sk_sndmsg_off += copy; + frag->size += copy; + skb->len += copy; + skb->data_len += copy; + offset += copy; + length -= copy; + + } while (length > 0); + + return 0; +} + void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", @@ -1747,3 +1821,4 @@ EXPORT_SYMBOL(skb_prepare_seq_read); EXPORT_SYMBOL(skb_seq_read); EXPORT_SYMBOL(skb_abort_seq_read); EXPORT_SYMBOL(skb_find_text); +EXPORT_SYMBOL(skb_append_datato_frags); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 87e350069abb..17758234a3e3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -275,7 +275,8 @@ int ip_output(struct sk_buff *skb) { IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); - if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->tso_size) + if (skb->len > dst_mtu(skb->dst) && + !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) return ip_fragment(skb, ip_finish_output); else return ip_finish_output(skb); @@ -688,6 +689,60 @@ csum_page(struct page *page, int offset, int copy) return csum; } +inline int ip_ufo_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, + int odd, struct sk_buff *skb), + void *from, int length, int hh_len, int fragheaderlen, + int transhdrlen, int mtu,unsigned int flags) +{ + struct sk_buff *skb; + int err; + + /* There is support for UDP fragmentation offload by network + * device, so create one single skb packet containing complete + * udp datagram + */ + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { + skb = sock_alloc_send_skb(sk, + hh_len + fragheaderlen + transhdrlen + 20, + (flags & MSG_DONTWAIT), &err); + + if (skb == NULL) + return err; + + /* reserve space for Hardware header */ + skb_reserve(skb, hh_len); + + /* create space for UDP/IP header */ + skb_put(skb,fragheaderlen + transhdrlen); + + /* initialize network header pointer */ + skb->nh.raw = skb->data; + + /* initialize protocol header pointer */ + skb->h.raw = skb->data + fragheaderlen; + + skb->ip_summed = CHECKSUM_HW; + skb->csum = 0; + sk->sk_sndmsg_off = 0; + } + + err = skb_append_datato_frags(sk,skb, getfrag, from, + (length - transhdrlen)); + if (!err) { + /* specify the length of each IP datagram fragment*/ + skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); + __skb_queue_tail(&sk->sk_write_queue, skb); + + return 0; + } + /* There is not enough support do UFO , + * so follow normal path + */ + kfree_skb(skb); + return err; +} + /* * ip_append_data() and ip_append_page() can make one large IP datagram * from many pieces of data. Each pieces will be holded on the socket @@ -777,6 +832,15 @@ int ip_append_data(struct sock *sk, csummode = CHECKSUM_HW; inet->cork.length += length; + if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && + (rt->u.dst.dev->features & NETIF_F_UFO)) { + + if(ip_ufo_append_data(sk, getfrag, from, length, hh_len, + fragheaderlen, transhdrlen, mtu, flags)) + goto error; + + return 0; + } /* So, what's going on in the loop below? * @@ -1008,14 +1072,23 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, return -EINVAL; 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); + while (size > 0) { int i; - /* Check if the remaining data fits into current packet. */ - len = mtu - skb->len; - if (len < size) - len = maxfraglen - skb->len; + if (skb_shinfo(skb)->ufo_size) + len = size; + else { + + /* Check if the remaining data fits into current packet. */ + len = mtu - skb->len; + if (len < size) + len = maxfraglen - skb->len; + } if (len <= 0) { struct sk_buff *skb_prev; char *data; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 563b442ffab8..614296a920c6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -147,7 +147,8 @@ static int ip6_output2(struct sk_buff *skb) int ip6_output(struct sk_buff *skb) { - if (skb->len > dst_mtu(skb->dst) || dst_allfrag(skb->dst)) + if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) || + dst_allfrag(skb->dst)) return ip6_fragment(skb, ip6_output2); else return ip6_output2(skb); @@ -768,6 +769,65 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) *dst = NULL; return err; } +inline int ip6_ufo_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, + int odd, struct sk_buff *skb), + void *from, int length, int hh_len, int fragheaderlen, + int transhdrlen, int mtu,unsigned int flags) + +{ + struct sk_buff *skb; + int err; + + /* There is support for UDP large send offload by network + * device, so create one single skb packet containing complete + * udp datagram + */ + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { + skb = sock_alloc_send_skb(sk, + hh_len + fragheaderlen + transhdrlen + 20, + (flags & MSG_DONTWAIT), &err); + if (skb == NULL) + return -ENOMEM; + + /* reserve space for Hardware header */ + skb_reserve(skb, hh_len); + + /* create space for UDP/IP header */ + skb_put(skb,fragheaderlen + transhdrlen); + + /* initialize network header pointer */ + skb->nh.raw = skb->data; + + /* initialize protocol header pointer */ + skb->h.raw = skb->data + fragheaderlen; + + skb->ip_summed = CHECKSUM_HW; + skb->csum = 0; + sk->sk_sndmsg_off = 0; + } + + err = skb_append_datato_frags(sk,skb, getfrag, from, + (length - transhdrlen)); + if (!err) { + struct frag_hdr fhdr; + + /* specify the length of each IP datagram fragment*/ + skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) - + sizeof(struct frag_hdr); + ipv6_select_ident(skb, &fhdr); + skb_shinfo(skb)->ip6_frag_id = fhdr.identification; + __skb_queue_tail(&sk->sk_write_queue, skb); + + return 0; + } + /* There is not enough support do UPD LSO, + * so follow normal path + */ + kfree_skb(skb); + + return err; +} int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), @@ -860,6 +920,15 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, */ inet->cork.length += length; + if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && + (rt->u.dst.dev->features & NETIF_F_UFO)) { + + if(ip6_ufo_append_data(sk, getfrag, from, length, hh_len, + fragheaderlen, transhdrlen, mtu, flags)) + goto error; + + return 0; + } if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) goto alloc_new_skb; From f12baeab9d65e2fe1b43b09b666f5efcb81b9369 Mon Sep 17 00:00:00 2001 From: Yan Zheng Date: Sat, 29 Oct 2005 00:02:32 +0800 Subject: [PATCH 0968/1939] [MCAST] IPv6: Fix algorithm to compute Querier's Query Interval 5.1.3. Maximum Response Code The Maximum Response Code field specifies the maximum time allowed before sending a responding Report. The actual time allowed, called the Maximum Response Delay, is represented in units of milliseconds, and is derived from the Maximum Response Code as follows: If Maximum Response Code < 32768, Maximum Response Delay = Maximum Response Code If Maximum Response Code >=32768, Maximum Response Code represents a floating-point value as follows: 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Maximum Response Delay = (mant | 0x1000) << (exp+3) 5.1.9. QQIC (Querier's Query Interval Code) The Querier's Query Interval Code field specifies the [Query Interval] used by the Querier. The actual interval, called the Querier's Query Interval (QQI), is represented in units of seconds, and is derived from the Querier's Query Interval Code as follows: If QQIC < 128, QQI = QQIC If QQIC >= 128, QQIC represents a floating-point value as follows: 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ QQI = (mant | 0x10) << (exp + 3) -- rfc3810 #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) Above macro are defined in mcast.c. but 1 << 4 == 0x10 and 1 << 12 == 0x1000. So the result computed by original Macro is larger. Signed-off-by: Yan Zheng Acked-by: David L Stevens Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv6/mcast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 39a96c768102..c4f2a0ef7489 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -164,7 +164,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, #define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) #define MLDV2_EXP(thresh, nbmant, nbexp, value) \ ((value) < (thresh) ? (value) : \ - ((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \ + ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) From a21a84a375ea3783cf9a53730d643c4db24371bc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 28 Oct 2005 15:43:16 -0400 Subject: [PATCH 0969/1939] [libata pdc_adma] minor fixes and cleanups Changes mostly from Mark Lord. - fix bugs in probe-time error handling - only complete qc if not NULL - check port-level polling flags --- drivers/scsi/pdc_adma.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 9820f272f889..7999817915c3 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -46,7 +46,7 @@ #include #define DRV_NAME "pdc_adma" -#define DRV_VERSION "0.01" +#define DRV_VERSION "0.03" /* macro to calculate base address for ATA regs */ #define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) @@ -79,7 +79,6 @@ enum { aNIEN = (1 << 8), /* irq mask: 1==masked */ aGO = (1 << 7), /* packet trigger ("Go!") */ aRSTADM = (1 << 5), /* ADMA logic reset */ - aRSTA = (1 << 2), /* ATA hard reset */ aPIOMD4 = 0x0003, /* PIO mode 4 */ /* ADMA_STATUS register bits */ @@ -452,24 +451,25 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) struct adma_port_priv *pp; struct ata_queued_cmd *qc; void __iomem *chan = ADMA_REGS(mmio_base, port_no); - u8 drv_stat, status = readb(chan + ADMA_STATUS); + u8 drv_stat = 0, status = readb(chan + ADMA_STATUS); if (status == 0) continue; handled = 1; adma_enter_reg_mode(ap); - if ((ap->flags & ATA_FLAG_PORT_DISABLED)) + if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) continue; pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - drv_stat = 0; - if ((status & (aPERR | aPSD | aUIRQ))) - drv_stat = ATA_ERR; - else if (pp->pkt[0] != cDONE) - drv_stat = ATA_ERR; - ata_qc_complete(qc, drv_stat); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if ((status & (aPERR | aPSD | aUIRQ))) + drv_stat = ATA_ERR; + else if (pp->pkt[0] != cDONE) + drv_stat = ATA_ERR; + ata_qc_complete(qc, drv_stat); + } } return handled; } @@ -561,15 +561,15 @@ static int adma_port_start(struct ata_port *ap) if ((pp->pkt_dma & 7) != 0) { printk("bad alignment for pp->pkt_dma: %08x\n", (u32)pp->pkt_dma); - goto err_out_kfree2; + dma_free_coherent(dev, ADMA_PKT_BYTES, + pp->pkt, pp->pkt_dma); + goto err_out_kfree; } memset(pp->pkt, 0, ADMA_PKT_BYTES); ap->private_data = pp; adma_reinit_engine(ap); return 0; -err_out_kfree2: - kfree(pp); err_out_kfree: kfree(pp); err_out: From 00ac37f508689da281586c7ef304f26b5138d8a6 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Fri, 28 Oct 2005 15:58:28 -0400 Subject: [PATCH 0970/1939] [libata scsi] MODE SELECT, strengthen mode sense - move default mode pages to the front of libata-scsi.c so various functions can access them - partial annotation of these pages, point out divergence from sat-r06 - replace various mode page magic numbers with defines - strengthen MODE SENSE command decoding: handle DBD bit in cdb, yield block descriptor (per sat-r06) and handle mode sub pages Signed-off-by: Douglas Gilbert Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 144 ++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b761bd1b9717..89a04b1a5a0e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -51,6 +51,45 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scs static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +#define RW_RECOVERY_MPAGE 0x1 +#define RW_RECOVERY_MPAGE_LEN 12 +#define CACHE_MPAGE 0x8 +#define CACHE_MPAGE_LEN 20 +#define CONTROL_MPAGE 0xa +#define CONTROL_MPAGE_LEN 12 +#define ALL_MPAGES 0x3f +#define ALL_SUB_MPAGES 0xff + + +static const u8 def_rw_recovery_mpage[] = { + RW_RECOVERY_MPAGE, + RW_RECOVERY_MPAGE_LEN - 2, + (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ + (1 << 6), /* ARRE (auto read reallocation) */ + 0, /* read retry count */ + 0, 0, 0, 0, + 0, /* write retry count */ + 0, 0, 0 +}; + +static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = { + CACHE_MPAGE, + CACHE_MPAGE_LEN - 2, + 0, /* contains WCE, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* contains DRA, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0 +}; + +static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { + CONTROL_MPAGE, + CONTROL_MPAGE_LEN - 2, + 2, /* DSENSE=0, GLTSD=1 */ + 0, /* [QAM+QERR may be 1, see 05-359r1] */ + 0, 0, 0, 0, 0xff, 0xff, + 0, 30 /* extended self test time, see 05-359r1 */ +}; + static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) @@ -1583,13 +1622,9 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, const u8 *last) { - u8 page[] = { - 0x8, /* page code */ - 0x12, /* page length */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ - }; + u8 page[CACHE_MPAGE_LEN]; + memcpy(page, def_cache_mpage, sizeof(page)); if (ata_id_wcache_enabled(id)) page[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) @@ -1613,15 +1648,9 @@ static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) { - const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; - - /* byte 2: set the descriptor format sense data bit (bit 2) - * since we need to support returning this format for SAT - * commands and any SCSI commands against a 48b LBA device. - */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_control_mpage, + sizeof(def_control_mpage)); + return sizeof(def_control_mpage); } /** @@ -1638,15 +1667,10 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) { - const u8 page[] = { - 0x1, /* page code */ - 0xa, /* page length */ - (1 << 7) | (1 << 6), /* note auto r/w reallocation */ - 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ - }; - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_rw_recovery_mpage, + sizeof(def_rw_recovery_mpage)); + return sizeof(def_rw_recovery_mpage); } /** @@ -1655,7 +1679,9 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * - * Simulate MODE SENSE commands. + * Simulate MODE SENSE commands. Assume this is invoked for direct + * access devices (e.g. disks) only. There should be no block + * descriptor for other device types. * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -1665,15 +1691,22 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { u8 *scsicmd = args->cmd->cmnd, *p, *last; - unsigned int page_control, six_byte, output_len; + const u8 sat_blk_desc[] = { + 0, 0, 0, 0, /* number of blocks: sat unspecified */ + 0, + 0, 0x2, 0x0 /* block length: 512 bytes */ + }; + u8 pg, spg; + unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; VPRINTK("ENTER\n"); six_byte = (scsicmd[0] == MODE_SENSE); - - /* we only support saved and current values (which we treat - * in the same manner) + ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */ + /* + * LLBA bit in msense(10) ignored (compliant) */ + page_control = scsicmd[2] >> 6; switch (page_control) { case 0: /* current */ @@ -1686,29 +1719,42 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (six_byte) - output_len = 4; - else - output_len = 8; + if (six_byte) { + output_len = 4 + (ebd ? 8 : 0); + alloc_len = scsicmd[4]; + } else { + output_len = 8 + (ebd ? 8 : 0); + alloc_len = (scsicmd[7] << 8) + scsicmd[8]; + } + minlen = (alloc_len < buflen) ? alloc_len : buflen; p = rbuf + output_len; - last = rbuf + buflen - 1; + last = rbuf + minlen - 1; - switch(scsicmd[2] & 0x3f) { - case 0x01: /* r/w error recovery */ + pg = scsicmd[2] & 0x3f; + spg = scsicmd[3]; + /* + * No mode subpages supported (yet) but asking for _all_ + * subpages may be valid + */ + if (spg && (spg != ALL_SUB_MPAGES)) + goto invalid_fld; + + switch(pg) { + case RW_RECOVERY_MPAGE: output_len += ata_msense_rw_recovery(&p, last); break; - case 0x08: /* caching */ + case CACHE_MPAGE: output_len += ata_msense_caching(args->id, &p, last); break; - case 0x0a: { /* control mode */ + case CONTROL_MPAGE: { output_len += ata_msense_ctl_mode(&p, last); break; } - case 0x3f: /* all pages */ + case ALL_MPAGES: output_len += ata_msense_rw_recovery(&p, last); output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); @@ -1718,15 +1764,31 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } + if (minlen < 1) + return 0; if (six_byte) { output_len--; rbuf[0] = output_len; + if (ebd) { + if (minlen > 3) + rbuf[3] = sizeof(sat_blk_desc); + if (minlen > 11) + memcpy(rbuf + 4, sat_blk_desc, + sizeof(sat_blk_desc)); + } } else { output_len -= 2; rbuf[0] = output_len >> 8; - rbuf[1] = output_len; + if (minlen > 1) + rbuf[1] = output_len; + if (ebd) { + if (minlen > 7) + rbuf[7] = sizeof(sat_blk_desc); + if (minlen > 15) + memcpy(rbuf + 8, sat_blk_desc, + sizeof(sat_blk_desc)); + } } - return 0; invalid_fld: @@ -2156,7 +2218,7 @@ ata_scsi_map_proto(u8 byte1) * Zero on success, non-zero on failure. */ static unsigned int -ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd) +ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &(qc->tf); struct scsi_cmnd *cmd = qc->scsicmd; From a4e2b347848bf626b822599329933887dc90e50f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:46:52 -0700 Subject: [PATCH 0971/1939] [PATCH] tg3: add 5714/5715 support Add complete support for 5714/5715. These chips are very similar to 5780 so the changes are very trivial. A TG3_FLG2_5780_CLASS flag is added to identify these chips. Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 39 +++++++++++++++++++++++++-------------- drivers/net/tg3.h | 11 +++++++++-- include/linux/pci_ids.h | 2 ++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1802c3b48799..cf2204f5b7f9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -219,6 +219,10 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, @@ -570,7 +574,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) return; orig_clock_ctrl = clock_ctrl; @@ -1210,7 +1214,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); udelay(40); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { @@ -3712,14 +3716,14 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; ethtool_op_set_tso(dev, 0); } else tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } else { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } @@ -3850,7 +3854,7 @@ static void tg3_init_rings(struct tg3 *tp) memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) && + if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && (tp->dev->mtu > ETH_DATA_LEN)) tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; @@ -4347,7 +4351,7 @@ static int tg3_chip_reset(struct tg3 *tp) val &= ~PCIX_CAPS_RELAXED_ORDERING; pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { u32 val; /* Chip reset on 5780 will reset MSI enable bit, @@ -6003,7 +6007,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780)) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) limit = 8; else limit = 16; @@ -7237,7 +7241,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -8380,7 +8384,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -8980,7 +8984,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_MII_SERDES; else tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; @@ -9393,8 +9397,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Find msi capability. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); + } /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & @@ -9412,7 +9419,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || @@ -9607,7 +9614,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * ether_setup() via the alloc_etherdev() call */ if (tp->dev->mtu > ETH_DATA_LEN && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; /* Determine WakeOnLan speed to use. */ @@ -9830,7 +9837,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && !(tp->tg3_flags & TG3_FLG2_SUN_570X)) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -10148,6 +10155,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* 5780 always in PCIX mode */ tp->dma_rwctrl |= 0x00144000; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + /* 5714 always in PCIX mode */ + tp->dma_rwctrl |= 0x00148000; } else { tp->dma_rwctrl |= 0x001b000f; } @@ -10347,6 +10357,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; case PHY_ID_BCM5752: return "5752"; + case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 2e733c60bfa4..456ef2b3d0ef 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -137,6 +137,7 @@ #define ASIC_REV_5750 0x04 #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 +#define ASIC_REV_5714 0x09 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -531,6 +532,8 @@ #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 /* 0x598 --> 0x5b0 unused */ +#define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ +#define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 #define SG_DIG_USING_HW_AUTONEG 0x80000000 #define SG_DIG_SOFT_RESET 0x40000000 @@ -1329,6 +1332,8 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_USE_SIG_DETECT 0x00000010 /* 5714/5780 only */ +#define GRC_LCLCTRL_USE_EXT_SIG_DETECT 0x00000020 /* 5714/5780 only */ #define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 #define GRC_LCLCTRL_GPIO_OE3 0x00000040 #define GRC_LCLCTRL_GPIO_OUTPUT3 0x00000080 @@ -2175,6 +2180,7 @@ struct tg3 { TG3_FLG2_MII_SERDES) #define TG3_FLG2_PARALLEL_DETECT 0x01000000 #define TG3_FLG2_ICH_WORKAROUND 0x02000000 +#define TG3_FLG2_5780_CLASS 0x04000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2222,6 +2228,7 @@ struct tg3 { #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM5752 0x60008100 +#define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2246,8 +2253,8 @@ struct tg3 { (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ + (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 71834f05504f..d6865bbd9ea4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2165,11 +2165,13 @@ #define PCI_DEVICE_ID_TIGON3_5721 0x1659 #define PCI_DEVICE_ID_TIGON3_5705M 0x165d #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e +#define PCI_DEVICE_ID_TIGON3_5714 0x1668 #define PCI_DEVICE_ID_TIGON3_5780 0x166a #define PCI_DEVICE_ID_TIGON3_5780S 0x166b #define PCI_DEVICE_ID_TIGON3_5705F 0x166e #define PCI_DEVICE_ID_TIGON3_5750 0x1676 #define PCI_DEVICE_ID_TIGON3_5751 0x1677 +#define PCI_DEVICE_ID_TIGON3_5715 0x1678 #define PCI_DEVICE_ID_TIGON3_5750M 0x167c #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e From 28fbef78a420acdea20570d31f3bdcbfa0cac0d2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:48:35 -0700 Subject: [PATCH 0972/1939] [PATCH] tg3: fix ASF heartbeat Change the ASF heart beat to 5 seconds for faster detection of system crash. The driver sends the heartbeat every 2 seconds and the ASF firmware will timeout and reset the device if no heartbeat is received after 5 seconds. The old scheme of 2 minutes is ineffective. tg3_write_mem_fast() is added to speed up the IO to send the heartbeat. When no workaround is needed, it will use direct MMIO to memory space to write to memory. Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 21 ++++++++++++++++----- drivers/net/tg3.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cf2204f5b7f9..479be21425fb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -470,6 +470,15 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } +static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) +{ + /* If no workaround is needed, write to mem space directly */ + if (tp->write32 != tg3_write_indirect_reg32) + tw32(NIC_SRAM_WIN_BASE + off, val); + else + tg3_write_mem(tp, off, val); +} + static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; @@ -6195,14 +6204,16 @@ static void tg3_timer(unsigned long __opaque) tp->timer_counter = tp->timer_multiplier; } - /* Heartbeat is only sent once every 120 seconds. */ + /* Heartbeat is only sent once every 2 seconds. */ if (!--tp->asf_counter) { if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + /* 5 seconds timeout */ + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -6413,7 +6424,7 @@ static int tg3_open(struct net_device *dev) tp->timer_counter = tp->timer_multiplier = (HZ / tp->timer_offset); tp->asf_counter = tp->asf_multiplier = - ((HZ / tp->timer_offset) * 120); + ((HZ / tp->timer_offset) * 2); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 456ef2b3d0ef..fb7e2a5f4a08 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1512,6 +1512,7 @@ #define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004 #define FWCMD_NICDRV_FIX_DMAR 0x00000005 #define FWCMD_NICDRV_FIX_DMAW 0x00000006 +#define FWCMD_NICDRV_ALIVE2 0x0000000d #define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c #define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80 #define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00 From 37ff238d68683d42e7363eee3303773906c336d9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:49:51 -0700 Subject: [PATCH 0973/1939] [PATCH] tg3: update version and minor fixes Update version and reldate and add more sanity checking to tg3_set_settings(). Signed-off-by: Gary Zambrano Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 479be21425fb..551c9449322d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -67,8 +67,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.42" -#define DRV_MODULE_RELDATE "Oct 3, 2005" +#define DRV_MODULE_VERSION "3.43" +#define DRV_MODULE_RELDATE "Oct 24, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7279,7 +7279,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -7287,7 +7287,17 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_Autoneg | ADVERTISED_FIBRE))) return -EINVAL; - } + /* Fiber can only do SPEED_1000. */ + else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed != SPEED_1000)) + return -EINVAL; + /* Copper cannot force SPEED_1000. */ + } else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed == SPEED_1000)) + return -EINVAL; + else if ((cmd->speed == SPEED_1000) && + (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + return -EINVAL; tg3_full_lock(tp, 0); From 0abe791e94033b727f2b55670c2966f3d3d3cf70 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:46:53 -0600 Subject: [PATCH 0974/1939] [PATCH] ibmveth fix bonding This patch updates dev->trans_start and dev->last_rx so that the ibmveth driver can be used with the ARP monitor in the bonding driver. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index a2c4dd4fb221..5617bec7fd53 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -725,6 +725,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) } else { adapter->stats.tx_packets++; adapter->stats.tx_bytes += skb->len; + netdev->trans_start = jiffies; } do { @@ -776,6 +777,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) adapter->stats.rx_packets++; adapter->stats.rx_bytes += length; frames_processed++; + netdev->last_rx = jiffies; } } else { more_work = 0; From b6d35182fe62e57d368062adcc880ca35119d88e Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:01 -0600 Subject: [PATCH 0975/1939] [PATCH] ibmveth fix buffer pool management This patch changes the way the ibmveth driver handles the receive buffers. The old code mallocs and maps all the buffers in the pools regardless of MTU size and it also limits the number of buffer pools to three. This patch makes the driver malloc and map the buffers necessary to support the current MTU. It also changes the hardcoded names of the buffer pool number, size, and elements to arrays to make it easier to change (with the hope of making them runtime parameters in the future). Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 102 ++++++++++++++++++++++++++++++------------ drivers/net/ibmveth.h | 18 +++++--- 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5617bec7fd53..d985b804a762 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -97,6 +97,7 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); +static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "net/ibmveth" @@ -181,6 +182,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) atomic_set(&pool->available, 0); pool->producer_index = 0; pool->consumer_index = 0; + pool->active = 0; return 0; } @@ -258,9 +260,14 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc /* check if replenishing is needed. */ static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) { - return ((atomic_read(&adapter->rx_buff_pool[0].available) < adapter->rx_buff_pool[0].threshold) || - (atomic_read(&adapter->rx_buff_pool[1].available) < adapter->rx_buff_pool[1].threshold) || - (atomic_read(&adapter->rx_buff_pool[2].available) < adapter->rx_buff_pool[2].threshold)); + int i; + + for(i = 0; i < IbmVethNumBufferPools; i++) + if(adapter->rx_buff_pool[i].active && + (atomic_read(&adapter->rx_buff_pool[i].available) < + adapter->rx_buff_pool[i].threshold)) + return 1; + return 0; } /* kick the replenish tasklet if we need replenishing and it isn't already running */ @@ -275,11 +282,14 @@ static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter /* replenish tasklet routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { + int i; + adapter->replenish_task_cycles++; - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; i < IbmVethNumBufferPools; i++) + if(adapter->rx_buff_pool[i].active) + ibmveth_replenish_buffer_pool(adapter, + &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); @@ -321,6 +331,7 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm kfree(pool->skbuff); pool->skbuff = NULL; } + pool->active = 0; } /* remove a buffer from a pool */ @@ -379,6 +390,12 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) ibmveth_assert(pool < IbmVethNumBufferPools); ibmveth_assert(index < adapter->rx_buff_pool[pool].size); + if(!adapter->rx_buff_pool[pool].active) { + ibmveth_rxq_harvest_buffer(adapter); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]); + return; + } + desc.desc = 0; desc.fields.valid = 1; desc.fields.length = adapter->rx_buff_pool[pool].buff_size; @@ -409,6 +426,8 @@ static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) static void ibmveth_cleanup(struct ibmveth_adapter *adapter) { + int i; + if(adapter->buffer_list_addr != NULL) { if(!dma_mapping_error(adapter->buffer_list_dma)) { dma_unmap_single(&adapter->vdev->dev, @@ -443,26 +462,24 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) adapter->rx_queue.queue_addr = NULL; } - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; irx_buff_pool[i]); } static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; u64 mac_address = 0; - int rxq_entries; + int rxq_entries = 1; unsigned long lpar_rc; int rc; union ibmveth_buf_desc rxq_desc; + int i; ibmveth_debug_printk("open starting\n"); - rxq_entries = - adapter->rx_buff_pool[0].size + - adapter->rx_buff_pool[1].size + - adapter->rx_buff_pool[2].size + 1; + for(i = 0; irx_buff_pool[i].size; adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL); adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL); @@ -502,14 +519,8 @@ static int ibmveth_open(struct net_device *netdev) adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - if(ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[0]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[1]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[2])) - { - ibmveth_error_printk("unable to allocate buffer pools\n"); - ibmveth_cleanup(adapter); - return -ENOMEM; - } + /* call change_mtu to init the buffer pools based in initial mtu */ + ibmveth_change_mtu(netdev, netdev->mtu); memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; @@ -885,17 +896,52 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > (1<<20))) + struct ibmveth_adapter *adapter = dev->priv; + int i; + int prev_smaller = 1; + + if ((new_mtu < 68) || + (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) return -EINVAL; + + for(i = 0; i (pool_size[i] - IBMVETH_BUFF_OH)) { + activate = 1; + prev_smaller= 1; + } else { + if (prev_smaller) + activate = 1; + prev_smaller= 0; + } + + if (activate && !adapter->rx_buff_pool[i].active) { + struct ibmveth_buff_pool *pool = + &adapter->rx_buff_pool[i]; + if(ibmveth_alloc_buffer_pool(pool)) { + ibmveth_error_printk("unable to alloc pool\n"); + return -ENOMEM; + } + adapter->rx_buff_pool[i].active = 1; + } else if (!activate && adapter->rx_buff_pool[i].active) { + adapter->rx_buff_pool[i].active = 0; + h_free_logical_lan_buffer(adapter->vdev->unit_address, + (u64)pool_size[i]); + } + + } + + + ibmveth_schedule_replenishing(adapter); dev->mtu = new_mtu; return 0; } static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { - int rc; + int rc, i; struct net_device *netdev; - struct ibmveth_adapter *adapter; + struct ibmveth_adapter *adapter = NULL; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -965,9 +1011,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[0], 0, IbmVethPool0DftCnt, IbmVethPool0DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[1], 1, IbmVethPool1DftCnt, IbmVethPool1DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[2], 2, IbmVethPool2DftCnt, IbmVethPool2DftSize); + for(i = 0; irx_buff_pool[i], i, + pool_count[i], pool_size[i]); ibmveth_debug_printk("adapter @ 0x%p\n", adapter); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 51a470da9686..a5d27a9cdf1f 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -49,6 +49,7 @@ #define H_SEND_LOGICAL_LAN 0x120 #define H_MULTICAST_CTRL 0x130 #define H_CHANGE_LOGICAL_LAN_MAC 0x14C +#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ @@ -69,13 +70,15 @@ #define h_change_logical_lan_mac(ua, mac) \ plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac) -#define IbmVethNumBufferPools 3 -#define IbmVethPool0DftSize (1024 * 2) -#define IbmVethPool1DftSize (1024 * 4) -#define IbmVethPool2DftSize (1024 * 10) -#define IbmVethPool0DftCnt 256 -#define IbmVethPool1DftCnt 256 -#define IbmVethPool2DftCnt 256 +#define h_free_logical_lan_buffer(ua, bufsize) \ + plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize) + +#define IbmVethNumBufferPools 5 +#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */ + +/* pool_size should be sorted */ +static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 }; +static int pool_count[] = { 256, 768, 256, 256, 256 }; #define IBM_VETH_INVALID_MAP ((u16)0xffff) @@ -90,6 +93,7 @@ struct ibmveth_buff_pool { u16 *free_map; dma_addr_t *dma_addr; struct sk_buff **skbuff; + int active; }; struct ibmveth_rx_q { From e2adbcb480992de8a01acf9218e8bbd9b507fc6f Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:08 -0600 Subject: [PATCH 0976/1939] [PATCH] ibmveth fix buffer replenishing This patch removes the allocation of RX skb's buffers from a workqueue to be called directly at RX processing time. This change was suggested by Dave Miller when the driver was starving the RX buffers and deadlocking under heavy traffic: > Allocating RX SKBs via tasklet is, IMHO, the worst way to > do it. It is no surprise that there are starvation cases. > > If tasklets or work queues get delayed in any way, you lose, > and it's very easy for a card to catch up with the driver RX'ing > packets very fast, no matter how aggressive you make the > replenishing. By the time you detect that you need to be > "more aggressive" it is already too late. > The only pseudo-reliable way is to allocate at RX processing time. > Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 48 ++++++++----------------------------------- drivers/net/ibmveth.h | 4 ---- 2 files changed, 8 insertions(+), 44 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index d985b804a762..aea1598b2253 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -96,7 +96,6 @@ static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); #ifdef CONFIG_PROC_FS @@ -257,29 +256,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc atomic_add(buffers_added, &(pool->available)); } -/* check if replenishing is needed. */ -static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) -{ - int i; - - for(i = 0; i < IbmVethNumBufferPools; i++) - if(adapter->rx_buff_pool[i].active && - (atomic_read(&adapter->rx_buff_pool[i].available) < - adapter->rx_buff_pool[i].threshold)) - return 1; - return 0; -} - -/* kick the replenish tasklet if we need replenishing and it isn't already running */ -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter) -{ - if(ibmveth_is_replenishing_needed(adapter) && - (atomic_dec_if_positive(&adapter->not_replenishing) == 0)) { - schedule_work(&adapter->replenish_task); - } -} - -/* replenish tasklet routine */ +/* replenish routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { int i; @@ -292,10 +269,6 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); - - atomic_inc(&adapter->not_replenishing); - - ibmveth_schedule_replenishing(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -563,10 +536,10 @@ static int ibmveth_open(struct net_device *netdev) return rc; } - netif_start_queue(netdev); + ibmveth_debug_printk("initial replenish cycle\n"); + ibmveth_replenish_task(adapter); - ibmveth_debug_printk("scheduling initial replenish cycle\n"); - ibmveth_schedule_replenishing(adapter); + netif_start_queue(netdev); ibmveth_debug_printk("open complete\n"); @@ -584,9 +557,6 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); - cancel_delayed_work(&adapter->replenish_task); - flush_scheduled_work(); - do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); @@ -795,7 +765,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) } } while(more_work && (frames_processed < max_frames_to_process)); - ibmveth_schedule_replenishing(adapter); + ibmveth_replenish_task(adapter); if(more_work) { /* more work to do - return that we are not done yet */ @@ -931,8 +901,10 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) } + /* kick the interrupt handler so that the new buffer pools get + replenished or deallocated */ + ibmveth_interrupt(dev->irq, dev, NULL); - ibmveth_schedule_replenishing(adapter); dev->mtu = new_mtu; return 0; } @@ -1017,14 +989,10 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("adapter @ 0x%p\n", adapter); - INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); - adapter->buffer_list_dma = DMA_ERROR_CODE; adapter->filter_list_dma = DMA_ERROR_CODE; adapter->rx_queue.queue_dma = DMA_ERROR_CODE; - atomic_set(&adapter->not_replenishing, 1); - ibmveth_debug_printk("registering netdev...\n"); rc = register_netdev(netdev); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index a5d27a9cdf1f..a3ea02937d63 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -118,10 +118,6 @@ struct ibmveth_adapter { dma_addr_t filter_list_dma; struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; - atomic_t not_replenishing; - - /* helper tasks */ - struct work_struct replenish_task; /* adapter specific stats */ u64 replenish_task_cycles; From 60296d9e4be1cd9e096f7804ce6e839e0cbd97cf Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:16 -0600 Subject: [PATCH 0977/1939] [PATCH] ibmveth lockless TX This patch adds the lockless TX feature to the ibmveth driver. The hypervisor has its own locking so the only change that is necessary is to protect the statistics counters. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 44 ++++++++++++++++++++++++++++--------------- drivers/net/ibmveth.h | 1 + 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index aea1598b2253..987bcba01889 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -621,12 +621,18 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned long lpar_rc; int nfrags = 0, curfrag; unsigned long correlator; + unsigned long flags; unsigned int retry_count; + unsigned int tx_dropped = 0; + unsigned int tx_bytes = 0; + unsigned int tx_packets = 0; + unsigned int tx_send_failed = 0; + unsigned int tx_map_failed = 0; + if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_dropped++; + goto out; } memset(&desc, 0, sizeof(desc)); @@ -645,10 +651,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_map_failed++; + tx_dropped++; + goto out; } curfrag = nfrags; @@ -665,8 +670,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; + tx_map_failed++; + tx_dropped++; /* Free all the mappings we just created */ while(curfrag < nfrags) { dma_unmap_single(&adapter->vdev->dev, @@ -675,8 +680,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) DMA_TO_DEVICE); curfrag++; } - dev_kfree_skb(skb); - return 0; + goto out; } } @@ -701,11 +705,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); } - adapter->tx_send_failed++; - adapter->stats.tx_dropped++; + tx_send_failed++; + tx_dropped++; } else { - adapter->stats.tx_packets++; - adapter->stats.tx_bytes += skb->len; + tx_packets++; + tx_bytes += skb->len; netdev->trans_start = jiffies; } @@ -715,6 +719,14 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[nfrags].fields.length, DMA_TO_DEVICE); } while(--nfrags >= 0); +out: spin_lock_irqsave(&adapter->stats_lock, flags); + adapter->stats.tx_dropped += tx_dropped; + adapter->stats.tx_bytes += tx_bytes; + adapter->stats.tx_packets += tx_packets; + adapter->tx_send_failed += tx_send_failed; + adapter->tx_map_failed += tx_map_failed; + spin_unlock_irqrestore(&adapter->stats_lock, flags); + dev_kfree_skb(skb); return 0; } @@ -980,6 +992,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); + netdev->features |= NETIF_F_LLTX; + spin_lock_init(&adapter->stats_lock); memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index a3ea02937d63..46919a814fca 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -131,6 +131,7 @@ struct ibmveth_adapter { u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; + spinlock_t stats_lock; }; struct ibmveth_buf_desc_fields { From 82702d37a559cf94fe238cd3f8ef63cf7fa699a9 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:23 -0600 Subject: [PATCH 0978/1939] [PATCH] ibmveth fix failed addbuf This patch fixes a bug that happens when the hypervisor can't add a buffer. The old code wrote IBM_VETH_INVALID_MAP into the free_map array, so next time the index was used, a ibmveth_assert() caught it and called BUG(). The patch writes the right value into the free_map array so that the index can be reused. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 987bcba01889..f5819527ec9d 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -237,7 +237,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { - pool->free_map[free_index] = IBM_VETH_INVALID_MAP; + pool->free_map[free_index] = index; pool->skbuff[index] = NULL; pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, From d89a64bedf956ef0b406018a7cb76e027fe3e751 Mon Sep 17 00:00:00 2001 From: Komuro Date: Fri, 28 Oct 2005 16:09:54 -0400 Subject: [PATCH 0979/1939] pcnet_cs: fix mii init code for older DL10019 based cards Some older DL10019 based cards need to setup the auto-negotiation-advertisement register to advertise 100Full,100Half,10Full and 10Half. Signed-off-by: Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/pcnet_cs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9f22d138e3ad..818c185d6438 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1020,6 +1020,12 @@ static void set_misc_reg(struct net_device *dev) } else { outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG); } + } else if (info->flags & IS_DL10019) { + /* Advertise 100F, 100H, 10F, 10H */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1); + /* Restart MII autonegotiation */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000); + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200); } } From 008d55903a1e9e179ff1d366dfcfa9b72abd116d Mon Sep 17 00:00:00 2001 From: Roger While Date: Fri, 28 Oct 2005 16:11:49 -0400 Subject: [PATCH 0980/1939] [wireless prism54] Fix frame length prism54 is leaking information when passing transmits to the firmware. There is no requirement to adjust the length to >= ETH_ZLEN. Just pass the skb length (after possible adjustment). Signed-off-by: Roger While Signed-off-by: Jeff Garzik --- drivers/net/wireless/prism54/islpci_eth.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 5952e9960499..0975dd4ed77d 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -97,12 +97,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* lock the driver code */ spin_lock_irqsave(&priv->slock, flags); - /* determine the amount of fragments needed to store the frame */ - - frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - if (init_wds) - frame_size += 6; - /* check whether the destination queue has enough fragments for the frame */ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { @@ -213,6 +207,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* store the skb address for future freeing */ priv->data_low_tx[index] = skb; /* set the proper fragment start address and size information */ + frame_size = skb->len; fragment->size = cpu_to_le16(frame_size); fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ fragment->address = cpu_to_le32(pci_map_address); From 9eb343aeb3e106c1e4c07e2863f45b2c121b3b78 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 21 Oct 2005 19:06:42 +0900 Subject: [PATCH 0981/1939] [PATCH] s2io: kconfig help fix The documentation about s2io is available at Documentation/networking/s2io.txt. Signed-off-by: Akinobu Mita Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5148d47492a0..8fa0e26fa805 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2201,8 +2201,8 @@ config S2IO depends on PCI ---help--- This driver supports the 10Gbe XFrame NIC of S2IO. - For help regarding driver compilation, installation and - tuning please look into ~/drivers/net/s2io/README.txt. + More specific information on configuring the driver is in + . config S2IO_NAPI bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" From adf6e00064ebcd3d82009ba6ef66f489f0885ebd Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 4 Oct 2005 11:25:17 -0600 Subject: [PATCH 0982/1939] [PATCH] b44 reports wrong advertised flags Looks like someone used the MII constants instead of the ethtool constants. Signed-off-by: Matthew Wilcox Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 282ebd15f011..225d14fd9239 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1619,14 +1619,14 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = 0; if (bp->flags & B44_FLAG_ADV_10HALF) - cmd->advertising |= ADVERTISE_10HALF; + cmd->advertising |= ADVERTISED_10baseT_Half; if (bp->flags & B44_FLAG_ADV_10FULL) - cmd->advertising |= ADVERTISE_10FULL; + cmd->advertising |= ADVERTISED_10baseT_Full; if (bp->flags & B44_FLAG_ADV_100HALF) - cmd->advertising |= ADVERTISE_100HALF; + cmd->advertising |= ADVERTISED_100baseT_Half; if (bp->flags & B44_FLAG_ADV_100FULL) - cmd->advertising |= ADVERTISE_100FULL; - cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + cmd->advertising |= ADVERTISED_100baseT_Full; + cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? SPEED_100 : SPEED_10; cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? From 8fee5f51a56aa7a67d955993572a2ae05d31a2c6 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 5 Oct 2005 23:29:58 +0200 Subject: [PATCH 0983/1939] [PATCH] sis190.c: fix multicast MAC filter Here is a patch that changes the way the MAC filter is computed for the multicast addresses. The computation is taken from the SiS GPL driver. This patch is necessary to get IPv6 working. Signed-off-by: Aurelien Jarno Signed-off-by: Jeff Garzik --- drivers/net/sis190.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 92f75529eff8..478791e09bf7 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -842,7 +842,7 @@ static void sis190_set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = - ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; } From 99e1baf869cf20791e66e38facd51d14b28551f8 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 5 Oct 2005 11:10:24 -0400 Subject: [PATCH 0984/1939] [PATCH] smc91x: shut down power after probing If the interface is not used right away after being probed it wastes power needlessly. Noted by Holger Schurig. Signed-off-by: Nicolas Pitre Signed-off-by: Jeff Garzik --- drivers/net/smc91x.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 1438fdd20826..c5bc8ae84dd3 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1983,6 +1983,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (lp->version >= (CHIP_91100 << 4)) smc_phy_detect(dev); + /* then shut everything down to save power */ + smc_shutdown(dev); + smc_phy_powerdown(dev); + /* Set default parameters */ lp->msg_enable = NETIF_MSG_LINK; lp->ctl_rfduplx = 0; From 712cb1ebb1653538527500165d8382ca48a7fca1 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Sun, 23 Oct 2005 13:41:35 -0700 Subject: [PATCH 0985/1939] [PATCH] Fix CS89x0 KConfig for IXDP2X01 IXDP2x01 systems can be built without PCI network cards, so we should not require NET_PCI to build CS89x0 on these systems. Signed-off-by: Deepak Saxena Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8fa0e26fa805..814a93b8c903 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1338,7 +1338,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on (NET_PCI && ISA) || ARCH_PNX0105 || ARCH_IXDP2X01 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the From d8840ac907c7943bc7e196b11812adfa95cb28ef Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 7 Oct 2005 02:05:23 +0400 Subject: [PATCH 0986/1939] [PATCH] starfire: free_irq() on error path of netdev_open() Signed-off-by: Alexey Dobriyan Signed-off-by: Jeff Garzik --- drivers/net/starfire.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index efdb179ecc8c..38b2b0a3ce96 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1091,8 +1091,10 @@ static int netdev_open(struct net_device *dev) rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE; np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size; np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma); - if (np->queue_mem == 0) + if (np->queue_mem == NULL) { + free_irq(dev->irq, dev); return -ENOMEM; + } np->tx_done_q = np->queue_mem; np->tx_done_q_dma = np->queue_mem_dma; From 48257c4f168e5d040394aeca4d37b59f68e0d36b Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Fri, 28 Oct 2005 16:25:58 -0400 Subject: [PATCH 0987/1939] Add fs_enet ethernet network driver, for several embedded platforms. --- drivers/net/Kconfig | 1 + drivers/net/Makefile | 3 + drivers/net/fs_enet/Kconfig | 20 + drivers/net/fs_enet/Makefile | 10 + drivers/net/fs_enet/fs_enet-main.c | 1226 ++++++++++++++++++++++++++++ drivers/net/fs_enet/fs_enet-mii.c | 507 ++++++++++++ drivers/net/fs_enet/fs_enet.h | 245 ++++++ drivers/net/fs_enet/mac-fcc.c | 578 +++++++++++++ drivers/net/fs_enet/mac-fec.c | 653 +++++++++++++++ drivers/net/fs_enet/mac-scc.c | 524 ++++++++++++ drivers/net/fs_enet/mii-bitbang.c | 405 +++++++++ drivers/net/fs_enet/mii-fixed.c | 92 +++ include/linux/fs_enet_pd.h | 136 +++ 13 files changed, 4400 insertions(+) create mode 100644 drivers/net/fs_enet/Kconfig create mode 100644 drivers/net/fs_enet/Makefile create mode 100644 drivers/net/fs_enet/fs_enet-main.c create mode 100644 drivers/net/fs_enet/fs_enet-mii.c create mode 100644 drivers/net/fs_enet/fs_enet.h create mode 100644 drivers/net/fs_enet/mac-fcc.c create mode 100644 drivers/net/fs_enet/mac-fec.c create mode 100644 drivers/net/fs_enet/mac-scc.c create mode 100644 drivers/net/fs_enet/mii-bitbang.c create mode 100644 drivers/net/fs_enet/mii-fixed.c create mode 100644 include/linux/fs_enet_pd.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 814a93b8c903..27732fdeeea4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1775,6 +1775,7 @@ config NE_H8300 controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" +source "drivers/net/fs_enet/Kconfig" endmenu diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1a84e0435f64..7c313cb341b8 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -203,3 +203,6 @@ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_NETCONSOLE) += netconsole.o + +obj-$(CONFIG_FS_ENET) += fs_enet/ + diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 000000000000..6aaee67dd4b7 --- /dev/null +++ b/drivers/net/fs_enet/Kconfig @@ -0,0 +1,20 @@ +config FS_ENET + tristate "Freescale Ethernet Driver" + depends on NET_ETHERNET && (CPM1 || CPM2) + select MII + +config FS_ENET_HAS_SCC + bool "Chip has an SCC usable for ethernet" + depends on FS_ENET && (CPM1 || CPM2) + default y + +config FS_ENET_HAS_FCC + bool "Chip has an FCC usable for ethernet" + depends on FS_ENET && CPM2 + default y + +config FS_ENET_HAS_FEC + bool "Chip has an FEC usable for ethernet" + depends on FS_ENET && CPM1 + default y + diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 000000000000..d6dd3f2fb43e --- /dev/null +++ b/drivers/net/fs_enet/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Freescale Ethernet controllers +# + +obj-$(CONFIG_FS_ENET) += fs_enet.o + +obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o +obj-$(CONFIG_8260) += mac-fcc.o + +fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c new file mode 100644 index 000000000000..44fac7373289 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -0,0 +1,1226 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * Heavily based on original FEC driver by Dan Malek + * and modifications by Joakim Tjernlund + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "fs_enet.h" + +/*************************************************/ + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; + +MODULE_AUTHOR("Pantelis Antoniou "); +MODULE_DESCRIPTION("Freescale Ethernet Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +MODULE_PARM(fs_enet_debug, "i"); +MODULE_PARM_DESC(fs_enet_debug, + "Freescale bitmapped debugging message enable value"); + +int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ + +static void fs_set_multicast_list(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + (*fep->ops->set_multicast_list)(dev); +} + +/* NAPI receive function */ +static int fs_enet_rx_napi(struct net_device *dev, int *budget) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + int rx_work_limit = 0; /* pacify gcc */ + + rx_work_limit = min(dev->quota, *budget); + + if (!netif_running(dev)) + return 0; + + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + /* clear RX status bits for napi*/ + (*fep->ops->napi_clear_rx_event)(dev); + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + /* napi, got packet but no quota */ + if (--rx_work_limit < 0) + break; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_receive_skb(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + dev->quota -= received; + *budget -= received; + + if (rx_work_limit < 0) + return 1; /* not done */ + + /* done */ + netif_rx_complete(dev); + + (*fep->ops->napi_enable_rx)(dev); + + return 0; +} + +/* non NAPI receive function */ +static int fs_enet_rx_non_napi(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_rx(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + return 0; +} + +static void fs_enet_tx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int dirtyidx, do_wake, do_restart; + u16 sc; + + spin_lock(&fep->lock); + bdp = fep->dirty_tx; + + do_wake = do_restart = 0; + while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { + + dirtyidx = bdp - fep->tx_bd_base; + + if (fep->tx_free == fep->tx_ring) + break; + + skb = fep->tx_skbuff[dirtyidx]; + + /* + * Check for errors. + */ + if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | + BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { + + if (sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + + if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + fep->stats.tx_errors++; + do_restart = 1; + } + } else + fep->stats.tx_packets++; + + if (sc & BD_ENET_TX_READY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s HEY! Enet xmit interrupt and TX_READY.\n", + dev->name); + + /* + * Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (sc & BD_ENET_TX_DEF) + fep->stats.collisions++; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(skb); + fep->tx_skbuff[dirtyidx] = NULL; + + /* + * Update pointer to next buffer descriptor to be transmitted. + */ + if ((sc & BD_ENET_TX_WRAP) == 0) + bdp++; + else + bdp = fep->tx_bd_base; + + /* + * Since we have freed up a buffer, the ring is no longer + * full. + */ + if (!fep->tx_free++) + do_wake = 1; + } + + fep->dirty_tx = bdp; + + if (do_restart) + (*fep->ops->tx_restart)(dev); + + spin_unlock(&fep->lock); + + if (do_wake) + netif_wake_queue(dev); +} + +/* + * The interrupt handler. + * This is called from the MPC core interrupt. + */ +static irqreturn_t +fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + u32 int_events; + u32 int_clr_events; + int nr, napi_ok; + int handled; + + fep = netdev_priv(dev); + fpi = fep->fpi; + + nr = 0; + while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { + + nr++; + + int_clr_events = int_events; + if (fpi->use_napi) + int_clr_events &= ~fep->ev_napi_rx; + + (*fep->ops->clear_int_events)(dev, int_clr_events); + + if (int_events & fep->ev_err) + (*fep->ops->ev_error)(dev, int_events); + + if (int_events & fep->ev_rx) { + if (!fpi->use_napi) + fs_enet_rx_non_napi(dev); + else { + napi_ok = netif_rx_schedule_prep(dev); + + (*fep->ops->napi_disable_rx)(dev); + (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); + + /* NOTE: it is possible for FCCs in NAPI mode */ + /* to submit a spurious interrupt while in poll */ + if (napi_ok) + __netif_rx_schedule(dev); + } + } + + if (int_events & fep->ev_tx) + fs_enet_tx(dev); + } + + handled = nr > 0; + return IRQ_RETVAL(handled); +} + +void fs_init_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int i; + + fs_cleanup_bds(dev); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->tx_free = fep->tx_ring; + fep->cur_rx = fep->rx_bd_base; + + /* + * Initialize the receive buffer descriptors. + */ + for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { + skb = dev_alloc_skb(ENET_RX_FRSIZE); + if (skb == NULL) { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, unable to allocate skb\n", + dev->name); + break; + } + fep->rx_skbuff[i] = skb; + skb->dev = dev; + CBDW_BUFADDR(bdp, + dma_map_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); /* zero */ + CBDW_SC(bdp, BD_ENET_RX_EMPTY | + ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); + } + /* + * if we failed, fillup remainder + */ + for (; i < fep->rx_ring; i++, bdp++) { + fep->rx_skbuff[i] = NULL; + CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); + } + + /* + * ...and the same for transmit. + */ + for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { + fep->tx_skbuff[i] = NULL; + CBDW_BUFADDR(bdp, 0); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); + } +} + +void fs_cleanup_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct sk_buff *skb; + int i; + + /* + * Reset SKB transmit buffers. + */ + for (i = 0; i < fep->tx_ring; i++) { + if ((skb = fep->tx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + fep->tx_skbuff[i] = NULL; + dev_kfree_skb(skb); + } + + /* + * Reset SKB receive buffers + */ + for (i = 0; i < fep->rx_ring; i++) { + if ((skb = fep->rx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + fep->rx_skbuff[i] = NULL; + + dev_kfree_skb(skb); + } +} + +/**********************************************************************************/ + +static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + int curidx; + u16 sc; + unsigned long flags; + + spin_lock_irqsave(&fep->tx_lock, flags); + + /* + * Fill in a Tx ring entry + */ + bdp = fep->cur_tx; + + if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&fep->tx_lock, flags); + + /* + * Ooops. All transmit buffers are full. Bail out. + * This should not happen, since the tx queue should be stopped. + */ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s tx queue full!.\n", dev->name); + return NETDEV_TX_BUSY; + } + + curidx = bdp - fep->tx_bd_base; + /* + * Clear all of the status flags. + */ + CBDC_SC(bdp, BD_ENET_TX_STATS); + + /* + * Save skb pointer. + */ + fep->tx_skbuff[curidx] = skb; + + fep->stats.tx_bytes += skb->len; + + /* + * Push the data cache so the CPM does not get stale memory data. + */ + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, + skb->data, skb->len, DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, skb->len); + + dev->trans_start = jiffies; + + /* + * If this was the last BD in the ring, start at the beginning again. + */ + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + fep->cur_tx++; + else + fep->cur_tx = fep->tx_bd_base; + + if (!--fep->tx_free) + netif_stop_queue(dev); + + /* Trigger transmission start */ + sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | + BD_ENET_TX_LAST | BD_ENET_TX_TC; + + /* note that while FEC does not have this bit + * it marks it as available for software use + * yay for hw reuse :) */ + if (skb->len <= 60) + sc |= BD_ENET_TX_PAD; + CBDS_SC(bdp, sc); + + (*fep->ops->tx_kickstart)(dev); + + spin_unlock_irqrestore(&fep->tx_lock, flags); + + return NETDEV_TX_OK; +} + +static int fs_request_irq(struct net_device *dev, int irq, const char *name, + irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + (*fep->ops->pre_request_irq)(dev, irq); + return request_irq(irq, irqf, SA_SHIRQ, name, dev); +} + +static void fs_free_irq(struct net_device *dev, int irq) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + free_irq(irq, dev); + (*fep->ops->post_free_irq)(dev, irq); +} + +/**********************************************************************************/ + +/* This interrupt occurs when the PHY detects a link change. */ +static irqreturn_t +fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + + fep = netdev_priv(dev); + fpi = fep->fpi; + + /* + * Acknowledge the interrupt if possible. If we have not + * found the PHY yet we can't process or acknowledge the + * interrupt now. Instead we ignore this interrupt for now, + * which we can do since it is edge triggered. It will be + * acknowledged later by fs_enet_open(). + */ + if (!fep->phy) + return IRQ_NONE; + + fs_mii_ack_int(dev); + fs_mii_link_status_change_check(dev, 0); + + return IRQ_HANDLED; +} + +static void fs_timeout(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int wake = 0; + + fep->stats.tx_errors++; + + spin_lock_irqsave(&fep->lock, flags); + + if (dev->flags & IFF_UP) { + (*fep->ops->stop)(dev); + (*fep->ops->restart)(dev); + } + + wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); + spin_unlock_irqrestore(&fep->lock, flags); + + if (wake) + netif_wake_queue(dev); +} + +static int fs_enet_open(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + int r; + + /* Install our interrupt handler. */ + r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s Could not allocate FEC IRQ!", dev->name); + return -EINVAL; + } + + /* Install our phy interrupt handler */ + if (fpi->phy_irq != -1) { + + r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s Could not allocate PHY IRQ!", dev->name); + fs_free_irq(dev, fep->interrupt); + return -EINVAL; + } + } + + fs_mii_startup(dev); + netif_carrier_off(dev); + fs_mii_link_status_change_check(dev, 1); + + return 0; +} + +static int fs_enet_close(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + unsigned long flags; + + netif_stop_queue(dev); + netif_carrier_off(dev); + fs_mii_shutdown(dev); + + spin_lock_irqsave(&fep->lock, flags); + (*fep->ops->stop)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + + /* release any irqs */ + if (fpi->phy_irq != -1) + fs_free_irq(dev, fpi->phy_irq); + fs_free_irq(dev, fep->interrupt); + + return 0; +} + +static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return &fep->stats; +} + +/*************************************************************************/ + +static void fs_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); +} + +static int fs_get_regs_len(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + return (*fep->ops->get_regs_len)(dev); +} + +static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int r, len; + + len = regs->len; + + spin_lock_irqsave(&fep->lock, flags); + r = (*fep->ops->get_regs)(dev, p, &len); + spin_unlock_irqrestore(&fep->lock, flags); + + if (r == 0) + regs->version = 0; +} + +static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&fep->lock, flags); + rc = mii_ethtool_gset(&fep->mii_if, cmd); + spin_unlock_irqrestore(&fep->lock, flags); + + return rc; +} + +static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&fep->lock, flags); + rc = mii_ethtool_sset(&fep->mii_if, cmd); + spin_unlock_irqrestore(&fep->lock, flags); + + return rc; +} + +static int fs_nway_reset(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return mii_nway_restart(&fep->mii_if); +} + +static u32 fs_get_msglevel(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return fep->msg_enable; +} + +static void fs_set_msglevel(struct net_device *dev, u32 value) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fep->msg_enable = value; +} + +static struct ethtool_ops fs_ethtool_ops = { + .get_drvinfo = fs_get_drvinfo, + .get_regs_len = fs_get_regs_len, + .get_settings = fs_get_settings, + .set_settings = fs_set_settings, + .nway_reset = fs_nway_reset, + .get_link = ethtool_op_get_link, + .get_msglevel = fs_get_msglevel, + .set_msglevel = fs_set_msglevel, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_regs = fs_get_regs, +}; + +static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; + unsigned long flags; + int rc; + + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irqsave(&fep->lock, flags); + rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); + spin_unlock_irqrestore(&fep->lock, flags); + return rc; +} + +extern int fs_mii_connect(struct net_device *dev); +extern void fs_mii_disconnect(struct net_device *dev); + +static struct net_device *fs_init_instance(struct device *dev, + const struct fs_platform_info *fpi) +{ + struct net_device *ndev = NULL; + struct fs_enet_private *fep = NULL; + int privsize, i, r, err = 0, registered = 0; + + /* guard */ + if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) + return ERR_PTR(-EINVAL); + + privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * + (fpi->rx_ring + fpi->tx_ring)); + + ndev = alloc_etherdev(privsize); + if (!ndev) { + err = -ENOMEM; + goto err; + } + SET_MODULE_OWNER(ndev); + + fep = netdev_priv(ndev); + memset(fep, 0, privsize); /* clear everything */ + + fep->dev = dev; + dev_set_drvdata(dev, ndev); + fep->fpi = fpi; + if (fpi->init_ioports) + fpi->init_ioports(); + +#ifdef CONFIG_FS_ENET_HAS_FEC + if (fs_get_fec_index(fpi->fs_no) >= 0) + fep->ops = &fs_fec_ops; +#endif + +#ifdef CONFIG_FS_ENET_HAS_SCC + if (fs_get_scc_index(fpi->fs_no) >=0 ) + fep->ops = &fs_scc_ops; +#endif + +#ifdef CONFIG_FS_ENET_HAS_FCC + if (fs_get_fcc_index(fpi->fs_no) >= 0) + fep->ops = &fs_fcc_ops; +#endif + + if (fep->ops == NULL) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s No matching ops found (%d).\n", + ndev->name, fpi->fs_no); + err = -EINVAL; + goto err; + } + + r = (*fep->ops->setup_data)(ndev); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s setup_data failed\n", + ndev->name); + err = r; + goto err; + } + + /* point rx_skbuff, tx_skbuff */ + fep->rx_skbuff = (struct sk_buff **)&fep[1]; + fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + + /* init locks */ + spin_lock_init(&fep->lock); + spin_lock_init(&fep->tx_lock); + + /* + * Set the Ethernet address. + */ + for (i = 0; i < 6; i++) + ndev->dev_addr[i] = fpi->macaddr[i]; + + r = (*fep->ops->allocate_bd)(ndev); + + if (fep->ring_base == NULL) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); + err = r; + goto err; + } + + /* + * Set receive and transmit descriptor base. + */ + fep->rx_bd_base = fep->ring_base; + fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; + + /* initialize ring size variables */ + fep->tx_ring = fpi->tx_ring; + fep->rx_ring = fpi->rx_ring; + + /* + * The FEC Ethernet specific entries in the device structure. + */ + ndev->open = fs_enet_open; + ndev->hard_start_xmit = fs_enet_start_xmit; + ndev->tx_timeout = fs_timeout; + ndev->watchdog_timeo = 2 * HZ; + ndev->stop = fs_enet_close; + ndev->get_stats = fs_enet_get_stats; + ndev->set_multicast_list = fs_set_multicast_list; + if (fpi->use_napi) { + ndev->poll = fs_enet_rx_napi; + ndev->weight = fpi->napi_weight; + } + ndev->ethtool_ops = &fs_ethtool_ops; + ndev->do_ioctl = fs_ioctl; + + init_timer(&fep->phy_timer_list); + + netif_carrier_off(ndev); + + err = register_netdev(ndev); + if (err != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s register_netdev failed.\n", ndev->name); + goto err; + } + registered = 1; + + err = fs_mii_connect(ndev); + if (err != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s fs_mii_connect failed.\n", ndev->name); + goto err; + } + + return ndev; + + err: + if (ndev != NULL) { + + if (registered) + unregister_netdev(ndev); + + if (fep != NULL) { + (*fep->ops->free_bd)(ndev); + (*fep->ops->cleanup_data)(ndev); + } + + free_netdev(ndev); + } + + dev_set_drvdata(dev, NULL); + + return ERR_PTR(err); +} + +static int fs_cleanup_instance(struct net_device *ndev) +{ + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + struct device *dev; + + if (ndev == NULL) + return -EINVAL; + + fep = netdev_priv(ndev); + if (fep == NULL) + return -EINVAL; + + fpi = fep->fpi; + + fs_mii_disconnect(ndev); + + unregister_netdev(ndev); + + dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), + fep->ring_base, fep->ring_mem_addr); + + /* reset it */ + (*fep->ops->cleanup_data)(ndev); + + dev = fep->dev; + if (dev != NULL) { + dev_set_drvdata(dev, NULL); + fep->dev = NULL; + } + + free_netdev(ndev); + + return 0; +} + +/**************************************************************************************/ + +/* handy pointer to the immap */ +void *fs_enet_immap = NULL; + +static int setup_immap(void) +{ + phys_addr_t paddr = 0; + unsigned long size = 0; + +#ifdef CONFIG_CPM1 + paddr = IMAP_ADDR; + size = 0x10000; /* map 64K */ +#endif + +#ifdef CONFIG_CPM2 + paddr = CPM_MAP_ADDR; + size = 0x40000; /* map 256 K */ +#endif + fs_enet_immap = ioremap(paddr, size); + if (fs_enet_immap == NULL) + return -EBADF; /* XXX ahem; maybe just BUG_ON? */ + + return 0; +} + +static void cleanup_immap(void) +{ + if (fs_enet_immap != NULL) { + iounmap(fs_enet_immap); + fs_enet_immap = NULL; + } +} + +/**************************************************************************************/ + +static int __devinit fs_enet_probe(struct device *dev) +{ + struct net_device *ndev; + + /* no fixup - no device */ + if (dev->platform_data == NULL) { + printk(KERN_INFO "fs_enet: " + "probe called with no platform data; " + "remove unused devices\n"); + return -ENODEV; + } + + ndev = fs_init_instance(dev, dev->platform_data); + if (IS_ERR(ndev)) + return PTR_ERR(ndev); + return 0; +} + +static int fs_enet_remove(struct device *dev) +{ + return fs_cleanup_instance(dev_get_drvdata(dev)); +} + +static struct device_driver fs_enet_fec_driver = { + .name = "fsl-cpm-fec", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static struct device_driver fs_enet_scc_driver = { + .name = "fsl-cpm-scc", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static struct device_driver fs_enet_fcc_driver = { + .name = "fsl-cpm-fcc", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static int __init fs_init(void) +{ + int r; + + printk(KERN_INFO + "%s", version); + + r = setup_immap(); + if (r != 0) + return r; + r = driver_register(&fs_enet_fec_driver); + if (r != 0) + goto err; + + r = driver_register(&fs_enet_fcc_driver); + if (r != 0) + goto err; + + r = driver_register(&fs_enet_scc_driver); + if (r != 0) + goto err; + + return 0; +err: + cleanup_immap(); + return r; + +} + +static void __exit fs_cleanup(void) +{ + driver_unregister(&fs_enet_fec_driver); + driver_unregister(&fs_enet_fcc_driver); + driver_unregister(&fs_enet_scc_driver); + cleanup_immap(); +} + +/**************************************************************************************/ + +module_init(fs_init); +module_exit(fs_cleanup); diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c new file mode 100644 index 000000000000..c6770377ef87 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-mii.c @@ -0,0 +1,507 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * Heavily based on original FEC driver by Dan Malek + * and modifications by Joakim Tjernlund + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fs_enet.h" + +/*************************************************/ + +/* + * Generic PHY support. + * Should work for all PHYs, but link change is detected by polling + */ + +static void generic_timer_callback(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct fs_enet_private *fep = netdev_priv(dev); + + fep->phy_timer_list.expires = jiffies + HZ / 2; + + add_timer(&fep->phy_timer_list); + + fs_mii_link_status_change_check(dev, 0); +} + +static void generic_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ + fep->phy_timer_list.data = (unsigned long)dev; + fep->phy_timer_list.function = generic_timer_callback; + add_timer(&fep->phy_timer_list); +} + +static void generic_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + del_timer_sync(&fep->phy_timer_list); +} + +/* ------------------------------------------------------------------------- */ +/* The Davicom DM9161 is used on the NETTA board */ + +/* register definitions */ + +#define MII_DM9161_ANAR 4 /* Aux. Config Register */ +#define MII_DM9161_ACR 16 /* Aux. Config Register */ +#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ +#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ +#define MII_DM9161_INTR 21 /* Interrupt Register */ +#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ +#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ + +static void dm9161_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); + /* Start autonegotiation */ + fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ*8); +} + +static void dm9161_ack_int(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); +} + +static void dm9161_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); +} + +/**********************************************************************************/ + +static const struct phy_info phy_info[] = { + { + .id = 0x00181b88, + .name = "DM9161", + .startup = dm9161_startup, + .ack_int = dm9161_ack_int, + .shutdown = dm9161_shutdown, + }, { + .id = 0, + .name = "GENERIC", + .startup = generic_startup, + .shutdown = generic_shutdown, + }, +}; + +/**********************************************************************************/ + +static int phy_id_detect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + struct fs_enet_mii_bus *bus = fep->mii_bus; + int i, r, start, end, phytype, physubtype; + const struct phy_info *phy; + int phy_hwid, phy_id; + + phy_hwid = -1; + fep->phy = NULL; + + /* auto-detect? */ + if (fpi->phy_addr == -1) { + start = 1; + end = 32; + } else { /* direct */ + start = fpi->phy_addr; + end = start + 1; + } + + for (phy_id = start; phy_id < end; phy_id++) { + /* skip already used phy addresses on this bus */ + if (bus->usage_map & (1 << phy_id)) + continue; + r = fs_mii_read(dev, phy_id, MII_PHYSID1); + if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) + continue; + r = fs_mii_read(dev, phy_id, MII_PHYSID2); + if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) + continue; + phy_hwid = (phytype << 16) | physubtype; + if (phy_hwid != -1) + break; + } + + if (phy_hwid == -1) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s No PHY detected! range=0x%02x-0x%02x\n", + dev->name, start, end); + return -1; + } + + for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) + if (phy->id == (phy_hwid >> 4) || phy->id == 0) + break; + + if (i >= ARRAY_SIZE(phy_info)) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s PHY id 0x%08x is not supported!\n", + dev->name, phy_hwid); + return -1; + } + + fep->phy = phy; + + /* mark this address as used */ + bus->usage_map |= (1 << phy_id); + + printk(KERN_INFO DRV_MODULE_NAME + ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", + dev->name, phy_id, fep->phy->name, phy_hwid, + fpi->phy_addr == -1 ? " (auto-detected)" : ""); + + return phy_id; +} + +void fs_mii_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->startup) + (*fep->phy->startup) (dev); +} + +void fs_mii_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->shutdown) + (*fep->phy->shutdown) (dev); +} + +void fs_mii_ack_int(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->ack_int) + (*fep->phy->ack_int) (dev); +} + +#define MII_LINK 0x0001 +#define MII_HALF 0x0002 +#define MII_FULL 0x0004 +#define MII_BASE4 0x0008 +#define MII_10M 0x0010 +#define MII_100M 0x0020 +#define MII_1G 0x0040 +#define MII_10G 0x0080 + +/* return full mii info at one gulp, with a usable form */ +static unsigned int mii_full_status(struct mii_if_info *mii) +{ + unsigned int status; + int bmsr, adv, lpa, neg; + struct fs_enet_private* fep = netdev_priv(mii->dev); + + /* first, a dummy read, needed to latch some MII phys */ + (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + + /* no link */ + if ((bmsr & BMSR_LSTATUS) == 0) + return 0; + + status = MII_LINK; + + /* Lets look what ANEG says if it's supported - otherwize we shall + take the right values from the platform info*/ + if(!mii->force_media) { + /* autoneg not completed; don't bother */ + if ((bmsr & BMSR_ANEGCOMPLETE) == 0) + return 0; + + adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); + lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); + + neg = lpa & adv; + } else { + neg = fep->fpi->bus_info->lpa; + } + + if (neg & LPA_100FULL) + status |= MII_FULL | MII_100M; + else if (neg & LPA_100BASE4) + status |= MII_FULL | MII_BASE4 | MII_100M; + else if (neg & LPA_100HALF) + status |= MII_HALF | MII_100M; + else if (neg & LPA_10FULL) + status |= MII_FULL | MII_10M; + else + status |= MII_HALF | MII_10M; + + return status; +} + +void fs_mii_link_status_change_check(struct net_device *dev, int init_media) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct mii_if_info *mii = &fep->mii_if; + unsigned int mii_status; + int ok_to_print, link, duplex, speed; + unsigned long flags; + + ok_to_print = netif_msg_link(fep); + + mii_status = mii_full_status(mii); + + if (!init_media && mii_status == fep->last_mii_status) + return; + + fep->last_mii_status = mii_status; + + link = !!(mii_status & MII_LINK); + duplex = !!(mii_status & MII_FULL); + speed = (mii_status & MII_100M) ? 100 : 10; + + if (link == 0) { + netif_carrier_off(mii->dev); + netif_stop_queue(dev); + if (!init_media) { + spin_lock_irqsave(&fep->lock, flags); + (*fep->ops->stop)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + } + + if (ok_to_print) + printk(KERN_INFO "%s: link down\n", mii->dev->name); + + } else { + + mii->full_duplex = duplex; + + netif_carrier_on(mii->dev); + + spin_lock_irqsave(&fep->lock, flags); + fep->duplex = duplex; + fep->speed = speed; + (*fep->ops->restart)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + + netif_start_queue(dev); + + if (ok_to_print) + printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", + dev->name, speed, duplex ? "full" : "half"); + } +} + +/**********************************************************************************/ + +int fs_mii_read(struct net_device *dev, int phy_id, int location) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = fep->mii_bus; + + unsigned long flags; + int ret; + + spin_lock_irqsave(&bus->mii_lock, flags); + ret = (*bus->mii_read)(bus, phy_id, location); + spin_unlock_irqrestore(&bus->mii_lock, flags); + + return ret; +} + +void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = fep->mii_bus; + unsigned long flags; + + spin_lock_irqsave(&bus->mii_lock, flags); + (*bus->mii_write)(bus, phy_id, location, value); + spin_unlock_irqrestore(&bus->mii_lock, flags); +} + +/*****************************************************************************/ + +/* list of all registered mii buses */ +static LIST_HEAD(fs_mii_bus_list); + +static struct fs_enet_mii_bus *lookup_bus(int method, int id) +{ + struct list_head *ptr; + struct fs_enet_mii_bus *bus; + + list_for_each(ptr, &fs_mii_bus_list) { + bus = list_entry(ptr, struct fs_enet_mii_bus, list); + if (bus->bus_info->method == method && + bus->bus_info->id == id) + return bus; + } + return NULL; +} + +static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) +{ + struct fs_enet_mii_bus *bus; + int ret = 0; + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (bus == NULL) { + ret = -ENOMEM; + goto err; + } + memset(bus, 0, sizeof(*bus)); + spin_lock_init(&bus->mii_lock); + bus->bus_info = bi; + bus->refs = 0; + bus->usage_map = 0; + + /* perform initialization */ + switch (bi->method) { + + case fsmii_fixed: + ret = fs_mii_fixed_init(bus); + if (ret != 0) + goto err; + break; + + case fsmii_bitbang: + ret = fs_mii_bitbang_init(bus); + if (ret != 0) + goto err; + break; +#ifdef CONFIG_FS_ENET_HAS_FEC + case fsmii_fec: + ret = fs_mii_fec_init(bus); + if (ret != 0) + goto err; + break; +#endif + default: + ret = -EINVAL; + goto err; + } + + list_add(&bus->list, &fs_mii_bus_list); + + return bus; + +err: + if (bus) + kfree(bus); + return ERR_PTR(ret); +} + +static void destroy_bus(struct fs_enet_mii_bus *bus) +{ + /* remove from bus list */ + list_del(&bus->list); + + /* nothing more needed */ + kfree(bus); +} + +int fs_mii_connect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + struct fs_enet_mii_bus *bus = NULL; + + /* check method validity */ + switch (fpi->bus_info->method) { + case fsmii_fixed: + case fsmii_bitbang: + break; +#ifdef CONFIG_FS_ENET_HAS_FEC + case fsmii_fec: + break; +#endif + default: + printk(KERN_ERR DRV_MODULE_NAME + ": %s Unknown MII bus method (%d)!\n", + dev->name, fpi->bus_info->method); + return -EINVAL; + } + + bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); + + /* if not found create new bus */ + if (bus == NULL) { + bus = create_bus(fpi->bus_info); + if (IS_ERR(bus)) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s MII bus creation failure!\n", dev->name); + return PTR_ERR(bus); + } + } + + bus->refs++; + + fep->mii_bus = bus; + + fep->mii_if.dev = dev; + fep->mii_if.phy_id_mask = 0x1f; + fep->mii_if.reg_num_mask = 0x1f; + fep->mii_if.mdio_read = fs_mii_read; + fep->mii_if.mdio_write = fs_mii_write; + fep->mii_if.force_media = fpi->bus_info->disable_aneg; + fep->mii_if.phy_id = phy_id_detect(dev); + + return 0; +} + +void fs_mii_disconnect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = NULL; + + bus = fep->mii_bus; + fep->mii_bus = NULL; + + if (--bus->refs <= 0) + destroy_bus(bus); +} diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h new file mode 100644 index 000000000000..1105543b9d88 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet.h @@ -0,0 +1,245 @@ +#ifndef FS_ENET_H +#define FS_ENET_H + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef CONFIG_CPM1 +#include +#endif + +#ifdef CONFIG_CPM2 +#include +#endif + +/* hw driver ops */ +struct fs_ops { + int (*setup_data)(struct net_device *dev); + int (*allocate_bd)(struct net_device *dev); + void (*free_bd)(struct net_device *dev); + void (*cleanup_data)(struct net_device *dev); + void (*set_multicast_list)(struct net_device *dev); + void (*restart)(struct net_device *dev); + void (*stop)(struct net_device *dev); + void (*pre_request_irq)(struct net_device *dev, int irq); + void (*post_free_irq)(struct net_device *dev, int irq); + void (*napi_clear_rx_event)(struct net_device *dev); + void (*napi_enable_rx)(struct net_device *dev); + void (*napi_disable_rx)(struct net_device *dev); + void (*rx_bd_done)(struct net_device *dev); + void (*tx_kickstart)(struct net_device *dev); + u32 (*get_int_events)(struct net_device *dev); + void (*clear_int_events)(struct net_device *dev, u32 int_events); + void (*ev_error)(struct net_device *dev, u32 int_events); + int (*get_regs)(struct net_device *dev, void *p, int *sizep); + int (*get_regs_len)(struct net_device *dev); + void (*tx_restart)(struct net_device *dev); +}; + +struct phy_info { + unsigned int id; + const char *name; + void (*startup) (struct net_device * dev); + void (*shutdown) (struct net_device * dev); + void (*ack_int) (struct net_device * dev); +}; + +/* The FEC stores dest/src/type, data, and checksum for receive packets. + */ +#define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ +#define MIN_MTU 46 /* this is data size */ +#define CRC_LEN 4 + +#define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) +#define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) + +/* Must be a multiple of 32 (to cover both FEC & FCC) */ +#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) +/* This is needed so that invalidate_xxx wont invalidate too much */ +#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) + +struct fs_enet_mii_bus { + struct list_head list; + spinlock_t mii_lock; + const struct fs_mii_bus_info *bus_info; + int refs; + u32 usage_map; + + int (*mii_read)(struct fs_enet_mii_bus *bus, + int phy_id, int location); + + void (*mii_write)(struct fs_enet_mii_bus *bus, + int phy_id, int location, int value); + + union { + struct { + unsigned int mii_speed; + void *fecp; + } fec; + + struct { + /* note that the actual port size may */ + /* be different; cpm(s) handle it OK */ + u8 mdio_msk; + u8 *mdio_dir; + u8 *mdio_dat; + u8 mdc_msk; + u8 *mdc_dir; + u8 *mdc_dat; + } bitbang; + + struct { + u16 lpa; + } fixed; + }; +}; + +int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); +int fs_mii_fec_init(struct fs_enet_mii_bus *bus); + +struct fs_enet_private { + struct device *dev; /* pointer back to the device (must be initialized first) */ + spinlock_t lock; /* during all ops except TX pckt processing */ + spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ + const struct fs_platform_info *fpi; + const struct fs_ops *ops; + int rx_ring, tx_ring; + dma_addr_t ring_mem_addr; + void *ring_base; + struct sk_buff **rx_skbuff; + struct sk_buff **tx_skbuff; + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *dirty_tx; /* ring entries to be free()ed. */ + cbd_t *cur_rx; + cbd_t *cur_tx; + int tx_free; + struct net_device_stats stats; + struct timer_list phy_timer_list; + const struct phy_info *phy; + u32 msg_enable; + struct mii_if_info mii_if; + unsigned int last_mii_status; + struct fs_enet_mii_bus *mii_bus; + int interrupt; + + int duplex, speed; /* current settings */ + + /* event masks */ + u32 ev_napi_rx; /* mask of NAPI rx events */ + u32 ev_rx; /* rx event mask */ + u32 ev_tx; /* tx event mask */ + u32 ev_err; /* error event mask */ + + u16 bd_rx_empty; /* mask of BD rx empty */ + u16 bd_rx_err; /* mask of BD rx errors */ + + union { + struct { + int idx; /* FEC1 = 0, FEC2 = 1 */ + void *fecp; /* hw registers */ + u32 hthi, htlo; /* state for multicast */ + } fec; + + struct { + int idx; /* FCC1-3 = 0-2 */ + void *fccp; /* hw registers */ + void *ep; /* parameter ram */ + void *fcccp; /* hw registers cont. */ + void *mem; /* FCC DPRAM */ + u32 gaddrh, gaddrl; /* group address */ + } fcc; + + struct { + int idx; /* FEC1 = 0, FEC2 = 1 */ + void *sccp; /* hw registers */ + void *ep; /* parameter ram */ + u32 hthi, htlo; /* state for multicast */ + } scc; + + }; +}; + +/***************************************************************************/ + +int fs_mii_read(struct net_device *dev, int phy_id, int location); +void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); + +void fs_mii_startup(struct net_device *dev); +void fs_mii_shutdown(struct net_device *dev); +void fs_mii_ack_int(struct net_device *dev); + +void fs_mii_link_status_change_check(struct net_device *dev, int init_media); + +void fs_init_bds(struct net_device *dev); +void fs_cleanup_bds(struct net_device *dev); + +/***************************************************************************/ + +#define DRV_MODULE_NAME "fs_enet" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "1.0" +#define DRV_MODULE_RELDATE "Aug 8, 2005" + +/***************************************************************************/ + +int fs_enet_platform_init(void); +void fs_enet_platform_cleanup(void); + +/***************************************************************************/ + +/* buffer descriptor access macros */ + +/* access macros */ +#if defined(CONFIG_CPM1) +/* for a a CPM1 __raw_xxx's are sufficient */ +#define __cbd_out32(addr, x) __raw_writel(x, addr) +#define __cbd_out16(addr, x) __raw_writew(x, addr) +#define __cbd_in32(addr) __raw_readl(addr) +#define __cbd_in16(addr) __raw_readw(addr) +#else +/* for others play it safe */ +#define __cbd_out32(addr, x) out_be32(addr, x) +#define __cbd_out16(addr, x) out_be16(addr, x) +#define __cbd_in32(addr) in_be32(addr) +#define __cbd_in16(addr) in_be16(addr) +#endif + +/* write */ +#define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) +#define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) +#define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) + +/* read */ +#define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) +#define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) +#define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) + +/* set bits */ +#define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) + +/* clear bits */ +#define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) + +/*******************************************************************/ + +extern const struct fs_ops fs_fec_ops; +extern const struct fs_ops fs_fcc_ops; +extern const struct fs_ops fs_scc_ops; + +/*******************************************************************/ + +/* handy pointer to the immap */ +extern void *fs_enet_immap; + +/*******************************************************************/ + +#endif diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 000000000000..a940b96433c7 --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c @@ -0,0 +1,578 @@ +/* + * FCC driver for Motorola MPC82xx (PQ2). + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#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 "fs_enet.h" + +/*************************************************/ + +/* FCC access macros */ + +#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) +#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) +#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) +#define __fcc_in32(addr) in_be32((unsigned *)addr) +#define __fcc_in16(addr) in_be16((unsigned short *)addr) +#define __fcc_in8(addr) in_8((unsigned char *)addr) + +/* parameter space */ + +/* write, read, set bits, clear bits */ +#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) +#define R32(_p, _m) __fcc_in32(&(_p)->_m) +#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) +#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) + +#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) +#define R16(_p, _m) __fcc_in16(&(_p)->_m) +#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) +#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) + +#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) +#define R8(_p, _m) __fcc_in8(&(_p)->_m) +#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) +#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) + +/*************************************************/ + +#define FCC_MAX_MULTICAST_ADDRS 64 + +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) +#define mk_mii_end 0 + +#define MAX_CR_CMD_LOOPS 10000 + +static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) +{ + const struct fs_platform_info *fpi = fep->fpi; + + cpm2_map_t *immap = fs_enet_immap; + cpm_cpm2_t *cpmp = &immap->im_cpm; + u32 v; + int i; + + /* Currently I don't know what feature call will look like. But + I guess there'd be something like do_cpm_cmd() which will require page & sblock */ + v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); + W32(cpmp, cp_cpcr, v | CPM_CR_FLG); + for (i = 0; i < MAX_CR_CMD_LOOPS; i++) + if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) + break; + + if (i >= MAX_CR_CMD_LOOPS) { + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; + } + + return 0; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq(pdev, 0); + + /* Attach the memory for the FCC Parameter RAM */ + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); + fep->fcc.ep = (void *)r->start; + + if (fep->fcc.ep == NULL) + return -EINVAL; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); + fep->fcc.fccp = (void *)r->start; + + if (fep->fcc.fccp == NULL) + return -EINVAL; + + fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + + if (fep->fcc.fcccp == NULL) + return -EINVAL; + + return 0; +} + +#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) +#define FCC_RX_EVENT (FCC_ENET_RXF) +#define FCC_TX_EVENT (FCC_ENET_TXB) +#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); + if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ + return -EINVAL; + + fep->fcc.mem = (void *)fpi->mem_offset; + + if (do_pd_setup(fep) != 0) + return -EINVAL; + + fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; + fep->ev_rx = FCC_RX_EVENT; + fep->ev_tx = FCC_TX_EVENT; + fep->ev_err = FCC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_base = dma_alloc_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), &fep->ring_mem_addr, + GFP_KERNEL); + if (fep->ring_base == NULL) + return -ENOMEM; + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + if (fep->ring_base) + dma_free_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), + fep->ring_base, fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_enet_t *ep = fep->fcc.ep; + + W32(ep, fen_gaddrh, 0); + W32(ep, fen_gaddrl, 0); +} + +static void set_multicast_one(struct net_device *dev, const u8 *mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_enet_t *ep = fep->fcc.ep; + u16 taddrh, taddrm, taddrl; + + taddrh = ((u16)mac[5] << 8) | mac[4]; + taddrm = ((u16)mac[3] << 8) | mac[2]; + taddrl = ((u16)mac[1] << 8) | mac[0]; + + W16(ep, fen_taddrh, taddrh); + W16(ep, fen_taddrm, taddrm); + W16(ep, fen_taddrl, taddrl); + fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + fcc_enet_t *ep = fep->fcc.ep; + + /* clear promiscuous always */ + C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { + + W32(ep, fen_gaddrh, 0xffffffff); + W32(ep, fen_gaddrl, 0xffffffff); + } + + /* read back */ + fep->fcc.gaddrh = R32(ep, fen_gaddrh); + fep->fcc.gaddrl = R32(ep, fen_gaddrl); +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +static void restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + fcc_t *fccp = fep->fcc.fccp; + fcc_c_t *fcccp = fep->fcc.fcccp; + fcc_enet_t *ep = fep->fcc.ep; + dma_addr_t rx_bd_base_phys, tx_bd_base_phys; + u16 paddrh, paddrm, paddrl; + u16 mem_addr; + const unsigned char *mac; + int i; + + C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); + + /* clear everything (slow & steady does it) */ + for (i = 0; i < sizeof(*ep); i++) + __fcc_out8((char *)ep + i, 0); + + /* get physical address */ + rx_bd_base_phys = fep->ring_mem_addr; + tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; + + /* point to bds */ + W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); + W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); + + W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); + W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + + mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ + + W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); + W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); + W16(ep, fen_padptr, mem_addr + 64); + + /* fill with special symbol... */ + memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); + + W32(ep, fen_genfcc.fcc_rbptr, 0); + W32(ep, fen_genfcc.fcc_tbptr, 0); + W32(ep, fen_genfcc.fcc_rcrc, 0); + W32(ep, fen_genfcc.fcc_tcrc, 0); + W16(ep, fen_genfcc.fcc_res1, 0); + W32(ep, fen_genfcc.fcc_res2, 0); + + /* no CAM */ + W32(ep, fen_camptr, 0); + + /* Set CRC preset and mask */ + W32(ep, fen_cmask, 0xdebb20e3); + W32(ep, fen_cpres, 0xffffffff); + + W32(ep, fen_crcec, 0); /* CRC Error counter */ + W32(ep, fen_alec, 0); /* alignment error counter */ + W32(ep, fen_disfc, 0); /* discard frame counter */ + W16(ep, fen_retlim, 15); /* Retry limit threshold */ + W16(ep, fen_pper, 0); /* Normal persistence */ + + /* set group address */ + W32(ep, fen_gaddrh, fep->fcc.gaddrh); + W32(ep, fen_gaddrl, fep->fcc.gaddrh); + + /* Clear hash filter tables */ + W32(ep, fen_iaddrh, 0); + W32(ep, fen_iaddrl, 0); + + /* Clear the Out-of-sequence TxBD */ + W16(ep, fen_tfcstat, 0); + W16(ep, fen_tfclen, 0); + W32(ep, fen_tfcptr, 0); + + W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ + W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ + + /* set address */ + mac = dev->dev_addr; + paddrh = ((u16)mac[5] << 8) | mac[4]; + paddrm = ((u16)mac[3] << 8) | mac[2]; + paddrl = ((u16)mac[1] << 8) | mac[0]; + + W16(ep, fen_paddrh, paddrh); + W16(ep, fen_paddrm, paddrm); + W16(ep, fen_paddrl, paddrl); + + W16(ep, fen_taddrh, 0); + W16(ep, fen_taddrm, 0); + W16(ep, fen_taddrl, 0); + + W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ + W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON */ + W32(ep, fen_octc, 0); + W32(ep, fen_colc, 0); + W32(ep, fen_broc, 0); + W32(ep, fen_mulc, 0); + W32(ep, fen_uspc, 0); + W32(ep, fen_frgc, 0); + W32(ep, fen_ospc, 0); + W32(ep, fen_jbrc, 0); + W32(ep, fen_p64c, 0); + W32(ep, fen_p65c, 0); + W32(ep, fen_p128c, 0); + W32(ep, fen_p256c, 0); + W32(ep, fen_p512c, 0); + W32(ep, fen_p1024c, 0); + + W16(ep, fen_rfthr, 0); /* Suggested by manual */ + W16(ep, fen_rfcnt, 0); + W16(ep, fen_cftype, 0); + + fs_init_bds(dev); + + /* adjust to speed (for RMII mode) */ + if (fpi->use_rmii) { + if (fep->speed == 100) + C8(fcccp, fcc_gfemr, 0x20); + else + S8(fcccp, fcc_gfemr, 0x20); + } + + fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); + + /* clear events */ + W16(fccp, fcc_fcce, 0xffff); + + /* Enable interrupts we wish to service */ + W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Set GFMR to enable Ethernet operating mode */ + W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* set sync/delimiters */ + W16(fccp, fcc_fdsr, 0xd555); + + W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); + + if (fpi->use_rmii) + S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); + + /* adjust to duplex mode */ + if (fep->duplex) + S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); + else + C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); + + S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + /* stop ethernet */ + C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); + + /* clear events */ + W16(fccp, fcc_fcce, 0xffff); + + /* clear interrupt mask */ + W16(fccp, fcc_fccm, 0); + + fs_cleanup_bds(dev); +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + /* nothing */ +} + +static void tx_kickstart(struct net_device *dev) +{ + /* nothing */ +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + return (u32)R16(fccp, fcc_fcce); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + W16(fccp, fcc_fcce, int_events & 0xffff); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); +} + +int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) + return -EINVAL; + + memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); + p = (char *)p + sizeof(fcc_t); + + memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); + p = (char *)p + sizeof(fcc_c_t); + + memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); + + return 0; +} + +int get_regs_len(struct net_device *dev) +{ + return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); +} + +/* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. Also, To workaround 8260 device erratum + * CPM37, we must disable and then re-enable the transmitter + * following a Late Collision, Underrun, or Retry Limit error. + */ +void tx_restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + C32(fccp, fcc_gfmr, FCC_GFMR_ENT); + udelay(10); + S32(fccp, fcc_gfmr, FCC_GFMR_ENT); + + fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); +} + +/*************************************************************************/ + +const struct fs_ops fs_fcc_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 000000000000..5ef4e845a387 --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c @@ -0,0 +1,653 @@ +/* + * Freescale Ethernet controllers + * + * Copyright (c) 2005 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_8xx +#include +#include +#include +#include +#endif + +#include "fs_enet.h" + +/*************************************************/ + +#if defined(CONFIG_CPM1) +/* for a CPM1 __raw_xxx's are sufficient */ +#define __fs_out32(addr, x) __raw_writel(x, addr) +#define __fs_out16(addr, x) __raw_writew(x, addr) +#define __fs_in32(addr) __raw_readl(addr) +#define __fs_in16(addr) __raw_readw(addr) +#else +/* for others play it safe */ +#define __fs_out32(addr, x) out_be32(addr, x) +#define __fs_out16(addr, x) out_be16(addr, x) +#define __fs_in32(addr) in_be32(addr) +#define __fs_in16(addr) in_be16(addr) +#endif + +/* write */ +#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) + +/* read */ +#define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) + +/* set bits */ +#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) + +/* clear bits */ +#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) + + +/* CRC polynomium used by the FEC for the multicast group filtering */ +#define FEC_CRC_POLY 0x04C11DB7 + +#define FEC_MAX_MULTICAST_ADDRS 64 + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ +#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ +#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ +#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ +#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ +#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ +#define FEC_ENET_RXF 0x02000000U /* Full frame received */ +#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ +#define FEC_ENET_MII 0x00800000U /* MII interrupt */ +#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ + +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + + +/* Make MII read/write commands for the FEC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) +#define mk_mii_end 0 + +#define FEC_MII_LOOPS 10000 + +/* + * Delay to wait for FEC reset command to complete (in us) + */ +#define FEC_RESET_DELAY 50 + +static int whack_reset(fec_t * fecp) +{ + int i; + + FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); + for (i = 0; i < FEC_RESET_DELAY; i++) { + if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) + return 0; /* OK */ + udelay(1); + } + + return -1; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + fep->fec.fecp =(void*)r->start; + + if(fep->fec.fecp == NULL) + return -EINVAL; + + return 0; + +} + +#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) +#define FEC_RX_EVENT (FEC_ENET_RXF) +#define FEC_TX_EVENT (FEC_ENET_TXF) +#define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ + FEC_ENET_BABT | FEC_ENET_EBERR) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (do_pd_setup(fep) != 0) + return -EINVAL; + + fep->fec.hthi = 0; + fep->fec.htlo = 0; + + fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; + fep->ev_rx = FEC_RX_EVENT; + fep->ev_tx = FEC_TX_EVENT; + fep->ev_err = FEC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_base = dma_alloc_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), &fep->ring_mem_addr, + GFP_KERNEL); + if (fep->ring_base == NULL) + return -ENOMEM; + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + if(fep->ring_base) + dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) + * sizeof(cbd_t), + fep->ring_base, + fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FS(fecp, r_cntrl, FEC_RCNTRL_PROM); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fep->fec.hthi = 0; + fep->fec.htlo = 0; +} + +static void set_multicast_one(struct net_device *dev, const u8 *mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + int temp, hash_index, i, j; + u32 crc, csrVal; + u8 byte, msb; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + byte = mac[i]; + for (j = 0; j < 8; j++) { + msb = crc >> 31; + crc <<= 1; + if (msb ^ (byte & 0x1)) + crc ^= FEC_CRC_POLY; + byte >>= 1; + } + } + + temp = (crc & 0x3f) >> 1; + hash_index = ((temp & 0x01) << 4) | + ((temp & 0x02) << 2) | + ((temp & 0x04)) | + ((temp & 0x08) >> 2) | + ((temp & 0x10) >> 4); + csrVal = 1 << hash_index; + if (crc & 1) + fep->fec.hthi |= csrVal; + else + fep->fec.htlo |= csrVal; +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { + fep->fec.hthi = 0xffffffffU; + fep->fec.htlo = 0xffffffffU; + } + + FC(fecp, r_cntrl, FEC_RCNTRL_PROM); + FW(fecp, hash_table_high, fep->fec.hthi); + FW(fecp, hash_table_low, fep->fec.htlo); +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +static void restart(struct net_device *dev) +{ +#ifdef CONFIG_DUET + immap_t *immap = fs_enet_immap; + u32 cptr; +#endif + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + const struct fs_platform_info *fpi = fep->fpi; + dma_addr_t rx_bd_base_phys, tx_bd_base_phys; + int r; + u32 addrhi, addrlo; + + r = whack_reset(fep->fec.fecp); + if (r != 0) + printk(KERN_ERR DRV_MODULE_NAME + ": %s FEC Reset FAILED!\n", dev->name); + + /* + * Set station address. + */ + addrhi = ((u32) dev->dev_addr[0] << 24) | + ((u32) dev->dev_addr[1] << 16) | + ((u32) dev->dev_addr[2] << 8) | + (u32) dev->dev_addr[3]; + addrlo = ((u32) dev->dev_addr[4] << 24) | + ((u32) dev->dev_addr[5] << 16); + FW(fecp, addr_low, addrhi); + FW(fecp, addr_high, addrlo); + + /* + * Reset all multicast. + */ + FW(fecp, hash_table_high, fep->fec.hthi); + FW(fecp, hash_table_low, fep->fec.htlo); + + /* + * Set maximum receive buffer size. + */ + FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); + FW(fecp, r_hash, PKT_MAXBUF_SIZE); + + /* get physical address */ + rx_bd_base_phys = fep->ring_mem_addr; + tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; + + /* + * Set receive and transmit descriptor base. + */ + FW(fecp, r_des_start, rx_bd_base_phys); + FW(fecp, x_des_start, tx_bd_base_phys); + + fs_init_bds(dev); + + /* + * Enable big endian and don't care about SDMA FC. + */ + FW(fecp, fun_code, 0x78000000); + + /* + * Set MII speed. + */ + FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); + + /* + * Clear any outstanding interrupt. + */ + FW(fecp, ievent, 0xffc0); + FW(fecp, ivec, (fep->interrupt / 2) << 29); + + + /* + * adjust to speed (only for DUET & RMII) + */ +#ifdef CONFIG_DUET + if (fpi->use_rmii) { + cptr = in_be32(&immap->im_cpm.cp_cptr); + switch (fs_get_fec_index(fpi->fs_no)) { + case 0: + cptr |= 0x100; + if (fep->speed == 10) + cptr |= 0x0000010; + else if (fep->speed == 100) + cptr &= ~0x0000010; + break; + case 1: + cptr |= 0x80; + if (fep->speed == 10) + cptr |= 0x0000008; + else if (fep->speed == 100) + cptr &= ~0x0000008; + break; + default: + BUG(); /* should never happen */ + break; + } + out_be32(&immap->im_cpm.cp_cptr, cptr); + } +#endif + + FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + /* + * adjust to duplex mode + */ + if (fep->duplex) { + FC(fecp, r_cntrl, FEC_RCNTRL_DRT); + FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ + } else { + FS(fecp, r_cntrl, FEC_RCNTRL_DRT); + FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ + } + + /* + * Enable interrupts we wish to service. + */ + FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB); + + /* + * And last, enable the transmit and receive processing. + */ + FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, r_des_active, 0x01000000); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + struct fs_enet_mii_bus *bus = fep->mii_bus; + const struct fs_mii_bus_info *bi = bus->bus_info; + int i; + + if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) + return; /* already down */ + + FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ + for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && + i < FEC_RESET_DELAY; i++) + udelay(1); + + if (i == FEC_RESET_DELAY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FEC timeout on graceful transmit stop\n", + dev->name); + /* + * Disable FEC. Let only MII interrupts. + */ + FW(fecp, imask, 0); + FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); + + fs_cleanup_bds(dev); + + /* shut down FEC1? that's where the mii bus is */ + if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { + FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, ievent, FEC_ENET_MII); + FW(fecp, mii_speed, bus->fec.mii_speed); + } +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + immap_t *immap = fs_enet_immap; + u32 siel; + + /* SIU interrupt */ + if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { + + siel = in_be32(&immap->im_siu_conf.sc_siel); + if ((irq & 1) == 0) + siel |= (0x80000000 >> irq); + else + siel &= ~(0x80000000 >> (irq & ~1)); + out_be32(&immap->im_siu_conf.sc_siel, siel); + } +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, r_des_active, 0x01000000); +} + +static void tx_kickstart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, x_des_active, 0x01000000); +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + return FR(fecp, ievent) & FR(fecp, imask); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, ievent, int_events); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); +} + +int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(fec_t)) + return -EINVAL; + + memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t)); + + return 0; +} + +int get_regs_len(struct net_device *dev) +{ + return sizeof(fec_t); +} + +void tx_restart(struct net_device *dev) +{ + /* nothing */ +} + +/*************************************************************************/ + +const struct fs_ops fs_fec_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; + +/***********************************************************************/ + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + fec_t *fecp = bus->fec.fecp; + int i, ret = -1; + + if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) { + FW(fecp, ievent, FEC_ENET_MII); + ret = FR(fecp, mii_data) & 0xffff; + } + + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) +{ + fec_t *fecp = bus->fec.fecp; + int i; + + /* this must never happen */ + if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) + FW(fecp, ievent, FEC_ENET_MII); +} + +int fs_mii_fec_init(struct fs_enet_mii_bus *bus) +{ + bd_t *bd = (bd_t *)__res; + const struct fs_mii_bus_info *bi = bus->bus_info; + fec_t *fecp; + + if (bi->id != 0) + return -1; + + bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; + bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) + & 0x3F) << 1; + + fecp = bus->fec.fecp; + + FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, ievent, FEC_ENET_MII); + FW(fecp, mii_speed, bus->fec.mii_speed); + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 000000000000..d8c6e9cadcf5 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c @@ -0,0 +1,524 @@ +/* + * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_8xx +#include +#include +#include +#include +#endif + +#include "fs_enet.h" + +/*************************************************/ + +#if defined(CONFIG_CPM1) +/* for a 8xx __raw_xxx's are sufficient */ +#define __fs_out32(addr, x) __raw_writel(x, addr) +#define __fs_out16(addr, x) __raw_writew(x, addr) +#define __fs_out8(addr, x) __raw_writeb(x, addr) +#define __fs_in32(addr) __raw_readl(addr) +#define __fs_in16(addr) __raw_readw(addr) +#define __fs_in8(addr) __raw_readb(addr) +#else +/* for others play it safe */ +#define __fs_out32(addr, x) out_be32(addr, x) +#define __fs_out16(addr, x) out_be16(addr, x) +#define __fs_in32(addr) in_be32(addr) +#define __fs_in16(addr) in_be16(addr) +#endif + +/* write, read, set bits, clear bits */ +#define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) +#define R32(_p, _m) __fs_in32(&(_p)->_m) +#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) +#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) + +#define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) +#define R16(_p, _m) __fs_in16(&(_p)->_m) +#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) +#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) + +#define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) +#define R8(_p, _m) __fs_in8(&(_p)->_m) +#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) +#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) + +#define SCC_MAX_MULTICAST_ADDRS 64 + +/* + * Delay to wait for SCC reset command to complete (in us) + */ +#define SCC_RESET_DELAY 50 +#define MAX_CR_CMD_LOOPS 10000 + +static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) +{ + cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; + u32 v, ch; + int i = 0; + + ch = fep->scc.idx << 2; + v = mk_cr_cmd(ch, op); + W16(cpmp, cp_cpcr, v | CPM_CR_FLG); + for (i = 0; i < MAX_CR_CMD_LOOPS; i++) + if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) + break; + + if (i >= MAX_CR_CMD_LOOPS) { + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; + } + return 0; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + fep->scc.sccp = (void *)r->start; + + if (fep->scc.sccp == NULL) + return -EINVAL; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); + fep->scc.ep = (void *)r->start; + + if (fep->scc.ep == NULL) + return -EINVAL; + + return 0; +} + +#define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) +#define SCC_RX_EVENT (SCCE_ENET_RXF) +#define SCC_TX_EVENT (SCCE_ENET_TXB) +#define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->scc.idx = fs_get_scc_index(fpi->fs_no); + if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ + return -EINVAL; + + do_pd_setup(fep); + + fep->scc.hthi = 0; + fep->scc.htlo = 0; + + fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; + fep->ev_rx = SCC_RX_EVENT; + fep->ev_tx = SCC_TX_EVENT; + fep->ev_err = SCC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), 8); + if (IS_DPERR(fep->ring_mem_addr)) + return -ENOMEM; + + fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->ring_base) + cpm_dpfree(fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + S16(sccp, scc_psmr, SCC_PSMR_PRO); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_enet_t *ep = fep->scc.ep; + + W16(ep, sen_gaddr1, 0); + W16(ep, sen_gaddr2, 0); + W16(ep, sen_gaddr3, 0); + W16(ep, sen_gaddr4, 0); +} + +static void set_multicast_one(struct net_device *dev, const u8 * mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_enet_t *ep = fep->scc.ep; + u16 taddrh, taddrm, taddrl; + + taddrh = ((u16) mac[5] << 8) | mac[4]; + taddrm = ((u16) mac[3] << 8) | mac[2]; + taddrl = ((u16) mac[1] << 8) | mac[0]; + + W16(ep, sen_taddrh, taddrh); + W16(ep, sen_taddrm, taddrm); + W16(ep, sen_taddrl, taddrl); + scc_cr_cmd(fep, CPM_CR_SET_GADDR); +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + scc_enet_t *ep = fep->scc.ep; + + /* clear promiscuous always */ + C16(sccp, scc_psmr, SCC_PSMR_PRO); + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { + + W16(ep, sen_gaddr1, 0xffff); + W16(ep, sen_gaddr2, 0xffff); + W16(ep, sen_gaddr3, 0xffff); + W16(ep, sen_gaddr4, 0xffff); + } +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +/* + * This function is called to start or restart the FEC during a link + * change. This only happens when switching between half and full + * duplex. + */ +static void restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + scc_enet_t *ep = fep->scc.ep; + const struct fs_platform_info *fpi = fep->fpi; + u16 paddrh, paddrm, paddrl; + const unsigned char *mac; + int i; + + C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* clear everything (slow & steady does it) */ + for (i = 0; i < sizeof(*ep); i++) + __fs_out8((char *)ep + i, 0); + + /* point to bds */ + W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); + W16(ep, sen_genscc.scc_tbase, + fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); + + /* Initialize function code registers for big-endian. + */ + W8(ep, sen_genscc.scc_rfcr, SCC_EB); + W8(ep, sen_genscc.scc_tfcr, SCC_EB); + + /* Set maximum bytes per receive buffer. + * This appears to be an Ethernet frame size, not the buffer + * fragment size. It must be a multiple of four. + */ + W16(ep, sen_genscc.scc_mrblr, 0x5f0); + + /* Set CRC preset and mask. + */ + W32(ep, sen_cpres, 0xffffffff); + W32(ep, sen_cmask, 0xdebb20e3); + + W32(ep, sen_crcec, 0); /* CRC Error counter */ + W32(ep, sen_alec, 0); /* alignment error counter */ + W32(ep, sen_disfc, 0); /* discard frame counter */ + + W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ + W16(ep, sen_retlim, 15); /* Retry limit threshold */ + + W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ + + W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ + + W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ + W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ + + /* Clear hash tables. + */ + W16(ep, sen_gaddr1, 0); + W16(ep, sen_gaddr2, 0); + W16(ep, sen_gaddr3, 0); + W16(ep, sen_gaddr4, 0); + W16(ep, sen_iaddr1, 0); + W16(ep, sen_iaddr2, 0); + W16(ep, sen_iaddr3, 0); + W16(ep, sen_iaddr4, 0); + + /* set address + */ + mac = dev->dev_addr; + paddrh = ((u16) mac[5] << 8) | mac[4]; + paddrm = ((u16) mac[3] << 8) | mac[2]; + paddrl = ((u16) mac[1] << 8) | mac[0]; + + W16(ep, sen_paddrh, paddrh); + W16(ep, sen_paddrm, paddrm); + W16(ep, sen_paddrl, paddrl); + + W16(ep, sen_pper, 0); + W16(ep, sen_taddrl, 0); + W16(ep, sen_taddrm, 0); + W16(ep, sen_taddrh, 0); + + fs_init_bds(dev); + + scc_cr_cmd(fep, CPM_CR_INIT_TRX); + + W16(sccp, scc_scce, 0xffff); + + /* Enable interrupts we wish to service. + */ + W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); + + /* Set GSMR_H to enable all normal operating modes. + * Set GSMR_L to enable Ethernet to MC68160. + */ + W32(sccp, scc_gsmrh, 0); + W32(sccp, scc_gsmrl, + SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | + SCC_GSMRL_MODE_ENET); + + /* Set sync/delimiters. + */ + W16(sccp, scc_dsr, 0xd555); + + /* Set processing mode. Use Ethernet CRC, catch broadcast, and + * start frame search 22 bit times after RENA. + */ + W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); + + /* Set full duplex mode if needed */ + if (fep->duplex) + S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); + + S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + int i; + + for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) + udelay(1); + + if (i == SCC_RESET_DELAY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s SCC timeout on graceful transmit stop\n", + dev->name); + + W16(sccp, scc_sccm, 0); + C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + fs_cleanup_bds(dev); +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + immap_t *immap = fs_enet_immap; + u32 siel; + + /* SIU interrupt */ + if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { + + siel = in_be32(&immap->im_siu_conf.sc_siel); + if ((irq & 1) == 0) + siel |= (0x80000000 >> irq); + else + siel &= ~(0x80000000 >> (irq & ~1)); + out_be32(&immap->im_siu_conf.sc_siel, siel); + } +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + /* nothing */ +} + +static void tx_kickstart(struct net_device *dev) +{ + /* nothing */ +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + return (u32) R16(sccp, scc_scce); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + W16(sccp, scc_scce, int_events & 0xffff); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events); +} + +static int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) + return -EINVAL; + + memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); + p = (char *)p + sizeof(scc_t); + + memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); + + return 0; +} + +static int get_regs_len(struct net_device *dev) +{ + return sizeof(scc_t) + sizeof(scc_enet_t); +} + +static void tx_restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + scc_cr_cmd(fep, CPM_CR_RESTART_TX); +} + +/*************************************************************************/ + +const struct fs_ops fs_scc_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c new file mode 100644 index 000000000000..24a5e2e23d18 --- /dev/null +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -0,0 +1,405 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#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 "fs_enet.h" + +#ifdef CONFIG_8xx +static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +{ + immap_t *im = (immap_t *)fs_enet_immap; + void *dir, *dat, *ppar; + int adv; + u8 msk; + + switch (port) { + case fsiop_porta: + dir = &im->im_ioport.iop_padir; + dat = &im->im_ioport.iop_padat; + ppar = &im->im_ioport.iop_papar; + break; + + case fsiop_portb: + dir = &im->im_cpm.cp_pbdir; + dat = &im->im_cpm.cp_pbdat; + ppar = &im->im_cpm.cp_pbpar; + break; + + case fsiop_portc: + dir = &im->im_ioport.iop_pcdir; + dat = &im->im_ioport.iop_pcdat; + ppar = &im->im_ioport.iop_pcpar; + break; + + case fsiop_portd: + dir = &im->im_ioport.iop_pddir; + dat = &im->im_ioport.iop_pddat; + ppar = &im->im_ioport.iop_pdpar; + break; + + case fsiop_porte: + dir = &im->im_cpm.cp_pedir; + dat = &im->im_cpm.cp_pedat; + ppar = &im->im_cpm.cp_pepar; + break; + + default: + printk(KERN_ERR DRV_MODULE_NAME + "Illegal port value %d!\n", port); + return -EINVAL; + } + + adv = bit >> 3; + dir = (char *)dir + adv; + dat = (char *)dat + adv; + ppar = (char *)ppar + adv; + + msk = 1 << (7 - (bit & 7)); + if ((in_8(ppar) & msk) != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "pin %d on port %d is not general purpose!\n", bit, port); + return -EINVAL; + } + + *dirp = dir; + *datp = dat; + *mskp = msk; + + return 0; +} +#endif + +#ifdef CONFIG_8260 +static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +{ + iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; + void *dir, *dat, *ppar; + int adv; + u8 msk; + + switch (port) { + case fsiop_porta: + dir = &io->iop_pdira; + dat = &io->iop_pdata; + ppar = &io->iop_ppara; + break; + + case fsiop_portb: + dir = &io->iop_pdirb; + dat = &io->iop_pdatb; + ppar = &io->iop_pparb; + break; + + case fsiop_portc: + dir = &io->iop_pdirc; + dat = &io->iop_pdatc; + ppar = &io->iop_pparc; + break; + + case fsiop_portd: + dir = &io->iop_pdird; + dat = &io->iop_pdatd; + ppar = &io->iop_ppard; + break; + + default: + printk(KERN_ERR DRV_MODULE_NAME + "Illegal port value %d!\n", port); + return -EINVAL; + } + + adv = bit >> 3; + dir = (char *)dir + adv; + dat = (char *)dat + adv; + ppar = (char *)ppar + adv; + + msk = 1 << (7 - (bit & 7)); + if ((in_8(ppar) & msk) != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "pin %d on port %d is not general purpose!\n", bit, port); + return -EINVAL; + } + + *dirp = dir; + *datp = dat; + *mskp = msk; + + return 0; +} +#endif + +static inline void bb_set(u8 *p, u8 m) +{ + out_8(p, in_8(p) | m); +} + +static inline void bb_clr(u8 *p, u8 m) +{ + out_8(p, in_8(p) & ~m); +} + +static inline int bb_read(u8 *p, u8 m) +{ + return (in_8(p) & m) != 0; +} + +static inline void mdio_active(struct fs_enet_mii_bus *bus) +{ + bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); +} + +static inline void mdio_tristate(struct fs_enet_mii_bus *bus) +{ + bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); +} + +static inline int mdio_read(struct fs_enet_mii_bus *bus) +{ + return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); +} + +static inline void mdio(struct fs_enet_mii_bus *bus, int what) +{ + if (what) + bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + else + bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); +} + +static inline void mdc(struct fs_enet_mii_bus *bus, int what) +{ + if (what) + bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + else + bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); +} + +static inline void mii_delay(struct fs_enet_mii_bus *bus) +{ + udelay(bus->bus_info->i.bitbang.delay); +} + +/* Utility to send the preamble, address, and register (common to read and write). */ +static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) +{ + int j; + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. + * The IEEE spec says this is a PHY optional requirement. The AMD + * 79C874 requires one after power up and one after a MII communications + * error. This means that we are doing more preambles than we need, + * but it is safer and will be much more robust. + */ + + mdio_active(bus); + mdio(bus, 1); + for (j = 0; j < 32; j++) { + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + } + + /* send the start bit (01) and the read opcode (10) or write (10) */ + mdc(bus, 0); + mdio(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, 1); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, read); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, !read); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* send the PHY address */ + for (j = 0; j < 5; j++) { + mdc(bus, 0); + mdio(bus, (addr & 0x10) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + addr <<= 1; + } + + /* send the register address */ + for (j = 0; j < 5; j++) { + mdc(bus, 0); + mdio(bus, (reg & 0x10) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + reg <<= 1; + } +} + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + u16 rdreg; + int ret, j; + u8 addr = phy_id & 0xff; + u8 reg = location & 0xff; + + bitbang_pre(bus, 1, addr, reg); + + /* tri-state our MDIO I/O pin so we can read */ + mdc(bus, 0); + mdio_tristate(bus); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* check the turnaround bit: the PHY should be driving it to zero */ + if (mdio_read(bus) != 0) { + /* PHY didn't drive TA low */ + for (j = 0; j < 32; j++) { + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + } + ret = -1; + goto out; + } + + mdc(bus, 0); + mii_delay(bus); + + /* read 16 bits of register data, MSB first */ + rdreg = 0; + for (j = 0; j < 16; j++) { + mdc(bus, 1); + mii_delay(bus); + rdreg <<= 1; + rdreg |= mdio_read(bus); + mdc(bus, 0); + mii_delay(bus); + } + + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + ret = rdreg; +out: + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +{ + int j; + u8 addr = phy_id & 0xff; + u8 reg = location & 0xff; + u16 value = val & 0xffff; + + bitbang_pre(bus, 0, addr, reg); + + /* send the turnaround (10) */ + mdc(bus, 0); + mdio(bus, 1); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* write 16 bits of register data, MSB first */ + for (j = 0; j < 16; j++) { + mdc(bus, 0); + mdio(bus, (value & 0x8000) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + value <<= 1; + } + + /* + * Tri-state the MDIO line. + */ + mdio_tristate(bus); + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); +} + +int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) +{ + const struct fs_mii_bus_info *bi = bus->bus_info; + int r; + + r = bitbang_prep_bit(&bus->bitbang.mdio_dir, + &bus->bitbang.mdio_dat, + &bus->bitbang.mdio_msk, + bi->i.bitbang.mdio_port, + bi->i.bitbang.mdio_bit); + if (r != 0) + return r; + + r = bitbang_prep_bit(&bus->bitbang.mdc_dir, + &bus->bitbang.mdc_dat, + &bus->bitbang.mdc_msk, + bi->i.bitbang.mdc_port, + bi->i.bitbang.mdc_bit); + if (r != 0) + return r; + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c new file mode 100644 index 000000000000..b3e192d612e5 --- /dev/null +++ b/drivers/net/fs_enet/mii-fixed.c @@ -0,0 +1,92 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#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 "fs_enet.h" + +static const u16 mii_regs[7] = { + 0x3100, + 0x786d, + 0x0fff, + 0x0fff, + 0x01e1, + 0x45e1, + 0x0003, +}; + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + int ret = 0; + + if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) + return -1; + + if (location != 5) + ret = mii_regs[location]; + else + ret = bus->fixed.lpa; + + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +{ + /* do nothing */ +} + +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) +{ + const struct fs_mii_bus_info *bi = bus->bus_info; + + bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ + + /* if speed is fixed at 10Mb, remove 100Mb modes */ + if (bi->i.fixed.speed == 10) + bus->fixed.lpa &= ~LPA_100; + + /* if duplex is half, remove full duplex modes */ + if (bi->i.fixed.duplex == 0) + bus->fixed.lpa &= ~LPA_DUPLEX; + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h new file mode 100644 index 000000000000..bef23bbf8690 --- /dev/null +++ b/include/linux/fs_enet_pd.h @@ -0,0 +1,136 @@ +/* + * Platform information definitions for the + * universal Freescale Ethernet driver. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef FS_ENET_PD_H +#define FS_ENET_PD_H + +#include +#include + +#define FS_ENET_NAME "fs_enet" + +enum fs_id { + fsid_fec1, + fsid_fec2, + fsid_fcc1, + fsid_fcc2, + fsid_fcc3, + fsid_scc1, + fsid_scc2, + fsid_scc3, + fsid_scc4, +}; + +#define FS_MAX_INDEX 9 + +static inline int fs_get_fec_index(enum fs_id id) +{ + if (id >= fsid_fec1 && id <= fsid_fec2) + return id - fsid_fec1; + return -1; +} + +static inline int fs_get_fcc_index(enum fs_id id) +{ + if (id >= fsid_fcc1 && id <= fsid_fcc3) + return id - fsid_fcc1; + return -1; +} + +static inline int fs_get_scc_index(enum fs_id id) +{ + if (id >= fsid_scc1 && id <= fsid_scc4) + return id - fsid_scc1; + return -1; +} + +enum fs_mii_method { + fsmii_fixed, + fsmii_fec, + fsmii_bitbang, +}; + +enum fs_ioport { + fsiop_porta, + fsiop_portb, + fsiop_portc, + fsiop_portd, + fsiop_porte, +}; + +struct fs_mii_bus_info { + int method; /* mii method */ + int id; /* the id of the mii_bus */ + int disable_aneg; /* if the controller needs to negothiate speed & duplex */ + int lpa; /* the default board-specific vallues will be applied otherwise */ + + union { + struct { + int duplex; + int speed; + } fixed; + + struct { + /* nothing */ + } fec; + + struct { + /* nothing */ + } scc; + + struct { + int mdio_port; /* port & bit for MDIO */ + int mdio_bit; + int mdc_port; /* port & bit for MDC */ + int mdc_bit; + int delay; /* delay in us */ + } bitbang; + } i; +}; + +struct fs_platform_info { + + void(*init_ioports)(void); + /* device specific information */ + int fs_no; /* controller index */ + + u32 cp_page; /* CPM page */ + u32 cp_block; /* CPM sblock */ + + u32 clk_trx; /* some stuff for pins & mux configuration*/ + u32 clk_route; + u32 clk_mask; + + u32 mem_offset; + u32 dpram_offset; + u32 fcc_regs_c; + + u32 device_flags; + + int phy_addr; /* the phy address (-1 no phy) */ + int phy_irq; /* the phy irq (if it exists) */ + + const struct fs_mii_bus_info *bus_info; + + int rx_ring, tx_ring; /* number of buffers on rx */ + __u8 macaddr[6]; /* mac address */ + int rx_copybreak; /* limit we copy small frames */ + int use_napi; /* use NAPI */ + int napi_weight; /* NAPI weight */ + + int use_rmii; /* use RMII mode */ +}; + +#endif From 19c1f3ca4272008a256cc153f3e3feb097799070 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 28 Oct 2005 21:37:29 +0100 Subject: [PATCH 0988/1939] [MMC] wbsd suspend support Proper handling of suspend/resume in the wbsd driver. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 119 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 25f7ce7b3bc0..3ace875decc4 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1033,13 +1033,16 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) } else { - setup &= ~WBSD_DAT3_H; + if (setup & WBSD_DAT3_H) + { + setup &= ~WBSD_DAT3_H; - /* - * We cannot resume card detection immediatly - * because of capacitance and delays in the chip. - */ - mod_timer(&host->ignore_timer, jiffies + HZ/100); + /* + * We cannot resume card detection immediatly + * because of capacitance and delays in the chip. + */ + mod_timer(&host->ignore_timer, jiffies + HZ/100); + } } wbsd_write_index(host, WBSD_IDX_SETUP, setup); @@ -1461,8 +1464,10 @@ static int __devinit wbsd_scan(struct wbsd_host* host) { id = 0xFFFF; - outb(unlock_codes[j], config_ports[i]); - outb(unlock_codes[j], config_ports[i]); + host->config = config_ports[i]; + host->unlock_code = unlock_codes[j]; + + wbsd_unlock_config(host); outb(WBSD_CONF_ID_HI, config_ports[i]); id = inb(config_ports[i] + 1) << 8; @@ -1470,13 +1475,13 @@ static int __devinit wbsd_scan(struct wbsd_host* host) outb(WBSD_CONF_ID_LO, config_ports[i]); id |= inb(config_ports[i] + 1); + wbsd_lock_config(host); + for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++) { if (id == valid_ids[k]) { host->chip_id = id; - host->config = config_ports[i]; - host->unlock_code = unlock_codes[i]; return 0; } @@ -1487,13 +1492,14 @@ static int __devinit wbsd_scan(struct wbsd_host* host) DBG("Unknown hardware (id %x) found at %x\n", id, config_ports[i]); } - - outb(LOCK_CODE, config_ports[i]); } release_region(config_ports[i], 2); } + host->config = 0; + host->unlock_code = 0; + return -ENODEV; } @@ -1699,8 +1705,10 @@ static void __devexit wbsd_release_resources(struct wbsd_host* host) * Configure the resources the chip should use. */ -static void __devinit wbsd_chip_config(struct wbsd_host* host) +static void wbsd_chip_config(struct wbsd_host* host) { + wbsd_unlock_config(host); + /* * Reset the chip. */ @@ -1733,16 +1741,20 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host) */ wbsd_write_config(host, WBSD_CONF_ENABLE, 1); wbsd_write_config(host, WBSD_CONF_POWER, 0x20); + + wbsd_lock_config(host); } /* * Check that configured resources are correct. */ -static int __devinit wbsd_chip_validate(struct wbsd_host* host) +static int wbsd_chip_validate(struct wbsd_host* host) { int base, irq, dma; + wbsd_unlock_config(host); + /* * Select SD/MMC function. */ @@ -1758,6 +1770,8 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host) dma = wbsd_read_config(host, WBSD_CONF_DRQ); + wbsd_lock_config(host); + /* * Validate against given configuration. */ @@ -1771,6 +1785,20 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host) return 1; } +/* + * Powers down the SD function + */ + +static void wbsd_chip_poweroff(struct wbsd_host* host) +{ + wbsd_unlock_config(host); + + wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); + wbsd_write_config(host, WBSD_CONF_ENABLE, 0); + + wbsd_lock_config(host); +} + /*****************************************************************************\ * * * Devices setup and shutdown * @@ -1844,7 +1872,11 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, */ #ifdef CONFIG_PM if (host->config) + { + wbsd_unlock_config(host); wbsd_write_config(host, WBSD_CONF_PME, 0xA0); + wbsd_lock_config(host); + } #endif /* * Allow device to initialise itself properly. @@ -1885,16 +1917,11 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp) mmc_remove_host(mmc); + /* + * Power down the SD/MMC function. + */ if (!pnp) - { - /* - * Power down the SD/MMC function. - */ - wbsd_unlock_config(host); - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - wbsd_write_config(host, WBSD_CONF_ENABLE, 0); - wbsd_lock_config(host); - } + wbsd_chip_poweroff(host); wbsd_release_resources(host); @@ -1955,23 +1982,59 @@ static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) */ #ifdef CONFIG_PM + static int wbsd_suspend(struct device *dev, pm_message_t state) { - DBGF("Not yet supported\n"); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct wbsd_host *host; + int ret; + + if (!mmc) + return 0; + + DBG("Suspending...\n"); + + ret = mmc_suspend_host(mmc, state); + if (!ret) + return ret; + + host = mmc_priv(mmc); + + wbsd_chip_poweroff(host); return 0; } static int wbsd_resume(struct device *dev) { - DBGF("Not yet supported\n"); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct wbsd_host *host; - return 0; + if (!mmc) + return 0; + + DBG("Resuming...\n"); + + host = mmc_priv(mmc); + + wbsd_chip_config(host); + + /* + * Allow device to initialise itself properly. + */ + mdelay(5); + + wbsd_init_device(host); + + return mmc_resume_host(mmc); } -#else + +#else /* CONFIG_PM */ + #define wbsd_suspend NULL #define wbsd_resume NULL -#endif + +#endif /* CONFIG_PM */ static struct platform_device *wbsd_device; From 89358f90ab6f6657d386e77e19c805d7ab88694f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 28 Oct 2005 16:38:02 -0400 Subject: [PATCH 0989/1939] [netdrvr b44] include linux/dma-mapping.h to eliminate warning --- drivers/net/b44.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 225d14fd9239..ab845076ff9f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include From b71b95efa5abca33e1bfb85d55162c7f99f54c23 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Fri, 28 Oct 2005 12:23:47 +0200 Subject: [PATCH 0990/1939] [PATCH] sundance: fix DFE-580TX Tx Underrun Under heavy PCI bus load, ports of the DFE-580TX 4-ethernet port board stop working, with currently no other cure than a powercycle. Here is a tested fix. By the way, I also fixed some references and attribution. Signed-off-by: Philippe De Muyter Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 62 ++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 5de0554fd7c6..0ab9c38b4a34 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -80,7 +80,7 @@ I/O access could affect performance in ARM-based system - Add Linux software VLAN support - Version LK1.08 (D-Link): + Version LK1.08 (Philippe De Muyter phdm@macqel.be): - Fix bug of custom mac address (StationAddr register only accept word write) @@ -91,11 +91,14 @@ Version LK1.09a (ICPlus): - Add the delay time in reading the contents of EEPROM + Version LK1.10 (Philippe De Muyter phdm@macqel.be): + - Make 'unblock interface after Tx underrun' work + */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01+LK1.09a" -#define DRV_RELDATE "10-Jul-2003" +#define DRV_VERSION "1.01+LK1.10" +#define DRV_RELDATE "28-Oct-2005" /* The user-configurable values. @@ -263,8 +266,10 @@ IV. Notes IVb. References The Sundance ST201 datasheet, preliminary version. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +The Kendin KS8723 datasheet, preliminary version. +The ICplus IP100 datasheet, preliminary version. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata @@ -500,6 +505,25 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); static struct ethtool_ops ethtool_ops; +static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base + ASICCtrl; + int countdown; + + /* ST201 documentation states ASICCtrl is a 32bit register */ + iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); + /* ST201 documentation states reset can take up to 1 ms */ + countdown = 10 + 1; + while (ioread32 (ioaddr) & (ResetBusy << 16)) { + if (--countdown == 0) { + printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); + break; + } + udelay(100); + } +} + static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1190,23 +1214,33 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ("%s: Transmit status is %2.2x.\n", dev->name, tx_status); if (tx_status & 0x1e) { + if (netif_msg_tx_err(np)) + printk("%s: Transmit error status %4.4x.\n", + dev->name, tx_status); np->stats.tx_errors++; if (tx_status & 0x10) np->stats.tx_fifo_errors++; if (tx_status & 0x08) np->stats.collisions++; + if (tx_status & 0x04) + np->stats.tx_fifo_errors++; if (tx_status & 0x02) np->stats.tx_window_errors++; - /* This reset has not been verified!. */ - if (tx_status & 0x10) { /* Reset the Tx. */ - np->stats.tx_fifo_errors++; - spin_lock(&np->lock); - reset_tx(dev); - spin_unlock(&np->lock); + /* + ** This reset has been verified on + ** DFE-580TX boards ! phdm@macqel.be. + */ + if (tx_status & 0x10) { /* TxUnderrun */ + unsigned short txthreshold; + + txthreshold = ioread16 (ioaddr + TxStartThresh); + /* Restart Tx FIFO and transmitter */ + sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); + iowrite16 (txthreshold, ioaddr + TxStartThresh); + /* No need to reset the Tx pointer here */ } - if (tx_status & 0x1e) /* Restart the Tx. */ - iowrite16 (TxEnable, - ioaddr + MACCtrl1); + /* Restart the Tx. */ + iowrite16 (TxEnable, ioaddr + MACCtrl1); } /* Yup, this is a documentation bug. It cost me *hours*. */ iowrite16 (0, ioaddr + TxStatus); From 37448f7d39717db7c1098c1a88b9074694c69797 Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Mon, 10 Oct 2005 16:58:14 -0700 Subject: [PATCH 0991/1939] [PATCH] New PowerPC 4xx on-chip ethernet controller driver This patch replaces current PowerPC 4xx EMAC driver with new, re-written from the scratch version. This patch is quite big (~234K) because there is virtualy 0% of common code between old and new version. New driver uses NAPI, it solves stability problems under heavy packet load and low memory, corrects chip register access and fixes numerous small bugs I don't even remember now. This patch has been tested on all supported in 2.6 PPC 4xx boards. It's been used in production for almost a year now on custom 4xx hardware. PPC32 specific parts are already upstream. Patch was acked by the current EMAC driver maintainer (Matt Porter). I will be maintaining this new version. Signed-off-by: Eugene Surovegin -- Kconfig | 72 ibm_emac/Makefile | 13 ibm_emac/ibm_emac.h | 418 +++-- ibm_emac/ibm_emac_core.c | 3414 ++++++++++++++++++++++++---------------------- ibm_emac/ibm_emac_core.h | 313 ++-- ibm_emac/ibm_emac_debug.c | 377 ++--- ibm_emac/ibm_emac_debug.h | 63 ibm_emac/ibm_emac_mal.c | 674 +++++---- ibm_emac/ibm_emac_mal.h | 336 +++- ibm_emac/ibm_emac_phy.c | 335 ++-- ibm_emac/ibm_emac_phy.h | 105 - ibm_emac/ibm_emac_rgmii.c | 201 ++ ibm_emac/ibm_emac_rgmii.h | 68 ibm_emac/ibm_emac_tah.c | 111 + ibm_emac/ibm_emac_tah.h | 96 - ibm_emac/ibm_emac_zmii.c | 255 +++ ibm_emac/ibm_emac_zmii.h | 114 - 17 files changed, 4114 insertions(+), 2851 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 72 +- drivers/net/ibm_emac/Makefile | 13 +- drivers/net/ibm_emac/ibm_emac.h | 408 +-- drivers/net/ibm_emac/ibm_emac_core.c | 3864 +++++++++++++------------ drivers/net/ibm_emac/ibm_emac_core.h | 293 +- drivers/net/ibm_emac/ibm_emac_debug.c | 377 ++- drivers/net/ibm_emac/ibm_emac_debug.h | 63 + drivers/net/ibm_emac/ibm_emac_mal.c | 686 +++-- drivers/net/ibm_emac/ibm_emac_mal.h | 330 ++- drivers/net/ibm_emac/ibm_emac_phy.c | 459 +-- drivers/net/ibm_emac/ibm_emac_phy.h | 105 +- drivers/net/ibm_emac/ibm_emac_rgmii.c | 201 ++ drivers/net/ibm_emac/ibm_emac_rgmii.h | 60 +- drivers/net/ibm_emac/ibm_emac_tah.c | 111 + drivers/net/ibm_emac/ibm_emac_tah.h | 96 +- drivers/net/ibm_emac/ibm_emac_zmii.c | 255 ++ drivers/net/ibm_emac/ibm_emac_zmii.h | 104 +- 17 files changed, 4380 insertions(+), 3117 deletions(-) create mode 100644 drivers/net/ibm_emac/ibm_emac_debug.h create mode 100644 drivers/net/ibm_emac/ibm_emac_rgmii.c create mode 100644 drivers/net/ibm_emac/ibm_emac_tah.c create mode 100644 drivers/net/ibm_emac/ibm_emac_zmii.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 27732fdeeea4..54ab70e7eff4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1163,38 +1163,74 @@ config IBMVETH be called ibmveth. config IBM_EMAC - bool "IBM PPC4xx EMAC driver support" + tristate "PowerPC 4xx on-chip Ethernet support" depends on 4xx - select CRC32 - ---help--- - This driver supports the IBM PPC4xx EMAC family of on-chip - Ethernet controllers. - -config IBM_EMAC_ERRMSG - bool "Verbose error messages" - depends on IBM_EMAC && BROKEN + help + This driver supports the PowerPC 4xx EMAC family of on-chip + Ethernet controllers. config IBM_EMAC_RXB int "Number of receive buffers" depends on IBM_EMAC - default "128" if IBM_EMAC4 - default "64" + default "128" config IBM_EMAC_TXB int "Number of transmit buffers" depends on IBM_EMAC - default "128" if IBM_EMAC4 - default "8" + default "64" -config IBM_EMAC_FGAP - int "Frame gap" +config IBM_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" depends on IBM_EMAC - default "8" + default "32" -config IBM_EMAC_SKBRES - int "Skb reserve amount" +config IBM_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" + depends on IBM_EMAC + default "256" + +config IBM_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" depends on IBM_EMAC default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usualy there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_EMAC_PHY_RX_CLK_FIX + bool "PHY Rx clock workaround" + depends on IBM_EMAC && (405EP || 440GX || 440EP) + help + Enable this if EMAC attached to a PHY which doesn't generate + RX clock if there is no link, if this is the case, you will + see "TX disable timeout" or "RX disable timeout" in the system + log. + + If unsure, say N. + +config IBM_EMAC_DEBUG + bool "Debugging" + depends on IBM_EMAC + default n + +config IBM_EMAC_ZMII + bool + depends on IBM_EMAC && (NP405H || NP405L || 44x) + default y + +config IBM_EMAC_RGMII + bool + depends on IBM_EMAC && 440GX + default y + +config IBM_EMAC_TAH + bool + depends on IBM_EMAC && 440GX + default y config NET_PCI bool "EISA, VLB, PCI and on board controllers" diff --git a/drivers/net/ibm_emac/Makefile b/drivers/net/ibm_emac/Makefile index 7f583a333c24..f98ddf0e807a 100644 --- a/drivers/net/ibm_emac/Makefile +++ b/drivers/net/ibm_emac/Makefile @@ -1,12 +1,11 @@ # -# Makefile for the IBM PPC4xx EMAC controllers +# Makefile for the PowerPC 4xx on-chip ethernet driver # obj-$(CONFIG_IBM_EMAC) += ibm_emac.o -ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o - -# Only need this if you want to see additional debug messages -ifeq ($(CONFIG_IBM_EMAC_ERRMSG), y) -ibm_emac-objs += ibm_emac_debug.o -endif +ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o +ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o +ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o +ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o +ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h index 15d5a0e82862..28c476f28c20 100644 --- a/drivers/net/ibm_emac/ibm_emac.h +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -1,110 +1,142 @@ /* - * ibm_emac.h + * drivers/net/ibm_emac/ibm_emac.h * + * Register definitions for PowerPC 4xx on-chip ethernet contoller * - * Armin Kuster akuster@mvista.com - * June, 2002 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or * - * Copyright 2002 MontaVista Softare Inc. + * Based on original work by + * Matt Porter + * Armin Kuster + * Copyright 2002-2004 MontaVista Software 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 __IBM_EMAC_H_ +#define __IBM_EMAC_H_ -#ifndef _IBM_EMAC_H_ -#define _IBM_EMAC_H_ -/* General defines needed for the driver */ +#include +#include -/* Emac */ -typedef struct emac_regs { - u32 em0mr0; - u32 em0mr1; - u32 em0tmr0; - u32 em0tmr1; - u32 em0rmr; - u32 em0isr; - u32 em0iser; - u32 em0iahr; - u32 em0ialr; - u32 em0vtpid; - u32 em0vtci; - u32 em0ptr; - u32 em0iaht1; - u32 em0iaht2; - u32 em0iaht3; - u32 em0iaht4; - u32 em0gaht1; - u32 em0gaht2; - u32 em0gaht3; - u32 em0gaht4; - u32 em0lsah; - u32 em0lsal; - u32 em0ipgvr; - u32 em0stacr; - u32 em0trtr; - u32 em0rwmr; -} emac_t; +/* This is a simple check to prevent use of this driver on non-tested SoCs */ +#if !defined(CONFIG_405GP) && !defined(CONFIG_405GPR) && !defined(CONFIG_405EP) && \ + !defined(CONFIG_440GP) && !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && \ + !defined(CONFIG_440EP) && !defined(CONFIG_NP405H) +#error "Unknown SoC. Please, check chip user manual and make sure EMAC defines are OK" +#endif -/* MODE REG 0 */ -#define EMAC_M0_RXI 0x80000000 -#define EMAC_M0_TXI 0x40000000 -#define EMAC_M0_SRST 0x20000000 -#define EMAC_M0_TXE 0x10000000 -#define EMAC_M0_RXE 0x08000000 -#define EMAC_M0_WKE 0x04000000 +/* EMAC registers Write Access rules */ +struct emac_regs { + u32 mr0; /* special */ + u32 mr1; /* Reset */ + u32 tmr0; /* special */ + u32 tmr1; /* special */ + u32 rmr; /* Reset */ + u32 isr; /* Always */ + u32 iser; /* Reset */ + u32 iahr; /* Reset, R, T */ + u32 ialr; /* Reset, R, T */ + u32 vtpid; /* Reset, R, T */ + u32 vtci; /* Reset, R, T */ + u32 ptr; /* Reset, T */ + u32 iaht1; /* Reset, R */ + u32 iaht2; /* Reset, R */ + u32 iaht3; /* Reset, R */ + u32 iaht4; /* Reset, R */ + u32 gaht1; /* Reset, R */ + u32 gaht2; /* Reset, R */ + u32 gaht3; /* Reset, R */ + u32 gaht4; /* Reset, R */ + u32 lsah; + u32 lsal; + u32 ipgvr; /* Reset, T */ + u32 stacr; /* special */ + u32 trtr; /* special */ + u32 rwmr; /* Reset */ + u32 octx; + u32 ocrx; + u32 ipcr; +}; -/* MODE Reg 1 */ -#define EMAC_M1_FDE 0x80000000 -#define EMAC_M1_ILE 0x40000000 -#define EMAC_M1_VLE 0x20000000 -#define EMAC_M1_EIFC 0x10000000 -#define EMAC_M1_APP 0x08000000 -#define EMAC_M1_AEMI 0x02000000 -#define EMAC_M1_IST 0x01000000 -#define EMAC_M1_MF_1000GPCS 0x00c00000 /* Internal GPCS */ -#define EMAC_M1_MF_1000MBPS 0x00800000 /* External GPCS */ -#define EMAC_M1_MF_100MBPS 0x00400000 -#define EMAC_M1_RFS_16K 0x00280000 /* 000 for 512 byte */ -#define EMAC_M1_TR 0x00008000 -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_M1_RFS_8K 0x00200000 -#define EMAC_M1_RFS_4K 0x00180000 -#define EMAC_M1_RFS_2K 0x00100000 -#define EMAC_M1_RFS_1K 0x00080000 -#define EMAC_M1_TX_FIFO_16K 0x00050000 /* 0's for 512 byte */ -#define EMAC_M1_TX_FIFO_8K 0x00040000 -#define EMAC_M1_TX_FIFO_4K 0x00030000 -#define EMAC_M1_TX_FIFO_2K 0x00020000 -#define EMAC_M1_TX_FIFO_1K 0x00010000 -#define EMAC_M1_TX_TR 0x00008000 -#define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */ -#define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */ -#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */ -#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */ -#define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */ -#define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */ -#else /* CONFIG_IBM_EMAC4 */ -#define EMAC_M1_RFS_4K 0x00300000 /* ~4k for 512 byte */ -#define EMAC_M1_RFS_2K 0x00200000 -#define EMAC_M1_RFS_1K 0x00100000 -#define EMAC_M1_TX_FIFO_2K 0x00080000 /* 0's for 512 byte */ -#define EMAC_M1_TX_FIFO_1K 0x00040000 -#define EMAC_M1_TR0_DEPEND 0x00010000 /* 0'x for single packet */ -#define EMAC_M1_TR1_DEPEND 0x00004000 -#define EMAC_M1_TR1_MULTI 0x00002000 -#define EMAC_M1_JUMBO_ENABLE 0x00001000 -#endif /* CONFIG_IBM_EMAC4 */ -#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \ - EMAC_M1_APP | \ - EMAC_M1_TR | EMAC_M1_VLE) +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_ETHTOOL_REGS_VER 0 +#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) +#else +#define EMAC_ETHTOOL_REGS_VER 1 +#define EMAC_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) +#endif -/* Transmit Mode Register 0 */ -#define EMAC_TMR0_GNP0 0x80000000 -#define EMAC_TMR0_GNP1 0x40000000 -#define EMAC_TMR0_GNPD 0x20000000 -#define EMAC_TMR0_FC 0x10000000 +/* EMACx_MR0 */ +#define EMAC_MR0_RXI 0x80000000 +#define EMAC_MR0_TXI 0x40000000 +#define EMAC_MR0_SRST 0x20000000 +#define EMAC_MR0_TXE 0x10000000 +#define EMAC_MR0_RXE 0x08000000 +#define EMAC_MR0_WKE 0x04000000 + +/* EMACx_MR1 */ +#define EMAC_MR1_FDE 0x80000000 +#define EMAC_MR1_ILE 0x40000000 +#define EMAC_MR1_VLE 0x20000000 +#define EMAC_MR1_EIFC 0x10000000 +#define EMAC_MR1_APP 0x08000000 +#define EMAC_MR1_IST 0x01000000 + +#define EMAC_MR1_MF_MASK 0x00c00000 +#define EMAC_MR1_MF_10 0x00000000 +#define EMAC_MR1_MF_100 0x00400000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_MR1_MF_1000 0x00000000 +#define EMAC_MR1_MF_1000GPCS 0x00000000 +#define EMAC_MR1_MF_IPPA(id) 0x00000000 +#else +#define EMAC_MR1_MF_1000 0x00800000 +#define EMAC_MR1_MF_1000GPCS 0x00c00000 +#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) +#endif + +#define EMAC_TX_FIFO_SIZE 2048 + +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_MR1_RFS_4K 0x00300000 +#define EMAC_MR1_RFS_16K 0x00000000 +#define EMAC_RX_FIFO_SIZE(gige) 4096 +#define EMAC_MR1_TFS_2K 0x00080000 +#define EMAC_MR1_TR0_MULT 0x00008000 +#define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) +#else +#define EMAC_MR1_RFS_4K 0x00180000 +#define EMAC_MR1_RFS_16K 0x00280000 +#define EMAC_RX_FIFO_SIZE(gige) ((gige) ? 16384 : 4096) +#define EMAC_MR1_TFS_2K 0x00020000 +#define EMAC_MR1_TR 0x00008000 +#define EMAC_MR1_MWSW_001 0x00001000 +#define EMAC_MR1_JPSM 0x00000800 +#define EMAC_MR1_OBCI_MASK 0x00000038 +#define EMAC_MR1_OBCI_50 0x00000000 +#define EMAC_MR1_OBCI_66 0x00000008 +#define EMAC_MR1_OBCI_83 0x00000010 +#define EMAC_MR1_OBCI_100 0x00000018 +#define EMAC_MR1_OBCI_100P 0x00000020 +#define EMAC_MR1_OBCI(freq) ((freq) <= 50 ? EMAC_MR1_OBCI_50 : \ + (freq) <= 66 ? EMAC_MR1_OBCI_66 : \ + (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ + (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ + EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb)) +#endif + +/* EMACx_TMR0 */ +#define EMAC_TMR0_GNP 0x80000000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TMR0_DEFAULT 0x00000000 +#else #define EMAC_TMR0_TFAE_2_32 0x00000001 #define EMAC_TMR0_TFAE_4_64 0x00000002 #define EMAC_TMR0_TFAE_8_128 0x00000003 @@ -112,14 +144,36 @@ typedef struct emac_regs { #define EMAC_TMR0_TFAE_32_512 0x00000005 #define EMAC_TMR0_TFAE_64_1024 0x00000006 #define EMAC_TMR0_TFAE_128_2048 0x00000007 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 +#endif +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) -/* Receive Mode Register */ +/* EMACx_TMR1 */ + +/* IBM manuals are not very clear here. + * This is my interpretation of how things are. --ebs + */ +#if defined(CONFIG_40x) +#define EMAC_FIFO_ENTRY_SIZE 8 +#define EMAC_MAL_BURST_SIZE (16 * 4) +#else +#define EMAC_FIFO_ENTRY_SIZE 16 +#define EMAC_MAL_BURST_SIZE (64 * 4) +#endif + +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) +#else +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) +#endif + +/* EMACx_RMR */ #define EMAC_RMR_SP 0x80000000 #define EMAC_RMR_SFCS 0x40000000 -#define EMAC_RMR_ARRP 0x20000000 -#define EMAC_RMR_ARP 0x10000000 -#define EMAC_RMR_AROP 0x08000000 -#define EMAC_RMR_ARPI 0x04000000 +#define EMAC_RMR_RRP 0x20000000 +#define EMAC_RMR_RFP 0x10000000 +#define EMAC_RMR_ROP 0x08000000 +#define EMAC_RMR_RPIR 0x04000000 #define EMAC_RMR_PPP 0x02000000 #define EMAC_RMR_PME 0x01000000 #define EMAC_RMR_PMME 0x00800000 @@ -127,6 +181,9 @@ typedef struct emac_regs { #define EMAC_RMR_MIAE 0x00200000 #define EMAC_RMR_BAE 0x00100000 #define EMAC_RMR_MAE 0x00080000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_RMR_BASE 0x00000000 +#else #define EMAC_RMR_RFAF_2_32 0x00000001 #define EMAC_RMR_RFAF_4_64 0x00000002 #define EMAC_RMR_RFAF_8_128 0x00000003 @@ -134,9 +191,21 @@ typedef struct emac_regs { #define EMAC_RMR_RFAF_32_512 0x00000005 #define EMAC_RMR_RFAF_64_1024 0x00000006 #define EMAC_RMR_RFAF_128_2048 0x00000007 -#define EMAC_RMR_BASE (EMAC_RMR_IAE | EMAC_RMR_BAE) +#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048 +#endif -/* Interrupt Status & enable Regs */ +/* EMACx_ISR & EMACx_ISER */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_ISR_TXPE 0x00000000 +#define EMAC_ISR_RXPE 0x00000000 +#define EMAC_ISR_TXUE 0x00000000 +#define EMAC_ISR_RXOE 0x00000000 +#else +#define EMAC_ISR_TXPE 0x20000000 +#define EMAC_ISR_RXPE 0x10000000 +#define EMAC_ISR_TXUE 0x08000000 +#define EMAC_ISR_RXOE 0x04000000 +#endif #define EMAC_ISR_OVR 0x02000000 #define EMAC_ISR_PP 0x01000000 #define EMAC_ISR_BP 0x00800000 @@ -147,53 +216,62 @@ typedef struct emac_regs { #define EMAC_ISR_PTLE 0x00040000 #define EMAC_ISR_ORE 0x00020000 #define EMAC_ISR_IRE 0x00010000 -#define EMAC_ISR_DBDM 0x00000200 -#define EMAC_ISR_DB0 0x00000100 -#define EMAC_ISR_SE0 0x00000080 -#define EMAC_ISR_TE0 0x00000040 -#define EMAC_ISR_DB1 0x00000020 -#define EMAC_ISR_SE1 0x00000010 -#define EMAC_ISR_TE1 0x00000008 +#define EMAC_ISR_SQE 0x00000080 +#define EMAC_ISR_TE 0x00000040 #define EMAC_ISR_MOS 0x00000002 #define EMAC_ISR_MOF 0x00000001 -/* STA CONTROL REG */ +/* EMACx_STACR */ +#define EMAC_STACR_PHYD_MASK 0xffff +#define EMAC_STACR_PHYD_SHIFT 16 #define EMAC_STACR_OC 0x00008000 #define EMAC_STACR_PHYE 0x00004000 -#define EMAC_STACR_WRITE 0x00002000 -#define EMAC_STACR_READ 0x00001000 -#define EMAC_STACR_CLK_83MHZ 0x00000800 /* 0's for 50Mhz */ -#define EMAC_STACR_CLK_66MHZ 0x00000400 -#define EMAC_STACR_CLK_100MHZ 0x00000C00 +#define EMAC_STACR_STAC_MASK 0x00003000 +#define EMAC_STACR_STAC_READ 0x00001000 +#define EMAC_STACR_STAC_WRITE 0x00002000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_STACR_OPBC_MASK 0x00000C00 +#define EMAC_STACR_OPBC_50 0x00000000 +#define EMAC_STACR_OPBC_66 0x00000400 +#define EMAC_STACR_OPBC_83 0x00000800 +#define EMAC_STACR_OPBC_100 0x00000C00 +#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ + (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ + (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) +#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) +#else +#define EMAC_STACR_BASE(opb) 0x00000000 +#endif +#define EMAC_STACR_PCDA_MASK 0x1f +#define EMAC_STACR_PCDA_SHIFT 5 +#define EMAC_STACR_PRA_MASK 0x1f -/* Transmit Request Threshold Register */ -#define EMAC_TRTR_1600 0x18000000 /* 0's for 64 Bytes */ -#define EMAC_TRTR_1024 0x0f000000 -#define EMAC_TRTR_512 0x07000000 -#define EMAC_TRTR_256 0x03000000 -#define EMAC_TRTR_192 0x10000000 -#define EMAC_TRTR_128 0x01000000 +/* EMACx_TRTR */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TRTR_SHIFT 27 +#else +#define EMAC_TRTR_SHIFT 24 +#endif +#define EMAC_TRTR(size) ((((size) >> 6) - 1) << EMAC_TRTR_SHIFT) +/* EMACx_RWMR */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_RWMR(l,h) (((l) << 23) | ( ((h) & 0x1ff) << 7)) +#else +#define EMAC_RWMR(l,h) (((l) << 22) | ( ((h) & 0x3ff) << 6)) +#endif + +/* EMAC specific TX descriptor control fields (write access) */ #define EMAC_TX_CTRL_GFCS 0x0200 #define EMAC_TX_CTRL_GP 0x0100 #define EMAC_TX_CTRL_ISA 0x0080 #define EMAC_TX_CTRL_RSA 0x0040 #define EMAC_TX_CTRL_IVT 0x0020 #define EMAC_TX_CTRL_RVT 0x0010 -#define EMAC_TX_CTRL_TAH_CSUM 0x000e /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG4 0x000a /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG3 0x0008 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG2 0x0006 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG1 0x0004 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG0 0x0002 /* TAH only */ -#define EMAC_TX_CTRL_TAH_DIS 0x0000 /* TAH only */ +#define EMAC_TX_CTRL_TAH_CSUM 0x000e -#define EMAC_TX_CTRL_DFLT ( \ - MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP ) - -/* madmal transmit status / Control bits */ +/* EMAC specific TX descriptor status fields (read access) */ #define EMAC_TX_ST_BFCS 0x0200 -#define EMAC_TX_ST_BPP 0x0100 #define EMAC_TX_ST_LCS 0x0080 #define EMAC_TX_ST_ED 0x0040 #define EMAC_TX_ST_EC 0x0020 @@ -202,8 +280,16 @@ typedef struct emac_regs { #define EMAC_TX_ST_SC 0x0004 #define EMAC_TX_ST_UR 0x0002 #define EMAC_TX_ST_SQE 0x0001 +#if !defined(CONFIG_IBM_EMAC_TAH) +#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ + EMAC_TX_ST_MC | EMAC_TX_ST_UR)) +#else +#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC)) +#endif -/* madmal receive status / Control bits */ +/* EMAC specific RX descriptor status fields (read access) */ #define EMAC_RX_ST_OE 0x0200 #define EMAC_RX_ST_PP 0x0100 #define EMAC_RX_ST_BP 0x0080 @@ -214,54 +300,10 @@ typedef struct emac_regs { #define EMAC_RX_ST_PTL 0x0004 #define EMAC_RX_ST_ORE 0x0002 #define EMAC_RX_ST_IRE 0x0001 -#define EMAC_BAD_RX_PACKET 0x02ff -#define EMAC_CSUM_VER_ERROR 0x0003 - -/* identify a bad rx packet dependent on emac features */ -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_IS_BAD_RX_PACKET(desc) \ - (((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \ - ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \ - ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE))) -#else -#define EMAC_IS_BAD_RX_PACKET(desc) \ - (desc & EMAC_BAD_RX_PACKET) -#endif - -/* SoC implementation specific EMAC register defaults */ -#if defined(CONFIG_440GP) -#define EMAC_RWMR_DEFAULT 0x80009000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0xf8640000 -#elif defined(CONFIG_440GX) -#define EMAC_RWMR_DEFAULT 0x1000a200 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 -#define EMAC_TMR1_DEFAULT 0xa00f0000 -#elif defined(CONFIG_440SP) -#define EMAC_RWMR_DEFAULT 0x08002000 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 -#define EMAC_TMR1_DEFAULT 0xf8200000 -#else -#define EMAC_RWMR_DEFAULT 0x0f002000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0x380f0000 -#endif /* CONFIG_440GP */ - -/* Revision specific EMAC register defaults */ -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ - EMAC_M1_OPB_CLK_83 | \ - EMAC_M1_TX_MWSW) -#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ - EMAC_RMR_RFAF_128_2048) -#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ - EMAC_TMR0_DEFAULT) -#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 -#else /* !CONFIG_IBM_EMAC4 */ -#define EMAC_M1_DEFAULT EMAC_M1_BASE -#define EMAC_RMR_DEFAULT EMAC_RMR_BASE -#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0 -#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 -#endif /* CONFIG_IBM_EMAC4 */ - -#endif +#define EMAC_RX_TAH_BAD_CSUM 0x0003 +#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ + EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ + EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ + EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ + EMAC_RX_ST_IRE ) +#endif /* __IBM_EMAC_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 14e9b6315f20..943fbd1546ff 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1,13 +1,14 @@ /* - * ibm_emac_core.c + * drivers/net/ibm_emac/ibm_emac_core.c * - * Ethernet driver for the built in ethernet on the IBM 4xx PowerPC - * processors. - * - * (c) 2003 Benjamin Herrenschmidt + * Driver for PowerPC 4xx on-chip ethernet controller. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or * * Based on original work by - * + * Matt Porter + * (c) 2003 Benjamin Herrenschmidt * Armin Kuster * Johnnie Peters * @@ -15,29 +16,24 @@ * 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. - * TODO - * - Check for races in the "remove" code path - * - Add some Power Management to the MAC and the PHY - * - Audit remaining of non-rewritten code (--BenH) - * - Cleanup message display using msglevel mecanism - * - Address all errata - * - Audit all register update paths to ensure they - * are being written post soft reset if required. + * */ + +#include #include #include #include #include -#include -#include #include -#include -#include #include #include #include #include -#include +#include +#include +#include +#include +#include #include #include #include @@ -45,1691 +41,1893 @@ #include #include #include -#include #include #include -#include -#include -#include -#include - #include "ibm_emac_core.h" - -//#define MDIO_DEBUG(fmt) printk fmt -#define MDIO_DEBUG(fmt) - -//#define LINK_DEBUG(fmt) printk fmt -#define LINK_DEBUG(fmt) - -//#define PKT_DEBUG(fmt) printk fmt -#define PKT_DEBUG(fmt) - -#define DRV_NAME "emac" -#define DRV_VERSION "2.0" -#define DRV_AUTHOR "Benjamin Herrenschmidt " -#define DRV_DESC "IBM EMAC Ethernet driver" +#include "ibm_emac_debug.h" /* - * When mdio_idx >= 0, contains a list of emac ocp_devs - * that have had their initialization deferred until the - * common MDIO controller has been initialized. + * Lack of dma_unmap_???? calls is intentional. + * + * API-correct usage requires additional support state information to be + * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to + * EMAC design (e.g. TX buffer passed from network stack can be split into + * several BDs, dma_map_single/dma_map_page can be used to map particular BD), + * maintaining such information will add additional overhead. + * Current DMA API implementation for 4xx processors only ensures cache coherency + * and dma_unmap_???? routines are empty and are likely to stay this way. + * I decided to omit dma_unmap_??? calls because I don't want to add additional + * complexity just for the sake of following some abstract API, when it doesn't + * add any real benefit to the driver. I understand that this decision maybe + * controversial, but I really tried to make code API-correct and efficient + * at the same time and didn't come up with code I liked :(. --ebs */ -LIST_HEAD(emac_init_list); -MODULE_AUTHOR(DRV_AUTHOR); +#define DRV_NAME "emac" +#define DRV_VERSION "3.53" +#define DRV_DESC "PPC 4xx OCP EMAC driver" + MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR + ("Eugene Surovegin or "); MODULE_LICENSE("GPL"); -static int skb_res = SKB_RES; -module_param(skb_res, int, 0444); -MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n" - "The 405 handles a misaligned IP header fine but\n" - "this can help if you are routing to a tunnel or a\n" - "device that needs aligned data. 0..2"); +/* minimum number of free TX descriptors required to wake up TX process */ +#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) -#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev)) - -static unsigned int rgmii_enable[] = { - RGMII_RTBI, - RGMII_RGMII, - RGMII_TBI, - RGMII_GMII -}; - -static unsigned int rgmii_speed_mask[] = { - RGMII_MII2_SPDMASK, - RGMII_MII3_SPDMASK -}; - -static unsigned int rgmii_speed100[] = { - RGMII_MII2_100MB, - RGMII_MII3_100MB -}; - -static unsigned int rgmii_speed1000[] = { - RGMII_MII2_1000MB, - RGMII_MII3_1000MB -}; - -#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev)) - -static unsigned int zmii_enable[][4] = { - {ZMII_SMII0, ZMII_RMII0, ZMII_MII0, - ~(ZMII_MDI1 | ZMII_MDI2 | ZMII_MDI3)}, - {ZMII_SMII1, ZMII_RMII1, ZMII_MII1, - ~(ZMII_MDI0 | ZMII_MDI2 | ZMII_MDI3)}, - {ZMII_SMII2, ZMII_RMII2, ZMII_MII2, - ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)}, - {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)} -}; - -static unsigned int mdi_enable[] = { - ZMII_MDI0, - ZMII_MDI1, - ZMII_MDI2, - ZMII_MDI3 -}; - -static unsigned int zmii_speed = 0x0; -static unsigned int zmii_speed100[] = { - ZMII_MII0_100MB, - ZMII_MII1_100MB, - ZMII_MII2_100MB, - ZMII_MII3_100MB -}; +/* If packet size is less than this number, we allocate small skb and copy packet + * contents into it instead of just sending original big skb up + */ +#define EMAC_RX_COPY_THRESH CONFIG_IBM_EMAC_RX_COPY_THRESHOLD /* Since multiple EMACs share MDIO lines in various ways, we need * to avoid re-using the same PHY ID in cases where the arch didn't * setup precise phy_map entries */ -static u32 busy_phy_map = 0; +static u32 busy_phy_map; -/* If EMACs share a common MDIO device, this points to it */ -static struct net_device *mdio_ndev = NULL; - -struct emac_def_dev { - struct list_head link; - struct ocp_device *ocpdev; - struct ibm_ocp_mal *mal; -}; - -static struct net_device_stats *emac_stats(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - return &fep->stats; -}; - -static int -emac_init_rgmii(struct ocp_device *rgmii_dev, int input, int phy_mode) -{ - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(rgmii_dev); - const char *mode_name[] = { "RTBI", "RGMII", "TBI", "GMII" }; - int mode = -1; - - if (!rgmii) { - rgmii = kmalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); - - if (rgmii == NULL) { - printk(KERN_ERR - "rgmii%d: Out of memory allocating RGMII structure!\n", - rgmii_dev->def->index); - return -ENOMEM; - } - - memset(rgmii, 0, sizeof(*rgmii)); - - rgmii->base = - (struct rgmii_regs *)ioremap(rgmii_dev->def->paddr, - sizeof(*rgmii->base)); - if (rgmii->base == NULL) { - printk(KERN_ERR - "rgmii%d: Cannot ioremap bridge registers!\n", - rgmii_dev->def->index); - - kfree(rgmii); - return -ENOMEM; - } - ocp_set_drvdata(rgmii_dev, rgmii); - } - - if (phy_mode) { - switch (phy_mode) { - case PHY_MODE_GMII: - mode = GMII; - break; - case PHY_MODE_TBI: - mode = TBI; - break; - case PHY_MODE_RTBI: - mode = RTBI; - break; - case PHY_MODE_RGMII: - default: - mode = RGMII; - } - rgmii->base->fer &= ~RGMII_FER_MASK(input); - rgmii->base->fer |= rgmii_enable[mode] << (4 * input); - } else { - switch ((rgmii->base->fer & RGMII_FER_MASK(input)) >> (4 * - input)) { - case RGMII_RTBI: - mode = RTBI; - break; - case RGMII_RGMII: - mode = RGMII; - break; - case RGMII_TBI: - mode = TBI; - break; - case RGMII_GMII: - mode = GMII; - } - } - - /* Set mode to RGMII if nothing valid is detected */ - if (mode < 0) - mode = RGMII; - - printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", - rgmii_dev->def->index, input, mode_name[mode]); - - rgmii->mode[input] = mode; - rgmii->users++; - - return 0; -} - -static void -emac_rgmii_port_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); - unsigned int rgmii_speed; - - rgmii_speed = in_be32(&rgmii->base->ssr); - - rgmii_speed &= ~rgmii_speed_mask[input]; - - if (speed == 1000) - rgmii_speed |= rgmii_speed1000[input]; - else if (speed == 100) - rgmii_speed |= rgmii_speed100[input]; - - out_be32(&rgmii->base->ssr, rgmii_speed); -} - -static void emac_close_rgmii(struct ocp_device *ocpdev) -{ - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); - BUG_ON(!rgmii || rgmii->users == 0); - - if (!--rgmii->users) { - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)rgmii->base); - kfree(rgmii); - } -} - -static int emac_init_zmii(struct ocp_device *zmii_dev, int input, int phy_mode) -{ - struct ibm_ocp_zmii *zmii = ZMII_PRIV(zmii_dev); - const char *mode_name[] = { "SMII", "RMII", "MII" }; - int mode = -1; - - if (!zmii) { - zmii = kmalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); - if (zmii == NULL) { - printk(KERN_ERR - "zmii%d: Out of memory allocating ZMII structure!\n", - zmii_dev->def->index); - return -ENOMEM; - } - memset(zmii, 0, sizeof(*zmii)); - - zmii->base = - (struct zmii_regs *)ioremap(zmii_dev->def->paddr, - sizeof(*zmii->base)); - if (zmii->base == NULL) { - printk(KERN_ERR - "zmii%d: Cannot ioremap bridge registers!\n", - zmii_dev->def->index); - - kfree(zmii); - return -ENOMEM; - } - ocp_set_drvdata(zmii_dev, zmii); - } - - if (phy_mode) { - switch (phy_mode) { - case PHY_MODE_MII: - mode = MII; - break; - case PHY_MODE_RMII: - mode = RMII; - break; - case PHY_MODE_SMII: - default: - mode = SMII; - } - zmii->base->fer &= ~ZMII_FER_MASK(input); - zmii->base->fer |= zmii_enable[input][mode]; - } else { - switch ((zmii->base->fer & ZMII_FER_MASK(input)) << (4 * input)) { - case ZMII_MII0: - mode = MII; - break; - case ZMII_RMII0: - mode = RMII; - break; - case ZMII_SMII0: - mode = SMII; - } - } - - /* Set mode to SMII if nothing valid is detected */ - if (mode < 0) - mode = SMII; - - printk(KERN_NOTICE "zmii%d: input %d in %s mode\n", - zmii_dev->def->index, input, mode_name[mode]); - - zmii->mode[input] = mode; - zmii->users++; - - return 0; -} - -static void emac_enable_zmii_port(struct ocp_device *ocpdev, int input) -{ - u32 mask; - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - - mask = in_be32(&zmii->base->fer); - mask &= zmii_enable[input][MDI]; /* turn all non enabled MDI's off */ - mask |= zmii_enable[input][zmii->mode[input]] | mdi_enable[input]; - out_be32(&zmii->base->fer, mask); -} - -static void -emac_zmii_port_speed(struct ocp_device *ocpdev, int input, int speed) -{ - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - - if (speed == 100) - zmii_speed |= zmii_speed100[input]; - else - zmii_speed &= ~zmii_speed100[input]; - - out_be32(&zmii->base->ssr, zmii_speed); -} - -static void emac_close_zmii(struct ocp_device *ocpdev) -{ - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - BUG_ON(!zmii || zmii->users == 0); - - if (!--zmii->users) { - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)zmii->base); - kfree(zmii); - } -} - -int emac_phy_read(struct net_device *dev, int mii_id, int reg) -{ - int count; - uint32_t stacr; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - - MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id, - reg)); - - /* Enable proper ZMII port */ - if (fep->zmii_dev) - emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); - - /* Use the EMAC that has the MDIO port */ - if (fep->mdio_dev) { - dev = fep->mdio_dev; - fep = dev->priv; - emacp = fep->emacp; - } - - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); - - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name); - return -1; - } - - /* Clear the speed bits and make a read request to the PHY */ - stacr = ((EMAC_STACR_READ | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); - stacr |= ((mii_id & 0x1F) << 5); - - out_be32(&emacp->em0stacr, stacr); - - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); - - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name); - return -1; - } - - /* Check for a read error */ - if (stacr & EMAC_STACR_PHYE) { - MDIO_DEBUG(("EMAC MDIO PHY error !\n")); - return -1; - } - - MDIO_DEBUG((" -> 0x%x\n", stacr >> 16)); - - return (stacr >> 16); -} - -void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) -{ - int count; - uint32_t stacr; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - - MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n", - dev->name, mii_id, reg, data)); - - /* Enable proper ZMII port */ - if (fep->zmii_dev) - emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); - - /* Use the EMAC that has the MDIO port */ - if (fep->mdio_dev) { - dev = fep->mdio_dev; - fep = dev->priv; - emacp = fep->emacp; - } - - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); - - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); - return; - } - - /* Clear the speed bits and make a read request to the PHY */ - - stacr = ((EMAC_STACR_WRITE | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); - stacr |= ((mii_id & 0x1f) << 5) | ((data & 0xffff) << 16); - - out_be32(&emacp->em0stacr, stacr); - - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); - - if ((stacr & EMAC_STACR_OC) == 0) - printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); - - /* Check for a write error */ - if ((stacr & EMAC_STACR_PHYE) != 0) { - MDIO_DEBUG(("EMAC MDIO PHY error !\n")); - } -} - -static void emac_txeob_dev(void *param, u32 chanmask) -{ - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&fep->lock, flags); - - PKT_DEBUG(("emac_txeob_dev() entry, tx_cnt: %d\n", fep->tx_cnt)); - - while (fep->tx_cnt && - !(fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_READY)) { - - if (fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_LAST) { - /* Tell the system the transmit completed. */ - dma_unmap_single(&fep->ocpdev->dev, - fep->tx_desc[fep->ack_slot].data_ptr, - fep->tx_desc[fep->ack_slot].data_len, - DMA_TO_DEVICE); - dev_kfree_skb_irq(fep->tx_skb[fep->ack_slot]); - - if (fep->tx_desc[fep->ack_slot].ctrl & - (EMAC_TX_ST_EC | EMAC_TX_ST_MC | EMAC_TX_ST_SC)) - fep->stats.collisions++; - } - - fep->tx_skb[fep->ack_slot] = (struct sk_buff *)NULL; - if (++fep->ack_slot == NUM_TX_BUFF) - fep->ack_slot = 0; - - fep->tx_cnt--; - } - if (fep->tx_cnt < NUM_TX_BUFF) - netif_wake_queue(dev); - - PKT_DEBUG(("emac_txeob_dev() exit, tx_cnt: %d\n", fep->tx_cnt)); - - spin_unlock_irqrestore(&fep->lock, flags); -} - -/* - Fill/Re-fill the rx chain with valid ctrl/ptrs. - This function will fill from rx_slot up to the parm end. - So to completely fill the chain pre-set rx_slot to 0 and - pass in an end of 0. +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && (defined(CONFIG_405EP) || defined(CONFIG_440EP)) +/* 405EP has "EMAC to PHY Control Register" (CPC0_EPCTL) which can help us + * with PHY RX clock problem. + * 440EP has more sane SDR0_MFR register implementation than 440GX, which + * also allows controlling each EMAC clock */ -static void emac_rx_fill(struct net_device *dev, int end) +static inline void EMAC_RX_CLK_TX(int idx) { - int i; - struct ocp_enet_private *fep = dev->priv; - - i = fep->rx_slot; - do { - /* We don't want the 16 bytes skb_reserve done by dev_alloc_skb, - * it breaks our cache line alignement. However, we still allocate - * +16 so that we end up allocating the exact same size as - * dev_alloc_skb() would do. - * Also, because of the skb_res, the max DMA size we give to EMAC - * is slighly wrong, causing it to potentially DMA 2 more bytes - * from a broken/oversized packet. These 16 bytes will take care - * that we don't walk on somebody else toes with that. - */ - fep->rx_skb[i] = - alloc_skb(fep->rx_buffer_size + 16, GFP_ATOMIC); - - if (fep->rx_skb[i] == NULL) { - /* Keep rx_slot here, the next time clean/fill is called - * we will try again before the MAL wraps back here - * If the MAL tries to use this descriptor with - * the EMPTY bit off it will cause the - * rxde interrupt. That is where we will - * try again to allocate an sk_buff. - */ - break; - - } - - if (skb_res) - skb_reserve(fep->rx_skb[i], skb_res); - - /* We must NOT dma_map_single the cache line right after the - * buffer, so we must crop our sync size to account for the - * reserved space - */ - fep->rx_desc[i].data_ptr = - (unsigned char *)dma_map_single(&fep->ocpdev->dev, - (void *)fep->rx_skb[i]-> - data, - fep->rx_buffer_size - - skb_res, DMA_FROM_DEVICE); - - /* - * Some 4xx implementations use the previously - * reserved bits in data_len to encode the MS - * 4-bits of a 36-bit physical address (ERPN) - * This must be initialized. - */ - fep->rx_desc[i].data_len = 0; - fep->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR | - (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - - } while ((i = (i + 1) % NUM_RX_BUFF) != end); - - fep->rx_slot = i; -} - -static void -emac_rx_csum(struct net_device *dev, unsigned short ctrl, struct sk_buff *skb) -{ - struct ocp_enet_private *fep = dev->priv; - - /* Exit if interface has no TAH engine */ - if (!fep->tah_dev) { - skb->ip_summed = CHECKSUM_NONE; - return; - } - - /* Check for TCP/UDP/IP csum error */ - if (ctrl & EMAC_CSUM_VER_ERROR) { - /* Let the stack verify checksum errors */ - skb->ip_summed = CHECKSUM_NONE; -/* adapter->hw_csum_err++; */ - } else { - /* Csum is good */ - skb->ip_summed = CHECKSUM_UNNECESSARY; -/* adapter->hw_csum_good++; */ - } -} - -static int emac_rx_clean(struct net_device *dev) -{ - int i, b, bnum = 0, buf[6]; - int error, frame_length; - struct ocp_enet_private *fep = dev->priv; - unsigned short ctrl; - - i = fep->rx_slot; - - PKT_DEBUG(("emac_rx_clean() entry, rx_slot: %d\n", fep->rx_slot)); - - do { - if (fep->rx_skb[i] == NULL) - continue; /*we have already handled the packet but haved failed to alloc */ - /* - since rx_desc is in uncached mem we don't keep reading it directly - we pull out a local copy of ctrl and do the checks on the copy. - */ - ctrl = fep->rx_desc[i].ctrl; - if (ctrl & MAL_RX_CTRL_EMPTY) - break; /*we don't have any more ready packets */ - - if (EMAC_IS_BAD_RX_PACKET(ctrl)) { - fep->stats.rx_errors++; - fep->stats.rx_dropped++; - - if (ctrl & EMAC_RX_ST_OE) - fep->stats.rx_fifo_errors++; - if (ctrl & EMAC_RX_ST_AE) - fep->stats.rx_frame_errors++; - if (ctrl & EMAC_RX_ST_BFCS) - fep->stats.rx_crc_errors++; - if (ctrl & (EMAC_RX_ST_RP | EMAC_RX_ST_PTL | - EMAC_RX_ST_ORE | EMAC_RX_ST_IRE)) - fep->stats.rx_length_errors++; - } else { - if ((ctrl & (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) == - (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) { - /* Single descriptor packet */ - emac_rx_csum(dev, ctrl, fep->rx_skb[i]); - /* Send the skb up the chain. */ - frame_length = fep->rx_desc[i].data_len - 4; - skb_put(fep->rx_skb[i], frame_length); - fep->rx_skb[i]->dev = dev; - fep->rx_skb[i]->protocol = - eth_type_trans(fep->rx_skb[i], dev); - error = netif_rx(fep->rx_skb[i]); - - if ((error == NET_RX_DROP) || - (error == NET_RX_BAD)) { - fep->stats.rx_dropped++; - } else { - fep->stats.rx_packets++; - fep->stats.rx_bytes += frame_length; - } - fep->rx_skb[i] = NULL; - } else { - /* Multiple descriptor packet */ - if (ctrl & MAL_RX_CTRL_FIRST) { - if (fep->rx_desc[(i + 1) % NUM_RX_BUFF]. - ctrl & MAL_RX_CTRL_EMPTY) - break; - bnum = 0; - buf[bnum] = i; - ++bnum; - continue; - } - if (((ctrl & MAL_RX_CTRL_FIRST) != - MAL_RX_CTRL_FIRST) && - ((ctrl & MAL_RX_CTRL_LAST) != - MAL_RX_CTRL_LAST)) { - if (fep->rx_desc[(i + 1) % - NUM_RX_BUFF].ctrl & - MAL_RX_CTRL_EMPTY) { - i = buf[0]; - break; - } - buf[bnum] = i; - ++bnum; - continue; - } - if (ctrl & MAL_RX_CTRL_LAST) { - buf[bnum] = i; - ++bnum; - skb_put(fep->rx_skb[buf[0]], - fep->rx_desc[buf[0]].data_len); - for (b = 1; b < bnum; b++) { - /* - * MAL is braindead, we need - * to copy the remainder - * of the packet from the - * latter descriptor buffers - * to the first skb. Then - * dispose of the source - * skbs. - * - * Once the stack is fixed - * to handle frags on most - * protocols we can generate - * a fragmented skb with - * no copies. - */ - memcpy(fep->rx_skb[buf[0]]-> - data + - fep->rx_skb[buf[0]]->len, - fep->rx_skb[buf[b]]-> - data, - fep->rx_desc[buf[b]]. - data_len); - skb_put(fep->rx_skb[buf[0]], - fep->rx_desc[buf[b]]. - data_len); - dma_unmap_single(&fep->ocpdev-> - dev, - fep-> - rx_desc[buf - [b]]. - data_ptr, - fep-> - rx_desc[buf - [b]]. - data_len, - DMA_FROM_DEVICE); - dev_kfree_skb(fep-> - rx_skb[buf[b]]); - } - emac_rx_csum(dev, ctrl, - fep->rx_skb[buf[0]]); - - fep->rx_skb[buf[0]]->dev = dev; - fep->rx_skb[buf[0]]->protocol = - eth_type_trans(fep->rx_skb[buf[0]], - dev); - error = netif_rx(fep->rx_skb[buf[0]]); - - if ((error == NET_RX_DROP) - || (error == NET_RX_BAD)) { - fep->stats.rx_dropped++; - } else { - fep->stats.rx_packets++; - fep->stats.rx_bytes += - fep->rx_skb[buf[0]]->len; - } - for (b = 0; b < bnum; b++) - fep->rx_skb[buf[b]] = NULL; - } - } - } - } while ((i = (i + 1) % NUM_RX_BUFF) != fep->rx_slot); - - PKT_DEBUG(("emac_rx_clean() exit, rx_slot: %d\n", fep->rx_slot)); - - return i; -} - -static void emac_rxeob_dev(void *param, u32 chanmask) -{ - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; unsigned long flags; + local_irq_save(flags); + +#if defined(CONFIG_405EP) + mtdcr(0xf3, mfdcr(0xf3) | (1 << idx)); +#else /* CONFIG_440EP */ + SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) | (0x08000000 >> idx)); +#endif + + local_irq_restore(flags); +} + +static inline void EMAC_RX_CLK_DEFAULT(int idx) +{ + unsigned long flags; + local_irq_save(flags); + +#if defined(CONFIG_405EP) + mtdcr(0xf3, mfdcr(0xf3) & ~(1 << idx)); +#else /* CONFIG_440EP */ + SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~(0x08000000 >> idx)); +#endif + + local_irq_restore(flags); +} +#else +#define EMAC_RX_CLK_TX(idx) ((void)0) +#define EMAC_RX_CLK_DEFAULT(idx) ((void)0) +#endif + +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && defined(CONFIG_440GX) +/* We can switch Ethernet clock to the internal source through SDR0_MFR[ECS], + * unfortunately this is less flexible than 440EP case, because it's a global + * setting for all EMACs, therefore we do this clock trick only during probe. + */ +#define EMAC_CLK_INTERNAL SDR_WRITE(DCRN_SDR_MFR, \ + SDR_READ(DCRN_SDR_MFR) | 0x08000000) +#define EMAC_CLK_EXTERNAL SDR_WRITE(DCRN_SDR_MFR, \ + SDR_READ(DCRN_SDR_MFR) & ~0x08000000) +#else +#define EMAC_CLK_INTERNAL ((void)0) +#define EMAC_CLK_EXTERNAL ((void)0) +#endif + +/* I don't want to litter system log with timeout errors + * when we have brain-damaged PHY. + */ +static inline void emac_report_timeout_error(struct ocp_enet_private *dev, + const char *error) +{ +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) + DBG("%d: %s" NL, dev->def->index, error); +#else + if (net_ratelimit()) + printk(KERN_ERR "emac%d: %s\n", dev->def->index, error); +#endif +} + +/* PHY polling intervals */ +#define PHY_POLL_LINK_ON HZ +#define PHY_POLL_LINK_OFF (HZ / 5) + +/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ +static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", + "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", + "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", + "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", + "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", + "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", + "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", + "rx_bad_packet", "rx_runt_packet", "rx_short_event", + "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", + "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", + "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", + "tx_bd_excessive_collisions", "tx_bd_late_collision", + "tx_bd_multple_collisions", "tx_bd_single_collision", + "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", + "tx_errors" +}; + +static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs); +static void emac_clean_tx_ring(struct ocp_enet_private *dev); + +static inline int emac_phy_supports_gige(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline int emac_phy_gpcs(int phy_mode) +{ + return phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline void emac_tx_enable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; + + local_irq_save(flags); + + DBG("%d: tx_enable" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_TXE)) + out_be32(&p->mr0, r | EMAC_MR0_TXE); + local_irq_restore(flags); +} + +static void emac_tx_disable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; + + local_irq_save(flags); + + DBG("%d: tx_disable" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_TXE) { + int n = 300; + out_be32(&p->mr0, r & ~EMAC_MR0_TXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, "TX disable timeout"); + } + local_irq_restore(flags); +} + +static void emac_rx_enable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; + + local_irq_save(flags); + if (unlikely(dev->commac.rx_stopped)) + goto out; + + DBG("%d: rx_enable" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_RXE)) { + if (unlikely(!(r & EMAC_MR0_RXI))) { + /* Wait if previous async disable is still in progress */ + int n = 100; + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, + "RX disable timeout"); + } + out_be32(&p->mr0, r | EMAC_MR0_RXE); + } + out: + local_irq_restore(flags); +} + +static void emac_rx_disable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; + + local_irq_save(flags); + + DBG("%d: rx_disable" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) { + int n = 300; + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, "RX disable timeout"); + } + local_irq_restore(flags); +} + +static inline void emac_rx_disable_async(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; + + local_irq_save(flags); + + DBG("%d: rx_disable_async" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + local_irq_restore(flags); +} + +static int emac_reset(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + int n = 20; + + DBG("%d: reset" NL, dev->def->index); + + local_irq_save(flags); + + if (!dev->reset_failed) { + /* 40x erratum suggests stopping RX channel before reset, + * we stop TX as well + */ + emac_rx_disable(dev); + emac_tx_disable(dev); + } + + out_be32(&p->mr0, EMAC_MR0_SRST); + while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) + --n; + local_irq_restore(flags); + + if (n) { + dev->reset_failed = 0; + return 0; + } else { + emac_report_timeout_error(dev, "reset timeout"); + dev->reset_failed = 1; + return -ETIMEDOUT; + } +} + +static void emac_hash_mc(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + u16 gaht[4] = { 0 }; + struct dev_mc_list *dmi; + + DBG("%d: hash_mc %d" NL, dev->def->index, dev->ndev->mc_count); + + for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { + int bit; + DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL, + dev->def->index, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + + bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); + gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); + } + out_be32(&p->gaht1, gaht[0]); + out_be32(&p->gaht2, gaht[1]); + out_be32(&p->gaht3, gaht[2]); + out_be32(&p->gaht4, gaht[3]); +} + +static inline u32 emac_iff2rmr(struct net_device *ndev) +{ + u32 r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE | + EMAC_RMR_BASE; + + if (ndev->flags & IFF_PROMISC) + r |= EMAC_RMR_PME; + else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) + r |= EMAC_RMR_PMME; + else if (ndev->mc_count > 0) + r |= EMAC_RMR_MAE; + + return r; +} + +static inline int emac_opb_mhz(void) +{ + return (ocp_sys_info.opb_bus_freq + 500000) / 1000000; +} + +/* BHs disabled */ +static int emac_configure(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + struct net_device *ndev = dev->ndev; + int gige; + u32 r; + + DBG("%d: configure" NL, dev->def->index); + + if (emac_reset(dev) < 0) + return -ETIMEDOUT; + + tah_reset(dev->tah_dev); + + /* Mode register */ + r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; + if (dev->phy.duplex == DUPLEX_FULL) + r |= EMAC_MR1_FDE; + switch (dev->phy.speed) { + case SPEED_1000: + if (emac_phy_gpcs(dev->phy.mode)) { + r |= EMAC_MR1_MF_1000GPCS | + EMAC_MR1_MF_IPPA(dev->phy.address); + + /* Put some arbitrary OUI, Manuf & Rev IDs so we can + * identify this GPCS PHY later. + */ + out_be32(&p->ipcr, 0xdeadbeef); + } else + r |= EMAC_MR1_MF_1000; + r |= EMAC_MR1_RFS_16K; + gige = 1; + + if (dev->ndev->mtu > ETH_DATA_LEN) + r |= EMAC_MR1_JPSM; + break; + case SPEED_100: + r |= EMAC_MR1_MF_100; + /* Fall through */ + default: + r |= EMAC_MR1_RFS_4K; + gige = 0; + break; + } + + if (dev->rgmii_dev) + rgmii_set_speed(dev->rgmii_dev, dev->rgmii_input, + dev->phy.speed); + else + zmii_set_speed(dev->zmii_dev, dev->zmii_input, dev->phy.speed); + +#if !defined(CONFIG_40x) + /* on 40x erratum forces us to NOT use integrated flow control, + * let's hope it works on 44x ;) + */ + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + r |= EMAC_MR1_EIFC | EMAC_MR1_APP; + else if (dev->phy.asym_pause) + r |= EMAC_MR1_APP; + } +#endif + out_be32(&p->mr1, r); + + /* Set individual MAC address */ + out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); + out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | + (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | + ndev->dev_addr[5]); + + /* VLAN Tag Protocol ID */ + out_be32(&p->vtpid, 0x8100); + + /* Receive mode register */ + r = emac_iff2rmr(ndev); + if (r & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, r); + + /* FIFOs thresholds */ + r = EMAC_TMR1((EMAC_MAL_BURST_SIZE / EMAC_FIFO_ENTRY_SIZE) + 1, + EMAC_TX_FIFO_SIZE / 2 / EMAC_FIFO_ENTRY_SIZE); + out_be32(&p->tmr1, r); + out_be32(&p->trtr, EMAC_TRTR(EMAC_TX_FIFO_SIZE / 2)); + + /* PAUSE frame is sent when RX FIFO reaches its high-water mark, + there should be still enough space in FIFO to allow the our link + partner time to process this frame and also time to send PAUSE + frame itself. + + Here is the worst case scenario for the RX FIFO "headroom" + (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): + + 1) One maximum-length frame on TX 1522 bytes + 2) One PAUSE frame time 64 bytes + 3) PAUSE frame decode time allowance 64 bytes + 4) One maximum-length frame on RX 1522 bytes + 5) Round-trip propagation delay of the link (100Mb) 15 bytes + ---------- + 3187 bytes + + I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) + low-water mark to RX_FIFO_SIZE / 8 (512 bytes) + */ + r = EMAC_RWMR(EMAC_RX_FIFO_SIZE(gige) / 8 / EMAC_FIFO_ENTRY_SIZE, + EMAC_RX_FIFO_SIZE(gige) / 4 / EMAC_FIFO_ENTRY_SIZE); + out_be32(&p->rwmr, r); + + /* Set PAUSE timer to the maximum */ + out_be32(&p->ptr, 0xffff); + + /* IRQ sources */ + out_be32(&p->iser, EMAC_ISR_TXPE | EMAC_ISR_RXPE | /* EMAC_ISR_TXUE | + EMAC_ISR_RXOE | */ EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | + EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | + EMAC_ISR_IRE | EMAC_ISR_TE); + + /* We need to take GPCS PHY out of isolate mode after EMAC reset */ + if (emac_phy_gpcs(dev->phy.mode)) + mii_reset_phy(&dev->phy); + + return 0; +} + +/* BHs disabled */ +static void emac_reinitialize(struct ocp_enet_private *dev) +{ + DBG("%d: reinitialize" NL, dev->def->index); + + if (!emac_configure(dev)) { + emac_tx_enable(dev); + emac_rx_enable(dev); + } +} + +/* BHs disabled */ +static void emac_full_tx_reset(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + DBG("%d: full_tx_reset" NL, dev->def->index); + + emac_tx_disable(dev); + mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); + emac_clean_tx_ring(dev); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; + + emac_configure(dev); + + mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + + netif_wake_queue(ndev); +} + +static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) +{ + struct emac_regs *p = dev->emacp; + u32 r; int n; - spin_lock_irqsave(&fep->lock, flags); - if ((n = emac_rx_clean(dev)) != fep->rx_slot) - emac_rx_fill(dev, n); - spin_unlock_irqrestore(&fep->lock, flags); -} + DBG2("%d: mdio_read(%02x,%02x)" NL, dev->def->index, id, reg); -/* - * This interrupt should never occurr, we don't program - * the MAL for contiunous mode. - */ -static void emac_txde_dev(void *param, u32 chanmask) -{ - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; + /* Enable proper MDIO port */ + zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); - printk(KERN_WARNING "%s: transmit descriptor error\n", dev->name); - - emac_mac_dump(dev); - emac_mal_dump(dev); - - /* Reenable the transmit channel */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); -} - -/* - * This interrupt should be very rare at best. This occurs when - * the hardware has a problem with the receive descriptors. The manual - * states that it occurs when the hardware cannot the receive descriptor - * empty bit is not set. The recovery mechanism will be to - * traverse through the descriptors, handle any that are marked to be - * handled and reinitialize each along the way. At that point the driver - * will be restarted. - */ -static void emac_rxde_dev(void *param, u32 chanmask) -{ - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; - unsigned long flags; - - if (net_ratelimit()) { - printk(KERN_WARNING "%s: receive descriptor error\n", - fep->ndev->name); - - emac_mac_dump(dev); - emac_mal_dump(dev); - emac_desc_dump(dev); + /* Wait for management interface to become idle */ + n = 10; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; } - /* Disable RX channel */ - spin_lock_irqsave(&fep->lock, flags); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + /* Issue read command */ + out_be32(&p->stacr, + EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_READ | + (reg & EMAC_STACR_PRA_MASK) + | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT)); - /* For now, charge the error against all emacs */ - fep->stats.rx_errors++; + /* Wait for read to complete */ + n = 100; + while (!((r = in_be32(&p->stacr)) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; + } - /* so do we have any good packets still? */ - emac_rx_clean(dev); + if (unlikely(r & EMAC_STACR_PHYE)) { + DBG("%d: mdio_read(%02x, %02x) failed" NL, dev->def->index, + id, reg); + return -EREMOTEIO; + } - /* When the interface is restarted it resets processing to the - * first descriptor in the table. + r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); + DBG2("%d: mdio_read -> %04x" NL, dev->def->index, r); + return r; + to: + DBG("%d: MII management interface timeout (read)" NL, dev->def->index); + return -ETIMEDOUT; +} + +static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg, + u16 val) +{ + struct emac_regs *p = dev->emacp; + int n; + + DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg, + val); + + /* Enable proper MDIO port */ + zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); + + /* Wait for management interface to be idle */ + n = 10; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; + } + + /* Issue write command */ + out_be32(&p->stacr, + EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_WRITE | + (reg & EMAC_STACR_PRA_MASK) | + ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | + (val << EMAC_STACR_PHYD_SHIFT)); + + /* Wait for write to complete */ + n = 100; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; + } + return; + to: + DBG("%d: MII management interface timeout (write)" NL, dev->def->index); +} + +static int emac_mdio_read(struct net_device *ndev, int id, int reg) +{ + struct ocp_enet_private *dev = ndev->priv; + int res; + + local_bh_disable(); + res = __emac_mdio_read(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, + (u8) reg); + local_bh_enable(); + return res; +} + +static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) +{ + struct ocp_enet_private *dev = ndev->priv; + + local_bh_disable(); + __emac_mdio_write(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, + (u8) reg, (u16) val); + local_bh_enable(); +} + +/* BHs disabled */ +static void emac_set_multicast_list(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct emac_regs *p = dev->emacp; + u32 rmr = emac_iff2rmr(ndev); + + DBG("%d: multicast %08x" NL, dev->def->index, rmr); + BUG_ON(!netif_running(dev->ndev)); + + /* I decided to relax register access rules here to avoid + * full EMAC reset. + * + * There is a real problem with EMAC4 core if we use MWSW_001 bit + * in MR1 register and do a full EMAC reset. + * One TX BD status update is delayed and, after EMAC reset, it + * never happens, resulting in TX hung (it'll be recovered by TX + * timeout handler eventually, but this is just gross). + * So we either have to do full TX reset or try to cheat here :) + * + * The only required change is to RX mode register, so I *think* all + * we need is just to stop RX channel. This seems to work on all + * tested SoCs. --ebs */ - - fep->rx_slot = 0; - emac_rx_fill(dev, 0); - - set_mal_dcrn(fep->mal, DCRN_MALRXEOBISR, fep->commac.rx_chan_mask); - set_mal_dcrn(fep->mal, DCRN_MALRXDEIR, fep->commac.rx_chan_mask); - - /* Reenable the receive channels */ - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - spin_unlock_irqrestore(&fep->lock, flags); + emac_rx_disable(dev); + if (rmr & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, rmr); + emac_rx_enable(dev); } -static irqreturn_t -emac_mac_irq(int irq, void *dev_instance, struct pt_regs *regs) +/* BHs disabled */ +static int emac_resize_rx_ring(struct ocp_enet_private *dev, int new_mtu) { - struct net_device *dev = dev_instance; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - unsigned long tmp_em0isr; + struct ocp_func_emac_data *emacdata = dev->def->additions; + int rx_sync_size = emac_rx_sync_size(new_mtu); + int rx_skb_size = emac_rx_skb_size(new_mtu); + int i, ret = 0; - /* EMAC interrupt */ - tmp_em0isr = in_be32(&emacp->em0isr); - if (tmp_em0isr & (EMAC_ISR_TE0 | EMAC_ISR_TE1)) { - /* This error is a hard transmit error - could retransmit */ - fep->stats.tx_errors++; + emac_rx_disable(dev); + mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); - /* Reenable the transmit channel */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - - } else { - fep->stats.rx_errors++; + if (dev->rx_sg_skb) { + ++dev->estats.rx_dropped_resize; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; } - if (tmp_em0isr & EMAC_ISR_RP) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_ALE) - fep->stats.rx_frame_errors++; - if (tmp_em0isr & EMAC_ISR_BFCS) - fep->stats.rx_crc_errors++; - if (tmp_em0isr & EMAC_ISR_PTLE) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_ORE) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_TE0) - fep->stats.tx_aborted_errors++; + /* Make a first pass over RX ring and mark BDs ready, dropping + * non-processed packets on the way. We need this as a separate pass + * to simplify error recovery in the case of allocation failure later. + */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) + ++dev->estats.rx_dropped_resize; - emac_err_dump(dev, tmp_em0isr); + dev->rx_desc[i].data_len = 0; + dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | + (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + } - out_be32(&emacp->em0isr, tmp_em0isr); + /* Reallocate RX ring only if bigger skb buffers are required */ + if (rx_skb_size <= dev->rx_skb_size) + goto skip; + + /* Second pass, allocate new skbs */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); + if (!skb) { + ret = -ENOMEM; + goto oom; + } + + BUG_ON(!dev->rx_skb[i]); + dev_kfree_skb(dev->rx_skb[i]); + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[i].data_ptr = + dma_map_single(dev->ldev, skb->data - 2, rx_sync_size, + DMA_FROM_DEVICE) + 2; + dev->rx_skb[i] = skb; + } + skip: + /* Check if we need to change "Jumbo" bit in MR1 */ + if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { + /* This is to prevent starting RX channel in emac_rx_enable() */ + dev->commac.rx_stopped = 1; + + dev->ndev->mtu = new_mtu; + emac_full_tx_reset(dev->ndev); + } + + mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(new_mtu)); + oom: + /* Restart RX */ + dev->commac.rx_stopped = dev->rx_slot = 0; + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_rx_enable(dev); + + return ret; +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct ocp_enet_private *dev = ndev->priv; + int ret = 0; + + if (new_mtu < EMAC_MIN_MTU || new_mtu > EMAC_MAX_MTU) + return -EINVAL; + + DBG("%d: change_mtu(%d)" NL, dev->def->index, new_mtu); + + local_bh_disable(); + if (netif_running(ndev)) { + /* Check if we really need to reinitalize RX ring */ + if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) + ret = emac_resize_rx_ring(dev, new_mtu); + } + + if (!ret) { + ndev->mtu = new_mtu; + dev->rx_skb_size = emac_rx_skb_size(new_mtu); + dev->rx_sync_size = emac_rx_sync_size(new_mtu); + } + local_bh_enable(); + + return ret; +} + +static void emac_clean_tx_ring(struct ocp_enet_private *dev) +{ + int i; + for (i = 0; i < NUM_TX_BUFF; ++i) { + if (dev->tx_skb[i]) { + dev_kfree_skb(dev->tx_skb[i]); + dev->tx_skb[i] = NULL; + if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) + ++dev->estats.tx_dropped; + } + dev->tx_desc[i].ctrl = 0; + dev->tx_desc[i].data_ptr = 0; + } +} + +static void emac_clean_rx_ring(struct ocp_enet_private *dev) +{ + int i; + for (i = 0; i < NUM_RX_BUFF; ++i) + if (dev->rx_skb[i]) { + dev->rx_desc[i].ctrl = 0; + dev_kfree_skb(dev->rx_skb[i]); + dev->rx_skb[i] = NULL; + dev->rx_desc[i].data_ptr = 0; + } + + if (dev->rx_sg_skb) { + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } +} + +static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot, + int flags) +{ + struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); + if (unlikely(!skb)) + return -ENOMEM; + + dev->rx_skb[slot] = skb; + dev->rx_desc[slot].data_len = 0; + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[slot].data_ptr = + dma_map_single(dev->ldev, skb->data - 2, dev->rx_sync_size, + DMA_FROM_DEVICE) + 2; + barrier(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + + return 0; +} + +static void emac_print_link_status(struct ocp_enet_private *dev) +{ + if (netif_carrier_ok(dev->ndev)) + printk(KERN_INFO "%s: link is up, %d %s%s\n", + dev->ndev->name, dev->phy.speed, + dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", + dev->phy.pause ? ", pause enabled" : + dev->phy.asym_pause ? ", assymetric pause enabled" : ""); + else + printk(KERN_INFO "%s: link is down\n", dev->ndev->name); +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_open(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; + int err, i; + + DBG("%d: open" NL, dev->def->index); + + /* Setup error IRQ handler */ + err = request_irq(dev->def->irq, emac_irq, 0, "EMAC", dev); + if (err) { + printk(KERN_ERR "%s: failed to request IRQ %d\n", + ndev->name, dev->def->irq); + return err; + } + + /* Allocate RX ring */ + for (i = 0; i < NUM_RX_BUFF; ++i) + if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { + printk(KERN_ERR "%s: failed to allocate RX ring\n", + ndev->name); + goto oom; + } + + local_bh_disable(); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = + dev->commac.rx_stopped = 0; + dev->rx_sg_skb = NULL; + + if (dev->phy.address >= 0) { + int link_poll_interval; + if (dev->phy.def->ops->poll_link(&dev->phy)) { + dev->phy.def->ops->read_link(&dev->phy); + EMAC_RX_CLK_DEFAULT(dev->def->index); + netif_carrier_on(dev->ndev); + link_poll_interval = PHY_POLL_LINK_ON; + } else { + EMAC_RX_CLK_TX(dev->def->index); + netif_carrier_off(dev->ndev); + link_poll_interval = PHY_POLL_LINK_OFF; + } + mod_timer(&dev->link_timer, jiffies + link_poll_interval); + emac_print_link_status(dev); + } else + netif_carrier_on(dev->ndev); + + emac_configure(dev); + mal_poll_add(dev->mal, &dev->commac); + mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); + mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(ndev->mtu)); + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + netif_start_queue(ndev); + local_bh_enable(); + + return 0; + oom: + emac_clean_rx_ring(dev); + free_irq(dev->def->irq, dev); + return -ENOMEM; +} + +/* BHs disabled */ +static int emac_link_differs(struct ocp_enet_private *dev) +{ + u32 r = in_be32(&dev->emacp->mr1); + + int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; + int speed, pause, asym_pause; + + if (r & (EMAC_MR1_MF_1000 | EMAC_MR1_MF_1000GPCS)) + speed = SPEED_1000; + else if (r & EMAC_MR1_MF_100) + speed = SPEED_100; + else + speed = SPEED_10; + + switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { + case (EMAC_MR1_EIFC | EMAC_MR1_APP): + pause = 1; + asym_pause = 0; + break; + case EMAC_MR1_APP: + pause = 0; + asym_pause = 1; + break; + default: + pause = asym_pause = 0; + } + return speed != dev->phy.speed || duplex != dev->phy.duplex || + pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; +} + +/* BHs disabled */ +static void emac_link_timer(unsigned long data) +{ + struct ocp_enet_private *dev = (struct ocp_enet_private *)data; + int link_poll_interval; + + DBG2("%d: link timer" NL, dev->def->index); + + if (dev->phy.def->ops->poll_link(&dev->phy)) { + if (!netif_carrier_ok(dev->ndev)) { + EMAC_RX_CLK_DEFAULT(dev->def->index); + + /* Get new link parameters */ + dev->phy.def->ops->read_link(&dev->phy); + + if (dev->tah_dev || emac_link_differs(dev)) + emac_full_tx_reset(dev->ndev); + + netif_carrier_on(dev->ndev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_ON; + } else { + if (netif_carrier_ok(dev->ndev)) { + EMAC_RX_CLK_TX(dev->def->index); +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) + emac_reinitialize(dev); +#endif + netif_carrier_off(dev->ndev); + emac_print_link_status(dev); + } + + /* Retry reset if the previous attempt failed. + * This is needed mostly for CONFIG_IBM_EMAC_PHY_RX_CLK_FIX + * case, but I left it here because it shouldn't trigger for + * sane PHYs anyway. + */ + if (unlikely(dev->reset_failed)) + emac_reinitialize(dev); + + link_poll_interval = PHY_POLL_LINK_OFF; + } + mod_timer(&dev->link_timer, jiffies + link_poll_interval); +} + +/* BHs disabled */ +static void emac_force_link_update(struct ocp_enet_private *dev) +{ + netif_carrier_off(dev->ndev); + if (timer_pending(&dev->link_timer)) + mod_timer(&dev->link_timer, jiffies + PHY_POLL_LINK_OFF); +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_close(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + DBG("%d: close" NL, dev->def->index); + + local_bh_disable(); + + if (dev->phy.address >= 0) + del_timer_sync(&dev->link_timer); + + netif_stop_queue(ndev); + emac_rx_disable(dev); + emac_tx_disable(dev); + mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); + mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); + mal_poll_del(dev->mal, &dev->commac); + local_bh_enable(); + + emac_clean_tx_ring(dev); + emac_clean_rx_ring(dev); + free_irq(dev->def->irq, dev); + + return 0; +} + +static inline u16 emac_tx_csum(struct ocp_enet_private *dev, + struct sk_buff *skb) +{ +#if defined(CONFIG_IBM_EMAC_TAH) + if (skb->ip_summed == CHECKSUM_HW) { + ++dev->stats.tx_packets_csum; + return EMAC_TX_CTRL_TAH_CSUM; + } +#endif + return 0; +} + +static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len) +{ + struct emac_regs *p = dev->emacp; + struct net_device *ndev = dev->ndev; + + /* Send the packet out */ + out_be32(&p->tmr0, EMAC_TMR0_XMIT); + + if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { + netif_stop_queue(ndev); + DBG2("%d: stopped TX queue" NL, dev->def->index); + } + + ndev->trans_start = jiffies; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += len; + + return 0; +} + +/* BHs disabled */ +static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + unsigned int len = skb->len; + int slot; + + u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); + + slot = dev->tx_slot++; + if (dev->tx_slot == NUM_TX_BUFF) { + dev->tx_slot = 0; + ctrl |= MAL_TX_CTRL_WRAP; + } + + DBG2("%d: xmit(%u) %d" NL, dev->def->index, len, slot); + + dev->tx_skb[slot] = skb; + dev->tx_desc[slot].data_ptr = dma_map_single(dev->ldev, skb->data, len, + DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) len; + barrier(); + dev->tx_desc[slot].ctrl = ctrl; + + return emac_xmit_finish(dev, len); +} + +#if defined(CONFIG_IBM_EMAC_TAH) +static inline int emac_xmit_split(struct ocp_enet_private *dev, int slot, + u32 pd, int len, int last, u16 base_ctrl) +{ + while (1) { + u16 ctrl = base_ctrl; + int chunk = min(len, MAL_MAX_TX_SIZE); + len -= chunk; + + slot = (slot + 1) % NUM_TX_BUFF; + + if (last && !len) + ctrl |= MAL_TX_CTRL_LAST; + if (slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + + dev->tx_skb[slot] = NULL; + dev->tx_desc[slot].data_ptr = pd; + dev->tx_desc[slot].data_len = (u16) chunk; + dev->tx_desc[slot].ctrl = ctrl; + ++dev->tx_cnt; + + if (!len) + break; + + pd += chunk; + } + return slot; +} + +/* BHs disabled (SG version for TAH equipped EMACs) */ +static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + int nr_frags = skb_shinfo(skb)->nr_frags; + int len = skb->len, chunk; + int slot, i; + u16 ctrl; + u32 pd; + + /* This is common "fast" path */ + if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) + return emac_start_xmit(skb, ndev); + + len -= skb->data_len; + + /* Note, this is only an *estimation*, we can still run out of empty + * slots because of the additional fragmentation into + * MAL_MAX_TX_SIZE-sized chunks + */ + if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) + goto stop_queue; + + ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + emac_tx_csum(dev, skb); + slot = dev->tx_slot; + + /* skb data */ + dev->tx_skb[slot] = NULL; + chunk = min(len, MAL_MAX_TX_SIZE); + dev->tx_desc[slot].data_ptr = pd = + dma_map_single(dev->ldev, skb->data, len, DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) chunk; + len -= chunk; + if (unlikely(len)) + slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, + ctrl); + /* skb fragments */ + for (i = 0; i < nr_frags; ++i) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + len = frag->size; + + if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) + goto undo_frame; + + pd = dma_map_page(dev->ldev, frag->page, frag->page_offset, len, + DMA_TO_DEVICE); + + slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, + ctrl); + } + + DBG2("%d: xmit_sg(%u) %d - %d" NL, dev->def->index, skb->len, + dev->tx_slot, slot); + + /* Attach skb to the last slot so we don't release it too early */ + dev->tx_skb[slot] = skb; + + /* Send the packet out */ + if (dev->tx_slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + barrier(); + dev->tx_desc[dev->tx_slot].ctrl = ctrl; + dev->tx_slot = (slot + 1) % NUM_TX_BUFF; + + return emac_xmit_finish(dev, skb->len); + + undo_frame: + /* Well, too bad. Our previous estimation was overly optimistic. + * Undo everything. + */ + while (slot != dev->tx_slot) { + dev->tx_desc[slot].ctrl = 0; + --dev->tx_cnt; + if (--slot < 0) + slot = NUM_TX_BUFF - 1; + } + ++dev->estats.tx_undo; + + stop_queue: + netif_stop_queue(ndev); + DBG2("%d: stopped TX queue" NL, dev->def->index); + return 1; +} +#else +# define emac_start_xmit_sg emac_start_xmit +#endif /* !defined(CONFIG_IBM_EMAC_TAH) */ + +/* BHs disabled */ +static void emac_parse_tx_error(struct ocp_enet_private *dev, u16 ctrl) +{ + struct ibm_emac_error_stats *st = &dev->estats; + DBG("%d: BD TX error %04x" NL, dev->def->index, ctrl); + + ++st->tx_bd_errors; + if (ctrl & EMAC_TX_ST_BFCS) + ++st->tx_bd_bad_fcs; + if (ctrl & EMAC_TX_ST_LCS) + ++st->tx_bd_carrier_loss; + if (ctrl & EMAC_TX_ST_ED) + ++st->tx_bd_excessive_deferral; + if (ctrl & EMAC_TX_ST_EC) + ++st->tx_bd_excessive_collisions; + if (ctrl & EMAC_TX_ST_LC) + ++st->tx_bd_late_collision; + if (ctrl & EMAC_TX_ST_MC) + ++st->tx_bd_multple_collisions; + if (ctrl & EMAC_TX_ST_SC) + ++st->tx_bd_single_collision; + if (ctrl & EMAC_TX_ST_UR) + ++st->tx_bd_underrun; + if (ctrl & EMAC_TX_ST_SQE) + ++st->tx_bd_sqe; +} + +static void emac_poll_tx(void *param) +{ + struct ocp_enet_private *dev = param; + DBG2("%d: poll_tx, %d %d" NL, dev->def->index, dev->tx_cnt, + dev->ack_slot); + + if (dev->tx_cnt) { + u16 ctrl; + int slot = dev->ack_slot, n = 0; + again: + ctrl = dev->tx_desc[slot].ctrl; + if (!(ctrl & MAL_TX_CTRL_READY)) { + struct sk_buff *skb = dev->tx_skb[slot]; + ++n; + + if (skb) { + dev_kfree_skb(skb); + dev->tx_skb[slot] = NULL; + } + slot = (slot + 1) % NUM_TX_BUFF; + + if (unlikely(EMAC_IS_BAD_TX(ctrl))) + emac_parse_tx_error(dev, ctrl); + + if (--dev->tx_cnt) + goto again; + } + if (n) { + dev->ack_slot = slot; + if (netif_queue_stopped(dev->ndev) && + dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) + netif_wake_queue(dev->ndev); + + DBG2("%d: tx %d pkts" NL, dev->def->index, n); + } + } +} + +static inline void emac_recycle_rx_skb(struct ocp_enet_private *dev, int slot, + int len) +{ + struct sk_buff *skb = dev->rx_skb[slot]; + DBG2("%d: recycle %d %d" NL, dev->def->index, slot, len); + + if (len) + dma_map_single(dev->ldev, skb->data - 2, + EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); + + dev->rx_desc[slot].data_len = 0; + barrier(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); +} + +static void emac_parse_rx_error(struct ocp_enet_private *dev, u16 ctrl) +{ + struct ibm_emac_error_stats *st = &dev->estats; + DBG("%d: BD RX error %04x" NL, dev->def->index, ctrl); + + ++st->rx_bd_errors; + if (ctrl & EMAC_RX_ST_OE) + ++st->rx_bd_overrun; + if (ctrl & EMAC_RX_ST_BP) + ++st->rx_bd_bad_packet; + if (ctrl & EMAC_RX_ST_RP) + ++st->rx_bd_runt_packet; + if (ctrl & EMAC_RX_ST_SE) + ++st->rx_bd_short_event; + if (ctrl & EMAC_RX_ST_AE) + ++st->rx_bd_alignment_error; + if (ctrl & EMAC_RX_ST_BFCS) + ++st->rx_bd_bad_fcs; + if (ctrl & EMAC_RX_ST_PTL) + ++st->rx_bd_packet_too_long; + if (ctrl & EMAC_RX_ST_ORE) + ++st->rx_bd_out_of_range; + if (ctrl & EMAC_RX_ST_IRE) + ++st->rx_bd_in_range; +} + +static inline void emac_rx_csum(struct ocp_enet_private *dev, + struct sk_buff *skb, u16 ctrl) +{ +#if defined(CONFIG_IBM_EMAC_TAH) + if (!ctrl && dev->tah_dev) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + ++dev->stats.rx_packets_csum; + } +#endif +} + +static inline int emac_rx_sg_append(struct ocp_enet_private *dev, int slot) +{ + if (likely(dev->rx_sg_skb != NULL)) { + int len = dev->rx_desc[slot].data_len; + int tot_len = dev->rx_sg_skb->len + len; + + if (unlikely(tot_len + 2 > dev->rx_skb_size)) { + ++dev->estats.rx_dropped_mtu; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } else { + cacheable_memcpy(dev->rx_sg_skb->tail, + dev->rx_skb[slot]->data, len); + skb_put(dev->rx_sg_skb, len); + emac_recycle_rx_skb(dev, slot, len); + return 0; + } + } + emac_recycle_rx_skb(dev, slot, 0); + return -1; +} + +/* BHs disabled */ +static int emac_poll_rx(void *param, int budget) +{ + struct ocp_enet_private *dev = param; + int slot = dev->rx_slot, received = 0; + + DBG2("%d: poll_rx(%d)" NL, dev->def->index, budget); + + again: + while (budget > 0) { + int len; + struct sk_buff *skb; + u16 ctrl = dev->rx_desc[slot].ctrl; + + if (ctrl & MAL_RX_CTRL_EMPTY) + break; + + skb = dev->rx_skb[slot]; + barrier(); + len = dev->rx_desc[slot].data_len; + + if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) + goto sg; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + emac_recycle_rx_skb(dev, slot, 0); + len = 0; + goto next; + } + + if (len && len < EMAC_RX_COPY_THRESH) { + struct sk_buff *copy_skb = + alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); + if (unlikely(!copy_skb)) + goto oom; + + skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); + cacheable_memcpy(copy_skb->data - 2, skb->data - 2, + len + 2); + emac_recycle_rx_skb(dev, slot, len); + skb = copy_skb; + } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) + goto oom; + + skb_put(skb, len); + push_packet: + skb->dev = dev->ndev; + skb->protocol = eth_type_trans(skb, dev->ndev); + emac_rx_csum(dev, skb, ctrl); + + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + ++dev->estats.rx_dropped_stack; + next: + ++dev->stats.rx_packets; + skip: + dev->stats.rx_bytes += len; + slot = (slot + 1) % NUM_RX_BUFF; + --budget; + ++received; + continue; + sg: + if (ctrl & MAL_RX_CTRL_FIRST) { + BUG_ON(dev->rx_sg_skb); + if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { + DBG("%d: rx OOM %d" NL, dev->def->index, slot); + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + } else { + dev->rx_sg_skb = skb; + skb_put(skb, len); + } + } else if (!emac_rx_sg_append(dev, slot) && + (ctrl & MAL_RX_CTRL_LAST)) { + + skb = dev->rx_sg_skb; + dev->rx_sg_skb = NULL; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(skb); + len = 0; + } else + goto push_packet; + } + goto skip; + oom: + DBG("%d: rx OOM %d" NL, dev->def->index, slot); + /* Drop the packet and recycle skb */ + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + goto next; + } + + if (received) { + DBG2("%d: rx %d BDs" NL, dev->def->index, received); + dev->rx_slot = slot; + } + + if (unlikely(budget && dev->commac.rx_stopped)) { + struct ocp_func_emac_data *emacdata = dev->def->additions; + + barrier(); + if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { + DBG2("%d: rx restart" NL, dev->def->index); + received = 0; + goto again; + } + + if (dev->rx_sg_skb) { + DBG2("%d: dropping partial rx packet" NL, + dev->def->index); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } + + dev->commac.rx_stopped = 0; + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_rx_enable(dev); + dev->rx_slot = 0; + } + return received; +} + +/* BHs disabled */ +static int emac_peek_rx(void *param) +{ + struct ocp_enet_private *dev = param; + return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); +} + +/* BHs disabled */ +static int emac_peek_rx_sg(void *param) +{ + struct ocp_enet_private *dev = param; + int slot = dev->rx_slot; + while (1) { + u16 ctrl = dev->rx_desc[slot].ctrl; + if (ctrl & MAL_RX_CTRL_EMPTY) + return 0; + else if (ctrl & MAL_RX_CTRL_LAST) + return 1; + + slot = (slot + 1) % NUM_RX_BUFF; + + /* I'm just being paranoid here :) */ + if (unlikely(slot == dev->rx_slot)) + return 0; + } +} + +/* Hard IRQ */ +static void emac_rxde(void *param) +{ + struct ocp_enet_private *dev = param; + ++dev->estats.rx_stopped; + emac_rx_disable_async(dev); +} + +/* Hard IRQ */ +static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ocp_enet_private *dev = dev_instance; + struct emac_regs *p = dev->emacp; + struct ibm_emac_error_stats *st = &dev->estats; + + u32 isr = in_be32(&p->isr); + out_be32(&p->isr, isr); + + DBG("%d: isr = %08x" NL, dev->def->index, isr); + + if (isr & EMAC_ISR_TXPE) + ++st->tx_parity; + if (isr & EMAC_ISR_RXPE) + ++st->rx_parity; + if (isr & EMAC_ISR_TXUE) + ++st->tx_underrun; + if (isr & EMAC_ISR_RXOE) + ++st->rx_fifo_overrun; + if (isr & EMAC_ISR_OVR) + ++st->rx_overrun; + if (isr & EMAC_ISR_BP) + ++st->rx_bad_packet; + if (isr & EMAC_ISR_RP) + ++st->rx_runt_packet; + if (isr & EMAC_ISR_SE) + ++st->rx_short_event; + if (isr & EMAC_ISR_ALE) + ++st->rx_alignment_error; + if (isr & EMAC_ISR_BFCS) + ++st->rx_bad_fcs; + if (isr & EMAC_ISR_PTLE) + ++st->rx_packet_too_long; + if (isr & EMAC_ISR_ORE) + ++st->rx_out_of_range; + if (isr & EMAC_ISR_IRE) + ++st->rx_in_range; + if (isr & EMAC_ISR_SQE) + ++st->tx_sqe; + if (isr & EMAC_ISR_TE) + ++st->tx_errors; return IRQ_HANDLED; } -static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev) +static struct net_device_stats *emac_stats(struct net_device *ndev) { - unsigned short ctrl; - unsigned long flags; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - int len = skb->len; - unsigned int offset = 0, size, f, tx_slot_first; - unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + struct ocp_enet_private *dev = ndev->priv; + struct ibm_emac_stats *st = &dev->stats; + struct ibm_emac_error_stats *est = &dev->estats; + struct net_device_stats *nst = &dev->nstats; - spin_lock_irqsave(&fep->lock, flags); + DBG2("%d: stats" NL, dev->def->index); - len -= skb->data_len; + /* Compute "legacy" statistics */ + local_irq_disable(); + nst->rx_packets = (unsigned long)st->rx_packets; + nst->rx_bytes = (unsigned long)st->rx_bytes; + nst->tx_packets = (unsigned long)st->tx_packets; + nst->tx_bytes = (unsigned long)st->tx_bytes; + nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + + est->rx_dropped_error + + est->rx_dropped_resize + + est->rx_dropped_mtu); + nst->tx_dropped = (unsigned long)est->tx_dropped; - if ((fep->tx_cnt + nr_frags + len / DESC_BUF_SIZE + 1) > NUM_TX_BUFF) { - PKT_DEBUG(("emac_start_xmit() stopping queue\n")); - netif_stop_queue(dev); - spin_unlock_irqrestore(&fep->lock, flags); - return -EBUSY; - } + nst->rx_errors = (unsigned long)est->rx_bd_errors; + nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + + est->rx_fifo_overrun + + est->rx_overrun); + nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + + est->rx_alignment_error); + nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + + est->rx_bad_fcs); + nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + + est->rx_bd_short_event + + est->rx_bd_packet_too_long + + est->rx_bd_out_of_range + + est->rx_bd_in_range + + est->rx_runt_packet + + est->rx_short_event + + est->rx_packet_too_long + + est->rx_out_of_range + + est->rx_in_range); - tx_slot_first = fep->tx_slot; - - while (len) { - size = min(len, DESC_BUF_SIZE); - - fep->tx_desc[fep->tx_slot].data_len = (short)size; - fep->tx_desc[fep->tx_slot].data_ptr = - (unsigned char *)dma_map_single(&fep->ocpdev->dev, - (void *)((unsigned int)skb-> - data + offset), - size, DMA_TO_DEVICE); - - ctrl = EMAC_TX_CTRL_DFLT; - if (fep->tx_slot != tx_slot_first) - ctrl |= MAL_TX_CTRL_READY; - if ((NUM_TX_BUFF - 1) == fep->tx_slot) - ctrl |= MAL_TX_CTRL_WRAP; - if (!nr_frags && (len == size)) { - ctrl |= MAL_TX_CTRL_LAST; - fep->tx_skb[fep->tx_slot] = skb; - } - if (skb->ip_summed == CHECKSUM_HW) - ctrl |= EMAC_TX_CTRL_TAH_CSUM; - - fep->tx_desc[fep->tx_slot].ctrl = ctrl; - - len -= size; - offset += size; - - /* Bump tx count */ - if (++fep->tx_cnt == NUM_TX_BUFF) - netif_stop_queue(dev); - - /* Next descriptor */ - if (++fep->tx_slot == NUM_TX_BUFF) - fep->tx_slot = 0; - } - - for (f = 0; f < nr_frags; f++) { - struct skb_frag_struct *frag; - - frag = &skb_shinfo(skb)->frags[f]; - len = frag->size; - offset = 0; - - while (len) { - size = min(len, DESC_BUF_SIZE); - - dma_map_page(&fep->ocpdev->dev, - frag->page, - frag->page_offset + offset, - size, DMA_TO_DEVICE); - - ctrl = EMAC_TX_CTRL_DFLT | MAL_TX_CTRL_READY; - if ((NUM_TX_BUFF - 1) == fep->tx_slot) - ctrl |= MAL_TX_CTRL_WRAP; - if ((f == (nr_frags - 1)) && (len == size)) { - ctrl |= MAL_TX_CTRL_LAST; - fep->tx_skb[fep->tx_slot] = skb; - } - - if (skb->ip_summed == CHECKSUM_HW) - ctrl |= EMAC_TX_CTRL_TAH_CSUM; - - fep->tx_desc[fep->tx_slot].data_len = (short)size; - fep->tx_desc[fep->tx_slot].data_ptr = - (char *)((page_to_pfn(frag->page) << PAGE_SHIFT) + - frag->page_offset + offset); - fep->tx_desc[fep->tx_slot].ctrl = ctrl; - - len -= size; - offset += size; - - /* Bump tx count */ - if (++fep->tx_cnt == NUM_TX_BUFF) - netif_stop_queue(dev); - - /* Next descriptor */ - if (++fep->tx_slot == NUM_TX_BUFF) - fep->tx_slot = 0; - } - } - - /* - * Deferred set READY on first descriptor of packet to - * avoid TX MAL race. - */ - fep->tx_desc[tx_slot_first].ctrl |= MAL_TX_CTRL_READY; - - /* Send the packet out. */ - out_be32(&emacp->em0tmr0, EMAC_TMR0_XMIT); - - fep->stats.tx_packets++; - fep->stats.tx_bytes += skb->len; - - PKT_DEBUG(("emac_start_xmit() exitn")); - - spin_unlock_irqrestore(&fep->lock, flags); - - return 0; + nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); + nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + + est->tx_underrun); + nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; + nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + + est->tx_bd_excessive_collisions + + est->tx_bd_late_collision + + est->tx_bd_multple_collisions); + local_irq_enable(); + return nst; } -static int emac_adjust_to_link(struct ocp_enet_private *fep) +static void emac_remove(struct ocp_device *ocpdev) { - emac_t *emacp = fep->emacp; - unsigned long mode_reg; - int full_duplex, speed; + struct ocp_enet_private *dev = ocp_get_drvdata(ocpdev); - full_duplex = 0; - speed = SPEED_10; + DBG("%d: remove" NL, dev->def->index); - /* set mode register 1 defaults */ - mode_reg = EMAC_M1_DEFAULT; + ocp_set_drvdata(ocpdev, 0); + unregister_netdev(dev->ndev); - /* Read link mode on PHY */ - if (fep->phy_mii.def->ops->read_link(&fep->phy_mii) == 0) { - /* If an error occurred, we don't deal with it yet */ - full_duplex = (fep->phy_mii.duplex == DUPLEX_FULL); - speed = fep->phy_mii.speed; - } + tah_fini(dev->tah_dev); + rgmii_fini(dev->rgmii_dev, dev->rgmii_input); + zmii_fini(dev->zmii_dev, dev->zmii_input); + emac_dbg_register(dev->def->index, 0); - /* set speed (default is 10Mb) */ - switch (speed) { - case SPEED_1000: - mode_reg |= EMAC_M1_RFS_16K; - if (fep->rgmii_dev) { - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev); - - if ((rgmii->mode[fep->rgmii_input] == RTBI) - || (rgmii->mode[fep->rgmii_input] == TBI)) - mode_reg |= EMAC_M1_MF_1000GPCS; - else - mode_reg |= EMAC_M1_MF_1000MBPS; - - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 1000); - } - break; - case SPEED_100: - mode_reg |= EMAC_M1_MF_100MBPS | EMAC_M1_RFS_4K; - if (fep->rgmii_dev) - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 100); - if (fep->zmii_dev) - emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, - 100); - break; - case SPEED_10: - default: - mode_reg = (mode_reg & ~EMAC_M1_MF_100MBPS) | EMAC_M1_RFS_4K; - if (fep->rgmii_dev) - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 10); - if (fep->zmii_dev) - emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, - 10); - } - - if (full_duplex) - mode_reg |= EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_IST; - else - mode_reg &= ~(EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_ILE); - - LINK_DEBUG(("%s: adjust to link, speed: %d, duplex: %d, opened: %d\n", - fep->ndev->name, speed, full_duplex, fep->opened)); - - printk(KERN_INFO "%s: Speed: %d, %s duplex.\n", - fep->ndev->name, speed, full_duplex ? "Full" : "Half"); - if (fep->opened) - out_be32(&emacp->em0mr1, mode_reg); - - return 0; + mal_unregister_commac(dev->mal, &dev->commac); + iounmap((void *)dev->emacp); + kfree(dev->ndev); } -static int emac_set_mac_address(struct net_device *ndev, void *p) +static struct mal_commac_ops emac_commac_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx, + .rxde = &emac_rxde, +}; + +static struct mal_commac_ops emac_commac_sg_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx_sg, + .rxde = &emac_rxde, +}; + +/* Ethtool support */ +static int emac_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) { - struct ocp_enet_private *fep = ndev->priv; - emac_t *emacp = fep->emacp; - struct sockaddr *addr = p; + struct ocp_enet_private *dev = ndev->priv; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); - - /* set the high address */ - out_be32(&emacp->em0iahr, - (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); - - /* set the low address */ - out_be32(&emacp->em0ialr, - (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) - | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); - - return 0; -} - -static int emac_change_mtu(struct net_device *dev, int new_mtu) -{ - struct ocp_enet_private *fep = dev->priv; - int old_mtu = dev->mtu; - unsigned long mode_reg; - emac_t *emacp = fep->emacp; - u32 em0mr0; - int i, full; - unsigned long flags; - - if ((new_mtu < EMAC_MIN_MTU) || (new_mtu > EMAC_MAX_MTU)) { - printk(KERN_ERR - "emac: Invalid MTU setting, MTU must be between %d and %d\n", - EMAC_MIN_MTU, EMAC_MAX_MTU); - return -EINVAL; - } - - if (old_mtu != new_mtu && netif_running(dev)) { - /* Stop rx engine */ - em0mr0 = in_be32(&emacp->em0mr0); - out_be32(&emacp->em0mr0, em0mr0 & ~EMAC_M0_RXE); - - /* Wait for descriptors to be empty */ - do { - full = 0; - for (i = 0; i < NUM_RX_BUFF; i++) - if (!(fep->rx_desc[i].ctrl & MAL_RX_CTRL_EMPTY)) { - printk(KERN_NOTICE - "emac: RX ring is still full\n"); - full = 1; - } - } while (full); - - spin_lock_irqsave(&fep->lock, flags); - - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - - /* Destroy all old rx skbs */ - for (i = 0; i < NUM_RX_BUFF; i++) { - dma_unmap_single(&fep->ocpdev->dev, - fep->rx_desc[i].data_ptr, - fep->rx_desc[i].data_len, - DMA_FROM_DEVICE); - dev_kfree_skb(fep->rx_skb[i]); - fep->rx_skb[i] = NULL; - } - - /* Set new rx_buffer_size, jumbo cap, and advertise new mtu */ - mode_reg = in_be32(&emacp->em0mr1); - if (new_mtu > ENET_DEF_MTU_SIZE) { - mode_reg |= EMAC_M1_JUMBO_ENABLE; - fep->rx_buffer_size = EMAC_MAX_FRAME; - } else { - mode_reg &= ~EMAC_M1_JUMBO_ENABLE; - fep->rx_buffer_size = ENET_DEF_BUF_SIZE; - } - dev->mtu = new_mtu; - out_be32(&emacp->em0mr1, mode_reg); - - /* Re-init rx skbs */ - fep->rx_slot = 0; - emac_rx_fill(dev, 0); - - /* Restart the rx engine */ - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - out_be32(&emacp->em0mr0, em0mr0 | EMAC_M0_RXE); - - spin_unlock_irqrestore(&fep->lock, flags); - } - - return 0; -} - -static void __emac_set_multicast_list(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - u32 rmr = in_be32(&emacp->em0rmr); - - /* First clear all special bits, they can be set later */ - rmr &= ~(EMAC_RMR_PME | EMAC_RMR_PMME | EMAC_RMR_MAE); - - if (dev->flags & IFF_PROMISC) { - rmr |= EMAC_RMR_PME; - } else if (dev->flags & IFF_ALLMULTI || 32 < dev->mc_count) { - /* - * Must be setting up to use multicast - * Now check for promiscuous multicast - */ - rmr |= EMAC_RMR_PMME; - } else if (dev->flags & IFF_MULTICAST && 0 < dev->mc_count) { - unsigned short em0gaht[4] = { 0, 0, 0, 0 }; - struct dev_mc_list *dmi; - - /* Need to hash on the multicast address. */ - for (dmi = dev->mc_list; dmi; dmi = dmi->next) { - unsigned long mc_crc; - unsigned int bit_number; - - mc_crc = ether_crc(6, (char *)dmi->dmi_addr); - bit_number = 63 - (mc_crc >> 26); /* MSB: 0 LSB: 63 */ - em0gaht[bit_number >> 4] |= - 0x8000 >> (bit_number & 0x0f); - } - emacp->em0gaht1 = em0gaht[0]; - emacp->em0gaht2 = em0gaht[1]; - emacp->em0gaht3 = em0gaht[2]; - emacp->em0gaht4 = em0gaht[3]; - - /* Turn on multicast addressing */ - rmr |= EMAC_RMR_MAE; - } - out_be32(&emacp->em0rmr, rmr); -} - -static int emac_init_tah(struct ocp_enet_private *fep) -{ - tah_t *tahp; - - /* Initialize TAH and enable checksum verification */ - tahp = (tah_t *) ioremap(fep->tah_dev->def->paddr, sizeof(*tahp)); - - if (tahp == NULL) { - printk(KERN_ERR "tah%d: Cannot ioremap TAH registers!\n", - fep->tah_dev->def->index); - - return -ENOMEM; - } - - out_be32(&tahp->tah_mr, TAH_MR_SR); - - /* wait for reset to complete */ - while (in_be32(&tahp->tah_mr) & TAH_MR_SR) ; - - /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ - out_be32(&tahp->tah_mr, - TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | - TAH_MR_DIG); - - iounmap(tahp); - - return 0; -} - -static void emac_init_rings(struct net_device *dev) -{ - struct ocp_enet_private *ep = dev->priv; - int loop; - - ep->tx_desc = (struct mal_descriptor *)((char *)ep->mal->tx_virt_addr + - (ep->mal_tx_chan * - MAL_DT_ALIGN)); - ep->rx_desc = - (struct mal_descriptor *)((char *)ep->mal->rx_virt_addr + - (ep->mal_rx_chan * MAL_DT_ALIGN)); - - /* Fill in the transmit descriptor ring. */ - for (loop = 0; loop < NUM_TX_BUFF; loop++) { - if (ep->tx_skb[loop]) { - dma_unmap_single(&ep->ocpdev->dev, - ep->tx_desc[loop].data_ptr, - ep->tx_desc[loop].data_len, - DMA_TO_DEVICE); - dev_kfree_skb_irq(ep->tx_skb[loop]); - } - ep->tx_skb[loop] = NULL; - ep->tx_desc[loop].ctrl = 0; - ep->tx_desc[loop].data_len = 0; - ep->tx_desc[loop].data_ptr = NULL; - } - ep->tx_desc[loop - 1].ctrl |= MAL_TX_CTRL_WRAP; - - /* Format the receive descriptor ring. */ - ep->rx_slot = 0; - /* Default is MTU=1500 + Ethernet overhead */ - ep->rx_buffer_size = dev->mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE; - emac_rx_fill(dev, 0); - if (ep->rx_slot != 0) { - printk(KERN_ERR - "%s: Not enough mem for RxChain durning Open?\n", - dev->name); - /*We couldn't fill the ring at startup? - *We could clean up and fail to open but right now we will try to - *carry on. It may be a sign of a bad NUM_RX_BUFF value - */ - } - - ep->tx_cnt = 0; - ep->tx_slot = 0; - ep->ack_slot = 0; -} - -static void emac_reset_configure(struct ocp_enet_private *fep) -{ - emac_t *emacp = fep->emacp; - int i; - - mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - - /* - * Check for a link, some PHYs don't provide a clock if - * no link is present. Some EMACs will not come out of - * soft reset without a PHY clock present. - */ - if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { - /* Reset the EMAC */ - out_be32(&emacp->em0mr0, EMAC_M0_SRST); - udelay(20); - for (i = 0; i < 100; i++) { - if ((in_be32(&emacp->em0mr0) & EMAC_M0_SRST) == 0) - break; - udelay(10); - } - - if (i >= 100) { - printk(KERN_ERR "%s: Cannot reset EMAC\n", - fep->ndev->name); - return; - } - } - - /* Switch IRQs off for now */ - out_be32(&emacp->em0iser, 0); - - /* Configure MAL rx channel */ - mal_set_rcbs(fep->mal, fep->mal_rx_chan, DESC_BUF_SIZE_REG); - - /* set the high address */ - out_be32(&emacp->em0iahr, - (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); - - /* set the low address */ - out_be32(&emacp->em0ialr, - (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) - | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); - - /* Adjust to link */ - if (netif_carrier_ok(fep->ndev)) - emac_adjust_to_link(fep); - - /* enable broadcast/individual address and RX FIFO defaults */ - out_be32(&emacp->em0rmr, EMAC_RMR_DEFAULT); - - /* set transmit request threshold register */ - out_be32(&emacp->em0trtr, EMAC_TRTR_DEFAULT); - - /* Reconfigure multicast */ - __emac_set_multicast_list(fep->ndev); - - /* Set receiver/transmitter defaults */ - out_be32(&emacp->em0rwmr, EMAC_RWMR_DEFAULT); - out_be32(&emacp->em0tmr0, EMAC_TMR0_DEFAULT); - out_be32(&emacp->em0tmr1, EMAC_TMR1_DEFAULT); - - /* set frame gap */ - out_be32(&emacp->em0ipgvr, CONFIG_IBM_EMAC_FGAP); - - /* set VLAN Tag Protocol Identifier */ - out_be32(&emacp->em0vtpid, 0x8100); - - /* Init ring buffers */ - emac_init_rings(fep->ndev); -} - -static void emac_kick(struct ocp_enet_private *fep) -{ - emac_t *emacp = fep->emacp; - unsigned long emac_ier; - - emac_ier = EMAC_ISR_PP | EMAC_ISR_BP | EMAC_ISR_RP | - EMAC_ISR_SE | EMAC_ISR_PTLE | EMAC_ISR_ALE | - EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE; - - out_be32(&emacp->em0iser, emac_ier); - - /* enable all MAL transmit and receive channels */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - - /* set transmit and receive enable */ - out_be32(&emacp->em0mr0, EMAC_M0_TXE | EMAC_M0_RXE); -} - -static void -emac_start_link(struct ocp_enet_private *fep, struct ethtool_cmd *ep) -{ - u32 advertise; - int autoneg; - int forced_speed; - int forced_duplex; - - /* Default advertise */ - advertise = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full; - autoneg = fep->want_autoneg; - forced_speed = fep->phy_mii.speed; - forced_duplex = fep->phy_mii.duplex; - - /* Setup link parameters */ - if (ep) { - if (ep->autoneg == AUTONEG_ENABLE) { - advertise = ep->advertising; - autoneg = 1; - } else { - autoneg = 0; - forced_speed = ep->speed; - forced_duplex = ep->duplex; - } - } - - /* Configure PHY & start aneg */ - fep->want_autoneg = autoneg; - if (autoneg) { - LINK_DEBUG(("%s: start link aneg, advertise: 0x%x\n", - fep->ndev->name, advertise)); - fep->phy_mii.def->ops->setup_aneg(&fep->phy_mii, advertise); - } else { - LINK_DEBUG(("%s: start link forced, speed: %d, duplex: %d\n", - fep->ndev->name, forced_speed, forced_duplex)); - fep->phy_mii.def->ops->setup_forced(&fep->phy_mii, forced_speed, - forced_duplex); - } - fep->timer_ticks = 0; - mod_timer(&fep->link_timer, jiffies + HZ); -} - -static void emac_link_timer(unsigned long data) -{ - struct ocp_enet_private *fep = (struct ocp_enet_private *)data; - int link; - - if (fep->going_away) - return; - - spin_lock_irq(&fep->lock); - - link = fep->phy_mii.def->ops->poll_link(&fep->phy_mii); - LINK_DEBUG(("%s: poll_link: %d\n", fep->ndev->name, link)); - - if (link == netif_carrier_ok(fep->ndev)) { - if (!link && fep->want_autoneg && (++fep->timer_ticks) > 10) - emac_start_link(fep, NULL); - goto out; - } - printk(KERN_INFO "%s: Link is %s\n", fep->ndev->name, - link ? "Up" : "Down"); - if (link) { - netif_carrier_on(fep->ndev); - /* Chip needs a full reset on config change. That sucks, so I - * should ultimately move that to some tasklet to limit - * latency peaks caused by this code - */ - emac_reset_configure(fep); - if (fep->opened) - emac_kick(fep); - } else { - fep->timer_ticks = 0; - netif_carrier_off(fep->ndev); - } - out: - mod_timer(&fep->link_timer, jiffies + HZ); - spin_unlock_irq(&fep->lock); -} - -static void emac_set_multicast_list(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - - spin_lock_irq(&fep->lock); - __emac_set_multicast_list(dev); - spin_unlock_irq(&fep->lock); -} - -static int emac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) -{ - struct ocp_enet_private *fep = ndev->priv; - - cmd->supported = fep->phy_mii.def->features; + cmd->supported = dev->phy.features; cmd->port = PORT_MII; - cmd->transceiver = XCVR_EXTERNAL; - cmd->phy_address = fep->mii_phy_addr; - spin_lock_irq(&fep->lock); - cmd->autoneg = fep->want_autoneg; - cmd->speed = fep->phy_mii.speed; - cmd->duplex = fep->phy_mii.duplex; - spin_unlock_irq(&fep->lock); + cmd->phy_address = dev->phy.address; + cmd->transceiver = + dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; + + local_bh_disable(); + cmd->advertising = dev->phy.advertising; + cmd->autoneg = dev->phy.autoneg; + cmd->speed = dev->phy.speed; + cmd->duplex = dev->phy.duplex; + local_bh_enable(); + return 0; } -static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +static int emac_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) { - struct ocp_enet_private *fep = ndev->priv; - unsigned long features = fep->phy_mii.def->features; + struct ocp_enet_private *dev = ndev->priv; + u32 f = dev->phy.features; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + DBG("%d: set_settings(%d, %d, %d, 0x%08x)" NL, dev->def->index, + cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + /* Basic sanity checks */ + if (dev->phy.address < 0) + return -EOPNOTSUPP; if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) return -EINVAL; if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) return -EINVAL; - if (cmd->autoneg == AUTONEG_DISABLE) + + if (cmd->autoneg == AUTONEG_DISABLE) { switch (cmd->speed) { case SPEED_10: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_10baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_10baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_10baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_10baseT_Full)) return -EINVAL; break; case SPEED_100: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_100baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_100baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_100baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_100baseT_Full)) return -EINVAL; break; case SPEED_1000: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_1000baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_1000baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_1000baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_1000baseT_Full)) return -EINVAL; break; default: return -EINVAL; - } else if ((features & SUPPORTED_Autoneg) == 0) - return -EINVAL; - spin_lock_irq(&fep->lock); - emac_start_link(fep, cmd); - spin_unlock_irq(&fep->lock); + } + + local_bh_disable(); + dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, + cmd->duplex); + + } else { + if (!(f & SUPPORTED_Autoneg)) + return -EINVAL; + + local_bh_disable(); + dev->phy.def->ops->setup_aneg(&dev->phy, + (cmd->advertising & f) | + (dev->phy.advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause))); + } + emac_force_link_update(dev); + local_bh_enable(); + return 0; } -static void -emac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) +static void emac_ethtool_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *rp) { - struct ocp_enet_private *fep = ndev->priv; + rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; + rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; +} - strcpy(info->driver, DRV_NAME); +static void emac_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + struct ocp_enet_private *dev = ndev->priv; + + local_bh_disable(); + if ((dev->phy.features & SUPPORTED_Autoneg) && + (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) + pp->autoneg = 1; + + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + pp->rx_pause = pp->tx_pause = 1; + else if (dev->phy.asym_pause) + pp->tx_pause = 1; + } + local_bh_enable(); +} + +static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + return dev->tah_dev != 0; +} + +static int emac_get_regs_len(struct ocp_enet_private *dev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + EMAC_ETHTOOL_REGS_SIZE; +} + +static int emac_ethtool_get_regs_len(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + return sizeof(struct emac_ethtool_regs_hdr) + + emac_get_regs_len(dev) + mal_get_regs_len(dev->mal) + + zmii_get_regs_len(dev->zmii_dev) + + rgmii_get_regs_len(dev->rgmii_dev) + + tah_get_regs_len(dev->tah_dev); +} + +static void *emac_dump_regs(struct ocp_enet_private *dev, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + + hdr->version = EMAC_ETHTOOL_REGS_VER; + hdr->index = dev->def->index; + memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); +} + +static void emac_ethtool_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *buf) +{ + struct ocp_enet_private *dev = ndev->priv; + struct emac_ethtool_regs_hdr *hdr = buf; + + hdr->components = 0; + buf = hdr + 1; + + local_irq_disable(); + buf = mal_dump_regs(dev->mal, buf); + buf = emac_dump_regs(dev, buf); + if (dev->zmii_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_ZMII; + buf = zmii_dump_regs(dev->zmii_dev, buf); + } + if (dev->rgmii_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_RGMII; + buf = rgmii_dump_regs(dev->rgmii_dev, buf); + } + if (dev->tah_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_TAH; + buf = tah_dump_regs(dev->tah_dev, buf); + } + local_irq_enable(); +} + +static int emac_ethtool_nway_reset(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + int res = 0; + + DBG("%d: nway_reset" NL, dev->def->index); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + local_bh_disable(); + if (!dev->phy.autoneg) { + res = -EINVAL; + goto out; + } + + dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); + emac_force_link_update(dev); + + out: + local_bh_enable(); + return res; +} + +static int emac_ethtool_get_stats_count(struct net_device *ndev) +{ + return EMAC_ETHTOOL_STATS_COUNT; +} + +static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, + u8 * buf) +{ + if (stringset == ETH_SS_STATS) + memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); +} + +static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *estats, + u64 * tmp_stats) +{ + struct ocp_enet_private *dev = ndev->priv; + local_irq_disable(); + memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); + tmp_stats += sizeof(dev->stats) / sizeof(u64); + memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); + local_irq_enable(); +} + +static void emac_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct ocp_enet_private *dev = ndev->priv; + + strcpy(info->driver, "ibm_emac"); strcpy(info->version, DRV_VERSION); info->fw_version[0] = '\0'; - sprintf(info->bus_info, "IBM EMAC %d", fep->ocpdev->def->index); - info->regdump_len = 0; -} - -static int emac_nway_reset(struct net_device *ndev) -{ - struct ocp_enet_private *fep = ndev->priv; - - if (!fep->want_autoneg) - return -EINVAL; - spin_lock_irq(&fep->lock); - emac_start_link(fep, NULL); - spin_unlock_irq(&fep->lock); - return 0; -} - -static u32 emac_get_link(struct net_device *ndev) -{ - return netif_carrier_ok(ndev); + sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); + info->n_stats = emac_ethtool_get_stats_count(ndev); + info->regdump_len = emac_ethtool_get_regs_len(ndev); } static struct ethtool_ops emac_ethtool_ops = { - .get_settings = emac_get_settings, - .set_settings = emac_set_settings, - .get_drvinfo = emac_get_drvinfo, - .nway_reset = emac_nway_reset, - .get_link = emac_get_link + .get_settings = emac_ethtool_get_settings, + .set_settings = emac_ethtool_set_settings, + .get_drvinfo = emac_ethtool_get_drvinfo, + + .get_regs_len = emac_ethtool_get_regs_len, + .get_regs = emac_ethtool_get_regs, + + .nway_reset = emac_ethtool_nway_reset, + + .get_ringparam = emac_ethtool_get_ringparam, + .get_pauseparam = emac_ethtool_get_pauseparam, + + .get_rx_csum = emac_ethtool_get_rx_csum, + + .get_strings = emac_ethtool_get_strings, + .get_stats_count = emac_ethtool_get_stats_count, + .get_ethtool_stats = emac_ethtool_get_ethtool_stats, + + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, }; -static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - struct ocp_enet_private *fep = dev->priv; + struct ocp_enet_private *dev = ndev->priv; uint16_t *data = (uint16_t *) & rq->ifr_ifru; + DBG("%d: ioctl %08x" NL, dev->def->index, cmd); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + switch (cmd) { case SIOCGMIIPHY: - data[0] = fep->mii_phy_addr; + case SIOCDEVPRIVATE: + data[0] = dev->phy.address; /* Fall through */ case SIOCGMIIREG: - data[3] = emac_phy_read(dev, fep->mii_phy_addr, data[1]); + case SIOCDEVPRIVATE + 1: + data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); return 0; + case SIOCSMIIREG: + case SIOCDEVPRIVATE + 2: if (!capable(CAP_NET_ADMIN)) return -EPERM; - - emac_phy_write(dev, fep->mii_phy_addr, data[1], data[2]); + emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); return 0; default: return -EOPNOTSUPP; } } -static int emac_open(struct net_device *dev) +static int __init emac_probe(struct ocp_device *ocpdev) { - struct ocp_enet_private *fep = dev->priv; - int rc; - - spin_lock_irq(&fep->lock); - - fep->opened = 1; - netif_carrier_off(dev); - - /* Reset & configure the chip */ - emac_reset_configure(fep); - - spin_unlock_irq(&fep->lock); - - /* Request our interrupt lines */ - rc = request_irq(dev->irq, emac_mac_irq, 0, "IBM EMAC MAC", dev); - if (rc != 0) { - printk("dev->irq %d failed\n", dev->irq); - goto bail; - } - /* Kick the chip rx & tx channels into life */ - spin_lock_irq(&fep->lock); - emac_kick(fep); - spin_unlock_irq(&fep->lock); - - netif_start_queue(dev); - bail: - return rc; -} - -static int emac_close(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - - /* XXX Stop IRQ emitting here */ - spin_lock_irq(&fep->lock); - fep->opened = 0; - mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - netif_carrier_off(dev); - netif_stop_queue(dev); - - /* - * Check for a link, some PHYs don't provide a clock if - * no link is present. Some EMACs will not come out of - * soft reset without a PHY clock present. - */ - if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { - out_be32(&emacp->em0mr0, EMAC_M0_SRST); - udelay(10); - - if (emacp->em0mr0 & EMAC_M0_SRST) { - /*not sure what to do here hopefully it clears before another open */ - printk(KERN_ERR - "%s: Phy SoftReset didn't clear, no link?\n", - dev->name); - } - } - - /* Free the irq's */ - free_irq(dev->irq, dev); - - spin_unlock_irq(&fep->lock); - - return 0; -} - -static void emac_remove(struct ocp_device *ocpdev) -{ - struct net_device *dev = ocp_get_drvdata(ocpdev); - struct ocp_enet_private *ep = dev->priv; - - /* FIXME: locking, races, ... */ - ep->going_away = 1; - ocp_set_drvdata(ocpdev, NULL); - if (ep->rgmii_dev) - emac_close_rgmii(ep->rgmii_dev); - if (ep->zmii_dev) - emac_close_zmii(ep->zmii_dev); - - unregister_netdev(dev); - del_timer_sync(&ep->link_timer); - mal_unregister_commac(ep->mal, &ep->commac); - iounmap((void *)ep->emacp); - kfree(dev); -} - -struct mal_commac_ops emac_commac_ops = { - .txeob = &emac_txeob_dev, - .txde = &emac_txde_dev, - .rxeob = &emac_rxeob_dev, - .rxde = &emac_rxde_dev, -}; - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void emac_netpoll(struct net_device *ndev) -{ - emac_rxeob_dev((void *)ndev, 0); - emac_txeob_dev((void *)ndev, 0); -} -#endif - -static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal) -{ - int deferred_init = 0; - int rc = 0, i; + struct ocp_func_emac_data *emacdata = ocpdev->def->additions; struct net_device *ndev; - struct ocp_enet_private *ep; - struct ocp_func_emac_data *emacdata; - int commac_reg = 0; - u32 phy_map; + struct ocp_device *maldev; + struct ocp_enet_private *dev; + int err, i; + + DBG("%d: probe" NL, ocpdev->def->index); - emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; if (!emacdata) { printk(KERN_ERR "emac%d: Missing additional data!\n", ocpdev->def->index); @@ -1738,304 +1936,312 @@ static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal) /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct ocp_enet_private)); - if (ndev == NULL) { - printk(KERN_ERR - "emac%d: Could not allocate ethernet device.\n", + if (!ndev) { + printk(KERN_ERR "emac%d: could not allocate ethernet device!\n", ocpdev->def->index); return -ENOMEM; } - ep = ndev->priv; - ep->ndev = ndev; - ep->ocpdev = ocpdev; - ndev->irq = ocpdev->def->irq; - ep->wol_irq = emacdata->wol_irq; - if (emacdata->mdio_idx >= 0) { - if (emacdata->mdio_idx == ocpdev->def->index) { - /* Set the common MDIO net_device */ - mdio_ndev = ndev; - deferred_init = 1; + dev = ndev->priv; + dev->ndev = ndev; + dev->ldev = &ocpdev->dev; + dev->def = ocpdev->def; + SET_MODULE_OWNER(ndev); + + /* Find MAL device we are connected to */ + maldev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_MAL, emacdata->mal_idx); + if (!maldev) { + printk(KERN_ERR "emac%d: unknown mal%d device!\n", + dev->def->index, emacdata->mal_idx); + err = -ENODEV; + goto out; + } + dev->mal = ocp_get_drvdata(maldev); + if (!dev->mal) { + printk(KERN_ERR "emac%d: mal%d hasn't been initialized yet!\n", + dev->def->index, emacdata->mal_idx); + err = -ENODEV; + goto out; + } + + /* Register with MAL */ + dev->commac.ops = &emac_commac_ops; + dev->commac.dev = dev; + dev->commac.tx_chan_mask = MAL_CHAN_MASK(emacdata->mal_tx_chan); + dev->commac.rx_chan_mask = MAL_CHAN_MASK(emacdata->mal_rx_chan); + err = mal_register_commac(dev->mal, &dev->commac); + if (err) { + printk(KERN_ERR "emac%d: failed to register with mal%d!\n", + dev->def->index, emacdata->mal_idx); + goto out; + } + dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); + dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); + + /* Get pointers to BD rings */ + dev->tx_desc = + dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, + emacdata->mal_tx_chan); + dev->rx_desc = + dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, + emacdata->mal_rx_chan); + + DBG("%d: tx_desc %p" NL, ocpdev->def->index, dev->tx_desc); + DBG("%d: rx_desc %p" NL, ocpdev->def->index, dev->rx_desc); + + /* Clean rings */ + memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); + memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); + + /* If we depend on another EMAC for MDIO, check whether it was probed already */ + if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) { + struct ocp_device *mdiodev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, + emacdata->mdio_idx); + if (!mdiodev) { + printk(KERN_ERR "emac%d: unknown emac%d device!\n", + dev->def->index, emacdata->mdio_idx); + err = -ENODEV; + goto out2; } - ep->mdio_dev = mdio_ndev; - } else { - ep->mdio_dev = ndev; - } - - ocp_set_drvdata(ocpdev, ndev); - - spin_lock_init(&ep->lock); - - /* Fill out MAL informations and register commac */ - ep->mal = mal; - ep->mal_tx_chan = emacdata->mal_tx_chan; - ep->mal_rx_chan = emacdata->mal_rx_chan; - ep->commac.ops = &emac_commac_ops; - ep->commac.dev = ndev; - ep->commac.tx_chan_mask = MAL_CHAN_MASK(ep->mal_tx_chan); - ep->commac.rx_chan_mask = MAL_CHAN_MASK(ep->mal_rx_chan); - rc = mal_register_commac(ep->mal, &ep->commac); - if (rc != 0) - goto bail; - commac_reg = 1; - - /* Map our MMIOs */ - ep->emacp = (emac_t *) ioremap(ocpdev->def->paddr, sizeof(emac_t)); - - /* Check if we need to attach to a ZMII */ - if (emacdata->zmii_idx >= 0) { - ep->zmii_input = emacdata->zmii_mux; - ep->zmii_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_ZMII, - emacdata->zmii_idx); - if (ep->zmii_dev == NULL) - printk(KERN_WARNING - "emac%d: ZMII %d requested but not found !\n", - ocpdev->def->index, emacdata->zmii_idx); - else if ((rc = - emac_init_zmii(ep->zmii_dev, ep->zmii_input, - emacdata->phy_mode)) != 0) - goto bail; - } - - /* Check if we need to attach to a RGMII */ - if (emacdata->rgmii_idx >= 0) { - ep->rgmii_input = emacdata->rgmii_mux; - ep->rgmii_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_RGMII, - emacdata->rgmii_idx); - if (ep->rgmii_dev == NULL) - printk(KERN_WARNING - "emac%d: RGMII %d requested but not found !\n", - ocpdev->def->index, emacdata->rgmii_idx); - else if ((rc = - emac_init_rgmii(ep->rgmii_dev, ep->rgmii_input, - emacdata->phy_mode)) != 0) - goto bail; - } - - /* Check if we need to attach to a TAH */ - if (emacdata->tah_idx >= 0) { - ep->tah_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, - emacdata->tah_idx); - if (ep->tah_dev == NULL) - printk(KERN_WARNING - "emac%d: TAH %d requested but not found !\n", - ocpdev->def->index, emacdata->tah_idx); - else if ((rc = emac_init_tah(ep)) != 0) - goto bail; - } - - if (deferred_init) { - if (!list_empty(&emac_init_list)) { - struct list_head *entry; - struct emac_def_dev *ddev; - - list_for_each(entry, &emac_init_list) { - ddev = - list_entry(entry, struct emac_def_dev, - link); - emac_init_device(ddev->ocpdev, ddev->mal); - } + dev->mdio_dev = ocp_get_drvdata(mdiodev); + if (!dev->mdio_dev) { + printk(KERN_ERR + "emac%d: emac%d hasn't been initialized yet!\n", + dev->def->index, emacdata->mdio_idx); + err = -ENODEV; + goto out2; } } - /* Init link monitoring timer */ - init_timer(&ep->link_timer); - ep->link_timer.function = emac_link_timer; - ep->link_timer.data = (unsigned long)ep; - ep->timer_ticks = 0; + /* Attach to ZMII, if needed */ + if ((err = zmii_attach(dev)) != 0) + goto out2; - /* Fill up the mii_phy structure */ - ep->phy_mii.dev = ndev; - ep->phy_mii.mdio_read = emac_phy_read; - ep->phy_mii.mdio_write = emac_phy_write; - ep->phy_mii.mode = emacdata->phy_mode; + /* Attach to RGMII, if needed */ + if ((err = rgmii_attach(dev)) != 0) + goto out3; - /* Find PHY */ - phy_map = emacdata->phy_map | busy_phy_map; - for (i = 0; i <= 0x1f; i++, phy_map >>= 1) { - if ((phy_map & 0x1) == 0) { - int val = emac_phy_read(ndev, i, MII_BMCR); - if (val != 0xffff && val != -1) - break; - } - } - if (i == 0x20) { - printk(KERN_WARNING "emac%d: Can't find PHY.\n", - ocpdev->def->index); - rc = -ENODEV; - goto bail; - } - busy_phy_map |= 1 << i; - ep->mii_phy_addr = i; - rc = mii_phy_probe(&ep->phy_mii, i); - if (rc) { - printk(KERN_WARNING "emac%d: Failed to probe PHY type.\n", - ocpdev->def->index); - rc = -ENODEV; - goto bail; - } - - /* Disable any PHY features not supported by the platform */ - ep->phy_mii.def->features &= ~emacdata->phy_feat_exc; + /* Attach to TAH, if needed */ + if ((err = tah_attach(dev)) != 0) + goto out4; - /* Setup initial PHY config & startup aneg */ - if (ep->phy_mii.def->ops->init) - ep->phy_mii.def->ops->init(&ep->phy_mii); - netif_carrier_off(ndev); - if (ep->phy_mii.def->features & SUPPORTED_Autoneg) - ep->want_autoneg = 1; - else { - ep->want_autoneg = 0; - - /* Select highest supported speed/duplex */ - if (ep->phy_mii.def->features & SUPPORTED_1000baseT_Full) { - ep->phy_mii.speed = SPEED_1000; - ep->phy_mii.duplex = DUPLEX_FULL; - } else if (ep->phy_mii.def->features & - SUPPORTED_1000baseT_Half) { - ep->phy_mii.speed = SPEED_1000; - ep->phy_mii.duplex = DUPLEX_HALF; - } else if (ep->phy_mii.def->features & - SUPPORTED_100baseT_Full) { - ep->phy_mii.speed = SPEED_100; - ep->phy_mii.duplex = DUPLEX_FULL; - } else if (ep->phy_mii.def->features & - SUPPORTED_100baseT_Half) { - ep->phy_mii.speed = SPEED_100; - ep->phy_mii.duplex = DUPLEX_HALF; - } else if (ep->phy_mii.def->features & - SUPPORTED_10baseT_Full) { - ep->phy_mii.speed = SPEED_10; - ep->phy_mii.duplex = DUPLEX_FULL; - } else { - ep->phy_mii.speed = SPEED_10; - ep->phy_mii.duplex = DUPLEX_HALF; - } + /* Map EMAC regs */ + dev->emacp = + (struct emac_regs *)ioremap(dev->def->paddr, + sizeof(struct emac_regs)); + if (!dev->emacp) { + printk(KERN_ERR "emac%d: could not ioremap device registers!\n", + dev->def->index); + err = -ENOMEM; + goto out5; } - emac_start_link(ep, NULL); - /* read the MAC Address */ - for (i = 0; i < 6; i++) + /* Fill in MAC address */ + for (i = 0; i < 6; ++i) ndev->dev_addr[i] = emacdata->mac_addr[i]; + /* Set some link defaults before we can find out real parameters */ + dev->phy.speed = SPEED_100; + dev->phy.duplex = DUPLEX_FULL; + dev->phy.autoneg = AUTONEG_DISABLE; + dev->phy.pause = dev->phy.asym_pause = 0; + init_timer(&dev->link_timer); + dev->link_timer.function = emac_link_timer; + dev->link_timer.data = (unsigned long)dev; + + /* Find PHY if any */ + dev->phy.dev = ndev; + dev->phy.mode = emacdata->phy_mode; + if (emacdata->phy_map != 0xffffffff) { + u32 phy_map = emacdata->phy_map | busy_phy_map; + u32 adv; + + DBG("%d: PHY maps %08x %08x" NL, dev->def->index, + emacdata->phy_map, busy_phy_map); + + EMAC_RX_CLK_TX(dev->def->index); + + dev->phy.mdio_read = emac_mdio_read; + dev->phy.mdio_write = emac_mdio_write; + + /* Configure EMAC with defaults so we can at least use MDIO + * This is needed mostly for 440GX + */ + if (emac_phy_gpcs(dev->phy.mode)) { + /* XXX + * Make GPCS PHY address equal to EMAC index. + * We probably should take into account busy_phy_map + * and/or phy_map here. + */ + dev->phy.address = dev->def->index; + } + + emac_configure(dev); + + for (i = 0; i < 0x20; phy_map >>= 1, ++i) + if (!(phy_map & 1)) { + int r; + busy_phy_map |= 1 << i; + + /* Quick check if there is a PHY at the address */ + r = emac_mdio_read(dev->ndev, i, MII_BMCR); + if (r == 0xffff || r < 0) + continue; + if (!mii_phy_probe(&dev->phy, i)) + break; + } + if (i == 0x20) { + printk(KERN_WARNING "emac%d: can't find PHY!\n", + dev->def->index); + goto out6; + } + + /* Init PHY */ + if (dev->phy.def->ops->init) + dev->phy.def->ops->init(&dev->phy); + + /* Disable any PHY features not supported by the platform */ + dev->phy.def->features &= ~emacdata->phy_feat_exc; + + /* Setup initial link parameters */ + if (dev->phy.features & SUPPORTED_Autoneg) { + adv = dev->phy.features; +#if !defined(CONFIG_40x) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; +#endif + /* Restart autonegotiation */ + dev->phy.def->ops->setup_aneg(&dev->phy, adv); + } else { + u32 f = dev->phy.def->features; + int speed = SPEED_10, fd = DUPLEX_HALF; + + /* Select highest supported speed/duplex */ + if (f & SUPPORTED_1000baseT_Full) { + speed = SPEED_1000; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_1000baseT_Half) + speed = SPEED_1000; + else if (f & SUPPORTED_100baseT_Full) { + speed = SPEED_100; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_100baseT_Half) + speed = SPEED_100; + else if (f & SUPPORTED_10baseT_Full) + fd = DUPLEX_FULL; + + /* Force link parameters */ + dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); + } + } else { + emac_reset(dev); + + /* PHY-less configuration. + * XXX I probably should move these settings to emacdata + */ + dev->phy.address = -1; + dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.pause = 1; + } + /* Fill in the driver function table */ ndev->open = &emac_open; - ndev->hard_start_xmit = &emac_start_xmit; + if (dev->tah_dev) { + ndev->hard_start_xmit = &emac_start_xmit_sg; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + } else + ndev->hard_start_xmit = &emac_start_xmit; + ndev->tx_timeout = &emac_full_tx_reset; + ndev->watchdog_timeo = 5 * HZ; ndev->stop = &emac_close; ndev->get_stats = &emac_stats; - if (emacdata->jumbo) - ndev->change_mtu = &emac_change_mtu; - ndev->set_mac_address = &emac_set_mac_address; ndev->set_multicast_list = &emac_set_multicast_list; ndev->do_ioctl = &emac_ioctl; + if (emac_phy_supports_gige(emacdata->phy_mode)) { + ndev->change_mtu = &emac_change_mtu; + dev->commac.ops = &emac_commac_sg_ops; + } SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); - if (emacdata->tah_idx >= 0) - ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG; -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = emac_netpoll; -#endif - SET_MODULE_OWNER(ndev); + netif_carrier_off(ndev); + netif_stop_queue(ndev); - rc = register_netdev(ndev); - if (rc != 0) - goto bail; + err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "emac%d: failed to register net device (%d)!\n", + dev->def->index, err); + goto out6; + } - printk("%s: IBM emac, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, + ocp_set_drvdata(ocpdev, dev); + + printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, dev->def->index, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); - printk(KERN_INFO "%s: Found %s PHY (0x%02x)\n", - ndev->name, ep->phy_mii.def->name, ep->mii_phy_addr); - bail: - if (rc && commac_reg) - mal_unregister_commac(ep->mal, &ep->commac); - if (rc && ndev) - kfree(ndev); + if (dev->phy.address >= 0) + printk("%s: found %s PHY (0x%02x)\n", ndev->name, + dev->phy.def->name, dev->phy.address); - return rc; -} - -static int emac_probe(struct ocp_device *ocpdev) -{ - struct ocp_device *maldev; - struct ibm_ocp_mal *mal; - struct ocp_func_emac_data *emacdata; - - emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; - if (emacdata == NULL) { - printk(KERN_ERR "emac%d: Missing additional datas !\n", - ocpdev->def->index); - return -ENODEV; - } - - /* Get the MAL device */ - maldev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_MAL, emacdata->mal_idx); - if (maldev == NULL) { - printk("No maldev\n"); - return -ENODEV; - } - /* - * Get MAL driver data, it must be here due to link order. - * When the driver is modularized, symbol dependencies will - * ensure the MAL driver is already present if built as a - * module. - */ - mal = (struct ibm_ocp_mal *)ocp_get_drvdata(maldev); - if (mal == NULL) { - printk("No maldrv\n"); - return -ENODEV; - } - - /* If we depend on another EMAC for MDIO, wait for it to show up */ - if (emacdata->mdio_idx >= 0 && - (emacdata->mdio_idx != ocpdev->def->index) && !mdio_ndev) { - struct emac_def_dev *ddev; - /* Add this index to the deferred init table */ - ddev = kmalloc(sizeof(struct emac_def_dev), GFP_KERNEL); - ddev->ocpdev = ocpdev; - ddev->mal = mal; - list_add_tail(&ddev->link, &emac_init_list); - } else { - emac_init_device(ocpdev, mal); - } + emac_dbg_register(dev->def->index, dev); return 0; + out6: + iounmap((void *)dev->emacp); + out5: + tah_fini(dev->tah_dev); + out4: + rgmii_fini(dev->rgmii_dev, dev->rgmii_input); + out3: + zmii_fini(dev->zmii_dev, dev->zmii_input); + out2: + mal_unregister_commac(dev->mal, &dev->commac); + out: + kfree(ndev); + return err; } -/* Structure for a device driver */ static struct ocp_device_id emac_ids[] = { - {.vendor = OCP_ANY_ID,.function = OCP_FUNC_EMAC}, - {.vendor = OCP_VENDOR_INVALID} + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_EMAC }, + { .vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver emac_driver = { .name = "emac", .id_table = emac_ids, - .probe = emac_probe, .remove = emac_remove, }; static int __init emac_init(void) { - printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n"); - printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n"); + printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); - if (skb_res > 2) { - printk(KERN_WARNING "Invalid skb_res: %d, cropping to 2\n", - skb_res); - skb_res = 2; + DBG(": init" NL); + + if (mal_init()) + return -ENODEV; + + EMAC_CLK_INTERNAL; + if (ocp_register_driver(&emac_driver)) { + EMAC_CLK_EXTERNAL; + ocp_unregister_driver(&emac_driver); + mal_exit(); + return -ENODEV; } + EMAC_CLK_EXTERNAL; - return ocp_register_driver(&emac_driver); + emac_init_debug(); + return 0; } static void __exit emac_exit(void) { + DBG(": exit" NL); ocp_unregister_driver(&emac_driver); + mal_exit(); + emac_fini_debug(); } module_init(emac_init); diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h index 97e6e1ea8c89..e9b44d030ac3 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -1,146 +1,221 @@ /* - * ibm_emac_core.h + * drivers/net/ibm_emac/ibm_emac_core.h * - * Ethernet driver for the built in ethernet on the IBM 405 PowerPC - * processor. + * Driver for PowerPC 4xx on-chip ethernet controller. * - * Armin Kuster akuster@mvista.com - * Sept, 2001 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or * - * Orignial driver - * Johnnie Peters - * jpeters@mvista.com - * - * Copyright 2000 MontaVista Softare Inc. + * Based on original work by + * Armin Kuster + * Johnnie Peters + * Copyright 2000, 2001 MontaVista Softare 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 __IBM_EMAC_CORE_H_ +#define __IBM_EMAC_CORE_H_ -#ifndef _IBM_EMAC_CORE_H_ -#define _IBM_EMAC_CORE_H_ - +#include #include +#include #include -#include /* For phys_addr_t */ #include "ibm_emac.h" #include "ibm_emac_phy.h" -#include "ibm_emac_rgmii.h" #include "ibm_emac_zmii.h" +#include "ibm_emac_rgmii.h" #include "ibm_emac_mal.h" #include "ibm_emac_tah.h" -#ifndef CONFIG_IBM_EMAC_TXB -#define NUM_TX_BUFF 64 -#define NUM_RX_BUFF 64 -#else -#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB -#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB +#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB + +/* Simple sanity check */ +#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 +#error Invalid number of buffer descriptors (greater than 256) #endif -/* This does 16 byte alignment, exactly what we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. +// XXX +#define EMAC_MIN_MTU 46 +#define EMAC_MAX_MTU 9000 + +/* Maximum L2 header length (VLAN tagged, no FCS) */ +#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) + +/* RX BD size for the given MTU */ +static inline int emac_rx_size(int mtu) +{ + if (mtu > ETH_DATA_LEN) + return MAL_MAX_RX_SIZE; + else + return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); +} + +#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) + +#define EMAC_RX_SKB_HEADROOM \ + EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM) + +/* Size of RX skb for the given MTU */ +static inline int emac_rx_skb_size(int mtu) +{ + int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); + return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; +} + +/* RX DMA sync size */ +static inline int emac_rx_sync_size(int mtu) +{ + return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); +} + +/* Driver statistcs is split into two parts to make it more cache friendly: + * - normal statistics (packet count, etc) + * - error statistics + * + * When statistics is requested by ethtool, these parts are concatenated, + * normal one goes first. + * + * Please, keep these structures in sync with emac_stats_keys. */ -#ifndef CONFIG_IBM_EMAC_SKBRES -#define SKB_RES 2 -#else -#define SKB_RES CONFIG_IBM_EMAC_SKBRES -#endif -/* Note about alignement. alloc_skb() returns a cache line - * aligned buffer. However, dev_alloc_skb() will add 16 more - * bytes and "reserve" them, so our buffer will actually end - * on a half cache line. What we do is to use directly - * alloc_skb, allocate 16 more bytes to match the total amount - * allocated by dev_alloc_skb(), but we don't reserve. - */ -#define MAX_NUM_BUF_DESC 255 -#define DESC_BUF_SIZE 4080 /* max 4096-16 */ -#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16) +/* Normal TX/RX Statistics */ +struct ibm_emac_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets_csum; + u64 tx_packets_csum; +}; -/* Transmitter timeout. */ -#define TX_TIMEOUT (2*HZ) +/* Error statistics */ +struct ibm_emac_error_stats { + u64 tx_undo; -/* MDIO latency delay */ -#define MDIO_DELAY 250 + /* Software RX Errors */ + u64 rx_dropped_stack; + u64 rx_dropped_oom; + u64 rx_dropped_error; + u64 rx_dropped_resize; + u64 rx_dropped_mtu; + u64 rx_stopped; + /* BD reported RX errors */ + u64 rx_bd_errors; + u64 rx_bd_overrun; + u64 rx_bd_bad_packet; + u64 rx_bd_runt_packet; + u64 rx_bd_short_event; + u64 rx_bd_alignment_error; + u64 rx_bd_bad_fcs; + u64 rx_bd_packet_too_long; + u64 rx_bd_out_of_range; + u64 rx_bd_in_range; + /* EMAC IRQ reported RX errors */ + u64 rx_parity; + u64 rx_fifo_overrun; + u64 rx_overrun; + u64 rx_bad_packet; + u64 rx_runt_packet; + u64 rx_short_event; + u64 rx_alignment_error; + u64 rx_bad_fcs; + u64 rx_packet_too_long; + u64 rx_out_of_range; + u64 rx_in_range; -/* Power managment shift registers */ -#define IBM_CPM_EMMII 0 /* Shift value for MII */ -#define IBM_CPM_EMRX 1 /* Shift value for recv */ -#define IBM_CPM_EMTX 2 /* Shift value for MAC */ -#define IBM_CPM_EMAC(x) (((x)>>IBM_CPM_EMMII) | ((x)>>IBM_CPM_EMRX) | ((x)>>IBM_CPM_EMTX)) + /* Software TX Errors */ + u64 tx_dropped; + /* BD reported TX errors */ + u64 tx_bd_errors; + u64 tx_bd_bad_fcs; + u64 tx_bd_carrier_loss; + u64 tx_bd_excessive_deferral; + u64 tx_bd_excessive_collisions; + u64 tx_bd_late_collision; + u64 tx_bd_multple_collisions; + u64 tx_bd_single_collision; + u64 tx_bd_underrun; + u64 tx_bd_sqe; + /* EMAC IRQ reported TX errors */ + u64 tx_parity; + u64 tx_underrun; + u64 tx_sqe; + u64 tx_errors; +}; -#define ENET_HEADER_SIZE 14 -#define ENET_FCS_SIZE 4 -#define ENET_DEF_MTU_SIZE 1500 -#define ENET_DEF_BUF_SIZE (ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE) -#define EMAC_MIN_FRAME 64 -#define EMAC_MAX_FRAME 9018 -#define EMAC_MIN_MTU (EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) -#define EMAC_MAX_MTU (EMAC_MAX_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) - -#ifdef CONFIG_IBM_EMAC_ERRMSG -void emac_serr_dump_0(struct net_device *dev); -void emac_serr_dump_1(struct net_device *dev); -void emac_err_dump(struct net_device *dev, int em0isr); -void emac_phy_dump(struct net_device *); -void emac_desc_dump(struct net_device *); -void emac_mac_dump(struct net_device *); -void emac_mal_dump(struct net_device *); -#else -#define emac_serr_dump_0(dev) do { } while (0) -#define emac_serr_dump_1(dev) do { } while (0) -#define emac_err_dump(dev,x) do { } while (0) -#define emac_phy_dump(dev) do { } while (0) -#define emac_desc_dump(dev) do { } while (0) -#define emac_mac_dump(dev) do { } while (0) -#define emac_mal_dump(dev) do { } while (0) -#endif +#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \ + sizeof(struct ibm_emac_error_stats)) \ + / sizeof(u64)) struct ocp_enet_private { - struct sk_buff *tx_skb[NUM_TX_BUFF]; - struct sk_buff *rx_skb[NUM_RX_BUFF]; - struct mal_descriptor *tx_desc; - struct mal_descriptor *rx_desc; - struct mal_descriptor *rx_dirty; - struct net_device_stats stats; - int tx_cnt; - int rx_slot; - int dirty_rx; - int tx_slot; - int ack_slot; - int rx_buffer_size; + struct net_device *ndev; /* 0 */ + struct emac_regs *emacp; + + struct mal_descriptor *tx_desc; + int tx_cnt; + int tx_slot; + int ack_slot; - struct mii_phy phy_mii; - int mii_phy_addr; - int want_autoneg; - int timer_ticks; - struct timer_list link_timer; - struct net_device *mdio_dev; + struct mal_descriptor *rx_desc; + int rx_slot; + struct sk_buff *rx_sg_skb; /* 1 */ + int rx_skb_size; + int rx_sync_size; - struct ocp_device *rgmii_dev; - int rgmii_input; + struct ibm_emac_stats stats; + struct ocp_device *tah_dev; - struct ocp_device *zmii_dev; - int zmii_input; + struct ibm_ocp_mal *mal; + struct mal_commac commac; - struct ibm_ocp_mal *mal; - int mal_tx_chan, mal_rx_chan; - struct mal_commac commac; + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; - struct ocp_device *tah_dev; + struct ocp_device *zmii_dev; + int zmii_input; + struct ocp_enet_private *mdio_dev; + struct ocp_device *rgmii_dev; + int rgmii_input; - int opened; - int going_away; - int wol_irq; - emac_t *emacp; - struct ocp_device *ocpdev; - struct net_device *ndev; - spinlock_t lock; + struct ocp_def *def; + + struct mii_phy phy; + struct timer_list link_timer; + int reset_failed; + + struct ibm_emac_error_stats estats; + struct net_device_stats nstats; + + struct device* ldev; }; -#endif /* _IBM_EMAC_CORE_H_ */ + +/* Ethtool get_regs complex data. + * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH + * when available. + * + * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, + * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. + * Each register component is preceded with emac_ethtool_regs_subhdr. + * Order of the optional headers follows their relative bit posititions + * in emac_ethtool_regs_hdr.components + */ +#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 +#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 +#define EMAC_ETHTOOL_REGS_TAH 0x00000004 + +struct emac_ethtool_regs_hdr { + u32 components; +}; + +struct emac_ethtool_regs_subhdr { + u32 version; + u32 index; +}; + +#endif /* __IBM_EMAC_CORE_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index c8512046cf84..75d3b8639041 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -1,224 +1,213 @@ /* - * ibm_ocp_debug.c + * drivers/net/ibm_emac/ibm_emac_debug.c * - * This has all the debug routines that where in *_enet.c + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. * - * Armin Kuster akuster@mvista.com - * April , 2002 - * - * Copyright 2002 MontaVista Softare Inc. + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or * * 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 "ibm_ocp_mal.h" -#include "ibm_ocp_zmii.h" -#include "ibm_ocp_enet.h" -extern int emac_phy_read(struct net_device *dev, int mii_id, int reg); +#include "ibm_emac_core.h" -void emac_phy_dump(struct net_device *dev) +static void emac_desc_dump(int idx, struct ocp_enet_private *p) { - struct ocp_enet_private *fep = dev->priv; - unsigned long i; - uint data; + int i; + printk("** EMAC%d TX BDs **\n" + " tx_cnt = %d tx_slot = %d ack_slot = %d\n", + idx, p->tx_cnt, p->tx_slot, p->ack_slot); + for (i = 0; i < NUM_TX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', + p->tx_desc[i].ctrl, p->tx_desc[i].data_len, + NUM_TX_BUFF / 2 + i, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, + p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', + p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); - printk(KERN_DEBUG " Prepare for Phy dump....\n"); - for (i = 0; i < 0x1A; i++) { - data = emac_phy_read(dev, fep->mii_phy_addr, i); - printk(KERN_DEBUG "Phy reg 0x%lx ==> %4x\n", i, data); - if (i == 0x07) - i = 0x0f; + printk("** EMAC%d RX BDs **\n" + " rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n" + " rx_sg_skb = 0x%p\n", + idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size, + p->rx_sync_size, p->rx_sg_skb); + for (i = 0; i < NUM_RX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', + p->rx_desc[i].ctrl, p->rx_desc[i].data_len, + NUM_RX_BUFF / 2 + i, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, + p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', + p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); +} + +static void emac_mac_dump(int idx, struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + + printk("** EMAC%d registers **\n" + "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" + "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" + "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" + "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " + "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" + "LSA = %04x%08x IPGVR = 0x%04x\n" + "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" + "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", + idx, in_be32(&p->mr0), in_be32(&p->mr1), + in_be32(&p->tmr0), in_be32(&p->tmr1), + in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), + in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), + in_be32(&p->vtci), + in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), + in_be32(&p->iaht4), + in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), + in_be32(&p->gaht4), + in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), + in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), + in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) + ); + + emac_desc_dump(idx, dev); +} + +static void emac_mal_dump(struct ibm_ocp_mal *mal) +{ + struct ocp_func_mal_data *maldata = mal->def->additions; + int i; + + printk("** MAL%d Registers **\n" + "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" + "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" + "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", + mal->def->index, + get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), + get_mal_dcrn(mal, MAL_IER), + get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), + get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), + get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), + get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) + ); + + printk("TX|"); + for (i = 0; i < maldata->num_tx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); } -} - -void emac_desc_dump(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - int curr_slot; - - printk(KERN_DEBUG - "dumping the receive descriptors: current slot is %d\n", - fep->rx_slot); - for (curr_slot = 0; curr_slot < NUM_RX_BUFF; curr_slot++) { - printk(KERN_DEBUG - "Desc %02d: status 0x%04x, length %3d, addr 0x%x\n", - curr_slot, fep->rx_desc[curr_slot].ctrl, - fep->rx_desc[curr_slot].data_len, - (unsigned int)fep->rx_desc[curr_slot].data_ptr); + printk("\nRX|"); + for (i = 0; i < maldata->num_rx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); } -} - -void emac_mac_dump(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - volatile emac_t *emacp = fep->emacp; - - printk(KERN_DEBUG "EMAC DEBUG ********** \n"); - printk(KERN_DEBUG "EMAC_M0 ==> 0x%x\n", in_be32(&emacp->em0mr0)); - printk(KERN_DEBUG "EMAC_M1 ==> 0x%x\n", in_be32(&emacp->em0mr1)); - printk(KERN_DEBUG "EMAC_TXM0==> 0x%x\n", in_be32(&emacp->em0tmr0)); - printk(KERN_DEBUG "EMAC_TXM1==> 0x%x\n", in_be32(&emacp->em0tmr1)); - printk(KERN_DEBUG "EMAC_RXM ==> 0x%x\n", in_be32(&emacp->em0rmr)); - printk(KERN_DEBUG "EMAC_ISR ==> 0x%x\n", in_be32(&emacp->em0isr)); - printk(KERN_DEBUG "EMAC_IER ==> 0x%x\n", in_be32(&emacp->em0iser)); - printk(KERN_DEBUG "EMAC_IAH ==> 0x%x\n", in_be32(&emacp->em0iahr)); - printk(KERN_DEBUG "EMAC_IAL ==> 0x%x\n", in_be32(&emacp->em0ialr)); - printk(KERN_DEBUG "EMAC_VLAN_TPID_REG ==> 0x%x\n", - in_be32(&emacp->em0vtpid)); -} - -void emac_mal_dump(struct net_device *dev) -{ - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - - printk(KERN_DEBUG " MAL DEBUG ********** \n"); - printk(KERN_DEBUG " MCR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALCR)); - printk(KERN_DEBUG " ESR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALESR)); - printk(KERN_DEBUG " IER ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALIER)); -#ifdef CONFIG_40x - printk(KERN_DEBUG " DBR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALDBR)); -#endif /* CONFIG_40x */ - printk(KERN_DEBUG " TXCASR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCASR)); - printk(KERN_DEBUG " TXCARR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCARR)); - printk(KERN_DEBUG " TXEOBISR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXEOBISR)); - printk(KERN_DEBUG " TXDEIR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXDEIR)); - printk(KERN_DEBUG " RXCASR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCASR)); - printk(KERN_DEBUG " RXCARR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCARR)); - printk(KERN_DEBUG " RXEOBISR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXEOBISR)); - printk(KERN_DEBUG " RXDEIR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXDEIR)); - printk(KERN_DEBUG " TXCTP0R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP0R)); - printk(KERN_DEBUG " TXCTP1R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP1R)); - printk(KERN_DEBUG " TXCTP2R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP2R)); - printk(KERN_DEBUG " TXCTP3R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP3R)); - printk(KERN_DEBUG " RXCTP0R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP0R)); - printk(KERN_DEBUG " RXCTP1R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP1R)); - printk(KERN_DEBUG " RCBS0 ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS0)); - printk(KERN_DEBUG " RCBS1 ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS1)); -} - -void emac_serr_dump_0(struct net_device *dev) -{ - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - unsigned long int mal_error, plb_error, plb_addr; - - mal_error = get_mal_dcrn(mal, DCRN_MALESR); - printk(KERN_DEBUG "ppc405_eth_serr: %s channel %ld \n", - (mal_error & 0x40000000) ? "Receive" : - "Transmit", (mal_error & 0x3e000000) >> 25); - printk(KERN_DEBUG " ----- latched error -----\n"); - if (mal_error & MALESR_DE) - printk(KERN_DEBUG " DE: descriptor error\n"); - if (mal_error & MALESR_OEN) - printk(KERN_DEBUG " ONE: OPB non-fullword error\n"); - if (mal_error & MALESR_OTE) - printk(KERN_DEBUG " OTE: OPB timeout error\n"); - if (mal_error & MALESR_OSE) - printk(KERN_DEBUG " OSE: OPB slave error\n"); - - if (mal_error & MALESR_PEIN) { - plb_error = mfdcr(DCRN_PLB0_BESR); - printk(KERN_DEBUG - " PEIN: PLB error, PLB0_BESR is 0x%x\n", - (unsigned int)plb_error); - plb_addr = mfdcr(DCRN_PLB0_BEAR); - printk(KERN_DEBUG - " PEIN: PLB error, PLB0_BEAR is 0x%x\n", - (unsigned int)plb_addr); + printk("\n "); + for (i = 0; i < maldata->num_rx_chans; ++i) { + u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); + if (i && !(i % 3)) + printk("\n "); + printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); } + printk("\n"); } -void emac_serr_dump_1(struct net_device *dev) +static struct ocp_enet_private *__emacs[4]; +static struct ibm_ocp_mal *__mals[1]; + +void emac_dbg_register(int idx, struct ocp_enet_private *dev) { - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - int mal_error = get_mal_dcrn(mal, DCRN_MALESR); + unsigned long flags; - printk(KERN_DEBUG " ----- cumulative errors -----\n"); - if (mal_error & MALESR_DEI) - printk(KERN_DEBUG " DEI: descriptor error interrupt\n"); - if (mal_error & MALESR_ONEI) - printk(KERN_DEBUG " OPB non-fullword error interrupt\n"); - if (mal_error & MALESR_OTEI) - printk(KERN_DEBUG " OTEI: timeout error interrupt\n"); - if (mal_error & MALESR_OSEI) - printk(KERN_DEBUG " OSEI: slave error interrupt\n"); - if (mal_error & MALESR_PBEI) - printk(KERN_DEBUG " PBEI: PLB bus error interrupt\n"); + if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) { + printk(KERN_WARNING + "invalid index %d when registering EMAC for debugging\n", + idx); + return; + } + + local_irq_save(flags); + __emacs[idx] = dev; + local_irq_restore(flags); } -void emac_err_dump(struct net_device *dev, int em0isr) +void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) { - printk(KERN_DEBUG "%s: on-chip ethernet error:\n", dev->name); + unsigned long flags; - if (em0isr & EMAC_ISR_OVR) - printk(KERN_DEBUG " OVR: overrun\n"); - if (em0isr & EMAC_ISR_PP) - printk(KERN_DEBUG " PP: control pause packet\n"); - if (em0isr & EMAC_ISR_BP) - printk(KERN_DEBUG " BP: packet error\n"); - if (em0isr & EMAC_ISR_RP) - printk(KERN_DEBUG " RP: runt packet\n"); - if (em0isr & EMAC_ISR_SE) - printk(KERN_DEBUG " SE: short event\n"); - if (em0isr & EMAC_ISR_ALE) - printk(KERN_DEBUG " ALE: odd number of nibbles in packet\n"); - if (em0isr & EMAC_ISR_BFCS) - printk(KERN_DEBUG " BFCS: bad FCS\n"); - if (em0isr & EMAC_ISR_PTLE) - printk(KERN_DEBUG " PTLE: oversized packet\n"); - if (em0isr & EMAC_ISR_ORE) - printk(KERN_DEBUG - " ORE: packet length field > max allowed LLC\n"); - if (em0isr & EMAC_ISR_IRE) - printk(KERN_DEBUG " IRE: In Range error\n"); - if (em0isr & EMAC_ISR_DBDM) - printk(KERN_DEBUG " DBDM: xmit error or SQE\n"); - if (em0isr & EMAC_ISR_DB0) - printk(KERN_DEBUG " DB0: xmit error or SQE on TX channel 0\n"); - if (em0isr & EMAC_ISR_SE0) - printk(KERN_DEBUG - " SE0: Signal Quality Error test failure from TX channel 0\n"); - if (em0isr & EMAC_ISR_TE0) - printk(KERN_DEBUG " TE0: xmit channel 0 aborted\n"); - if (em0isr & EMAC_ISR_DB1) - printk(KERN_DEBUG " DB1: xmit error or SQE on TX channel \n"); - if (em0isr & EMAC_ISR_SE1) - printk(KERN_DEBUG - " SE1: Signal Quality Error test failure from TX channel 1\n"); - if (em0isr & EMAC_ISR_TE1) - printk(KERN_DEBUG " TE1: xmit channel 1 aborted\n"); - if (em0isr & EMAC_ISR_MOS) - printk(KERN_DEBUG " MOS\n"); - if (em0isr & EMAC_ISR_MOF) - printk(KERN_DEBUG " MOF\n"); + if (idx >= sizeof(__mals) / sizeof(__mals[0])) { + printk(KERN_WARNING + "invalid index %d when registering MAL for debugging\n", + idx); + return; + } - emac_mac_dump(dev); - emac_mal_dump(dev); + local_irq_save(flags); + __mals[idx] = mal; + local_irq_restore(flags); } + +void emac_dbg_dump_all(void) +{ + unsigned int i; + unsigned long flags; + + local_irq_save(flags); + + for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i) + if (__mals[i]) + emac_mal_dump(__mals[i]); + + for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i) + if (__emacs[i]) + emac_mac_dump(i, __emacs[i]); + + local_irq_restore(flags); +} + +#if defined(CONFIG_MAGIC_SYSRQ) +static void emac_sysrq_handler(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + emac_dbg_dump_all(); +} + +static struct sysrq_key_op emac_sysrq_op = { + .handler = emac_sysrq_handler, + .help_msg = "emaC", + .action_msg = "Show EMAC(s) status", +}; + +int __init emac_init_debug(void) +{ + return register_sysrq_key('c', &emac_sysrq_op); +} + +void __exit emac_fini_debug(void) +{ + unregister_sysrq_key('c', &emac_sysrq_op); +} + +#else +int __init emac_init_debug(void) +{ + return 0; +} +void __exit emac_fini_debug(void) +{ +} +#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h new file mode 100644 index 000000000000..e85fbe0a8da9 --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_debug.h @@ -0,0 +1,63 @@ +/* + * drivers/net/ibm_emac/ibm_ocp_debug.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or + * + * 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 __IBM_EMAC_DEBUG_H_ +#define __IBM_EMAC_DEBUG_H_ + +#include +#include +#include "ibm_emac_core.h" +#include "ibm_emac_mal.h" + +#if defined(CONFIG_IBM_EMAC_DEBUG) +void emac_dbg_register(int idx, struct ocp_enet_private *dev); +void mal_dbg_register(int idx, struct ibm_ocp_mal *mal); +int emac_init_debug(void) __init; +void emac_fini_debug(void) __exit; +void emac_dbg_dump_all(void); +# define DBG_LEVEL 1 +#else +# define emac_dbg_register(x,y) ((void)0) +# define mal_dbg_register(x,y) ((void)0) +# define emac_init_debug() ((void)0) +# define emac_fini_debug() ((void)0) +# define emac_dbg_dump_all() ((void)0) +# define DBG_LEVEL 0 +#endif + +#if DBG_LEVEL > 0 +# define DBG(f,x...) printk("emac" f, ##x) +# define MAL_DBG(f,x...) printk("mal" f, ##x) +# define ZMII_DBG(f,x...) printk("zmii" f, ##x) +# define RGMII_DBG(f,x...) printk("rgmii" f, ##x) +# define NL "\n" +#else +# define DBG(f,x...) ((void)0) +# define MAL_DBG(f,x...) ((void)0) +# define ZMII_DBG(f,x...) ((void)0) +# define RGMII_DBG(f,x...) ((void)0) +#endif +#if DBG_LEVEL > 1 +# define DBG2(f,x...) DBG(f, ##x) +# define MAL_DBG2(f,x...) MAL_DBG(f, ##x) +# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x) +# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x) +#else +# define DBG2(f,x...) ((void)0) +# define MAL_DBG2(f,x...) ((void)0) +# define ZMII_DBG2(f,x...) ((void)0) +# define RGMII_DBG2(f,x...) ((void)0) +#endif + +#endif /* __IBM_EMAC_DEBUG_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index e59f57f363ca..da88d43081cc 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -1,436 +1,565 @@ /* - * ibm_ocp_mal.c + * drivers/net/ibm_emac/ibm_emac_mal.c * - * Armin Kuster akuster@mvista.com - * Juen, 2002 + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or * - * Copyright 2002 MontaVista Softare Inc. + * Based on original work by + * Benjamin Herrenschmidt , + * David Gibson , + * + * Armin Kuster + * Copyright 2002 MontaVista Softare 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 "ibm_emac_core.h" #include "ibm_emac_mal.h" +#include "ibm_emac_debug.h" -// Locking: Should we share a lock with the client ? The client could provide -// a lock pointer (optionally) in the commac structure... I don't think this is -// really necessary though - -/* This lock protects the commac list. On today UP implementations, it's - * really only used as IRQ protection in mal_{register,unregister}_commac() - */ -static DEFINE_RWLOCK(mal_list_lock); - -int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +int __init mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) { unsigned long flags; + local_irq_save(flags); - write_lock_irqsave(&mal_list_lock, flags); + MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index, + commac->tx_chan_mask, commac->rx_chan_mask); - /* Don't let multiple commacs claim the same channel */ + /* Don't let multiple commacs claim the same channel(s) */ if ((mal->tx_chan_mask & commac->tx_chan_mask) || (mal->rx_chan_mask & commac->rx_chan_mask)) { - write_unlock_irqrestore(&mal_list_lock, flags); + local_irq_restore(flags); + printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", + mal->def->index); return -EBUSY; } mal->tx_chan_mask |= commac->tx_chan_mask; mal->rx_chan_mask |= commac->rx_chan_mask; + list_add(&commac->list, &mal->list); - list_add(&commac->list, &mal->commac); - - write_unlock_irqrestore(&mal_list_lock, flags); - + local_irq_restore(flags); return 0; } -int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +void __exit mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) { unsigned long flags; + local_irq_save(flags); - write_lock_irqsave(&mal_list_lock, flags); + MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index, + commac->tx_chan_mask, commac->rx_chan_mask); mal->tx_chan_mask &= ~commac->tx_chan_mask; mal->rx_chan_mask &= ~commac->rx_chan_mask; - list_del_init(&commac->list); - write_unlock_irqrestore(&mal_list_lock, flags); - - return 0; + local_irq_restore(flags); } int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) { - switch (channel) { - case 0: - set_mal_dcrn(mal, DCRN_MALRCBS0, size); - break; -#ifdef DCRN_MALRCBS1 - case 1: - set_mal_dcrn(mal, DCRN_MALRCBS1, size); - break; -#endif -#ifdef DCRN_MALRCBS2 - case 2: - set_mal_dcrn(mal, DCRN_MALRCBS2, size); - break; -#endif -#ifdef DCRN_MALRCBS3 - case 3: - set_mal_dcrn(mal, DCRN_MALRCBS3, size); - break; -#endif - default: + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_rx_chans || + size > MAL_MAX_RX_SIZE); + + MAL_DBG("%d: set_rbcs(%d, %lu)" NL, mal->def->index, channel, size); + + if (size & 0xf) { + printk(KERN_WARNING + "mal%d: incorrect RX size %lu for the channel %d\n", + mal->def->index, size, channel); return -EINVAL; } + set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); return 0; } +int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel) +{ + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_tx_chans); + return channel * NUM_TX_BUFF; +} + +int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel) +{ + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_rx_chans); + return maldata->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; +} + +void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel) +{ + local_bh_disable(); + MAL_DBG("%d: enable_tx(%d)" NL, mal->def->index, channel); + set_mal_dcrn(mal, MAL_TXCASR, + get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); + local_bh_enable(); +} + +void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel) +{ + set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); + MAL_DBG("%d: disable_tx(%d)" NL, mal->def->index, channel); +} + +void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel) +{ + local_bh_disable(); + MAL_DBG("%d: enable_rx(%d)" NL, mal->def->index, channel); + set_mal_dcrn(mal, MAL_RXCASR, + get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); + local_bh_enable(); +} + +void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel) +{ + set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); + MAL_DBG("%d: disable_rx(%d)" NL, mal->def->index, channel); +} + +void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + local_bh_disable(); + MAL_DBG("%d: poll_add(%p)" NL, mal->def->index, commac); + list_add_tail(&commac->poll_list, &mal->poll_list); + local_bh_enable(); +} + +void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + local_bh_disable(); + MAL_DBG("%d: poll_del(%p)" NL, mal->def->index, commac); + list_del(&commac->poll_list); + local_bh_enable(); +} + +/* synchronized by mal_poll() */ +static inline void mal_enable_eob_irq(struct ibm_ocp_mal *mal) +{ + MAL_DBG2("%d: enable_irq" NL, mal->def->index); + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); +} + +/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ +static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal) +{ + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); + MAL_DBG2("%d: disable_irq" NL, mal->def->index); +} + static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - unsigned long mal_error; - - /* - * This SERR applies to one of the devices on the MAL, here we charge - * it against the first EMAC registered for the MAL. - */ - - mal_error = get_mal_dcrn(mal, DCRN_MALESR); - - printk(KERN_ERR "%s: System Error (MALESR=%lx)\n", - "MAL" /* FIXME: get the name right */ , mal_error); - - /* FIXME: decipher error */ - /* DIXME: distribute to commacs, if possible */ + u32 esr = get_mal_dcrn(mal, MAL_ESR); /* Clear the error status register */ - set_mal_dcrn(mal, DCRN_MALESR, mal_error); + set_mal_dcrn(mal, MAL_ESR, esr); + MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr); + + if (esr & MAL_ESR_EVB) { + if (esr & MAL_ESR_DE) { + /* We ignore Descriptor error, + * TXDE or RXDE interrupt will be generated anyway. + */ + return IRQ_HANDLED; + } + + if (esr & MAL_ESR_PEIN) { + /* PLB error, it's probably buggy hardware or + * incorrect physical address in BD (i.e. bug) + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, PLB (ESR = 0x%08x)\n", + mal->def->index, esr); + return IRQ_HANDLED; + } + + /* OPB error, it's probably buggy hardware or incorrect EBC setup */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, OPB (ESR = 0x%08x)\n", + mal->def->index, esr); + } return IRQ_HANDLED; } +static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) +{ + if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + MAL_DBG2("%d: schedule_poll" NL, mal->def->index); + mal_disable_eob_irq(mal); + __netif_rx_schedule(&mal->poll_dev); + } else + MAL_DBG2("%d: already in poll" NL, mal->def->index); +} + static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; - - isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR); - set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (isr & mc->tx_chan_mask) { - mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask); - } - } - read_unlock(&mal_list_lock); - + u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); + MAL_DBG2("%d: txeob %08x" NL, mal->def->index, r); + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_TXEOBISR, r); return IRQ_HANDLED; } static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; - - isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR); - set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (isr & mc->rx_chan_mask) { - mc->ops->rxeob(mc->dev, isr & mc->rx_chan_mask); - } - } - read_unlock(&mal_list_lock); - + u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); + MAL_DBG2("%d: rxeob %08x" NL, mal->def->index, r); + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXEOBISR, r); return IRQ_HANDLED; } static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long deir; + u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); + set_mal_dcrn(mal, MAL_TXDEIR, deir); - deir = get_mal_dcrn(mal, DCRN_MALTXDEIR); + MAL_DBG("%d: txde %08x" NL, mal->def->index, deir); - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Tx descriptor error (MALTXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (deir & mc->tx_chan_mask) { - mc->ops->txde(mc->dev, deir & mc->tx_chan_mask); - } - } - read_unlock(&mal_list_lock); + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", + mal->def->index, deir); return IRQ_HANDLED; } -/* - * This interrupt should be very rare at best. This occurs when - * the hardware has a problem with the receive descriptors. The manual - * states that it occurs when the hardware cannot the receive descriptor - * empty bit is not set. The recovery mechanism will be to - * traverse through the descriptors, handle any that are marked to be - * handled and reinitialize each along the way. At that point the driver - * will be restarted. - */ static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; struct list_head *l; - unsigned long deir; + u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); - deir = get_mal_dcrn(mal, DCRN_MALRXDEIR); + MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir); - /* - * This really is needed. This case encountered in stress testing. - */ - if (deir == 0) - return IRQ_HANDLED; - - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { + list_for_each(l, &mal->list) { struct mal_commac *mc = list_entry(l, struct mal_commac, list); - if (deir & mc->rx_chan_mask) { - mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask); + mc->rx_stopped = 1; + mc->ops->rxde(mc->dev); } } - read_unlock(&mal_list_lock); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXDEIR, deir); return IRQ_HANDLED; } +static int mal_poll(struct net_device *ndev, int *budget) +{ + struct ibm_ocp_mal *mal = ndev->priv; + struct list_head *l; + int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + + MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, + rx_work_limit); + again: + /* Process TX skbs */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + mc->ops->poll_tx(mc->dev); + } + + /* Process RX skbs. + * We _might_ need something more smart here to enforce polling fairness. + */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + int n = mc->ops->poll_rx(mc->dev, rx_work_limit); + if (n) { + received += n; + rx_work_limit -= n; + if (rx_work_limit <= 0) { + done = 0; + goto more_work; // XXX What if this is the last one ? + } + } + } + + /* We need to disable IRQs to protect from RXDE IRQ here */ + local_irq_disable(); + __netif_rx_complete(ndev); + mal_enable_eob_irq(mal); + local_irq_enable(); + + done = 1; + + /* Check for "rotting" packet(s) */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { + MAL_DBG2("%d: rotting packet" NL, mal->def->index); + if (netif_rx_reschedule(ndev, received)) + mal_disable_eob_irq(mal); + else + MAL_DBG2("%d: already in poll list" NL, + mal->def->index); + + if (rx_work_limit > 0) + goto again; + else + goto more_work; + } + mc->ops->poll_tx(mc->dev); + } + + more_work: + ndev->quota -= received; + *budget -= received; + + MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget, + done ? 0 : 1); + return done ? 0 : 1; +} + +static void mal_reset(struct ibm_ocp_mal *mal) +{ + int n = 10; + MAL_DBG("%d: reset" NL, mal->def->index); + + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); + + /* Wait for reset to complete (1 system clock) */ + while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index); +} + +int mal_get_regs_len(struct ibm_ocp_mal *mal) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct ibm_mal_regs); +} + +void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + struct ibm_mal_regs *regs = (struct ibm_mal_regs *)(hdr + 1); + struct ocp_func_mal_data *maldata = mal->def->additions; + int i; + + hdr->version = MAL_VERSION; + hdr->index = mal->def->index; + + regs->tx_count = maldata->num_tx_chans; + regs->rx_count = maldata->num_rx_chans; + + regs->cfg = get_mal_dcrn(mal, MAL_CFG); + regs->esr = get_mal_dcrn(mal, MAL_ESR); + regs->ier = get_mal_dcrn(mal, MAL_IER); + regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); + regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); + regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); + regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); + regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); + regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); + regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); + regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); + + for (i = 0; i < regs->tx_count; ++i) + regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); + + for (i = 0; i < regs->rx_count; ++i) { + regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); + regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); + } + return regs + 1; +} + static int __init mal_probe(struct ocp_device *ocpdev) { - struct ibm_ocp_mal *mal = NULL; + struct ibm_ocp_mal *mal; struct ocp_func_mal_data *maldata; - int err = 0; + int err = 0, i, bd_size; - maldata = (struct ocp_func_mal_data *)ocpdev->def->additions; + MAL_DBG("%d: probe" NL, ocpdev->def->index); + + maldata = ocpdev->def->additions; if (maldata == NULL) { - printk(KERN_ERR "mal%d: Missing additional datas !\n", + printk(KERN_ERR "mal%d: missing additional data!\n", ocpdev->def->index); return -ENODEV; } - mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); - if (mal == NULL) { + mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); + if (!mal) { printk(KERN_ERR - "mal%d: Out of memory allocating MAL structure !\n", + "mal%d: out of memory allocating MAL structure!\n", ocpdev->def->index); return -ENOMEM; } - memset(mal, 0, sizeof(*mal)); + mal->dcrbase = maldata->dcr_base; + mal->def = ocpdev->def; - switch (ocpdev->def->index) { - case 0: - mal->dcrbase = DCRN_MAL_BASE; - break; -#ifdef DCRN_MAL1_BASE - case 1: - mal->dcrbase = DCRN_MAL1_BASE; - break; -#endif - default: - BUG(); - } + INIT_LIST_HEAD(&mal->poll_list); + set_bit(__LINK_STATE_START, &mal->poll_dev.state); + mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; + mal->poll_dev.poll = mal_poll; + mal->poll_dev.priv = mal; + atomic_set(&mal->poll_dev.refcnt, 1); - /**************************/ + INIT_LIST_HEAD(&mal->list); - INIT_LIST_HEAD(&mal->commac); - - set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF); - set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF); - - set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */ - /* FIXME: Add delay */ + /* Load power-on reset defaults */ + mal_reset(mal); /* Set the MAL configuration register */ - set_mal_dcrn(mal, DCRN_MALCR, - MALCR_PLBB | MALCR_OPBBL | MALCR_LEA | - MALCR_PLBLT_DEFAULT); + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB | + MAL_CFG_OPBBL | MAL_CFG_LEA); - /* It would be nice to allocate buffers separately for each - * channel, but we can't because the channels share the upper - * 13 bits of address lines. Each channels buffer must also - * be 4k aligned, so we allocate 4k for each channel. This is - * inefficient FIXME: do better, if possible */ - mal->tx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_tx_chans, - &mal->tx_phys_addr, GFP_KERNEL); - if (mal->tx_virt_addr == NULL) { + mal_enable_eob_irq(mal); + + /* Allocate space for BD rings */ + BUG_ON(maldata->num_tx_chans <= 0 || maldata->num_tx_chans > 32); + BUG_ON(maldata->num_rx_chans <= 0 || maldata->num_rx_chans > 32); + bd_size = sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * maldata->num_tx_chans + + NUM_RX_BUFF * maldata->num_rx_chans); + mal->bd_virt = + dma_alloc_coherent(&ocpdev->dev, bd_size, &mal->bd_dma, GFP_KERNEL); + + if (!mal->bd_virt) { printk(KERN_ERR - "mal%d: Out of memory allocating MAL descriptors !\n", - ocpdev->def->index); + "mal%d: out of memory allocating RX/TX descriptors!\n", + mal->def->index); err = -ENOMEM; goto fail; } + memset(mal->bd_virt, 0, bd_size); - /* God, oh, god, I hate DCRs */ - set_mal_dcrn(mal, DCRN_MALTXCTP0R, mal->tx_phys_addr); -#ifdef DCRN_MALTXCTP1R - if (maldata->num_tx_chans > 1) - set_mal_dcrn(mal, DCRN_MALTXCTP1R, - mal->tx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP1R */ -#ifdef DCRN_MALTXCTP2R - if (maldata->num_tx_chans > 2) - set_mal_dcrn(mal, DCRN_MALTXCTP2R, - mal->tx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP2R */ -#ifdef DCRN_MALTXCTP3R - if (maldata->num_tx_chans > 3) - set_mal_dcrn(mal, DCRN_MALTXCTP3R, - mal->tx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP3R */ -#ifdef DCRN_MALTXCTP4R - if (maldata->num_tx_chans > 4) - set_mal_dcrn(mal, DCRN_MALTXCTP4R, - mal->tx_phys_addr + 4 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP4R */ -#ifdef DCRN_MALTXCTP5R - if (maldata->num_tx_chans > 5) - set_mal_dcrn(mal, DCRN_MALTXCTP5R, - mal->tx_phys_addr + 5 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP5R */ -#ifdef DCRN_MALTXCTP6R - if (maldata->num_tx_chans > 6) - set_mal_dcrn(mal, DCRN_MALTXCTP6R, - mal->tx_phys_addr + 6 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP6R */ -#ifdef DCRN_MALTXCTP7R - if (maldata->num_tx_chans > 7) - set_mal_dcrn(mal, DCRN_MALTXCTP7R, - mal->tx_phys_addr + 7 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP7R */ + for (i = 0; i < maldata->num_tx_chans; ++i) + set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_tx_bd_offset(mal, i)); - mal->rx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_rx_chans, - &mal->rx_phys_addr, GFP_KERNEL); - - set_mal_dcrn(mal, DCRN_MALRXCTP0R, mal->rx_phys_addr); -#ifdef DCRN_MALRXCTP1R - if (maldata->num_rx_chans > 1) - set_mal_dcrn(mal, DCRN_MALRXCTP1R, - mal->rx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP1R */ -#ifdef DCRN_MALRXCTP2R - if (maldata->num_rx_chans > 2) - set_mal_dcrn(mal, DCRN_MALRXCTP2R, - mal->rx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP2R */ -#ifdef DCRN_MALRXCTP3R - if (maldata->num_rx_chans > 3) - set_mal_dcrn(mal, DCRN_MALRXCTP3R, - mal->rx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP3R */ + for (i = 0; i < maldata->num_rx_chans; ++i) + set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_rx_bd_offset(mal, i)); err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal); if (err) - goto fail; - err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal); + goto fail2; + err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal); if (err) - goto fail; + goto fail3; err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) - goto fail; + goto fail4; err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); if (err) - goto fail; + goto fail5; err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); if (err) - goto fail; + goto fail6; - set_mal_dcrn(mal, DCRN_MALIER, - MALIER_DE | MALIER_NE | MALIER_TE | - MALIER_OPBE | MALIER_PLBE); + /* Enable all MAL SERR interrupt sources */ + set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS); - /* Advertise me to the rest of the world */ + /* Advertise this instance to the rest of the world */ ocp_set_drvdata(ocpdev, mal); - printk(KERN_INFO "mal%d: Initialized, %d tx channels, %d rx channels\n", - ocpdev->def->index, maldata->num_tx_chans, - maldata->num_rx_chans); + mal_dbg_register(mal->def->index, mal); + printk(KERN_INFO "mal%d: initialized, %d TX channels, %d RX channels\n", + mal->def->index, maldata->num_tx_chans, maldata->num_rx_chans); return 0; + fail6: + free_irq(maldata->rxde_irq, mal); + fail5: + free_irq(maldata->txeob_irq, mal); + fail4: + free_irq(maldata->txde_irq, mal); + fail3: + free_irq(maldata->serr_irq, mal); + fail2: + dma_free_coherent(&ocpdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail: - /* FIXME: dispose requested IRQs ! */ - if (err && mal) - kfree(mal); + kfree(mal); return err; } static void __exit mal_remove(struct ocp_device *ocpdev) { struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev); - struct ocp_func_mal_data *maldata = ocpdev->def->additions; + struct ocp_func_mal_data *maldata = mal->def->additions; - BUG_ON(!maldata); + MAL_DBG("%d: remove" NL, mal->def->index); + + /* Syncronize with scheduled polling, + stolen from net/core/dev.c:dev_close() + */ + clear_bit(__LINK_STATE_START, &mal->poll_dev.state); + netif_poll_disable(&mal->poll_dev); + + if (!list_empty(&mal->list)) { + /* This is *very* bad */ + printk(KERN_EMERG + "mal%d: commac list is not empty on remove!\n", + mal->def->index); + } ocp_set_drvdata(ocpdev, NULL); - /* FIXME: shut down the MAL, deal with dependency with emac */ free_irq(maldata->serr_irq, mal); free_irq(maldata->txde_irq, mal); free_irq(maldata->txeob_irq, mal); free_irq(maldata->rxde_irq, mal); free_irq(maldata->rxeob_irq, mal); - if (mal->tx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_tx_chans, - mal->tx_virt_addr, mal->tx_phys_addr); + mal_reset(mal); - if (mal->rx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_rx_chans, - mal->rx_virt_addr, mal->rx_phys_addr); + mal_dbg_register(mal->def->index, NULL); + + dma_free_coherent(&ocpdev->dev, + sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * maldata->num_tx_chans + + NUM_RX_BUFF * maldata->num_rx_chans), mal->bd_virt, + mal->bd_dma); kfree(mal); } /* Structure for a device driver */ static struct ocp_device_id mal_ids[] = { - {.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL}, - {.vendor = OCP_VENDOR_INVALID} + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_MAL }, + { .vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver mal_driver = { @@ -441,23 +570,14 @@ static struct ocp_driver mal_driver = { .remove = mal_remove, }; -static int __init init_mals(void) +int __init mal_init(void) { - int rc; - - rc = ocp_register_driver(&mal_driver); - if (rc < 0) { - ocp_unregister_driver(&mal_driver); - return -ENODEV; - } - - return 0; + MAL_DBG(": init" NL); + return ocp_register_driver(&mal_driver); } -static void __exit exit_mals(void) +void __exit mal_exit(void) { + MAL_DBG(": exit" NL); ocp_unregister_driver(&mal_driver); } - -module_init(init_mals); -module_exit(exit_mals); diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index dd9f0dabc6e0..15b0bdae26ac 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -1,131 +1,267 @@ -#ifndef _IBM_EMAC_MAL_H -#define _IBM_EMAC_MAL_H +/* + * drivers/net/ibm_emac/ibm_emac_mal.h + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2002 MontaVista Softare 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 __IBM_EMAC_MAL_H_ +#define __IBM_EMAC_MAL_H_ +#include +#include #include +#include -#define MAL_DT_ALIGN (4096) /* Alignment for each channel's descriptor table */ +#include -#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan)) +/* + * These MAL "versions" probably aren't the real versions IBM uses for these + * MAL cores, I assigned them just to make #ifdefs in this file nicer and + * reflect the fact that 40x and 44x have slightly different MALs. --ebs + */ +#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \ + defined(CONFIG_440EP) || defined(CONFIG_NP405H) +#define MAL_VERSION 1 +#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) +#define MAL_VERSION 2 +#else +#error "Unknown SoC, please check chip manual and choose MAL 'version'" +#endif + +/* MALx DCR registers */ +#define MAL_CFG 0x00 +#define MAL_CFG_SR 0x80000000 +#define MAL_CFG_PLBB 0x00004000 +#define MAL_CFG_OPBBL 0x00000080 +#define MAL_CFG_EOPIE 0x00000004 +#define MAL_CFG_LEA 0x00000002 +#define MAL_CFG_SD 0x00000001 +#if MAL_VERSION == 1 +#define MAL_CFG_PLBP_MASK 0x00c00000 +#define MAL_CFG_PLBP_10 0x00800000 +#define MAL_CFG_GA 0x00200000 +#define MAL_CFG_OA 0x00100000 +#define MAL_CFG_PLBLE 0x00080000 +#define MAL_CFG_PLBT_MASK 0x00078000 +#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK) +#elif MAL_VERSION == 2 +#define MAL_CFG_RPP_MASK 0x00c00000 +#define MAL_CFG_RPP_10 0x00800000 +#define MAL_CFG_RMBS_MASK 0x00300000 +#define MAL_CFG_WPP_MASK 0x000c0000 +#define MAL_CFG_WPP_10 0x00080000 +#define MAL_CFG_WMBS_MASK 0x00030000 +#define MAL_CFG_PLBLE 0x00008000 +#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \ + MAL_CFG_RPP_10 | MAL_CFG_WPP_10) +#else +#error "Unknown MAL version" +#endif + +#define MAL_ESR 0x01 +#define MAL_ESR_EVB 0x80000000 +#define MAL_ESR_CIDT 0x40000000 +#define MAL_ESR_CID_MASK 0x3e000000 +#define MAL_ESR_CID_SHIFT 25 +#define MAL_ESR_DE 0x00100000 +#define MAL_ESR_OTE 0x00040000 +#define MAL_ESR_OSE 0x00020000 +#define MAL_ESR_PEIN 0x00010000 +#define MAL_ESR_DEI 0x00000010 +#define MAL_ESR_OTEI 0x00000004 +#define MAL_ESR_OSEI 0x00000002 +#define MAL_ESR_PBEI 0x00000001 +#if MAL_VERSION == 1 +#define MAL_ESR_ONE 0x00080000 +#define MAL_ESR_ONEI 0x00000008 +#elif MAL_VERSION == 2 +#define MAL_ESR_PTE 0x00800000 +#define MAL_ESR_PRE 0x00400000 +#define MAL_ESR_PWE 0x00200000 +#define MAL_ESR_PTEI 0x00000080 +#define MAL_ESR_PREI 0x00000040 +#define MAL_ESR_PWEI 0x00000020 +#else +#error "Unknown MAL version" +#endif + +#define MAL_IER 0x02 +#define MAL_IER_DE 0x00000010 +#define MAL_IER_OTE 0x00000004 +#define MAL_IER_OE 0x00000002 +#define MAL_IER_PE 0x00000001 +#if MAL_VERSION == 1 +#define MAL_IER_NWE 0x00000008 +#define MAL_IER_SOC_EVENTS MAL_IER_NWE +#elif MAL_VERSION == 2 +#define MAL_IER_PT 0x00000080 +#define MAL_IER_PRE 0x00000040 +#define MAL_IER_PWE 0x00000020 +#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE) +#else +#error "Unknown MAL version" +#endif +#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + +#define MAL_TXCASR 0x04 +#define MAL_TXCARR 0x05 +#define MAL_TXEOBISR 0x06 +#define MAL_TXDEIR 0x07 +#define MAL_RXCASR 0x10 +#define MAL_RXCARR 0x11 +#define MAL_RXEOBISR 0x12 +#define MAL_RXDEIR 0x13 +#define MAL_TXCTPR(n) ((n) + 0x20) +#define MAL_RXCTPR(n) ((n) + 0x40) +#define MAL_RCBS(n) ((n) + 0x60) + +/* In reality MAL can handle TX buffers up to 4095 bytes long, + * but this isn't a good round number :) --ebs + */ +#define MAL_MAX_TX_SIZE 4080 +#define MAL_MAX_RX_SIZE 4080 + +static inline int mal_rx_size(int len) +{ + len = (len + 0xf) & ~0xf; + return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; +} + +static inline int mal_tx_chunks(int len) +{ + return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; +} + +#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) /* MAL Buffer Descriptor structure */ struct mal_descriptor { - unsigned short ctrl; /* MAL / Commac status control bits */ - short data_len; /* Max length is 4K-1 (12 bits) */ - unsigned char *data_ptr; /* pointer to actual data buffer */ -} __attribute__ ((packed)); + u16 ctrl; /* MAL / Commac status control bits */ + u16 data_len; /* Max length is 4K-1 (12 bits) */ + u32 data_ptr; /* pointer to actual data buffer */ +}; /* the following defines are for the MadMAL status and control registers. */ /* MADMAL transmit and receive status/control bits */ -#define MAL_RX_CTRL_EMPTY 0x8000 -#define MAL_RX_CTRL_WRAP 0x4000 -#define MAL_RX_CTRL_CM 0x2000 -#define MAL_RX_CTRL_LAST 0x1000 -#define MAL_RX_CTRL_FIRST 0x0800 -#define MAL_RX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) +#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) -#define MAL_TX_CTRL_READY 0x8000 -#define MAL_TX_CTRL_WRAP 0x4000 -#define MAL_TX_CTRL_CM 0x2000 -#define MAL_TX_CTRL_LAST 0x1000 -#define MAL_TX_CTRL_INTR 0x0400 +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 struct mal_commac_ops { - void (*txeob) (void *dev, u32 chanmask); - void (*txde) (void *dev, u32 chanmask); - void (*rxeob) (void *dev, u32 chanmask); - void (*rxde) (void *dev, u32 chanmask); + void (*poll_tx) (void *dev); + int (*poll_rx) (void *dev, int budget); + int (*peek_rx) (void *dev); + void (*rxde) (void *dev); }; struct mal_commac { - struct mal_commac_ops *ops; - void *dev; - u32 tx_chan_mask, rx_chan_mask; - struct list_head list; + struct mal_commac_ops *ops; + void *dev; + struct list_head poll_list; + int rx_stopped; + + u32 tx_chan_mask; + u32 rx_chan_mask; + struct list_head list; }; struct ibm_ocp_mal { - int dcrbase; + int dcrbase; - struct list_head commac; - u32 tx_chan_mask, rx_chan_mask; + struct list_head poll_list; + struct net_device poll_dev; - dma_addr_t tx_phys_addr; - struct mal_descriptor *tx_virt_addr; + struct list_head list; + u32 tx_chan_mask; + u32 rx_chan_mask; - dma_addr_t rx_phys_addr; - struct mal_descriptor *rx_virt_addr; + dma_addr_t bd_dma; + struct mal_descriptor *bd_virt; + + struct ocp_def *def; }; -#define GET_MAL_STANZA(base,dcrn) \ - case base: \ - x = mfdcr(dcrn(base)); \ - break; - -#define SET_MAL_STANZA(base,dcrn, val) \ - case base: \ - mtdcr(dcrn(base), (val)); \ - break; - -#define GET_MAL0_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL_BASE,dcrn) -#define SET_MAL0_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL_BASE,dcrn,val) - -#ifdef DCRN_MAL1_BASE -#define GET_MAL1_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL1_BASE,dcrn) -#define SET_MAL1_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL1_BASE,dcrn,val) -#else /* ! DCRN_MAL1_BASE */ -#define GET_MAL1_STANZA(dcrn) -#define SET_MAL1_STANZA(dcrn,val) -#endif - -#define get_mal_dcrn(mal, dcrn) ({ \ - u32 x; \ - switch ((mal)->dcrbase) { \ - GET_MAL0_STANZA(dcrn) \ - GET_MAL1_STANZA(dcrn) \ - default: \ - x = 0; \ - BUG(); \ - } \ -x; }) - -#define set_mal_dcrn(mal, dcrn, val) do { \ - switch ((mal)->dcrbase) { \ - SET_MAL0_STANZA(dcrn,val) \ - SET_MAL1_STANZA(dcrn,val) \ - default: \ - BUG(); \ - } } while (0) - -static inline void mal_enable_tx_channels(struct ibm_ocp_mal *mal, u32 chanmask) +static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) { - set_mal_dcrn(mal, DCRN_MALTXCASR, - get_mal_dcrn(mal, DCRN_MALTXCASR) | chanmask); + return mfdcr(mal->dcrbase + reg); } -static inline void mal_disable_tx_channels(struct ibm_ocp_mal *mal, - u32 chanmask) +static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) { - set_mal_dcrn(mal, DCRN_MALTXCARR, chanmask); + mtdcr(mal->dcrbase + reg, val); } -static inline void mal_enable_rx_channels(struct ibm_ocp_mal *mal, u32 chanmask) -{ - set_mal_dcrn(mal, DCRN_MALRXCASR, - get_mal_dcrn(mal, DCRN_MALRXCASR) | chanmask); -} +/* Register MAL devices */ +int mal_init(void) __init; +void mal_exit(void) __exit; -static inline void mal_disable_rx_channels(struct ibm_ocp_mal *mal, - u32 chanmask) -{ - set_mal_dcrn(mal, DCRN_MALRXCARR, chanmask); -} +int mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) __init; +void mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) __exit; +int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size); -extern int mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac); -extern int mal_unregister_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac); +/* Returns BD ring offset for a particular channel + (in 'struct mal_descriptor' elements) +*/ +int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel); +int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel); -extern int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, - unsigned long size); +void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel); -#endif /* _IBM_EMAC_MAL_H */ +/* Add/remove EMAC to/from MAL polling list */ +void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac); +void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac); + +/* Ethtool MAL registers */ +struct ibm_mal_regs { + u32 tx_count; + u32 rx_count; + + u32 cfg; + u32 esr; + u32 ier; + u32 tx_casr; + u32 tx_carr; + u32 tx_eobisr; + u32 tx_deir; + u32 rx_casr; + u32 rx_carr; + u32 rx_eobisr; + u32 rx_deir; + u32 tx_ctpr[32]; + u32 rx_ctpr[32]; + u32 rcbs[32]; +}; + +int mal_get_regs_len(struct ibm_ocp_mal *mal); +void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf); + +#endif /* __IBM_EMAC_MAL_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c index 14213f090e91..a27e49cfe43b 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.c +++ b/drivers/net/ibm_emac/ibm_emac_phy.c @@ -1,61 +1,256 @@ /* - * ibm_ocp_phy.c + * drivers/net/ibm_emac/ibm_emac_phy.c * - * PHY drivers for the ibm ocp ethernet driver. Borrowed - * from sungem_phy.c, though I only kept the generic MII + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. + * Borrowed from sungem_phy.c, though I only kept the generic MII * driver for now. * * This file should be shared with other drivers or eventually * merged as the "low level" part of miilib * * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (c) 2004-2005, Eugene Surovegin * */ - #include - #include - #include -#include #include #include -#include #include #include #include +#include + #include "ibm_emac_phy.h" -static int reset_one_mii_phy(struct mii_phy *phy, int phy_id) +static inline int phy_read(struct mii_phy *phy, int reg) { - u16 val; + return phy->mdio_read(phy->dev, phy->address, reg); +} + +static inline void phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->address, reg, val); +} + +int mii_reset_phy(struct mii_phy *phy) +{ + int val; int limit = 10000; - val = __phy_read(phy, phy_id, MII_BMCR); + val = phy_read(phy, MII_BMCR); val &= ~BMCR_ISOLATE; val |= BMCR_RESET; - __phy_write(phy, phy_id, MII_BMCR, val); + phy_write(phy, MII_BMCR, val); - udelay(100); + udelay(300); while (limit--) { - val = __phy_read(phy, phy_id, MII_BMCR); - if ((val & BMCR_RESET) == 0) + val = phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) break; udelay(10); } if ((val & BMCR_ISOLATE) && limit > 0) - __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); + phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); - return (limit <= 0); + return limit <= 0; } +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + int ctl, adv; + + phy->autoneg = AUTONEG_ENABLE; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + phy_write(phy, MII_ADVERTISE, adv); + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + adv = phy_read(phy, MII_CTRL1000); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & ADVERTISED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + if (advertise & ADVERTISED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + phy_write(phy, MII_CTRL1000, adv); + } + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + int ctl; + + phy->autoneg = AUTONEG_DISABLE; + phy->speed = speed; + phy->duplex = fd; + phy->pause = phy->asym_pause = 0; + + ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); + + /* First reset the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch (speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + ctl |= BMCR_SPEED1000; + break; + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + int status; + + /* Clear latched value with dummy read */ + phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if (status < 0 || (status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + if (phy->autoneg == AUTONEG_ENABLE) { + int glpa = 0; + int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); + if (lpa < 0) + return lpa; + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + int adv = phy_read(phy, MII_CTRL1000); + glpa = phy_read(phy, MII_STAT1000); + + if (glpa < 0 || adv < 0) + return adv; + + glpa &= adv << 2; + } + + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + if (glpa & (LPA_1000FULL | LPA_1000HALF)) { + phy->speed = SPEED_1000; + if (glpa & LPA_1000FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phy->speed = SPEED_100; + if (lpa & LPA_100FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & LPA_10FULL) + phy->duplex = DUPLEX_FULL; + + if (phy->duplex == DUPLEX_FULL) { + phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phy, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + phy->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + + phy->pause = phy->asym_pause = 0; + } + return 0; +} + +/* Generic implementation for most 10/100/1000 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def genmii_phy_def = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .ops = &generic_phy_ops +}; + +/* CIS8201 */ +#define MII_CIS8201_EPCR 0x17 +#define EPCR_MODE_MASK 0x3000 +#define EPCR_GMII_MODE 0x0000 +#define EPCR_RGMII_MODE 0x1000 +#define EPCR_TBI_MODE 0x2000 +#define EPCR_RTBI_MODE 0x3000 + static int cis8201_init(struct mii_phy *phy) { - u16 epcr; + int epcr; epcr = phy_read(phy, MII_CIS8201_EPCR); + if (epcr < 0) + return epcr; + epcr &= ~EPCR_MODE_MASK; switch (phy->mode) { @@ -78,178 +273,19 @@ static int cis8201_init(struct mii_phy *phy) return 0; } -static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) -{ - u16 ctl, adv; - - phy->autoneg = 1; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = 0; - phy->advertising = advertise; - - /* Setup standard advertise */ - adv = phy_read(phy, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - phy_write(phy, MII_ADVERTISE, adv); - - /* Start/Restart aneg */ - ctl = phy_read(phy, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) -{ - u16 ctl; - - phy->autoneg = 0; - phy->speed = speed; - phy->duplex = fd; - phy->pause = 0; - - ctl = phy_read(phy, MII_BMCR); - ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); - - /* First reset the PHY */ - phy_write(phy, MII_BMCR, ctl | BMCR_RESET); - - /* Select speed & duplex */ - switch (speed) { - case SPEED_10: - break; - case SPEED_100: - ctl |= BMCR_SPEED100; - break; - case SPEED_1000: - default: - return -EINVAL; - } - if (fd == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_poll_link(struct mii_phy *phy) -{ - u16 status; - - (void)phy_read(phy, MII_BMSR); - status = phy_read(phy, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - return 0; - if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return 0; - return 1; -} - -#define MII_CIS8201_ACSR 0x1c -#define ACSR_DUPLEX_STATUS 0x0020 -#define ACSR_SPEED_1000BASET 0x0010 -#define ACSR_SPEED_100BASET 0x0008 - -static int cis8201_read_link(struct mii_phy *phy) -{ - u16 acsr; - - if (phy->autoneg) { - acsr = phy_read(phy, MII_CIS8201_ACSR); - - if (acsr & ACSR_DUPLEX_STATUS) - phy->duplex = DUPLEX_FULL; - else - phy->duplex = DUPLEX_HALF; - if (acsr & ACSR_SPEED_1000BASET) { - phy->speed = SPEED_1000; - } else if (acsr & ACSR_SPEED_100BASET) - phy->speed = SPEED_100; - else - phy->speed = SPEED_10; - phy->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} - -static int genmii_read_link(struct mii_phy *phy) -{ - u16 lpa; - - if (phy->autoneg) { - lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); - - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = 0; - - if (lpa & (LPA_100FULL | LPA_100HALF)) { - phy->speed = SPEED_100; - if (lpa & LPA_100FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & LPA_10FULL) - phy->duplex = DUPLEX_FULL; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} - -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) - -/* CIS8201 phy ops */ static struct mii_phy_ops cis8201_phy_ops = { - init:cis8201_init, - setup_aneg:genmii_setup_aneg, - setup_forced:genmii_setup_forced, - poll_link:genmii_poll_link, - read_link:cis8201_read_link -}; - -/* Generic implementation for most 10/100 PHYs */ -static struct mii_phy_ops generic_phy_ops = { - setup_aneg:genmii_setup_aneg, - setup_forced:genmii_setup_forced, - poll_link:genmii_poll_link, - read_link:genmii_read_link + .init = cis8201_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link }; static struct mii_phy_def cis8201_phy_def = { - phy_id:0x000fc410, - phy_id_mask:0x000ffff0, - name:"CIS8201 Gigabit Ethernet", - features:MII_GBIT_FEATURES, - magic_aneg:0, - ops:&cis8201_phy_ops -}; - -static struct mii_phy_def genmii_phy_def = { - phy_id:0x00000000, - phy_id_mask:0x00000000, - name:"Generic MII", - features:MII_BASIC_FEATURES, - magic_aneg:0, - ops:&generic_phy_ops + .phy_id = 0x000fc410, + .phy_id_mask = 0x000ffff0, + .name = "CIS8201 Gigabit Ethernet", + .ops = &cis8201_phy_ops }; static struct mii_phy_def *mii_phy_table[] = { @@ -258,39 +294,60 @@ static struct mii_phy_def *mii_phy_table[] = { NULL }; -int mii_phy_probe(struct mii_phy *phy, int mii_id) +int mii_phy_probe(struct mii_phy *phy, int address) { - int rc; - u32 id; struct mii_phy_def *def; int i; + u32 id; - phy->autoneg = 0; + phy->autoneg = AUTONEG_DISABLE; phy->advertising = 0; - phy->mii_id = mii_id; - phy->speed = 0; - phy->duplex = 0; - phy->pause = 0; + phy->address = address; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; - /* Take PHY out of isloate mode and reset it. */ - rc = reset_one_mii_phy(phy, mii_id); - if (rc) + /* Take PHY out of isolate mode and reset it. */ + if (mii_reset_phy(phy)) return -ENODEV; /* Read ID and find matching entry */ - id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) - & 0xfffffff0; + id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); for (i = 0; (def = mii_phy_table[i]) != NULL; i++) if ((id & def->phy_id_mask) == def->phy_id) break; /* Should never be NULL (we have a generic entry), but... */ - if (def == NULL) + if (!def) return -ENODEV; phy->def = def; + /* Determine PHY features if needed */ + phy->features = def->features; + if (!phy->features) { + u16 bmsr = phy_read(phy, MII_BMSR); + if (bmsr & BMSR_ANEGCAPABLE) + phy->features |= SUPPORTED_Autoneg; + if (bmsr & BMSR_10HALF) + phy->features |= SUPPORTED_10baseT_Half; + if (bmsr & BMSR_10FULL) + phy->features |= SUPPORTED_10baseT_Full; + if (bmsr & BMSR_100HALF) + phy->features |= SUPPORTED_100baseT_Half; + if (bmsr & BMSR_100FULL) + phy->features |= SUPPORTED_100baseT_Full; + if (bmsr & BMSR_ESTATEN) { + u16 esr = phy_read(phy, MII_ESTATUS); + if (esr & ESTATUS_1000_TFULL) + phy->features |= SUPPORTED_1000baseT_Full; + if (esr & ESTATUS_1000_THALF) + phy->features |= SUPPORTED_1000baseT_Half; + } + phy->features |= SUPPORTED_MII; + } + /* Setup default advertising */ - phy->advertising = def->features; + phy->advertising = phy->features; return 0; } diff --git a/drivers/net/ibm_emac/ibm_emac_phy.h b/drivers/net/ibm_emac/ibm_emac_phy.h index 61afbea96563..a70e0fea54c4 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.h +++ b/drivers/net/ibm_emac/ibm_emac_phy.h @@ -1,65 +1,25 @@ - /* - * ibm_emac_phy.h + * drivers/net/ibm_emac/ibm_emac_phy.h * + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support * - * Benjamin Herrenschmidt - * February 2003 + * Benjamin Herrenschmidt + * February 2003 + * + * Minor additions by Eugene Surovegin , 2004 * * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * + * 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 file basically duplicates sungem_phy.{c,h} with different PHYs * supported. I'm looking into merging that in a single mii layer more * flexible than mii.c */ -#ifndef _IBM_EMAC_PHY_H_ -#define _IBM_EMAC_PHY_H_ - -/* - * PHY mode settings - * Used for multi-mode capable PHYs - */ -#define PHY_MODE_NA 0 -#define PHY_MODE_MII 1 -#define PHY_MODE_RMII 2 -#define PHY_MODE_SMII 3 -#define PHY_MODE_RGMII 4 -#define PHY_MODE_TBI 5 -#define PHY_MODE_GMII 6 -#define PHY_MODE_RTBI 7 -#define PHY_MODE_SGMII 8 - -/* - * PHY specific registers/values - */ - -/* CIS8201 */ -#define MII_CIS8201_EPCR 0x17 -#define EPCR_MODE_MASK 0x3000 -#define EPCR_GMII_MODE 0x0000 -#define EPCR_RGMII_MODE 0x1000 -#define EPCR_TBI_MODE 0x2000 -#define EPCR_RTBI_MODE 0x3000 +#ifndef _IBM_OCP_PHY_H_ +#define _IBM_OCP_PHY_H_ struct mii_phy; @@ -77,7 +37,8 @@ struct mii_phy_ops { struct mii_phy_def { u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ u32 phy_id_mask; /* Significant bits */ - u32 features; /* Ethtool SUPPORTED_* defines */ + u32 features; /* Ethtool SUPPORTED_* defines or + 0 for autodetect */ int magic_aneg; /* Autoneg does all speed test for us */ const char *name; const struct mii_phy_ops *ops; @@ -86,8 +47,11 @@ struct mii_phy_def { /* An instance of a PHY, partially borrowed from mii_if_info */ struct mii_phy { struct mii_phy_def *def; - int advertising; - int mii_id; + u32 advertising; /* Ethtool ADVERTISED_* defines */ + u32 features; /* Copied from mii_phy_def.features + or determined automaticaly */ + int address; /* PHY address */ + int mode; /* PHY mode */ /* 1: autoneg enabled, 0: disabled */ int autoneg; @@ -98,40 +62,19 @@ struct mii_phy { int speed; int duplex; int pause; - - /* PHY mode - if needed */ - int mode; + int asym_pause; /* Provided by host chip */ struct net_device *dev; - int (*mdio_read) (struct net_device * dev, int mii_id, int reg); - void (*mdio_write) (struct net_device * dev, int mii_id, int reg, + int (*mdio_read) (struct net_device * dev, int addr, int reg); + void (*mdio_write) (struct net_device * dev, int addr, int reg, int val); }; /* Pass in a struct mii_phy with dev, mdio_read and mdio_write * filled, the remaining fields will be filled on return */ -extern int mii_phy_probe(struct mii_phy *phy, int mii_id); +int mii_phy_probe(struct mii_phy *phy, int address); +int mii_reset_phy(struct mii_phy *phy); -static inline int __phy_read(struct mii_phy *phy, int id, int reg) -{ - return phy->mdio_read(phy->dev, id, reg); -} - -static inline void __phy_write(struct mii_phy *phy, int id, int reg, int val) -{ - phy->mdio_write(phy->dev, id, reg, val); -} - -static inline int phy_read(struct mii_phy *phy, int reg) -{ - return phy->mdio_read(phy->dev, phy->mii_id, reg); -} - -static inline void phy_write(struct mii_phy *phy, int reg, int val) -{ - phy->mdio_write(phy->dev, phy->mii_id, reg, val); -} - -#endif /* _IBM_EMAC_PHY_H_ */ +#endif /* _IBM_OCP_PHY_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.c b/drivers/net/ibm_emac/ibm_emac_rgmii.c new file mode 100644 index 000000000000..f0b1ffb2dbbf --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.c @@ -0,0 +1,201 @@ +/* + * drivers/net/ibm_emac/ibm_emac_rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * Copyright 2004 MontaVista Software, 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 "ibm_emac_core.h" +#include "ibm_emac_debug.h" + +/* RGMIIx_FER */ +#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) +#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) +#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) +#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) +#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) + +/* RGMIIx_SSR */ +#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) +#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) +#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) + +/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ +static inline int rgmii_valid_mode(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline const char *rgmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_RGMII: + return "RGMII"; + case PHY_MODE_TBI: + return "TBI"; + case PHY_MODE_GMII: + return "GMII"; + case PHY_MODE_RTBI: + return "RTBI"; + default: + BUG(); + } +} + +static inline u32 rgmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_RGMII: + return RGMII_FER_RGMII(input); + case PHY_MODE_TBI: + return RGMII_FER_TBI(input); + case PHY_MODE_GMII: + return RGMII_FER_GMII(input); + case PHY_MODE_RTBI: + return RGMII_FER_RTBI(input); + default: + BUG(); + } +} + +static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + struct rgmii_regs *p; + + RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode); + + if (!dev) { + dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR + "rgmii%d: couldn't allocate device structure!\n", + ocpdev->def->index); + return -ENOMEM; + } + + p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr, + sizeof(struct rgmii_regs)); + if (!p) { + printk(KERN_ERR + "rgmii%d: could not ioremap device registers!\n", + ocpdev->def->index); + kfree(dev); + return -ENOMEM; + } + + dev->base = p; + ocp_set_drvdata(ocpdev, dev); + + /* Disable all inputs by default */ + out_be32(&p->fer, 0); + } else + p = dev->base; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); + + printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", + ocpdev->def->index, input, rgmii_mode_name(mode)); + + ++dev->users; + return 0; +} + +int __init rgmii_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + /* Check if we need to attach to a RGMII */ + if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) { + dev->rgmii_input = emacdata->rgmii_mux; + dev->rgmii_dev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII, + emacdata->rgmii_idx); + if (!dev->rgmii_dev) { + printk(KERN_ERR "emac%d: unknown rgmii%d!\n", + dev->def->index, emacdata->rgmii_idx); + return -ENODEV; + } + if (rgmii_init + (dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) { + printk(KERN_ERR + "emac%d: rgmii%d initialization failed!\n", + dev->def->index, emacdata->rgmii_idx); + return -ENODEV; + } + } + return 0; +} + +void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input); + + RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); + + if (speed == SPEED_1000) + ssr |= RGMII_SSR_1000(input); + else if (speed == SPEED_100) + ssr |= RGMII_SSR_100(input); + + out_be32(&dev->base->ssr, ssr); +} + +void __exit __rgmii_fini(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + BUG_ON(!dev || dev->users == 0); + + RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input)); + + if (!--dev->users) { + /* Free everything if this is the last user */ + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)dev->base); + kfree(dev); + } +} + +int __rgmii_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct rgmii_regs); +} + +void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h index 49f188f4ea6e..a1ffb8a44fff 100644 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -1,5 +1,7 @@ /* - * Defines for the IBM RGMII bridge + * drivers/net/ibm_emac/ibm_emac_rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. * * Based on ocp_zmii.h/ibm_emac_zmii.h * Armin Kuster akuster@mvista.com @@ -7,6 +9,9 @@ * Copyright 2004 MontaVista Software, Inc. * Matt Porter * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * * 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 @@ -19,47 +24,42 @@ #include /* RGMII bridge */ -typedef struct rgmii_regs { +struct rgmii_regs { u32 fer; /* Function enable register */ u32 ssr; /* Speed select register */ -} rgmii_t; - -#define RGMII_INPUTS 4 +}; /* RGMII device */ struct ibm_ocp_rgmii { struct rgmii_regs *base; - int mode[RGMII_INPUTS]; int users; /* number of EMACs using this RGMII bridge */ }; -/* Fuctional Enable Reg */ -#define RGMII_FER_MASK(x) (0x00000007 << (4*x)) -#define RGMII_RTBI 0x00000004 -#define RGMII_RGMII 0x00000005 -#define RGMII_TBI 0x00000006 -#define RGMII_GMII 0x00000007 +#ifdef CONFIG_IBM_EMAC_RGMII +int rgmii_attach(void *emac) __init; -/* Speed Selection reg */ +void __rgmii_fini(struct ocp_device *ocpdev, int input) __exit; +static inline void rgmii_fini(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __rgmii_fini(ocpdev, input); +} -#define RGMII_SP2_100 0x00000002 -#define RGMII_SP2_1000 0x00000004 -#define RGMII_SP3_100 0x00000200 -#define RGMII_SP3_1000 0x00000400 +void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed); -#define RGMII_MII2_SPDMASK 0x00000007 -#define RGMII_MII3_SPDMASK 0x00000700 +int __rgmii_get_regs_len(struct ocp_device *ocpdev); +static inline int rgmii_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __rgmii_get_regs_len(ocpdev) : 0; +} -#define RGMII_MII2_100MB RGMII_SP2_100 & ~RGMII_SP2_1000 -#define RGMII_MII2_1000MB RGMII_SP2_1000 & ~RGMII_SP2_100 -#define RGMII_MII2_10MB ~(RGMII_SP2_100 | RGMII_SP2_1000) -#define RGMII_MII3_100MB RGMII_SP3_100 & ~RGMII_SP3_1000 -#define RGMII_MII3_1000MB RGMII_SP3_1000 & ~RGMII_SP3_100 -#define RGMII_MII3_10MB ~(RGMII_SP3_100 | RGMII_SP3_1000) - -#define RTBI 0 -#define RGMII 1 -#define TBI 2 -#define GMII 3 +void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf); +#else +# define rgmii_attach(x) 0 +# define rgmii_fini(x,y) ((void)0) +# define rgmii_set_speed(x,y,z) ((void)0) +# define rgmii_get_regs_len(x) 0 +# define rgmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_RGMII */ #endif /* _IBM_EMAC_RGMII_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_tah.c b/drivers/net/ibm_emac/ibm_emac_tah.c new file mode 100644 index 000000000000..af08afc22f9f --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_tah.c @@ -0,0 +1,111 @@ +/* + * drivers/net/ibm_emac/ibm_emac_tah.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2005 Eugene Surovegin + * + * 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 "ibm_emac_core.h" + +static int __init tah_init(struct ocp_device *ocpdev) +{ + struct tah_regs *p; + + if (ocp_get_drvdata(ocpdev)) { + printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index); + return -EBUSY; + } + + /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ + p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p)); + if (!p) { + printk(KERN_ERR "tah%d: could not ioremap device registers!\n", + ocpdev->def->index); + return -ENOMEM; + } + ocp_set_drvdata(ocpdev, p); + __tah_reset(ocpdev); + + return 0; +} + +int __init tah_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + /* Check if we need to attach to a TAH */ + if (emacdata->tah_idx >= 0) { + dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, + emacdata->tah_idx); + if (!dev->tah_dev) { + printk(KERN_ERR "emac%d: unknown tah%d!\n", + dev->def->index, emacdata->tah_idx); + return -ENODEV; + } + if (tah_init(dev->tah_dev)) { + printk(KERN_ERR + "emac%d: tah%d initialization failed!\n", + dev->def->index, emacdata->tah_idx); + return -ENODEV; + } + } + return 0; +} + +void __exit __tah_fini(struct ocp_device *ocpdev) +{ + struct tah_regs *p = ocp_get_drvdata(ocpdev); + BUG_ON(!p); + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)p); +} + +void __tah_reset(struct ocp_device *ocpdev) +{ + struct tah_regs *p = ocp_get_drvdata(ocpdev); + int n; + + /* Reset TAH */ + out_be32(&p->mr, TAH_MR_SR); + n = 100; + while ((in_be32(&p->mr) & TAH_MR_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index); + + /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + out_be32(&p->mr, + TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | + TAH_MR_DIG); +} + +int __tah_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct tah_regs); +} + +void *tah_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct tah_regs *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct tah_regs *regs = (struct tah_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev, sizeof(struct tah_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_tah.h b/drivers/net/ibm_emac/ibm_emac_tah.h index ecfc69805521..9299b5dd7eb1 100644 --- a/drivers/net/ibm_emac/ibm_emac_tah.h +++ b/drivers/net/ibm_emac/ibm_emac_tah.h @@ -1,9 +1,13 @@ /* - * Defines for the IBM TAH + * drivers/net/ibm_emac/ibm_emac_tah.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. * * Copyright 2004 MontaVista Software, Inc. * Matt Porter * + * Copyright (c) 2005 Eugene Surovegin + * * 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 @@ -13,36 +17,72 @@ #ifndef _IBM_EMAC_TAH_H #define _IBM_EMAC_TAH_H +#include +#include +#include + /* TAH */ -typedef struct tah_regs { - u32 tah_revid; +struct tah_regs { + u32 revid; u32 pad[3]; - u32 tah_mr; - u32 tah_ssr0; - u32 tah_ssr1; - u32 tah_ssr2; - u32 tah_ssr3; - u32 tah_ssr4; - u32 tah_ssr5; - u32 tah_tsr; -} tah_t; + u32 mr; + u32 ssr0; + u32 ssr1; + u32 ssr2; + u32 ssr3; + u32 ssr4; + u32 ssr5; + u32 tsr; +}; /* TAH engine */ -#define TAH_MR_CVR 0x80000000 -#define TAH_MR_SR 0x40000000 -#define TAH_MR_ST_256 0x01000000 -#define TAH_MR_ST_512 0x02000000 -#define TAH_MR_ST_768 0x03000000 -#define TAH_MR_ST_1024 0x04000000 -#define TAH_MR_ST_1280 0x05000000 -#define TAH_MR_ST_1536 0x06000000 -#define TAH_MR_TFS_16KB 0x00000000 -#define TAH_MR_TFS_2KB 0x00200000 -#define TAH_MR_TFS_4KB 0x00400000 -#define TAH_MR_TFS_6KB 0x00600000 -#define TAH_MR_TFS_8KB 0x00800000 -#define TAH_MR_TFS_10KB 0x00a00000 -#define TAH_MR_DTFP 0x00100000 -#define TAH_MR_DIG 0x00080000 +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 + +#ifdef CONFIG_IBM_EMAC_TAH +int tah_attach(void *emac) __init; + +void __tah_fini(struct ocp_device *ocpdev) __exit; +static inline void tah_fini(struct ocp_device *ocpdev) +{ + if (ocpdev) + __tah_fini(ocpdev); +} + +void __tah_reset(struct ocp_device *ocpdev); +static inline void tah_reset(struct ocp_device *ocpdev) +{ + if (ocpdev) + __tah_reset(ocpdev); +} + +int __tah_get_regs_len(struct ocp_device *ocpdev); +static inline int tah_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __tah_get_regs_len(ocpdev) : 0; +} + +void *tah_dump_regs(struct ocp_device *ocpdev, void *buf); +#else +# define tah_attach(x) 0 +# define tah_fini(x) ((void)0) +# define tah_reset(x) ((void)0) +# define tah_get_regs_len(x) 0 +# define tah_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_TAH */ #endif /* _IBM_EMAC_TAH_H */ diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.c b/drivers/net/ibm_emac/ibm_emac_zmii.c new file mode 100644 index 000000000000..35c1185079ed --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_zmii.c @@ -0,0 +1,255 @@ +/* + * drivers/net/ibm_emac/ibm_emac_zmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare 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 "ibm_emac_core.h" +#include "ibm_emac_debug.h" + +/* ZMIIx_FER */ +#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) +#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ + ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) + +#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMIIx_SSR */ +#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMII only supports MII, RMII and SMII + * we also support autodetection for backward compatibility + */ +static inline int zmii_valid_mode(int mode) +{ + return mode == PHY_MODE_MII || + mode == PHY_MODE_RMII || + mode == PHY_MODE_SMII || + mode == PHY_MODE_NA; +} + +static inline const char *zmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_MII: + return "MII"; + case PHY_MODE_RMII: + return "RMII"; + case PHY_MODE_SMII: + return "SMII"; + default: + BUG(); + } +} + +static inline u32 zmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_MII: + return ZMII_FER_MII(input); + case PHY_MODE_RMII: + return ZMII_FER_RMII(input); + case PHY_MODE_SMII: + return ZMII_FER_SMII(input); + default: + return 0; + } +} + +static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + struct zmii_regs *p; + + ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); + + if (!dev) { + dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR + "zmii%d: couldn't allocate device structure!\n", + ocpdev->def->index); + return -ENOMEM; + } + dev->mode = PHY_MODE_NA; + + p = (struct zmii_regs *)ioremap(ocpdev->def->paddr, + sizeof(struct zmii_regs)); + if (!p) { + printk(KERN_ERR + "zmii%d: could not ioremap device registers!\n", + ocpdev->def->index); + kfree(dev); + return -ENOMEM; + } + dev->base = p; + ocp_set_drvdata(ocpdev, dev); + + /* We may need FER value for autodetection later */ + dev->fer_save = in_be32(&p->fer); + + /* Disable all inputs by default */ + out_be32(&p->fer, 0); + } else + p = dev->base; + + if (!zmii_valid_mode(*mode)) { + /* Probably an EMAC connected to RGMII, + * but it still may need ZMII for MDIO + */ + goto out; + } + + /* Autodetect ZMII mode if not specified. + * This is only for backward compatibility with the old driver. + * Please, always specify PHY mode in your board port to avoid + * any surprises. + */ + if (dev->mode == PHY_MODE_NA) { + if (*mode == PHY_MODE_NA) { + u32 r = dev->fer_save; + + ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL, + ocpdev->def->index, r); + + if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) + dev->mode = PHY_MODE_MII; + else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) + dev->mode = PHY_MODE_RMII; + else + dev->mode = PHY_MODE_SMII; + } else + dev->mode = *mode; + + printk(KERN_NOTICE "zmii%d: bridge in %s mode\n", + ocpdev->def->index, zmii_mode_name(dev->mode)); + } else { + /* All inputs must use the same mode */ + if (*mode != PHY_MODE_NA && *mode != dev->mode) { + printk(KERN_ERR + "zmii%d: invalid mode %d specified for input %d\n", + ocpdev->def->index, *mode, input); + return -EINVAL; + } + } + + /* Report back correct PHY mode, + * it may be used during PHY initialization. + */ + *mode = dev->mode; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); + out: + ++dev->users; + return 0; +} + +int __init zmii_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + if (emacdata->zmii_idx >= 0) { + dev->zmii_input = emacdata->zmii_mux; + dev->zmii_dev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII, + emacdata->zmii_idx); + if (!dev->zmii_dev) { + printk(KERN_ERR "emac%d: unknown zmii%d!\n", + dev->def->index, emacdata->zmii_idx); + return -ENODEV; + } + if (zmii_init + (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) { + printk(KERN_ERR + "emac%d: zmii%d initialization failed!\n", + dev->def->index, emacdata->zmii_idx); + return -ENODEV; + } + } + return 0; +} + +void __zmii_enable_mdio(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; + + ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input); + + out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); +} + +void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + u32 ssr = in_be32(&dev->base->ssr); + + ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); + + if (speed == SPEED_100) + ssr |= ZMII_SSR_SP(input); + else + ssr &= ~ZMII_SSR_SP(input); + + out_be32(&dev->base->ssr, ssr); +} + +void __exit __zmii_fini(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + BUG_ON(!dev || dev->users == 0); + + ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); + + if (!--dev->users) { + /* Free everything if this is the last user */ + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)dev->base); + kfree(dev); + } +} + +int __zmii_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct zmii_regs); +} + +void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h index 6f6cd2a39e38..0bb26062c0ad 100644 --- a/drivers/net/ibm_emac/ibm_emac_zmii.h +++ b/drivers/net/ibm_emac/ibm_emac_zmii.h @@ -1,23 +1,27 @@ /* - * ocp_zmii.h + * drivers/net/ibm_emac/ibm_emac_zmii.h * - * Defines for the IBM ZMII bridge + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. * - * Armin Kuster akuster@mvista.com - * Dec, 2001 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or * - * Copyright 2001 MontaVista Softare Inc. + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare 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 _IBM_EMAC_ZMII_H_ #define _IBM_EMAC_ZMII_H_ #include +#include +#include /* ZMII bridge registers */ struct zmii_regs { @@ -26,68 +30,54 @@ struct zmii_regs { u32 smiirs; /* SMII status reg */ }; -#define ZMII_INPUTS 4 - /* ZMII device */ struct ibm_ocp_zmii { struct zmii_regs *base; - int mode[ZMII_INPUTS]; + int mode; /* subset of PHY_MODE_XXXX */ int users; /* number of EMACs using this ZMII bridge */ + u32 fer_save; /* FER value left by firmware */ }; -/* Fuctional Enable Reg */ +#ifdef CONFIG_IBM_EMAC_ZMII +int zmii_attach(void *emac) __init; -#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x)) +void __zmii_fini(struct ocp_device *ocpdev, int input) __exit; +static inline void zmii_fini(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __zmii_fini(ocpdev, input); +} -#define ZMII_MDI0 0x80000000 -#define ZMII_SMII0 0x40000000 -#define ZMII_RMII0 0x20000000 -#define ZMII_MII0 0x10000000 -#define ZMII_MDI1 0x08000000 -#define ZMII_SMII1 0x04000000 -#define ZMII_RMII1 0x02000000 -#define ZMII_MII1 0x01000000 -#define ZMII_MDI2 0x00800000 -#define ZMII_SMII2 0x00400000 -#define ZMII_RMII2 0x00200000 -#define ZMII_MII2 0x00100000 -#define ZMII_MDI3 0x00080000 -#define ZMII_SMII3 0x00040000 -#define ZMII_RMII3 0x00020000 -#define ZMII_MII3 0x00010000 +void __zmii_enable_mdio(struct ocp_device *ocpdev, int input); +static inline void zmii_enable_mdio(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __zmii_enable_mdio(ocpdev, input); +} -/* Speed Selection reg */ +void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed); +static inline void zmii_set_speed(struct ocp_device *ocpdev, int input, + int speed) +{ + if (ocpdev) + __zmii_set_speed(ocpdev, input, speed); +} -#define ZMII_SCI0 0x40000000 -#define ZMII_FSS0 0x20000000 -#define ZMII_SP0 0x10000000 -#define ZMII_SCI1 0x04000000 -#define ZMII_FSS1 0x02000000 -#define ZMII_SP1 0x01000000 -#define ZMII_SCI2 0x00400000 -#define ZMII_FSS2 0x00200000 -#define ZMII_SP2 0x00100000 -#define ZMII_SCI3 0x00040000 -#define ZMII_FSS3 0x00020000 -#define ZMII_SP3 0x00010000 +int __zmii_get_regs_len(struct ocp_device *ocpdev); +static inline int zmii_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __zmii_get_regs_len(ocpdev) : 0; +} -#define ZMII_MII0_100MB ZMII_SP0 -#define ZMII_MII0_10MB ~ZMII_SP0 -#define ZMII_MII1_100MB ZMII_SP1 -#define ZMII_MII1_10MB ~ZMII_SP1 -#define ZMII_MII2_100MB ZMII_SP2 -#define ZMII_MII2_10MB ~ZMII_SP2 -#define ZMII_MII3_100MB ZMII_SP3 -#define ZMII_MII3_10MB ~ZMII_SP3 +void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf); -/* SMII Status reg */ - -#define ZMII_STS0 0xFF000000 /* EMAC0 smii status mask */ -#define ZMII_STS1 0x00FF0000 /* EMAC1 smii status mask */ - -#define SMII 0 -#define RMII 1 -#define MII 2 -#define MDI 3 +#else +# define zmii_attach(x) 0 +# define zmii_fini(x,y) ((void)0) +# define zmii_enable_mdio(x,y) ((void)0) +# define zmii_set_speed(x,y,z) ((void)0) +# define zmii_get_regs_len(x) 0 +# define zmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_ZMII */ #endif /* _IBM_EMAC_ZMII_H_ */ From 24682978eb5316b9e6041c2773e210180a037d05 Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Fri, 14 Oct 2005 03:00:53 -0700 Subject: [PATCH 0992/1939] [PATCH] Add MAINTAINER entry for the new PowerPC 4xx on-chip ethernet controller driver Add MAINTAINER entry for the new PPC4xx EMAC driver Signed-off-by: Eugene Surovegin Signed-off-by: Jeff Garzik --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 767fb610963e..900bd58f2dbe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1942,6 +1942,14 @@ M: george@mvista.com L: netdev@vger.kernel.org S: Supported +POWERPC 4xx EMAC DRIVER +P: Eugene Surovegin +M: ebs@ebshome.net +W: http://kernel.ebshome.net/emac/ +L: linuxppc-embedded@ozlabs.org +L: netdev@vger.kernel.org +S: Maintained + PNP SUPPORT P: Adam Belay M: ambx1@neo.rr.com From b2795f596932286ef12dc08857960d654f577405 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 28 Oct 2005 16:43:40 -0400 Subject: [PATCH 0993/1939] [git] change permissions on drivers/net/amd8111e.[ch] to 0644, removing executable bits. --- drivers/net/amd8111e.c | 0 drivers/net/amd8111e.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 drivers/net/amd8111e.c mode change 100755 => 100644 drivers/net/amd8111e.h diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c old mode 100755 new mode 100644 diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h old mode 100755 new mode 100644 From 7380a78a973a8109c13cb0e47617c456b6f6e1f5 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Fri, 28 Oct 2005 16:46:35 -0400 Subject: [PATCH 0994/1939] sis900: come alive after temporary memory shortage 1) Forgotten counter incrementation in sis900_rx() in case it doesn't get memory for skb, that leads to whole interface failure. Problem is accompanied with messages: eth0: Memory squeeze,deferring packet. eth0: NULL pointer encountered in Rx ring, skipping 2) If counter cur_rx overflows and there'll be temporary memory problems buffer can't be recreated later, when memory IS available. 3) Limit the work in handler to prevent the endless packets processing if new packets are generated faster then handled. Signed-off-by: Konstantin Khorenko Signed-off-by: Vasily Averin Signed-off-by: Jeff Garzik --- drivers/net/sis900.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 23b713c700b3..1d4d88680db1 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1696,15 +1696,20 @@ static int sis900_rx(struct net_device *net_dev) long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + int rx_work_limit; if (netif_msg_rx_status(sis_priv)) printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); + rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx; while (rx_status & OWN) { unsigned int rx_size; + if (--rx_work_limit < 0) + break; + rx_size = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { @@ -1732,9 +1737,11 @@ static int sis900_rx(struct net_device *net_dev) we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { if (netif_msg_rx_err(sis_priv)) - printk(KERN_INFO "%s: NULL pointer " - "encountered in Rx ring, skipping\n", - net_dev->name); + printk(KERN_WARNING "%s: NULL pointer " + "encountered in Rx ring\n" + "cur_rx:%4.4d, dirty_rx:%4.4d\n", + net_dev->name, sis_priv->cur_rx, + sis_priv->dirty_rx); break; } @@ -1770,6 +1777,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_ring[entry].cmdsts = 0; sis_priv->rx_ring[entry].bufptr = 0; sis_priv->stats.rx_dropped++; + sis_priv->cur_rx++; break; } skb->dev = net_dev; @@ -1787,7 +1795,7 @@ static int sis900_rx(struct net_device *net_dev) /* refill the Rx buffer, what if the rate of refilling is slower * than consuming ?? */ - for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { + for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) { struct sk_buff *skb; entry = sis_priv->dirty_rx % NUM_RX_DESC; From b4558ea93d66a43f7990d26f145fd4c54a01c9bf Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 28 Oct 2005 16:53:13 -0400 Subject: [PATCH 0995/1939] drivers/net: Remove pointless checks for NULL prior to calling kfree() --- drivers/net/acenic.c | 6 +-- drivers/net/au1000_eth.c | 6 +-- drivers/net/b44.c | 12 ++---- drivers/net/bmac.c | 6 +-- drivers/net/bnx2.c | 12 ++---- drivers/net/e1000/e1000_ethtool.c | 7 +--- drivers/net/hamradio/mkiss.c | 6 +-- drivers/net/ibmveth.c | 6 +-- drivers/net/irda/donauboe.c | 6 +-- drivers/net/irda/irda-usb.c | 6 +-- drivers/net/irda/irport.c | 3 +- drivers/net/irda/sir_dev.c | 3 +- drivers/net/irda/vlsi_ir.c | 3 +- drivers/net/mace.c | 6 +-- drivers/net/ni65.c | 9 ++-- drivers/net/rrunner.c | 6 +-- drivers/net/s2io.c | 3 +- drivers/net/saa9730.c | 8 +--- drivers/net/tg3.c | 6 +-- drivers/net/tulip/de2104x.c | 6 +-- drivers/net/tulip/tulip_core.c | 6 +-- drivers/net/via-velocity.c | 6 +-- drivers/net/wireless/airo.c | 48 +++++++++------------- drivers/net/wireless/airo_cs.c | 4 +- drivers/net/wireless/atmel.c | 6 +-- drivers/net/wireless/atmel_cs.c | 3 +- drivers/net/wireless/hostap/hostap_ioctl.c | 9 +--- drivers/net/wireless/prism54/islpci_dev.c | 3 +- drivers/net/wireless/prism54/oid_mgt.c | 9 ++-- drivers/net/wireless/strip.c | 38 ++++++----------- include/net/ax25.h | 3 +- include/net/netrom.h | 3 +- 32 files changed, 90 insertions(+), 174 deletions(-) diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index dbecc6bf7851..b8953de5664a 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -871,10 +871,8 @@ static void ace_init_cleanup(struct net_device *dev) if (ap->info) pci_free_consistent(ap->pdev, sizeof(struct ace_info), ap->info, ap->info_dma); - if (ap->skb) - kfree(ap->skb); - if (ap->trace_buf) - kfree(ap->trace_buf); + kfree(ap->skb); + kfree(ap->trace_buf); if (dev->irq) free_irq(dev->irq, dev); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 78506911d656..332e9953c55c 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1606,8 +1606,7 @@ au1000_probe(u32 ioaddr, int irq, int port_num) /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); - if (aup->mii) - kfree(aup->mii); + kfree(aup->mii); for (i = 0; i < NUM_RX_DMA; i++) { if (aup->rx_db_inuse[i]) ReleaseDB(aup, aup->rx_db_inuse[i]); @@ -1806,8 +1805,7 @@ static void __exit au1000_cleanup_module(void) if (dev) { aup = (struct au1000_private *) dev->priv; unregister_netdev(dev); - if (aup->mii) - kfree(aup->mii); + kfree(aup->mii); for (j = 0; j < NUM_RX_DMA; j++) { if (aup->rx_db_inuse[j]) ReleaseDB(aup, aup->rx_db_inuse[j]); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ab845076ff9f..5485e3b1cd35 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1131,14 +1131,10 @@ static void b44_init_rings(struct b44 *bp) */ static void b44_free_consistent(struct b44 *bp) { - if (bp->rx_buffers) { - kfree(bp->rx_buffers); - bp->rx_buffers = NULL; - } - if (bp->tx_buffers) { - kfree(bp->tx_buffers); - bp->tx_buffers = NULL; - } + kfree(bp->rx_buffers); + bp->rx_buffers = NULL; + kfree(bp->tx_buffers); + bp->tx_buffers = NULL; if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 60dba4a1ca5c..73f2fcfc557f 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1689,10 +1689,8 @@ static void __exit bmac_exit(void) { macio_unregister_driver(&bmac_driver); - if (bmac_emergency_rxbuf != NULL) { - kfree(bmac_emergency_rxbuf); - bmac_emergency_rxbuf = NULL; - } + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; } MODULE_AUTHOR("Randy Gobbel/Paul Mackerras"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 3a2ace01e444..11d252318221 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -314,20 +314,16 @@ bnx2_free_mem(struct bnx2 *bp) bp->tx_desc_ring, bp->tx_desc_mapping); bp->tx_desc_ring = NULL; } - if (bp->tx_buf_ring) { - kfree(bp->tx_buf_ring); - bp->tx_buf_ring = NULL; - } + kfree(bp->tx_buf_ring); + bp->tx_buf_ring = NULL; if (bp->rx_desc_ring) { pci_free_consistent(bp->pdev, sizeof(struct rx_bd) * RX_DESC_CNT, bp->rx_desc_ring, bp->rx_desc_mapping); bp->rx_desc_ring = NULL; } - if (bp->rx_buf_ring) { - kfree(bp->rx_buf_ring); - bp->rx_buf_ring = NULL; - } + kfree(bp->rx_buf_ring); + bp->rx_buf_ring = NULL; } static int diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 6b9acc7f94a3..9c7feaeaa6a4 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -965,11 +965,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) if(rxdr->desc) pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); - if(txdr->buffer_info) - kfree(txdr->buffer_info); - if(rxdr->buffer_info) - kfree(rxdr->buffer_info); - + kfree(txdr->buffer_info); + kfree(rxdr->buffer_info); return; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 85d6dc005be0..3e9accf137e7 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -390,10 +390,8 @@ static void ax_changedmtu(struct mkiss *ax) "MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; - if (xbuff != NULL) - kfree(xbuff); - if (rbuff != NULL) - kfree(rbuff); + kfree(xbuff); + kfree(rbuff); return; } diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index f5819527ec9d..36da54ad2b7b 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -276,10 +276,8 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm { int i; - if(pool->free_map) { - kfree(pool->free_map); - pool->free_map = NULL; - } + kfree(pool->free_map); + pool->free_map = NULL; if(pool->skbuff && pool->dma_addr) { for(i = 0; i < pool->size; ++i) { diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 0a08c539c051..0282771b1cbb 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1695,11 +1695,9 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) freebufs: for (i = 0; i < TX_SLOTS; ++i) - if (self->tx_bufs[i]) - kfree (self->tx_bufs[i]); + kfree (self->tx_bufs[i]); for (i = 0; i < RX_SLOTS; ++i) - if (self->rx_bufs[i]) - kfree (self->rx_bufs[i]); + kfree (self->rx_bufs[i]); kfree(self->ringbuf); freeregion: diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6c766fdc51a6..c22c0517883c 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1168,10 +1168,8 @@ static inline void irda_usb_close(struct irda_usb_cb *self) unregister_netdev(self->netdev); /* Remove the speed buffer */ - if (self->speed_buff != NULL) { - kfree(self->speed_buff); - self->speed_buff = NULL; - } + kfree(self->speed_buff); + self->speed_buff = NULL; } /********************** USB CONFIG SUBROUTINES **********************/ diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 5971315f3fa0..3d016a498e1d 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -235,8 +235,7 @@ static int irport_close(struct irport_cb *self) __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); - if (self->tx_buff.head) - kfree(self->tx_buff.head); + kfree(self->tx_buff.head); if (self->rx_buff.skb) kfree_skb(self->rx_buff.skb); diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index efc5a8870565..df22b8b532e7 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -490,8 +490,7 @@ static void sirdev_free_buffers(struct sir_dev *dev) { if (dev->rx_buff.skb) kfree_skb(dev->rx_buff.skb); - if (dev->tx_buff.head) - kfree(dev->tx_buff.head); + kfree(dev->tx_buff.head); dev->rx_buff.head = dev->tx_buff.head = NULL; dev->rx_buff.skb = NULL; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 651c5a6578fd..a9f49f058cfb 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -473,8 +473,7 @@ static int vlsi_free_ring(struct vlsi_ring *r) rd_set_addr_status(rd, 0, 0); if (busaddr) pci_unmap_single(r->pdev, busaddr, r->len, r->dir); - if (rd->buf) - kfree(rd->buf); + kfree(rd->buf); } kfree(r); return 0; diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 81d0a26e4f41..09b1e7b364e5 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -1035,10 +1035,8 @@ static void __exit mace_cleanup(void) { macio_unregister_driver(&mace_driver); - if (dummy_buf) { - kfree(dummy_buf); - dummy_buf = NULL; - } + kfree(dummy_buf); + dummy_buf = NULL; } MODULE_AUTHOR("Paul Mackerras"); diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 925d1dfcc4dc..bb42ff218484 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -696,8 +696,7 @@ static void ni65_free_buffer(struct priv *p) return; for(i=0;itmdbounce[i]) - kfree(p->tmdbounce[i]); + kfree(p->tmdbounce[i]); #ifdef XMT_VIA_SKB if(p->tmd_skb[i]) dev_kfree_skb(p->tmd_skb[i]); @@ -710,12 +709,10 @@ static void ni65_free_buffer(struct priv *p) if(p->recv_skb[i]) dev_kfree_skb(p->recv_skb[i]); #else - if(p->recvbounce[i]) - kfree(p->recvbounce[i]); + kfree(p->recvbounce[i]); #endif } - if(p->self) - kfree(p->self); + kfree(p->self); } diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index ec1a18d189a1..19c2df9c86fe 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1710,10 +1710,8 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) error = -EFAULT; } wf_out: - if (oldimage) - kfree(oldimage); - if (image) - kfree(image); + kfree(oldimage); + kfree(image); return error; case SIOCRRID: diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d303d162974f..5ea897714a14 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -705,8 +705,7 @@ static void free_shared_mem(struct s2io_nic *nic) } kfree(mac_control->rings[i].ba[j]); } - if (mac_control->rings[i].ba) - kfree(mac_control->rings[i].ba); + kfree(mac_control->rings[i].ba); } #endif diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index fd0167077fbe..110e777f206e 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -997,10 +997,7 @@ static void __devexit saa9730_remove_one(struct pci_dev *pdev) if (dev) { unregister_netdev(dev); - - if (dev->priv) - kfree(dev->priv); - + kfree(dev->priv); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1096,8 +1093,7 @@ static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq) return 0; out: - if (dev->priv) - kfree(dev->priv); + kfree(dev->priv); return ret; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 551c9449322d..b547233ad9f7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3918,10 +3918,8 @@ static void tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { - if (tp->rx_std_buffers) { - kfree(tp->rx_std_buffers); - tp->rx_std_buffers = NULL; - } + kfree(tp->rx_std_buffers); + tp->rx_std_buffers = NULL; if (tp->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, tp->rx_std, tp->rx_std_mapping); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 6b8eee8f7bfd..d7fb3ffe06ac 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -2076,8 +2076,7 @@ static int __init de_init_one (struct pci_dev *pdev, return 0; err_out_iomap: - if (de->ee_data) - kfree(de->ee_data); + kfree(de->ee_data); iounmap(regs); err_out_res: pci_release_regions(pdev); @@ -2096,8 +2095,7 @@ static void __exit de_remove_one (struct pci_dev *pdev) if (!dev) BUG(); unregister_netdev(dev); - if (de->ee_data) - kfree(de->ee_data); + kfree(de->ee_data); iounmap(de->regs); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 6266a9a7e6e3..125ed00e95a5 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1727,8 +1727,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, tp->rx_ring, tp->rx_ring_dma); err_out_mtable: - if (tp->mtable) - kfree (tp->mtable); + kfree (tp->mtable); pci_iounmap(pdev, ioaddr); err_out_free_res: @@ -1806,8 +1805,7 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev) sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, tp->rx_ring, tp->rx_ring_dma); - if (tp->mtable) - kfree (tp->mtable); + kfree (tp->mtable); pci_iounmap(pdev, tp->base_addr); free_netdev (dev); pci_release_regions (pdev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index abc5cee6eedc..a368d08e7d19 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1212,10 +1212,8 @@ static void velocity_free_td_ring(struct velocity_info *vptr) velocity_free_td_ring_entry(vptr, j, i); } - if (vptr->td_infos[j]) { - kfree(vptr->td_infos[j]); - vptr->td_infos[j] = NULL; - } + kfree(vptr->td_infos[j]); + vptr->td_infos[j] = NULL; } } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index cb429e783749..4c11699bad91 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2381,14 +2381,10 @@ void stop_airo_card( struct net_device *dev, int freeres ) dev_kfree_skb(skb); } - if (ai->flash) - kfree(ai->flash); - if (ai->rssi) - kfree(ai->rssi); - if (ai->APList) - kfree(ai->APList); - if (ai->SSID) - kfree(ai->SSID); + kfree(ai->flash); + kfree(ai->rssi); + kfree(ai->APList); + kfree(ai->SSID); if (freeres) { /* PCMCIA frees this stuff, so only for PCI and ISA */ release_region( dev->base_addr, 64 ); @@ -3626,10 +3622,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) int rc; memset( &mySsid, 0, sizeof( mySsid ) ); - if (ai->flash) { - kfree (ai->flash); - ai->flash = NULL; - } + kfree (ai->flash); + ai->flash = NULL; /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; @@ -3666,14 +3660,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) tdsRssiRid rssi_rid; CapabilityRid cap_rid; - if (ai->APList) { - kfree(ai->APList); - ai->APList = NULL; - } - if (ai->SSID) { - kfree(ai->SSID); - ai->SSID = NULL; - } + kfree(ai->APList); + ai->APList = NULL; + kfree(ai->SSID); + ai->SSID = NULL; // general configuration (read/modify/write) status = readConfigRid(ai, lock); if ( status != SUCCESS ) return ERROR; @@ -3687,10 +3677,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ } else { - if (ai->rssi) { - kfree(ai->rssi); - ai->rssi = NULL; - } + kfree(ai->rssi); + ai->rssi = NULL; if (cap_rid.softCap & 8) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else @@ -5369,11 +5357,13 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { static int proc_close( struct inode *inode, struct file *file ) { - struct proc_data *data = (struct proc_data *)file->private_data; - if ( data->on_close != NULL ) data->on_close( inode, file ); - if ( data->rbuffer ) kfree( data->rbuffer ); - if ( data->wbuffer ) kfree( data->wbuffer ); - kfree( data ); + struct proc_data *data = file->private_data; + + if (data->on_close != NULL) + data->on_close(inode, file); + kfree(data->rbuffer); + kfree(data->wbuffer); + kfree(data); return 0; } diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index bf25584d68d3..784de9109113 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -258,9 +258,7 @@ static void airo_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - kfree(link->priv); - } + kfree(link->priv); kfree(link); } /* airo_detach */ diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index d57011028b72..1fbe027d26b6 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1653,8 +1653,7 @@ void stop_atmel_card(struct net_device *dev, int freeres) unregister_netdev(dev); remove_proc_entry("driver/atmel", NULL); free_irq(dev->irq, dev); - if (priv->firmware) - kfree(priv->firmware); + kfree(priv->firmware); if (freeres) { /* PCMCIA frees this stuff, so only for PCI */ release_region(dev->base_addr, 64); @@ -2450,8 +2449,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - if (priv->firmware) - kfree(priv->firmware); + kfree(priv->firmware); priv->firmware = new_firmware; priv->firmware_length = com.len; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index ff031a3985b3..195cb36619e8 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -259,8 +259,7 @@ static void atmel_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) - kfree(link->priv); + kfree(link->priv); kfree(link); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 53f5246c40aa..2617d70bcda9 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -552,7 +552,6 @@ static int prism2_ioctl_giwaplist(struct net_device *dev, kfree(addr); kfree(qual); - return 0; } @@ -3081,9 +3080,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) ret = local->func->download(local, param); out: - if (param != NULL) - kfree(param); - + kfree(param); return ret; } #endif /* PRISM2_DOWNLOAD_SUPPORT */ @@ -3890,9 +3887,7 @@ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) } out: - if (param != NULL) - kfree(param); - + kfree(param); return ret; } diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 6c9584a9f284..78bdb359835e 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -754,8 +754,7 @@ islpci_free_memory(islpci_private *priv) pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, PCI_DMA_FROMDEVICE); buf->pci_addr = 0; - if (buf->mem) - kfree(buf->mem); + kfree(buf->mem); buf->size = 0; buf->mem = NULL; } diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 12123e24b113..eea2f04c8c6d 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -268,11 +268,10 @@ mgt_clean(islpci_private *priv) if (!priv->mib) return; - for (i = 0; i < OID_NUM_LAST; i++) - if (priv->mib[i]) { - kfree(priv->mib[i]); - priv->mib[i] = NULL; - } + for (i = 0; i < OID_NUM_LAST; i++) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } kfree(priv->mib); priv->mib = NULL; } diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 7bc7fc823128..d25264ba0c0e 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -860,12 +860,9 @@ static int allocate_buffers(struct strip *strip_info, int mtu) strip_info->mtu = dev->mtu = mtu; return (1); } - if (r) - kfree(r); - if (s) - kfree(s); - if (t) - kfree(t); + kfree(r); + kfree(s); + kfree(t); return (0); } @@ -922,13 +919,9 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev->name, old_mtu, strip_info->mtu); - if (orbuff) - kfree(orbuff); - if (osbuff) - kfree(osbuff); - if (otbuff) - kfree(otbuff); - + kfree(orbuff); + kfree(osbuff); + kfree(otbuff); return 0; } @@ -2498,18 +2491,13 @@ static int strip_close_low(struct net_device *dev) /* * Free all STRIP frame buffers. */ - if (strip_info->rx_buff) { - kfree(strip_info->rx_buff); - strip_info->rx_buff = NULL; - } - if (strip_info->sx_buff) { - kfree(strip_info->sx_buff); - strip_info->sx_buff = NULL; - } - if (strip_info->tx_buff) { - kfree(strip_info->tx_buff); - strip_info->tx_buff = NULL; - } + kfree(strip_info->rx_buff); + strip_info->rx_buff = NULL; + kfree(strip_info->sx_buff); + strip_info->sx_buff = NULL; + kfree(strip_info->tx_buff); + strip_info->tx_buff = NULL; + del_timer(&strip_info->idle_timer); return 0; } diff --git a/include/net/ax25.h b/include/net/ax25.h index 30bb4a893237..2250a18b0cbb 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -237,8 +237,7 @@ typedef struct ax25_cb { static __inline__ void ax25_cb_put(ax25_cb *ax25) { if (atomic_dec_and_test(&ax25->refcount)) { - if (ax25->digipeat) - kfree(ax25->digipeat); + kfree(ax25->digipeat); kfree(ax25); } } diff --git a/include/net/netrom.h b/include/net/netrom.h index a6bf6e0f606a..a5ee53bce62f 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -136,8 +136,7 @@ static __inline__ void nr_node_put(struct nr_node *nr_node) static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) { if (atomic_dec_and_test(&nr_neigh->refcount)) { - if (nr_neigh->digipeat != NULL) - kfree(nr_neigh->digipeat); + kfree(nr_neigh->digipeat); kfree(nr_neigh); } } From 030ee39c0fef49d7dcd32e71b1ca98fcc23e2a72 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Oct 2005 13:55:08 -0700 Subject: [PATCH 0996/1939] pcmcia: add socket register data to sysfs for yenta devices It's simple, and it's a good debugging aid. Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index db9f952f9e3c..ec6ab65f0872 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -151,6 +151,40 @@ static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) readb(socket->base + 0x800 + reg + 1); } +static ssize_t show_yenta_registers(struct device *yentadev, struct device_attribute *attr, char *buf) +{ + struct pci_dev *dev = to_pci_dev(yentadev); + struct yenta_socket *socket = pci_get_drvdata(dev); + int offset = 0, i; + + offset = snprintf(buf, PAGE_SIZE, "CB registers:"); + for (i = 0; i < 0x24; i += 4) { + unsigned val; + if (!(i & 15)) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + val = cb_readl(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %08x", val); + } + + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n\nExCA registers:"); + for (i = 0; i < 0x45; i++) { + unsigned char val; + if (!(i & 7)) { + if (i & 8) { + memcpy(buf + offset, " -", 2); + offset += 2; + } else + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + } + val = exca_readb(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %02x", val); + } + buf[offset++] = '\n'; + return offset; +} + +static DEVICE_ATTR(yenta_registers, S_IRUSR, show_yenta_registers, NULL); + /* * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend * on what kind of card is inserted.. @@ -765,6 +799,9 @@ static void yenta_close(struct pci_dev *dev) { struct yenta_socket *sock = pci_get_drvdata(dev); + /* Remove the register attributes */ + device_remove_file(&dev->dev, &dev_attr_yenta_registers); + /* we don't want a dying socket registered */ pcmcia_unregister_socket(&sock->socket); @@ -1138,8 +1175,11 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); - if (ret == 0) + if (ret == 0) { + /* Add the yenta register attributes */ + device_create_file(&dev->dev, &dev_attr_yenta_registers); goto out; + } unmap: iounmap(socket->base); From 4f075707a9380592586d608a8d04dfbdb3c40339 Mon Sep 17 00:00:00 2001 From: Komuro Date: Fri, 28 Oct 2005 16:55:55 -0400 Subject: [PATCH 0997/1939] [netdrvr] ne2k-pci based card does not support bus-mastering. pci_set_master is unnecessary. Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Jeff Garzik --- drivers/net/ne2k-pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index e531a4eedfee..d11821dd86ed 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -675,7 +675,6 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); pci_enable_device(pdev); - pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); From ad18b0ea089928367185e13d11424aea91d4b41f Mon Sep 17 00:00:00 2001 From: Panagiotis Issaris Date: Mon, 5 Sep 2005 04:14:10 +0200 Subject: [PATCH 0998/1939] [PATCH] ipw2200: Missing kmalloc check The ipw2200 driver code in current GIT contains a kmalloc() followed by a memset() without handling a possible memory allocation failure. Signed-off-by: Panagiotis Issaris Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2200.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index de4e6c23e4b8..3db0c32afe82 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4030,6 +4030,10 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) int i; rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL); + if (unlikely(!rxq)) { + IPW_ERROR("memory allocation failed\n"); + return NULL; + } memset(rxq, 0, sizeof(*rxq)); spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); From 6cd37cda7ed117d5a13d9b69aeded57b4fd6de14 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Fri, 28 Oct 2005 20:23:39 +0200 Subject: [PATCH 0999/1939] [PATCH] Fix ext3 warning for unused var Fix compile warning in ext3 quota code. Signed-off-by: Peter Osterlund Signed-off-by: Linus Torvalds --- fs/ext3/super.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9e24ceb019fe..097383c11154 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -510,19 +510,11 @@ static void ext3_clear_inode(struct inode *inode) kfree(rsv); } -static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) +static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) { - struct super_block *sb = vfs->mnt_sb; +#if defined(CONFIG_QUOTA) struct ext3_sb_info *sbi = EXT3_SB(sb); - if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) - seq_puts(seq, ",data=journal"); - else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) - seq_puts(seq, ",data=ordered"); - else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) - seq_puts(seq, ",data=writeback"); - -#if defined(CONFIG_QUOTA) if (sbi->s_jquota_fmt) seq_printf(seq, ",jqfmt=%s", (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0"); @@ -539,6 +531,20 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) seq_puts(seq, ",grpquota"); #endif +} + +static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) +{ + struct super_block *sb = vfs->mnt_sb; + + if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + seq_puts(seq, ",data=journal"); + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) + seq_puts(seq, ",data=ordered"); + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + seq_puts(seq, ",data=writeback"); + + ext3_show_quota_options(seq, sb); return 0; } From 406119f49d4a6cf8b6eee639128e0575a95065e3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Oct 2005 14:46:53 -0400 Subject: [PATCH 1000/1939] [PATCH] Ensure that 'make distclean' does not delete files in '.git' Currently, 'make distclean' causes stgit to barf since it may delete files in .git/patches. We really shouldn't allow 'make distclean' anywhere near .git... Signed-off-by: Trond Myklebust Signed-off-by: Linus Torvalds --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f1d121f23025..79601320ac3e 100644 --- a/Makefile +++ b/Makefile @@ -371,8 +371,8 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve # Files to ignore in find ... statements -RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg \) -prune -o -export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg +RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git # =========================================================================== # Rules shared between *config targets and build targets From 07c1da2396632a4ad2cab41c6cd939b159f54968 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 28 Oct 2005 17:00:31 -0400 Subject: [PATCH 1001/1939] [libata sata_promise] add pci id Contributed by Daniel Mueller @ Siemens AG. --- drivers/scsi/sata_promise.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index eee93b0016df..50495569f409 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -195,6 +195,8 @@ static struct ata_port_info pdc_port_info[] = { static struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, From 205cf13e0b57500e2cc6442effa991c1a63f4db7 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Sat, 17 Sep 2005 05:32:55 +1000 Subject: [PATCH 1002/1939] [PATCH] hwmon: adm9240 driver update - cleanups hwmon: adm9240 update 1/2: cleanups: o remove i2c read/write wrapper interface as it does nothing, o change kmalloc + memset to kzalloc Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm9240.c | 92 ++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index bc7faef162f7..ecef342e5fa3 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -170,17 +170,6 @@ struct adm9240_data { u8 vrm; /* -- vrm set on startup, no accessor */ }; -/* i2c byte read/write interface */ -static int adm9240_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - /*** sysfs accessors ***/ /* temperature */ @@ -207,7 +196,7 @@ static ssize_t set_##value(struct device *dev, \ \ down(&data->update_lock); \ data->value = TEMP_TO_REG(temp); \ - adm9240_write_value(client, reg, data->value); \ + i2c_smbus_write_byte_data(client, reg, data->value); \ up(&data->update_lock); \ return count; \ } @@ -249,7 +238,8 @@ static ssize_t set_in_min(struct device *dev, const char *buf, down(&data->update_lock); data->in_min[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(nr), + data->in_min[nr]); up(&data->update_lock); return count; } @@ -263,7 +253,8 @@ static ssize_t set_in_max(struct device *dev, const char *buf, down(&data->update_lock); data->in_max[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(nr), + data->in_max[nr]); up(&data->update_lock); return count; } @@ -341,11 +332,11 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, { u8 reg, old, shift = (nr + 2) * 2; - reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); old = (reg >> shift) & 3; reg &= ~(3 << shift); reg |= (fan_div << shift); - adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg); dev_dbg(&client->dev, "fan%d clock divider changed from %u " "to %u\n", nr + 1, 1 << old, 1 << fan_div); } @@ -406,7 +397,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, data->fan_div[nr] = new_div; adm9240_write_fan_div(client, nr, new_div); } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr), data->fan_min[nr]); up(&data->update_lock); @@ -479,7 +470,7 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const down(&data->update_lock); data->aout = AOUT_TO_REG(val); - adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout); up(&data->update_lock); return count; } @@ -492,7 +483,8 @@ static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, unsigned long val = simple_strtol(buf, NULL, 10); if (val == 1) { - adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + i2c_smbus_write_byte_data(client, + ADM9240_REG_CHASSIS_CLEAR, 0x80); dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); } return count; @@ -513,11 +505,10 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm9240_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -533,7 +524,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if (kind < 0) { /* verify chip: reg address should match i2c address */ - if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) != address) { dev_err(&adapter->dev, "detect fail: address match, " "0x%02x\n", address); @@ -541,8 +532,8 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) } /* check known chip manufacturer */ - man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); - + man_id = i2c_smbus_read_byte_data(new_client, + ADM9240_REG_MAN_ID); if (man_id == 0x23) { kind = adm9240; } else if (man_id == 0xda) { @@ -556,7 +547,8 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) } /* successful detect, print chip info */ - die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + die_rev = i2c_smbus_read_byte_data(new_client, + ADM9240_REG_DIE_REV); dev_info(&adapter->dev, "found %s revision %u\n", man_id == 0x23 ? "ADM9240" : man_id == 0xda ? "DS1780" : "LM81", die_rev); @@ -654,8 +646,8 @@ static int adm9240_detach_client(struct i2c_client *client) static void adm9240_init_client(struct i2c_client *client) { struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); - u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + u8 conf = i2c_smbus_read_byte_data(client, ADM9240_REG_CONFIG); + u8 mode = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF) & 3; data->vrm = vid_which_vrm(); /* need this to report vid as mV */ @@ -672,18 +664,22 @@ static void adm9240_init_client(struct i2c_client *client) for (i = 0; i < 6; i++) { - adm9240_write_value(client, + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(i), 0); - adm9240_write_value(client, + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(i), 255); } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); - adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); - adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); - adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + i2c_smbus_write_byte_data(client, + ADM9240_REG_FAN_MIN(0), 255); + i2c_smbus_write_byte_data(client, + ADM9240_REG_FAN_MIN(1), 255); + i2c_smbus_write_byte_data(client, + ADM9240_REG_TEMP_HIGH, 127); + i2c_smbus_write_byte_data(client, + ADM9240_REG_TEMP_HYST, 127); /* start measurement cycle */ - adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); dev_info(&client->dev, "cold start: config was 0x%02x " "mode %u\n", conf, mode); @@ -704,25 +700,25 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) for (i = 0; i < 6; i++) /* read voltages */ { - data->in[i] = adm9240_read_value(client, + data->in[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN(i)); } - data->alarms = adm9240_read_value(client, + data->alarms = i2c_smbus_read_byte_data(client, ADM9240_REG_INT(0)) | - adm9240_read_value(client, + i2c_smbus_read_byte_data(client, ADM9240_REG_INT(1)) << 8; /* read temperature: assume temperature changes less than * 0.5'C per two measurement cycles thus ignore possible * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = ((adm9240_read_value(client, + data->temp = ((i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 8) | - adm9240_read_value(client, + i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF)) / 128; for (i = 0; i < 2; i++) /* read fans */ { - data->fan[i] = adm9240_read_value(client, + data->fan[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN(i)); /* adjust fan clock divider on overflow */ @@ -747,30 +743,30 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) for (i = 0; i < 6; i++) { - data->in_min[i] = adm9240_read_value(client, + data->in_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MIN(i)); - data->in_max[i] = adm9240_read_value(client, + data->in_max[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { - data->fan_min[i] = adm9240_read_value(client, + data->fan_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN_MIN(i)); } - data->temp_high = adm9240_read_value(client, + data->temp_high = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_HIGH); - data->temp_hyst = adm9240_read_value(client, + data->temp_hyst = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_HYST); /* read fan divs and 5-bit VID */ - i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); data->fan_div[0] = (i >> 4) & 3; data->fan_div[1] = (i >> 6) & 3; data->vid = i & 0x0f; - data->vid |= (adm9240_read_value(client, + data->vid |= (i2c_smbus_read_byte_data(client, ADM9240_REG_VID4) & 1) << 4; /* read analog out */ - data->aout = adm9240_read_value(client, + data->aout = i2c_smbus_read_byte_data(client, ADM9240_REG_ANALOG_OUT); data->last_updated_config = jiffies; From c7461a6652f40ce4f8e19d7368c7a807a618fb68 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Sat, 17 Sep 2005 05:32:57 +1000 Subject: [PATCH 1003/1939] [PATCH] hwmon: adm9240 driver update - dynamic sysfs hwmon: adm9240 update 2/2: convert to use dynamic sysfs accessors This patch converts adm9240 to use Yani Ioannou's dynamic sysfs callbacks, reducing driver memory footprint from 16312 to 14104 bytes on 2.6.14-rc1, removing the old driver macro mess. Run tested on Intel SE440BX-2 mobo. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm9240.c | 332 +++++++++++++++++++--------------------- 1 file changed, 161 insertions(+), 171 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index ecef342e5fa3..8bb6d6e45ed5 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -69,8 +70,7 @@ I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81); #define ADM9240_REG_INT(nr) (0x41 + (nr)) #define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) #define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_TEMP_HIGH 0x39 -#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_TEMP_MAX(nr) (0x39 + (nr)) /* 0, 1 = high, hyst */ #define ADM9240_REG_ANALOG_OUT 0x19 #define ADM9240_REG_CHASSIS_CLEAR 0x46 #define ADM9240_REG_VID_FAN_DIV 0x47 @@ -162,8 +162,7 @@ struct adm9240_data { u8 fan_min[2]; /* rw fan1_min */ u8 fan_div[2]; /* rw fan1_div, read-only accessor */ s16 temp; /* ro temp1_input, 9-bit sign-extended */ - s8 temp_high; /* rw temp1_max */ - s8 temp_hyst; /* rw temp1_max_hyst */ + s8 temp_max[2]; /* rw 0 -> temp_max, 1 -> temp_max_hyst */ u16 alarms; /* ro alarms */ u8 aout; /* rw aout_output */ u8 vid; /* ro vid */ @@ -173,157 +172,143 @@ struct adm9240_data { /*** sysfs accessors ***/ /* temperature */ -#define show_temp(value, scale) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct adm9240_data *data = adm9240_update_device(dev); \ - return sprintf(buf, "%d\n", data->value * scale); \ -} -show_temp(temp_high, 1000); -show_temp(temp_hyst, 1000); -show_temp(temp, 500); /* 0.5'C per bit */ - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm9240_data *data = adm9240_update_device(dev); \ - long temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */ } -set_temp(temp_high, ADM9240_REG_TEMP_HIGH); -set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); +static ssize_t show_max(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000); +} + +static ssize_t set_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[attr->index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index), + data->temp_max[attr->index]); + up(&data->update_lock); + return count; +} -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_high, set_temp_high); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, - show_temp_hyst, set_temp_hyst); static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_max, set_max, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_max, set_max, 1); /* voltage */ -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index], + attr->index)); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index], + attr->index)); } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index], + attr->index)); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(nr), - data->in_min[nr]); + data->in_min[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index), + data->in_min[attr->index]); up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(nr), - data->in_max[nr]); + data->in_max[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index), + data->in_max[attr->index]); up(&data->update_lock); return count; } -#define show_in_offset(offset) \ -static ssize_t show_in##offset(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static ssize_t show_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t \ -set_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t \ -set_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +#define vin(nr) \ +static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO, \ + show_in, NULL, nr); \ +static SENSOR_DEVICE_ATTR(in##nr##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, nr); \ +static SENSOR_DEVICE_ATTR(in##nr##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, nr); -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); +vin(0); +vin(1); +vin(2); +vin(3); +vin(4); +vin(5); /* fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - 1 << data->fan_div[nr])); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], + 1 << data->fan_div[attr->index])); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - 1 << data->fan_div[nr])); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index], + 1 << data->fan_div[attr->index])); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); + return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]); } /* write new fan div, callers must hold data->update_lock */ @@ -352,12 +337,15 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, * - otherwise: select fan clock divider to suit fan speed low limit, * measurement code may adjust registers to ensure fan speed reading */ -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); + int nr = attr->index; u8 new_div; down(&data->update_lock); @@ -404,40 +392,16 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, return count; } -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ -return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan_##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); +#define fan(nr) \ +static SENSOR_DEVICE_ATTR(fan##nr##_input, S_IRUGO, \ + show_fan, NULL, nr - 1); \ +static SENSOR_DEVICE_ATTR(fan##nr##_div, S_IRUGO, \ + show_fan_div, NULL, nr - 1); \ +static SENSOR_DEVICE_ATTR(fan##nr##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, nr - 1); -show_fan_offset(1); -show_fan_offset(2); +fan(1); +fan(2); /* alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -580,33 +544,59 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_max.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_aout_output); device_create_file(&new_client->dev, &dev_attr_chassis_clear); @@ -674,9 +664,9 @@ static void adm9240_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(1), 255); i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_HIGH, 127); + ADM9240_REG_TEMP_MAX(0), 127); i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_HYST, 127); + ADM9240_REG_TEMP_MAX(1), 127); /* start measurement cycle */ i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); @@ -753,10 +743,10 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) data->fan_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN_MIN(i)); } - data->temp_high = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_HIGH); - data->temp_hyst = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_HYST); + data->temp_max[0] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(0)); + data->temp_max[1] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(1)); /* read fan divs and 5-bit VID */ i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); From 088341bd0c78143bf82ff21f7f0a715f99568c73 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 10 Sep 2005 23:00:46 +0200 Subject: [PATCH 1004/1939] [PATCH] hwmon: via686a: save 0.5k by long v[256] -> s16 v[256] We can save 0.5kB of data in the via686a driver. From: Denis Vlasenko Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/via686a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 05ddc88e7dd2..60e94879f415 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -198,7 +198,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) but the function is very linear in the useful range (0-80 deg C), so we'll just use linear interpolation for 10-bit readings.) So, tempLUT is the temp at via register values 0-255: */ -static const long tempLUT[] = +static const s16 tempLUT[] = { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, @@ -270,7 +270,7 @@ static inline u8 TEMP_TO_REG(long val) } /* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) +#define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100) /* for 10-bit temperature readings */ static inline long TEMP_FROM_REG10(u16 val) From e415e48b68155bea8b5452113dedba4ec486f3f6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:14:18 +0200 Subject: [PATCH 1005/1939] [PATCH] hwmon: adm9240 whitespace cleanups This whitespace cleanup patch removes one trailing space and breaks lines longer than 80 characters. Signed-off-by: Grant Coady Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/hwmon/adm9240.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) --- drivers/hwmon/adm9240.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 8bb6d6e45ed5..11dc95f8a17e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -219,8 +219,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *devattr, attr->index)); } -static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t show_in_min(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); @@ -228,8 +228,8 @@ static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, attr->index)); } -static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t show_in_max(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); @@ -237,7 +237,8 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, attr->index)); } -static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, +static ssize_t set_in_min(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -253,7 +254,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, +static ssize_t set_in_max(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -326,7 +328,7 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, "to %u\n", nr + 1, 1 << old, 1 << fan_div); } -/* +/* * set fan speed low limit: * * - value is zero: disable fan speed low limit alarm @@ -404,7 +406,8 @@ fan(1); fan(2); /* alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -412,7 +415,8 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* vid */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -420,13 +424,16 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* analog output */ -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_aout(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_aout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); @@ -441,7 +448,9 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); /* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t chassis_clear(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtol(buf, NULL, 10); From b918ecd2429e1a89b846d9e49ca4520b963c13e8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:18:49 +0200 Subject: [PATCH 1006/1939] [PATCH] hwmon: Do not forcibly enable via686a by default Do not enable the VIA VT82C686A/B integrated sensors by default, as disabled sensors usually means that this feature is not used so the values won't make any sense. This has been confusing many users in the past: http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1786 http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1811 http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=2052 It is still possible to forcibly enable the sensors by using the force_addr module parameter. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Documentation/hwmon/via686a | 17 +++++++++++++++-- drivers/hwmon/via686a.c | 18 +++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) --- Documentation/hwmon/via686a | 17 +++++++++++++++-- drivers/hwmon/via686a.c | 18 +++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/via686a b/Documentation/hwmon/via686a index b82014cb7c53..a936fb3824b2 100644 --- a/Documentation/hwmon/via686a +++ b/Documentation/hwmon/via686a @@ -18,8 +18,9 @@ Authors: Module Parameters ----------------- -force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards - that don't set the address in the BIOS. Does not do a +force_addr=0xaddr Set the I/O base address. Useful for boards that + don't set the address in the BIOS. Look for a BIOS + upgrade before resorting to this. Does not do a PCI force; the via686a must still be present in lspci. Don't use this unless the driver complains that the base address is not set. @@ -63,3 +64,15 @@ miss once-only alarms. The driver only updates its values each 1.5 seconds; reading it more often will do no harm, but will return 'old' values. + +Known Issues +------------ + +This driver handles sensors integrated in some VIA south bridges. It is +possible that a motherboard maker used a VT82C686A/B chip as part of a +product design but was not interested in its hardware monitoring features, +in which case the sensor inputs will not be wired. This is the case of +the Asus K7V, A7V and A7V133 motherboards, to name only a few of them. +So, if you need the force_addr parameter, and end up with values which +don't seem to make any sense, don't look any further: your chip is simply +not wired for hardware monitoring. diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 60e94879f415..688ccf924c3a 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -589,10 +589,8 @@ static int via686a_detect(struct i2c_adapter *adapter) u16 val; /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if (force_addr) - address = force_addr & 0xFF00; - if (force_addr) { + address = force_addr & 0xFF00; dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); if (PCIBIOS_SUCCESSFUL != @@ -603,11 +601,17 @@ static int via686a_detect(struct i2c_adapter *adapter) pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) return -ENODEV; if (!(val & 0x0001)) { - dev_warn(&adapter->dev, "enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) + if (force_addr) { + dev_info(&adapter->dev, "enabling sensors\n"); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, + val | 0x0001)) + return -ENODEV; + } else { + dev_warn(&adapter->dev, "sensors disabled - enable " + "with force_addr=0x%x\n", address); return -ENODEV; + } } /* Reserve the ISA region */ From 605070952f0b41caaa211c47b02eeac703529008 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:23:07 +0200 Subject: [PATCH 1007/1939] [PATCH] i2c: Discard explicit static initializations to 0 Kill explicit static initializations to 0 in 10 i2c drivers. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/algos/i2c-algo-pca.c | 2 +- drivers/i2c/algos/i2c-algo-sibyte.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 4 ++-- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 8 ++++---- drivers/i2c/busses/i2c-sis5595.c | 4 ++-- drivers/i2c/busses/i2c-sis630.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) --- drivers/i2c/algos/i2c-algo-pca.c | 2 +- drivers/i2c/algos/i2c-algo-sibyte.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 4 ++-- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 8 ++++---- drivers/i2c/busses/i2c-sis5595.c | 4 ++-- drivers/i2c/busses/i2c-sis630.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index beb10edfe9c1..82946acab4c7 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -34,7 +34,7 @@ #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) #define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0) -static int i2c_debug=0; +static int i2c_debug; #define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) #define pca_inw(adap, reg) adap->read_byte(adap, reg) diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 8ed5ad12552f..938848ae162d 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c @@ -42,7 +42,7 @@ /* module parameters: */ -static int bit_scan=0; /* have a look at what's hanging 'round */ +static int bit_scan; /* have a look at what's hanging 'round */ static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index b3f50bff39a0..e13d60c120b9 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -125,12 +125,12 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static u16 force_addr = 0; +static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -static unsigned short ali15x3_smba = 0; +static unsigned short ali15x3_smba; static int ali15x3_setup(struct pci_dev *ALI15X3_dev) { diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 6ad0603384b8..3bbac2f8ce38 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -86,7 +86,7 @@ #define AMD756_BLOCK_DATA 0x05 -static unsigned short amd756_ioport = 0; +static unsigned short amd756_ioport; /* SMBUS event = I/O 28-29 bit 11 diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 7bd9102db701..745e3a51f3e5 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -43,7 +43,7 @@ #include "i2c-iop3xx.h" /* global unit counter */ -static int i2c_id = 0; +static int i2c_id; static inline unsigned char iic_cook_addr(struct i2c_msg *msg) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d48a4da7bed..1b2d3ebd1075 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -90,13 +90,13 @@ struct sd { /* If force is set to anything different from 0, we forcibly enable the PIIX4. DANGEROUS! */ -static int force = 0; +static int force; module_param (force, int, 0); MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!"); /* If force_addr is set to anything different from 0, we forcibly enable the PIIX4 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; +static int force_addr; module_param (force_addr, int, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the PIIX4 at the given address. " @@ -104,14 +104,14 @@ MODULE_PARM_DESC(force_addr, /* If fix_hstcfg is set to anything different from 0, we reset one of the registers to be a valid value. */ -static int fix_hstcfg = 0; +static int fix_hstcfg; module_param (fix_hstcfg, int, 0); MODULE_PARM_DESC(fix_hstcfg, "Fix config register. Needed on some boards (Force CPCI735)."); static int piix4_transaction(void); -static unsigned short piix4_smba = 0; +static unsigned short piix4_smba; static struct i2c_adapter piix4_adapter; static struct dmi_system_id __devinitdata piix4_dmi_table[] = { diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 080318d6f54b..3fd38f4673e3 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -123,11 +123,11 @@ static int blacklist[] = { /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static u16 force_addr = 0; +static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -static unsigned short sis5595_base = 0; +static unsigned short sis5595_base; static u8 sis5595_read(u8 reg) { diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 86f0f448fa0b..44c4e68e9a98 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -101,7 +101,7 @@ module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); /* acpi base address */ -static unsigned short acpi_base = 0; +static unsigned short acpi_base; /* supported chips */ static int supported[] = { diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index ead2ff3cf60e..9ddd910c3b99 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -83,7 +83,7 @@ #define SIS96x_BLOCK_DATA 0x05 static struct i2c_adapter sis96x_adapter; -static u16 sis96x_smbus_base = 0; +static u16 sis96x_smbus_base; static inline u8 sis96x_read(u8 reg) { diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 040b8abeabba..0b3edd4e6c12 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -45,7 +45,7 @@ #define IOSPACE 0x06 #define IOTEXT "via-i2c" -static u16 pm_io_base = 0; +static u16 pm_io_base; /* It does not appear from the datasheet that the GPIO pins are From 0200296310a454b39efc995e676f9ff60e641edb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:26:44 +0200 Subject: [PATCH 1008/1939] [PATCH] hwmon: Discard explicit static initializations to 0 Kill explicit static initializations to 0 in 2 hwmon drivers. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/hwmon/adm1021.c | 2 +- drivers/hwmon/via686a.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) --- drivers/hwmon/adm1021.c | 2 +- drivers/hwmon/via686a.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index e928cdb041cb..58aee3a00caa 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -121,7 +121,7 @@ static int adm1021_write_value(struct i2c_client *client, u8 reg, static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; +static int read_only; /* This is the driver that will be inserted */ diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 688ccf924c3a..54861f13fee2 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -44,7 +44,7 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static unsigned short force_addr = 0; +static unsigned short force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); From 7d845b10d06fa20a595a5161edabc5e846ed28a6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:29:38 +0200 Subject: [PATCH 1009/1939] [PATCH] hwmon: Discard bogus comment about init setting limits Discard a common out-of-date comment in 5 hardware monitoring drivers. The hardware monitoring chip drivers are no more setting sensor limits at initialization time, for quite some time already. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/hwmon/lm78.c | 1 - drivers/hwmon/via686a.c | 1 - drivers/hwmon/w83627hf.c | 1 - drivers/hwmon/w83781d.c | 1 - drivers/hwmon/w83792d.c | 1 - 5 files changed, 5 deletions(-) --- drivers/hwmon/lm78.c | 1 - drivers/hwmon/via686a.c | 1 - drivers/hwmon/w83627hf.c | 1 - drivers/hwmon/w83781d.c | 1 - drivers/hwmon/w83792d.c | 1 - 5 files changed, 5 deletions(-) diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index f6730dc3573b..d697a554286f 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -726,7 +726,6 @@ static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -/* Called when we have found a new LM78. It should set limits, etc. */ static void lm78_init_client(struct i2c_client *client) { u8 config = lm78_read_value(client, LM78_REG_CONFIG); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 54861f13fee2..c6e64f4abdea 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -712,7 +712,6 @@ static int via686a_detach_client(struct i2c_client *client) return 0; } -/* Called when we have found a new VIA686A. Set limits, etc. */ static void via686a_init_client(struct i2c_client *client) { u8 reg; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 3479dc5208e2..7f6f7280878d 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1275,7 +1275,6 @@ static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) return 0; } -/* Called when we have found a new W83781D. It should set limits, etc. */ static void w83627hf_init_client(struct i2c_client *client) { struct w83627hf_data *data = i2c_get_clientdata(client); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 4c43337ca780..26b1fac7c619 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1451,7 +1451,6 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) return 0; } -/* Called when we have found a new W83781D. It should set limits, etc. */ static void w83781d_init_client(struct i2c_client *client) { diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index ba0c28015f6a..7bbd1888ce94 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1429,7 +1429,6 @@ w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) return 0; } -/* Called when we have found a new W83792D. It should set limits, etc. */ static void w83792d_init_client(struct i2c_client *client) { From d6072f842a77014220683ee5b781b7cee8f020d1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:37:04 +0200 Subject: [PATCH 1010/1939] [PATCH] i2c: Reuse name strings in i2c bus drivers Clean up name string usage in 12 i2c bus drivers: * Use the i2c_adapter name for requesting the I/O region rather than redefining a new string. * Do not initialize the i2c_adapter name to "unset". This should save a few data bytes here and there. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-ali1535.c | 6 +++--- drivers/i2c/busses/i2c-ali1563.c | 6 ++++-- drivers/i2c/busses/i2c-ali15x3.c | 5 +++-- drivers/i2c/busses/i2c-amd756.c | 5 ++--- drivers/i2c/busses/i2c-amd8111.c | 4 +++- drivers/i2c/busses/i2c-i801.c | 4 ++-- drivers/i2c/busses/i2c-nforce2.c | 4 ++-- drivers/i2c/busses/i2c-piix4.c | 4 ++-- drivers/i2c/busses/i2c-sis5595.c | 5 +++-- drivers/i2c/busses/i2c-sis630.c | 6 ++++-- drivers/i2c/busses/i2c-sis96x.c | 5 +++-- drivers/i2c/busses/i2c-via.c | 4 ++-- 12 files changed, 33 insertions(+), 25 deletions(-) --- drivers/i2c/busses/i2c-ali1535.c | 6 +++--- drivers/i2c/busses/i2c-ali1563.c | 6 ++++-- drivers/i2c/busses/i2c-ali15x3.c | 5 +++-- drivers/i2c/busses/i2c-amd756.c | 5 ++--- drivers/i2c/busses/i2c-amd8111.c | 4 +++- drivers/i2c/busses/i2c-i801.c | 4 ++-- drivers/i2c/busses/i2c-nforce2.c | 4 ++-- drivers/i2c/busses/i2c-piix4.c | 4 ++-- drivers/i2c/busses/i2c-sis5595.c | 5 +++-- drivers/i2c/busses/i2c-sis630.c | 6 ++++-- drivers/i2c/busses/i2c-sis96x.c | 5 +++-- drivers/i2c/busses/i2c-via.c | 4 ++-- 12 files changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index f021acd2674e..3eb47890db40 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -134,7 +134,7 @@ /* -> Read = 1 */ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ - +static struct pci_driver ali1535_driver; static unsigned short ali1535_smba; static DECLARE_MUTEX(i2c_ali1535_sem); @@ -162,7 +162,8 @@ static int ali1535_setup(struct pci_dev *dev) goto exit; } - if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, "ali1535-smb")) { + if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, + ali1535_driver.name)) { dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", ali1535_smba); goto exit; @@ -480,7 +481,6 @@ static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id ali1535_ids[] = { diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 86947504aea1..e6f63208fc4a 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -60,6 +60,7 @@ #define HST_CNTL2_SIZEMASK 0x38 +static struct pci_driver ali1563_pci_driver; static unsigned short ali1563_smba; static int ali1563_transaction(struct i2c_adapter * a, int size) @@ -350,7 +351,8 @@ static int __devinit ali1563_setup(struct pci_dev * dev) dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); goto Err; } - if (!request_region(ali1563_smba,ALI1563_SMB_IOSIZE,"i2c-ali1563")) { + if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, + ali1563_pci_driver.name)) { dev_warn(&dev->dev,"Could not allocate I/O space"); goto Err; } @@ -406,7 +408,7 @@ static struct pci_device_id __devinitdata ali1563_id_table[] = { MODULE_DEVICE_TABLE (pci, ali1563_id_table); static struct pci_driver ali1563_pci_driver = { - .name = "ali1563_i2c", + .name = "ali1563_smbus", .id_table = ali1563_id_table, .probe = ali1563_probe, .remove = __devexit_p(ali1563_remove), diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index e13d60c120b9..7a5c0941dbc1 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -130,6 +130,7 @@ module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); +static struct pci_driver ali15x3_driver; static unsigned short ali15x3_smba; static int ali15x3_setup(struct pci_dev *ALI15X3_dev) @@ -166,7 +167,8 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev) if(force_addr) ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); - if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) { + if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, + ali15x3_driver.name)) { dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region 0x%x already in use!\n", ali15x3_smba); @@ -470,7 +472,6 @@ static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id ali15x3_ids[] = { diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 3bbac2f8ce38..1750dedaf4b5 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -85,7 +85,7 @@ #define AMD756_PROCESS_CALL 0x04 #define AMD756_BLOCK_DATA 0x05 - +static struct pci_driver amd756_driver; static unsigned short amd756_ioport; /* @@ -303,7 +303,6 @@ struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 }; @@ -365,7 +364,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev, amd756_ioport += SMB_ADDR_OFFSET; } - if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { + if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) { dev_err(&pdev->dev, "SMB region 0x%x already in use!\n", amd756_ioport); return -ENODEV; diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 45ea24ba14d5..49ff11e5134f 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -30,6 +30,8 @@ struct amd_smbus { int size; }; +static struct pci_driver amd8111_driver; + /* * AMD PCI control registers definitions. */ @@ -352,7 +354,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ smbus->base = pci_resource_start(dev, 0); smbus->size = pci_resource_len(dev, 0); - if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) + if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) goto out_kfree; smbus->adapter.owner = THIS_MODULE; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 709beab76609..588583530c9f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -110,6 +110,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, int command); static unsigned short i801_smba; +static struct pci_driver i801_driver; static struct pci_dev *I801_dev; static int isich4; @@ -143,7 +144,7 @@ static int i801_setup(struct pci_dev *dev) } } - if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) { + if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) { dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n", i801_smba); error_return = -EBUSY; @@ -543,7 +544,6 @@ static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id i801_ids[] = { diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index fe9c0f42a2b7..dd4b6d8e03ef 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -97,6 +97,7 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a #define NVIDIA_SMB_PRTCL_PEC 0x80 +static struct pci_driver nforce2_driver; static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, @@ -113,7 +114,6 @@ static struct i2c_adapter nforce2_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; /* Return -1 on error. See smbus.h for more information */ @@ -285,7 +285,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, smbus->base = iobase & 0xfffc; smbus->size = 8; - if (!request_region(smbus->base, smbus->size, "nForce2 SMBus")) { + if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name); return -1; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 1b2d3ebd1075..692f47345481 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -112,6 +112,7 @@ MODULE_PARM_DESC(fix_hstcfg, static int piix4_transaction(void); static unsigned short piix4_smba; +static struct pci_driver piix4_driver; static struct i2c_adapter piix4_adapter; static struct dmi_system_id __devinitdata piix4_dmi_table[] = { @@ -157,7 +158,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, } } - if (!request_region(piix4_smba, SMBIOSIZE, "piix4-smbus")) { + if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", piix4_smba); return -ENODEV; @@ -407,7 +408,6 @@ static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id piix4_ids[] = { diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 3fd38f4673e3..b57ab74d23ec 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -127,6 +127,7 @@ static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); +static struct pci_driver sis5595_driver; static unsigned short sis5595_base; static u8 sis5595_read(u8 reg) @@ -172,7 +173,8 @@ static int sis5595_setup(struct pci_dev *SIS5595_dev) /* NB: We grab just the two SMBus registers here, but this may still * interfere with ACPI :-( */ - if (!request_region(sis5595_base + SMB_INDEX, 2, "sis5595-smbus")) { + if (!request_region(sis5595_base + SMB_INDEX, 2, + sis5595_driver.name)) { dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n", sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1); return -ENODEV; @@ -364,7 +366,6 @@ static struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, - .name = "unset", .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 44c4e68e9a98..acb75e282414 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -92,6 +92,8 @@ #define SIS630_PCALL 0x04 #define SIS630_BLOCK_DATA 0x05 +static struct pci_driver sis630_driver; + /* insmod parameters */ static int high_clock; static int force; @@ -432,7 +434,8 @@ static int sis630_setup(struct pci_dev *sis630_dev) dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base); /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, "sis630-smbus")) { + if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, + sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); goto exit; @@ -455,7 +458,6 @@ static struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, - .name = "unset", .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 9ddd910c3b99..3024907cdafe 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -82,6 +82,7 @@ #define SIS96x_PROC_CALL 0x04 #define SIS96x_BLOCK_DATA 0x05 +static struct pci_driver sis96x_driver; static struct i2c_adapter sis96x_adapter; static u16 sis96x_smbus_base; @@ -257,7 +258,6 @@ static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id sis96x_ids[] = { @@ -294,7 +294,8 @@ static int __devinit sis96x_probe(struct pci_dev *dev, sis96x_smbus_base); /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(sis96x_smbus_base, SMB_IOSIZE, "sis96x-smbus")) { + if (!request_region(sis96x_smbus_base, SMB_IOSIZE, + sis96x_driver.name)) { dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x " "already in use!\n", sis96x_smbus_base, sis96x_smbus_base + SMB_IOSIZE - 1); diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 0b3edd4e6c12..484bbacfce6b 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -43,8 +43,8 @@ /* io-region reservation */ #define IOSPACE 0x06 -#define IOTEXT "via-i2c" +static struct pci_driver vt586b_driver; static u16 pm_io_base; /* @@ -130,7 +130,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i pci_read_config_word(dev, base, &pm_io_base); pm_io_base &= (0xff << 8); - if (!request_region(I2C_DIR, IOSPACE, IOTEXT)) { + if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) { dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE); return -ENODEV; } From 709439a284bc5b7d42a70fee7119feb186c1ca99 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:41:18 +0200 Subject: [PATCH 1011/1939] [PATCH] hwmon: w83l785ts converted to dynamic sysfs callbacks Convert the w83l785ts driver to use dynamic sysfs callbacks. This is a small driver so the benefit is thin, but still worth it. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/hwmon/w83l785ts.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) --- drivers/hwmon/w83l785ts.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 133e34ab1d0a..fcb2c39b04fd 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* How many retries on register read error */ @@ -111,27 +112,24 @@ struct w83l785ts_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 temp, temp_over; + u8 temp[2]; /* 0: input + 1: critical limit */ }; /* * Sysfs stuff */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1); /* * Real code @@ -228,7 +226,7 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) init_MUTEX(&data->update_lock); /* Default values in case the first read fails (unlikely). */ - data->temp_over = data->temp = 0; + data->temp[1] = data->temp[0] = 0; /* Tell the I2C layer a new client has arrived. */ if ((err = i2c_attach_client(new_client))) @@ -246,8 +244,10 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); return 0; @@ -305,10 +305,10 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { dev_dbg(&client->dev, "Updating w83l785ts data.\n"); - data->temp = w83l785ts_read_value(client, - W83L785TS_REG_TEMP, data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); + data->temp[0] = w83l785ts_read_value(client, + W83L785TS_REG_TEMP, data->temp[0]); + data->temp[1] = w83l785ts_read_value(client, + W83L785TS_REG_TEMP_OVER, data->temp[1]); data->last_updated = jiffies; data->valid = 1; From cb929eae78ec0b243dbf58039bce4af354f6020c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:45:03 +0200 Subject: [PATCH 1012/1939] [PATCH] hwmon: Minor w83l785ts optimization Using s8 instead of u8 to store temperature register values saves a few instructions on sysfs file read. The very same was done for several other drivers a while ago (lm63, lm83, lm90...) Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/hwmon/w83l785ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- drivers/hwmon/w83l785ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index fcb2c39b04fd..db12a620b331 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -74,7 +74,7 @@ I2C_CLIENT_INSMOD_1(w83l785ts); * The W83L785TS-S uses signed 8-bit values. */ -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) +#define TEMP_FROM_REG(val) ((val) * 1000) /* * Functions declaration @@ -112,7 +112,7 @@ struct w83l785ts_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 temp[2]; /* 0: input + s8 temp[2]; /* 0: input 1: critical limit */ }; From 4366dc946c01305cff49b07dabb806d2364f1edb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:50:06 +0200 Subject: [PATCH 1013/1939] [PATCH] i2c: Adjust i2c_probe() for busses without SMBUS_QUICK Move the check for SMBUS_QUICK in i2c_probe() after the forced addresses have been handled. This makes it possible for a driver to leave the probed address lists empty, only providing forced addresses, and get i2c_probe to work even if the bus doesn't support SMBUS_QUICK. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/i2c-core.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) --- drivers/i2c/i2c-core.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 45aa0e54e297..b55097d57b7a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -706,10 +706,6 @@ int i2c_probe(struct i2c_adapter *adapter, int i, err; int adap_id = i2c_adapter_id(adapter); - /* Forget it if we can't probe using SMBUS_QUICK */ - if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) - return -1; - /* Force entries are done first, and are not affected by ignore entries */ if (address_data->forces) { @@ -736,6 +732,17 @@ int i2c_probe(struct i2c_adapter *adapter, } } + /* Stop here if we can't use SMBUS_QUICK */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { + if (address_data->probe[0] == I2C_CLIENT_END + && address_data->normal_i2c[0] == I2C_CLIENT_END) + return 0; + + dev_warn(&adapter->dev, "SMBus Quick command not supported, " + "can't probe for chips\n"); + return -1; + } + /* Probe entries are done second, and are not affected by ignore entries either */ for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { From d057c96cab72bc6b70570d25b90404f81d98e886 Mon Sep 17 00:00:00 2001 From: Hideki Iwamoto Date: Sun, 25 Sep 2005 16:53:04 +0200 Subject: [PATCH 1014/1939] [PATCH] i2c: Fix I2C_FUNC_PROTOCOL_MANGLING documentation Fix the description of I2C_FUNC_PROTOCOL_MANGLING. From: Hideki Iwamoto Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Documentation/i2c/functionality | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) --- Documentation/i2c/functionality | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality index 41ffefbdc60c..60cca249e452 100644 --- a/Documentation/i2c/functionality +++ b/Documentation/i2c/functionality @@ -17,9 +17,10 @@ For the most up-to-date list of functionality constants, please check I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus adapters typically can not do these) I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions - I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_REV_DIR_ADDR, - I2C_M_REV_DIR_ADDR and I2C_M_REV_DIR_NOSTART - flags (which modify the i2c protocol!) + I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_IGNORE_NAK, + I2C_M_REV_DIR_ADDR, I2C_M_NOSTART and + I2C_M_NO_RD_ACK flags (which modify the + I2C protocol!) I2C_FUNC_SMBUS_QUICK Handles the SMBus write_quick command I2C_FUNC_SMBUS_READ_BYTE Handles the SMBus read_byte command I2C_FUNC_SMBUS_WRITE_BYTE Handles the SMBus write_byte command From 332bf92b3338e140cbcfc25f69911e8ca59788c7 Mon Sep 17 00:00:00 2001 From: Hideki Iwamoto Date: Sun, 25 Sep 2005 16:56:43 +0200 Subject: [PATCH 1015/1939] [PATCH] i2c: Fix union i2c_smbus_data definition The i2c_smbus_data union block member has a comment stating that an extra byte is required for SMBus Block Process Call transactions. This has been true for three weeks around June 2002, but no more since, so it is about time that we drop this comment and fix the definition. From: Hideki Iwamoto Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman include/linux/i2c.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) --- include/linux/i2c.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 3d49a305bf88..17d63c1efdce 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -454,8 +454,7 @@ struct i2c_msg { union i2c_smbus_data { __u8 byte; __u16 word; - __u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */ - /* one more for read length in block process call */ + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ /* and one more for PEC */ }; From 0f69a612f950f7508e556bf1b09390087d112115 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 25 Sep 2005 16:58:22 +0200 Subject: [PATCH 1016/1939] [PATCH] i2c: Minor i2c-amd8111 cleanup I noticed a useless instruction in the i2c-amd8111 driver. Signed-off-by: Jean Delvare CC: Vojtech Pavlik Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-amd8111.c | 1 - 1 file changed, 1 deletion(-) --- drivers/i2c/busses/i2c-amd8111.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 49ff11e5134f..6200c9a087ad 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -244,7 +244,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl break; case I2C_SMBUS_BLOCK_PROC_CALL: - protocol |= pec; len = min_t(u8, data->block[0], 31); amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); From 5c50d1885981537ff3b8df6433951de6c9cb72cb Mon Sep 17 00:00:00 2001 From: Hideki Iwamoto Date: Sun, 25 Sep 2005 17:01:11 +0200 Subject: [PATCH 1017/1939] [PATCH] i2c: Several PEC-related fixes in software SMBus emulation Fix several errors in I2C SMBus emulation when PEC is used: * Weird logic error in SMBus Write Word transactions. * Wrong buffer size, affecting SMBus Block Write transactions. * Potential buffer overrun in SMBus Block Write transactions. From: Hideki Iwamoto Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/i2c-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) --- drivers/i2c/i2c-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b55097d57b7a..9583a54ce16b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -864,7 +864,7 @@ static int i2c_smbus_add_pec(u16 addr, u8 command, int size, break; case I2C_SMBUS_BYTE_DATA: buf[2] = data->byte; - data->word = buf[2] || + data->word = buf[2] | (i2c_smbus_pec(3, buf, NULL) << 8); size = I2C_SMBUS_WORD_DATA; break; @@ -1033,8 +1033,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ - unsigned char msgbuf0[34]; - unsigned char msgbuf1[34]; + unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; + unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } @@ -1097,7 +1097,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } if(size == I2C_SMBUS_BLOCK_DATA_PEC) (msg[0].len)++; - for (i = 1; i <= msg[0].len; i++) + for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; From 32c0a520f506c046f241de2a3a9b02a395ef76d2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 21:47:58 +0200 Subject: [PATCH 1018/1939] [PATCH] i2c-viapro: New maintainer I am taking over the maintenance of the i2c-viapro SMBus driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 248b93b32fc4..3928dc7d6ea9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2736,6 +2736,12 @@ P: Roger Luethi M: rl@hellgate.ch S: Maintained +VIAPRO SMBUS DRIVER +P: Jean Delvare +M: khali@linux-fr.org +L: lm-sensors@lm-sensors.org +S: Maintained + UCLINUX (AND M68KNOMMU) P: Greg Ungerer M: gerg@uclinux.org From 5f49ef8e8cefe0a95948b4270db28507c1c287d4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 21:50:47 +0200 Subject: [PATCH 1019/1939] [PATCH] i2c-viapro: Coding style fixes Before I go on cleaning up and improving the i2c-viapro driver, let's fix all the coding style issues: mostly trailing white space, and spaces used where tabs should be. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Documentation/i2c/busses/i2c-viapro | 12 ++--- drivers/i2c/busses/i2c-viapro.c | 76 ++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 45 deletions(-) --- Documentation/i2c/busses/i2c-viapro | 12 ++--- drivers/i2c/busses/i2c-viapro.c | 76 ++++++++++++++--------------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 702f5ac68c09..ef0f1e94e726 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -4,17 +4,17 @@ Supported adapters: * VIA Technologies, Inc. VT82C596A/B Datasheet: Sometimes available at the VIA website - * VIA Technologies, Inc. VT82C686A/B + * VIA Technologies, Inc. VT82C686A/B Datasheet: Sometimes available at the VIA website * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237 Datasheet: available on request from Via Authors: - Frodo Looijaard , - Philip Edelbrock , - Kyösti Mälkki , - Mark D. Studebaker + Frodo Looijaard , + Philip Edelbrock , + Kyösti Mälkki , + Mark D. Studebaker Module Parameters ----------------- @@ -43,5 +43,3 @@ Your lspci -n listing must show one of these : If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. - - diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 99d209e0485a..262755e1ae02 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -1,7 +1,7 @@ /* i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (c) 1998 - 2002 Frodo Looijaard , + Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , Mark D. Studebaker @@ -46,9 +46,9 @@ static struct pci_dev *vt596_pdev; -#define SMBBA1 0x90 -#define SMBBA2 0x80 -#define SMBBA3 0xD0 +#define SMBBA1 0x90 +#define SMBBA2 0x80 +#define SMBBA3 0xD0 /* SMBus address offsets */ static unsigned short vt596_smba; @@ -68,26 +68,26 @@ static unsigned short vt596_smba; /* PCI Address Constants */ /* SMBus data in configuration space can be found in two places, - We try to select the better one*/ + We try to select the better one */ static unsigned short smb_cf_hstcfg = 0xD2; -#define SMBHSTCFG (smb_cf_hstcfg) -#define SMBSLVC (smb_cf_hstcfg + 1) -#define SMBSHDW1 (smb_cf_hstcfg + 2) -#define SMBSHDW2 (smb_cf_hstcfg + 3) -#define SMBREV (smb_cf_hstcfg + 4) +#define SMBHSTCFG (smb_cf_hstcfg) +#define SMBSLVC (smb_cf_hstcfg + 1) +#define SMBSHDW1 (smb_cf_hstcfg + 2) +#define SMBSHDW2 (smb_cf_hstcfg + 3) +#define SMBREV (smb_cf_hstcfg + 4) /* Other settings */ #define MAX_TIMEOUT 500 #define ENABLE_INT9 0 /* VT82C596 constants */ -#define VT596_QUICK 0x00 -#define VT596_BYTE 0x04 -#define VT596_BYTE_DATA 0x08 -#define VT596_WORD_DATA 0x0C -#define VT596_BLOCK_DATA 0x14 +#define VT596_QUICK 0x00 +#define VT596_BYTE 0x04 +#define VT596_BYTE_DATA 0x08 +#define VT596_WORD_DATA 0x0C +#define VT596_BLOCK_DATA 0x14 /* If force is set to anything different from 0, we forcibly enable the @@ -115,19 +115,19 @@ static int vt596_transaction(void) int timeout = 0; dev_dbg(&vt596_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). " - "Resetting...\n", temp); - + "Resetting...\n", temp); + outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { dev_dbg(&vt596_adapter.dev, "Failed! (0x%02x)\n", temp); - + return -1; } else { dev_dbg(&vt596_adapter.dev, "Successfull!\n"); @@ -137,7 +137,7 @@ static int vt596_transaction(void) /* start the transaction by setting bit 6 */ outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); - /* We will always wait for a fraction of a second! + /* We will always wait for a fraction of a second! I don't know if VIA needs this, Intel did */ do { msleep(1); @@ -177,16 +177,16 @@ static int vt596_transaction(void) dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); - + return result; } /* Return -1 on error. */ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data *data) + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) { int i, len; @@ -256,7 +256,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, case VT596_BYTE: /* Where is the result put? I assume here it is in * SMBHSTDAT0 but it might just as well be in the - * SMBHSTCMD. No clue in the docs + * SMBHSTCMD. No clue in the docs */ data->byte = inb_p(SMBHSTDAT0); break; @@ -302,7 +302,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, { unsigned char temp; int error = -ENODEV; - + /* Determine the address of the SMBus areas */ if (force_addr) { vt596_smba = force_addr & 0xfff0; @@ -333,10 +333,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev, return -ENODEV; } - found: +found: if (!request_region(vt596_smba, 8, "viapro-smbus")) { dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n", - vt596_smba); + vt596_smba); return -ENODEV; } @@ -348,13 +348,13 @@ static int __devinit vt596_probe(struct pci_dev *pdev, pci_write_config_word(pdev, id->driver_data, vt596_smba); pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_warn(&pdev->dev, "WARNING: SMBus interface set to new " - "address 0x%04x!\n", vt596_smba); + "address 0x%04x!\n", vt596_smba); } else if ((temp & 1) == 0) { if (force) { - /* NOTE: This assumes I/O space and other allocations - * WERE done by the Bios! Don't complain if your - * hardware does weird things after enabling this. - * :') Check for Bios updates before resorting to + /* NOTE: This assumes I/O space and other allocations + * WERE done by the Bios! Don't complain if your + * hardware does weird things after enabling this. + * :') Check for Bios updates before resorting to * this. */ pci_write_config_byte(pdev, SMBHSTCFG, temp | 1); @@ -381,8 +381,8 @@ static int __devinit vt596_probe(struct pci_dev *pdev, vt596_adapter.dev.parent = &pdev->dev; snprintf(vt596_adapter.name, I2C_NAME_SIZE, - "SMBus Via Pro adapter at %04x", vt596_smba); - + "SMBus Via Pro adapter at %04x", vt596_smba); + vt596_pdev = pci_dev_get(pdev); if (i2c_add_adapter(&vt596_adapter)) { pci_dev_put(vt596_pdev); @@ -395,7 +395,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, */ return -ENODEV; - release_region: +release_region: release_region(vt596_smba, 8); return error; } @@ -420,7 +420,7 @@ static struct pci_device_id vt596_ids[] = { { 0, } }; -MODULE_DEVICE_TABLE (pci, vt596_ids); +MODULE_DEVICE_TABLE(pci, vt596_ids); static struct pci_driver vt596_driver = { .name = "vt596_smbus", From f118301416953d677de738100c33eb8cfb7adecb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 21:58:41 +0200 Subject: [PATCH 1020/1939] [PATCH] i2c-viapro: Implement I2C Block transactions Implement the I2C block transactions on VIA chips which support them: VT82C686B, VT8233, VT8233A, VT8235 and VT8237R. This speeds up EEPROM accesses by a factor 10 or so. I would like to thank Antonino A. Daplas, Hinko Kocevar, Salah Coronya and Andreas Henriksson for their help in testing this new feature. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Documentation/i2c/busses/i2c-viapro | 7 +++++- drivers/i2c/busses/i2c-viapro.c | 39 +++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) --- Documentation/i2c/busses/i2c-viapro | 7 +++++- drivers/i2c/busses/i2c-viapro.c | 39 ++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index ef0f1e94e726..387cbd4015fc 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -14,7 +14,8 @@ Authors: Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , - Mark D. Studebaker + Mark D. Studebaker , + Jean Delvare Module Parameters ----------------- @@ -43,3 +44,7 @@ Your lspci -n listing must show one of these : If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. + +Except for the oldest chips (VT82C596A/B, VT82C686A and most probably +VT8231), this driver supports I2C block transactions. Such transactions +are mainly useful to read from and write to EEPROMs. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 262755e1ae02..b420e752b1dc 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -4,6 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , Mark D. Studebaker + Copyright (C) 2005 Jean Delvare 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 @@ -88,6 +89,7 @@ static unsigned short smb_cf_hstcfg = 0xD2; #define VT596_BYTE_DATA 0x08 #define VT596_WORD_DATA 0x0C #define VT596_BLOCK_DATA 0x14 +#define VT596_I2C_BLOCK_DATA 0x34 /* If force is set to anything different from 0, we forcibly enable the @@ -107,6 +109,9 @@ MODULE_PARM_DESC(force_addr, static struct i2c_adapter vt596_adapter; +#define FEATURE_I2CBLOCK (1<<0) +static unsigned int vt596_features; + /* Another internally used function */ static int vt596_transaction(void) { @@ -225,6 +230,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, } size = VT596_WORD_DATA; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (!(vt596_features & FEATURE_I2CBLOCK)) + return -1; + if (read_write == I2C_SMBUS_READ) + outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); + /* Fall through */ case I2C_SMBUS_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); @@ -240,11 +251,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } - size = VT596_BLOCK_DATA; + size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ? + VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA; break; } - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); + outb_p((size & 0x3C) + (ENABLE_INT9 & 1), SMBHSTCNT); if (vt596_transaction()) /* Error in transaction */ return -1; @@ -266,6 +278,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, case VT596_WORD_DATA: data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; + case VT596_I2C_BLOCK_DATA: case VT596_BLOCK_DATA: data->block[0] = inb_p(SMBHSTDAT0); if (data->block[0] > I2C_SMBUS_BLOCK_MAX) @@ -280,9 +293,13 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, static u32 vt596_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; + + if (vt596_features & FEATURE_I2CBLOCK) + func |= I2C_FUNC_SMBUS_I2C_BLOCK; + return func; } static struct i2c_algorithm smbus_algorithm = { @@ -379,6 +396,22 @@ static int __devinit vt596_probe(struct pci_dev *pdev, dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_8237: + case PCI_DEVICE_ID_VIA_8235: + case PCI_DEVICE_ID_VIA_8233A: + case PCI_DEVICE_ID_VIA_8233_0: + vt596_features |= FEATURE_I2CBLOCK; + break; + case PCI_DEVICE_ID_VIA_82C686_4: + /* The VT82C686B (rev 0x40) does support I2C block + transactions, but the VT82C686A (rev 0x30) doesn't */ + if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp) + && temp >= 0x40) + vt596_features |= FEATURE_I2CBLOCK; + break; + } + vt596_adapter.dev.parent = &pdev->dev; snprintf(vt596_adapter.name, I2C_NAME_SIZE, "SMBus Via Pro adapter at %04x", vt596_smba); From c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 22:01:07 +0200 Subject: [PATCH 1021/1939] [PATCH] i2c-viapro: Code cleanups Cleanups to the i2c-viapro driver: * Kill unused defines. * Kill interrupt-related code, as the driver doesn't use interrupts. * Fix broken comments (some copied from i2c-piix4.) * Centralize the unsupported command error case in vt596_access. That way we'll catch all unsupported commands, not only I2C_SMBUS_PROC_CALL. * Refactor some code. * Convert some dev_dbg into dev_err. Errors better be reported even in non-debug mode. * Do not verify that the final reset succeeded. It'll be checked at the beginning of the next transaction anyway. * Use the driver name to reserve the I/O region. * Do not print the contents of the SMBREV register, it reads 0 on all chips I've seen so far. * Some other minor fixes all over the place. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-viapro.c | 122 +++++++++++++--------------------------- 1 file changed, 41 insertions(+), 81 deletions(-) --- drivers/i2c/busses/i2c-viapro.c | 122 +++++++++++--------------------- 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index b420e752b1dc..5cf8fe182806 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -54,34 +53,22 @@ static struct pci_dev *vt596_pdev; /* SMBus address offsets */ static unsigned short vt596_smba; #define SMBHSTSTS (vt596_smba + 0) -#define SMBHSLVSTS (vt596_smba + 1) #define SMBHSTCNT (vt596_smba + 2) #define SMBHSTCMD (vt596_smba + 3) #define SMBHSTADD (vt596_smba + 4) #define SMBHSTDAT0 (vt596_smba + 5) #define SMBHSTDAT1 (vt596_smba + 6) #define SMBBLKDAT (vt596_smba + 7) -#define SMBSLVCNT (vt596_smba + 8) -#define SMBSHDWCMD (vt596_smba + 9) -#define SMBSLVEVT (vt596_smba + 0xA) -#define SMBSLVDAT (vt596_smba + 0xC) /* PCI Address Constants */ /* SMBus data in configuration space can be found in two places, We try to select the better one */ -static unsigned short smb_cf_hstcfg = 0xD2; - -#define SMBHSTCFG (smb_cf_hstcfg) -#define SMBSLVC (smb_cf_hstcfg + 1) -#define SMBSHDW1 (smb_cf_hstcfg + 2) -#define SMBSHDW2 (smb_cf_hstcfg + 3) -#define SMBREV (smb_cf_hstcfg + 4) +static unsigned short SMBHSTCFG = 0xD2; /* Other settings */ #define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 /* VT82C596 constants */ #define VT596_QUICK 0x00 @@ -107,12 +94,13 @@ MODULE_PARM_DESC(force_addr, "EXTREMELY DANGEROUS!"); +static struct pci_driver vt596_driver; static struct i2c_adapter vt596_adapter; #define FEATURE_I2CBLOCK (1<<0) static unsigned int vt596_features; -/* Another internally used function */ +/* Return -1 on error, 0 on success */ static int vt596_transaction(void) { int temp; @@ -127,23 +115,21 @@ static int vt596_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). " - "Resetting...\n", temp); + "Resetting... ", temp); outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_dbg(&vt596_adapter.dev, "Failed! (0x%02x)\n", temp); - + printk("Failed! (0x%02x)\n", temp); return -1; } else { - dev_dbg(&vt596_adapter.dev, "Successfull!\n"); + printk("Successful!\n"); } } - /* start the transaction by setting bit 6 */ - outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); + /* Start the transaction by setting bit 6 */ + outb_p(inb(SMBHSTCNT) | 0x40, SMBHSTCNT); - /* We will always wait for a fraction of a second! - I don't know if VIA needs this, Intel did */ + /* We will always wait for a fraction of a second */ do { msleep(1); temp = inb_p(SMBHSTSTS); @@ -152,33 +138,32 @@ static int vt596_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; - dev_dbg(&vt596_adapter.dev, "SMBus Timeout!\n"); + dev_err(&vt596_adapter.dev, "SMBus timeout!\n"); } if (temp & 0x10) { result = -1; - dev_dbg(&vt596_adapter.dev, "Error: Failed bus transaction\n"); + dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n", + inb_p(SMBHSTCNT) & 0x3C); } if (temp & 0x08) { result = -1; - dev_info(&vt596_adapter.dev, "Bus collision! SMBus may be " - "locked until next hard\nreset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ + dev_err(&vt596_adapter.dev, "SMBus collision!\n"); } if (temp & 0x04) { result = -1; - dev_dbg(&vt596_adapter.dev, "Error: no response!\n"); + /* Quick commands are used to probe for chips, so + errors are expected, and we don't want to frighten the + user. */ + if ((inb_p(SMBHSTCNT) & 0x3C) != VT596_QUICK) + dev_err(&vt596_adapter.dev, "Transaction error!\n"); } - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { + /* Resetting status register */ + if (temp & 0x1F) outb_p(temp, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_warn(&vt596_adapter.dev, "Failed reset at end " - "of transaction (%02x)\n", temp); - } - } dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), @@ -188,41 +173,29 @@ static int vt596_transaction(void) return result; } -/* Return -1 on error. */ +/* Return -1 on error, 0 on success */ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { - int i, len; + int i; switch (size) { - case I2C_SMBUS_PROC_CALL: - dev_info(&vt596_adapter.dev, - "I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); size = VT596_QUICK; break; case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); if (read_write == I2C_SMBUS_WRITE) outb_p(command, SMBHSTCMD); size = VT596_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) outb_p(data->byte, SMBHSTDAT0); size = VT596_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { outb_p(data->word & 0xff, SMBHSTDAT0); @@ -232,31 +205,30 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: if (!(vt596_features & FEATURE_I2CBLOCK)) - return -1; + goto exit_unsupported; if (read_write == I2C_SMBUS_READ) outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); /* Fall through */ case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; + u8 len = data->block[0]; if (len > I2C_SMBUS_BLOCK_MAX) len = I2C_SMBUS_BLOCK_MAX; outb_p(len, SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ? VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA; break; + default: + goto exit_unsupported; } - outb_p((size & 0x3C) + (ENABLE_INT9 & 1), SMBHSTCNT); + outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD); + outb_p((size & 0x3C), SMBHSTCNT); if (vt596_transaction()) /* Error in transaction */ return -1; @@ -266,12 +238,6 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, switch (size) { case VT596_BYTE: - /* Where is the result put? I assume here it is in - * SMBHSTDAT0 but it might just as well be in the - * SMBHSTCMD. No clue in the docs - */ - data->byte = inb_p(SMBHSTDAT0); - break; case VT596_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; @@ -283,12 +249,17 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, data->block[0] = inb_p(SMBHSTDAT0); if (data->block[0] > I2C_SMBUS_BLOCK_MAX) data->block[0] = I2C_SMBUS_BLOCK_MAX; - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= data->block[0]; i++) data->block[i] = inb_p(SMBBLKDAT); break; } return 0; + +exit_unsupported: + dev_warn(&vt596_adapter.dev, "Unsupported command invoked! (0x%02x)\n", + size); + return -1; } static u32 vt596_func(struct i2c_adapter *adapter) @@ -311,7 +282,6 @@ static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static int __devinit vt596_probe(struct pci_dev *pdev, @@ -328,12 +298,12 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) || - !(vt596_smba & 0x1)) { + !(vt596_smba & 0x0001)) { /* try 2nd address and config reg. for 596 */ if (id->device == PCI_DEVICE_ID_VIA_82C596_3 && !pci_read_config_word(pdev, SMBBA2, &vt596_smba) && - (vt596_smba & 0x1)) { - smb_cf_hstcfg = 0x84; + (vt596_smba & 0x0001)) { + SMBHSTCFG = 0x84; } else { /* no matches at all */ dev_err(&pdev->dev, "Cannot configure " @@ -351,7 +321,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } found: - if (!request_region(vt596_smba, 8, "viapro-smbus")) { + if (!request_region(vt596_smba, 8, vt596_driver.name)) { dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n", vt596_smba); return -ENODEV; @@ -366,7 +336,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_warn(&pdev->dev, "WARNING: SMBus interface set to new " "address 0x%04x!\n", vt596_smba); - } else if ((temp & 1) == 0) { + } else if (!(temp & 0x01)) { if (force) { /* NOTE: This assumes I/O space and other allocations * WERE done by the Bios! Don't complain if your @@ -374,7 +344,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, * :') Check for Bios updates before resorting to * this. */ - pci_write_config_byte(pdev, SMBHSTCFG, temp | 1); + pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_info(&pdev->dev, "Enabling SMBus device\n"); } else { dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " @@ -384,16 +354,6 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } } - if ((temp & 0x0E) == 8) - dev_dbg(&pdev->dev, "using Interrupt 9 for SMBus.\n"); - else if ((temp & 0x0E) == 0) - dev_dbg(&pdev->dev, "using Interrupt SMI# for SMBus.\n"); - else - dev_dbg(&pdev->dev, "Illegal Interrupt configuration " - "(or code out of date)!\n"); - - pci_read_config_byte(pdev, SMBREV, &temp); - dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); switch (pdev->device) { From aaf7f1477668f34dda65aba17e87c0bc2ebe84d1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 22:09:07 +0200 Subject: [PATCH 1022/1939] [PATCH] i2c-viapro: Update supported devices list Make it clearer which chips are supported by the i2c-viapro driver, and which support I2C block transactions. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Documentation/i2c/busses/i2c-viapro | 12 ++++++------ drivers/i2c/busses/i2c-viapro.c | 22 +++++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) --- Documentation/i2c/busses/i2c-viapro | 12 ++++++------ drivers/i2c/busses/i2c-viapro.c | 22 +++++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 387cbd4015fc..9363b8bd6109 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -29,18 +29,18 @@ Description ----------- i2c-viapro is a true SMBus host driver for motherboards with one of the -supported VIA southbridges. +supported VIA south bridges. Your lspci -n listing must show one of these : - device 1106:3050 (VT82C596 function 3) - device 1106:3051 (VT82C596 function 3) + device 1106:3050 (VT82C596A function 3) + device 1106:3051 (VT82C596B function 3) device 1106:3057 (VT82C686 function 4) device 1106:3074 (VT8233) device 1106:3147 (VT8233A) - device 1106:8235 (VT8231) - devide 1106:3177 (VT8235) - devide 1106:3227 (VT8237) + device 1106:8235 (VT8231 function 4) + device 1106:3177 (VT8235) + device 1106:3227 (VT8237R) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 5cf8fe182806..3be476cd4bc5 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -22,15 +22,19 @@ */ /* - Supports Via devices: - 82C596A/B (0x3050) - 82C596B (0x3051) - 82C686A/B - 8231 - 8233 - 8233A (0x3147 and 0x3177) - 8235 - 8237 + Supports the following VIA south bridges: + + Chip name PCI ID REV I2C block + VT82C596A 0x3050 no + VT82C596B 0x3051 no + VT82C686A 0x3057 0x30 no + VT82C686B 0x3057 0x40 yes + VT8231 0x8235 no? + VT8233 0x3074 yes + VT8233A 0x3147 yes? + VT8235 0x3177 yes + VT8237R 0x3227 yes + Note: we assume there can only be one device, with one SMBus interface. */ From 50c1cc339ca72f7cb95d440d384346f4238dc494 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 22:15:53 +0200 Subject: [PATCH 1023/1939] [PATCH] i2c-viapro: Refactor control outb By slightly shifting the interface between vt596_access and vt596_transaction, we can save two I/O accesses per SMBus transaction. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-viapro.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) --- drivers/i2c/busses/i2c-viapro.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 3be476cd4bc5..a89a21264d37 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -105,7 +105,7 @@ static struct i2c_adapter vt596_adapter; static unsigned int vt596_features; /* Return -1 on error, 0 on success */ -static int vt596_transaction(void) +static int vt596_transaction(u8 size) { int temp; int result = 0; @@ -131,7 +131,7 @@ static int vt596_transaction(void) } /* Start the transaction by setting bit 6 */ - outb_p(inb(SMBHSTCNT) | 0x40, SMBHSTCNT); + outb_p(0x40 | (size & 0x3C), SMBHSTCNT); /* We will always wait for a fraction of a second */ do { @@ -232,9 +232,8 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, } outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD); - outb_p((size & 0x3C), SMBHSTCNT); - if (vt596_transaction()) /* Error in transaction */ + if (vt596_transaction(size)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK)) From ed5453e54f0c4a29605fd8399f58649d8739f5f0 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Sep 2005 22:23:32 +0200 Subject: [PATCH 1024/1939] [PATCH] i2c-viapro: Improve register dump Improve the register dump used to debug the i2c-viapro driver. The original dump was missing the HSTSTS register and the block data buffer. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-viapro.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) --- drivers/i2c/busses/i2c-viapro.c | 38 ++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index a89a21264d37..c1c9eb1d714f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -104,6 +104,30 @@ static struct i2c_adapter vt596_adapter; #define FEATURE_I2CBLOCK (1<<0) static unsigned int vt596_features; +#ifdef DEBUG +static void vt596_dump_regs(const char *msg, u8 size) +{ + dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x " + "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); + + if (size == VT596_BLOCK_DATA + || size == VT596_I2C_BLOCK_DATA) { + int i; + + dev_dbg(&vt596_adapter.dev, "BLK="); + for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++) + printk("%02x,", inb_p(SMBBLKDAT)); + printk("\n"); + dev_dbg(&vt596_adapter.dev, " "); + for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++) + printk("%02x,", inb_p(SMBBLKDAT)); + printk("%02x\n", inb_p(SMBBLKDAT)); + } +} +#endif + /* Return -1 on error, 0 on success */ static int vt596_transaction(u8 size) { @@ -111,10 +135,9 @@ static int vt596_transaction(u8 size) int result = 0; int timeout = 0; - dev_dbg(&vt596_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); +#ifdef DEBUG + vt596_dump_regs("Transaction (pre)", size); +#endif /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { @@ -169,10 +192,9 @@ static int vt596_transaction(u8 size) if (temp & 0x1F) outb_p(temp, SMBHSTSTS); - dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); +#ifdef DEBUG + vt596_dump_regs("Transaction (post)", size); +#endif return result; } From ca68f1193e8fc86470d4222d563d13b5584dc4f8 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Thu, 22 Sep 2005 22:23:32 +0200 Subject: [PATCH 1025/1939] [PATCH] i2c-viapro: Cleanup ifdef usage It's not nice to put #ifdef in the middle of functions. CC: Jean Delvare Signed-off-by: Greg Kroah-Hartman drivers/i2c/busses/i2c-viapro.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) --- drivers/i2c/busses/i2c-viapro.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index c1c9eb1d714f..566342d50c5f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -126,6 +126,8 @@ static void vt596_dump_regs(const char *msg, u8 size) printk("%02x\n", inb_p(SMBBLKDAT)); } } +#else +static inline void vt596_dump_regs(const char *msg, u8 size) { } #endif /* Return -1 on error, 0 on success */ @@ -135,9 +137,7 @@ static int vt596_transaction(u8 size) int result = 0; int timeout = 0; -#ifdef DEBUG vt596_dump_regs("Transaction (pre)", size); -#endif /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { @@ -192,9 +192,7 @@ static int vt596_transaction(u8 size) if (temp & 0x1F) outb_p(temp, SMBHSTSTS); -#ifdef DEBUG vt596_dump_regs("Transaction (post)", size); -#endif return result; } From 8a1b028bca95b5af36e94a660c4d284fe3313f74 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Oct 2005 23:04:48 +0200 Subject: [PATCH 1026/1939] [PATCH] i2c: Add missing i2c-ixp2000/4xx adapter name The ixp4xx and ixp2000 i2c bus drivers omit to fill the required i2c_adapter name field. Copy the device driver name field there. Signed-off-by: Jean Delvare Signed-off-by: Deepak Saxena Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-ixp2000.c | 4 ++++ drivers/i2c/busses/i2c-ixp4xx.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 1956af382cd8..9dee505ceed2 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -36,6 +36,8 @@ #include /* Pick up IXP2000-specific bits */ #include +static struct device_driver ixp2000_i2c_driver; + static inline int ixp2000_scl_pin(void *data) { return ((struct ixp2000_i2c_pins*)data)->scl_pin; @@ -121,6 +123,8 @@ static int ixp2000_i2c_probe(struct device *dev) drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP2000, + strlcpy(drv_data->adapter.name, ixp2000_i2c_driver.name, + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data, drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index f6f5ca31fdba..013981df38af 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -35,6 +35,8 @@ #include /* Pick up IXP4xx-specific bits */ +static struct device_driver ixp4xx_i2c_driver; + static inline int ixp4xx_scl_pin(void *data) { return ((struct ixp4xx_i2c_pins*)data)->scl_pin; @@ -129,6 +131,8 @@ static int ixp4xx_i2c_probe(struct device *dev) drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP4XX; + strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.name, + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; From e8aafcb2bba1fe122907161701a167e38174c7a5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Oct 2005 23:06:27 +0200 Subject: [PATCH 1027/1939] [PATCH] i2c: Cleanup i2c-dev ioctl debug message Cleanup the ioctl debug message in i2c-dev. In particular, the minor number is redundant now that the minor number and the adapter number are kept in sync. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index aa7a4fadef64..89f54a5e8484 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -177,8 +177,8 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, int i,datasize,res; unsigned long funcs; - dev_dbg(&client->adapter->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - iminor(inode),cmd, arg); + dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", + cmd, arg); switch ( cmd ) { case I2C_SLAVE: From bf813b314a2271c3f3903eb3279ebf5e09b3d27a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Oct 2005 23:09:04 +0200 Subject: [PATCH 1028/1939] [PATCH] i2c: Drop useless CVS revision IDs CVS revision IDs are totally useless and irrelevant by now. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c-algo-bit.h | 2 -- include/linux/i2c-algo-pcf.h | 2 -- include/linux/i2c-dev.h | 2 -- include/linux/i2c.h | 2 -- 4 files changed, 8 deletions(-) diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index 110904481238..fb592147caec 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -21,8 +21,6 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-bit.h,v 1.10 2003/01/21 08:08:16 kmalkki Exp $ */ - #ifndef _LINUX_I2C_ALGO_BIT_H #define _LINUX_I2C_ALGO_BIT_H diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index 2a508562255f..a0e534b334a9 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h @@ -22,8 +22,6 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-pcf.h,v 1.8 2003/01/21 08:08:16 kmalkki Exp $ */ - #ifndef _LINUX_I2C_ALGO_PCF_H #define _LINUX_I2C_ALGO_PCF_H diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h index 541695679762..81c229a0fbca 100644 --- a/include/linux/i2c-dev.h +++ b/include/linux/i2c-dev.h @@ -19,8 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: i2c-dev.h,v 1.13 2003/01/21 08:08:16 kmalkki Exp $ */ - #ifndef _LINUX_I2C_DEV_H #define _LINUX_I2C_DEV_H diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 17d63c1efdce..ec8188414506 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -23,8 +23,6 @@ /* With some changes from Kyösti Mälkki and Frodo Looijaard */ -/* $Id: i2c.h,v 1.68 2003/01/21 08:08:16 kmalkki Exp $ */ - #ifndef _LINUX_I2C_H #define _LINUX_I2C_H From ada0c2f8fa087dc1dbc34e096c318739b1d6381a Mon Sep 17 00:00:00 2001 From: Petr Vandrovec Date: Fri, 7 Oct 2005 23:11:03 +0200 Subject: [PATCH 1029/1939] [PATCH] hwmon: Fix w83627ehf/hf vs PNPACPI conflict (bug #4014) This patch changes w83627hf and w83627ehf drivers to reserve only ports 0x295-0x296, instead of full 0x290-0x297 range. While some other sensors chips respond to all addresses in 0x290-0x297 range, Winbond chips respond to 0x295-0x296 only (this behavior is implied by documentation, and matches behavior observed on real systems). This is not problem alone, as no BIOS was found to put something at these unused addresses, and sensors chip itself provides nothing there as well. But in addition to only respond to these two addresses, also BIOS vendors report in their ACPI-PnP structures that there is some resource at I/O address 0x295 of length 2. And when later this hwmon driver attempts to request region with base 0x290/length 8, it fails as one request_region cannot span more than one device. Due to this we have to ask only for region this hardware really occupies, otherwise driver cannot be loaded on systems with ACPI-PnP enabled. Signed-off-by: Petr Vandrovec Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 13 ++++++++----- drivers/hwmon/w83627hf.c | 21 +++++++++++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b60efe8f8b26..685eeb766809 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -105,7 +105,9 @@ superio_exit(void) * ISA constants */ -#define REGION_LENGTH 8 +#define REGION_ALIGNMENT ~7 +#define REGION_OFFSET 5 +#define REGION_LENGTH 2 #define ADDR_REG_OFFSET 5 #define DATA_REG_OFFSET 6 @@ -673,7 +675,8 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) struct w83627ehf_data *data; int i, err = 0; - if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + if (!request_region(address + REGION_OFFSET, REGION_LENGTH, + w83627ehf_driver.name)) { err = -EBUSY; goto exit; } @@ -762,7 +765,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) exit_free: kfree(data); exit_release: - release_region(address, REGION_LENGTH); + release_region(address + REGION_OFFSET, REGION_LENGTH); exit: return err; } @@ -776,7 +779,7 @@ static int w83627ehf_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - release_region(client->addr, REGION_LENGTH); + release_region(client->addr + REGION_OFFSET, REGION_LENGTH); kfree(data); return 0; @@ -807,7 +810,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr) superio_select(W83627EHF_LD_HWM); val = (superio_inb(SIO_REG_ADDR) << 8) | superio_inb(SIO_REG_ADDR + 1); - *addr = val & ~(REGION_LENGTH - 1); + *addr = val & REGION_ALIGNMENT; if (*addr == 0) { superio_exit(); return -ENODEV; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 7f6f7280878d..494274d27f01 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -142,10 +142,14 @@ superio_exit(void) #define WINB_BASE_REG 0x60 /* Constants specified below */ -/* Length of ISA address segment */ -#define WINB_EXTENT 8 +/* Alignment of the base address */ +#define WINB_ALIGNMENT ~7 -/* Where are the ISA address/data registers relative to the base address */ +/* Offset & size of I/O region we are interested in */ +#define WINB_REGION_OFFSET 5 +#define WINB_REGION_SIZE 2 + +/* Where are the sensors address/data registers relative to the base address */ #define W83781D_ADDR_REG_OFFSET 5 #define W83781D_DATA_REG_OFFSET 6 @@ -981,7 +985,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr) superio_select(W83627HF_LD_HWM); val = (superio_inb(WINB_BASE_REG) << 8) | superio_inb(WINB_BASE_REG + 1); - *addr = val & ~(WINB_EXTENT - 1); + *addr = val & WINB_ALIGNMENT; if (*addr == 0 && force_addr == 0) { superio_exit(); return -ENODEV; @@ -1000,9 +1004,10 @@ static int w83627hf_detect(struct i2c_adapter *adapter) const char *client_name = ""; if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); + address = force_addr & WINB_ALIGNMENT; - if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { + if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE, + w83627hf_driver.name)) { err = -EBUSY; goto ERROR0; } @@ -1148,7 +1153,7 @@ static int w83627hf_detect(struct i2c_adapter *adapter) ERROR2: kfree(data); ERROR1: - release_region(address, WINB_EXTENT); + release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE); ERROR0: return err; } @@ -1163,7 +1168,7 @@ static int w83627hf_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - release_region(client->addr, WINB_EXTENT); + release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE); kfree(data); return 0; From 47b8b103f7f50d56568eb8d6cff0e3a2373f0eb3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Oct 2005 23:56:46 +0200 Subject: [PATCH 1030/1939] [PATCH] i2c: Cleanup i2c-i801 ifdefs No more need to check for PEC support being available now that both the i2c-core and the i2c-i801 drivers are part of the Linux kernel source tree. It's just there. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 588583530c9f..413930cafc49 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -52,10 +52,6 @@ #include #include -#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC -#define HAVE_PEC -#endif - /* I801 SMBus address offsets */ #define SMBHSTSTS (0 + i801_smba) #define SMBHSTCNT (2 + i801_smba) @@ -392,7 +388,6 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, goto END; } -#ifdef HAVE_PEC if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { /* wait for INTR bit as advised by Intel */ timeout = 0; @@ -407,7 +402,6 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, } outb_p(temp, SMBHSTSTS); } -#endif result = 0; END: if (command == I2C_SMBUS_I2C_BLOCK_DATA) { @@ -426,10 +420,8 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, int block = 0; int ret, xact = 0; -#ifdef HAVE_PEC if(isich4) hwpec = (flags & I2C_CLIENT_PEC) != 0; -#endif switch (size) { case I2C_SMBUS_QUICK: @@ -464,11 +456,9 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: -#ifdef HAVE_PEC case I2C_SMBUS_BLOCK_DATA_PEC: if(hwpec && size == I2C_SMBUS_BLOCK_DATA) size = I2C_SMBUS_BLOCK_DATA_PEC; -#endif outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); @@ -480,13 +470,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, return -1; } -#ifdef HAVE_PEC if(isich4 && hwpec) { if(size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA) outb_p(1, SMBAUXCTL); /* enable HW PEC */ } -#endif if(block) ret = i801_block_transaction(data, read_write, size); else { @@ -494,13 +482,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, ret = i801_transaction(); } -#ifdef HAVE_PEC if(isich4 && hwpec) { if(size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA) outb_p(0, SMBAUXCTL); } -#endif if(block) return ret; @@ -527,12 +513,8 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK -#ifdef HAVE_PEC | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC | - I2C_FUNC_SMBUS_HWPEC_CALC - : 0) -#endif - ; + I2C_FUNC_SMBUS_HWPEC_CALC : 0); } static struct i2c_algorithm smbus_algorithm = { From 7865e24935ec7e76fb482c749015a23052e51f76 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:00:31 +0200 Subject: [PATCH 1031/1939] [PATCH] i2c: Documentation fixes i2c documentation fixes. >From Hideki Iwamoto: * i2c_smbus_read_i2c_block_data is not deleted in 2.6.10. It still exists. * The name which can be set to i2c_driver is up to 31 characters. >From Jean Delvare: * Reword the paragraph about i2c_driver.name, to reflect the "new" naming policy. * Delete the out-of-date note about now gone inc_use and dec_use fields. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/writing-clients | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 077275722a7c..1882811c7f5d 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -33,8 +33,8 @@ static struct i2c_driver foo_driver = { .command = &foo_command /* may be NULL */ } -The name can be chosen freely, and may be upto 40 characters long. Please -use something descriptive here. +The name field must match the driver name, including the case. It must not +contain spaces, and may be up to 31 characters long. Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This means that your driver will be notified when new adapters are found. @@ -43,9 +43,6 @@ This is almost always what you want. All other fields are for call-back functions which will be explained below. -There use to be two additional fields in this structure, inc_use et dec_use, -for module usage count, but these fields were obsoleted and removed. - Extra client data ================= @@ -576,12 +573,12 @@ SMBus communication extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values); + extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, + u8 command, u8 *values); These ones were removed in Linux 2.6.10 because they had no users, but could be added back later if needed: - extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, - u8 command, u8 *values); extern s32 i2c_smbus_read_block_data(struct i2c_client * client, u8 command, u8 *values); extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, From 31ec5bc57146a479fac6f6878146059180413e43 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:04:13 +0200 Subject: [PATCH 1032/1939] [PATCH] i2c: Fix misplaced i2c.h comment Fix a misplaced comment in i2c.h. Spotted by Hideki Iwamoto. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ec8188414506..6a1f3424f10f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -92,10 +92,10 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value); -/* Returns the number of bytes transferred */ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values); +/* Returns the number of read bytes */ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, u8 command, u8 *values); From 80ce3b7d0f52877b80cddc3ace8b332d888f0131 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:06:09 +0200 Subject: [PATCH 1033/1939] [PATCH] i2c: Drop out-of-date, colliding ioctl definitions Delete 2 out-of-date, colliding ioctl defines. I2C_UDELAY and I2C_MDELAY are supposed to be used by i2c-algo-bit, but actually aren't (and I suspect never were). Moreover, their values are the same as I2C_FUNCS and I2C_SLAVE_FORCE, respectively, which *are* widely used. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6a1f3424f10f..74103d0a8cd2 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -503,11 +503,6 @@ union i2c_smbus_data { #define I2C_SMBUS 0x0720 /* SMBus-level access */ -/* ... algo-bit.c recognizes */ -#define I2C_UDELAY 0x0705 /* set delay in microsecs between each */ - /* written byte (except address) */ -#define I2C_MDELAY 0x0706 /* millisec delay between written bytes */ - /* ----- I2C-DEV: char device interface stuff ------------------------- */ #define I2C_MAJOR 89 /* Device major number */ From 91749996287c230671788014f422f72e594e7b86 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:10:00 +0200 Subject: [PATCH 1034/1939] [PATCH] hwmon: Drop legacy ISA address support from it87 Drop legacy ISA address support from the it87 driver. All supported chips are Super-I/O chips, so the device ISA address can be safely read from Super-I/O space rather than blindly assumed. Two nearby inaccurate documentation statements have been fixed as well: * The IT8705F doesn't have an SMBus interface. * The SiS950 doesn't have a distinct prefix. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/it87 | 8 +++---- drivers/hwmon/it87.c | 51 +++++++++------------------------------- 2 files changed, 15 insertions(+), 44 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 0d0195040d88..7f42e441c645 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -4,18 +4,18 @@ Kernel driver it87 Supported chips: * IT8705F Prefix: 'it87' - Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Publicly available at the ITE website http://www.ite.com.tw/ * IT8712F Prefix: 'it8712' Addresses scanned: I2C 0x28 - 0x2f - from Super I/O config space, or default ISA 0x290 (8 I/O ports) + from Super I/O config space (8 I/O ports) Datasheet: Publicly available at the ITE website http://www.ite.com.tw/ * SiS950 [clone of IT8705F] - Prefix: 'sis950' - Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Prefix: 'it87' + Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: No longer be available Author: Christophe Gauthron diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 53cc2b6d6385..55e1c835a046 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -2,7 +2,7 @@ it87.c - Part of lm_sensors, Linux kernel modules for hardware monitoring. - Supports: IT8705F Super I/O chip w/LPC interface & SMBus + Supports: IT8705F Super I/O chip w/LPC interface IT8712F Super I/O chip w/LPC interface & SMBus Sis950 A clone of the IT8705F @@ -47,7 +47,7 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned short isa_address = 0x290; +static unsigned short isa_address; /* Insmod parameters */ I2C_CLIENT_INSMOD_2(it87, it8712); @@ -706,7 +706,7 @@ static int it87_isa_attach_adapter(struct i2c_adapter *adapter) } /* SuperIO detection - will change isa_address if a chip is found */ -static int __init it87_find(int *address) +static int __init it87_find(unsigned short *address) { int err = -ENODEV; @@ -757,34 +757,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) if (!request_region(address, IT87_EXTENT, it87_isa_driver.name)) goto ERROR0; - /* Probe whether there is anything available on this address. Already - done for SMBus and Super-I/O clients */ - if (kind < 0) { - if (is_isa && !chip_type) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the + /* For now, we presume we have a valid client. We create the client structure, even though we cannot fill it completely yet. But it allows us to access it87_{read,write}_value. */ @@ -1182,20 +1155,18 @@ static struct it87_data *it87_update_device(struct device *dev) static int __init sm_it87_init(void) { - int addr, res; - - if (!it87_find(&addr)) { - isa_address = addr; - } + int res; res = i2c_add_driver(&it87_driver); if (res) return res; - res = i2c_isa_add_driver(&it87_isa_driver); - if (res) { - i2c_del_driver(&it87_driver); - return res; + if (!it87_find(&isa_address)) { + res = i2c_isa_add_driver(&it87_isa_driver); + if (res) { + i2c_del_driver(&it87_driver); + return res; + } } return 0; From 862bc36f682b25dd97833f702b4f8c97661b8811 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:12:01 +0200 Subject: [PATCH 1035/1939] [PATCH] hwmon: Drop useless w83627hf initialization step Drop a useless initialization step in the w83627hf driver. The comment says that the W83627HF PWM2 can be disabled, but it can't. I suppose this is a leftover from the w83781d driver (from which the w83627hf driver is derived), as for example the W83782D had the ability to disable PWM2. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627hf.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 494274d27f01..48270819ff99 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -201,7 +201,6 @@ superio_exit(void) #define W83627HF_REG_PWM1 0x5A #define W83627HF_REG_PWM2 0x5B -#define W83627HF_REG_PWMCLK12 0x5C #define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ #define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ @@ -1373,12 +1372,6 @@ static void w83627hf_init_client(struct i2c_client *client) } } - if (type == w83627hf) { - /* enable PWM2 control (can't hurt since PWM reg - should have been reset to 0xff) */ - w83627hf_write_value(client, W83627HF_REG_PWMCLK12, - 0x19); - } /* enable comparator mode for temp2 and temp3 so alarm indication will work correctly */ i = w83627hf_read_value(client, W83781D_REG_IRQ); From d3554b4a2fb0e2229eb0d3fa9ece5b2f0b906d3e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:14:17 +0200 Subject: [PATCH 1036/1939] [PATCH] i2c: Drop unused per-i2c-algorithm adapter max There are no more per-i2c-algorithm adapter max. Last time there were was in July 1999. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c-algo-bit.h | 2 -- include/linux/i2c-algo-pca.h | 2 -- include/linux/i2c-algo-pcf.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index fb592147caec..c0e7fab28ce3 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -44,8 +44,6 @@ struct i2c_algo_bit_data { int timeout; /* in jiffies */ }; -#define I2C_BIT_ADAP_MAX 16 - int i2c_bit_add_bus(struct i2c_adapter *); int i2c_bit_del_bus(struct i2c_adapter *); diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index 941b786c5732..226693e0d88b 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -9,8 +9,6 @@ struct i2c_algo_pca_data { int (*wait_for_interrupt) (struct i2c_algo_pca_data *adap); }; -#define I2C_PCA_ADAP_MAX 16 - int i2c_pca_add_bus(struct i2c_adapter *); int i2c_pca_del_bus(struct i2c_adapter *); diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index a0e534b334a9..18b0adf57a3d 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h @@ -39,8 +39,6 @@ struct i2c_algo_pcf_data { int timeout; }; -#define I2C_PCF_ADAP_MAX 16 - int i2c_pcf_add_bus(struct i2c_adapter *); int i2c_pcf_del_bus(struct i2c_adapter *); From 30dac7469741906436b50f9413dccd446366d371 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:15:59 +0200 Subject: [PATCH 1037/1939] [PATCH] i2c: Drop I2C_SMBUS_I2C_BLOCK_MAX Drop I2C_SMBUS_I2C_BLOCK_MAX, use I2C_SMBUS_BLOCK_MAX instead. I2C_SMBUS_I2C_BLOCK_MAX has always been defined to the same value as I2C_SMBUS_BLOCK_MAX, and this will never change: setting it to a lower value would make no sense, setting it to a higher value would break i2c_smbus_data compatibility. There is no point in changing i2c_smbus_data to support larger block transactions in SMBus mode, as no SMBus hardware supports more than 32 byte blocks. Thus, for larger transactions, direct I2C transfers are the way to go. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/eeprom.c | 4 ++-- drivers/i2c/i2c-core.c | 8 ++++---- include/linux/i2c.h | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index d58403a47908..7fb739c43935 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -88,8 +88,8 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_I2C_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_I2C_BLOCK_MAX) + for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX) + if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX) goto exit; } else { if (i2c_smbus_write_byte(client, slice << 5)) { diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9583a54ce16b..15354176ff63 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1108,10 +1108,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, return -1; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; + msg[1].len = I2C_SMBUS_BLOCK_MAX; } else { msg[0].len = data->block[0] + 1; - if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); @@ -1144,8 +1144,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: /* fixed at 32 for now */ - data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; - for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 74103d0a8cd2..64c13c042f9d 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -448,7 +448,6 @@ struct i2c_msg { * Data for SMBus Messages */ #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ -#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ union i2c_smbus_data { __u8 byte; __u16 word; From 6c129be8c7bd1bdbd47ba8e17f6e5053ef04aee8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:17:35 +0200 Subject: [PATCH 1038/1939] [PATCH] i2c: Rename i2c-parport variable to avoid confusion It's a bit confusing to name a variable the same as an unrelated structure. The compiler doesn't complain, but it certainly makes the code harder to understand, and could confuse grep and LXR among others. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-parport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 71a2502fe069..fa506187fbe1 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -232,7 +232,7 @@ static void i2c_parport_detach (struct parport *port) } } -static struct parport_driver i2c_driver = { +static struct parport_driver i2c_parport_driver = { .name = "i2c-parport", .attach = i2c_parport_attach, .detach = i2c_parport_detach, @@ -250,12 +250,12 @@ static int __init i2c_parport_init(void) type = 0; } - return parport_register_driver(&i2c_driver); + return parport_register_driver(&i2c_parport_driver); } static void __exit i2c_parport_exit(void) { - parport_unregister_driver(&i2c_driver); + parport_unregister_driver(&i2c_parport_driver); } MODULE_AUTHOR("Jean Delvare "); From 00bffb6e29c5ef12cea7904905f8b959187076c9 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Oct 2005 00:19:52 +0200 Subject: [PATCH 1039/1939] [PATCH] i2c: Drop meaningless use of I2C_DF_NOTIFY in i2c_client structures I2C_DF_NOTIFY is an i2c_driver flag, using it as an i2c_client flag doesn't make any sense. Signed-off-by: Jean Delvare Acked-by: Mark A. Greer Acked-by: Randy Vinson Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/ds1374.c | 1 - drivers/i2c/chips/m41t00.c | 1 - drivers/i2c/chips/rtc8564.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 0936327a946d..ec640e9f085a 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -199,7 +199,6 @@ static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); - client->flags = I2C_DF_NOTIFY; client->addr = addr; client->adapter = adap; client->driver = &ds1374_driver; diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 3f14528a52a9..554f7ba61627 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -180,7 +180,6 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE); - client->flags = I2C_DF_NOTIFY; client->addr = addr; client->adapter = adap; client->driver = &m41t00_driver; diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 0b5385c892b1..dd9d42d7b6e7 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -158,7 +158,7 @@ static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); i2c_set_clientdata(new_client, d); - new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY; + new_client->flags = I2C_CLIENT_ALLOW_USE; new_client->addr = addr; new_client->adapter = adap; new_client->driver = &rtc8564_driver; From 3634ff6a32e90d9db0ec19297e80059143c1aa7f Mon Sep 17 00:00:00 2001 From: Stig Telfer Date: Sat, 8 Oct 2005 00:21:48 +0200 Subject: [PATCH 1040/1939] [PATCH] i2c: Fix i2c-elektor on Alpha This patch updates the i2c-elektor driver, enabling it to compile cleanly, load and run. The key change is that it uses the new __iomem/iowrite8/ioread8 functions to abstract the direct or memory-mapped variants of register access. Also, the original driver would crash on module load on the Alpha because the PCI memory region was not remapped into kernel memory. I have managed the following testing: * compiled and tested it on my Alpha UP2000+ system. * compiles cleanly for x86 but I don't have the hardware to test. Signed-off-by: Stig Telfer Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-elektor.c | 74 +++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 6930b660e508..75b4b442a636 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -46,6 +46,8 @@ #define DEFAULT_BASE 0x330 static int base; +static u8 __iomem *base_iomem; + static int irq; static int clock = 0x1c; static int own = 0x55; @@ -64,36 +66,27 @@ static spinlock_t lock; static void pcf_isa_setbyte(void *data, int ctl, int val) { - int address = ctl ? (base + 1) : base; + u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; /* enable irq if any specified for serial operation */ if (ctl && irq && (val & I2C_PCF_ESO)) { val |= I2C_PCF_ENI; } - pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255); - - switch (mmapped) { - case 0: /* regular I/O */ - outb(val, address); - break; - case 2: /* double mapped I/O needed for UP2000 board, - I don't know why this... */ - writeb(val, (void *)address); - /* fall */ - case 1: /* memory mapped I/O */ - writeb(val, (void *)address); - break; - } + pr_debug("i2c-elektor: Write %p 0x%02X\n", address, val); + iowrite8(val, address); +#ifdef __alpha__ + /* API UP2000 needs some hardware fudging to make the write stick */ + iowrite8(val, address); +#endif } static int pcf_isa_getbyte(void *data, int ctl) { - int address = ctl ? (base + 1) : base; - int val = mmapped ? readb((void *)address) : inb(address); - - pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val); + u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; + int val = ioread8(address); + pr_debug("i2c-elektor: Read %p 0x%02X\n", address, val); return (val); } @@ -155,7 +148,30 @@ static int pcf_isa_init(void) "is in use.\n", base); return -ENODEV; } + base_iomem = ioport_map(base, 2); + if (!base_iomem) { + printk(KERN_ERR "i2c-elektor: remap of I/O region " + "%#x failed\n", base); + release_region(base, 2); + return -ENODEV; + } + } else { + if (!request_mem_region(base, 2, "i2c-elektor")) { + printk(KERN_ERR "i2c-elektor: requested memory region " + "(%#x:2) is in use\n", base); + return -ENODEV; + } + base_iomem = ioremap(base, 2); + if (base_iomem == NULL) { + printk(KERN_ERR "i2c-elektor: remap of memory region " + "%#x failed\n", base); + release_mem_region(base, 2); + return -ENODEV; + } } + pr_debug("i2c-elektor: registers %#x remapped to %p\n", base, + base_iomem); + if (irq > 0) { if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) { printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq); @@ -200,7 +216,7 @@ static int __init i2c_pcfisa_init(void) cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, NULL); if (cy693_dev) { - char config; + unsigned char config; /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { @@ -219,9 +235,7 @@ static int __init i2c_pcfisa_init(void) if ((config & 0x7f) == 0x61) { /* seems to be UP2000 like board */ base = 0xe0000; - /* I don't know why we need to - write twice */ - mmapped = 2; + mmapped = 1; /* UP2000 drives ISA with 8.25 MHz (PCI/4) clock (this can be read from cypress) */ @@ -262,8 +276,13 @@ static int __init i2c_pcfisa_init(void) free_irq(irq, NULL); } - if (!mmapped) + if (!mmapped) { + ioport_unmap(base_iomem); release_region(base , 2); + } else { + iounmap(base_iomem); + release_mem_region(base, 2); + } return -ENODEV; } @@ -276,8 +295,13 @@ static void i2c_pcfisa_exit(void) free_irq(irq, NULL); } - if (!mmapped) + if (!mmapped) { + ioport_unmap(base_iomem); release_region(base , 2); + } else { + iounmap(base_iomem); + release_mem_region(base, 2); + } } MODULE_AUTHOR("Hans Berglund "); From fe3d6a99782d5345b1927e872d77d1778668094b Mon Sep 17 00:00:00 2001 From: Stig Telfer Date: Sat, 8 Oct 2005 00:23:27 +0200 Subject: [PATCH 1041/1939] [PATCH] i2c: Big i2c-elektor cleanup Cleanups to the i2c-elektor driver: * Set the i2c_adapter name field to "i2c-elektor" and use this string in all resource requests and printks. * Change space-padding for tab indentation, kill trailing white space, remove space before comma. * Use dev_info, pr_info and pr_debug instead of printk. * Lines chopped to 80 columns. Signed-off-by: Stig Telfer Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-elektor.c | 84 +++++++++++++++++--------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 75b4b442a636..59f8308c2356 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -22,7 +22,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of +/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of for Alpha Processor Inc. UP-2000(+) boards */ #include @@ -53,7 +53,7 @@ static int clock = 0x1c; static int own = 0x55; static int mmapped; -/* vdovikin: removed static struct i2c_pcf_isa gpi; code - +/* vdovikin: removed static struct i2c_pcf_isa gpi; code - this module in real supports only one device, due to missing arguments in some functions, called from the algo-pcf module. Sometimes it's need to be rewriten - but for now just remove this for simpler reading */ @@ -62,6 +62,8 @@ static wait_queue_head_t pcf_wait; static int pcf_pending; static spinlock_t lock; +static struct i2c_adapter pcf_isa_ops; + /* ----- local functions ---------------------------------------------- */ static void pcf_isa_setbyte(void *data, int ctl, int val) @@ -73,7 +75,7 @@ static void pcf_isa_setbyte(void *data, int ctl, int val) val |= I2C_PCF_ENI; } - pr_debug("i2c-elektor: Write %p 0x%02X\n", address, val); + pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val); iowrite8(val, address); #ifdef __alpha__ /* API UP2000 needs some hardware fudging to make the write stick */ @@ -86,7 +88,7 @@ static int pcf_isa_getbyte(void *data, int ctl) u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; int val = ioread8(address); - pr_debug("i2c-elektor: Read %p 0x%02X\n", address, val); + pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val); return (val); } @@ -142,39 +144,40 @@ static int pcf_isa_init(void) { spin_lock_init(&lock); if (!mmapped) { - if (!request_region(base, 2, "i2c (isa bus adapter)")) { - printk(KERN_ERR - "i2c-elektor: requested I/O region (0x%X:2) " - "is in use.\n", base); + if (!request_region(base, 2, pcf_isa_ops.name)) { + printk(KERN_ERR "%s: requested I/O region (%#x:2) is " + "in use\n", pcf_isa_ops.name, base); return -ENODEV; } base_iomem = ioport_map(base, 2); if (!base_iomem) { - printk(KERN_ERR "i2c-elektor: remap of I/O region " - "%#x failed\n", base); + printk(KERN_ERR "%s: remap of I/O region %#x failed\n", + pcf_isa_ops.name, base); release_region(base, 2); return -ENODEV; } } else { - if (!request_mem_region(base, 2, "i2c-elektor")) { - printk(KERN_ERR "i2c-elektor: requested memory region " - "(%#x:2) is in use\n", base); + if (!request_mem_region(base, 2, pcf_isa_ops.name)) { + printk(KERN_ERR "%s: requested memory region (%#x:2) " + "is in use\n", pcf_isa_ops.name, base); return -ENODEV; } base_iomem = ioremap(base, 2); if (base_iomem == NULL) { - printk(KERN_ERR "i2c-elektor: remap of memory region " - "%#x failed\n", base); + printk(KERN_ERR "%s: remap of memory region %#x " + "failed\n", pcf_isa_ops.name, base); release_mem_region(base, 2); return -ENODEV; } } - pr_debug("i2c-elektor: registers %#x remapped to %p\n", base, + pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base, base_iomem); if (irq > 0) { - if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) { - printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq); + if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name, + NULL) < 0) { + printk(KERN_ERR "%s: Request irq%d failed\n", + pcf_isa_ops.name, irq); irq = 0; } else enable_irq(irq); @@ -202,45 +205,49 @@ static struct i2c_adapter pcf_isa_ops = { .class = I2C_CLASS_HWMON, .id = I2C_HW_P_ELEK, .algo_data = &pcf_isa_data, - .name = "PCF8584 ISA adapter", + .name = "i2c-elektor", }; -static int __init i2c_pcfisa_init(void) +static int __init i2c_pcfisa_init(void) { #ifdef __alpha__ - /* check to see we have memory mapped PCF8584 connected to the + /* check to see we have memory mapped PCF8584 connected to the Cypress cy82c693 PCI-ISA bridge as on UP2000 board */ if (base == 0) { struct pci_dev *cy693_dev; - - cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, + + cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, NULL); if (cy693_dev) { unsigned char config; /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - - pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config); + + pr_debug("%s: found cy82c693, config " + "register 0x47 = 0x%02x\n", + pcf_isa_ops.name, config); /* UP2000 board has this register set to 0xe1, - but the most significant bit as seems can be + but the most significant bit as seems can be reset during the proper initialisation - sequence if guys from API decides to do that - (so, we can even enable Tsunami Pchip - window for the upper 1 Gb) */ + sequence if guys from API decides to do that + (so, we can even enable Tsunami Pchip + window for the upper 1 Gb) */ /* so just check for ROMCS at 0xe0000, - ROMCS enabled for writes + ROMCS enabled for writes and external XD Bus buffer in use. */ if ((config & 0x7f) == 0x61) { /* seems to be UP2000 like board */ base = 0xe0000; mmapped = 1; - /* UP2000 drives ISA with + /* UP2000 drives ISA with 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n"); + pr_info("%s: found API UP2000 like " + "board, will probe PCF8584 " + "later\n", pcf_isa_ops.name); } } pci_dev_put(cy693_dev); @@ -250,12 +257,11 @@ static int __init i2c_pcfisa_init(void) /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk(KERN_ERR "i2c-elektor: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); + printk(KERN_ERR "%s: incorrect base address (%#x) specified " + "for mmapped I/O\n", pcf_isa_ops.name, base); return -ENODEV; } - printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n"); - if (base == 0) { base = DEFAULT_BASE; } @@ -265,8 +271,8 @@ static int __init i2c_pcfisa_init(void) return -ENODEV; if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) goto fail; - - printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base); + + dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); return 0; @@ -278,7 +284,7 @@ static int __init i2c_pcfisa_init(void) if (!mmapped) { ioport_unmap(base_iomem); - release_region(base , 2); + release_region(base, 2); } else { iounmap(base_iomem); release_mem_region(base, 2); @@ -297,7 +303,7 @@ static void i2c_pcfisa_exit(void) if (!mmapped) { ioport_unmap(base_iomem); - release_region(base , 2); + release_region(base, 2); } else { iounmap(base_iomem); release_mem_region(base, 2); From ccd7aa0cc9413b79b69f6cd7c18daa1c22dfa512 Mon Sep 17 00:00:00 2001 From: Laurent Riffard Date: Mon, 17 Oct 2005 22:47:48 +0200 Subject: [PATCH 1042/1939] [PATCH] Owner field additions to many i2c drivers, 1 of 5 This patch updates .owner field for various struct pci_driver variables. Signed-off-by: Laurent Riffard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-ali1535.c | 1 + drivers/i2c/busses/i2c-ali1563.c | 1 + drivers/i2c/busses/i2c-ali15x3.c | 1 + drivers/i2c/busses/i2c-amd756.c | 1 + drivers/i2c/busses/i2c-amd8111.c | 1 + drivers/i2c/busses/i2c-hydra.c | 1 + drivers/i2c/busses/i2c-i801.c | 1 + drivers/i2c/busses/i2c-i810.c | 1 + drivers/i2c/busses/i2c-nforce2.c | 1 + drivers/i2c/busses/i2c-piix4.c | 1 + drivers/i2c/busses/i2c-prosavage.c | 1 + drivers/i2c/busses/i2c-savage4.c | 1 + drivers/i2c/busses/i2c-sis5595.c | 1 + drivers/i2c/busses/i2c-sis630.c | 1 + drivers/i2c/busses/i2c-sis96x.c | 1 + drivers/i2c/busses/i2c-via.c | 1 + drivers/i2c/busses/i2c-viapro.c | 1 + drivers/i2c/busses/i2c-voodoo3.c | 1 + 18 files changed, 18 insertions(+) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 3eb47890db40..ba90f5140af6 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -513,6 +513,7 @@ static void __devexit ali1535_remove(struct pci_dev *dev) } static struct pci_driver ali1535_driver = { + .owner = THIS_MODULE, .name = "ali1535_smbus", .id_table = ali1535_ids, .probe = ali1535_probe, diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index e6f63208fc4a..f1a62d892425 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -408,6 +408,7 @@ static struct pci_device_id __devinitdata ali1563_id_table[] = { MODULE_DEVICE_TABLE (pci, ali1563_id_table); static struct pci_driver ali1563_pci_driver = { + .owner = THIS_MODULE, .name = "ali1563_smbus", .id_table = ali1563_id_table, .probe = ali1563_probe, diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 7a5c0941dbc1..400b08ed4299 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -504,6 +504,7 @@ static void __devexit ali15x3_remove(struct pci_dev *dev) } static struct pci_driver ali15x3_driver = { + .owner = THIS_MODULE, .name = "ali15x3_smbus", .id_table = ali15x3_ids, .probe = ali15x3_probe, diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 1750dedaf4b5..de035d137c3f 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -401,6 +401,7 @@ static void __devexit amd756_remove(struct pci_dev *dev) } static struct pci_driver amd756_driver = { + .owner = THIS_MODULE, .name = "amd756_smbus", .id_table = amd756_ids, .probe = amd756_probe, diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 6200c9a087ad..0d29e78dff63 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -392,6 +392,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev) } static struct pci_driver amd8111_driver = { + .owner = THIS_MODULE, .name = "amd8111_smbus2", .id_table = amd8111_ids, .probe = amd8111_probe, diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index e0cb3b0f92fa..1b5354e24bf5 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -155,6 +155,7 @@ static void __devexit hydra_remove(struct pci_dev *dev) static struct pci_driver hydra_driver = { + .owner = THIS_MODULE, .name = "hydra_smbus", .id_table = hydra_ids, .probe = hydra_probe, diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 413930cafc49..e90b6c4e7da3 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -568,6 +568,7 @@ static void __devexit i801_remove(struct pci_dev *dev) } static struct pci_driver i801_driver = { + .owner = THIS_MODULE, .name = "i801_smbus", .id_table = i801_ids, .probe = i801_probe, diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 0ff7016e0629..1b3393b7c461 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -232,6 +232,7 @@ static void __devexit i810_remove(struct pci_dev *dev) } static struct pci_driver i810_driver = { + .owner = THIS_MODULE, .name = "i810_smbus", .id_table = i810_ids, .probe = i810_probe, diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index dd4b6d8e03ef..5dc62114cc8d 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -356,6 +356,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev) } static struct pci_driver nforce2_driver = { + .owner = THIS_MODULE, .name = "nForce2_smbus", .id_table = nforce2_ids, .probe = nforce2_probe, diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 692f47345481..7d63eec423fe 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -462,6 +462,7 @@ static void __devexit piix4_remove(struct pci_dev *dev) } static struct pci_driver piix4_driver = { + .owner = THIS_MODULE, .name = "piix4_smbus", .id_table = piix4_ids, .probe = piix4_probe, diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 83fd16d61ce5..92b744273577 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -308,6 +308,7 @@ static struct pci_device_id prosavage_pci_tbl[] = { MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl); static struct pci_driver prosavage_driver = { + .owner = THIS_MODULE, .name = "prosavage_smbus", .id_table = prosavage_pci_tbl, .probe = prosavage_probe, diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 0c8518298e4d..aebe87ba4033 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -179,6 +179,7 @@ static void __devexit savage4_remove(struct pci_dev *dev) } static struct pci_driver savage4_driver = { + .owner = THIS_MODULE, .name = "savage4_smbus", .id_table = savage4_ids, .probe = savage4_probe, diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index b57ab74d23ec..3ad27c3ba15b 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -398,6 +398,7 @@ static void __devexit sis5595_remove(struct pci_dev *dev) } static struct pci_driver sis5595_driver = { + .owner = THIS_MODULE, .name = "sis5595_smbus", .id_table = sis5595_ids, .probe = sis5595_probe, diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index acb75e282414..7f49e5fd3ff0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -496,6 +496,7 @@ static void __devexit sis630_remove(struct pci_dev *dev) static struct pci_driver sis630_driver = { + .owner = THIS_MODULE, .name = "sis630_smbus", .id_table = sis630_ids, .probe = sis630_probe, diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3024907cdafe..6a134c091324 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -329,6 +329,7 @@ static void __devexit sis96x_remove(struct pci_dev *dev) } static struct pci_driver sis96x_driver = { + .owner = THIS_MODULE, .name = "sis96x_smbus", .id_table = sis96x_ids, .probe = sis96x_probe, diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 484bbacfce6b..544a38e64394 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -159,6 +159,7 @@ static void __devexit vt586b_remove(struct pci_dev *dev) static struct pci_driver vt586b_driver = { + .owner = THIS_MODULE, .name = "vt586b_smbus", .id_table = vt586b_ids, .probe = vt586b_probe, diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 566342d50c5f..c9366b504833 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -439,6 +439,7 @@ static struct pci_device_id vt596_ids[] = { MODULE_DEVICE_TABLE(pci, vt596_ids); static struct pci_driver vt596_driver = { + .owner = THIS_MODULE, .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index b675773b0cc1..650c3ebde84c 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -225,6 +225,7 @@ static void __devexit voodoo3_remove(struct pci_dev *dev) } static struct pci_driver voodoo3_driver = { + .owner = THIS_MODULE, .name = "voodoo3_smbus", .id_table = voodoo3_ids, .probe = voodoo3_probe, From 0cf3628181660be4e21fe520766dcbc3da9d71c8 Mon Sep 17 00:00:00 2001 From: Laurent Riffard Date: Mon, 17 Oct 2005 22:51:37 +0200 Subject: [PATCH 1043/1939] [PATCH] Owner field additions to many i2c drivers, 2 of 5 This patch updates the .owner field for various struct xxxx_driver variables, other than pci_driver. Signed-off-by: Laurent Riffard Signed-off-by: Jean Delvare Acked-by: Mark A. Greer Acked-by: Ben Dooks Acked-by: Deepak Saxena Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-iop3xx.c | 1 + drivers/i2c/busses/i2c-ixp2000.c | 1 + drivers/i2c/busses/i2c-ixp4xx.c | 1 + drivers/i2c/busses/i2c-mpc.c | 1 + drivers/i2c/busses/i2c-mv64xxx.c | 1 + drivers/i2c/busses/i2c-s3c2410.c | 2 ++ drivers/i2c/chips/isp1301_omap.c | 1 + 7 files changed, 8 insertions(+) diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 745e3a51f3e5..0f7dfd8f4546 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -525,6 +525,7 @@ iop3xx_i2c_probe(struct device *dev) static struct device_driver iop3xx_i2c_driver = { + .owner = THIS_MODULE, .name = "IOP3xx-I2C", .bus = &platform_bus_type, .probe = iop3xx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 9dee505ceed2..c3292dc743f1 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -146,6 +146,7 @@ static int ixp2000_i2c_probe(struct device *dev) } static struct device_driver ixp2000_i2c_driver = { + .owner = THIS_MODULE, .name = "IXP2000-I2C", .bus = &platform_bus_type, .probe = ixp2000_i2c_probe, diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 013981df38af..3169280c25a6 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -155,6 +155,7 @@ static int ixp4xx_i2c_probe(struct device *dev) } static struct device_driver ixp4xx_i2c_driver = { + .owner = THIS_MODULE, .name = "IXP4XX-I2C", .bus = &platform_bus_type, .probe = ixp4xx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f065583ddcf1..b81c54620030 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -361,6 +361,7 @@ static int fsl_i2c_remove(struct device *device) /* Structure for a device driver */ static struct device_driver fsl_i2c_driver = { + .owner = THIS_MODULE, .name = "fsl-i2c", .bus = &platform_bus_type, .probe = fsl_i2c_probe, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 99abca45fece..69709ee0b896 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -570,6 +570,7 @@ mv64xxx_i2c_remove(struct device *dev) } static struct device_driver mv64xxx_i2c_driver = { + .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, .bus = &platform_bus_type, .probe = mv64xxx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 69fa282df2d5..6ced28e90070 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -896,6 +896,7 @@ static int s3c24xx_i2c_resume(struct device *dev) /* device driver for platform bus bits */ static struct device_driver s3c2410_i2c_driver = { + .owner = THIS_MODULE, .name = "s3c2410-i2c", .bus = &platform_bus_type, .probe = s3c24xx_i2c_probe, @@ -904,6 +905,7 @@ static struct device_driver s3c2410_i2c_driver = { }; static struct device_driver s3c2440_i2c_driver = { + .owner = THIS_MODULE, .name = "s3c2440-i2c", .bus = &platform_bus_type, .probe = s3c24xx_i2c_probe, diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 8ee56d4b3891..eaa4742e04fa 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -888,6 +888,7 @@ static int otg_remove(struct device *dev) } struct device_driver omap_otg_driver = { + .owner = THIS_MODULE, .name = "omap_otg", .bus = &platform_bus_type, .probe = otg_probe, From e78f857cc5299c3f6b3d046084696ef205948837 Mon Sep 17 00:00:00 2001 From: Laurent Riffard Date: Mon, 17 Oct 2005 22:53:52 +0200 Subject: [PATCH 1044/1939] [PATCH] Owner field additions to many i2c drivers, 3 of 5 This patch updates the .owner field for various struct xxxx_driver variables which are available on PPC_MAC arch. This one was _not_ even compile-tested... Signed-off-by: Laurent Riffard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-keywest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index eff5896ce865..34e43c8d8d5e 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -716,6 +716,7 @@ static struct of_device_id i2c_keywest_match[] = static struct macio_driver i2c_keywest_macio_driver = { + .owner = THIS_MODULE, .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_macio, @@ -724,6 +725,7 @@ static struct macio_driver i2c_keywest_macio_driver = static struct of_platform_driver i2c_keywest_of_platform_driver = { + .owner = THIS_MODULE, .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_of_platform, From 6586bcd7b2bbe255110b2db772da4415c7865a2a Mon Sep 17 00:00:00 2001 From: Laurent Riffard Date: Mon, 17 Oct 2005 22:54:45 +0200 Subject: [PATCH 1045/1939] [PATCH] Owner field additions to many i2c drivers, 4 of 5 This patch updates the .owner field for the i2c core struct xxxx_driver variables. Signed-off-by: Laurent Riffard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 15354176ff63..0040981b6698 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -85,6 +85,7 @@ void i2c_adapter_dev_release(struct device *dev) } struct device_driver i2c_adapter_driver = { + .owner = THIS_MODULE, .name = "i2c_adapter", .bus = &i2c_bus_type, .probe = i2c_device_probe, @@ -98,6 +99,7 @@ static void i2c_adapter_class_dev_release(struct class_device *dev) } struct class i2c_adapter_class = { + .owner = THIS_MODULE, .name = "i2c-adapter", .release = &i2c_adapter_class_dev_release, }; @@ -291,6 +293,7 @@ int i2c_add_driver(struct i2c_driver *driver) down(&core_lists); /* add the driver to the list of i2c drivers in the driver core */ + driver->driver.owner = driver->owner; driver->driver.name = driver->name; driver->driver.bus = &i2c_bus_type; driver->driver.probe = i2c_device_probe; From 1747ef1b8c9b7b9c6a9aae3543a9b99acabb7e10 Mon Sep 17 00:00:00 2001 From: Laurent Riffard Date: Mon, 17 Oct 2005 22:58:35 +0200 Subject: [PATCH 1046/1939] [PATCH] Owner field additions to many i2c drivers, 5 of 5 In function i2c_isa_add_driver, copied driver should inherit the owner field as well as the name field. Signed-off-by: Laurent Riffard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-isa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index bdc6806dafae..4fdc02411609 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -92,6 +92,7 @@ int i2c_isa_add_driver(struct i2c_driver *driver) /* Add the driver to the list of i2c drivers in the driver core */ driver->driver.name = driver->name; + driver->driver.owner = driver->owner; driver->driver.bus = &i2c_bus_type; driver->driver.probe = i2c_isa_device_probe; driver->driver.remove = i2c_isa_device_remove; From 7ab83a9137ccd3e092fb6ad0cb105b4d1fb617ae Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Mon, 17 Oct 2005 23:01:45 +0200 Subject: [PATCH 1047/1939] [PATCH] hwmon: New device ID for the smsc47b397 driver This patch adds a new ID to the SMSC LPC47B397-NC hardware monitoring driver - for a chip that is claimed to be 100% compatible otherwise. Signed-off-by: Bryan Young (Utilitek Systems, Inc.) Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/smsc47b397 | 8 ++++++-- drivers/hwmon/smsc47b397.c | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/hwmon/smsc47b397 b/Documentation/hwmon/smsc47b397 index da9d80c96432..20682f15ae41 100644 --- a/Documentation/hwmon/smsc47b397 +++ b/Documentation/hwmon/smsc47b397 @@ -3,6 +3,7 @@ Kernel driver smsc47b397 Supported chips: * SMSC LPC47B397-NC + * SMSC SCH5307-NS Prefix: 'smsc47b397' Addresses scanned: none, address read from Super I/O config space Datasheet: In this file @@ -12,11 +13,14 @@ Authors: Mark M. Hoffman November 23, 2004 -The following specification describes the SMSC LPC47B397-NC sensor chip +The following specification describes the SMSC LPC47B397-NC[1] sensor chip (for which there is no public datasheet available). This document was provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected by Mark M. Hoffman . +[1] And SMSC SCH5307-NS, which has a different device ID but is otherwise +compatible. + * * * * * Methods for detecting the HP SIO and reading the thermal data on a dc7100. @@ -127,7 +131,7 @@ OUT DX,AL The registers of interest for identifying the SIO on the dc7100 are Device ID (0x20) and Device Rev (0x21). -The Device ID will read 0X6F +The Device ID will read 0x6F (for SCH5307-NS, 0x81) The Device Rev currently reads 0x01 Obtaining the HWM Base Address. diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 7fe71576dea4..37ed8b33f01a 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -299,7 +299,7 @@ static int __init smsc47b397_find(unsigned short *addr) superio_enter(); id = superio_inb(SUPERIO_REG_DEVID); - if (id != 0x6f) { + if ((id != 0x6f) && (id != 0x81)) { superio_exit(); return -ENODEV; } @@ -310,8 +310,9 @@ static int __init smsc47b397_find(unsigned short *addr) *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) | superio_inb(SUPERIO_REG_BASE_LSB); - printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " - "(base address 0x%04x, revision %u)\n", *addr, rev); + printk(KERN_INFO "smsc47b397: found SMSC %s " + "(base address 0x%04x, revision %u)\n", + id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev); superio_exit(); return 0; From ddec748f328af6b67e4d0ce0248a8e9f36751827 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 17 Oct 2005 23:02:42 +0200 Subject: [PATCH 1048/1939] [PATCH] hwmon: Missing class check in two hwmon drivers The atxp1 and ds1621 drivers should make sure they do not probe non-hwmon i2c adapters. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/atxp1.c | 2 ++ drivers/hwmon/ds1621.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index deb4d34c9539..441324fc6b8b 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -253,6 +253,8 @@ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); static int atxp1_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; return i2c_probe(adapter, &addr_data, &atxp1_detect); }; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index b0199e063d0e..e1ff22cf984a 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -180,6 +180,8 @@ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); static int ds1621_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; return i2c_probe(adapter, &addr_data, ds1621_detect); } From 4d4e5ce8648561b964699afb2df5e7268a84599b Mon Sep 17 00:00:00 2001 From: Alessandro Zummo Date: Mon, 17 Oct 2005 23:04:42 +0200 Subject: [PATCH 1049/1939] [PATCH] i2c: New Xicor X1205 RTC driver New driver for the Xicor X1205 RTC chip. Signed-off-by: Alessandro Zummo Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/chips/x1205 | 38 ++ drivers/i2c/chips/Kconfig | 9 + drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/x1205.c | 698 ++++++++++++++++++++++++++++++++++ include/linux/x1205.h | 31 ++ 5 files changed, 777 insertions(+) create mode 100644 Documentation/i2c/chips/x1205 create mode 100644 drivers/i2c/chips/x1205.c create mode 100644 include/linux/x1205.h diff --git a/Documentation/i2c/chips/x1205 b/Documentation/i2c/chips/x1205 new file mode 100644 index 000000000000..09407c991fe5 --- /dev/null +++ b/Documentation/i2c/chips/x1205 @@ -0,0 +1,38 @@ +Kernel driver x1205 +=================== + +Supported chips: + * Xicor X1205 RTC + Prefix: 'x1205' + Addresses scanned: none + Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html + +Authors: + Karen Spearel , + Alessandro Zummo + +Description +----------- + +This module aims to provide complete access to the Xicor X1205 RTC. +Recently Xicor has merged with Intersil, but the chip is +still sold under the Xicor brand. + +This chip is located at address 0x6f and uses a 2-byte register addressing. +Two bytes need to be written to read a single register, while most +other chips just require one and take the second one as the data +to be written. To prevent corrupting unknown chips, the user must +explicitely set the probe parameter. + +example: + +modprobe x1205 probe=0,0x6f + +The module supports one more option, hctosys, which is used to set the +software clock from the x1205. On systems where the x1205 is the +only hardware rtc, this parameter could be used to achieve a correct +date/time earlier in the system boot sequence. + +example: + +modprobe x1205 probe=0,0x6f hctosys=1 diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 6bd44a44cd28..f9fae28f5612 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -126,4 +126,13 @@ config SENSORS_MAX6875 This driver can also be built as a module. If so, the module will be called max6875. +config RTC_X1205_I2C + tristate "Xicor X1205 RTC chip" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Xicor X1205 RTC chip. + + This driver can also be built as a module. If so, the module + will be called x1205. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index a876dd42b860..46178b57b1f1 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o +obj-$(CONFIG_RTC_X1205_I2C) += x1205.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/x1205.c b/drivers/i2c/chips/x1205.c new file mode 100644 index 000000000000..7da366cdc18c --- /dev/null +++ b/drivers/i2c/chips/x1205.c @@ -0,0 +1,698 @@ +/* + * x1205.c - An i2c driver for the Xicor X1205 RTC + * Copyright 2004 Karen Spearel + * Copyright 2005 Alessandro Zummo + * + * please send all reports to: + * kas11 at tampabay dot rr dot com + * a dot zummo at towertech dot it + * + * based on the other drivers in this same directory. + * + * 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 + +#define DRV_VERSION "0.9.9" + +/* Addresses to scan: none. This chip is located at + * 0x6f and uses a two bytes register addressing. + * Two bytes need to be written to read a single register, + * while most other chips just require one and take the second + * one as the data to be written. To prevent corrupting + * unknown chips, the user must explicitely set the probe parameter. + */ + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD; +I2C_CLIENT_MODULE_PARM(hctosys, + "Set the system time from the hardware clock upon initialization"); + +/* offsets into CCR area */ + +#define CCR_SEC 0 +#define CCR_MIN 1 +#define CCR_HOUR 2 +#define CCR_MDAY 3 +#define CCR_MONTH 4 +#define CCR_YEAR 5 +#define CCR_WDAY 6 +#define CCR_Y2K 7 + +#define X1205_REG_SR 0x3F /* status register */ +#define X1205_REG_Y2K 0x37 +#define X1205_REG_DW 0x36 +#define X1205_REG_YR 0x35 +#define X1205_REG_MO 0x34 +#define X1205_REG_DT 0x33 +#define X1205_REG_HR 0x32 +#define X1205_REG_MN 0x31 +#define X1205_REG_SC 0x30 +#define X1205_REG_DTR 0x13 +#define X1205_REG_ATR 0x12 +#define X1205_REG_INT 0x11 +#define X1205_REG_0 0x10 +#define X1205_REG_Y2K1 0x0F +#define X1205_REG_DWA1 0x0E +#define X1205_REG_YRA1 0x0D +#define X1205_REG_MOA1 0x0C +#define X1205_REG_DTA1 0x0B +#define X1205_REG_HRA1 0x0A +#define X1205_REG_MNA1 0x09 +#define X1205_REG_SCA1 0x08 +#define X1205_REG_Y2K0 0x07 +#define X1205_REG_DWA0 0x06 +#define X1205_REG_YRA0 0x05 +#define X1205_REG_MOA0 0x04 +#define X1205_REG_DTA0 0x03 +#define X1205_REG_HRA0 0x02 +#define X1205_REG_MNA0 0x01 +#define X1205_REG_SCA0 0x00 + +#define X1205_CCR_BASE 0x30 /* Base address of CCR */ +#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */ + +#define X1205_SR_RTCF 0x01 /* Clock failure */ +#define X1205_SR_WEL 0x02 /* Write Enable Latch */ +#define X1205_SR_RWEL 0x04 /* Register Write Enable */ + +#define X1205_DTR_DTR0 0x01 +#define X1205_DTR_DTR1 0x02 +#define X1205_DTR_DTR2 0x04 + +#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ + +/* Prototypes */ +static int x1205_attach(struct i2c_adapter *adapter); +static int x1205_detach(struct i2c_client *client); +static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); +static int x1205_command(struct i2c_client *client, unsigned int cmd, + void *arg); + +static struct i2c_driver x1205_driver = { + .owner = THIS_MODULE, + .name = "x1205", + .flags = I2C_DF_NOTIFY, + .attach_adapter = &x1205_attach, + .detach_client = &x1205_detach, +}; + +struct x1205_data { + struct i2c_client client; + struct list_head list; + unsigned int epoch; +}; + +static const unsigned char days_in_mo[] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static LIST_HEAD(x1205_clients); + +/* Workaround until the I2C subsytem will allow to send + * commands to a specific client. This function will send the command + * to the first client. + */ +int x1205_do_command(unsigned int cmd, void *arg) +{ + struct list_head *walk; + struct list_head *tmp; + struct x1205_data *data; + + list_for_each_safe(walk, tmp, &x1205_clients) { + data = list_entry(walk, struct x1205_data, list); + return x1205_command(&data->client, cmd, arg); + } + + return -ENODEV; +} + +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +/* make sure the rtc_time values are in bounds */ +static int x1205_validate_tm(struct rtc_time *tm) +{ + int year = tm->tm_year + 1900; + + if ((tm->tm_year < 70) || (tm->tm_year > 255)) + return -EINVAL; + + if ((tm->tm_mon > 11) || (tm->tm_mday == 0)) + return -EINVAL; + + if (tm->tm_mday > days_in_mo[tm->tm_mon] + + ((tm->tm_mon == 1) && is_leap(year))) + return -EINVAL; + + if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60)) + return -EINVAL; + + return 0; +} + +/* + * In the routines that deal directly with the x1205 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch + * Epoch is initialized as 2000. Time is set to UTC. + */ +static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, + u8 reg_base) +{ + unsigned char dt_addr[2] = { 0, reg_base }; + static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; + + unsigned char buf[8], sr; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, sr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &sr }, /* read status */ + { client->addr, 0, 2, dt_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 8, buf }, /* read date */ + }; + + struct x1205_data *data = i2c_get_clientdata(client); + + /* read status register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + /* check for battery failure */ + if (sr & X1205_SR_RTCF) { + dev_warn(&client->dev, + "Clock had a power failure, you must set the date.\n"); + return -EINVAL; + } + + /* read date registers */ + if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, + "%s: raw read data - sec=%02x, min=%02x, hr=%02x, " + "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + tm->tm_sec = BCD2BIN(buf[CCR_SEC]); + tm->tm_min = BCD2BIN(buf[CCR_MIN]); + tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ + tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); + tm->tm_mon = BCD2BIN(buf[CCR_MONTH]); + data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100; + tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900; + tm->tm_wday = buf[CCR_WDAY]; + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; +} + +static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, + int datetoo, u8 reg_base) +{ + int i, err, xfer; + + unsigned char buf[8]; + + static const unsigned char wel[3] = { 0, X1205_REG_SR, + X1205_SR_WEL }; + + static const unsigned char rwel[3] = { 0, X1205_REG_SR, + X1205_SR_WEL | X1205_SR_RWEL }; + + static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; + + struct x1205_data *data = i2c_get_clientdata(client); + + /* check if all values in the tm struct are correct */ + if ((err = x1205_validate_tm(tm)) < 0) + return err; + + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + buf[CCR_SEC] = BIN2BCD(tm->tm_sec); + buf[CCR_MIN] = BIN2BCD(tm->tm_min); + + /* set hour and 24hr bit */ + buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL; + + /* should we also set the date? */ + if (datetoo) { + buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); + + /* month, 0 - 11 */ + buf[CCR_MONTH] = BIN2BCD(tm->tm_mon); + + /* year, since 1900 */ + buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch); + buf[CCR_WDAY] = tm->tm_wday & 0x07; + buf[CCR_Y2K] = BIN2BCD(data->epoch / 100); + } + + /* this sequence is required to unlock the chip */ + xfer = i2c_master_send(client, wel, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + xfer = i2c_master_send(client, rwel, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + /* write register's data */ + for (i = 0; i < (datetoo ? 8 : 3); i++) { + unsigned char rdata[3] = { 0, reg_base + i, buf[i] }; + + xfer = i2c_master_send(client, rdata, 3); + if (xfer != 3) { + dev_err(&client->dev, + "%s: xfer=%d addr=%02x, data=%02x\n", + __FUNCTION__, + xfer, rdata[1], rdata[2]); + return -EIO; + } + }; + + /* disable further writes */ + xfer = i2c_master_send(client, diswe, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + return 0; +} + +static int x1205_get_dtrim(struct i2c_client *client, int *trim) +{ + unsigned char dtr; + static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR }; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, dtr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */ + }; + + /* read dtr register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr); + + *trim = 0; + + if (dtr & X1205_DTR_DTR0) + *trim += 20; + + if (dtr & X1205_DTR_DTR1) + *trim += 10; + + if (dtr & X1205_DTR_DTR2) + *trim = -*trim; + + return 0; +} + +static int x1205_get_atrim(struct i2c_client *client, int *trim) +{ + s8 atr; + static unsigned char atr_addr[2] = { 0, X1205_REG_ATR }; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, atr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &atr }, /* read atr */ + }; + + /* read atr register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr); + + /* atr is a two's complement value on 6 bits, + * perform sign extension. The formula is + * Catr = (atr * 0.25pF) + 11.00pF. + */ + if (atr & 0x20) + atr |= 0xC0; + + dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr); + + *trim = (atr * 250) + 11000; + + dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim); + + return 0; +} + +static int x1205_hctosys(struct i2c_client *client) +{ + int err; + + struct rtc_time tm; + struct timespec tv; + + err = x1205_command(client, X1205_CMD_GETDATETIME, &tm); + + if (err) { + dev_err(&client->dev, + "Unable to set the system clock\n"); + return err; + } + + /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary + * whether it stores the most close value or the value with partial + * seconds truncated. However, it is important that we use it to store + * the truncated value. This is because otherwise it is necessary, + * in an rtc sync function, to read both xtime.tv_sec and + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read + * of >32bits is not possible. So storing the most close value would + * slow down the sync API. So here we have the truncated value and + * the best guess is to add 0.5s. + */ + + tv.tv_nsec = NSEC_PER_SEC >> 1; + + /* WARNING: this is not the C library 'mktime' call, it is a built in + * inline function from include/linux/time.h. It expects (requires) + * the month to be in the range 1-12 + */ + + tv.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec); + + do_settimeofday(&tv); + + dev_info(&client->dev, + "setting the system clock to %d-%d-%d %d:%d:%d\n", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec); + + return 0; +} + +struct x1205_limit +{ + unsigned char reg; + unsigned char mask; + unsigned char min; + unsigned char max; +}; + +static int x1205_validate_client(struct i2c_client *client) +{ + int i, xfer; + + /* Probe array. We will read the register at the specified + * address and check if the given bits are zero. + */ + static const unsigned char probe_zero_pattern[] = { + /* register, mask */ + X1205_REG_SR, 0x18, + X1205_REG_DTR, 0xF8, + X1205_REG_ATR, 0xC0, + X1205_REG_INT, 0x18, + X1205_REG_0, 0xFF, + }; + + static const struct x1205_limit probe_limits_pattern[] = { + /* register, mask, min, max */ + { X1205_REG_Y2K, 0xFF, 19, 20 }, + { X1205_REG_DW, 0xFF, 0, 6 }, + { X1205_REG_YR, 0xFF, 0, 99 }, + { X1205_REG_MO, 0xFF, 0, 12 }, + { X1205_REG_DT, 0xFF, 0, 31 }, + { X1205_REG_HR, 0x7F, 0, 23 }, + { X1205_REG_MN, 0xFF, 0, 59 }, + { X1205_REG_SC, 0xFF, 0, 59 }, + { X1205_REG_Y2K1, 0xFF, 19, 20 }, + { X1205_REG_Y2K0, 0xFF, 19, 20 }, + }; + + /* check that registers have bits a 0 where expected */ + for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) { + unsigned char buf; + + unsigned char addr[2] = { 0, probe_zero_pattern[i] }; + + struct i2c_msg msgs[2] = { + { client->addr, 0, 2, addr }, + { client->addr, I2C_M_RD, 1, &buf }, + }; + + xfer = i2c_transfer(client->adapter, msgs, 2); + if (xfer != 2) { + dev_err(&client->adapter->dev, + "%s: could not read register %x\n", + __FUNCTION__, addr[1]); + + return -EIO; + } + + if ((buf & probe_zero_pattern[i+1]) != 0) { + dev_err(&client->adapter->dev, + "%s: register=%02x, zero pattern=%d, value=%x\n", + __FUNCTION__, addr[1], i, buf); + + return -ENODEV; + } + } + + /* check limits (only registers with bcd values) */ + for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) { + unsigned char reg, value; + + unsigned char addr[2] = { 0, probe_limits_pattern[i].reg }; + + struct i2c_msg msgs[2] = { + { client->addr, 0, 2, addr }, + { client->addr, I2C_M_RD, 1, ® }, + }; + + xfer = i2c_transfer(client->adapter, msgs, 2); + + if (xfer != 2) { + dev_err(&client->adapter->dev, + "%s: could not read register %x\n", + __FUNCTION__, addr[1]); + + return -EIO; + } + + value = BCD2BIN(reg & probe_limits_pattern[i].mask); + + if (value > probe_limits_pattern[i].max || + value < probe_limits_pattern[i].min) { + dev_dbg(&client->adapter->dev, + "%s: register=%x, lim pattern=%d, value=%d\n", + __FUNCTION__, addr[1], i, value); + + return -ENODEV; + } + } + + return 0; +} + +static int x1205_attach(struct i2c_adapter *adapter) +{ + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + + return i2c_probe(adapter, &addr_data, x1205_probe); +} + +int x1205_direct_attach(int adapter_id, + struct i2c_client_address_data *address_data) +{ + int err; + struct i2c_adapter *adapter = i2c_get_adapter(adapter_id); + + if (adapter) { + err = i2c_probe(adapter, + address_data, x1205_probe); + + i2c_put_adapter(adapter); + + return err; + } + + return -ENODEV; +} + +static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct x1205_data *data; + + int err = 0; + + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + err = -ENODEV; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + /* Initialize our structures */ + data->epoch = 2000; + + client = &data->client; + client->addr = address; + client->driver = &x1205_driver; + client->adapter = adapter; + + strlcpy(client->name, "x1205", I2C_NAME_SIZE); + + i2c_set_clientdata(client, data); + + /* Verify the chip is really an X1205 */ + if (kind < 0) { + if (x1205_validate_client(client) < 0) { + err = -ENODEV; + goto exit_kfree; + } + } + + /* Inform the i2c layer */ + if ((err = i2c_attach_client(client))) + goto exit_kfree; + + list_add(&data->list, &x1205_clients); + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + + /* If requested, set the system time */ + if (hctosys) + x1205_hctosys(client); + + return 0; + +exit_kfree: + kfree(data); + +exit: + return err; +} + +static int x1205_detach(struct i2c_client *client) +{ + int err; + struct x1205_data *data = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s\n", __FUNCTION__); + + if ((err = i2c_detach_client(client))) + return err; + + list_del(&data->list); + + kfree(data); + + return 0; +} + +static int x1205_command(struct i2c_client *client, unsigned int cmd, + void *param) +{ + if (param == NULL) + return -EINVAL; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); + + switch (cmd) { + case X1205_CMD_GETDATETIME: + return x1205_get_datetime(client, param, X1205_CCR_BASE); + + case X1205_CMD_SETTIME: + return x1205_set_datetime(client, param, 0, + X1205_CCR_BASE); + + case X1205_CMD_SETDATETIME: + return x1205_set_datetime(client, param, 1, + X1205_CCR_BASE); + + case X1205_CMD_GETALARM: + return x1205_get_datetime(client, param, X1205_ALM0_BASE); + + case X1205_CMD_SETALARM: + return x1205_set_datetime(client, param, 1, + X1205_ALM0_BASE); + + case X1205_CMD_GETDTRIM: + return x1205_get_dtrim(client, param); + + case X1205_CMD_GETATRIM: + return x1205_get_atrim(client, param); + + default: + return -EINVAL; + } +} + +static int __init x1205_init(void) +{ + return i2c_add_driver(&x1205_driver); +} + +static void __exit x1205_exit(void) +{ + i2c_del_driver(&x1205_driver); +} + +MODULE_AUTHOR( + "Karen Spearel , " + "Alessandro Zummo "); +MODULE_DESCRIPTION("Xicor X1205 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +EXPORT_SYMBOL_GPL(x1205_do_command); +EXPORT_SYMBOL_GPL(x1205_direct_attach); + +module_init(x1205_init); +module_exit(x1205_exit); diff --git a/include/linux/x1205.h b/include/linux/x1205.h new file mode 100644 index 000000000000..64fd3af894a5 --- /dev/null +++ b/include/linux/x1205.h @@ -0,0 +1,31 @@ +/* + * x1205.h - defines for drivers/i2c/chips/x1205.c + * Copyright 2004 Karen Spearel + * Copyright 2005 Alessandro Zummo + * + * 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 __LINUX_X1205_H__ +#define __LINUX_X1205_H__ + +/* commands */ + +#define X1205_CMD_GETDATETIME 0 +#define X1205_CMD_SETTIME 1 +#define X1205_CMD_SETDATETIME 2 +#define X1205_CMD_GETALARM 3 +#define X1205_CMD_SETALARM 4 +#define X1205_CMD_GETDTRIM 5 +#define X1205_CMD_SETDTRIM 6 +#define X1205_CMD_GETATRIM 7 +#define X1205_CMD_SETATRIM 8 + +extern int x1205_do_command(unsigned int cmd, void *arg); +extern int x1205_direct_attach(int adapter_id, + struct i2c_client_address_data *address_data); + +#endif /* __LINUX_X1205_H__ */ From 2286066faf51890e49ad61e2ceab683666cd9108 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 17 Oct 2005 23:07:05 +0200 Subject: [PATCH 1050/1939] [PATCH] i2c: kzalloc conversion, ixp bus drivers Use kzalloc instead of kmalloc+memzero in the ixp2000 and ixp4xx I2C bus drivers. Signed-off-by: Deepak Saxena Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-ixp2000.c | 3 +-- drivers/i2c/busses/i2c-ixp4xx.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index c3292dc743f1..42016ee6ef13 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -106,11 +106,10 @@ static int ixp2000_i2c_probe(struct device *dev) struct platform_device *plat_dev = to_platform_device(dev); struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data; struct ixp2000_i2c_data *drv_data = - kmalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); + kzalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; - memzero(drv_data, sizeof(*drv_data)); drv_data->gpio_pins = gpio; drv_data->algo_data.data = gpio; diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 3169280c25a6..69303ab65e04 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -107,12 +107,11 @@ static int ixp4xx_i2c_probe(struct device *dev) struct platform_device *plat_dev = to_platform_device(dev); struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data; struct ixp4xx_i2c_data *drv_data = - kmalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); + kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); if(!drv_data) return -ENOMEM; - memzero(drv_data, sizeof(struct ixp4xx_i2c_data)); drv_data->gpio_pins = gpio; /* From ba9c2e8d15da029ea3051c95e446b2d638ef02e2 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 17 Oct 2005 23:08:32 +0200 Subject: [PATCH 1051/1939] [PATCH] hwmon: kzalloc conversion Use kzalloc instead of kmalloc+memset in all hardware monitoring drivers. Signed-off-by: Deepak Saxena Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1021.c | 3 +-- drivers/hwmon/adm1025.c | 3 +-- drivers/hwmon/adm1026.c | 4 +--- drivers/hwmon/adm1031.c | 3 +-- drivers/hwmon/asb100.c | 11 ++++------- drivers/hwmon/atxp1.c | 3 +-- drivers/hwmon/ds1621.c | 3 +-- drivers/hwmon/fscher.c | 3 +-- drivers/hwmon/fscpos.c | 3 +-- drivers/hwmon/gl518sm.c | 3 +-- drivers/hwmon/gl520sm.c | 3 +-- drivers/hwmon/it87.c | 3 +-- drivers/hwmon/lm63.c | 3 +-- drivers/hwmon/lm75.c | 3 +-- drivers/hwmon/lm77.c | 3 +-- drivers/hwmon/lm78.c | 3 +-- drivers/hwmon/lm80.c | 3 +-- drivers/hwmon/lm83.c | 3 +-- drivers/hwmon/lm85.c | 3 +-- drivers/hwmon/lm87.c | 3 +-- drivers/hwmon/lm90.c | 3 +-- drivers/hwmon/lm92.c | 3 +-- drivers/hwmon/max1619.c | 3 +-- drivers/hwmon/pc87360.c | 3 +-- drivers/hwmon/sis5595.c | 3 +-- drivers/hwmon/smsc47b397.c | 3 +-- drivers/hwmon/smsc47m1.c | 3 +-- drivers/hwmon/via686a.c | 3 +-- drivers/hwmon/w83627ehf.c | 3 +-- drivers/hwmon/w83627hf.c | 3 +-- drivers/hwmon/w83781d.c | 10 +++------- drivers/hwmon/w83792d.c | 6 ++---- drivers/hwmon/w83l785ts.c | 4 +--- 33 files changed, 39 insertions(+), 80 deletions(-) diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 58aee3a00caa..8102876c7c3f 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -204,11 +204,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access adm1021_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { err = -ENOMEM; goto error0; } - memset(data, 0, sizeof(struct adm1021_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 526b7ff179eb..3ec12421694f 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -331,11 +331,10 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1025_data)); /* The common I2C client data is placed right before the ADM1025-specific data. */ diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 625158110fd4..3b5814183738 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1470,13 +1470,11 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access adm1026_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1026_data)); - new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 58338ed7c8a1..7c545d5eee45 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -740,11 +740,10 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1031_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 8e34855a6274..52c469722a65 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -629,19 +629,17 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, int i, id, err; struct asb100_data *data = i2c_get_clientdata(new_client); - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[1])) { err = -ENOMEM; goto ERROR_SC_1; } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); id = i2c_adapter_id(adapter); @@ -724,12 +722,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access asb100_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); + if (!(data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL))) { + pr_debug("asb100.o: detect failed, kzalloc failed!\n"); err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct asb100_data)); new_client = &data->client; init_MUTEX(&data->lock); diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 441324fc6b8b..53324f56404e 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -268,12 +268,11 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct atxp1_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index e1ff22cf984a..c5afa0058308 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -202,11 +202,10 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct ds1621_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index eef6061d786b..a02e1c34c757 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -303,11 +303,10 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the * client structure, even though we cannot fill it completely yet. * But it allows us to access i2c_smbus_read_byte_data. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct fscher_data)); /* The common I2C client data is placed right before the * Hermes-specific data. */ diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 5fc77a5fed07..a378e4f5c93b 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -453,11 +453,10 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) * But it allows us to access fscpos_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct fscpos_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 256b9323c84b..2f178dbe3d87 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -365,11 +365,10 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access gl518_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct gl518_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 12fd757066fc..c39ba1239426 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -536,11 +536,10 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access gl520_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct gl520_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 55e1c835a046..9a5b8b268397 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -761,11 +761,10 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access it87_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct it87_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct it87_data)); new_client = &data->client; if (is_isa) diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index be5c7095ecbb..954ec2497249 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -375,11 +375,10 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm63_data)); /* The common I2C client data is placed right before the LM63-specific data. */ diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 9a3ebdf583f4..d70f4c8fc1e6 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -127,11 +127,10 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm75_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 866eab96a6f6..9380fda7dcd1 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -226,11 +226,10 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm77_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm77_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index d697a554286f..924462362743 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -540,11 +540,10 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access lm78_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct lm78_data)); new_client = &data->client; if (is_isa) diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 83af8b3a0cac..b4cd6c661f11 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -407,11 +407,10 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm80_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index d74b2c20c719..9a70611a9f69 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -230,11 +230,10 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm83_data)); /* The common I2C client data is placed right after the * LM83-specific data. */ diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index ab214df9624b..d5537a5377f7 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1033,11 +1033,10 @@ int lm85_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access lm85_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm85_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct lm85_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index dca996de4c33..eeec18177861 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -554,11 +554,10 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm87_data)); /* The common I2C client data is placed right before the LM87-specific data. */ diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 14de05fcd431..dad0f1074956 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -370,11 +370,10 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm90_data)); /* The common I2C client data is placed right before the LM90-specific data. */ diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 647b7c7cd575..7a4b3701ed1a 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -300,11 +300,10 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_WORD_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm92_data)); /* Fill in enough client fields so that we can read from the chip, which is required for identication */ diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 16bf71f3a04d..6a82ffae1bfd 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -197,11 +197,10 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct max1619_data)); /* The common I2C client data is placed right before the MAX1619-specific data. */ diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index cf2a35799c7c..17f745a23d04 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -754,9 +754,8 @@ static int pc87360_detect(struct i2c_adapter *adapter) const char *name = "pc87360"; int use_thermistors = 0; - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) return -ENOMEM; - memset(data, 0x00, sizeof(struct pc87360_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 21aa9a41f62c..9c6cadec1087 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -518,11 +518,10 @@ static int sis5595_detect(struct i2c_adapter *adapter) goto exit_release; } - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct sis5595_data)); new_client = &data->client; new_client->addr = address; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 37ed8b33f01a..2a3e21b5b6b4 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -244,11 +244,10 @@ static int smsc47b397_detect(struct i2c_adapter *adapter) return -EBUSY; } - if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { err = -ENOMEM; goto error_release; } - memset(data, 0x00, sizeof(struct smsc47b397_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index c9cc683eba4a..bbe93a0688ec 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -396,11 +396,10 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) return -EBUSY; } - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { err = -ENOMEM; goto error_release; } - memset(data, 0x00, sizeof(struct smsc47m1_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index c6e64f4abdea..6f696f897176 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -621,11 +621,10 @@ static int via686a_detect(struct i2c_adapter *adapter) return -ENODEV; } - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct via686a_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 685eeb766809..eee22a57e929 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -681,11 +681,10 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) goto exit; } - if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct w83627ehf_data)); client = &data->client; i2c_set_clientdata(client, data); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 48270819ff99..70ef926c3bd8 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1045,11 +1045,10 @@ static int w83627hf_detect(struct i2c_adapter *adapter) client structure, even though we cannot fill it completely yet. But it allows us to access w83627hf_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct w83627hf_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 26b1fac7c619..9265f32122fa 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -889,12 +889,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, const char *client_name = ""; struct w83781d_data *data = i2c_get_clientdata(new_client); - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); id = i2c_adapter_id(adapter); @@ -919,13 +918,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, } if (kind != w83783s) { - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[1])) { err = -ENOMEM; goto ERROR_SC_1; } - memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); if (force_subclients[0] == id && force_subclients[1] == address) { @@ -1064,11 +1061,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access w83781d_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct w83781d_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 7bbd1888ce94..4be59dbb78c4 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1086,11 +1086,10 @@ w83792d_create_subclient(struct i2c_adapter *adapter, int err; struct i2c_client *sub_client; - (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + (*sub_cli) = sub_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(sub_client)) { return -ENOMEM; } - memset(sub_client, 0x00, sizeof(struct i2c_client)); sub_client->addr = 0x48 + addr; i2c_set_clientdata(sub_client, NULL); sub_client->adapter = adapter; @@ -1184,11 +1183,10 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access w83792d_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct w83792d_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index db12a620b331..f495b6378668 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -156,12 +156,10 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct w83l785ts_data)); - /* The common I2C client data is placed right before the * W83L785TS-specific data. */ From 5263ebb51eb098b01caf229498c954999117e4a7 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 17 Oct 2005 23:09:43 +0200 Subject: [PATCH 1052/1939] [PATCH] i2c: kzalloc conversion, other drivers Use kzalloc instead of kmalloc+memset in all remaining i2c bus and chip drivers. Signed-off-by: Deepak Saxena Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-amd8111.c | 3 +-- drivers/i2c/busses/i2c-ibm_iic.c | 3 +-- drivers/i2c/busses/i2c-iop3xx.c | 6 ++---- drivers/i2c/busses/i2c-keywest.c | 3 +-- drivers/i2c/busses/i2c-mpc.c | 3 +-- drivers/i2c/busses/i2c-mv64xxx.c | 5 +---- drivers/i2c/busses/i2c-nforce2.c | 3 +-- drivers/i2c/busses/i2c-parport.c | 5 ++--- drivers/i2c/busses/i2c-pmac-smu.c | 3 +-- drivers/i2c/busses/i2c-prosavage.c | 4 +--- drivers/i2c/busses/scx200_acb.c | 3 +-- drivers/i2c/chips/ds1337.c | 3 +-- drivers/i2c/chips/ds1374.c | 3 +-- drivers/i2c/chips/eeprom.c | 3 +-- drivers/i2c/chips/m41t00.c | 3 +-- drivers/i2c/chips/max6875.c | 6 ++---- drivers/i2c/chips/pca9539.c | 3 +-- drivers/i2c/chips/pcf8574.c | 3 +-- drivers/i2c/chips/pcf8591.c | 3 +-- drivers/i2c/chips/rtc8564.c | 3 +-- drivers/i2c/chips/tps65010.c | 3 +-- drivers/i2c/i2c-dev.c | 3 +-- 22 files changed, 25 insertions(+), 52 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 0d29e78dff63..aface7938a5b 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -344,10 +344,9 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) return -ENODEV; - smbus = kmalloc(sizeof(struct amd_smbus), GFP_KERNEL); + smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL); if (!smbus) return -ENOMEM; - memset(smbus, 0, sizeof(struct amd_smbus)); smbus->dev = dev; smbus->base = pci_resource_start(dev, 0); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index a3ed9590f028..1a587253d716 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -672,13 +672,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){ printk(KERN_WARNING"ibm-iic%d: missing additional data!\n", ocp->def->index); - if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){ + if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) { printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n", ocp->def->index); return -ENOMEM; } - memset(dev, 0, sizeof(*dev)); dev->idx = ocp->def->index; ocp_set_drvdata(ocp, dev); diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 0f7dfd8f4546..9888fae1f37a 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -440,19 +440,17 @@ iop3xx_i2c_probe(struct device *dev) struct i2c_adapter *new_adapter; struct i2c_algo_iop3xx_data *adapter_data; - new_adapter = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); if (!new_adapter) { ret = -ENOMEM; goto out; } - memset((void*)new_adapter, 0, sizeof(*new_adapter)); - adapter_data = kmalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); + adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); if (!adapter_data) { ret = -ENOMEM; goto free_adapter; } - memset((void*)adapter_data, 0, sizeof(*adapter_data)); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 34e43c8d8d5e..ef281e0c567b 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -535,13 +535,12 @@ create_iface(struct device_node *np, struct device *dev) tsize = sizeof(struct keywest_iface) + (sizeof(struct keywest_chan) + 4) * nchan; - iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); + iface = (struct keywest_iface *) kzalloc(tsize, GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); pmac_low_i2c_unlock(np); return -ENOMEM; } - memset(iface, 0, tsize); spin_lock_init(&iface->lock); init_completion(&iface->complete); iface->node = of_node_get(np); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index b81c54620030..8491633005b8 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -296,10 +296,9 @@ static int fsl_i2c_probe(struct device *device) pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data; - if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { + if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) { return -ENOMEM; } - memset(i2c, 0, sizeof(*i2c)); i2c->irq = platform_get_irq(pdev, 0); i2c->flags = pdata->device_flags; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 69709ee0b896..d0d2a6f1386e 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -500,13 +500,10 @@ mv64xxx_i2c_probe(struct device *dev) if ((pd->id != 0) || !pdata) return -ENODEV; - drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); - + drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; - memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); - if (mv64xxx_i2c_map_regs(pd, drv_data)) { rc = -ENODEV; goto exit_kfree; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 5dc62114cc8d..87b6e26aa8a0 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -313,10 +313,9 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ int res1, res2; /* we support 2 SMBus adapters */ - if (!(smbuses = (void *)kmalloc(2*sizeof(struct nforce2_smbus), + if (!(smbuses = (void *)kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL))) return -ENOMEM; - memset (smbuses, 0, 2*sizeof(struct nforce2_smbus)); pci_set_drvdata(dev, smbuses); /* SMBus adapter 1 */ diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index fa506187fbe1..2854d858fc9b 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -155,12 +155,11 @@ static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; - adapter = kmalloc(sizeof(struct i2c_par), GFP_KERNEL); + adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL); if (adapter == NULL) { - printk(KERN_ERR "i2c-parport: Failed to kmalloc\n"); + printk(KERN_ERR "i2c-parport: Failed to kzalloc\n"); return; } - memset(adapter, 0x00, sizeof(struct i2c_par)); pr_debug("i2c-parport: attaching to %s\n", port->name); adapter->pdev = parport_register_device(port, "i2c-parport", diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c index 8a9f5648a23d..bfefe7f7a53d 100644 --- a/drivers/i2c/busses/i2c-pmac-smu.c +++ b/drivers/i2c/busses/i2c-pmac-smu.c @@ -211,12 +211,11 @@ static int create_iface(struct device_node *np, struct device *dev) } busid = *reg; - iface = kmalloc(sizeof(struct smu_iface), GFP_KERNEL); + iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n"); return -ENOMEM; } - memset(iface, 0, sizeof(struct smu_iface)); init_completion(&iface->complete); iface->busid = busid; diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 92b744273577..42f8b5ce3bf8 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -241,14 +241,12 @@ static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_devic struct s_i2c_chip *chip; struct s_i2c_bus *bus; - pci_set_drvdata(dev, kmalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); + pci_set_drvdata(dev, kzalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); chip = (struct s_i2c_chip *)pci_get_drvdata(dev); if (chip == NULL) { return -ENOMEM; } - memset(chip, 0, sizeof(struct s_i2c_chip)); - base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK; len = dev->resource[0].end - base + 1; chip->mmio = ioremap_nocache(base, len); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index a1d580e05361..d3478e084522 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -442,14 +442,13 @@ static int __init scx200_acb_create(int base, int index) int rc = 0; char description[64]; - iface = kmalloc(sizeof(*iface), GFP_KERNEL); + iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { printk(KERN_ERR NAME ": can't allocate memory\n"); rc = -ENOMEM; goto errout; } - memset(iface, 0, sizeof(*iface)); adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 9d3175c03395..01b037007410 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -243,11 +243,10 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) I2C_FUNC_I2C)) goto exit; - if (!(data = kmalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct ds1337_data)); INIT_LIST_HEAD(&data->list); /* The common I2C client data is placed right before the diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index ec640e9f085a..1596e6478782 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -193,11 +193,10 @@ static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *client; int rc; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!client) return -ENOMEM; - memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); client->addr = addr; client->adapter = adap; diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 7fb739c43935..ee7cbc823fd1 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -171,11 +171,10 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_BYTE)) goto exit; - if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct eeprom_data)); new_client = &data->client; memset(data->data, 0xff, EEPROM_SIZE); diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 554f7ba61627..3df309ae44a6 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -174,11 +174,10 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *client; int rc; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!client) return -ENOMEM; - memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE); client->addr = addr; client->adapter = adap; diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 9e1aeb69abf9..b376a006883c 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -179,16 +179,14 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) if (address & 1) return 0; - if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) + if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) return -ENOMEM; - memset(data, 0, sizeof(struct max6875_data)); /* A fake client is created on the odd address */ - if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { err = -ENOMEM; goto exit_kfree1; } - memset(fake_client, 0, sizeof(struct i2c_client)); /* Init real i2c_client */ real_client = &data->client; diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c index 225577fdda4d..59a930346229 100644 --- a/drivers/i2c/chips/pca9539.c +++ b/drivers/i2c/chips/pca9539.c @@ -122,11 +122,10 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pca9539_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 6525743ff9fd..2c2555d46fdf 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -127,11 +127,10 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pcf8574_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 80f1df9a4500..3c815b153249 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -178,11 +178,10 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pcf8591_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index dd9d42d7b6e7..916cdc1af23c 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -148,12 +148,11 @@ static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) {addr, I2C_M_RD, 2, data} }; - d = kmalloc(sizeof(struct rtc8564_data), GFP_KERNEL); + d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL); if (!d) { ret = -ENOMEM; goto done; } - memset(d, 0, sizeof(struct rtc8564_data)); new_client = &d->client; strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 280e9638c0f8..280dd7a45db6 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -500,11 +500,10 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) return 0; } - tps = kmalloc(sizeof *tps, GFP_KERNEL); + tps = kzalloc(sizeof *tps, GFP_KERNEL); if (!tps) return 0; - memset(tps, 0, sizeof *tps); init_MUTEX(&tps->lock); INIT_WORK(&tps->work, tps65010_work, tps); tps->irq = -1; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 89f54a5e8484..276ec42a0717 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -80,10 +80,9 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) { struct i2c_dev *i2c_dev; - i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL); + i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) return ERR_PTR(-ENOMEM); - memset(i2c_dev, 0x00, sizeof(*i2c_dev)); spin_lock(&i2c_dev_array_lock); if (i2c_dev_array[adap->nr]) { From 078d9fe4fe8dada13e37d2e2790b0ad780324097 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 17 Oct 2005 23:12:36 +0200 Subject: [PATCH 1053/1939] [PATCH] i2c: kzalloc cleanups, 1 of 2 Drop useless casts on kzalloc returned values, as suggested by Jiri Slaby. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-keywest.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index ef281e0c567b..d61f748278fc 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -535,7 +535,7 @@ create_iface(struct device_node *np, struct device *dev) tsize = sizeof(struct keywest_iface) + (sizeof(struct keywest_chan) + 4) * nchan; - iface = (struct keywest_iface *) kzalloc(tsize, GFP_KERNEL); + iface = kzalloc(tsize, GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); pmac_low_i2c_unlock(np); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 87b6e26aa8a0..9b4247610815 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -313,8 +313,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ int res1, res2; /* we support 2 SMBus adapters */ - if (!(smbuses = (void *)kzalloc(2*sizeof(struct nforce2_smbus), - GFP_KERNEL))) + if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL))) return -ENOMEM; pci_set_drvdata(dev, smbuses); From deb875c7ff2ef417a2daff41ee4b357098b7ab10 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 17 Oct 2005 23:14:31 +0200 Subject: [PATCH 1054/1939] [PATCH] i2c: kzalloc cleanups, 2 of 2 Use kzalloc instead of kmalloc in the S4882 SMBus multiplexing driver. I guess it's safer that way. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-amd756-s4882.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 4e553e8c5cba..f51ab652300a 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -169,12 +169,12 @@ static int __init amd756_s4882_init(void) init_MUTEX(&amd756_lock); /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kmalloc(5 * sizeof(struct i2c_adapter), + if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL))) { error = -ENOMEM; goto ERROR1; } - if (!(s4882_algo = kmalloc(5 * sizeof(struct i2c_algorithm), + if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL))) { error = -ENOMEM; goto ERROR2; From 2445eb62e98250f1ec8cbc8cf7c4be9cfafe88e5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 17 Oct 2005 23:16:25 +0200 Subject: [PATCH 1055/1939] [PATCH] i2c: Documentation update Update the i2c documentation: kzalloc should be used instead of kmalloc. I also fixed a couple other things nearby in writing-clients, as several past changes had never been reported there. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/porting-clients | 2 +- Documentation/i2c/writing-clients | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index 4849dfd6961c..184fac2377aa 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -82,7 +82,7 @@ Technical changes: exit and exit_free. For i2c+isa drivers, labels should be named ERROR0, ERROR1 and ERROR2. Don't forget to properly set err before jumping to error labels. By the way, labels should be left-aligned. - Use memset to fill the client and data area with 0x00. + Use kzalloc instead of kmalloc. Use i2c_set_clientdata to set the client data (as opposed to a direct access to client->data). Use strlcpy instead of strcpy to copy the client name. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 1882811c7f5d..e94d9c6cc522 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -55,6 +55,7 @@ be very useful. An example structure is below. struct foo_data { + struct i2c_client client; struct semaphore lock; /* For ISA access in `sensors' drivers. */ int sysctl_id; /* To keep the /proc directory entry for `sensors' drivers. */ @@ -307,22 +308,15 @@ For now, you can ignore the `flags' parameter. It is there for future use. client structure, even though we cannot fill it completely yet. But it allows us to access several i2c functions safely */ - /* Note that we reserve some space for foo_data too. If you don't - need it, remove it. We do it here to help to lessen memory - fragmentation. */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct foo_data), - GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct foo_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } - /* This is tricky, but it will set the data to the right value. */ - client->data = new_client + 1; - data = (struct foo_data *) (client->data); + new_client = &data->client; + i2c_set_clientdata(new_client, data); new_client->addr = address; - new_client->data = data; new_client->adapter = adapter; new_client->driver = &foo_driver; new_client->flags = 0; @@ -448,7 +442,7 @@ much simpler than the attachment code, fortunately! release_region(client->addr,LM78_EXTENT); /* HYBRID SENSORS CHIP ONLY END */ - kfree(client); /* Frees client data too, if allocated at the same time */ + kfree(data); return 0; } From 6536c49a1ee2bd85eee0e7fa41e67c5743f2f93e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 26 Oct 2005 21:04:12 +0200 Subject: [PATCH 1056/1939] [PATCH] i2c: Static function fixes, 1 of 4 eeprom_detect is first declared static and then when the function is actually implemented, there is no static. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index ee7cbc823fd1..4baf573fa04f 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -155,7 +155,7 @@ static int eeprom_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) +static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct eeprom_data *data; From d8d2061590c87c20bf78133461bc74df78803ecb Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 26 Oct 2005 21:05:46 +0200 Subject: [PATCH 1057/1939] [PATCH] hwmon: Static function fixes, 2 of 4 lm78.c and lm85.c have a number of items declared static then implemented without the static on them. The following patch fixes these sparse errors. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm78.c | 2 +- drivers/hwmon/lm85.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 924462362743..bde0cda9477e 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -480,7 +480,7 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) { int i, err; struct i2c_client *new_client; diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index d5537a5377f7..d1070ed2bee6 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1007,14 +1007,14 @@ temp_auto(1); temp_auto(2); temp_auto(3); -int lm85_attach_adapter(struct i2c_adapter *adapter) +static int lm85_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_probe(adapter, &addr_data, lm85_detect); } -int lm85_detect(struct i2c_adapter *adapter, int address, +static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { int company, verstep ; @@ -1235,7 +1235,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address, return err; } -int lm85_detach_client(struct i2c_client *client) +static int lm85_detach_client(struct i2c_client *client) { struct lm85_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); @@ -1245,7 +1245,7 @@ int lm85_detach_client(struct i2c_client *client) } -int lm85_read_value(struct i2c_client *client, u8 reg) +static int lm85_read_value(struct i2c_client *client, u8 reg) { int res; @@ -1275,7 +1275,7 @@ int lm85_read_value(struct i2c_client *client, u8 reg) return res ; } -int lm85_write_value(struct i2c_client *client, u8 reg, int value) +static int lm85_write_value(struct i2c_client *client, u8 reg, int value) { int res ; @@ -1304,7 +1304,7 @@ int lm85_write_value(struct i2c_client *client, u8 reg, int value) return res ; } -void lm85_init_client(struct i2c_client *client) +static void lm85_init_client(struct i2c_client *client) { int value; struct lm85_data *data = i2c_get_clientdata(client); From c49efceffa599299ab3f38b1cdf8c2f1bf9811c4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 26 Oct 2005 21:07:25 +0200 Subject: [PATCH 1058/1939] [PATCH] hwmon: Static function fixes, 3 of 4 Fixup functions that have been declared static and then actually defined without the static on. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1026.c | 18 +++++++++--------- drivers/hwmon/ds1621.c | 4 ++-- drivers/hwmon/fscpos.c | 2 +- drivers/hwmon/it87.c | 2 +- drivers/hwmon/lm80.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 3b5814183738..e0f56549d1d8 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -315,7 +315,7 @@ static struct i2c_driver adm1026_driver = { .detach_client = adm1026_detach_client, }; -int adm1026_attach_adapter(struct i2c_adapter *adapter) +static int adm1026_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; @@ -323,7 +323,7 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1026_detect); } -int adm1026_detach_client(struct i2c_client *client) +static int adm1026_detach_client(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); @@ -332,7 +332,7 @@ int adm1026_detach_client(struct i2c_client *client) return 0; } -int adm1026_read_value(struct i2c_client *client, u8 reg) +static int adm1026_read_value(struct i2c_client *client, u8 reg) { int res; @@ -346,7 +346,7 @@ int adm1026_read_value(struct i2c_client *client, u8 reg) return res; } -int adm1026_write_value(struct i2c_client *client, u8 reg, int value) +static int adm1026_write_value(struct i2c_client *client, u8 reg, int value) { int res; @@ -360,7 +360,7 @@ int adm1026_write_value(struct i2c_client *client, u8 reg, int value) return res; } -void adm1026_init_client(struct i2c_client *client) +static void adm1026_init_client(struct i2c_client *client) { int value, i; struct adm1026_data *data = i2c_get_clientdata(client); @@ -460,7 +460,7 @@ void adm1026_init_client(struct i2c_client *client) } } -void adm1026_print_gpio(struct i2c_client *client) +static void adm1026_print_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); int i; @@ -492,7 +492,7 @@ void adm1026_print_gpio(struct i2c_client *client) } } -void adm1026_fixup_gpio(struct i2c_client *client) +static void adm1026_fixup_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); int i; @@ -1452,8 +1452,8 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind) +static int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind) { int company, verstep; struct i2c_client *new_client; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index c5afa0058308..34f71b7c7f37 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -186,8 +186,8 @@ static int ds1621_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind) +static int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind) { int conf, temp; struct i2c_client *new_client; diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index a378e4f5c93b..64e4edc64f8d 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -438,7 +438,7 @@ static int fscpos_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, fscpos_detect); } -int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) +static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct fscpos_data *data; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 9a5b8b268397..6c41e25e670b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -738,7 +738,7 @@ static int __init it87_find(unsigned short *address) } /* This function is called by i2c_probe */ -int it87_detect(struct i2c_adapter *adapter, int address, int kind) +static int it87_detect(struct i2c_adapter *adapter, int address, int kind) { int i; struct i2c_client *new_client; diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index b4cd6c661f11..c359fdea211e 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -393,7 +393,7 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm80_detect); } -int lm80_detect(struct i2c_adapter *adapter, int address, int kind) +static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) { int i, cur; struct i2c_client *new_client; From 6344a8ece0bacccf61817450e8ccf78c973fc0c5 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 26 Oct 2005 21:09:41 +0200 Subject: [PATCH 1059/1939] [PATCH] i2c: Static function fixes, 4 of 4 Fix functions declared static and then implemented without the static in drivers/i2c/chips. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/ds1374.c | 3 ++- drivers/i2c/chips/pcf8574.c | 2 +- drivers/i2c/chips/pcf8591.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 1596e6478782..da488b735abf 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -167,7 +167,8 @@ static void ds1374_set_tlet(ulong arg) static ulong new_time; -DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); +static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, + (ulong) & new_time); int ds1374_set_rtc_time(ulong nowtime) { diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 2c2555d46fdf..c323c2de236c 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -115,7 +115,7 @@ static int pcf8574_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) +static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct pcf8574_data *data; diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 3c815b153249..ce420a67560b 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -166,7 +166,7 @@ static int pcf8591_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) +static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct pcf8591_data *data; From cd19cc4732395eb3dbaf49042233b5ac69b1fbd3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:14:16 +0200 Subject: [PATCH 1060/1939] [PATCH] i2c: ID redefinition cleanups Fix several redefinitions of i2c IDs. i2c IDs must not be defined outside of i2c-id.h. Signed-off-by: Jean Delvare Signed-off-by: Henk Vergonet Acked-by: Mark McClelland Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-prosavage.c | 5 ----- include/media/ovcamchip.h | 14 -------------- 2 files changed, 19 deletions(-) diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 42f8b5ce3bf8..42cb1d8ca659 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -83,11 +83,6 @@ struct s_i2c_chip { /* * i2c configuration */ -#ifndef I2C_HW_B_S3VIA -#define I2C_HW_B_S3VIA 0x18 /* S3VIA ProSavage adapter */ -#endif - -/* delays */ #define CYCLE_DELAY 10 #define TIMEOUT (HZ / 2) diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h index cb7c0aa96f22..8138983adced 100644 --- a/include/media/ovcamchip.h +++ b/include/media/ovcamchip.h @@ -17,20 +17,6 @@ #include #include -/* Remove these once they are officially defined */ -#ifndef I2C_DRIVERID_OVCAMCHIP - #define I2C_DRIVERID_OVCAMCHIP 0xf00f -#endif -#ifndef I2C_HW_SMBUS_OV511 - #define I2C_HW_SMBUS_OV511 0xfe -#endif -#ifndef I2C_HW_SMBUS_OV518 - #define I2C_HW_SMBUS_OV518 0xff -#endif -#ifndef I2C_HW_SMBUS_OVFX2 - #define I2C_HW_SMBUS_OVFX2 0xfd -#endif - /* --------------------------------- */ /* ENUMERATIONS */ /* --------------------------------- */ From eb00a28ae1a8fc4b3914f94ab1944396b8dda9fc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:20:17 +0200 Subject: [PATCH 1061/1939] [PATCH] i2c: Drop unused parport i2c IDs Drop unused i2c-over-parallel-port i2c IDs: * I2C_HW_B_LPC was never actually used as far as I could search. * I2C_HW_B_ELV and I2C_HW_B_VELLE are no more used since the introduction of the unified i2c-parport driver in Linux 2.6.2. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c-id.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 44f30876a1c9..1ce4b54caa21 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -164,10 +164,7 @@ /* --- Bit algorithm adapters */ #define I2C_HW_B_LP 0x010000 /* Parallel port Philips style */ -#define I2C_HW_B_LPC 0x010001 /* Parallel port control reg. */ #define I2C_HW_B_SER 0x010002 /* Serial line interface */ -#define I2C_HW_B_ELV 0x010003 /* ELV Card */ -#define I2C_HW_B_VELLE 0x010004 /* Vellemann K8000 */ #define I2C_HW_B_BT848 0x010005 /* BT848 video boards */ #define I2C_HW_B_WNV 0x010006 /* Winnov Videums */ #define I2C_HW_B_VIA 0x010007 /* Via vt82c586b */ From 142078f6f09986c2b8f5ebe215ce405438080317 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:21:50 +0200 Subject: [PATCH 1062/1939] [PATCH] i2c: i2c-i810 documentation update Update the documented list of devices supported by the i2c-i810 driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/busses/i2c-i810 | 1 + drivers/i2c/busses/Kconfig | 3 ++- drivers/i2c/busses/i2c-i810.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810 index 0544eb332887..83c3b9743c3c 100644 --- a/Documentation/i2c/busses/i2c-i810 +++ b/Documentation/i2c/busses/i2c-i810 @@ -2,6 +2,7 @@ Kernel driver i2c-i810 Supported adapters: * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH) + * Intel 82845G (GMCH) Authors: Frodo Looijaard , diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3badfec75b1c..4010fe92e72b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -135,11 +135,12 @@ config I2C_I810 help If you say yes to this option, support will be included for the Intel 810/815 family of mainboard I2C interfaces. Specifically, the - following versions of the chipset is supported: + following versions of the chipset are supported: i810AA i810AB i810E i815 + i845G This driver can also be built as a module. If so, the module will be called i2c-i810. diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 1b3393b7c461..52bc30593bd7 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -32,6 +32,7 @@ i810AB 7123 i810E 7125 i815 1132 + i845G 2562 */ #include From b8095544bc27044a7aa79e1e073b781a249910c3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:25:04 +0200 Subject: [PATCH 1063/1939] [PATCH] i2c: SMBus PEC support rewrite, 1 of 3 Discard I2C_FUNC_SMBUS_*_PEC defines. i2c clients are not supposed to check for PEC support of i2c bus drivers on individual SMBus transactions, and i2c bus drivers are not supposed to advertise them. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 3 +-- include/linux/i2c.h | 18 ------------------ 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e90b6c4e7da3..b05e045f770c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -513,8 +513,7 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC | - I2C_FUNC_SMBUS_HWPEC_CALC : 0); + | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0); } static struct i2c_algorithm smbus_algorithm = { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 64c13c042f9d..bcd4bb1b450c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -389,10 +389,6 @@ struct i2c_msg { #define I2C_FUNC_10BIT_ADDR 0x00000002 #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ #define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 @@ -408,8 +404,6 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ -#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE) @@ -423,17 +417,6 @@ struct i2c_msg { I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) #define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) -#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC) -#define I2C_FUNC_SMBUS_WORD_DATA_PEC (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC) - -#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA -#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA -#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA -#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA -#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA -#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA #define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ I2C_FUNC_SMBUS_BYTE | \ @@ -441,7 +424,6 @@ struct i2c_msg { I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_PROC_CALL | \ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ I2C_FUNC_SMBUS_I2C_BLOCK) /* From 421ef47be20c5454b12ae0ec918d5073a9d2b938 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:28:55 +0200 Subject: [PATCH 1064/1939] [PATCH] i2c: SMBus PEC support rewrite, 2 of 3 This is my rewrite of the SMBus PEC support. The original implementation was known to have bugs (credits go to Hideki Iwamoto for reporting many of them recently), and was incomplete due to a conceptual limitation. The rewrite affects only software PEC. Hardware PEC needs very little code and is mostly untouched. Technically, both implementations differ in that the original one was emulating PEC in software by modifying the contents of an i2c_smbus_data union (changing the transaction to a different type), while the new one works one level lower, on i2c_msg structures (working on message contents). Due to the definition of the i2c_smbus_data union, not all SMBus transactions could be handled (at least not without changing the definition of this union, which would break user-space compatibility), and those which could had to be implemented individually. At the opposite, adding PEC to an i2c_msg structure can be done on any SMBus transaction with common code. Advantages of the new implementation: * It's about twice as small (from ~136 lines before to ~70 now, only counting i2c-core, including blank and comment lines). The memory used by i2c-core is down by ~640 bytes (~3.5%). * Easier to validate, less tricky code. The code being common to all transactions by design, the risk that a bug can stay uncovered is lower. * All SMBus transactions have PEC support in I2C emulation mode (providing the non-PEC transaction is also implemented). Transactions which have no emulation code right now will get PEC support for free when they finally get implemented. * Allows for code simplifications in header files and bus drivers (patch follows). Drawbacks (I guess there had to be at least one): * PEC emulation for non-PEC capable non-I2C SMBus masters was dropped. It was based on SMBus tricks and doesn't quite fit in the new design. I don't think it's really a problem, as the benefit was certainly not worth the additional complexity, but it's only fair that I at least mention it. Lastly, let's note that the new implementation does slightly affect compatibility (both in kernel and user-space), but doesn't actually break it. Some defines will be dropped, but the code can always be changed in a way that will work with both the old and the new implementations. It shouldn't be a problem as there doesn't seem to be many users of SMBus PEC to date anyway. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 162 ++++++++++++----------------------------- include/linux/i2c.h | 2 +- 2 files changed, 49 insertions(+), 115 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0040981b6698..02e335a04f09 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -19,7 +19,8 @@ /* With some changes from Kyösti Mälkki . All SMBus-related things are written by Frodo Looijaard - SMBus 2.0 support by Mark Studebaker */ + SMBus 2.0 support by Mark Studebaker and + Jean Delvare */ #include #include @@ -830,101 +831,44 @@ crc8(u16 data) return (u8)(data >> 8); } -/* CRC over count bytes in the first array plus the bytes in the rest - array if it is non-null. rest[0] is the (length of rest) - 1 - and is included. */ -static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +/* Incremental CRC8 over count bytes in the array pointed to by p */ +static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) { int i; for(i = 0; i < count; i++) - crc = crc8((crc ^ first[i]) << 8); - if(rest != NULL) - for(i = 0; i <= rest[0]; i++) - crc = crc8((crc ^ rest[i]) << 8); + crc = crc8((crc ^ p[i]) << 8); return crc; } -static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +/* Assume a 7-bit address, which is reasonable for SMBus */ +static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg) { - return i2c_smbus_partial_pec(0, count, first, rest); + /* The address will be sent first */ + u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); + pec = i2c_smbus_pec(pec, &addr, 1); + + /* The data buffer follows */ + return i2c_smbus_pec(pec, msg->buf, msg->len); } -/* Returns new "size" (transaction type) - Note that we convert byte to byte_data and byte_data to word_data - rather than invent new xxx_PEC transactions. */ -static int i2c_smbus_add_pec(u16 addr, u8 command, int size, - union i2c_smbus_data *data) +/* Used for write only transactions */ +static inline void i2c_smbus_add_pec(struct i2c_msg *msg) { - u8 buf[3]; - - buf[0] = addr << 1; - buf[1] = command; - switch(size) { - case I2C_SMBUS_BYTE: - data->byte = i2c_smbus_pec(2, buf, NULL); - size = I2C_SMBUS_BYTE_DATA; - break; - case I2C_SMBUS_BYTE_DATA: - buf[2] = data->byte; - data->word = buf[2] | - (i2c_smbus_pec(3, buf, NULL) << 8); - size = I2C_SMBUS_WORD_DATA; - break; - case I2C_SMBUS_WORD_DATA: - /* unsupported */ - break; - case I2C_SMBUS_BLOCK_DATA: - data->block[data->block[0] + 1] = - i2c_smbus_pec(2, buf, data->block); - size = I2C_SMBUS_BLOCK_DATA_PEC; - break; - } - return size; + msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); + msg->len++; } -static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, - union i2c_smbus_data *data) +/* Return <0 on CRC error + If there was a write before this read (most cases) we need to take the + partial CRC from the write part into account. + Note that this function does modify the message (we need to decrease the + message length to hide the CRC byte from the caller). */ +static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) { - u8 buf[3], rpec, cpec; + u8 rpec = msg->buf[--msg->len]; + cpec = i2c_smbus_msg_pec(cpec, msg); - buf[1] = command; - switch(size) { - case I2C_SMBUS_BYTE_DATA: - buf[0] = (addr << 1) | 1; - cpec = i2c_smbus_pec(2, buf, NULL); - rpec = data->byte; - break; - case I2C_SMBUS_WORD_DATA: - buf[0] = (addr << 1) | 1; - buf[2] = data->word & 0xff; - cpec = i2c_smbus_pec(3, buf, NULL); - rpec = data->word >> 8; - break; - case I2C_SMBUS_WORD_DATA_PEC: - /* unsupported */ - cpec = rpec = 0; - break; - case I2C_SMBUS_PROC_CALL_PEC: - /* unsupported */ - cpec = rpec = 0; - break; - case I2C_SMBUS_BLOCK_DATA_PEC: - buf[0] = (addr << 1); - buf[2] = (addr << 1) | 1; - cpec = i2c_smbus_pec(3, buf, data->block); - rpec = data->block[data->block[0] + 1]; - break; - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - buf[0] = (addr << 1) | 1; - rpec = i2c_smbus_partial_pec(partial, 1, - buf, data->block); - cpec = data->block[data->block[0] + 1]; - break; - default: - cpec = rpec = 0; - break; - } if (rpec != cpec) { pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); @@ -951,9 +895,8 @@ s32 i2c_smbus_read_byte(struct i2c_client *client) s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) { - union i2c_smbus_data data; /* only for PEC */ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) @@ -1043,6 +986,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; + u8 partial_pec = 0; msgbuf0[0] = command; switch(size) { @@ -1085,7 +1029,6 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, msgbuf0[2] = (data->word >> 8) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_DATA_PEC: if (read_write == I2C_SMBUS_READ) { dev_err(&adapter->dev, "Block read not supported " "under I2C emulation!\n"); @@ -1098,14 +1041,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, data->block[0]); return -1; } - if(size == I2C_SMBUS_BLOCK_DATA_PEC) - (msg[0].len)++; for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: dev_dbg(&adapter->dev, "Block process call not supported " "under I2C emulation!\n"); return -1; @@ -1130,9 +1070,30 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, return -1; } + i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA); + if (i) { + /* Compute PEC if first message is a write */ + if (!(msg[0].flags & I2C_M_RD)) { + if (num == 1) /* Write only */ + i2c_smbus_add_pec(&msg[0]); + else /* Write followed by read */ + partial_pec = i2c_smbus_msg_pec(0, &msg[0]); + } + /* Ask for PEC if last message is a read */ + if (msg[num-1].flags & I2C_M_RD) + msg[num-1].len++; + } + if (i2c_transfer(adapter, msg, num) < 0) return -1; + /* Check PEC if last message is a read */ + if (i && (msg[num-1].flags & I2C_M_RD)) { + if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0) + return -1; + } + if (read_write == I2C_SMBUS_READ) switch(size) { case I2C_SMBUS_BYTE: @@ -1161,28 +1122,8 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, union i2c_smbus_data * data) { s32 res; - int swpec = 0; - u8 partial = 0; flags &= I2C_M_TEN | I2C_CLIENT_PEC; - if((flags & I2C_CLIENT_PEC) && - !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { - swpec = 1; - if(read_write == I2C_SMBUS_READ && - size == I2C_SMBUS_BLOCK_DATA) - size = I2C_SMBUS_BLOCK_DATA_PEC; - else if(size == I2C_SMBUS_PROC_CALL) - size = I2C_SMBUS_PROC_CALL_PEC; - else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { - i2c_smbus_add_pec(addr, command, - I2C_SMBUS_BLOCK_DATA, data); - partial = data->block[data->block[0] + 1]; - size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; - } else if(read_write == I2C_SMBUS_WRITE && - size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - size = i2c_smbus_add_pec(addr, command, size, data); - } if (adapter->algo->smbus_xfer) { down(&adapter->bus_lock); @@ -1193,13 +1134,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); - if(res >= 0 && swpec && - size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && - (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || - size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { - if(i2c_smbus_check_pec(addr, command, size, partial, data)) - return -1; - } return res; } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index bcd4bb1b450c..78c64f7b3105 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -434,7 +434,7 @@ union i2c_smbus_data { __u8 byte; __u16 word; __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ - /* and one more for PEC */ + /* and one more for user-space compatibility */ }; /* smbus_access read or write markers */ From 585b3160f8212e58325bc1c0292c2ec01ac5db84 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:31:15 +0200 Subject: [PATCH 1065/1939] [PATCH] i2c: SMBus PEC support rewrite, 3 of 3 The new SMBus PEC implementation doesn't support PEC emulation on non-PEC non-I2C SMBus masters, so we can drop all related code. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-amd8111.c | 7 ------- drivers/i2c/busses/i2c-i801.c | 13 +++++-------- drivers/i2c/busses/i2c-nforce2.c | 7 ------- include/linux/i2c.h | 4 ---- 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index aface7938a5b..f3b79a68dbec 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -253,13 +253,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl read_write = I2C_SMBUS_READ; break; - case I2C_SMBUS_WORD_DATA_PEC: - case I2C_SMBUS_BLOCK_DATA_PEC: - case I2C_SMBUS_PROC_CALL_PEC: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - dev_warn(&adap->dev, "Unexpected software PEC transaction %d\n.", size); - return -1; - default: dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index b05e045f770c..27e7894a9d1c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -102,8 +102,8 @@ MODULE_PARM_DESC(force_addr, "EXTREMELY DANGEROUS!"); static int i801_transaction(void); -static int i801_block_transaction(union i2c_smbus_data *data, - char read_write, int command); +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command, int hwpec); static unsigned short i801_smba; static struct pci_driver i801_driver; @@ -249,7 +249,7 @@ static int i801_transaction(void) /* All-inclusive block transaction function */ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command) + int command, int hwpec) { int i, len; int smbcmd; @@ -388,7 +388,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, goto END; } - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { + if (hwpec && command == I2C_SMBUS_BLOCK_DATA) { /* wait for INTR bit as advised by Intel */ timeout = 0; do { @@ -456,9 +456,6 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: - case I2C_SMBUS_BLOCK_DATA_PEC: - if(hwpec && size == I2C_SMBUS_BLOCK_DATA) - size = I2C_SMBUS_BLOCK_DATA_PEC; outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); @@ -476,7 +473,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, outb_p(1, SMBAUXCTL); /* enable HW PEC */ } if(block) - ret = i801_block_transaction(data, read_write, size); + ret = i801_block_transaction(data, read_write, size, hwpec); else { outb_p(xact | ENABLE_INT9, SMBHSTCNT); ret = i801_transaction(); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 9b4247610815..fd26036e68a3 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -188,13 +188,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); return -1; - case I2C_SMBUS_WORD_DATA_PEC: - case I2C_SMBUS_BLOCK_DATA_PEC: - case I2C_SMBUS_PROC_CALL_PEC: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - dev_err(&adap->dev, "Unexpected software PEC transaction %d\n.", size); - return -1; - default: dev_err(&adap->dev, "Unsupported transaction %d\n", size); return -1; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 78c64f7b3105..32977fb1d99a 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -451,10 +451,6 @@ union i2c_smbus_data { #define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_I2C_BLOCK_DATA 6 #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ -#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */ -#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */ -#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */ -#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */ /* ----- commands for the ioctl like i2c_command call: From e8aac4a9b417643dd9739b48473790a09b8b6cbe Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:34:42 +0200 Subject: [PATCH 1066/1939] [PATCH] i2c: i2c-i801 PEC code cleanups The tests leading to the use of hardware PEC in the i2c-i801 driver can be simplified. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 27e7894a9d1c..4f63195069da 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -388,7 +388,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, goto END; } - if (hwpec && command == I2C_SMBUS_BLOCK_DATA) { + if (hwpec) { /* wait for INTR bit as advised by Intel */ timeout = 0; do { @@ -416,12 +416,13 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { - int hwpec = 0; + int hwpec; int block = 0; int ret, xact = 0; - if(isich4) - hwpec = (flags & I2C_CLIENT_PEC) != 0; + hwpec = isich4 && (flags & I2C_CLIENT_PEC) + && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA; switch (size) { case I2C_SMBUS_QUICK: @@ -467,11 +468,9 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, return -1; } - if(isich4 && hwpec) { - if(size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - outb_p(1, SMBAUXCTL); /* enable HW PEC */ - } + if (hwpec) + outb_p(1, SMBAUXCTL); /* enable hardware PEC */ + if(block) ret = i801_block_transaction(data, read_write, size, hwpec); else { @@ -479,11 +478,8 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, ret = i801_transaction(); } - if(isich4 && hwpec) { - if(size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - outb_p(0, SMBAUXCTL); - } + if (hwpec) + outb_p(0, SMBAUXCTL); /* disable hardware PEC */ if(block) return ret; From 8256fe0f40f1cd72f80f2c46fe0ab1638f03a98d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:37:52 +0200 Subject: [PATCH 1067/1939] [PATCH] hwmon: Separate the lm90 register read function Preparatory patch to add PEC support to the lm90 driver. We need a centralized function to read register values, where the PEC code will be later inserted. A positive side effect is that read errors are now handled properly. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm90.c | 105 +++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index dad0f1074956..5acc12ae4e36 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -349,6 +349,22 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); * Real code */ +static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) +{ + int err; + + err = i2c_smbus_read_byte_data(client, reg); + + if (err < 0) { + dev_warn(&client->dev, "Register %#02x read failed (%d)\n", + reg, err); + return err; + } + *value = err; + + return 0; +} + static int lm90_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) @@ -402,20 +418,22 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) if (kind < 0) { /* detection and identification */ u8 man_id, chip_id, reg_config1, reg_convrate; - man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1); - reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE); + if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID, + &man_id) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID, + &chip_id) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CONFIG1, + ®_config1) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CONVRATE, + ®_convrate) < 0) + goto exit_free; if (man_id == 0x01) { /* National Semiconductor */ u8 reg_config2; - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2); + if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2, + ®_config2) < 0) + goto exit_free; if ((reg_config1 & 0x2A) == 0x00 && (reg_config2 & 0xF8) == 0x00 @@ -547,7 +565,10 @@ static void lm90_init_client(struct i2c_client *client) */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); + if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { + dev_warn(&client->dev, "Initialization failed!\n"); + return; + } if (config & 0x40) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config & 0xBF); /* run */ @@ -575,21 +596,15 @@ static struct lm90_data *lm90_update_device(struct device *dev) down(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - u8 oldh, newh; + u8 oldh, newh, l; dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp8[3] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp8[4] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); - data->temp_hyst = i2c_smbus_read_byte_data(client, - LM90_REG_R_TCRIT_HYST); + lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, &data->temp8[0]); + lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[1]); + lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[2]); + lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[3]); + lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[4]); + lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); /* * There is a trick here. We have to read two registers to @@ -605,36 +620,20 @@ static struct lm90_data *lm90_update_device(struct device *dev) * then we have a valid reading. Else we have to read the low * byte again, and now we believe we have a correct reading. */ - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); - newh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - if (newh != oldh) { - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); -#ifdef DEBUG - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp11[0] |= (newh << 8); + if (lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &oldh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &newh) == 0 + && (newh == oldh + || lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0)) + data->temp11[0] = (newh << 8) | l; - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHL); - data->alarms = i2c_smbus_read_byte_data(client, - LM90_REG_R_STATUS); + if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) + data->temp11[1] = (newh << 8) | l; + if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) + data->temp11[2] = (newh << 8) | l; + lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); data->last_updated = jiffies; data->valid = 1; From c3df5806cdae6fac678c662b527cb974bef4b60c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 21:39:40 +0200 Subject: [PATCH 1068/1939] [PATCH] hwmon: Add PEC support to the lm90 driver Add PEC support to the lm90 driver. Only the ADM1032 chip supports it, and in a rather tricky way, which is why this patch comes with documentation reinforcements. At least, this demonstrates that the new PEC support logic in i2c-core can properly deal with chips with partial PEC support. As enabling PEC causes a significant performance drop, it can be disabled through a sysfs file (unsurprisingly named "pec"). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/lm90 | 39 +++++++++++++++++++- Documentation/hwmon/sysfs-interface | 3 ++ drivers/hwmon/lm90.c | 57 ++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 2c4cf39471f4..70abf93ea376 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -71,8 +71,8 @@ increased resolution of the remote temperature measurement. The different chipsets of the family are not strictly identical, although very similar. This driver doesn't handle any specific feature for now, -but could if there ever was a need for it. For reference, here comes a -non-exhaustive list of specific features: +with the exception of SMBus PEC. For reference, here comes a non-exhaustive +list of specific features: LM90: * Filter and alert configuration register at 0xBF. @@ -91,6 +91,7 @@ ADM1032: * Conversion averaging. * Up to 64 conversions/s. * ALERT is triggered by open remote sensor. + * SMBus PEC support for Write Byte and Receive Byte transactions. ADT7461 * Extended temperature range (breaks compatibility) @@ -119,3 +120,37 @@ The lm90 driver will not update its values more frequently than every other second; reading them more often will do no harm, but will return 'old' values. +PEC Support +----------- + +The ADM1032 is the only chip of the family which supports PEC. It does +not support PEC on all transactions though, so some care must be taken. + +When reading a register value, the PEC byte is computed and sent by the +ADM1032 chip. However, in the case of a combined transaction (SMBus Read +Byte), the ADM1032 computes the CRC value over only the second half of +the message rather than its entirety, because it thinks the first half +of the message belongs to a different transaction. As a result, the CRC +value differs from what the SMBus master expects, and all reads fail. + +For this reason, the lm90 driver will enable PEC for the ADM1032 only if +the bus supports the SMBus Send Byte and Receive Byte transaction types. +These transactions will be used to read register values, instead of +SMBus Read Byte, and PEC will work properly. + +Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC. +Instead, it will try to write the PEC value to the register (because the +SMBus Send Byte transaction with PEC is similar to a Write Byte transaction +without PEC), which is not what we want. Thus, PEC is explicitely disabled +on SMBus Send Byte transactions in the lm90 driver. + +PEC on byte data transactions represents a significant increase in bandwidth +usage (+33% for writes, +25% for reads) in normal conditions. With the need +to use two SMBus transaction for reads, this overhead jumps to +50%. Worse, +two transactions will typically mean twice as much delay waiting for +transaction completion, effectively doubling the register cache refresh time. +I guess reliability comes at a price, but it's quite expensive this time. + +So, as not everyone might enjoy the slowdown, PEC can be disabled through +sysfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1 +to that file to enable PEC again. diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 346400519d0d..764cdc5480e7 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -272,3 +272,6 @@ beep_mask Bitmask for beep. eeprom Raw EEPROM data in binary form. Read only. + +pec Enable or disable PEC (SMBus only) + Read/Write diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 5acc12ae4e36..fa0793e684fd 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -345,15 +345,63 @@ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +/* pec used for ADM1032 only */ +static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); +} + +static ssize_t set_pec(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + long val = simple_strtol(buf, NULL, 10); + + switch (val) { + case 0: + client->flags &= ~I2C_CLIENT_PEC; + break; + case 1: + client->flags |= I2C_CLIENT_PEC; + break; + default: + return -EINVAL; + } + + return count; +} + +static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec); + /* * Real code */ +/* The ADM1032 supports PEC but not on write byte transactions, so we need + to explicitely ask for a transaction without PEC. */ +static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) +{ + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags & ~I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); +} + +/* It is assumed that client->update_lock is held (unless we are in + detection or initialization steps). This matters when PEC is enabled, + because we don't want the address pointer to change between the write + byte and the read byte transactions. */ static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) { int err; - err = i2c_smbus_read_byte_data(client, reg); + if (client->flags & I2C_CLIENT_PEC) { + err = adm1032_write_byte(client, reg); + if (err >= 0) + err = i2c_smbus_read_byte(client); + } else + err = i2c_smbus_read_byte_data(client, reg); if (err < 0) { dev_warn(&client->dev, "Register %#02x read failed (%d)\n", @@ -494,6 +542,10 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) name = "lm90"; } else if (kind == adm1032) { name = "adm1032"; + /* The ADM1032 supports PEC, but only if combined + transactions are not used. */ + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + new_client->flags |= I2C_CLIENT_PEC; } else if (kind == lm99) { name = "lm99"; } else if (kind == lm86) { @@ -546,6 +598,9 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_temp2_crit_hyst.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); + if (new_client->flags & I2C_CLIENT_PEC) + device_create_file(&new_client->dev, &dev_attr_pec); + return 0; exit_detach: From 90209b42d0498d57a804bf81fea427bf39c5315c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 22:20:21 +0200 Subject: [PATCH 1069/1939] [PATCH] hwmon: lm90 documentation update Update the I2C addresses for the ADM1032 and ADT7461 chips. Also update the links to the Analog Devices web site. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/lm90 | 8 ++++---- drivers/hwmon/lm90.c | 16 +++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 70abf93ea376..438cb24cee5b 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -24,14 +24,14 @@ Supported chips: http://www.national.com/pf/LM/LM86.html * Analog Devices ADM1032 Prefix: 'adm1032' - Addresses scanned: I2C 0x4c + Addresses scanned: I2C 0x4c and 0x4d Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADM1032 + http://www.analog.com/en/prod/0,2877,ADM1032,00.html * Analog Devices ADT7461 Prefix: 'adt7461' - Addresses scanned: I2C 0x4c + Addresses scanned: I2C 0x4c and 0x4d Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADT7461 + http://www.analog.com/en/prod/0,2877,ADT7461,00.html Note: Only if in ADM1032 compatibility mode * Maxim MAX6657 Prefix: 'max6657' diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index fa0793e684fd..83cf2e1b09f5 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -31,7 +31,7 @@ * Devices. That chip is similar to the LM90, with a few differences * that are not handled by this driver. Complete datasheet can be * obtained from Analog's website at: - * http://products.analog.com/products/info.asp?product=ADM1032 + * http://www.analog.com/en/prod/0,2877,ADM1032,00.html * Among others, it has a higher accuracy than the LM90, much like the * LM86 does. * @@ -49,7 +49,7 @@ * register values are decoded differently) it is ignored by this * driver. Complete datasheet can be obtained from Analog's website * at: - * http://products.analog.com/products/info.asp?product=ADT7461 + * http://www.analog.com/en/prod/0,2877,ADT7461,00.html * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -83,10 +83,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. - * LM89-1, and LM99-1 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658 + * have address 0x4c. + * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d. * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - * ADT7461 always has address 0x4c. */ static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; @@ -500,14 +500,12 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) } } else if (man_id == 0x41) { /* Analog Devices */ - if (address == 0x4C - && (chip_id & 0xF0) == 0x40 /* ADM1032 */ + if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ && (reg_config1 & 0x3F) == 0x00 && reg_convrate <= 0x0A) { kind = adm1032; } else - if (address == 0x4c - && chip_id == 0x51 /* ADT7461 */ + if (chip_id == 0x51 /* ADT7461 */ && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ && reg_convrate <= 0x0A) { kind = adt7461; From b890a07f7b002ee473986fa85ae3582de399a4cf Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Oct 2005 22:21:24 +0200 Subject: [PATCH 1070/1939] [PATCH] hwmon: smsc47m1 documentation update The SMSC LPC47M997 Super-I/O chip seems to be compatible with the LPC47M192, so it is supported by the smsc47m1 driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/smsc47m1 | 7 +++++++ drivers/hwmon/smsc47m1.c | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1 index 34e6478c1425..c15bbe68264e 100644 --- a/Documentation/hwmon/smsc47m1 +++ b/Documentation/hwmon/smsc47m1 @@ -12,6 +12,10 @@ Supported chips: http://www.smsc.com/main/datasheets/47m14x.pdf http://www.smsc.com/main/tools/discontinued/47m15x.pdf http://www.smsc.com/main/datasheets/47m192.pdf + * SMSC LPC47M997 + Addresses scanned: none, address read from Super I/O config space + Prefix: 'smsc47m1' + Datasheet: none Authors: Mark D. Studebaker , @@ -30,6 +34,9 @@ The 47M15x and 47M192 chips contain a full 'hardware monitoring block' in addition to the fan monitoring and control. The hardware monitoring block is not supported by the driver. +No documentation is available for the 47M997, but it has the same device +ID as the 47M15x and 47M192 chips and seems to be compatible. + Fan rotation speeds are reported in RPM (rotations per minute). An alarm is triggered if the rotation speed has dropped below a programmable limit. Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to give diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index bbe93a0688ec..5905c1af88f2 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -3,7 +3,7 @@ for hardware monitoring Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x and LPC47M192 Super-I/O chips. + LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker Copyright (C) 2004 Jean Delvare @@ -356,6 +356,8 @@ static int __init smsc47m1_find(unsigned short *addr) * 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" * can do much more besides (device id 0x60). + * The LPC47M997 is undocumented, but seems to be compatible with + * the LPC47M192, and has the same device id. */ if (val == 0x51) printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); @@ -364,7 +366,8 @@ static int __init smsc47m1_find(unsigned short *addr) else if (val == 0x5F) printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); else if (val == 0x60) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); + printk(KERN_INFO "smsc47m1: Found SMSC " + "LPC47M15x/LPC47M192/LPC47M997\n"); else { superio_exit(); return -ENODEV; From 0dc9a32d9a975ccd25b9f531451165c93e1c7313 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 22 Oct 2005 00:23:27 +0200 Subject: [PATCH 1071/1939] [PATCH] I2C: remove devfs support from i2c-dev driver as devfs is gone, this isn't needed anymore. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-dev.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 276ec42a0717..ea14c8f1c82b 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -26,15 +26,11 @@ /* The I2C_RDWR ioctl code is written by Kolja Waschk */ -/* The devfs code is contributed by Philipp Matthias Hahn - */ - #include #include #include #include #include -#include #include #include #include @@ -431,8 +427,6 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap) if (IS_ERR(i2c_dev)) return PTR_ERR(i2c_dev); - devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor), - S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor); pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", adap->name, i2c_dev->minor); @@ -465,7 +459,6 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap) return -ENODEV; init_completion(&i2c_dev->released); - devfs_remove("i2c/%d", i2c_dev->minor); return_i2c_dev(i2c_dev); class_device_unregister(&i2c_dev->class_dev); wait_for_completion(&i2c_dev->released); @@ -521,8 +514,6 @@ static int __init i2c_dev_init(void) if (res) goto out_unreg_class; - devfs_mk_dir("i2c"); - return 0; out_unreg_class: @@ -538,7 +529,6 @@ static void __exit i2c_dev_exit(void) { i2c_del_driver(&i2cdev_driver); class_unregister(&i2c_dev_class); - devfs_remove("i2c"); unregister_chrdev(I2C_MAJOR,"i2c"); } From a9d1b24d91f91b77db3da8aeacb414764f789b9c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 22 Oct 2005 00:23:27 +0200 Subject: [PATCH 1072/1939] [PATCH] I2C: add i2c module alias for i2c drivers to use This is the start of adding hotplug-like support for i2c devices. Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 1 + include/linux/mod_devicetable.h | 5 +++++ scripts/mod/file2alias.c | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 32977fb1d99a..f88577ca3b3a 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -29,6 +29,7 @@ #include #include #include +#include #include /* for struct device */ #include diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 2f0299a448f6..7b08c11ec4cc 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -244,4 +244,9 @@ struct pcmcia_device_id { #define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200 #define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400 +/* I2C */ +struct i2c_device_id { + __u16 id; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index f2ee673329a7..e3d144a3f10b 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -359,6 +359,13 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio, return 1; } +static int do_i2c_entry(const char *filename, struct i2c_device_id *i2c, char *alias) +{ + strcpy(alias, "i2c:"); + ADD(alias, "id", 1, i2c->id); + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -443,6 +450,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, else if (sym_is(symname, "__mod_vio_device_table")) do_table(symval, sym->st_size, sizeof(struct vio_device_id), do_vio_entry, mod); + else if (sym_is(symname, "__mod_i2c_device_table")) + do_table(symval, sym->st_size, sizeof(struct i2c_device_id), + do_i2c_entry, mod); } From c45154a3b1fecdbb51b5462c9f730b44e62b83a5 Mon Sep 17 00:00:00 2001 From: Ed Kear Date: Sat, 16 Jul 2005 23:32:19 -0400 Subject: [PATCH 1073/1939] [PATCH] libata: add support for Promise SATA 300 TX2plus PDC40775 I'm using this card in a RAID1 with 2 new SATA drives with no problems. Card - SATA 300 TX2plus PDC40775 (3d73) Signed-off-by: Ed Kear Signed-off-by: Jeff Garzik --- drivers/scsi/sata_promise.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 50495569f409..63911f16b6ec 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -209,6 +209,8 @@ static struct pci_device_id pdc_ata_pci_tbl[] = { board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, From eaa5c54dbec70e2a93d6ed412bb589bbf9c90a17 Mon Sep 17 00:00:00 2001 From: Ivan Skytte Jorgensen Date: Fri, 28 Oct 2005 15:10:00 -0700 Subject: [PATCH 1074/1939] [SCTP] Rename SCTP specific control message flags. Rename SCTP specific control message flags to use SCTP_ prefix rather than MSG_ prefix as per the latest sctp sockets API draft. Signed-off-by: Ivan Skytte Jorgensen Signed-off-by: Sridhar Samudrala --- include/net/sctp/user.h | 8 ++++---- net/sctp/sm_make_chunk.c | 2 +- net/sctp/socket.c | 32 ++++++++++++++++---------------- net/sctp/ulpevent.c | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 1c5f19f995ad..f1c3bc54526a 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -171,10 +171,10 @@ struct sctp_sndrcvinfo { */ enum sctp_sinfo_flags { - MSG_UNORDERED = 1, /* Send/receive message unordered. */ - MSG_ADDR_OVER = 2, /* Override the primary destination. */ - MSG_ABORT=4, /* Send an ABORT message to the peer. */ - /* MSG_EOF is already defined per socket.h */ + SCTP_UNORDERED = 1, /* Send/receive message unordered. */ + SCTP_ADDR_OVER = 2, /* Override the primary destination. */ + SCTP_ABORT=4, /* Send an ABORT message to the peer. */ + SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ }; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 10e82ec2ebd3..660c61bdf164 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -554,7 +554,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, dp.ppid = sinfo->sinfo_ppid; /* Set the flags for an unordered send. */ - if (sinfo->sinfo_flags & MSG_UNORDERED) { + if (sinfo->sinfo_flags & SCTP_UNORDERED) { flags |= SCTP_DATA_UNORDERED; dp.ssn = 0; } else diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 02e068d3450d..170045b6ee98 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1389,27 +1389,27 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, SCTP_DEBUG_PRINTK("msg_len: %zu, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); - /* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */ - if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) { + /* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */ + if (sctp_style(sk, TCP) && (sinfo_flags & (SCTP_EOF | SCTP_ABORT))) { err = -EINVAL; goto out_nounlock; } - /* If MSG_EOF is set, no data can be sent. Disallow sending zero - * length messages when MSG_EOF|MSG_ABORT is not set. - * If MSG_ABORT is set, the message length could be non zero with + /* If SCTP_EOF is set, no data can be sent. Disallow sending zero + * length messages when SCTP_EOF|SCTP_ABORT is not set. + * If SCTP_ABORT is set, the message length could be non zero with * the msg_iov set to the user abort reason. */ - if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) || - (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { + if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) || + (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) { err = -EINVAL; goto out_nounlock; } - /* If MSG_ADDR_OVER is set, there must be an address + /* If SCTP_ADDR_OVER is set, there must be an address * specified in msg_name. */ - if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) { + if ((sinfo_flags & SCTP_ADDR_OVER) && (!msg->msg_name)) { err = -EINVAL; goto out_nounlock; } @@ -1458,14 +1458,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_unlock; } - if (sinfo_flags & MSG_EOF) { + if (sinfo_flags & SCTP_EOF) { SCTP_DEBUG_PRINTK("Shutting down association: %p\n", asoc); sctp_primitive_SHUTDOWN(asoc, NULL); err = 0; goto out_unlock; } - if (sinfo_flags & MSG_ABORT) { + if (sinfo_flags & SCTP_ABORT) { SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc); sctp_primitive_ABORT(asoc, msg); err = 0; @@ -1477,7 +1477,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, if (!asoc) { SCTP_DEBUG_PRINTK("There is no association yet.\n"); - if (sinfo_flags & (MSG_EOF | MSG_ABORT)) { + if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) { err = -EINVAL; goto out_unlock; } @@ -1611,10 +1611,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* If an address is passed with the sendto/sendmsg call, it is used * to override the primary destination address in the TCP model, or - * when MSG_ADDR_OVER flag is set in the UDP model. + * when SCTP_ADDR_OVER flag is set in the UDP model. */ if ((sctp_style(sk, TCP) && msg_name) || - (sinfo_flags & MSG_ADDR_OVER)) { + (sinfo_flags & SCTP_ADDR_OVER)) { chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); if (!chunk_tp) { err = -EINVAL; @@ -4640,8 +4640,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, /* Minimally, validate the sinfo_flags. */ if (cmsgs->info->sinfo_flags & - ~(MSG_UNORDERED | MSG_ADDR_OVER | - MSG_ABORT | MSG_EOF)) + ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_ABORT | SCTP_EOF)) return -EINVAL; break; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 057e7fac3af0..e049f41faa47 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -698,7 +698,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, event->ssn = ntohs(chunk->subh.data_hdr->ssn); event->ppid = chunk->subh.data_hdr->ppid; if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { - event->flags |= MSG_UNORDERED; + event->flags |= SCTP_UNORDERED; event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); } event->tsn = ntohl(chunk->subh.data_hdr->tsn); @@ -824,7 +824,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, * * recvmsg() flags: * - * MSG_UNORDERED - This flag is present when the message was sent + * SCTP_UNORDERED - This flag is present when the message was sent * non-ordered. */ sinfo.sinfo_flags = event->flags; @@ -839,7 +839,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, * This field will hold the current cumulative TSN as * known by the underlying SCTP layer. Note this field is * ignored when sending and only valid for a receive - * operation when sinfo_flags are set to MSG_UNORDERED. + * operation when sinfo_flags are set to SCTP_UNORDERED. */ sinfo.sinfo_cumtsn = event->cumtsn; /* sinfo_assoc_id: sizeof (sctp_assoc_t) From 1993d683f39f77ddb46a662d7146247877d50b8f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Oct 2005 15:30:34 -0700 Subject: [PATCH 1075/1939] [IPoIB] Drop RX packets when out of memory Change the way IPoIB handles RX packets when it can't allocate a new receive skbuff. If the allocation of a new receive skb fails, we now drop the packet we just received and repost the original receive skb. This means that the receive ring always stays full and we don't have to monkey around with trying to schedule a refill task for later. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 21 ++-- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 128 +++++++++++++--------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +- 3 files changed, 91 insertions(+), 66 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 6b14bd1c60a0..c994a916a58a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -100,7 +100,12 @@ struct ipoib_pseudoheader { struct ipoib_mcast; -struct ipoib_buf { +struct ipoib_rx_buf { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct ipoib_tx_buf { struct sk_buff *skb; DECLARE_PCI_UNMAP_ADDR(mapping) }; @@ -150,14 +155,14 @@ struct ipoib_dev_priv { unsigned int admin_mtu; unsigned int mcast_mtu; - struct ipoib_buf *rx_ring; + struct ipoib_rx_buf *rx_ring; - spinlock_t tx_lock; - struct ipoib_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - struct ib_sge tx_sge; - struct ib_send_wr tx_wr; + spinlock_t tx_lock; + struct ipoib_tx_buf *tx_ring; + unsigned tx_head; + unsigned tx_tail; + struct ib_sge tx_sge; + struct ib_send_wr tx_wr; struct ib_wc ibwc[IPOIB_NUM_WC]; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 02d0e0006578..192fef884e21 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -95,65 +95,77 @@ void ipoib_free_ah(struct kref *kref) } } -static inline int ipoib_ib_receive(struct ipoib_dev_priv *priv, - unsigned int wr_id, - dma_addr_t addr) -{ - struct ib_sge list = { - .addr = addr, - .length = IPOIB_BUF_SIZE, - .lkey = priv->mr->lkey, - }; - struct ib_recv_wr param = { - .wr_id = wr_id | IPOIB_OP_RECV, - .sg_list = &list, - .num_sge = 1, - }; - struct ib_recv_wr *bad_wr; - - return ib_post_recv(priv->qp, ¶m, &bad_wr); -} - static int ipoib_ib_post_receive(struct net_device *dev, int id) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct sk_buff *skb; - dma_addr_t addr; + struct ib_sge list; + struct ib_recv_wr param; + struct ib_recv_wr *bad_wr; int ret; - skb = dev_alloc_skb(IPOIB_BUF_SIZE + 4); - if (!skb) { - ipoib_warn(priv, "failed to allocate receive buffer\n"); + list.addr = priv->rx_ring[id].mapping; + list.length = IPOIB_BUF_SIZE; + list.lkey = priv->mr->lkey; - priv->rx_ring[id].skb = NULL; - return -ENOMEM; - } - skb_reserve(skb, 4); /* 16 byte align IP header */ - priv->rx_ring[id].skb = skb; - addr = dma_map_single(priv->ca->dma_device, - skb->data, IPOIB_BUF_SIZE, - DMA_FROM_DEVICE); - pci_unmap_addr_set(&priv->rx_ring[id], mapping, addr); + param.next = NULL; + param.wr_id = id | IPOIB_OP_RECV; + param.sg_list = &list; + param.num_sge = 1; - ret = ipoib_ib_receive(priv, id, addr); - if (ret) { - ipoib_warn(priv, "ipoib_ib_receive failed for buf %d (%d)\n", - id, ret); - dma_unmap_single(priv->ca->dma_device, addr, + ret = ib_post_recv(priv->qp, ¶m, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "receive failed for buf %d (%d)\n", id, ret); + dma_unmap_single(priv->ca->dma_device, + priv->rx_ring[id].mapping, IPOIB_BUF_SIZE, DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + dev_kfree_skb_any(priv->rx_ring[id].skb); priv->rx_ring[id].skb = NULL; } return ret; } +static int ipoib_alloc_rx_skb(struct net_device *dev, int id) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct sk_buff *skb; + dma_addr_t addr; + + skb = dev_alloc_skb(IPOIB_BUF_SIZE + 4); + if (!skb) + return -ENOMEM; + + /* + * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte + * header. So we need 4 more bytes to get to 48 and align the + * IP header to a multiple of 16. + */ + skb_reserve(skb, 4); + + addr = dma_map_single(priv->ca->dma_device, + skb->data, IPOIB_BUF_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(addr))) { + dev_kfree_skb_any(skb); + return -EIO; + } + + priv->rx_ring[id].skb = skb; + priv->rx_ring[id].mapping = addr; + + return 0; +} + static int ipoib_ib_post_receives(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); int i; for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) { + if (ipoib_alloc_rx_skb(dev, i)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + return -ENOMEM; + } if (ipoib_ib_post_receive(dev, i)) { ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); return -EIO; @@ -176,28 +188,36 @@ static void ipoib_ib_handle_wc(struct net_device *dev, wr_id &= ~IPOIB_OP_RECV; if (wr_id < IPOIB_RX_RING_SIZE) { - struct sk_buff *skb = priv->rx_ring[wr_id].skb; + struct sk_buff *skb = priv->rx_ring[wr_id].skb; + dma_addr_t addr = priv->rx_ring[wr_id].mapping; - priv->rx_ring[wr_id].skb = NULL; - - dma_unmap_single(priv->ca->dma_device, - pci_unmap_addr(&priv->rx_ring[wr_id], - mapping), - IPOIB_BUF_SIZE, - DMA_FROM_DEVICE); - - if (wc->status != IB_WC_SUCCESS) { + if (unlikely(wc->status != IB_WC_SUCCESS)) { if (wc->status != IB_WC_WR_FLUSH_ERR) ipoib_warn(priv, "failed recv event " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); + dma_unmap_single(priv->ca->dma_device, addr, + IPOIB_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); + priv->rx_ring[wr_id].skb = NULL; return; } + /* + * If we can't allocate a new RX buffer, dump + * this packet and reuse the old buffer. + */ + if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) { + ++priv->stats.rx_dropped; + goto repost; + } + ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid); + dma_unmap_single(priv->ca->dma_device, addr, + IPOIB_BUF_SIZE, DMA_FROM_DEVICE); + skb_put(skb, wc->byte_len); skb_pull(skb, IB_GRH_BYTES); @@ -220,8 +240,8 @@ static void ipoib_ib_handle_wc(struct net_device *dev, dev_kfree_skb_any(skb); } - /* repost receive */ - if (ipoib_ib_post_receive(dev, wr_id)) + repost: + if (unlikely(ipoib_ib_post_receive(dev, wr_id))) ipoib_warn(priv, "ipoib_ib_post_receive failed " "for buf %d\n", wr_id); } else @@ -229,7 +249,7 @@ static void ipoib_ib_handle_wc(struct net_device *dev, wr_id); } else { - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; unsigned long flags; if (wr_id >= IPOIB_TX_RING_SIZE) { @@ -302,7 +322,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; dma_addr_t addr; if (skb->len > dev->mtu + INFINIBAND_ALEN) { @@ -468,7 +488,7 @@ int ipoib_ib_dev_stop(struct net_device *dev) struct ib_qp_attr qp_attr; int attr_mask; unsigned long begin; - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; int i; /* Kill the existing QP and allocate a new one */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ee303859b044..cd4f42328dbe 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -732,7 +732,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) /* Allocate RX/TX "rings" to hold queued skbs */ - priv->rx_ring = kmalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_buf), + priv->rx_ring = kmalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf), GFP_KERNEL); if (!priv->rx_ring) { printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", @@ -740,9 +740,9 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out; } memset(priv->rx_ring, 0, - IPOIB_RX_RING_SIZE * sizeof (struct ipoib_buf)); + IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf)); - priv->tx_ring = kmalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_buf), + priv->tx_ring = kmalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf), GFP_KERNEL); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", @@ -750,7 +750,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out_rx_ring_cleanup; } memset(priv->tx_ring, 0, - IPOIB_TX_RING_SIZE * sizeof (struct ipoib_buf)); + IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf)); /* priv->tx_head & tx_tail are already 0 */ From a1ab3582699def352dab1355adcadd3d47f79f0f Mon Sep 17 00:00:00 2001 From: Ivan Skytte Jorgensen Date: Fri, 28 Oct 2005 15:33:24 -0700 Subject: [PATCH 1076/1939] [SCTP] Fix SCTP_SETADAPTION sockopt to use the correct structure. Signed-off-by: Ivan Skytte Jorgensen Signed-off-by: Sridhar Samudrala --- net/sctp/socket.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 170045b6ee98..c66c161908c0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2384,14 +2384,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, int optlen) { - __u32 val; + struct sctp_setadaption adaption; - if (optlen < sizeof(__u32)) + if (optlen != sizeof(struct sctp_setadaption)) return -EINVAL; - if (copy_from_user(&val, optval, sizeof(__u32))) + if (copy_from_user(&adaption, optval, optlen)) return -EFAULT; - sctp_sk(sk)->adaption_ind = val; + sctp_sk(sk)->adaption_ind = adaption.ssb_adaption_ind; return 0; } @@ -3672,17 +3672,15 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, static int sctp_getsockopt_adaption_layer(struct sock *sk, int len, char __user *optval, int __user *optlen) { - __u32 val; + struct sctp_setadaption adaption; - if (len < sizeof(__u32)) + if (len != sizeof(struct sctp_setadaption)) return -EINVAL; - len = sizeof(__u32); - val = sctp_sk(sk)->adaption_ind; - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) + adaption.ssb_adaption_ind = sctp_sk(sk)->adaption_ind; + if (copy_to_user(optval, &adaption, len)) return -EFAULT; + return 0; } From 96a339985d4c6874d32909e8f1903e6e6c141399 Mon Sep 17 00:00:00 2001 From: Ivan Skytte Jorgensen Date: Fri, 28 Oct 2005 15:36:12 -0700 Subject: [PATCH 1077/1939] [SCTP] Allow SCTP_MAXSEG to revert to default frag point with a '0' value. Signed-off-by: Ivan Skytte Jorgensen Signed-off-by: Sridhar Samudrala --- net/sctp/socket.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c66c161908c0..97b556c1c450 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2306,16 +2306,14 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl return -EINVAL; if (get_user(val, (int __user *)optval)) return -EFAULT; - if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) + if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) return -EINVAL; sp->user_frag = val; - if (val) { - /* Update the frag_point of the existing associations. */ - list_for_each(pos, &(sp->ep->asocs)) { - asoc = list_entry(pos, struct sctp_association, asocs); - asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); - } + /* Update the frag_point of the existing associations. */ + list_for_each(pos, &(sp->ep->asocs)) { + asoc = list_entry(pos, struct sctp_association, asocs); + asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); } return 0; From 2cea752f683af1be58ee8f25717c0a8118e0ac5b Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Tue, 27 Sep 2005 21:54:51 +0000 Subject: [PATCH 1078/1939] [PATCH] PCI: ICH6 ACPI and GPIO quirk This patch just adds ACPI and GPIO regions to its LPC bridge, similar way as ICH4 did. I would like to thank Michal Mleczko for testing. Signed-off-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman drivers/pci/quirks.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) --- drivers/pci/quirks.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7992bc8cc6a4..0663428a0e64 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -414,6 +414,18 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi ); +static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) +{ + u32 region; + + pci_read_config_dword(dev, 0x40, ®ion); + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH6 ACPI/GPIO/TCO"); + + pci_read_config_dword(dev, 0x48, ®ion); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO"); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); + /* * VIA ACPI: One IO region pointed to by longword at * 0x48 or 0x20 (256 bytes of ACPI registers) From e04b0ea2e0f9c1bb0d874db4493fc7f7a623116b Mon Sep 17 00:00:00 2001 From: Brian King Date: Tue, 27 Sep 2005 01:21:55 -0700 Subject: [PATCH 1079/1939] [PATCH] PCI: Block config access during BIST Some PCI adapters (eg. ipr scsi adapters) have an exposure today in that they issue BIST to the adapter to reset the card. If, during the time it takes to complete BIST, userspace attempts to access PCI config space, the host bus bridge will master abort the access since the ipr adapter does not respond on the PCI bus for a brief period of time when running BIST. On PPC64 hardware, this master abort results in the host PCI bridge isolating that PCI device from the rest of the system, making the device unusable until Linux is rebooted. This patch is an attempt to close that exposure by introducing some blocking code in the PCI code. When blocked, writes will be humored and reads will return the cached value. Ben Herrenschmidt has also mentioned that he plans to use this in PPC power management. Signed-off-by: Brian King Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman drivers/pci/access.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci-sysfs.c | 20 +++++----- drivers/pci/pci.h | 7 +++ drivers/pci/proc.c | 28 +++++++-------- drivers/pci/syscall.c | 14 +++---- include/linux/pci.h | 7 +++ 6 files changed, 134 insertions(+), 31 deletions(-) --- drivers/pci/access.c | 89 +++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci-sysfs.c | 20 ++++----- drivers/pci/pci.h | 7 ++++ drivers/pci/proc.c | 28 ++++++------- drivers/pci/syscall.c | 14 +++---- include/linux/pci.h | 7 ++++ 6 files changed, 134 insertions(+), 31 deletions(-) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 24a76de49f41..2a42add7f563 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -60,3 +60,92 @@ EXPORT_SYMBOL(pci_bus_read_config_dword); EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); + +static u32 pci_user_cached_config(struct pci_dev *dev, int pos) +{ + u32 data; + + data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])]; + data >>= (pos % sizeof(dev->saved_config_space[0])) * 8; + return data; +} + +#define PCI_USER_READ_CONFIG(size,type) \ +int pci_user_read_config_##size \ + (struct pci_dev *dev, int pos, type *val) \ +{ \ + unsigned long flags; \ + int ret = 0; \ + u32 data = -1; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + if (likely(!dev->block_ucfg_access)) \ + ret = dev->bus->ops->read(dev->bus, dev->devfn, \ + pos, sizeof(type), &data); \ + else if (pos < sizeof(dev->saved_config_space)) \ + data = pci_user_cached_config(dev, pos); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + *val = (type)data; \ + return ret; \ +} + +#define PCI_USER_WRITE_CONFIG(size,type) \ +int pci_user_write_config_##size \ + (struct pci_dev *dev, int pos, type val) \ +{ \ + unsigned long flags; \ + int ret = -EIO; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + if (likely(!dev->block_ucfg_access)) \ + ret = dev->bus->ops->write(dev->bus, dev->devfn, \ + pos, sizeof(type), val); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return ret; \ +} + +PCI_USER_READ_CONFIG(byte, u8) +PCI_USER_READ_CONFIG(word, u16) +PCI_USER_READ_CONFIG(dword, u32) +PCI_USER_WRITE_CONFIG(byte, u8) +PCI_USER_WRITE_CONFIG(word, u16) +PCI_USER_WRITE_CONFIG(dword, u32) + +/** + * pci_block_user_cfg_access - Block userspace PCI config reads/writes + * @dev: pci device struct + * + * This function blocks any userspace PCI config accesses from occurring. + * When blocked, any writes will be bit bucketed and reads will return the + * data saved using pci_save_state for the first 64 bytes of config + * space and return 0xff for all other config reads. + **/ +void pci_block_user_cfg_access(struct pci_dev *dev) +{ + unsigned long flags; + + pci_save_state(dev); + + /* spinlock to synchronize with anyone reading config space now */ + spin_lock_irqsave(&pci_lock, flags); + dev->block_ucfg_access = 1; + spin_unlock_irqrestore(&pci_lock, flags); +} +EXPORT_SYMBOL_GPL(pci_block_user_cfg_access); + +/** + * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes + * @dev: pci device struct + * + * This function allows userspace PCI config accesses to resume. + **/ +void pci_unblock_user_cfg_access(struct pci_dev *dev) +{ + unsigned long flags; + + /* spinlock to synchronize with anyone reading saved config space */ + spin_lock_irqsave(&pci_lock, flags); + dev->block_ucfg_access = 0; + spin_unlock_irqrestore(&pci_lock, flags); +} +EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 2898830c496f..965a5934623a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -130,7 +130,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 1) && size) { u8 val; - pci_read_config_byte(dev, off, &val); + pci_user_read_config_byte(dev, off, &val); data[off - init_off] = val; off++; size--; @@ -138,7 +138,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 3) && size > 2) { u16 val; - pci_read_config_word(dev, off, &val); + pci_user_read_config_word(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; off += 2; @@ -147,7 +147,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) while (size > 3) { u32 val; - pci_read_config_dword(dev, off, &val); + pci_user_read_config_dword(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; data[off - init_off + 2] = (val >> 16) & 0xff; @@ -158,7 +158,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size >= 2) { u16 val; - pci_read_config_word(dev, off, &val); + pci_user_read_config_word(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; off += 2; @@ -167,7 +167,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size > 0) { u8 val; - pci_read_config_byte(dev, off, &val); + pci_user_read_config_byte(dev, off, &val); data[off - init_off] = val; off++; --size; @@ -192,7 +192,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) } if ((off & 1) && size) { - pci_write_config_byte(dev, off, data[off - init_off]); + pci_user_write_config_byte(dev, off, data[off - init_off]); off++; size--; } @@ -200,7 +200,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 3) && size > 2) { u16 val = data[off - init_off]; val |= (u16) data[off - init_off + 1] << 8; - pci_write_config_word(dev, off, val); + pci_user_write_config_word(dev, off, val); off += 2; size -= 2; } @@ -210,7 +210,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) val |= (u32) data[off - init_off + 1] << 8; val |= (u32) data[off - init_off + 2] << 16; val |= (u32) data[off - init_off + 3] << 24; - pci_write_config_dword(dev, off, val); + pci_user_write_config_dword(dev, off, val); off += 4; size -= 4; } @@ -218,13 +218,13 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size >= 2) { u16 val = data[off - init_off]; val |= (u16) data[off - init_off + 1] << 8; - pci_write_config_word(dev, off, val); + pci_user_write_config_word(dev, off, val); off += 2; size -= 2; } if (size) { - pci_write_config_byte(dev, off, data[off - init_off]); + pci_user_write_config_byte(dev, off, data[off - init_off]); off++; --size; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d3f3dd42240d..6527b36c9a61 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -15,6 +15,13 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); +extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); +extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); +extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); +extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); +extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); +extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); + /* PCI /proc functions */ #ifdef CONFIG_PROC_FS extern int pci_proc_attach_device(struct pci_dev *dev); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 9613f666c110..9eb465727fce 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -80,7 +80,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if ((pos & 1) && cnt) { unsigned char val; - pci_read_config_byte(dev, pos, &val); + pci_user_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -89,7 +89,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if ((pos & 3) && cnt > 2) { unsigned short val; - pci_read_config_word(dev, pos, &val); + pci_user_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short __user *) buf); buf += 2; pos += 2; @@ -98,7 +98,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp while (cnt >= 4) { unsigned int val; - pci_read_config_dword(dev, pos, &val); + pci_user_read_config_dword(dev, pos, &val); __put_user(cpu_to_le32(val), (unsigned int __user *) buf); buf += 4; pos += 4; @@ -107,7 +107,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if (cnt >= 2) { unsigned short val; - pci_read_config_word(dev, pos, &val); + pci_user_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short __user *) buf); buf += 2; pos += 2; @@ -116,7 +116,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if (cnt) { unsigned char val; - pci_read_config_byte(dev, pos, &val); + pci_user_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -151,7 +151,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if ((pos & 1) && cnt) { unsigned char val; __get_user(val, buf); - pci_write_config_byte(dev, pos, val); + pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -160,7 +160,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if ((pos & 3) && cnt > 2) { unsigned short val; __get_user(val, (unsigned short __user *) buf); - pci_write_config_word(dev, pos, le16_to_cpu(val)); + pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -169,7 +169,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof while (cnt >= 4) { unsigned int val; __get_user(val, (unsigned int __user *) buf); - pci_write_config_dword(dev, pos, le32_to_cpu(val)); + pci_user_write_config_dword(dev, pos, le32_to_cpu(val)); buf += 4; pos += 4; cnt -= 4; @@ -178,7 +178,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if (cnt >= 2) { unsigned short val; __get_user(val, (unsigned short __user *) buf); - pci_write_config_word(dev, pos, le16_to_cpu(val)); + pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -187,7 +187,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if (cnt) { unsigned char val; __get_user(val, buf); - pci_write_config_byte(dev, pos, val); + pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -484,10 +484,10 @@ static int show_dev_config(struct seq_file *m, void *v) drv = pci_dev_driver(dev); - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); - pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat); + pci_user_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + pci_user_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + pci_user_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); + pci_user_read_config_byte (dev, PCI_MAX_LAT, &max_lat); seq_printf(m, " Bus %2d, device %3d, function %2d:\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); seq_printf(m, " Class %04x", class_rev >> 16); diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index c071790cc983..87fafc08cb9d 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -13,7 +13,7 @@ #include #include #include - +#include "pci.h" asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, @@ -38,13 +38,13 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, lock_kernel(); switch (len) { case 1: - cfg_ret = pci_read_config_byte(dev, off, &byte); + cfg_ret = pci_user_read_config_byte(dev, off, &byte); break; case 2: - cfg_ret = pci_read_config_word(dev, off, &word); + cfg_ret = pci_user_read_config_word(dev, off, &word); break; case 4: - cfg_ret = pci_read_config_dword(dev, off, &dword); + cfg_ret = pci_user_read_config_dword(dev, off, &dword); break; default: err = -EINVAL; @@ -112,7 +112,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(byte, (u8 __user *)buf); if (err) break; - err = pci_write_config_byte(dev, off, byte); + err = pci_user_write_config_byte(dev, off, byte); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; @@ -121,7 +121,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(word, (u16 __user *)buf); if (err) break; - err = pci_write_config_word(dev, off, word); + err = pci_user_write_config_word(dev, off, word); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; @@ -130,7 +130,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(dword, (u32 __user *)buf); if (err) break; - err = pci_write_config_dword(dev, off, dword); + err = pci_user_write_config_dword(dev, off, dword); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; diff --git a/include/linux/pci.h b/include/linux/pci.h index 7349058ed778..3596ac94ecff 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -132,6 +132,7 @@ struct pci_dev { unsigned int is_enabled:1; /* pci_enable_device has been called */ 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 */ u32 saved_config_space[16]; /* config space saved at suspend time */ struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ @@ -490,6 +491,9 @@ extern void pci_disable_msix(struct pci_dev *dev); extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); #endif +extern void pci_block_user_cfg_access(struct pci_dev *dev); +extern void pci_unblock_user_cfg_access(struct pci_dev *dev); + /* * PCI domain support. Sometimes called PCI segment (eg by ACPI), * a PCI domain is defined to be a set of PCI busses which share @@ -560,6 +564,9 @@ static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int en #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) +static inline void pci_block_user_cfg_access(struct pci_dev *dev) { } +static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { } + #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ From b30197d2c07b396907b81673354a015a9d2b216c Mon Sep 17 00:00:00 2001 From: Brian King Date: Tue, 27 Sep 2005 01:21:56 -0700 Subject: [PATCH 1080/1939] [PATCH] PCI: ipr: Block config access during BIST IPR scsi adapter have an exposure today in that they issue BIST to the adapter to reset the card. If, during the time it takes to complete BIST, userspace attempts to access PCI config space, the host bus bridge will master abort the access since the ipr adapter does not respond on the PCI bus for a brief period of time when running BIST. On PPC64 hardware, this master abort results in the host PCI bridge isolating that PCI device from the rest of the system, making the device unusable until Linux is rebooted. This patch makes use of some newly added PCI layer APIs that allow for protection from userspace accessing config space of a device in scenarios such as this. Signed-off-by: Brian King Cc: Benjamin Herrenschmidt Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman drivers/scsi/ipr.c | 2 ++ 1 file changed, 2 insertions(+) --- drivers/scsi/ipr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index babd48363402..e0039dfae8e5 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4944,6 +4944,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) int rc; ENTER; + pci_unblock_user_cfg_access(ioa_cfg->pdev); rc = pci_restore_state(ioa_cfg->pdev); if (rc != PCIBIOS_SUCCESSFUL) { @@ -4998,6 +4999,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) int rc; ENTER; + pci_block_user_cfg_access(ioa_cfg->pdev); rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc != PCIBIOS_SUCCESSFUL) { From d3535fbbce0eef8faa8de30d187fc83b11b858ef Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Sep 2005 17:50:51 -0400 Subject: [PATCH 1081/1939] [PATCH] pci: cleanup need_restore switch statement Cleanup the need_restore switch statement in pci_set_power_state(). This makes it more safe by explicitly handling all the PCI power states instead of handling them as the default case. It also reads a little better IMHO. Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 259d247b7551..39bdb938521d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -314,19 +314,19 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) * sets PowerState to 0. */ switch (dev->current_state) { + case PCI_D0: + case PCI_D1: + case PCI_D2: + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= state; + break; case PCI_UNKNOWN: /* Boot-up */ if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) need_restore = 1; /* Fall-through: force to D0 */ - case PCI_D3hot: - case PCI_D3cold: - case PCI_POWER_ERROR: - pmcsr = 0; - break; default: - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= state; + pmcsr = 0; break; } From c8920f0c8b3b42537ab4a54ff92c11daf48fdfec Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 28 Sep 2005 15:15:16 -0600 Subject: [PATCH 1082/1939] [PATCH] cpcihp_zt5550: add pci_enable_device() Add pci_{enable,disable}_device() calls. Without pci_enable_device(), dev->irq is garbage, and cpcihp_zt5550 relies on it. Compiled but untested, since I don't have the hardware. Signed-off-by: Bjorn Helgaas Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman drivers/pci/hotplug/cpcihp_zt5550.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) --- drivers/pci/hotplug/cpcihp_zt5550.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index e9928024be78..790abadd816c 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -78,11 +78,20 @@ static void __iomem *csr_int_mask; static int zt5550_hc_config(struct pci_dev *pdev) { + int ret; + /* Since we know that no boards exist with two HC chips, treat it as an error */ if(hc_dev) { err("too many host controller devices?"); return -EBUSY; } + + ret = pci_enable_device(pdev); + if(ret) { + err("cannot enable %s\n", pci_name(pdev)); + return ret; + } + hc_dev = pdev; dbg("hc_dev = %p", hc_dev); dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); @@ -91,7 +100,8 @@ static int zt5550_hc_config(struct pci_dev *pdev) if(!request_mem_region(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1), MY_NAME)) { err("cannot reserve MMIO region"); - return -ENOMEM; + ret = -ENOMEM; + goto exit_disable_device; } hc_registers = @@ -99,9 +109,8 @@ static int zt5550_hc_config(struct pci_dev *pdev) if(!hc_registers) { err("cannot remap MMIO region %lx @ %lx", pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return -ENODEV; + ret = -ENODEV; + goto exit_release_region; } csr_hc_index = hc_registers + CSR_HCINDEX; @@ -124,6 +133,13 @@ static int zt5550_hc_config(struct pci_dev *pdev) writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); dbg("disabled timer0, timer1 and ENUM interrupts"); return 0; + +exit_release_region: + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); +exit_disable_device: + pci_disable_device(hc_dev); + return ret; } static int zt5550_hc_cleanup(void) @@ -134,6 +150,7 @@ static int zt5550_hc_cleanup(void) iounmap(hc_registers); release_mem_region(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); + pci_disable_device(hc_dev); return 0; } From fe89cf4c4b7a3d9a0ff95eb0506aa7c9baaccda1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 28 Sep 2005 14:03:08 -0600 Subject: [PATCH 1083/1939] [PATCH] cpqphp: add pci_enable_device() Add pci_{enable,disable}_device() calls. Without pci_enable_device(), dev->irq is garbage, and cpqphp relies on it. This fixes a problem reported by Bruno Redondi. He reported a flood of ACPI interrupts, that caused kacpid to run 100% of the time: http://bugzilla.kernel.org/show_bug.cgi?id=5312 Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman drivers/pci/hotplug/cpqphp_core.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) --- drivers/pci/hotplug/cpqphp_core.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 8c6d3987d461..9aed8efe6a11 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -794,12 +794,21 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u32 rc; struct controller *ctrl; struct pci_func *func; + int err; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR MY_NAME ": cannot enable PCI device %s (%d)\n", + pci_name(pdev), err); + return err; + } // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { err(msg_HPC_non_compaq_or_intel); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } dbg("Vendor ID: %x\n", vendor_id); @@ -807,7 +816,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dbg("revision: %d\n", rev); if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { err(msg_HPC_rev_error); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } /* Check for the proper subsytem ID's @@ -820,18 +830,20 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); if (rc) { err("%s : pci_read_config_word failed\n", __FUNCTION__); - return rc; + goto err_disable_device; } dbg("Subsystem Vendor ID: %x\n", subsystem_vid); if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_non_compaq_or_intel); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); - return -ENOMEM; + rc = -ENOMEM; + goto err_disable_device; } memset(ctrl, 0, sizeof(struct controller)); @@ -1264,6 +1276,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) kfree(ctrl->pci_bus); err_free_ctrl: kfree(ctrl); +err_disable_device: + pci_disable_device(pdev); return rc; } From acc06632e387fd05d2bf3480f6a2f4d1a62734b8 Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Thu, 29 Sep 2005 08:35:41 +0000 Subject: [PATCH 1084/1939] [PATCH] unhide ICH6 SMBus - take 2 This patch unhides hidden SMBus on ICH6 chipset installed in Asus M6V notebook. I would like to thank Michal Mleczko for testing and help. Signed-Off-By: Rudolf Marek Signed-off-by: Greg Kroah-Hartman drivers/pci/quirks.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) --- drivers/pci/quirks.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0663428a0e64..e1bd169cf55c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -934,6 +934,12 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x186a: /* M6Ne notebook */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + switch (dev->subsystem_device) { + case 0x1882: /* M6V notebook */ + asus_hides_smbus = 1; + } + } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -978,6 +984,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); static void __init asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -1002,6 +1009,23 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, as DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) +{ + u32 val, rcba; + void __iomem *base; + + if (likely(!asus_hides_smbus)) + return; + pci_read_config_dword(dev, 0xF0, &rcba); + base = ioremap_nocache(rcba & 0xFFFFC000, 0x4000); /* use bits 31:14, 16 kB aligned */ + if (base == NULL) return; + val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */ + writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */ + iounmap(base); + printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n"); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); + /* * SiS 96x south bridge: BIOS typically hides SMBus device... */ From b135c4815051bad6b2472e4ad0152f205918d2c5 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 29 Sep 2005 10:39:46 +1000 Subject: [PATCH 1085/1939] [PATCH] pci_ids: remove duplicates from pci_ids.h pci_ids.h cleanup: remove duplicated entries and change some defines to explicit value rather than in terms of another constant, preparation for removing unused symbols Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman include/linux/pci_ids.h | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) --- include/linux/pci_ids.h | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 71834f05504f..0631074954f7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -274,7 +274,6 @@ #define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 #define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 #define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 -#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 #define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 #define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 #define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 @@ -517,16 +516,16 @@ #define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 #define PCI_DEVICE_ID_AMD_VIPER_7414 0x7414 #define PCI_DEVICE_ID_AMD_OPUS_7440 0x7440 -# define PCI_DEVICE_ID_AMD_VIPER_7440 PCI_DEVICE_ID_AMD_OPUS_7440 +#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 #define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441 -# define PCI_DEVICE_ID_AMD_VIPER_7441 PCI_DEVICE_ID_AMD_OPUS_7441 +#define PCI_DEVICE_ID_AMD_VIPER_7441 0x7441 #define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443 -# define PCI_DEVICE_ID_AMD_VIPER_7443 PCI_DEVICE_ID_AMD_OPUS_7443 +#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 #define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445 #define PCI_DEVICE_ID_AMD_OPUS_7448 0x7448 -# define PCI_DEVICE_ID_AMD_VIPER_7448 PCI_DEVICE_ID_AMD_OPUS_7448 +#define PCI_DEVICE_ID_AMD_VIPER_7448 0x7448 #define PCI_DEVICE_ID_AMD_OPUS_7449 0x7449 -# define PCI_DEVICE_ID_AMD_VIPER_7449 PCI_DEVICE_ID_AMD_OPUS_7449 +#define PCI_DEVICE_ID_AMD_VIPER_7449 0x7449 #define PCI_DEVICE_ID_AMD_8111_LAN 0x7462 #define PCI_DEVICE_ID_AMD_8111_LPC 0x7468 #define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 @@ -585,7 +584,6 @@ #define PCI_DEVICE_ID_CT_65550 0x00e0 #define PCI_DEVICE_ID_CT_65554 0x00e4 #define PCI_DEVICE_ID_CT_65555 0x00e5 -#define PCI_DEVICE_ID_CT_69000 0x00c0 #define PCI_VENDOR_ID_MIRO 0x1031 #define PCI_DEVICE_ID_MIRO_36050 0x5601 @@ -1197,7 +1195,6 @@ #define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc #define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 -#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 #define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6 @@ -1623,7 +1620,7 @@ #define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB +#define PCI_DEVICE_ID_SERVERWORKS_CSB5USB 0x0220 #define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221 #define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 #define PCI_DEVICE_ID_SERVERWORKS_GCLE 0x0225 @@ -1792,10 +1789,6 @@ #define PCI_DEVICE_ID_PC300_TE_M_2 0x0320 #define PCI_DEVICE_ID_PC300_TE_M_1 0x0321 -/* Allied Telesyn */ -#define PCI_VENDOR_ID_AT 0x1259 -#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 - #define PCI_VENDOR_ID_ESSENTIAL 0x120f #define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 @@ -2340,16 +2333,13 @@ #define PCI_VENDOR_ID_DUNORD 0x5544 #define PCI_DEVICE_ID_DUNORD_I3000 0x0001 +#define PCI_VENDOR_ID_GENROCO 0x5555 +#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003 + #define PCI_VENDOR_ID_DCI 0x6666 #define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 #define PCI_DEVICE_ID_DCI_PCCOM8 0x0002 -#define PCI_VENDOR_ID_DUNORD 0x5544 -#define PCI_DEVICE_ID_DUNORD_I3000 0x0001 - -#define PCI_VENDOR_ID_GENROCO 0x5555 -#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003 - #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 #define PCI_DEVICE_ID_INTEL_21145 0x0039 From 4153812fc10ea91cb1a7b6ea4f4337dd211c1ef7 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 29 Sep 2005 10:40:52 +1000 Subject: [PATCH 1086/1939] [PATCH] pci_ids: macros: replace partial with whole symbols pci_ids cleanup: replace symbols built by macros with whole symbols to aid grep searches. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman drivers/video/cirrusfb.c | 24 ++++++++++++------------ sound/oss/ymfpci.c | 17 +++++++++-------- sound/pci/bt87x.c | 11 +++++++---- 3 files changed, 28 insertions(+), 24 deletions(-) --- drivers/video/cirrusfb.c | 24 ++++++++++++------------ sound/oss/ymfpci.c | 17 +++++++++-------- sound/pci/bt87x.c | 11 +++++++---- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index a3040429c27b..3a26f9cc8585 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -275,20 +275,20 @@ static const struct cirrusfb_board_info_rec { #ifdef CONFIG_PCI #define CHIP(id, btype) \ - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_##id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } + { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } static struct pci_device_id cirrusfb_pci_table[] = { - CHIP( CIRRUS_5436, BT_ALPINE ), - CHIP( CIRRUS_5434_8, BT_ALPINE ), - CHIP( CIRRUS_5434_4, BT_ALPINE ), - CHIP( CIRRUS_5430, BT_ALPINE ), /* GD-5440 has identical id */ - CHIP( CIRRUS_7543, BT_ALPINE ), - CHIP( CIRRUS_7548, BT_ALPINE ), - CHIP( CIRRUS_5480, BT_GD5480 ), /* MacPicasso probably */ - CHIP( CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is a GD5446 */ - CHIP( CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ - CHIP( CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ - CHIP( CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ + CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */ + CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */ + CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */ + CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ + CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ + CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ { 0, } }; MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c index 05203ad523f7..8dae59bd05a2 100644 --- a/sound/oss/ymfpci.c +++ b/sound/oss/ymfpci.c @@ -107,14 +107,15 @@ static LIST_HEAD(ymf_devs); */ static struct pci_device_id ymf_id_tbl[] = { -#define DEV(v, d, data) \ - { PCI_VENDOR_ID_##v, PCI_DEVICE_ID_##v##_##d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)data } - DEV (YAMAHA, 724, "YMF724"), - DEV (YAMAHA, 724F, "YMF724F"), - DEV (YAMAHA, 740, "YMF740"), - DEV (YAMAHA, 740C, "YMF740C"), - DEV (YAMAHA, 744, "YMF744"), - DEV (YAMAHA, 754, "YMF754"), +#define DEV(dev, data) \ + { PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \ + (unsigned long)data } + DEV (PCI_DEVICE_ID_YAMAHA_724, "YMF724"), + DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"), + DEV (PCI_DEVICE_ID_YAMAHA_740, "YMF740"), + DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"), + DEV (PCI_DEVICE_ID_YAMAHA_744, "YMF744"), + DEV (PCI_DEVICE_ID_YAMAHA_754, "YMF754"), #undef DEV { } }; diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 2236c958aec0..01d98eeb242e 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -761,15 +761,18 @@ static int __devinit snd_bt87x_create(snd_card_t *card, #define BT_DEVICE(chip, subvend, subdev, rate) \ { .vendor = PCI_VENDOR_ID_BROOKTREE, \ - .device = PCI_DEVICE_ID_BROOKTREE_##chip, \ + .device = chip, \ .subvendor = subvend, .subdevice = subdev, \ .driver_data = rate } /* driver_data is the default digital_rate value for that device */ static struct pci_device_id snd_bt87x_ids[] = { - BT_DEVICE(878, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */ - BT_DEVICE(879, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */ - BT_DEVICE(878, 0x0070, 0xff01, 44100), /* Viewcast Osprey 200 */ + /* Hauppauge WinTV series */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, 32000), + /* Hauppauge WinTV series */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), + /* Viewcast Osprey 200 */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), { } }; MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); From b7924c38c9a9c6151213bc0d91776eace614e761 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 29 Sep 2005 11:06:40 +1000 Subject: [PATCH 1087/1939] [PATCH] pci_ids: remove non-referenced symbols from pci_ids.h pci_ids.h cleanup: removed non-referenced symbols, compile tested with 'make allmodconfig' Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman include/linux/pci_ids.h | 540 ------------------------------------------------ 1 file changed, 540 deletions(-) --- include/linux/pci_ids.h | 540 ---------------------------------------- 1 file changed, 540 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 0631074954f7..11fed60a928d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -132,9 +132,6 @@ #define PCI_VENDOR_ID_COMPAQ 0x0e11 #define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508 -#define PCI_DEVICE_ID_COMPAQ_1280 0x3033 -#define PCI_DEVICE_ID_COMPAQ_TRIFLEX 0x4000 -#define PCI_DEVICE_ID_COMPAQ_6010 0x6010 #define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc #define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10 #define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32 @@ -281,8 +278,6 @@ #define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057 #define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058 /* Rage128 M4 */ -#define PCI_DEVICE_ID_ATI_RADEON_LE 0x4d45 -#define PCI_DEVICE_ID_ATI_RADEON_LF 0x4d46 /* Radeon R100 */ #define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144 #define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145 @@ -303,32 +298,22 @@ #define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157 #define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158 /* Radeon NV-100 */ -#define PCI_DEVICE_ID_ATI_RADEON_N1 0x5159 -#define PCI_DEVICE_ID_ATI_RADEON_N2 0x515a /* Radeon RV250 (9000) */ #define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964 #define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965 #define PCI_DEVICE_ID_ATI_RADEON_If 0x4966 #define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967 /* Radeon RV280 (9200) */ -#define PCI_DEVICE_ID_ATI_RADEON_Y_ 0x5960 #define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961 #define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964 /* Radeon R300 (9500) */ -#define PCI_DEVICE_ID_ATI_RADEON_AD 0x4144 /* Radeon R300 (9700) */ #define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44 #define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45 #define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46 #define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47 -#define PCI_DEVICE_ID_ATI_RADEON_AE 0x4145 -#define PCI_DEVICE_ID_ATI_RADEON_AF 0x4146 /* Radeon R350 (9800) */ -#define PCI_DEVICE_ID_ATI_RADEON_NH 0x4e48 -#define PCI_DEVICE_ID_ATI_RADEON_NI 0x4e49 /* Radeon RV350 (9600) */ -#define PCI_DEVICE_ID_ATI_RADEON_AP 0x4150 -#define PCI_DEVICE_ID_ATI_RADEON_AR 0x4152 /* Radeon M6 */ #define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59 #define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a @@ -341,10 +326,6 @@ #define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66 #define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67 /* Radeon */ -#define PCI_DEVICE_ID_ATI_RADEON_RA 0x5144 -#define PCI_DEVICE_ID_ATI_RADEON_RB 0x5145 -#define PCI_DEVICE_ID_ATI_RADEON_RC 0x5146 -#define PCI_DEVICE_ID_ATI_RADEON_RD 0x5147 /* RadeonIGP */ #define PCI_DEVICE_ID_ATI_RS100 0xcab0 #define PCI_DEVICE_ID_ATI_RS200 0xcab2 @@ -445,34 +426,18 @@ #define PCI_DEVICE_ID_CIRRUS_5465 0x00d6 #define PCI_DEVICE_ID_CIRRUS_6729 0x1100 #define PCI_DEVICE_ID_CIRRUS_6832 0x1110 -#define PCI_DEVICE_ID_CIRRUS_7542 0x1200 #define PCI_DEVICE_ID_CIRRUS_7543 0x1202 -#define PCI_DEVICE_ID_CIRRUS_7541 0x1204 #define PCI_DEVICE_ID_CIRRUS_4610 0x6001 #define PCI_DEVICE_ID_CIRRUS_4612 0x6003 #define PCI_DEVICE_ID_CIRRUS_4615 0x6004 -#define PCI_DEVICE_ID_CIRRUS_4281 0x6005 #define PCI_VENDOR_ID_IBM 0x1014 -#define PCI_DEVICE_ID_IBM_FIRE_CORAL 0x000a #define PCI_DEVICE_ID_IBM_TR 0x0018 -#define PCI_DEVICE_ID_IBM_82G2675 0x001d -#define PCI_DEVICE_ID_IBM_MCA 0x0020 -#define PCI_DEVICE_ID_IBM_82351 0x0022 -#define PCI_DEVICE_ID_IBM_PYTHON 0x002d -#define PCI_DEVICE_ID_IBM_SERVERAID 0x002e #define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e -#define PCI_DEVICE_ID_IBM_MPIC 0x0046 -#define PCI_DEVICE_ID_IBM_3780IDSP 0x007d -#define PCI_DEVICE_ID_IBM_CHUKAR 0x0096 #define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc -#define PCI_DEVICE_ID_IBM_CPC710_PCI32 0x0105 -#define PCI_DEVICE_ID_IBM_405GP 0x0156 #define PCI_DEVICE_ID_IBM_SNIPE 0x0180 -#define PCI_DEVICE_ID_IBM_SERVERAIDI960 0x01bd #define PCI_DEVICE_ID_IBM_CITRINE 0x028C #define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166 -#define PCI_DEVICE_ID_IBM_MPIC_2 0xffff #define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031 #define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219 #define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A @@ -483,7 +448,6 @@ #define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 #define PCI_VENDOR_ID_WD 0x101c -#define PCI_DEVICE_ID_WD_7197 0x3296 #define PCI_DEVICE_ID_WD_90C 0xc24a #define PCI_VENDOR_ID_AMI 0x101e @@ -500,33 +464,18 @@ #define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 #define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 #define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C -#define PCI_DEVICE_ID_AMD_FE_GATE_700D 0x700D #define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E -#define PCI_DEVICE_ID_AMD_FE_GATE_700F 0x700F -#define PCI_DEVICE_ID_AMD_COBRA_7400 0x7400 #define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401 -#define PCI_DEVICE_ID_AMD_COBRA_7403 0x7403 -#define PCI_DEVICE_ID_AMD_COBRA_7404 0x7404 -#define PCI_DEVICE_ID_AMD_VIPER_7408 0x7408 #define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409 #define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B -#define PCI_DEVICE_ID_AMD_VIPER_740C 0x740C #define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410 #define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 #define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 -#define PCI_DEVICE_ID_AMD_VIPER_7414 0x7414 -#define PCI_DEVICE_ID_AMD_OPUS_7440 0x7440 #define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 #define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441 -#define PCI_DEVICE_ID_AMD_VIPER_7441 0x7441 #define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443 #define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 #define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445 -#define PCI_DEVICE_ID_AMD_OPUS_7448 0x7448 -#define PCI_DEVICE_ID_AMD_VIPER_7448 0x7448 -#define PCI_DEVICE_ID_AMD_OPUS_7449 0x7449 -#define PCI_DEVICE_ID_AMD_VIPER_7449 0x7449 -#define PCI_DEVICE_ID_AMD_8111_LAN 0x7462 #define PCI_DEVICE_ID_AMD_8111_LPC 0x7468 #define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 #define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a @@ -637,7 +586,6 @@ #define PCI_DEVICE_ID_SI_550 0x0550 #define PCI_DEVICE_ID_SI_540_VGA 0x5300 #define PCI_DEVICE_ID_SI_550_VGA 0x5315 -#define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 #define PCI_DEVICE_ID_SI_633 0x0633 @@ -648,30 +596,22 @@ #define PCI_DEVICE_ID_SI_648 0x0648 #define PCI_DEVICE_ID_SI_650 0x0650 #define PCI_DEVICE_ID_SI_651 0x0651 -#define PCI_DEVICE_ID_SI_652 0x0652 #define PCI_DEVICE_ID_SI_655 0x0655 #define PCI_DEVICE_ID_SI_661 0x0661 #define PCI_DEVICE_ID_SI_730 0x0730 #define PCI_DEVICE_ID_SI_733 0x0733 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 -#define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 #define PCI_DEVICE_ID_SI_740 0x0740 #define PCI_DEVICE_ID_SI_741 0x0741 #define PCI_DEVICE_ID_SI_745 0x0745 #define PCI_DEVICE_ID_SI_746 0x0746 -#define PCI_DEVICE_ID_SI_748 0x0748 -#define PCI_DEVICE_ID_SI_750 0x0750 -#define PCI_DEVICE_ID_SI_751 0x0751 -#define PCI_DEVICE_ID_SI_752 0x0752 #define PCI_DEVICE_ID_SI_755 0x0755 #define PCI_DEVICE_ID_SI_760 0x0760 #define PCI_DEVICE_ID_SI_900 0x0900 #define PCI_DEVICE_ID_SI_961 0x0961 #define PCI_DEVICE_ID_SI_962 0x0962 #define PCI_DEVICE_ID_SI_963 0x0963 -#define PCI_DEVICE_ID_SI_5107 0x5107 -#define PCI_DEVICE_ID_SI_5300 0x5300 #define PCI_DEVICE_ID_SI_5511 0x5511 #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5518 0x5518 @@ -683,10 +623,6 @@ #define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_5598 0x5598 #define PCI_DEVICE_ID_SI_5600 0x5600 -#define PCI_DEVICE_ID_SI_6300 0x6300 -#define PCI_DEVICE_ID_SI_6306 0x6306 -#define PCI_DEVICE_ID_SI_6326 0x6326 -#define PCI_DEVICE_ID_SI_7001 0x7001 #define PCI_DEVICE_ID_SI_7012 0x7012 #define PCI_DEVICE_ID_SI_7013 0x7013 #define PCI_DEVICE_ID_SI_7016 0x7016 @@ -707,14 +643,11 @@ #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A #define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B -#define PCI_DEVICE_ID_HP_PCI_LBA 0x1054 -#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0 #define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 #define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b #define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 #define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 #define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 -#define PCI_DEVICE_ID_HP_ZX1_SBA 0x1229 #define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a #define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e #define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c @@ -722,9 +655,7 @@ #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 #define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 #define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a -#define PCI_DEVICE_ID_HP_CISS 0x3210 #define PCI_DEVICE_ID_HP_CISSA 0x3220 -#define PCI_DEVICE_ID_HP_CISSB 0x3222 #define PCI_DEVICE_ID_HP_CISSC 0x3230 #define PCI_DEVICE_ID_HP_CISSD 0x3238 #define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 @@ -732,8 +663,6 @@ #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 #define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 -#define PCI_DEVICE_ID_PCTECH_SAMURAI_0 0x3000 -#define PCI_DEVICE_ID_PCTECH_SAMURAI_1 0x3010 #define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 #define PCI_VENDOR_ID_ASUSTEK 0x1043 @@ -743,24 +672,15 @@ #define PCI_DEVICE_ID_DPT 0xa400 #define PCI_VENDOR_ID_OPTI 0x1045 -#define PCI_DEVICE_ID_OPTI_92C178 0xc178 -#define PCI_DEVICE_ID_OPTI_82C557 0xc557 #define PCI_DEVICE_ID_OPTI_82C558 0xc558 #define PCI_DEVICE_ID_OPTI_82C621 0xc621 #define PCI_DEVICE_ID_OPTI_82C700 0xc700 -#define PCI_DEVICE_ID_OPTI_82C701 0xc701 -#define PCI_DEVICE_ID_OPTI_82C814 0xc814 -#define PCI_DEVICE_ID_OPTI_82C822 0xc822 -#define PCI_DEVICE_ID_OPTI_82C861 0xc861 #define PCI_DEVICE_ID_OPTI_82C825 0xd568 #define PCI_VENDOR_ID_ELSA 0x1048 #define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 #define PCI_DEVICE_ID_ELSA_QS3000 0x3000 -#define PCI_VENDOR_ID_SGS 0x104a -#define PCI_DEVICE_ID_SGS_2000 0x0008 -#define PCI_DEVICE_ID_SGS_1764 0x0009 #define PCI_VENDOR_ID_BUSLOGIC 0x104B #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 @@ -768,7 +688,6 @@ #define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 #define PCI_VENDOR_ID_TI 0x104c -#define PCI_DEVICE_ID_TI_TVP4010 0x3d04 #define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 @@ -802,14 +721,10 @@ #define PCI_DEVICE_ID_TI_X420 0xac8e #define PCI_VENDOR_ID_SONY 0x104d -#define PCI_DEVICE_ID_SONY_CXD3222 0x8039 -#define PCI_VENDOR_ID_OAK 0x104e -#define PCI_DEVICE_ID_OAK_OTI107 0x0107 /* Winbond have two vendor IDs! See 0x10ad as well */ #define PCI_VENDOR_ID_WINBOND2 0x1050 -#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 #define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a #define PCI_DEVICE_ID_WINBOND2_6692 0x6692 @@ -818,19 +733,15 @@ #define PCI_VENDOR_ID_EFAR 0x1055 #define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130 -#define PCI_DEVICE_ID_EFAR_SLC90E66_0 0x9460 -#define PCI_DEVICE_ID_EFAR_SLC90E66_2 0x9462 #define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463 #define PCI_VENDOR_ID_MOTOROLA 0x1057 -#define PCI_VENDOR_ID_MOTOROLA_OOPS 0x1507 #define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001 #define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 #define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004 #define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 #define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802 #define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803 -#define PCI_DEVICE_ID_MOTOROLA_CPX8216 0x4806 #define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b #define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803 @@ -841,33 +752,19 @@ #define PCI_DEVICE_ID_PROMISE_20262 0x4d38 #define PCI_DEVICE_ID_PROMISE_20263 0x0D38 #define PCI_DEVICE_ID_PROMISE_20268 0x4d68 -#define PCI_DEVICE_ID_PROMISE_20268R 0x6268 #define PCI_DEVICE_ID_PROMISE_20269 0x4d69 #define PCI_DEVICE_ID_PROMISE_20270 0x6268 #define PCI_DEVICE_ID_PROMISE_20271 0x6269 #define PCI_DEVICE_ID_PROMISE_20275 0x1275 #define PCI_DEVICE_ID_PROMISE_20276 0x5275 #define PCI_DEVICE_ID_PROMISE_20277 0x7275 -#define PCI_DEVICE_ID_PROMISE_5300 0x5300 -#define PCI_VENDOR_ID_N9 0x105d -#define PCI_DEVICE_ID_N9_I128 0x2309 -#define PCI_DEVICE_ID_N9_I128_2 0x2339 -#define PCI_DEVICE_ID_N9_I128_T2R 0x493d #define PCI_VENDOR_ID_UMC 0x1060 #define PCI_DEVICE_ID_UMC_UM8673F 0x0101 -#define PCI_DEVICE_ID_UMC_UM8891A 0x0891 #define PCI_DEVICE_ID_UMC_UM8886BF 0x673a #define PCI_DEVICE_ID_UMC_UM8886A 0x886a -#define PCI_DEVICE_ID_UMC_UM8881F 0x8881 -#define PCI_DEVICE_ID_UMC_UM8886F 0x8886 -#define PCI_DEVICE_ID_UMC_UM9017F 0x9017 -#define PCI_DEVICE_ID_UMC_UM8886N 0xe886 -#define PCI_DEVICE_ID_UMC_UM8891N 0xe891 -#define PCI_VENDOR_ID_X 0x1061 -#define PCI_DEVICE_ID_X_AGX016 0x0001 #define PCI_VENDOR_ID_MYLEX 0x1069 #define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001 @@ -878,37 +775,26 @@ #define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56 #define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166 -#define PCI_VENDOR_ID_PICOP 0x1066 -#define PCI_DEVICE_ID_PICOP_PT86C52X 0x0001 -#define PCI_DEVICE_ID_PICOP_PT80C524 0x8002 #define PCI_VENDOR_ID_APPLE 0x106b #define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 -#define PCI_DEVICE_ID_APPLE_GC 0x0002 #define PCI_DEVICE_ID_APPLE_HYDRA 0x000e #define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 -#define PCI_DEVICE_ID_APPLE_KL_USB 0x0019 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 -#define PCI_DEVICE_ID_APPLE_KEYLARGO 0x0022 #define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 -#define PCI_DEVICE_ID_APPLE_KEYLARGO_P 0x0025 -#define PCI_DEVICE_ID_APPLE_KL_USB_P 0x0026 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d #define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e -#define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 #define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 #define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b -#define PCI_DEVICE_ID_APPLE_KEYLARGO_I 0x003e #define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 #define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b #define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c #define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 #define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 -#define PCI_DEVICE_ID_APPLE_SH_FW 0x0052 #define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058 #define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059 #define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 @@ -921,12 +807,9 @@ #define PCI_DEVICE_ID_YAMAHA_744 0x0010 #define PCI_DEVICE_ID_YAMAHA_754 0x0012 -#define PCI_VENDOR_ID_NEXGEN 0x1074 -#define PCI_DEVICE_ID_NEXGEN_82C501 0x4e78 #define PCI_VENDOR_ID_QLOGIC 0x1077 #define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 -#define PCI_DEVICE_ID_QLOGIC_ISP1022 0x1022 #define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 #define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 #define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 @@ -944,32 +827,20 @@ #define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001 #define PCI_DEVICE_ID_CYRIX_5520 0x0002 #define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100 -#define PCI_DEVICE_ID_CYRIX_5530_SMI 0x0101 #define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102 #define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103 #define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104 -#define PCI_VENDOR_ID_LEADTEK 0x107d -#define PCI_DEVICE_ID_LEADTEK_805 0x0000 -#define PCI_VENDOR_ID_INTERPHASE 0x107e -#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004 -#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005 -#define PCI_DEVICE_ID_INTERPHASE_5575 0x0008 #define PCI_VENDOR_ID_CONTAQ 0x1080 -#define PCI_DEVICE_ID_CONTAQ_82C599 0x0600 #define PCI_DEVICE_ID_CONTAQ_82C693 0xc693 -#define PCI_VENDOR_ID_FOREX 0x1083 #define PCI_VENDOR_ID_OLICOM 0x108d -#define PCI_DEVICE_ID_OLICOM_OC3136 0x0001 -#define PCI_DEVICE_ID_OLICOM_OC2315 0x0011 #define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 #define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 #define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 -#define PCI_DEVICE_ID_OLICOM_OC6151 0x0021 #define PCI_VENDOR_ID_SUN 0x108e #define PCI_DEVICE_ID_SUN_EBUS 0x1000 @@ -988,49 +859,31 @@ #define PCI_DEVICE_ID_SUN_CASSINI 0xabba #define PCI_VENDOR_ID_CMD 0x1095 -#define PCI_DEVICE_ID_CMD_640 0x0640 #define PCI_DEVICE_ID_CMD_643 0x0643 #define PCI_DEVICE_ID_CMD_646 0x0646 -#define PCI_DEVICE_ID_CMD_647 0x0647 #define PCI_DEVICE_ID_CMD_648 0x0648 #define PCI_DEVICE_ID_CMD_649 0x0649 -#define PCI_DEVICE_ID_CMD_670 0x0670 -#define PCI_DEVICE_ID_CMD_680 0x0680 #define PCI_DEVICE_ID_SII_680 0x0680 #define PCI_DEVICE_ID_SII_3112 0x3112 #define PCI_DEVICE_ID_SII_1210SA 0x0240 -#define PCI_VENDOR_ID_VISION 0x1098 -#define PCI_DEVICE_ID_VISION_QD8500 0x0001 -#define PCI_DEVICE_ID_VISION_QD8580 0x0002 #define PCI_VENDOR_ID_BROOKTREE 0x109e -#define PCI_DEVICE_ID_BROOKTREE_848 0x0350 -#define PCI_DEVICE_ID_BROOKTREE_849A 0x0351 -#define PCI_DEVICE_ID_BROOKTREE_878_1 0x036e #define PCI_DEVICE_ID_BROOKTREE_878 0x0878 #define PCI_DEVICE_ID_BROOKTREE_879 0x0879 -#define PCI_DEVICE_ID_BROOKTREE_8474 0x8474 -#define PCI_VENDOR_ID_SIERRA 0x10a8 -#define PCI_DEVICE_ID_SIERRA_STB 0x0000 #define PCI_VENDOR_ID_SGI 0x10a9 #define PCI_DEVICE_ID_SGI_IOC3 0x0003 #define PCI_DEVICE_ID_SGI_IOC4 0x100a #define PCI_VENDOR_ID_SGI_LITHIUM 0x1002 -#define PCI_VENDOR_ID_ACC 0x10aa -#define PCI_DEVICE_ID_ACC_2056 0x0000 #define PCI_VENDOR_ID_WINBOND 0x10ad -#define PCI_DEVICE_ID_WINBOND_83769 0x0001 #define PCI_DEVICE_ID_WINBOND_82C105 0x0105 #define PCI_DEVICE_ID_WINBOND_83C553 0x0565 -#define PCI_VENDOR_ID_DATABOOK 0x10b3 -#define PCI_DEVICE_ID_DATABOOK_87144 0xb106 #define PCI_VENDOR_ID_PLX 0x10b5 #define PCI_DEVICE_ID_PLX_R685 0x1030 @@ -1041,33 +894,19 @@ #define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 #define PCI_DEVICE_ID_PLX_R753 0x1152 #define PCI_DEVICE_ID_PLX_OLITEC 0x1187 -#define PCI_DEVICE_ID_PLX_9030 0x9030 #define PCI_DEVICE_ID_PLX_9050 0x9050 -#define PCI_DEVICE_ID_PLX_9060 0x9060 -#define PCI_DEVICE_ID_PLX_9060ES 0x906E -#define PCI_DEVICE_ID_PLX_9060SD 0x906D #define PCI_DEVICE_ID_PLX_9080 0x9080 #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 #define PCI_VENDOR_ID_MADGE 0x10b6 #define PCI_DEVICE_ID_MADGE_MK2 0x0002 -#define PCI_DEVICE_ID_MADGE_C155S 0x1001 #define PCI_VENDOR_ID_3COM 0x10b7 #define PCI_DEVICE_ID_3COM_3C985 0x0001 #define PCI_DEVICE_ID_3COM_3C940 0x1700 #define PCI_DEVICE_ID_3COM_3C339 0x3390 #define PCI_DEVICE_ID_3COM_3C359 0x3590 -#define PCI_DEVICE_ID_3COM_3C590 0x5900 -#define PCI_DEVICE_ID_3COM_3C595TX 0x5950 -#define PCI_DEVICE_ID_3COM_3C595T4 0x5951 -#define PCI_DEVICE_ID_3COM_3C595MII 0x5952 #define PCI_DEVICE_ID_3COM_3C940B 0x80eb -#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000 -#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001 -#define PCI_DEVICE_ID_3COM_3C905TX 0x9050 -#define PCI_DEVICE_ID_3COM_3C905T4 0x9051 -#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055 #define PCI_DEVICE_ID_3COM_3CR990 0x9900 #define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902 #define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903 @@ -1077,24 +916,11 @@ #define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909 #define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a -#define PCI_VENDOR_ID_SMC 0x10b8 -#define PCI_DEVICE_ID_SMC_EPIC100 0x0005 #define PCI_VENDOR_ID_AL 0x10b9 -#define PCI_DEVICE_ID_AL_M1445 0x1445 -#define PCI_DEVICE_ID_AL_M1449 0x1449 -#define PCI_DEVICE_ID_AL_M1451 0x1451 -#define PCI_DEVICE_ID_AL_M1461 0x1461 -#define PCI_DEVICE_ID_AL_M1489 0x1489 -#define PCI_DEVICE_ID_AL_M1511 0x1511 -#define PCI_DEVICE_ID_AL_M1513 0x1513 -#define PCI_DEVICE_ID_AL_M1521 0x1521 -#define PCI_DEVICE_ID_AL_M1523 0x1523 -#define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1535 0x1535 #define PCI_DEVICE_ID_AL_M1541 0x1541 -#define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M1563 0x1563 #define PCI_DEVICE_ID_AL_M1621 0x1621 #define PCI_DEVICE_ID_AL_M1631 0x1631 @@ -1107,49 +933,23 @@ #define PCI_DEVICE_ID_AL_M1681 0x1681 #define PCI_DEVICE_ID_AL_M1683 0x1683 #define PCI_DEVICE_ID_AL_M1689 0x1689 -#define PCI_DEVICE_ID_AL_M3307 0x3307 -#define PCI_DEVICE_ID_AL_M4803 0x5215 #define PCI_DEVICE_ID_AL_M5219 0x5219 #define PCI_DEVICE_ID_AL_M5228 0x5228 #define PCI_DEVICE_ID_AL_M5229 0x5229 -#define PCI_DEVICE_ID_AL_M5237 0x5237 -#define PCI_DEVICE_ID_AL_M5243 0x5243 #define PCI_DEVICE_ID_AL_M5451 0x5451 #define PCI_DEVICE_ID_AL_M7101 0x7101 -#define PCI_VENDOR_ID_MITSUBISHI 0x10ba -#define PCI_VENDOR_ID_SURECOM 0x10bd -#define PCI_DEVICE_ID_SURECOM_NE34 0x0e34 #define PCI_VENDOR_ID_NEOMAGIC 0x10c8 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV 0x0005 -#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS 0x0083 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 #define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 -#define PCI_VENDOR_ID_ASP 0x10cd -#define PCI_DEVICE_ID_ASP_ABP940 0x1200 -#define PCI_DEVICE_ID_ASP_ABP940U 0x1300 -#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300 - -#define PCI_VENDOR_ID_MACRONIX 0x10d9 -#define PCI_DEVICE_ID_MACRONIX_MX98713 0x0512 -#define PCI_DEVICE_ID_MACRONIX_MX987x5 0x0531 #define PCI_VENDOR_ID_TCONRAD 0x10da #define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508 -#define PCI_VENDOR_ID_CERN 0x10dc -#define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001 -#define PCI_DEVICE_ID_CERN_SPSB_PCI 0x0002 -#define PCI_DEVICE_ID_CERN_HIPPI_DST 0x0021 -#define PCI_DEVICE_ID_CERN_HIPPI_SRC 0x0022 #define PCI_VENDOR_ID_NVIDIA 0x10de #define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 @@ -1281,7 +1081,6 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F #define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 #define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 -#define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 @@ -1332,24 +1131,13 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 #define PCI_VENDOR_ID_IMS 0x10e0 -#define PCI_DEVICE_ID_IMS_8849 0x8849 #define PCI_DEVICE_ID_IMS_TT128 0x9128 #define PCI_DEVICE_ID_IMS_TT3D 0x9135 -#define PCI_VENDOR_ID_TEKRAM2 0x10e1 -#define PCI_DEVICE_ID_TEKRAM2_690c 0x690c -#define PCI_VENDOR_ID_TUNDRA 0x10e3 -#define PCI_DEVICE_ID_TUNDRA_CA91C042 0x0000 -#define PCI_VENDOR_ID_AMCC 0x10e8 -#define PCI_DEVICE_ID_AMCC_MYRINET 0x8043 -#define PCI_DEVICE_ID_AMCC_PARASTATION 0x8062 -#define PCI_DEVICE_ID_AMCC_S5933 0x807d -#define PCI_DEVICE_ID_AMCC_S5933_HEPC3 0x809c #define PCI_VENDOR_ID_INTERG 0x10ea -#define PCI_DEVICE_ID_INTERG_1680 0x1680 #define PCI_DEVICE_ID_INTERG_1682 0x1682 #define PCI_DEVICE_ID_INTERG_2000 0x2000 #define PCI_DEVICE_ID_INTERG_2010 0x2010 @@ -1357,27 +1145,18 @@ #define PCI_DEVICE_ID_INTERG_5050 0x5050 #define PCI_VENDOR_ID_REALTEK 0x10ec -#define PCI_DEVICE_ID_REALTEK_8029 0x8029 -#define PCI_DEVICE_ID_REALTEK_8129 0x8129 #define PCI_DEVICE_ID_REALTEK_8139 0x8139 -#define PCI_DEVICE_ID_REALTEK_8169 0x8169 #define PCI_VENDOR_ID_XILINX 0x10ee #define PCI_DEVICE_ID_RME_DIGI96 0x3fc0 #define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1 #define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2 #define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3 -#define PCI_DEVICE_ID_XILINX_HAMMERFALL 0x3fc4 #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 -#define PCI_DEVICE_ID_TURBOPAM 0x4020 -#define PCI_VENDOR_ID_TRUEVISION 0x10fa -#define PCI_DEVICE_ID_TRUEVISION_T1000 0x000c #define PCI_VENDOR_ID_INIT 0x1101 -#define PCI_DEVICE_ID_INIT_320P 0x9100 -#define PCI_DEVICE_ID_INIT_360P 0x9500 #define PCI_VENDOR_ID_CREATIVE 0x1102 // duplicate: ECTIVA #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 @@ -1405,36 +1184,25 @@ #define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 #define PCI_DEVICE_ID_VIA_8501_0 0x0501 -#define PCI_DEVICE_ID_VIA_82C505 0x0505 #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_82C585 0x0585 #define PCI_DEVICE_ID_VIA_82C586_0 0x0586 -#define PCI_DEVICE_ID_VIA_82C595 0x0595 #define PCI_DEVICE_ID_VIA_82C596 0x0596 #define PCI_DEVICE_ID_VIA_82C597_0 0x0597 #define PCI_DEVICE_ID_VIA_82C598_0 0x0598 #define PCI_DEVICE_ID_VIA_8601_0 0x0601 #define PCI_DEVICE_ID_VIA_8605_0 0x0605 -#define PCI_DEVICE_ID_VIA_82C680 0x0680 #define PCI_DEVICE_ID_VIA_82C686 0x0686 #define PCI_DEVICE_ID_VIA_82C691_0 0x0691 -#define PCI_DEVICE_ID_VIA_82C693 0x0693 -#define PCI_DEVICE_ID_VIA_82C693_1 0x0698 -#define PCI_DEVICE_ID_VIA_82C926 0x0926 #define PCI_DEVICE_ID_VIA_82C576_1 0x1571 -#define PCI_DEVICE_ID_VIA_82C595_97 0x1595 #define PCI_DEVICE_ID_VIA_82C586_2 0x3038 #define PCI_DEVICE_ID_VIA_82C586_3 0x3040 -#define PCI_DEVICE_ID_VIA_6305 0x3044 #define PCI_DEVICE_ID_VIA_82C596_3 0x3050 #define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 #define PCI_DEVICE_ID_VIA_82C686_4 0x3057 #define PCI_DEVICE_ID_VIA_82C686_5 0x3058 #define PCI_DEVICE_ID_VIA_8233_5 0x3059 -#define PCI_DEVICE_ID_VIA_8233_7 0x3065 -#define PCI_DEVICE_ID_VIA_82C686_6 0x3068 #define PCI_DEVICE_ID_VIA_8233_0 0x3074 #define PCI_DEVICE_ID_VIA_8633_0 0x3091 #define PCI_DEVICE_ID_VIA_8367_0 0x3099 @@ -1452,38 +1220,23 @@ #define PCI_DEVICE_ID_VIA_XN266 0x3156 #define PCI_DEVICE_ID_VIA_8754C_0 0x3168 #define PCI_DEVICE_ID_VIA_8235 0x3177 -#define PCI_DEVICE_ID_VIA_P4N333 0x3178 #define PCI_DEVICE_ID_VIA_8385_0 0x3188 #define PCI_DEVICE_ID_VIA_8377_0 0x3189 #define PCI_DEVICE_ID_VIA_8378_0 0x3205 #define PCI_DEVICE_ID_VIA_8783_0 0x3208 -#define PCI_DEVICE_ID_VIA_P4M400 0x3209 #define PCI_DEVICE_ID_VIA_8237 0x3227 #define PCI_DEVICE_ID_VIA_3296_0 0x0296 -#define PCI_DEVICE_ID_VIA_86C100A 0x6100 #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_8371_1 0x8391 -#define PCI_DEVICE_ID_VIA_8501_1 0x8501 -#define PCI_DEVICE_ID_VIA_82C597_1 0x8597 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 -#define PCI_DEVICE_ID_VIA_8601_1 0x8601 -#define PCI_DEVICE_ID_VIA_8505_1 0x8605 -#define PCI_DEVICE_ID_VIA_8633_1 0xB091 -#define PCI_DEVICE_ID_VIA_8367_1 0xB099 -#define PCI_DEVICE_ID_VIA_P4X266_1 0xB101 -#define PCI_DEVICE_ID_VIA_8615_1 0xB103 -#define PCI_DEVICE_ID_VIA_8361_1 0xB112 -#define PCI_DEVICE_ID_VIA_8235_1 0xB168 #define PCI_DEVICE_ID_VIA_838X_1 0xB188 #define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198 #define PCI_VENDOR_ID_SIEMENS 0x110A #define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 -#define PCI_VENDOR_ID_SMC2 0x1113 -#define PCI_DEVICE_ID_SMC2_1211TX 0x1211 #define PCI_VENDOR_ID_VORTEX 0x1119 #define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 @@ -1506,18 +1259,6 @@ #define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103 #define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104 #define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105 -#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1 0x0110 -#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1 0x0111 -#define PCI_DEVICE_ID_VORTEX_GDT6537RP1 0x0112 -#define PCI_DEVICE_ID_VORTEX_GDT6557RP1 0x0113 -#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1 0x0114 -#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1 0x0115 -#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2 0x0120 -#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2 0x0121 -#define PCI_DEVICE_ID_VORTEX_GDT6537RP2 0x0122 -#define PCI_DEVICE_ID_VORTEX_GDT6557RP2 0x0123 -#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2 0x0124 -#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2 0x0125 #define PCI_VENDOR_ID_EF 0x111a #define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 @@ -1529,21 +1270,15 @@ #define PCI_DEVICE_ID_IDT_IDT77201 0x0001 #define PCI_VENDOR_ID_FORE 0x1127 -#define PCI_DEVICE_ID_FORE_PCA200PC 0x0210 #define PCI_DEVICE_ID_FORE_PCA200E 0x0300 -#define PCI_VENDOR_ID_IMAGINGTECH 0x112f -#define PCI_DEVICE_ID_IMAGINGTECH_ICPCI 0x0000 #define PCI_VENDOR_ID_PHILIPS 0x1131 -#define PCI_DEVICE_ID_PHILIPS_SAA7145 0x7145 #define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 #define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730 #define PCI_VENDOR_ID_EICON 0x1133 -#define PCI_DEVICE_ID_EICON_DIVA20PRO 0xe001 #define PCI_DEVICE_ID_EICON_DIVA20 0xe002 -#define PCI_DEVICE_ID_EICON_DIVA20PRO_U 0xe003 #define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 #define PCI_DEVICE_ID_EICON_DIVA201 0xe005 #define PCI_DEVICE_ID_EICON_DIVA202 0xe00b @@ -1555,35 +1290,17 @@ #define PCI_VENDOR_ID_ZIATECH 0x1138 #define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550 -#define PCI_VENDOR_ID_CYCLONE 0x113c -#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001 -#define PCI_VENDOR_ID_ALLIANCE 0x1142 -#define PCI_DEVICE_ID_ALLIANCE_PROMOTIO 0x3210 -#define PCI_DEVICE_ID_ALLIANCE_PROVIDEO 0x6422 -#define PCI_DEVICE_ID_ALLIANCE_AT24 0x6424 -#define PCI_DEVICE_ID_ALLIANCE_AT3D 0x643d #define PCI_VENDOR_ID_SYSKONNECT 0x1148 -#define PCI_DEVICE_ID_SYSKONNECT_FP 0x4000 #define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200 #define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300 #define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320 #define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400 #define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500 -#define PCI_VENDOR_ID_VMIC 0x114a -#define PCI_DEVICE_ID_VMIC_VME 0x7587 #define PCI_VENDOR_ID_DIGI 0x114f -#define PCI_DEVICE_ID_DIGI_EPC 0x0002 -#define PCI_DEVICE_ID_DIGI_RIGHTSWITCH 0x0003 -#define PCI_DEVICE_ID_DIGI_XEM 0x0004 -#define PCI_DEVICE_ID_DIGI_XR 0x0005 -#define PCI_DEVICE_ID_DIGI_CX 0x0006 -#define PCI_DEVICE_ID_DIGI_XRJ 0x0009 -#define PCI_DEVICE_ID_DIGI_EPCJ 0x000a -#define PCI_DEVICE_ID_DIGI_XR_920 0x0027 #define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070 #define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071 #define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072 @@ -1593,23 +1310,15 @@ #define PCI_DEVICE_ID_NEO_2RJ45 0x00CA #define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB -#define PCI_VENDOR_ID_MUTECH 0x1159 -#define PCI_DEVICE_ID_MUTECH_MV1000 0x0001 #define PCI_VENDOR_ID_XIRCOM 0x115d -#define PCI_DEVICE_ID_XIRCOM_X3201_ETH 0x0003 #define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101 #define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103 -#define PCI_VENDOR_ID_RENDITION 0x1163 -#define PCI_DEVICE_ID_RENDITION_VERITE 0x0001 -#define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000 #define PCI_VENDOR_ID_SERVERWORKS 0x1166 #define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 #define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 -#define PCI_DEVICE_ID_SERVERWORKS_CIOB30 0x0010 -#define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011 #define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 #define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 @@ -1619,13 +1328,7 @@ #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 #define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 -#define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5USB 0x0220 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221 #define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 -#define PCI_DEVICE_ID_SERVERWORKS_GCLE 0x0225 -#define PCI_DEVICE_ID_SERVERWORKS_GCLE2 0x0227 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230 #define PCI_VENDOR_ID_SBE 0x1176 #define PCI_DEVICE_ID_SBE_WANXL100 0x0301 @@ -1636,17 +1339,12 @@ #define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102 #define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103 #define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105 -#define PCI_DEVICE_ID_TOSHIBA_601 0x0601 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a -#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A 0x0603 -#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_B 0x060a #define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f #define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617 #define PCI_VENDOR_ID_TOSHIBA_2 0x102f -#define PCI_DEVICE_ID_TOSHIBA_TX3927 0x000a #define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 -#define PCI_DEVICE_ID_TOSHIBA_TX4927 0x0180 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 @@ -1661,7 +1359,6 @@ #define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 #define PCI_VENDOR_ID_ARTOP 0x1191 -#define PCI_DEVICE_ID_ARTOP_ATP8400 0x0004 #define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 #define PCI_DEVICE_ID_ARTOP_ATP860 0x0006 #define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007 @@ -1674,16 +1371,11 @@ #define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040 #define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050 #define PCI_DEVICE_ID_ARTOP_8060 0x8060 -#define PCI_DEVICE_ID_ARTOP_AEC67160 0x8080 -#define PCI_DEVICE_ID_ARTOP_AEC67160_2 0x8081 -#define PCI_DEVICE_ID_ARTOP_AEC67162 0x808a #define PCI_VENDOR_ID_ZEITNET 0x1193 #define PCI_DEVICE_ID_ZEITNET_1221 0x0001 #define PCI_DEVICE_ID_ZEITNET_1225 0x0002 -#define PCI_VENDOR_ID_OMEGA 0x119b -#define PCI_DEVICE_ID_OMEGA_82C092G 0x1221 #define PCI_VENDOR_ID_FUJITSU_ME 0x119e #define PCI_DEVICE_ID_FUJITSU_FS155 0x0001 @@ -1693,61 +1385,41 @@ #define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 #define PCI_VENDOR_ID_MARVELL 0x11ab -#define PCI_DEVICE_ID_MARVELL_GT64011 0x4146 -#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146 #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 #define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 #define PCI_DEVICE_ID_MARVELL_GT96100 0x9652 #define PCI_DEVICE_ID_MARVELL_GT96100A 0x9653 -#define PCI_VENDOR_ID_LITEON 0x11ad -#define PCI_DEVICE_ID_LITEON_LNE100TX 0x0002 #define PCI_VENDOR_ID_V3 0x11b0 #define PCI_DEVICE_ID_V3_V960 0x0001 -#define PCI_DEVICE_ID_V3_V350 0x0001 -#define PCI_DEVICE_ID_V3_V961 0x0002 #define PCI_DEVICE_ID_V3_V351 0x0002 -#define PCI_VENDOR_ID_NP 0x11bc -#define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001 #define PCI_VENDOR_ID_ATT 0x11c1 -#define PCI_DEVICE_ID_ATT_L56XMF 0x0440 #define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480 -#define PCI_VENDOR_ID_NEC2 0x11c3 /* NEC (2nd) */ #define PCI_VENDOR_ID_SPECIALIX 0x11cb #define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000 -#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 #define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 #define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004 -#define PCI_VENDOR_ID_AURAVISION 0x11d1 -#define PCI_DEVICE_ID_AURAVISION_VXP524 0x01f7 #define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 #define PCI_DEVICE_ID_AD1889JS 0x1889 -#define PCI_VENDOR_ID_IKON 0x11d5 -#define PCI_DEVICE_ID_IKON_10115 0x0115 -#define PCI_DEVICE_ID_IKON_10117 0x0117 -#define PCI_VENDOR_ID_SEGA 0x11db #define PCI_DEVICE_ID_SEGA_BBA 0x1234 #define PCI_VENDOR_ID_ZORAN 0x11de #define PCI_DEVICE_ID_ZORAN_36057 0x6057 #define PCI_DEVICE_ID_ZORAN_36120 0x6120 -#define PCI_VENDOR_ID_KINETIC 0x11f4 -#define PCI_DEVICE_ID_KINETIC_2915 0x2915 #define PCI_VENDOR_ID_COMPEX 0x11f6 #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 -#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401 #define PCI_VENDOR_ID_RP 0x11fe #define PCI_DEVICE_ID_RP32INTF 0x0001 @@ -1761,7 +1433,6 @@ #define PCI_DEVICE_ID_RP16SNI 0x0009 #define PCI_DEVICE_ID_RPP4 0x000A #define PCI_DEVICE_ID_RPP8 0x000B -#define PCI_DEVICE_ID_RP8M 0x000C #define PCI_DEVICE_ID_RP4M 0x000D #define PCI_DEVICE_ID_RP2_232 0x000E #define PCI_DEVICE_ID_RP2_422 0x000F @@ -1805,10 +1476,7 @@ #define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005 #define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 -#define PCI_VENDOR_ID_SIGMADES 0x1236 -#define PCI_DEVICE_ID_SIGMADES_6425 0x6401 -#define PCI_VENDOR_ID_CCUBE 0x123f #define PCI_VENDOR_ID_AVM 0x1244 #define PCI_DEVICE_ID_AVM_B1 0x0700 @@ -1818,19 +1486,8 @@ #define PCI_DEVICE_ID_AVM_C2 0x1100 #define PCI_DEVICE_ID_AVM_T1 0x1200 -#define PCI_VENDOR_ID_DIPIX 0x1246 #define PCI_VENDOR_ID_STALLION 0x124d -#define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000 -#define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002 -#define PCI_DEVICE_ID_STALLION_EIOPCI 0x0003 - -#define PCI_VENDOR_ID_OPTIBASE 0x1255 -#define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110 -#define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210 -#define PCI_DEVICE_ID_OPTIBASE_VPLEX 0x2110 -#define PCI_DEVICE_ID_OPTIBASE_VPLEXCC 0x2120 -#define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130 /* Allied Telesyn */ #define PCI_VENDOR_ID_AT 0x1259 @@ -1839,7 +1496,6 @@ #define PCI_VENDOR_ID_ESS 0x125d #define PCI_DEVICE_ID_ESS_ESS1968 0x1968 -#define PCI_DEVICE_ID_ESS_AUDIOPCI 0x1969 #define PCI_DEVICE_ID_ESS_ESS1978 0x1978 #define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 #define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 @@ -1852,11 +1508,7 @@ #define PCI_VENDOR_ID_SATSAGEM 0x1267 #define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 -#define PCI_DEVICE_ID_SATSAGEM_PCR2101 0x5352 -#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b -#define PCI_VENDOR_ID_HUGHES 0x1273 -#define PCI_DEVICE_ID_HUGHES_DIRECPC 0x0002 #define PCI_VENDOR_ID_ENSONIQ 0x1274 #define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 @@ -1877,13 +1529,10 @@ #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 /* formerly Platform Tech */ -#define PCI_VENDOR_ID_ESS_OLD 0x1285 #define PCI_DEVICE_ID_ESS_ESS0100 0x0100 #define PCI_VENDOR_ID_ALTEON 0x12ae -#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001 -#define PCI_VENDOR_ID_USR 0x12B9 #define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4 #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001 @@ -1898,8 +1547,6 @@ #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B -#define PCI_VENDOR_ID_PICTUREL 0x12c5 -#define PCI_DEVICE_ID_PICTUREL_PCIVST 0x0081 #define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 #define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 @@ -1921,8 +1568,6 @@ #define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8 #define PCI_DEVICE_ID_LML_33R10 0x8a02 -#define PCI_VENDOR_ID_CBOARDS 0x1307 -#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001 #define PCI_VENDOR_ID_SIIG 0x131f #define PCI_SUBVENDOR_ID_SIIG 0x131f @@ -1965,8 +1610,6 @@ #define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 -#define PCI_VENDOR_ID_RADISYS 0x1331 -#define PCI_DEVICE_ID_RADISYS_ENP2611 0x0030 #define PCI_VENDOR_ID_DOMEX 0x134a #define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 @@ -1974,8 +1617,6 @@ #define PCI_VENDOR_ID_QUATECH 0x135C #define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 #define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 -#define PCI_DEVICE_ID_QUATECH_DSC200 0x0030 -#define PCI_DEVICE_ID_QUATECH_QSC200 0x0040 #define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 #define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 @@ -1994,7 +1635,6 @@ #define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106 #define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 -#define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS 0x0109 #define PCI_VENDOR_ID_KAWASAKI 0x136b #define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 @@ -2008,12 +1648,9 @@ #define PCI_DEVICE_ID_LMC_SSI 0x0005 #define PCI_DEVICE_ID_LMC_T1 0x0006 -#define PCI_VENDOR_ID_MARIAN 0x1382 -#define PCI_DEVICE_ID_MARIAN_PRODIF_PLUS 0x2048 #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a -#define PCI_DEVICE_ID_NETGEAR_GA622 0x622a #define PCI_VENDOR_ID_APPLICOM 0x1389 #define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 @@ -2036,9 +1673,6 @@ #define PCI_DEVICE_ID_MOXA_CP134U 0x1340 #define PCI_DEVICE_ID_MOXA_C168 0x1680 #define PCI_DEVICE_ID_MOXA_CP168U 0x1681 -#define PCI_DEVICE_ID_MOXA_CP204J 0x2040 -#define PCI_DEVICE_ID_MOXA_C218 0x2180 -#define PCI_DEVICE_ID_MOXA_C320 0x3200 #define PCI_VENDOR_ID_CCD 0x1397 #define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 @@ -2059,9 +1693,7 @@ #define PCI_VENDOR_ID_MICROGATE 0x13c0 #define PCI_DEVICE_ID_MICROGATE_USC 0x0010 -#define PCI_DEVICE_ID_MICROGATE_SCC 0x0020 #define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 -#define PCI_DEVICE_ID_MICROGATE_USC2 0x0210 #define PCI_VENDOR_ID_3WARE 0x13C1 #define PCI_DEVICE_ID_3WARE_1000 0x1000 @@ -2112,10 +1744,6 @@ #define PCI_VENDOR_ID_SAMSUNG 0x144d -#define PCI_VENDOR_ID_AIRONET 0x14b9 -#define PCI_DEVICE_ID_AIRONET_4800_1 0x0001 -#define PCI_DEVICE_ID_AIRONET_4800 0x4500 // values switched? see -#define PCI_DEVICE_ID_AIRONET_4500 0x4800 // drivers/net/aironet4500_card.c #define PCI_VENDOR_ID_TITAN 0x14D2 #define PCI_DEVICE_ID_TITAN_010L 0x8001 @@ -2134,8 +1762,6 @@ #define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 -#define PCI_VENDOR_ID_SIPACKETS 0x14d9 -#define PCI_DEVICE_ID_SP_HT 0x0010 #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 @@ -2200,8 +1826,6 @@ #define PCI_VENDOR_ID_CHELSIO 0x1425 -#define PCI_VENDOR_ID_MIPS 0x153f -#define PCI_DEVICE_ID_SOC_IT 0x0001 #define PCI_VENDOR_ID_SYBA 0x1592 #define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 @@ -2221,15 +1845,7 @@ #define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 #define PCI_VENDOR_ID_PDC 0x15e9 -#define PCI_DEVICE_ID_PDC_1841 0x1841 -#define PCI_VENDOR_ID_MACROLINK 0x15ed -#define PCI_DEVICE_ID_MACROLINK_MCCS8 0x1000 -#define PCI_DEVICE_ID_MACROLINK_MCCS 0x1001 -#define PCI_DEVICE_ID_MACROLINK_MCCS8H 0x1002 -#define PCI_DEVICE_ID_MACROLINK_MCCSH 0x1003 -#define PCI_DEVICE_ID_MACROLINK_MCCR8 0x2000 -#define PCI_DEVICE_ID_MACROLINK_MCCR 0x2001 #define PCI_VENDOR_ID_FARSITE 0x1619 #define PCI_DEVICE_ID_FARSITE_T2P 0x0400 @@ -2247,7 +1863,6 @@ #define PCI_DEVICE_ID_REVOLUTION 0x0044 #define PCI_VENDOR_ID_LINKSYS 0x1737 -#define PCI_DEVICE_ID_LINKSYS_EG1032 0x1032 #define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 #define PCI_VENDOR_ID_ALTIMA 0x173b @@ -2262,7 +1877,6 @@ #define PCI_DEVICE_ID_HERC_WIN 0x5732 #define PCI_DEVICE_ID_HERC_UNI 0x5832 -#define PCI_VENDOR_ID_INFINICON 0x1820 #define PCI_VENDOR_ID_SITECOM 0x182d #define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 @@ -2272,8 +1886,6 @@ #define PCI_VENDOR_ID_TDI 0x192E #define PCI_DEVICE_ID_TDI_EHCI 0x0101 -#define PCI_VENDOR_ID_SYMPHONY 0x1c1c -#define PCI_DEVICE_ID_SYMPHONY_101 0x0001 #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 @@ -2282,59 +1894,26 @@ #define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013 #define PCI_VENDOR_ID_3DLABS 0x3d3d -#define PCI_DEVICE_ID_3DLABS_300SX 0x0001 -#define PCI_DEVICE_ID_3DLABS_500TX 0x0002 -#define PCI_DEVICE_ID_3DLABS_DELTA 0x0003 -#define PCI_DEVICE_ID_3DLABS_PERMEDIA 0x0004 -#define PCI_DEVICE_ID_3DLABS_MX 0x0006 #define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007 -#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008 #define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009 -#define PCI_VENDOR_ID_AVANCE 0x4005 -#define PCI_DEVICE_ID_AVANCE_ALG2064 0x2064 -#define PCI_DEVICE_ID_AVANCE_2302 0x2302 #define PCI_VENDOR_ID_AKS 0x416c #define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100 -#define PCI_DEVICE_ID_AKS_CPC 0x0200 -#define PCI_VENDOR_ID_REDCREEK 0x4916 -#define PCI_DEVICE_ID_RC45 0x1960 -#define PCI_VENDOR_ID_NETVIN 0x4a14 -#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000 #define PCI_VENDOR_ID_S3 0x5333 -#define PCI_DEVICE_ID_S3_PLATO_PXS 0x0551 -#define PCI_DEVICE_ID_S3_ViRGE 0x5631 #define PCI_DEVICE_ID_S3_TRIO 0x8811 -#define PCI_DEVICE_ID_S3_AURORA64VP 0x8812 -#define PCI_DEVICE_ID_S3_TRIO64UVP 0x8814 -#define PCI_DEVICE_ID_S3_ViRGE_VX 0x883d #define PCI_DEVICE_ID_S3_868 0x8880 -#define PCI_DEVICE_ID_S3_928 0x88b0 -#define PCI_DEVICE_ID_S3_864_1 0x88c0 -#define PCI_DEVICE_ID_S3_864_2 0x88c1 -#define PCI_DEVICE_ID_S3_964_1 0x88d0 -#define PCI_DEVICE_ID_S3_964_2 0x88d1 #define PCI_DEVICE_ID_S3_968 0x88f0 -#define PCI_DEVICE_ID_S3_TRIO64V2 0x8901 -#define PCI_DEVICE_ID_S3_PLATO_PXG 0x8902 -#define PCI_DEVICE_ID_S3_ViRGE_DXGX 0x8a01 -#define PCI_DEVICE_ID_S3_ViRGE_GX2 0x8a10 #define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25 -#define PCI_DEVICE_ID_S3_ViRGE_MX 0x8c01 -#define PCI_DEVICE_ID_S3_ViRGE_MXP 0x8c02 -#define PCI_DEVICE_ID_S3_ViRGE_MXPMV 0x8c03 #define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04 #define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 #define PCI_VENDOR_ID_DUNORD 0x5544 #define PCI_DEVICE_ID_DUNORD_I3000 0x0001 -#define PCI_VENDOR_ID_GENROCO 0x5555 -#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003 #define PCI_VENDOR_ID_DCI 0x6666 #define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 @@ -2342,7 +1921,6 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 -#define PCI_DEVICE_ID_INTEL_21145 0x0039 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 @@ -2351,30 +1929,17 @@ #define PCI_DEVICE_ID_INTEL_82375 0x0482 #define PCI_DEVICE_ID_INTEL_82424 0x0483 #define PCI_DEVICE_ID_INTEL_82378 0x0484 -#define PCI_DEVICE_ID_INTEL_82430 0x0486 -#define PCI_DEVICE_ID_INTEL_82434 0x04a3 #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 -#define PCI_DEVICE_ID_INTEL_82562ET 0x1031 -#define PCI_DEVICE_ID_INTEL_82801CAM 0x1038 #define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 -#define PCI_DEVICE_ID_INTEL_82815_AB 0x1131 #define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 -#define PCI_DEVICE_ID_INTEL_82559ER 0x1209 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 -#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 -#define PCI_DEVICE_ID_INTEL_7116 0x1223 #define PCI_DEVICE_ID_INTEL_7505_0 0x2550 -#define PCI_DEVICE_ID_INTEL_7505_1 0x2552 #define PCI_DEVICE_ID_INTEL_7205_0 0x255d -#define PCI_DEVICE_ID_INTEL_82596 0x1226 -#define PCI_DEVICE_ID_INTEL_82865 0x1227 -#define PCI_DEVICE_ID_INTEL_82557 0x1229 #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e #define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 #define PCI_DEVICE_ID_INTEL_82371MX 0x1234 -#define PCI_DEVICE_ID_INTEL_82437MX 0x1235 #define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82380FB 0x124b #define PCI_DEVICE_ID_INTEL_82439 0x1250 @@ -2383,83 +1948,53 @@ #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 #define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 -#define PCI_DEVICE_ID_INTEL_82801AA_2 0x2412 #define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 #define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 #define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416 #define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418 #define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420 #define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421 -#define PCI_DEVICE_ID_INTEL_82801AB_2 0x2422 #define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423 #define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425 #define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426 #define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428 #define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440 -#define PCI_DEVICE_ID_INTEL_82801BA_1 0x2442 #define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 -#define PCI_DEVICE_ID_INTEL_82801BA_3 0x2444 #define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445 -#define PCI_DEVICE_ID_INTEL_82801BA_5 0x2446 #define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448 -#define PCI_DEVICE_ID_INTEL_82801BA_7 0x2449 #define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a #define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b #define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c #define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e #define PCI_DEVICE_ID_INTEL_82801E_0 0x2450 -#define PCI_DEVICE_ID_INTEL_82801E_2 0x2452 -#define PCI_DEVICE_ID_INTEL_82801E_3 0x2453 -#define PCI_DEVICE_ID_INTEL_82801E_9 0x2459 #define PCI_DEVICE_ID_INTEL_82801E_11 0x245b -#define PCI_DEVICE_ID_INTEL_82801E_13 0x245d -#define PCI_DEVICE_ID_INTEL_82801E_14 0x245e #define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 -#define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482 #define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 -#define PCI_DEVICE_ID_INTEL_82801CA_4 0x2484 #define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485 #define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486 -#define PCI_DEVICE_ID_INTEL_82801CA_7 0x2487 #define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a #define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b #define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c #define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0 #define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1 -#define PCI_DEVICE_ID_INTEL_82801DB_2 0x24c2 #define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 -#define PCI_DEVICE_ID_INTEL_82801DB_4 0x24c4 #define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5 #define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6 -#define PCI_DEVICE_ID_INTEL_82801DB_7 0x24c7 #define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9 #define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca #define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb #define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc -#define PCI_DEVICE_ID_INTEL_82801DB_13 0x24cd #define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 #define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1 -#define PCI_DEVICE_ID_INTEL_82801EB_2 0x24d2 #define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3 -#define PCI_DEVICE_ID_INTEL_82801EB_4 0x24d4 #define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 #define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 -#define PCI_DEVICE_ID_INTEL_82801EB_7 0x24d7 #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db -#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd #define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 #define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 -#define PCI_DEVICE_ID_INTEL_ESB_3 0x25a3 -#define PCI_DEVICE_ID_INTEL_ESB_31 0x25b0 #define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 #define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 -#define PCI_DEVICE_ID_INTEL_ESB_6 0x25a7 -#define PCI_DEVICE_ID_INTEL_ESB_7 0x25a9 -#define PCI_DEVICE_ID_INTEL_ESB_8 0x25aa #define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab -#define PCI_DEVICE_ID_INTEL_ESB_11 0x25ac -#define PCI_DEVICE_ID_INTEL_ESB_12 0x25ad -#define PCI_DEVICE_ID_INTEL_ESB_13 0x25ae #define PCI_DEVICE_ID_INTEL_82820_HB 0x2500 #define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 @@ -2469,7 +2004,6 @@ #define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 #define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 #define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 -#define PCI_DEVICE_ID_INTEL_82875_IG 0x257b #define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580 #define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 #define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590 @@ -2479,80 +2013,23 @@ #define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 #define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 #define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 -#define PCI_DEVICE_ID_INTEL_ICH6_3 0x2651 -#define PCI_DEVICE_ID_INTEL_ICH6_4 0x2652 -#define PCI_DEVICE_ID_INTEL_ICH6_5 0x2653 -#define PCI_DEVICE_ID_INTEL_ICH6_6 0x2658 -#define PCI_DEVICE_ID_INTEL_ICH6_7 0x2659 -#define PCI_DEVICE_ID_INTEL_ICH6_8 0x265a -#define PCI_DEVICE_ID_INTEL_ICH6_9 0x265b -#define PCI_DEVICE_ID_INTEL_ICH6_10 0x265c -#define PCI_DEVICE_ID_INTEL_ICH6_11 0x2660 -#define PCI_DEVICE_ID_INTEL_ICH6_12 0x2662 -#define PCI_DEVICE_ID_INTEL_ICH6_13 0x2664 -#define PCI_DEVICE_ID_INTEL_ICH6_14 0x2666 -#define PCI_DEVICE_ID_INTEL_ICH6_15 0x2668 #define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a #define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d #define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e #define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f #define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 -#define PCI_DEVICE_ID_INTEL_ESB2_1 0x2680 -#define PCI_DEVICE_ID_INTEL_ESB2_2 0x2681 -#define PCI_DEVICE_ID_INTEL_ESB2_3 0x2682 -#define PCI_DEVICE_ID_INTEL_ESB2_4 0x2683 -#define PCI_DEVICE_ID_INTEL_ESB2_5 0x2688 -#define PCI_DEVICE_ID_INTEL_ESB2_6 0x2689 -#define PCI_DEVICE_ID_INTEL_ESB2_7 0x268a -#define PCI_DEVICE_ID_INTEL_ESB2_8 0x268b -#define PCI_DEVICE_ID_INTEL_ESB2_9 0x268c -#define PCI_DEVICE_ID_INTEL_ESB2_10 0x2690 -#define PCI_DEVICE_ID_INTEL_ESB2_11 0x2692 -#define PCI_DEVICE_ID_INTEL_ESB2_12 0x2694 -#define PCI_DEVICE_ID_INTEL_ESB2_13 0x2696 #define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 -#define PCI_DEVICE_ID_INTEL_ESB2_15 0x2699 -#define PCI_DEVICE_ID_INTEL_ESB2_16 0x269a #define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b #define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e #define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 -#define PCI_DEVICE_ID_INTEL_ICH7_2 0x27c0 -#define PCI_DEVICE_ID_INTEL_ICH7_3 0x27c1 #define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 #define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd -#define PCI_DEVICE_ID_INTEL_ICH7_5 0x27c4 -#define PCI_DEVICE_ID_INTEL_ICH7_6 0x27c5 -#define PCI_DEVICE_ID_INTEL_ICH7_7 0x27c8 -#define PCI_DEVICE_ID_INTEL_ICH7_8 0x27c9 -#define PCI_DEVICE_ID_INTEL_ICH7_9 0x27ca -#define PCI_DEVICE_ID_INTEL_ICH7_10 0x27cb -#define PCI_DEVICE_ID_INTEL_ICH7_11 0x27cc -#define PCI_DEVICE_ID_INTEL_ICH7_12 0x27d0 -#define PCI_DEVICE_ID_INTEL_ICH7_13 0x27d2 -#define PCI_DEVICE_ID_INTEL_ICH7_14 0x27d4 -#define PCI_DEVICE_ID_INTEL_ICH7_15 0x27d6 -#define PCI_DEVICE_ID_INTEL_ICH7_16 0x27d8 #define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da -#define PCI_DEVICE_ID_INTEL_ICH7_18 0x27dc #define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd #define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de #define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df -#define PCI_DEVICE_ID_INTEL_ICH7_22 0x27e0 -#define PCI_DEVICE_ID_INTEL_ICH7_23 0x27e2 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 -#define PCI_DEVICE_ID_INTEL_ESB2_19 0x3500 -#define PCI_DEVICE_ID_INTEL_ESB2_20 0x3501 -#define PCI_DEVICE_ID_INTEL_ESB2_21 0x3504 -#define PCI_DEVICE_ID_INTEL_ESB2_22 0x3505 -#define PCI_DEVICE_ID_INTEL_ESB2_23 0x350c -#define PCI_DEVICE_ID_INTEL_ESB2_24 0x350d -#define PCI_DEVICE_ID_INTEL_ESB2_25 0x3510 -#define PCI_DEVICE_ID_INTEL_ESB2_26 0x3511 -#define PCI_DEVICE_ID_INTEL_ESB2_27 0x3514 -#define PCI_DEVICE_ID_INTEL_ESB2_28 0x3515 -#define PCI_DEVICE_ID_INTEL_ESB2_29 0x3518 -#define PCI_DEVICE_ID_INTEL_ESB2_30 0x3519 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 @@ -2566,7 +2043,6 @@ #define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 #define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e -#define PCI_DEVICE_ID_INTEL_80310 0x530d #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 @@ -2591,22 +2067,15 @@ #define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 #define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 #define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 -#define PCI_DEVICE_ID_INTEL_82443MX_2 0x719a #define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 -#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 -#define PCI_DEVICE_ID_INTEL_82372FB_0 0x7600 #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 -#define PCI_DEVICE_ID_INTEL_82372FB_2 0x7602 -#define PCI_DEVICE_ID_INTEL_82372FB_3 0x7603 #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 -#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca #define PCI_DEVICE_ID_INTEL_82454NX 0x84cb #define PCI_DEVICE_ID_INTEL_84460GX 0x84ea #define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 -#define PCI_DEVICE_ID_INTEL_IXP2400 0x9001 #define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 @@ -2619,7 +2088,6 @@ #define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003 #define PCI_VENDOR_ID_KTI 0x8e2e -#define PCI_DEVICE_ID_KTI_ET32P2 0x3000 #define PCI_VENDOR_ID_ADAPTEC 0x9004 #define PCI_DEVICE_ID_ADAPTEC_7810 0x1078 @@ -2627,7 +2095,6 @@ #define PCI_DEVICE_ID_ADAPTEC_38602 0x3860 #define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 #define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 -#define PCI_DEVICE_ID_ADAPTEC_5800 0x5800 #define PCI_DEVICE_ID_ADAPTEC_3860 0x6038 #define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075 #define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 @@ -2647,7 +2114,6 @@ #define PCI_DEVICE_ID_ADAPTEC_7886 0x8678 #define PCI_DEVICE_ID_ADAPTEC_7887 0x8778 #define PCI_DEVICE_ID_ADAPTEC_7888 0x8878 -#define PCI_DEVICE_ID_ADAPTEC_1030 0x8b78 #define PCI_VENDOR_ID_ADAPTEC2 0x9005 #define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010 @@ -2667,8 +2133,6 @@ #define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf #define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503 -#define PCI_VENDOR_ID_ATRONICS 0x907f -#define PCI_DEVICE_ID_ATRONICS_2015 0x2015 #define PCI_VENDOR_ID_HOLTEK 0x9412 #define PCI_DEVICE_ID_HOLTEK_6565 0x6565 @@ -2701,7 +2165,3 @@ #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 -#define PCI_VENDOR_ID_ARK 0xedd8 -#define PCI_DEVICE_ID_ARK_STING 0xa091 -#define PCI_DEVICE_ID_ARK_STINGARK 0xa099 -#define PCI_DEVICE_ID_ARK_2000MT 0xa0a1 From 934199e95d6ac28f42686fe3009877eff33e06c3 Mon Sep 17 00:00:00 2001 From: linas Date: Wed, 28 Sep 2005 19:33:38 -0500 Subject: [PATCH 1088/1939] [PATCH] ppc64 PCI Hotplug: cleanup unsymmetric API routines This is a minor patch to the ppc64 PCI hotplug code; it makes the call to rpaphp_unconfig_pci_adapter() symmetric with respect to the call to rpaphp_config_pci_adapter(). I discussed this with John Rose, who had provided the last round of changes for these functions; he appearently had this patch but somehow failed to mail it out. Tested. (added/removed device). Signed-off-by: Linas Vepstas drivers/pci/hotplug/rpaphp.h | 3 ++- drivers/pci/hotplug/rpaphp_core.c | 5 ++++- drivers/pci/hotplug/rpaphp_pci.c | 11 +++-------- 3 files changed, 9 insertions(+), 10 deletions(-) --- drivers/pci/hotplug/rpaphp.h | 3 ++- drivers/pci/hotplug/rpaphp_core.c | 5 ++++- drivers/pci/hotplug/rpaphp_pci.c | 11 +++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 61d94d1e29cb..71ea5f9bb284 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -92,9 +92,10 @@ extern struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn); extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); extern int rpaphp_enable_pci_slot(struct slot *slot); extern int register_pci_slot(struct slot *slot); -extern int rpaphp_unconfig_pci_adapter(struct slot *slot); extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); + extern int rpaphp_config_pci_adapter(struct pci_bus *bus); +extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); /* rpaphp_core.c */ extern int rpaphp_add_slot(struct device_node *dn); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index c830ff0acdc3..cf075c34b578 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -426,8 +426,11 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) dbg("DISABLING SLOT %s\n", slot->name); down(&rpaphp_sem); - retval = rpaphp_unconfig_pci_adapter(slot); + retval = rpaphp_unconfig_pci_adapter(slot->bus); up(&rpaphp_sem); + slot->state = NOT_CONFIGURED; + info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, + slot->name); exit: dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 49e4d10a6488..46c157d26a2f 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -319,20 +319,15 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) return; } -int rpaphp_unconfig_pci_adapter(struct slot *slot) +int rpaphp_unconfig_pci_adapter(struct pci_bus *bus) { struct pci_dev *dev, *tmp; - int retval = 0; - list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) { + list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { rpaphp_eeh_remove_bus_device(dev); pci_remove_bus_device(dev); } - - slot->state = NOT_CONFIGURED; - info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, - slot->name); - return retval; + return 0; } static int setup_pci_hotplug_slot_info(struct slot *slot) From e3b1bd572f1cdb247bb4266a593b6894dc578d6a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 21 Sep 2005 22:26:31 +0200 Subject: [PATCH 1089/1939] [PATCH] PCI: Add quirk for SMBus on HP D530 One more SMBus unhiding quirk, this time for the HP D530. Requested and successfully tested by Ben Cranston. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e1bd169cf55c..ee1605906a3e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -950,6 +950,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ + case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) { From dbd7a78818d125a0ebd5507d4edb4dd5900006ab Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:36 -0700 Subject: [PATCH 1090/1939] [PATCH] shpchp: use the PCI core for hotplug resource management This patch converts the standard hotplug controller driver to use the PCI core for resource management. This eliminates a whole lot of duplicated code, and integrates shpchp in the system's normal PCI handling code. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 57 +- drivers/pci/hotplug/shpchp_core.c | 36 +- drivers/pci/hotplug/shpchp_ctrl.c | 1650 +----------------------- drivers/pci/hotplug/shpchp_pci.c | 482 +------ drivers/pci/hotplug/shpchp_sysfs.c | 121 +- drivers/pci/hotplug/shpchprm.h | 12 - drivers/pci/hotplug/shpchprm_acpi.c | 851 ------------ drivers/pci/hotplug/shpchprm_legacy.c | 294 ----- drivers/pci/hotplug/shpchprm_legacy.h | 113 -- drivers/pci/hotplug/shpchprm_nonacpi.c | 278 ---- drivers/pci/hotplug/shpchprm_nonacpi.h | 56 - 11 files changed, 181 insertions(+), 3769 deletions(-) delete mode 100644 drivers/pci/hotplug/shpchprm_legacy.h delete mode 100644 drivers/pci/hotplug/shpchprm_nonacpi.h diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index b7d1c61d6bbb..deea56c73cf2 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -63,14 +63,7 @@ struct pci_func { u8 switch_save; u8 presence_save; u8 pwr_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; struct pci_dev* pci_dev; }; @@ -96,12 +89,6 @@ struct slot { struct list_head slot_list; }; -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; -}; - struct event_info { u32 event_type; u8 hp_slot; @@ -113,10 +100,6 @@ struct controller { void * hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; struct pci_dev *pci_dev; struct pci_bus *pci_bus; struct event_info event_queue[10]; @@ -139,20 +122,6 @@ struct controller { u16 vendor_id; }; -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; -}; - -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; -}; - /* Define AMD SHPC ID */ #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 @@ -197,7 +166,6 @@ struct resource_lists { #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" #define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" #define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" -#define msg_unable_to_save "Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" #define msg_button_on "PCI slot #%d - powering on due to button press.\n" #define msg_button_off "PCI slot #%d - powering off due to button press.\n" #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" @@ -207,7 +175,6 @@ struct resource_lists { extern void shpchp_create_ctrl_files (struct controller *ctrl); /* controller functions */ -extern int shpchprm_find_available_resources(struct controller *ctrl); extern int shpchp_event_start_thread(void); extern void shpchp_event_stop_thread(void); extern struct pci_func *shpchp_slot_create(unsigned char busnumber); @@ -220,19 +187,10 @@ extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); -/* resource functions */ -extern int shpchp_resource_sort_and_combine(struct pci_resource **head); - /* pci functions */ -extern int shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -/*extern int shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag); extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); -extern void shpchp_destroy_board_resources(struct pci_func * func); -extern int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources); -extern void shpchp_destroy_resource_list(struct resource_lists * resources); -extern int shpchp_configure_device(struct controller* ctrl, struct pci_func* func); +extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct pci_func* func); @@ -240,10 +198,6 @@ extern int shpchp_unconfigure_device(struct pci_func* func); extern struct controller *shpchp_ctrl_list; extern struct pci_func *shpchp_slot_list[256]; -/* These are added to support AMD shpc */ -extern u8 shpchp_nic_irq; -extern u8 shpchp_disk_irq; - struct ctrl_reg { volatile u32 base_offset; volatile u32 slot_avail1; @@ -398,15 +352,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) return retval; } -/* Puts node back in the resource list pointed to by head */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) -{ - if (!node || !head) - return; - node->next = *head; - *head = node; -} - #define SLOT_NAME_SIZE 10 static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 6f7d8a29957a..8f5da504df34 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -418,16 +418,8 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_ctrl_bus; } - /* Get IO, memory, and IRQ resources for new devices */ - rc = shpchprm_find_available_resources(ctrl); - ctrl->add_support = !rc; + ctrl->add_support = 1; - if (rc) { - dbg("shpchprm_find_available_resources = %#x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_out_free_ctrl_bus; - } - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { @@ -497,18 +489,6 @@ static int shpc_start_thread(void) return retval; } -static inline void __exit -free_shpchp_res(struct pci_resource *res) -{ - struct pci_resource *tres; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - static void __exit unload_shpchpd(void) { struct pci_func *next; @@ -522,11 +502,6 @@ static void __exit unload_shpchpd(void) while (ctrl) { cleanup_slots(ctrl); - free_shpchp_res(ctrl->io_head); - free_shpchp_res(ctrl->mem_head); - free_shpchp_res(ctrl->p_mem_head); - free_shpchp_res(ctrl->bus_head); - kfree (ctrl->pci_bus); dbg("%s: calling release_ctlr\n", __FUNCTION__); @@ -541,11 +516,6 @@ static void __exit unload_shpchpd(void) for (loop = 0; loop < 256; loop++) { next = shpchp_slot_list[loop]; while (next != NULL) { - free_shpchp_res(next->io_head); - free_shpchp_res(next->mem_head); - free_shpchp_res(next->p_mem_head); - free_shpchp_res(next->bus_head); - TempSlot = next; next = next->next; kfree(TempSlot); @@ -607,9 +577,7 @@ static int __init shpcd_init(void) if (retval) { shpchprm_cleanup(); shpchp_event_stop_thread(); - } else - shpchprm_print_pirt(); - + } return retval; } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 91c9903e621f..aa507e453e49 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -38,13 +38,10 @@ #include #include #include +#include "../pci.h" #include "shpchp.h" #include "shpchprm.h" -static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); -static int configure_new_function( struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); static void interrupt_event_handler(struct controller *ctrl); static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ @@ -52,9 +49,6 @@ static struct semaphore event_exit; /* guard ensure thread has exited before ca static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ -u8 shpchp_disk_irq; -u8 shpchp_nic_irq; - u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) { struct controller *ctrl = (struct controller *) inst_id; @@ -260,624 +254,6 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) return rc; } - -/* - * sort_by_size - * - * Sorts nodes on the list by their length. - * Smallest first. - * - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * do_pre_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - if ((*head)->base != (*orig_head)->base) - return(NULL); - - if ((*head)->length == (*orig_head)->length) - return(NULL); - - - /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front - */ - node = *head; - - if (node->length & (alignment -1)) { - /* This one isn't an aligned length, so we'll make a new entry - * and split it up. - */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - /* Put it in the list */ - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) { - return(NULL); - } - - /* Now unlink it */ - if (*head == node) { - *head = node->next; - node->next = NULL; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - node->next = NULL; - } - - return(node); -} - - -/* - * do_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return(NULL); - } - - if (node->base & (alignment - 1)) { - /* Short circuit if adjusted size is too small */ - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return(NULL); - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - /* There's stuff in use after this node */ - kfree(node); - return(NULL); - } - - return(node); -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node = NULL; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /*/ Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* This one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return(node); -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M - * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. - */ -static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; - int i; - - if (!(*head)) - return(NULL); - - if (shpchp_resource_sort_and_combine(head)) - return(NULL); - - if (sort_by_max_size(head)) - return(NULL); - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* This one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - for ( i = 0; max_size[i] > size; i++) { - if (max->length > max_size[i]) { - split_node = kmalloc(sizeof(*split_node), - GFP_KERNEL); - if (!split_node) - break; /* return (NULL); */ - split_node->base = max->base + max_size[i]; - split_node->length = max->length - max_size[i]; - max->length = max_size[i]; - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - break; - } - } - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return(max); - } - - /* If we get here, we couldn't find one */ - return(NULL); -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return(node); -} - - -/* - * shpchp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int shpchp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - - if (!(*head)) - return(1); - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return(0); /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return(0); -} - - /** * shpchp_slot_create - Creates a node and adds it to the proper bus. * @busnumber - bus where new node is to be located @@ -933,7 +309,6 @@ static int slot_remove(struct pci_func * old_slot) if (next == old_slot) { shpchp_slot_list[old_slot->bus] = old_slot->next; - shpchp_destroy_board_resources(old_slot); kfree(old_slot); return(0); } @@ -944,7 +319,6 @@ static int slot_remove(struct pci_func * old_slot) if (next->next == old_slot) { next->next = old_slot->next; - shpchp_destroy_board_resources(old_slot); kfree(old_slot); return(0); } else @@ -1120,12 +494,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) { u8 hp_slot; u8 slots_not_empty = 0; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 retval, rc = 0; - struct pci_func *new_func = NULL; + u32 rc = 0; struct slot *p_slot; - struct resource_lists res_lists; enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; u8 pi, mode; @@ -1328,135 +698,65 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) /* Check for a power fault */ if (func->status == 0xFF) { /* power fault occurred, but it was benign */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + dbg("%s: power fault\n", __FUNCTION__); rc = POWER_FAILURE; func->status = 0; - } else { - /* Get vendor/device ID u32 */ - rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), - PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - /* Something's wrong here */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - /* Preset return code. It will be changed later if things go okay. */ - rc = NO_ADAPTER_PRESENT; + goto err_exit; } - /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); - dbg("%s: back from configure_new_device\n", __FUNCTION__); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->io_head)); - shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - retval = p_slot->hpc_ops->slot_disable(p_slot); - if (retval) { - err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - retval = p_slot->hpc_ops->check_cmd_status(ctrl); - if (retval) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, retval); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - return(rc); - } - shpchp_save_slot_config(ctrl, func); - - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - func->pwr_save = 1; - - /* Next, we will instantiate the linux pci_dev structures - * (with appropriate driver notification, if already present) - */ - index = 0; - do { - new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++); - if (new_func && !new_func->pci_dev) { - dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__); - shpchp_configure_device(ctrl, new_func); - } - } while (new_func); - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_on(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - } else { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - rc = p_slot->hpc_ops->slot_disable(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - return(rc); + if (shpchp_configure_device(p_slot)) { + err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, + p_slot->device); + goto err_exit; } + + shpchp_save_slot_config(ctrl, func); + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + func->pwr_save = 1; + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return 0; + +err_exit: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* turn off slot, turn on Amber LED, turn off Green LED */ + rc = p_slot->hpc_ops->slot_disable(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); } @@ -1466,13 +766,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) */ static u32 remove_board(struct pci_func *func, struct controller *ctrl) { - int index; - u8 skip = 0; u8 device; u8 hp_slot; u32 rc; - struct resource_lists res_lists; - struct pci_func *temp_func; struct slot *p_slot; if (func == NULL) @@ -1488,27 +784,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - if ((ctrl->add_support) && - !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { - /* Here we check to see if we've saved any of the board's - * resources already. If so, we'll skip the attempt to - * determine what's being used. - */ - index = 0; - - temp_func = func; - - while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) { - if (temp_func->bus_head || temp_func->mem_head - || temp_func->p_mem_head || temp_func->io_head) { - skip = 1; - break; - } - } - - if (!skip) - rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD); - } /* Change status to shutdown */ if (func->is_a_board) func->status = 0x01; @@ -1551,26 +826,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) if (ctrl->add_support) { while (func) { - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - - dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func->bus, - func->device, func->function); - - shpchp_return_board_resources(func, &res_lists); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->io_head)); - shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - if (is_bridge(func)) { dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); @@ -2050,798 +1305,3 @@ int shpchp_disable_slot (struct slot *p_slot) return rc; } - -/** - * configure_new_device - Configures the PCI header information of one board. - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Returns 0 if success - * - */ -static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) -{ - u8 temp_byte, function, max_functions, stop_it; - int rc; - u32 ID; - struct pci_func *new_slot; - struct pci_bus lpci_bus, *pci_bus; - int index; - - new_slot = func; - - dbg("%s\n", __FUNCTION__); - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - - /* Check for Multi-function device */ - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - return rc; - } - - if (temp_byte & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev); - - if (rc) { - dbg("configure_new_function failed %d\n",rc); - index = 0; - - while (new_slot) { - new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++); - - if (new_slot) - shpchp_return_board_resources(new_slot, resources); - } - - return(rc); - } - - function++; - - stop_it = 0; - - /* The following loop skips to the next present function - * and creates a board structure - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ - function++; - } else { /* There's something there */ - /* Setup slot structure. */ - new_slot = shpchp_slot_create(func->bus); - - if (new_slot == NULL) { - /* Out of memory */ - return(1); - } - - new_slot->bus = func->bus; - new_slot->device = func->device; - new_slot->function = function; - new_slot->is_a_board = 1; - new_slot->status = 0; - - stop_it++; - } - } - - } while (function < max_functions); - dbg("returning from configure_new_device\n"); - - return 0; -} - - -/* - * Configuration logic that involves the hotplug data structures and - * their bookkeeping - */ - - -/** - * configure_new_function - Configures the PCI header information of one device - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Calls itself recursively for bridged devices. - * Returns 0 if success - * - */ -static int configure_new_function (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) -{ - int cloop; - u8 temp_byte; - u8 device; - u8 class_code; - u16 temp_word; - u32 rc; - u32 temp_register; - u32 base; - u32 ID; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_resource *hold_mem_node; - struct pci_resource *hold_p_mem_node; - struct pci_resource *hold_IO_node; - struct pci_resource *hold_bus_node; - struct irq_mapping irqs; - struct pci_func *new_slot; - struct pci_bus lpci_bus, *pci_bus; - struct resource_lists temp_resources; -#if defined(CONFIG_X86_64) - u8 IRQ=0; -#endif - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check for Bridge */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); - if (rc) - return rc; - - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - /* set Primary bus */ - dbg("set Primary bus = 0x%x\n", func->bus); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); - if (rc) - return rc; - - /* find range of busses to use */ - bus_node = get_max_resource(&resources->bus_head, 1L); - - /* If we don't have any busses to allocate, we can't continue */ - if (!bus_node) { - err("Got NO bus resource to use\n"); - return -ENOMEM; - } - dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); - - /* set Secondary bus */ - temp_byte = (u8)bus_node->base; - dbg("set Secondary bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); - if (rc) - return rc; - - /* set subordinate bus */ - temp_byte = (u8)(bus_node->base + bus_node->length - 1); - dbg("set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - if (rc) - return rc; - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - if (rc) - return rc; - - /* Setup the IO, memory, and prefetchable windows */ - - io_node = get_max_resource(&(resources->io_head), 0x1000L); - if (io_node) { - dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); - } - - mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - if (mem_node) { - dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); - } - - if (resources->p_mem_head) - p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); - else { - /* - * In some platform implementation, MEM and PMEM are not - * distinguished, and hence ACPI _CRS has only MEM entries - * for both MEM and PMEM. - */ - dbg("using MEM for PMEM\n"); - p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - } - if (p_mem_node) { - dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); - } - - /* set up the IRQ info */ - if (!resources->irqs) { - irqs.barber_pole = 0; - irqs.interrupt[0] = 0; - irqs.interrupt[1] = 0; - irqs.interrupt[2] = 0; - irqs.interrupt[3] = 0; - irqs.valid_INT = 0; - } else { - irqs.barber_pole = resources->irqs->barber_pole; - irqs.interrupt[0] = resources->irqs->interrupt[0]; - irqs.interrupt[1] = resources->irqs->interrupt[1]; - irqs.interrupt[2] = resources->irqs->interrupt[2]; - irqs.interrupt[3] = resources->irqs->interrupt[3]; - irqs.valid_INT = resources->irqs->valid_INT; - } - - /* set up resource lists that are now aligned on top and bottom - * for anything behind the bridge. - */ - temp_resources.bus_head = bus_node; - temp_resources.io_head = io_node; - temp_resources.mem_head = mem_node; - temp_resources.p_mem_head = p_mem_node; - temp_resources.irqs = &irqs; - - /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources - */ - hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); - hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); - hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); - hold_p_mem_node = kmalloc(sizeof(*hold_p_mem_node), GFP_KERNEL); - - if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { - kfree(hold_bus_node); - kfree(hold_IO_node); - kfree(hold_mem_node); - kfree(hold_p_mem_node); - - return 1; - } - - memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); - - bus_node->base += 1; - bus_node->length -= 1; - bus_node->next = NULL; - - /* If we have IO resources copy them and fill in the bridge's - * IO range registers - */ - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - /* set IO base and Limit registers */ - RES_CHECK(io_node->base, 8); - temp_byte = (u8)(io_node->base >> 8); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); - - RES_CHECK(io_node->base + io_node->length - 1, 8); - temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } - - /* If we have memory resources copy them and fill in the bridge's - * memory range registers. Otherwise, fill in the range - * registers with values that disable them. - */ - if (mem_node) { - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; - - /* set Mem base and Limit registers */ - RES_CHECK(mem_node->base, 16); - temp_word = (u32)(mem_node->base >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - RES_CHECK(mem_node->base + mem_node->length - 1, 16); - temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - kfree(hold_mem_node); - hold_mem_node = NULL; - } - - /* If we have prefetchable memory resources copy them and - * fill in the bridge's memory range registers. Otherwise, - * fill in the range registers with values that disable them. - */ - if (p_mem_node) { - memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); - p_mem_node->next = NULL; - - /* set Pre Mem base and Limit registers */ - RES_CHECK(p_mem_node->base, 16); - temp_word = (u32)(p_mem_node->base >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); - temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - kfree(hold_p_mem_node); - hold_p_mem_node = NULL; - } - - /* Adjust this to compensate for extra adjustment in first loop */ - irqs.barber_pole--; - - rc = 0; - - /* Here we actually find the devices and configure them */ - for (device = 0; (device <= 0x1F) && !rc; device++) { - irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; - - ID = 0xFFFFFFFF; - pci_bus->number = hold_bus_node->base; - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), - PCI_VENDOR_ID, &ID); - pci_bus->number = func->bus; - - if (ID != 0xFFFFFFFF) { /* device Present */ - /* Setup slot structure. */ - new_slot = shpchp_slot_create(hold_bus_node->base); - - if (new_slot == NULL) { - /* Out of memory */ - rc = -ENOMEM; - continue; - } - - new_slot->bus = hold_bus_node->base; - new_slot->device = device; - new_slot->function = 0; - new_slot->is_a_board = 1; - new_slot->status = 0; - - rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device); - dbg("configure_new_device rc=0x%x\n",rc); - } /* End of IF (device in slot?) */ - } /* End of FOR loop */ - - if (rc) { - shpchp_destroy_resource_list(&temp_resources); - - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return(rc); - } - - /* save the interrupt routing information */ - if (resources->irqs) { - resources->irqs->interrupt[0] = irqs.interrupt[0]; - resources->irqs->interrupt[1] = irqs.interrupt[1]; - resources->irqs->interrupt[2] = irqs.interrupt[2]; - resources->irqs->interrupt[3] = irqs.interrupt[3]; - resources->irqs->valid_INT = irqs.valid_INT; - } else if (!behind_bridge) { - /* We need to hook up the interrupts here */ - for (cloop = 0; cloop < 4; cloop++) { - if (irqs.valid_INT & (0x01 << cloop)) { - rc = shpchp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); - if (rc) { - shpchp_destroy_resource_list (&temp_resources); - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return rc; - } - } - } /* end of for loop */ - } - - /* Return unused bus resources - * First use the temporary node to store information for the board - */ - if (hold_bus_node && bus_node && temp_resources.bus_head) { - hold_bus_node->length = bus_node->base - hold_bus_node->base; - - hold_bus_node->next = func->bus_head; - func->bus_head = hold_bus_node; - - temp_byte = (u8)(temp_resources.bus_head->base - 1); - - /* set subordinate bus */ - dbg("re-set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - - if (temp_resources.bus_head->length == 0) { - kfree(temp_resources.bus_head); - temp_resources.bus_head = NULL; - } else { - dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", - func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); - return_resource(&(resources->bus_head), temp_resources.bus_head); - } - } - - /* If we have IO space available and there is some left, - * return the unused portion - */ - if (hold_IO_node && temp_resources.io_head) { - io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), - &hold_IO_node, 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - hold_IO_node->base = io_node->base + io_node->length; - - RES_CHECK(hold_IO_node->base, 8); - temp_byte = (u8)((hold_IO_node->base) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - return_resource(&(resources->io_head), io_node); - } - - io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - /* First use the temporary node to store information for the board */ - hold_IO_node->length = io_node->base - hold_IO_node->base; - - /* If we used any, add it to the board's list */ - if (hold_IO_node->length) { - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - - RES_CHECK(io_node->base - 1, 8); - temp_byte = (u8)((io_node->base - 1) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - } else { - /* it doesn't need any IO */ - temp_byte = 0x00; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - kfree(hold_IO_node); - } - } else { - /* it used most of the range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - } else if (hold_IO_node) { - /* it used the whole range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - - /* If we have memory space available and there is some left, - * return the unused portion - */ - if (hold_mem_node && temp_resources.mem_head) { - mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - hold_mem_node->base = mem_node->base + mem_node->length; - - RES_CHECK(hold_mem_node->base, 16); - temp_word = (u32)((hold_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - return_resource(&(resources->mem_head), mem_node); - } - - mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - /* First use the temporary node to store information for the board */ - hold_mem_node->length = mem_node->base - hold_mem_node->base; - - if (hold_mem_node->length) { - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - - /* configure end address */ - RES_CHECK(mem_node->base - 1, 16); - temp_word = (u32)((mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - /* Return unused resources to the pool */ - return_resource(&(resources->mem_head), mem_node); - } else { - /* it doesn't need any Mem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->mem_head), mem_node); - kfree(hold_mem_node); - } - } else { - /* it used most of the range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - } else if (hold_mem_node) { - /* it used the whole range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - - /* If we have prefetchable memory space available and there is some - * left at the end, return the unused portion - */ - if (hold_p_mem_node && temp_resources.p_mem_head) { - p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), - &hold_p_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; - - RES_CHECK(hold_p_mem_node->base, 16); - temp_word = (u32)((hold_p_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } - - p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - /* First use the temporary node to store information for the board */ - hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; - - /* If we used any, add it to the board's list */ - if (hold_p_mem_node->length) { - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - - RES_CHECK(p_mem_node->base - 1, 16); - temp_word = (u32)((p_mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } else { - /* it doesn't need any PMem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - kfree(hold_p_mem_node); - } - } else { - /* it used the most of the range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - } else if (hold_p_mem_node) { - /* it used the whole range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - - /* We should be configuring an IRQ and the bridge's base address - * registers if it needs them. Although we have never seen such - * a device - */ - - shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - - dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - /* Standard device */ - u64 base64; - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_DISPLAY) - return (DEVICE_TYPE_NOT_SUPPORTED); - - /* Figure out IO and memory needs */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - temp_register = 0xFFFFFFFF; - - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, - func->function); - - if (!temp_register) - continue; - - base64 = 0L; - if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { - /* Map IO */ - - /* set base = amount of IO space */ - base = temp_register & 0xFFFFFFFC; - base = ~base + 1; - - dbg("NEED IO length(0x%x)\n", base); - io_node = get_io_resource(&(resources->io_head),(ulong)base); - - /* allocate the resource to the board */ - if (io_node) { - dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); - base = (u32)io_node->base; - io_node->next = func->io_head; - func->io_head = io_node; - } else { - err("Got NO IO resource(length=0x%x)\n", base); - return -ENOMEM; - } - } else { /* map MEM */ - int prefetchable = 1; - struct pci_resource **res_node = &func->p_mem_head; - char *res_type_str = "PMEM"; - u32 temp_register2; - - if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { - prefetchable = 0; - res_node = &func->mem_head; - res_type_str++; - } - - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node=get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node=get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base = (u32)mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, - mem_node->length); - } else { - err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, - temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node = get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node = get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base64 = mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), - (u32)base64, mem_node->length); - } else { - err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - default: - dbg("reserved BAR type=0x%x\n", temp_register); - break; - } - - } - - if (base64) { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - cloop += 4; - base64 >>= 32; - - if (base64) { - dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); - base64 = 0x0L; - } - - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - } else { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); - } - } /* End of base register loop */ - -#if defined(CONFIG_X86_64) - /* Figure out which interrupt pin this function uses */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); - - /* If this function needs an interrupt and we are behind a bridge - and the pin is tied to something that's alread mapped, - set this one the same - */ - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & - (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { - /* We have to share with something already set up */ - IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; - } else { - /* Program IRQ based on card type */ - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_STORAGE) { - IRQ = shpchp_disk_irq; - } else { - IRQ = shpchp_nic_irq; - } - } - - /* IRQ Line */ - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); - - if (!behind_bridge) { - rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); - if (rc) - return(1); - } else { - /* TBD - this code may also belong in the other clause of this If statement */ - resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; - resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; - } -#endif - /* Disable ROM base Address */ - rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); - if (rc) - return rc; - - shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); - - dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - } /* End of Not-A-Bridge else */ - else { - /* It's some strange type of PCI adapter (Cardbus?) */ - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - func->configured = 1; - - return 0; -} - diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index d867099114ec..89e404805777 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -37,46 +37,69 @@ #include #include "../pci.h" #include "shpchp.h" -#ifndef CONFIG_IA64 -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */ -#endif -int shpchp_configure_device (struct controller* ctrl, struct pci_func* func) +int shpchp_configure_device(struct slot *p_slot) { - unsigned char bus; - struct pci_bus *child; - int num; + struct pci_dev *dev; + struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + int num, fn; - if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - - /* Still NULL ? Well then scan for it ! */ - if (func->pci_dev == NULL) { - num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function)); - if (num) { - dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl->pci_dev->subordinate, - ctrl->pci_dev->subordinate->number); - pci_bus_add_devices(ctrl->pci_dev->subordinate); - } - - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - if (func->pci_dev == NULL) { - dbg("ERROR: pci_dev still null\n"); - return 0; - } + dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); + if (dev) { + err("Device %s already exists at %x:%x, cannot hot-add\n", + pci_name(dev), p_slot->bus, p_slot->device); + return -EINVAL; } - if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); - + num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); + if (num == 0) { + err("No new device found\n"); + return -ENODEV; } + for (fn = 0; fn < 8; fn++) { + if (!(dev = pci_find_slot(p_slot->bus, + PCI_DEVFN(p_slot->device, fn)))) + continue; + if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + err("Cannot hot-add display device %s\n", + pci_name(dev)); + continue; + } + if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || + (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { + /* Find an unused bus number for the new bridge */ + struct pci_bus *child; + unsigned char busnr, start = parent->secondary; + unsigned char end = parent->subordinate; + for (busnr = start; busnr <= end; busnr++) { + if (!pci_find_bus(pci_domain_nr(parent), + busnr)) + break; + } + if (busnr >= end) { + err("No free bus for hot-added bridge\n"); + continue; + } + child = pci_add_new_bus(parent, dev, busnr); + if (!child) { + err("Cannot add new bus for %s\n", + pci_name(dev)); + continue; + } + child->subordinate = pci_do_scan_bus(child); + pci_bus_size_bridges(child); + } + /* TBD: program firmware provided _HPP values */ + /* program_fw_provided_values(dev); */ + } + + pci_bus_assign_resources(parent); + pci_bus_add_devices(parent); + pci_enable_bridges(parent); return 0; } - int shpchp_unconfigure_device(struct pci_func* func) { int rc = 0; @@ -95,44 +118,6 @@ int shpchp_unconfigure_device(struct pci_func* func) return rc; } -/* - * shpchp_set_irq - * - * @bus_num: bus number of PCI device - * @dev_num: device number of PCI device - * @slot: pointer to u8 where slot number will be returned - */ -int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) -{ -#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) - int rc; - u16 temp_word; - struct pci_dev fakedev; - struct pci_bus fakebus; - - fakedev.devfn = dev_num << 3; - fakedev.bus = &fakebus; - fakebus.number = bus_num; - dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); - dbg("%s: rc %d\n", __FUNCTION__, rc); - if (!rc) - return !rc; - - /* set the Edge Level Control Register (ELCR) */ - temp_word = inb(0x4d0); - temp_word |= inb(0x4d1) << 8; - - temp_word |= 0x01 << irq_num; - - /* This should only be for x86 as it sets the Edge Level Control Register */ - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); -#endif - return 0; -} - /* More PCI configuration routines; this time centered around hotplug controller */ @@ -447,364 +432,3 @@ int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) return 0; } - -/* - * shpchp_save_used_resources - * - * Stores used resource information for existing boards. this is - * for boards that were in the system when this driver was loaded. - * this function is for hot plug ADD - * - * returns 0 if success - * if disable == 1(DISABLE_CARD), - * it loops for all functions of the slot and disables them. - * else, it just get resources of the function and return. - */ -int shpchp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 temp_byte; - u16 command; - u16 save_command; - u16 w_base, w_length; - u32 temp_register; - u32 save_base; - u32 base, length; - u64 base64 = 0; - int index = 0; - unsigned int devfn; - struct pci_resource *mem_node = NULL; - struct pci_resource *p_mem_node = NULL; - struct pci_resource *t_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - if (disable) - func = shpchp_slot_find(func->bus, func->device, index++); - - while ((func != NULL) && func->is_a_board) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Save the command register */ - pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); - - if (disable) { - /* disable card */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - } - - /* Check for Bridge */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - if (disable) { - /* Clear Bridge Control Register */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - } - - pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); - - bus_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = (ulong)secondary_bus; - bus_node->length = (ulong)(temp_byte - secondary_bus + 1); - - bus_node->next = func->bus_head; - func->bus_head = bus_node; - - /* Save IO base and Limit registers */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte); - base = temp_byte; - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); - length = temp_byte; - - if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { - io_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; - io_node->length = (ulong)(length - base + 0x10) << 8; - - io_node->next = func->io_head; - func->io_head = io_node; - } - - /* Save memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = (ulong)w_base << 16; - mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - /* Save prefetchable memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - p_mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = (ulong)w_base << 16; - p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - - /* Figure out IO and memory base lengths */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - - if (!disable) - pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base); - - if (!temp_register) - continue; - - base = temp_register; - - if ((base & PCI_BASE_ADDRESS_SPACE_IO) && - (!disable || (save_command & PCI_COMMAND_IO))) { - /* IO base */ - /* set temp_register = amount of IO space requested */ - base = base & 0xFFFFFFFCL; - base = (~base) + 1; - - io_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; - io_node->length = (ulong)base; - dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", - io_node->base, io_node->length); - - io_node->next = func->io_head; - func->io_head = io_node; - } else { /* map Memory */ - int prefetchable = 1; - /* struct pci_resources **res_node; */ - char *res_type_str = "PMEM"; - u32 temp_register2; - - t_mem_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!t_mem_node) - return -ENOMEM; - - if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && - (!disable || (save_command & PCI_COMMAND_MEMORY))) { - prefetchable = 0; - mem_node = t_mem_node; - res_type_str++; - } else - p_mem_node = t_mem_node; - - base = base & 0xFFFFFFF0L; - base = (~base) + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - if (prefetchable) { - p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - base64 = temp_register2; - base64 = (base64 << 32) | save_base; - - if (temp_register2) { - dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", - res_type_str, temp_register2, (u32)base64); - base64 &= 0x00000000FFFFFFFFL; - } - - if (prefetchable) { - p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - cloop += 4; - break; - default: - dbg("asur: reserved BAR type=0x%x\n", - temp_register); - break; - } - } - } /* End of base register loop */ - } else { /* Some other unknown header type */ - dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", - func->bus, func->device); - } - - /* find the next device in this slot */ - if (!disable) - break; - func = shpchp_slot_find(func->bus, func->device, index++); - } - - return 0; -} - -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -return_resource_list(struct pci_resource **func, struct pci_resource **res) -{ - struct pci_resource *node; - struct pci_resource *t_node; - - node = *func; - *func = NULL; - while (node) { - t_node = node->next; - return_resource(res, node); - node = t_node; - } -} - -/* - * shpchp_return_board_resources - * - * this routine returns all resources allocated to a board to - * the available pool. - * - * returns 0 if success - */ -int shpchp_return_board_resources(struct pci_func * func, - struct resource_lists * resources) -{ - int rc; - dbg("%s\n", __FUNCTION__); - - if (!func) - return 1; - - return_resource_list(&(func->io_head),&(resources->io_head)); - return_resource_list(&(func->mem_head),&(resources->mem_head)); - return_resource_list(&(func->p_mem_head),&(resources->p_mem_head)); - return_resource_list(&(func->bus_head),&(resources->bus_head)); - - rc = shpchp_resource_sort_and_combine(&(resources->mem_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->io_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->bus_head)); - - return rc; -} - -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -kfree_resource_list(struct pci_resource **r) -{ - struct pci_resource *res, *tres; - - res = *r; - *r = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - -/** - * shpchp_destroy_resource_list: put node back in the resource list - * @resources: list to put nodes back - */ -void shpchp_destroy_resource_list(struct resource_lists *resources) -{ - kfree_resource_list(&(resources->io_head)); - kfree_resource_list(&(resources->mem_head)); - kfree_resource_list(&(resources->p_mem_head)); - kfree_resource_list(&(resources->bus_head)); -} - -/** - * shpchp_destroy_board_resources: put node back in the resource list - * @resources: list to put nodes back - */ -void shpchp_destroy_board_resources(struct pci_func * func) -{ - kfree_resource_list(&(func->io_head)); - kfree_resource_list(&(func->mem_head)); - kfree_resource_list(&(func->p_mem_head)); - kfree_resource_list(&(func->bus_head)); -} diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index c9445ebda5c7..b0e781dbcffb 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -40,43 +40,49 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { - struct pci_dev *pci_dev; - struct controller *ctrl; + struct pci_dev *pdev; char * out = buf; - int index; - struct pci_resource *res; + int index, busnr; + struct resource *res; + struct pci_bus *bus; - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); + pdev = container_of (dev, struct pci_dev, dev); + bus = pdev->subordinate; out += sprintf(buf, "Free resources: memory\n"); - index = 11; - res = ctrl->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_MEM) && + !(res->flags & IORESOURCE_PREFETCH)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: prefetchable memory\n"); - index = 11; - res = ctrl->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_MEM) && + (res->flags & IORESOURCE_PREFETCH)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: IO\n"); - index = 11; - res = ctrl->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_IO)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: bus numbers\n"); - index = 11; - res = ctrl->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { + if (!pci_find_bus(pci_domain_nr(bus), busnr)) + break; } + if (busnr < bus->subordinate) + out += sprintf(out, "start = %8.8x, length = %8.8x\n", + busnr, (bus->subordinate - busnr)); return out - buf; } @@ -84,16 +90,16 @@ static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) { - struct pci_dev *pci_dev; + struct pci_dev *pdev, *fdev; struct controller *ctrl; char * out = buf; int index; - struct pci_resource *res; + struct resource *res; struct pci_func *new_slot; struct slot *slot; - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); + pdev = container_of (dev, struct pci_dev, dev); + ctrl = pci_get_drvdata(pdev); slot=ctrl->slot; @@ -101,34 +107,47 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char new_slot = shpchp_slot_find(slot->bus, slot->device, 0); if (!new_slot) break; + fdev = new_slot->pci_dev; + if (!fdev) + break; out += sprintf(out, "assigned resources: memory\n"); - index = 11; - res = new_slot->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index=0; index <= PCI_NUM_RESOURCES; index++) { + res = &(fdev->resource[index]); + if (res && (res->flags & IORESOURCE_MEM) && + !(res->flags & IORESOURCE_PREFETCH)) { + out += sprintf(out, + "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "assigned resources: prefetchable memory\n"); - index = 11; - res = new_slot->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index=0; index <= PCI_NUM_RESOURCES; index++) { + res = &(fdev->resource[index]); + if (res && (res->flags & (IORESOURCE_MEM | + IORESOURCE_PREFETCH))) { + out += sprintf(out, + "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "assigned resources: IO\n"); - index = 11; - res = new_slot->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index=0; index <= PCI_NUM_RESOURCES; index++) { + res = &(fdev->resource[index]); + if (res && (res->flags & IORESOURCE_IO)) { + out += sprintf(out, + "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "assigned resources: bus numbers\n"); - index = 11; - res = new_slot->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } + if (fdev->subordinate) + out += sprintf(out, "start = %8.8x, length = %8.8x\n", + fdev->subordinate->secondary, + (fdev->subordinate->subordinate - + fdev->subordinate->secondary)); + else + out += sprintf(out, "start = %8.8x, length = %8.8x\n", + fdev->bus->number, 1); slot=slot->next; } diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h index 057b192ce589..df474b27d6e8 100644 --- a/drivers/pci/hotplug/shpchprm.h +++ b/drivers/pci/hotplug/shpchprm.h @@ -32,24 +32,12 @@ #ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY #include "shpchprm_legacy.h" -#else -#include "shpchprm_nonacpi.h" #endif int shpchprm_init(enum php_ctlr_type ct); void shpchprm_cleanup(void); -int shpchprm_print_pirt(void); -int shpchprm_find_available_resources(struct controller *ctrl); int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); -#ifdef DEBUG -#define RES_CHECK(this, bits) \ - { if (((this) & (bits - 1))) \ - printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } -#else -#define RES_CHECK(this, bits) -#endif - #endif /* _SHPCHPRM_H_ */ diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index d37b31658edf..3d2f9c5269c7 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -34,9 +34,6 @@ #include #include #include -#ifdef CONFIG_IA64 -#include -#endif #include #include #include @@ -75,10 +72,6 @@ struct acpi_php_slot { int dev; int fun; u32 sun; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; void *slot_ops; /* _STA, _EJx, etc */ struct slot *slot; }; /* per func */ @@ -95,14 +88,6 @@ struct acpi_bridge { int bus; /* pdev->subordinate->number */ struct acpi__hpp *_hpp; struct acpi_php_slot *slots; - struct pci_resource *tmem_head; /* total from crs */ - struct pci_resource *tp_mem_head; /* total from crs */ - struct pci_resource *tio_head; /* total from crs */ - struct pci_resource *tbus_head; /* total from crs */ - struct pci_resource *mem_head; /* available */ - struct pci_resource *p_mem_head; /* available */ - struct pci_resource *io_head; /* available */ - struct pci_resource *bus_head; /* available */ int scanned; int type; }; @@ -252,485 +237,6 @@ static void acpi_run_oshp ( struct acpi_bridge *ab) return; } -static acpi_status acpi_evaluate_crs( - acpi_handle handle, - struct acpi_resource **retbuf - ) -{ - acpi_status status; - struct acpi_buffer crsbuf; - u8 *path_name = acpi_path_name(handle); - - crsbuf.length = 0; - crsbuf.pointer = NULL; - - status = acpi_get_current_resources (handle, &crsbuf); - - switch (status) { - case AE_BUFFER_OVERFLOW: - break; /* found */ - case AE_NOT_FOUND: - dbg("acpi_shpchprm:%s _CRS not found\n", path_name); - return status; - default: - err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status); - return status; - } - - crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); - if (!crsbuf.pointer) { - err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); - return AE_NO_MEMORY; - } - - status = acpi_get_current_resources (handle, &crsbuf); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status); - kfree(crsbuf.pointer); - return status; - } - - *retbuf = crsbuf.pointer; - - return status; -} - -static void free_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res, *next; - - for (res = aprh; res; res = next) { - next = res->next; - kfree(res); - } -} - -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - -static void print_slot_resources( struct acpi_php_slot *aps) -{ - if (aps->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (aps->bus_head); - } - - if (aps->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (aps->io_head); - } - - if (aps->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (aps->mem_head); - } - - if (aps->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (aps->p_mem_head); - } -} - -static void print_pci_resources( struct acpi_bridge *ab) -{ - if (ab->tbus_head) { - dbg(" Total BUS Resources:\n"); - print_pci_resource (ab->tbus_head); - } - if (ab->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (ab->bus_head); - } - - if (ab->tio_head) { - dbg(" Total IO Resources:\n"); - print_pci_resource (ab->tio_head); - } - if (ab->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (ab->io_head); - } - - if (ab->tmem_head) { - dbg(" Total MEM Resources:\n"); - print_pci_resource (ab->tmem_head); - } - if (ab->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (ab->mem_head); - } - - if (ab->tp_mem_head) { - dbg(" Total PMEM Resources:\n"); - print_pci_resource (ab->tp_mem_head); - } - if (ab->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (ab->p_mem_head); - } - if (ab->_hpp) { - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); - } -} - -static int shpchprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - shpchp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - -static int shpchprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - shpchprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - -static int shpchprm_add_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - - for (res = *aprh; res; res = res->next) { - if ((res->base + res->length) == base) { - res->length += size; - size = 0L; - break; - } - if (res->next == *aprh) - break; - } - - if (size) { - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!res) { - err ("acpi_shpchprm: alloc for res fail\n"); - return -ENOMEM; - } - memset(res, 0, sizeof (struct pci_resource)); - - res->base = base; - res->length = size; - res->next = *aprh; - *aprh = res; - } - - return 0; -} - -static int shpchprm_add_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - int rc = 0; - - for (res = this; res && !rc; res = res->next) - rc = shpchprm_add_resource(aprh, res->base, res->length); - - return rc; -} - -static void acpi_parse_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_io *dataio; - dataio = (struct acpi_resource_io *) data; - - dbg("Io Resource\n"); - dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); - dbg(" Range minimum base: %08X\n", dataio->min_base_address); - dbg(" Range maximum base: %08X\n", dataio->max_base_address); - dbg(" Alignment: %08X\n", dataio->alignment); - dbg(" Range Length: %08X\n", dataio->range_length); -} - -static void acpi_parse_fixed_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_fixed_io *datafio; - datafio = (struct acpi_resource_fixed_io *) data; - - dbg("Fixed Io Resource\n"); - dbg(" Range base address: %08X", datafio->base_address); - dbg(" Range length: %08X", datafio->range_length); -} - -static void acpi_parse_address16_32 ( - struct acpi_bridge *ab, - union acpi_resource_data *data, - acpi_resource_type id - ) -{ - /* - * acpi_resource_address16 == acpi_resource_address32 - * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; - */ - struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; - struct pci_resource **aprh, **tprh; - - if (id == ACPI_RSTYPE_ADDRESS16) - dbg("acpi_shpchprm:16-Bit Address Space Resource\n"); - else - dbg("acpi_shpchprm:32-Bit Address Space Resource\n"); - - switch (data32->resource_type) { - case ACPI_MEMORY_RANGE: - dbg(" Resource Type: Memory Range\n"); - aprh = &ab->mem_head; - tprh = &ab->tmem_head; - - switch (data32->attribute.memory.cache_attribute) { - case ACPI_NON_CACHEABLE_MEMORY: - dbg(" Type Specific: Noncacheable memory\n"); - break; - case ACPI_CACHABLE_MEMORY: - dbg(" Type Specific: Cacheable memory\n"); - break; - case ACPI_WRITE_COMBINING_MEMORY: - dbg(" Type Specific: Write-combining memory\n"); - break; - case ACPI_PREFETCHABLE_MEMORY: - aprh = &ab->p_mem_head; - dbg(" Type Specific: Prefetchable memory\n"); - break; - default: - dbg(" Type Specific: Invalid cache attribute\n"); - break; - } - - dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); - break; - - case ACPI_IO_RANGE: - dbg(" Resource Type: I/O Range\n"); - aprh = &ab->io_head; - tprh = &ab->tio_head; - - switch (data32->attribute.io.range_attribute) { - case ACPI_NON_ISA_ONLY_RANGES: - dbg(" Type Specific: Non-ISA Io Addresses\n"); - break; - case ACPI_ISA_ONLY_RANGES: - dbg(" Type Specific: ISA Io Addresses\n"); - break; - case ACPI_ENTIRE_RANGE: - dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); - break; - default: - dbg(" Type Specific: Invalid range attribute\n"); - break; - } - break; - - case ACPI_BUS_NUMBER_RANGE: - dbg(" Resource Type: Bus Number Range(fixed)\n"); - /* fixup to be compatible with the rest of php driver */ - data32->min_address_range++; - data32->address_length--; - aprh = &ab->bus_head; - tprh = &ab->tbus_head; - break; - default: - dbg(" Resource Type: Invalid resource type. Exiting.\n"); - return; - } - - dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); - dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); - dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); - dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); - dbg(" Granularity: %08X\n", data32->granularity); - dbg(" Address range min: %08X\n", data32->min_address_range); - dbg(" Address range max: %08X\n", data32->max_address_range); - dbg(" Address translation offset: %08X\n", data32->address_translation_offset); - dbg(" Address Length: %08X\n", data32->address_length); - - if (0xFF != data32->resource_source.index) { - dbg(" Resource Source Index: %X\n", data32->resource_source.index); - /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ - } - - shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length); -} - -static acpi_status acpi_parse_crs( - struct acpi_bridge *ab, - struct acpi_resource *crsbuf - ) -{ - acpi_status status = AE_OK; - struct acpi_resource *resource = crsbuf; - u8 count = 0; - u8 done = 0; - - while (!done) { - dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); - switch (resource->id) { - case ACPI_RSTYPE_IRQ: - dbg("Irq -------- Resource\n"); - break; - case ACPI_RSTYPE_DMA: - dbg("DMA -------- Resource\n"); - break; - case ACPI_RSTYPE_START_DPF: - dbg("Start DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_END_DPF: - dbg("End DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_IO: - acpi_parse_io (ab, &resource->data); - break; - case ACPI_RSTYPE_FIXED_IO: - acpi_parse_fixed_io (ab, &resource->data); - break; - case ACPI_RSTYPE_VENDOR: - dbg("Vendor -------- Resource\n"); - break; - case ACPI_RSTYPE_END_TAG: - dbg("End_tag -------- Resource\n"); - done = 1; - break; - case ACPI_RSTYPE_MEM24: - dbg("Mem24 -------- Resource\n"); - break; - case ACPI_RSTYPE_MEM32: - dbg("Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_FIXED_MEM32: - dbg("Fixed Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_ADDRESS16: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); - break; - case ACPI_RSTYPE_ADDRESS32: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); - break; - case ACPI_RSTYPE_ADDRESS64: - info("Address64 -------- Resource unparsed\n"); - break; - case ACPI_RSTYPE_EXT_IRQ: - dbg("Ext Irq -------- Resource\n"); - break; - default: - dbg("Invalid -------- resource type 0x%x\n", resource->id); - break; - } - - resource = (struct acpi_resource *) ((char *)resource + resource->length); - } - - return status; -} - -static acpi_status acpi_get_crs( struct acpi_bridge *ab) -{ - acpi_status status; - struct acpi_resource *crsbuf; - - status = acpi_evaluate_crs(ab->handle, &crsbuf); - if (ACPI_SUCCESS(status)) { - status = acpi_parse_crs(ab, crsbuf); - kfree(crsbuf); - - shpchp_resource_sort_and_combine(&ab->bus_head); - shpchp_resource_sort_and_combine(&ab->io_head); - shpchp_resource_sort_and_combine(&ab->mem_head); - shpchp_resource_sort_and_combine(&ab->p_mem_head); - - shpchprm_add_resources (&ab->tbus_head, ab->bus_head); - shpchprm_add_resources (&ab->tio_head, ab->io_head); - shpchprm_add_resources (&ab->tmem_head, ab->mem_head); - shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - } - - return status; -} - /* find acpi_bridge downword from ab. */ static struct acpi_bridge * find_acpi_bridge_by_bus( @@ -1047,13 +553,6 @@ static struct acpi_bridge * add_host_bridge( ab->scanned = 0; ab->type = BRIDGE_TYPE_HOST; - /* get root pci bridge's current resources */ - status = acpi_get_crs(ab); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status); - kfree(ab); - return NULL; - } build_a_bridge(ab, ab); return ab; @@ -1147,11 +646,6 @@ static void free_a_slot(struct acpi_php_slot *aps) { dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); - free_pci_resource (aps->io_head); - free_pci_resource (aps->bus_head); - free_pci_resource (aps->mem_head); - free_pci_resource (aps->p_mem_head); - kfree(aps); } @@ -1176,15 +670,6 @@ static void free_a_bridge( struct acpi_bridge *ab) free_a_slot(aps); } - free_pci_resource (ab->io_head); - free_pci_resource (ab->tio_head); - free_pci_resource (ab->bus_head); - free_pci_resource (ab->tbus_head); - free_pci_resource (ab->mem_head); - free_pci_resource (ab->tmem_head); - free_pci_resource (ab->p_mem_head); - free_pci_resource (ab->tp_mem_head); - kfree(ab); } @@ -1234,47 +719,6 @@ static int get_number_of_slots ( return slot_num; } -static int print_acpi_resources (struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps; - int i; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); - break; - case BRIDGE_TYPE_P2P: - dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); - break; - }; - - print_pci_resources (ab); - - for ( i = -1, aps = ab->slots; aps; aps = aps->next) { - if (aps->dev == i) - continue; - dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - print_slot_resources(aps); - i = aps->dev; - } - - if (ab->child) - print_acpi_resources (ab->child); - - if (ab->next) - print_acpi_resources (ab->next); - - return 0; -} - -int shpchprm_print_pirt(void) -{ - dbg("SHPCHPRM ACPI Slots\n"); - if (acpi_bridges_head) - print_acpi_resources (acpi_bridges_head); - return 0; -} - static struct acpi_php_slot * get_acpi_slot ( struct acpi_bridge *ab, u32 sun @@ -1302,265 +746,6 @@ static struct acpi_php_slot * get_acpi_slot ( } -#if 0 -static void * shpchprm_get_slot(struct slot *slot) -{ - struct acpi_bridge *ab = acpi_bridges_head; - struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); - - aps->slot = slot; - - dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - - return (void *)aps; -} -#endif - -static void shpchprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static void shpchprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -static int shpchprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = shpchprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - func = shpchp_slot_find(busn, devn, funn); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - shpchprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - shpchprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static int bind_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int status = 0; - - if (ab->bus_head) { - dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head); - if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head)) - warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); - - if (ab->io_head) { - dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->io_head, ab->io_head); - if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head)) - warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); - - if (ab->mem_head) { - dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head); - if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head)) - warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); - - if (ab->p_mem_head) { - dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); - if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) - warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); - - return status; -} - -static int no_pci_resources( struct acpi_bridge *ab) -{ - return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); -} - -static int find_pci_bridge_resources ( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - struct pci_func func; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ab->pbus; - func.device = ab->pdevice; - func.function = ab->pfunction; - func.is_a_board = 1; - - /* Get used resources for this PCI bridge */ - rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); - - ab->io_head = func.io_head; - ab->mem_head = func.mem_head; - ab->p_mem_head = func.p_mem_head; - ab->bus_head = func.bus_head; - if (ab->bus_head) - shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1); - - return rc; -} - -static int get_pci_resources_from_bridge( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); - - rc = find_pci_bridge_resources (ctrl, ab); - - shpchp_resource_sort_and_combine(&ab->bus_head); - shpchp_resource_sort_and_combine(&ab->io_head); - shpchp_resource_sort_and_combine(&ab->mem_head); - shpchp_resource_sort_and_combine(&ab->p_mem_head); - - shpchprm_add_resources (&ab->tbus_head, ab->bus_head); - shpchprm_add_resources (&ab->tio_head, ab->io_head); - shpchprm_add_resources (&ab->tmem_head, ab->mem_head); - shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - - return rc; -} - -static int get_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - if (no_pci_resources(ab)) { - dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); - rc = get_pci_resources_from_bridge(ctrl, ab); - } - - return rc; -} - int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { int offset = devnum - ctrl->slot_device_offset; @@ -1570,42 +755,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -/* - * Get resources for this ctrl. - * 1. get total resources from ACPI _CRS or bridge (this ctrl) - * 2. find used resources of existing adapters - * 3. subtract used resources from total resources - */ -int shpchprm_find_available_resources( struct controller *ctrl) -{ - int rc = 0; - struct acpi_bridge *ab; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); - if (!ab) { - err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); - return -1; - } - if (no_pci_resources(ab)) { - rc = get_pci_resources(ctrl, ab); - if (rc) { - err("pfar:cannot get pci resources of PCI 0x%x.\n",ctrl->pci_dev->subordinate->number); - return -1; - } - } - - rc = bind_pci_resources(ctrl, ab); - dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - shpchprm_dump_ctrl_res(ctrl); - - bind_pci_resources_to_slots (ctrl); - - dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - shpchprm_dump_ctrl_res(ctrl); - - return rc; -} - int shpchprm_set_hpp( struct controller *ctrl, struct pci_func *func, diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index ba6c549c9b9d..6c27debe9522 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c @@ -34,25 +34,11 @@ #include #include #include -#ifdef CONFIG_IA64 -#include -#endif #include "shpchp.h" #include "shpchprm.h" -#include "shpchprm_legacy.h" - -static void __iomem *shpchp_rom_start; -static u16 unused_IRQ; void shpchprm_cleanup(void) { - if (shpchp_rom_start) - iounmap(shpchp_rom_start); -} - -int shpchprm_print_pirt(void) -{ - return 0; } int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) @@ -63,280 +49,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -/* Find the Hot Plug Resource Table in the specified region of memory */ -static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end) -{ - void __iomem *fp; - void __iomem *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(struct hrt) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp + SIG0); - temp2 = readb(fp + SIG1); - temp3 = readb(fp + SIG2); - temp4 = readb(fp + SIG3); - if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered Hotplug Resource Table at %p\n", fp); - return fp; -} - -/* - * shpchprm_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int shpchprm_find_available_resources(struct controller *ctrl) -{ - u8 populated_slot; - u8 bridged_slot; - void __iomem *one_slot; - struct pci_func *func = NULL; - int i = 10, index = 0; - u32 temp_dword, rc; - ulong temp_ulong; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - void __iomem *rom_resource_table; - struct pci_bus lpci_bus, *pci_bus; - u8 cfgspc_irq, temp; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff); - dbg("rom_resource_table = %p\n", rom_resource_table); - if (rom_resource_table == NULL) - return -ENODEV; - - /* Sum all resources and setup resource maps */ - unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); - dbg("unused_IRQ = %x\n", unused_IRQ); - - temp = 0; - while (unused_IRQ) { - if (unused_IRQ & 1) { - shpchp_disk_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq); - unused_IRQ = unused_IRQ >> 1; - temp++; - - while (unused_IRQ) { - if (unused_IRQ & 1) { - shpchp_nic_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq); - unused_IRQ = readl(rom_resource_table + PCIIRQ); - - temp = 0; - - pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq); - - if (!shpchp_nic_irq) { - shpchp_nic_irq = cfgspc_irq; - } - - if (!shpchp_disk_irq) { - shpchp_disk_irq = cfgspc_irq; - } - - dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq); - - one_slot = rom_resource_table + sizeof(struct hrt); - - i = readb(rom_resource_table + NUMBER_OF_ENTRIES); - dbg("number_of_entries = %d\n", i); - - if (!readb(one_slot + SECONDARY_BUS)) - return (1); - - dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n"); - - while (i && readb(one_slot + SECONDARY_BUS)) { - u8 dev_func = readb(one_slot + DEV_FUNC); - u8 primary_bus = readb(one_slot + PRIMARY_BUS); - u8 secondary_bus = readb(one_slot + SECONDARY_BUS); - u8 max_bus = readb(one_slot + MAX_BUS); - u16 io_base = readw(one_slot + IO_BASE); - u16 io_length = readw(one_slot + IO_LENGTH); - u16 mem_base = readw(one_slot + MEM_BASE); - u16 mem_length = readw(one_slot + MEM_LENGTH); - u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); - u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); - - dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", - dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, - primary_bus, secondary_bus, max_bus); - - /* If this entry isn't for our controller's bus, ignore it */ - if (primary_bus != ctrl->slot_bus) { - i--; - one_slot += sizeof(struct slot_rt); - continue; - } - /* find out if this entry is for an occupied slot */ - temp_dword = 0xFFFFFFFF; - pci_bus->number = primary_bus; - pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); - - dbg("temp_D_word = %x\n", temp_dword); - - if (temp_dword != 0xFFFFFFFF) { - index = 0; - func = shpchp_slot_find(primary_bus, dev_func >> 3, 0); - - while (func && (func->function != (dev_func & 0x07))) { - dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index); - func = shpchp_slot_find(primary_bus, dev_func >> 3, index++); - } - - /* If we can't find a match, skip this table entry */ - if (!func) { - i--; - one_slot += sizeof(struct slot_rt); - continue; - } - /* this may not work and shouldn't be used */ - if (secondary_bus != primary_bus) - bridged_slot = 1; - else - bridged_slot = 0; - - populated_slot = 1; - } else { - populated_slot = 0; - bridged_slot = 0; - } - dbg("slot populated =%s \n", populated_slot?"yes":"no"); - - /* If we've got a valid IO base, use it */ - - temp_ulong = io_base + io_length; - - if ((io_base) && (temp_ulong <= 0x10000)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)io_base; - io_node->length = (ulong)io_length; - dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); - - if (!populated_slot) { - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } else { - io_node->next = func->io_head; - func->io_head = io_node; - } - } - - /* If we've got a valid memory base, use it */ - temp_ulong = mem_base + mem_length; - if ((mem_base) && (temp_ulong <= 0x10000)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = (ulong)mem_base << 16; - mem_node->length = (ulong)(mem_length << 16); - dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); - - if (!populated_slot) { - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } else { - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - } - - /* - * If we've got a valid prefetchable memory base, and - * the base + length isn't greater than 0xFFFF - */ - temp_ulong = pre_mem_base + pre_mem_length; - if ((pre_mem_base) && (temp_ulong <= 0x10000)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = (ulong)pre_mem_base << 16; - p_mem_node->length = (ulong)pre_mem_length << 16; - dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); - - if (!populated_slot) { - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } else { - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } - - /* - * If we've got a valid bus number, use it - * The second condition is to ignore bus numbers on - * populated slots that don't have PCI-PCI bridges - */ - if (secondary_bus && (secondary_bus != primary_bus)) { - bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = (ulong)secondary_bus; - bus_node->length = (ulong)(max_bus - secondary_bus + 1); - dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); - - if (!populated_slot) { - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } else { - bus_node->next = func->bus_head; - func->bus_head = bus_node; - } - } - - i--; - one_slot += sizeof(struct slot_rt); - } - - /* If all of the following fail, we don't have any resources for hot plug add */ - rc = 1; - rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - return (rc); -} - int shpchprm_set_hpp( struct controller *ctrl, struct pci_func *func, @@ -413,12 +125,6 @@ void shpchprm_enable_card( static int legacy_shpchprm_init_pci(void) { - shpchp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!shpchp_rom_start) { - err("Could not ioremap memory region for ROM\n"); - return -EIO; - } - return 0; } diff --git a/drivers/pci/hotplug/shpchprm_legacy.h b/drivers/pci/hotplug/shpchprm_legacy.h deleted file mode 100644 index 21bda74ddfa5..000000000000 --- a/drivers/pci/hotplug/shpchprm_legacy.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * - */ - -#ifndef _SHPCHPRM_LEGACY_H_ -#define _SHPCHPRM_LEGACY_H_ - -#define ROM_PHY_ADDR 0x0F0000 -#define ROM_PHY_LEN 0x00FFFF - -struct slot_rt { - u8 dev_func; - u8 primary_bus; - u8 secondary_bus; - u8 max_bus; - u16 io_base; - u16 io_length; - u16 mem_base; - u16 mem_length; - u16 pre_mem_base; - u16 pre_mem_length; -} __attribute__ ((packed)); - -/* offsets to the hotplug slot resource table registers based on the above structure layout */ -enum slot_rt_offsets { - DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), -}; - -struct hrt { - char sig0; - char sig1; - char sig2; - char sig3; - u16 unused_IRQ; - u16 PCIIRQ; - u8 number_of_entries; - u8 revision; - u16 reserved1; - u32 reserved2; -} __attribute__ ((packed)); - -/* offsets to the hotplug resource table registers based on the above structure layout */ -enum hrt_offsets { - SIG0 = offsetof(struct hrt, sig0), - SIG1 = offsetof(struct hrt, sig1), - SIG2 = offsetof(struct hrt, sig2), - SIG3 = offsetof(struct hrt, sig3), - UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), - PCIIRQ = offsetof(struct hrt, PCIIRQ), - NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), - REVISION = offsetof(struct hrt, revision), - HRT_RESERVED1 = offsetof(struct hrt, reserved1), - HRT_RESERVED2 = offsetof(struct hrt, reserved2), -}; - -struct irq_info { - u8 bus, devfn; /* bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__ ((packed)) irq[4]; - u8 slot; /* slot number, 0=onboard */ - u8 rfu; -} __attribute__ ((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__ ((packed)); - -#endif /* _SHPCHPRM_LEGACY_H_ */ diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index 5f75ef7f3df2..9d4ccae5f78e 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c @@ -34,23 +34,14 @@ #include #include #include -#ifdef CONFIG_IA64 -#include -#endif #include "shpchp.h" #include "shpchprm.h" -#include "shpchprm_nonacpi.h" void shpchprm_cleanup(void) { return; } -int shpchprm_print_pirt(void) -{ - return 0; -} - int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { int offset = devnum - ctrl->slot_device_offset; @@ -60,275 +51,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - - -static void phprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static int phprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int phprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - shpchp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - - -static int phprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - phprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = phprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - func = shpchp_slot_find(busn, devn, funn); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - phprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - phprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static void phprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -/* - * phprm_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int shpchprm_find_available_resources(struct controller *ctrl) -{ - struct pci_func func; - u32 rc; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ctrl->bus; - func.device = ctrl->device; - func.function = ctrl->function; - func.is_a_board = 1; - - /* Get resources for this PCI bridge */ - rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); - dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc); - - if (func.mem_head) - func.mem_head->next = ctrl->mem_head; - ctrl->mem_head = func.mem_head; - - if (func.p_mem_head) - func.p_mem_head->next = ctrl->p_mem_head; - ctrl->p_mem_head = func.p_mem_head; - - if (func.io_head) - func.io_head->next = ctrl->io_head; - ctrl->io_head = func.io_head; - - if(func.bus_head) - func.bus_head->next = ctrl->bus_head; - ctrl->bus_head = func.bus_head; - if (ctrl->bus_head) - phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); - - dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - bind_pci_resources_to_slots (ctrl); - - dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - - - /* If all of the following fail, we don't have any resources for hot plug add */ - rc = 1; - rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - return (rc); -} - int shpchprm_set_hpp( struct controller *ctrl, struct pci_func *func, diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.h b/drivers/pci/hotplug/shpchprm_nonacpi.h deleted file mode 100644 index cddaaa5ee1b3..000000000000 --- a/drivers/pci/hotplug/shpchprm_nonacpi.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * - */ - -#ifndef _SHPCHPRM_NONACPI_H_ -#define _SHPCHPRM_NONACPI_H_ - -struct irq_info { - u8 bus, devfn; /* bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__ ((packed)) irq[4]; - u8 slot; /* slot number, 0=onboard */ - u8 rfu; -} __attribute__ ((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__ ((packed)); - -#endif /* _SHPCHPRM_NONACPI_H_ */ From 7e88ed199689f333668b62348051202706b6a74a Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:37 -0700 Subject: [PATCH 1091/1939] [PATCH] shpchp: remove redundant display of PCI device resources Info about resources assigned to PCI devices is already available through sysfs and pci utilities. There's no need for shpchp to create another sysfs file to display the same information. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_sysfs.c | 68 ------------------------------ 1 file changed, 68 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index b0e781dbcffb..ce41719a88f7 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -88,75 +88,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pci_dev *pdev, *fdev; - struct controller *ctrl; - char * out = buf; - int index; - struct resource *res; - struct pci_func *new_slot; - struct slot *slot; - - pdev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pdev); - - slot=ctrl->slot; - - while (slot) { - new_slot = shpchp_slot_find(slot->bus, slot->device, 0); - if (!new_slot) - break; - fdev = new_slot->pci_dev; - if (!fdev) - break; - out += sprintf(out, "assigned resources: memory\n"); - for (index=0; index <= PCI_NUM_RESOURCES; index++) { - res = &(fdev->resource[index]); - if (res && (res->flags & IORESOURCE_MEM) && - !(res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, - "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); - } - } - out += sprintf(out, "assigned resources: prefetchable memory\n"); - for (index=0; index <= PCI_NUM_RESOURCES; index++) { - res = &(fdev->resource[index]); - if (res && (res->flags & (IORESOURCE_MEM | - IORESOURCE_PREFETCH))) { - out += sprintf(out, - "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); - } - } - out += sprintf(out, "assigned resources: IO\n"); - for (index=0; index <= PCI_NUM_RESOURCES; index++) { - res = &(fdev->resource[index]); - if (res && (res->flags & IORESOURCE_IO)) { - out += sprintf(out, - "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); - } - } - out += sprintf(out, "assigned resources: bus numbers\n"); - if (fdev->subordinate) - out += sprintf(out, "start = %8.8x, length = %8.8x\n", - fdev->subordinate->secondary, - (fdev->subordinate->subordinate - - fdev->subordinate->secondary)); - else - out += sprintf(out, "start = %8.8x, length = %8.8x\n", - fdev->bus->number, 1); - slot=slot->next; - } - - return out - buf; -} -static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); - void shpchp_create_ctrl_files (struct controller *ctrl) { device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); - device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); } From 424600f9706b20a8a33ad928d3d0326bd88679bc Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:38 -0700 Subject: [PATCH 1092/1939] [PATCH] shpchp: reduce dependence on ACPI Reduce the SHPC hotplug driver's dependence on ACPI. We don't walk the acpi namespace anymore to build a list of bridges and devices. The remaining interaction with ACPI is to run the _OSHP method to transition control of hotplug hardware from system BIOS to the shpc hotplug driver, and to run the _HPP method to get hotplug device parameters like cache line size, latency timer and SERR/PERR enable from BIOS. Note that one of the side effects of this patch is that shpchp does not enable the hot-added device or its DMA bus mastering automatically now. It expects the device driver to do that. This may break some drivers and we will have to fix them as they are reported. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 12 + drivers/pci/hotplug/shpchp_core.c | 13 +- drivers/pci/hotplug/shpchp_ctrl.c | 1 - drivers/pci/hotplug/shpchp_hpc.c | 2 +- drivers/pci/hotplug/shpchp_pci.c | 52 +- drivers/pci/hotplug/shpchprm.h | 43 -- drivers/pci/hotplug/shpchprm_acpi.c | 794 ++----------------------- drivers/pci/hotplug/shpchprm_legacy.c | 97 +-- drivers/pci/hotplug/shpchprm_nonacpi.c | 108 +--- 9 files changed, 138 insertions(+), 984 deletions(-) delete mode 100644 drivers/pci/hotplug/shpchprm.h diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index deea56c73cf2..1b345ae81ddb 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -122,6 +122,13 @@ struct controller { u16 vendor_id; }; +struct hotplug_params { + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + /* Define AMD SHPC ID */ #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 @@ -192,6 +199,11 @@ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ct extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct pci_func* func); +extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); +extern void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp); +extern int shpchprm_get_physical_slot_number(struct controller *ctrl, + u32 *sun, u8 busnum, u8 devnum); /* Global variables */ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 8f5da504df34..e3c0c17295da 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -39,7 +39,6 @@ #include #include #include "shpchp.h" -#include "shpchprm.h" /* Global variables */ int shpchp_debug; @@ -566,16 +565,12 @@ static int __init shpcd_init(void) if (retval) goto error_hpc_init; - retval = shpchprm_init(PCI); - if (!retval) { - retval = pci_register_driver(&shpc_driver); - dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - } + retval = pci_register_driver(&shpc_driver); + dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); error_hpc_init: if (retval) { - shpchprm_cleanup(); shpchp_event_stop_thread(); } return retval; @@ -586,8 +581,6 @@ static void __exit shpcd_cleanup(void) dbg("unload_shpchpd()\n"); unload_shpchpd(); - shpchprm_cleanup(); - dbg("pci_unregister_driver\n"); pci_unregister_driver(&shpc_driver); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index aa507e453e49..23dd61c4c66c 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -40,7 +40,6 @@ #include #include "../pci.h" #include "shpchp.h" -#include "shpchprm.h" static void interrupt_event_handler(struct controller *ctrl); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 8d98410bf1c0..d55a9a7f8d2b 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -1566,8 +1566,8 @@ int shpc_init(struct controller * ctrl, err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); goto abort_free_ctlr; } - /* Execute OSHP method here */ } + get_hp_hw_control_from_firmware(pdev); dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); /* Add this HPC instance into the HPC list */ diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 89e404805777..6209972313f3 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -38,6 +38,55 @@ #include "../pci.h" #include "shpchp.h" +void program_fw_provided_values(struct pci_dev *dev) +{ + u16 pci_cmd, pci_bctl; + struct pci_dev *cdev; + struct hotplug_params hpp = {0x8, 0x40, 0, 0}; /* defaults */ + + /* Program hpp values for this device */ + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + + get_hp_params_from_firmware(dev, &hpp); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + if (hpp.enable_serr) + pci_cmd |= PCI_COMMAND_SERR; + else + pci_cmd &= ~PCI_COMMAND_SERR; + if (hpp.enable_perr) + pci_cmd |= PCI_COMMAND_PARITY; + else + pci_cmd &= ~PCI_COMMAND_PARITY; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Program bridge control value and child devices */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, + hpp.latency_timer); + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); + if (hpp.enable_serr) + pci_bctl |= PCI_BRIDGE_CTL_SERR; + else + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; + if (hpp.enable_perr) + pci_bctl |= PCI_BRIDGE_CTL_PARITY; + else + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + program_fw_provided_values(cdev); + } + } +} + int shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; @@ -90,8 +139,7 @@ int shpchp_configure_device(struct slot *p_slot) child->subordinate = pci_do_scan_bus(child); pci_bus_size_bridges(child); } - /* TBD: program firmware provided _HPP values */ - /* program_fw_provided_values(dev); */ + program_fw_provided_values(dev); } pci_bus_assign_resources(parent); diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h deleted file mode 100644 index df474b27d6e8..000000000000 --- a/drivers/pci/hotplug/shpchprm.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * - */ - -#ifndef _SHPCHPRM_H_ -#define _SHPCHPRM_H_ - -#ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY -#include "shpchprm_legacy.h" -#endif - -int shpchprm_init(enum php_ctlr_type ct); -void shpchprm_cleanup(void); -int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); -void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); -int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); - -#endif /* _SHPCHPRM_H_ */ diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 3d2f9c5269c7..3be518c7d47a 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -38,62 +38,11 @@ #include #include #include "shpchp.h" -#include "shpchprm.h" - -#define PCI_MAX_BUS 0x100 -#define ACPI_STA_DEVICE_PRESENT 0x01 #define METHOD_NAME__SUN "_SUN" #define METHOD_NAME__HPP "_HPP" #define METHOD_NAME_OSHP "OSHP" -#define PHP_RES_BUS 0xA0 -#define PHP_RES_IO 0xA1 -#define PHP_RES_MEM 0xA2 -#define PHP_RES_PMEM 0xA3 - -#define BRIDGE_TYPE_P2P 0x00 -#define BRIDGE_TYPE_HOST 0x01 - -/* this should go to drivers/acpi/include/ */ -struct acpi__hpp { - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -struct acpi_php_slot { - struct acpi_php_slot *next; - struct acpi_bridge *bridge; - acpi_handle handle; - int seg; - int bus; - int dev; - int fun; - u32 sun; - void *slot_ops; /* _STA, _EJx, etc */ - struct slot *slot; -}; /* per func */ - -struct acpi_bridge { - struct acpi_bridge *parent; - struct acpi_bridge *next; - struct acpi_bridge *child; - acpi_handle handle; - int seg; - int pbus; /* pdev->bus->number */ - int pdevice; /* PCI_SLOT(pdev->devfn) */ - int pfunction; /* PCI_DEVFN(pdev->devfn) */ - int bus; /* pdev->subordinate->number */ - struct acpi__hpp *_hpp; - struct acpi_php_slot *slots; - int scanned; - int type; -}; - -static struct acpi_bridge *acpi_bridges_head; - static u8 * acpi_path_name( acpi_handle handle) { acpi_status status; @@ -109,82 +58,43 @@ static u8 * acpi_path_name( acpi_handle handle) return path_name; } -static void acpi_get__hpp ( struct acpi_bridge *ab); -static void acpi_run_oshp ( struct acpi_bridge *ab); - -static int acpi_add_slot_to_php_slots( - struct acpi_bridge *ab, - int bus_num, - acpi_handle handle, - u32 adr, - u32 sun - ) -{ - struct acpi_php_slot *aps; - static long samesun = -1; - - aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); - if (!aps) { - err ("acpi_shpchprm: alloc for aps fail\n"); - return -1; - } - memset(aps, 0, sizeof(struct acpi_php_slot)); - - aps->handle = handle; - aps->bus = bus_num; - aps->dev = (adr >> 16) & 0xffff; - aps->fun = adr & 0xffff; - aps->sun = sun; - - aps->next = ab->slots; /* cling to the bridge */ - aps->bridge = ab; - ab->slots = aps; - - ab->scanned += 1; - if (!ab->_hpp) - acpi_get__hpp(ab); - - acpi_run_oshp(ab); - - if (sun != samesun) { - info("acpi_shpchprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, - aps->bus, aps->dev, aps->fun); - samesun = sun; - } - return 0; -} - -static void acpi_get__hpp ( struct acpi_bridge *ab) +static acpi_status +acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) { acpi_status status; u8 nui[4]; struct acpi_buffer ret_buf = { 0, NULL}; union acpi_object *ext_obj, *package; - u8 *path_name = acpi_path_name(ab->handle); + u8 *path_name = acpi_path_name(handle); int i, len = 0; /* get _hpp */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); switch (status) { case AE_BUFFER_OVERFLOW: ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); if (!ret_buf.pointer) { - err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name); - return; + err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, + path_name); + return AE_NO_MEMORY; } - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + status = acpi_evaluate_object(handle, METHOD_NAME__HPP, + NULL, &ret_buf); if (ACPI_SUCCESS(status)) break; default: if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status); - return; + dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, + path_name, status); + return status; } } ext_obj = (union acpi_object *) ret_buf.pointer; if (ext_obj->type != ACPI_TYPE_PACKAGE) { - err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name); + err ("%s:%s _HPP obj not a package\n", __FUNCTION__, + path_name); + status = AE_ERROR; goto free_and_return; } @@ -197,553 +107,41 @@ static void acpi_get__hpp ( struct acpi_bridge *ab) nui[i] = (u8)ext_obj->integer.value; break; default: - err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name); + err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, + path_name); + status = AE_ERROR; goto free_and_return; } } - ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); - if (!ab->_hpp) { - err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name); - goto free_and_return; - } - memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); + hpp->cache_line_size = nui[0]; + hpp->latency_timer = nui[1]; + hpp->enable_serr = nui[2]; + hpp->enable_perr = nui[3]; - ab->_hpp->cache_line_size = nui[0]; - ab->_hpp->latency_timer = nui[1]; - ab->_hpp->enable_serr = nui[2]; - ab->_hpp->enable_perr = nui[3]; - - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); free_and_return: kfree(ret_buf.pointer); + return status; } -static void acpi_run_oshp ( struct acpi_bridge *ab) +static void acpi_run_oshp(acpi_handle handle) { acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); + u8 *path_name = acpi_path_name(handle); /* run OSHP */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); + status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); - } else - dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); - return; -} - -/* find acpi_bridge downword from ab. */ -static struct acpi_bridge * -find_acpi_bridge_by_bus( - struct acpi_bridge *ab, - int seg, - int bus /* pdev->subordinate->number */ - ) -{ - struct acpi_bridge *lab = NULL; - - if (!ab) - return NULL; - - if ((ab->bus == bus) && (ab->seg == seg)) - return ab; - - if (ab->child) - lab = find_acpi_bridge_by_bus(ab->child, seg, bus); - - if (!lab) - if (ab->next) - lab = find_acpi_bridge_by_bus(ab->next, seg, bus); - - return lab; -} - -/* - * Build a device tree of ACPI PCI Bridges - */ -static void shpchprm_acpi_register_a_bridge ( - struct acpi_bridge **head, - struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ - struct acpi_bridge *cab /* child bridge to add */ - ) -{ - struct acpi_bridge *lpab; - struct acpi_bridge *lcab; - - lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); - if (!lpab) { - if (!(pab->type & BRIDGE_TYPE_HOST)) - warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); - pab->next = *head; - *head = pab; - lpab = pab; - } - - if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) - return; - - lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); - if (lcab) { - if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) - err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); - return; - } else - lcab = cab; - - lcab->parent = lpab; - lcab->next = lpab->child; - lpab->child = lcab; -} - -static acpi_status shpchprm_acpi_build_php_slots_callback( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong bus_num; - ulong seg_num; - ulong sun, adr; - ulong padr = 0; - acpi_handle phandle = NULL; - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *lab; - acpi_status status; - u8 *path_name = acpi_path_name(handle); - - /* get _SUN */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); - switch(status) { - case AE_NOT_FOUND: - return AE_OK; - default: - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); - return status; - } - } - - /* get _ADR. _ADR must exist if _SUN exists */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return status; - } - - dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); - - status = acpi_get_parent(handle, &phandle); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); - return (status); - } - - bus_num = pab->bus; - seg_num = pab->seg; - - if (pab->bus == bus_num) { - lab = pab; + err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, + status); } else { - dbg("WARN: pab is not parent\n"); - lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); - if (!lab) { - dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); - lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); - if (!lab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return AE_NO_MEMORY; - } - memset(lab, 0, sizeof(struct acpi_bridge)); - - lab->handle = phandle; - lab->pbus = pab->bus; - lab->pdevice = (int)(padr >> 16) & 0xffff; - lab->pfunction = (int)(padr & 0xffff); - lab->bus = (int)bus_num; - lab->scanned = 0; - lab->type = BRIDGE_TYPE_P2P; - - shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); - } else - dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); } - - acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); - return (status); -} - -static int shpchprm_acpi_build_php_slots( - struct acpi_bridge *ab, - u32 depth - ) -{ - acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); - - /* Walk down this pci bridge to get _SUNs if any behind P2P */ - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - ab->handle, - depth, - shpchprm_acpi_build_php_slots_callback, - ab, - NULL ); - if (ACPI_FAILURE(status)) { - dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); - return -1; - } - - return 0; -} - -static void build_a_bridge( - struct acpi_bridge *pab, - struct acpi_bridge *ab - ) -{ - u8 *path_name = acpi_path_name(ab->handle); - - shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - case BRIDGE_TYPE_P2P: - dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - }; - - /* build any immediate PHP slots under this pci bridge */ - shpchprm_acpi_build_php_slots(ab, 1); -} - -static struct acpi_bridge * add_p2p_bridge( - acpi_handle handle, - struct acpi_bridge *pab, /* parent */ - ulong adr - ) -{ - struct acpi_bridge *ab; - struct pci_dev *pdev; - ulong devnum, funcnum; - u8 *path_name = acpi_path_name(handle); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev || !pdev->subordinate) { - err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); - kfree(ab); - return NULL; - } - - ab->handle = handle; - ab->seg = pab->seg; - ab->pbus = pab->bus; /* or pdev->bus->number */ - ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ - ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ - ab->bus = pdev->subordinate->number; - ab->scanned = 0; - ab->type = BRIDGE_TYPE_P2P; - - dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", - pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pab->bus, (u32)devnum, (u32)funcnum, path_name); - - build_a_bridge(pab, ab); - - return ab; -} - -static acpi_status scan_p2p_bridge( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *ab; - acpi_status status; - ulong adr = 0; - u8 *path_name = acpi_path_name(handle); - ulong devnum, funcnum; - struct pci_dev *pdev; - - /* get device, function */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return AE_OK; - } - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev) - return AE_OK; - if (!pdev->subordinate) - return AE_OK; - - ab = add_p2p_bridge(handle, pab, adr); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - (u32)1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static struct acpi_bridge * add_host_bridge( - acpi_handle handle, - ulong segnum, - ulong busnum - ) -{ - ulong adr = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get device, function: host br adr is always 0000 though. */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return NULL; - } - dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, - (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - ab->handle = handle; - ab->seg = (int)segnum; - ab->bus = ab->pbus = (int)busnum; - ab->pdevice = (int)(adr >> 16) & 0xffff; - ab->pfunction = (int)(adr & 0xffff); - ab->scanned = 0; - ab->type = BRIDGE_TYPE_HOST; - - build_a_bridge(ab, ab); - - return ab; -} - -static acpi_status acpi_scan_from_root_pci_callback ( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong segnum = 0; - ulong busnum = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); - return status; - } - segnum = 0; - } - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); - return (status); - } - - ab = add_host_bridge(handle, segnum, busnum); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - 1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static int shpchprm_acpi_scan_pci (void) -{ - acpi_status status; - - /* - * TBD: traverse LDM device tree with the help of - * unified ACPI augmented for php device population. - */ - status = acpi_get_devices ( PCI_ROOT_HID_STRING, - acpi_scan_from_root_pci_callback, - NULL, - NULL ); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); - return -1; - } - - return 0; -} - -int shpchprm_init(enum php_ctlr_type ctlr_type) -{ - int rc; - - if (ctlr_type != PCI) - return -ENODEV; - - dbg("shpchprm ACPI init \n"); - acpi_bridges_head = NULL; - - /* construct PCI bus:device tree of acpi_handles */ - rc = shpchprm_acpi_scan_pci(); - if (rc) - return rc; - - dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); - return rc; -} - -static void free_a_slot(struct acpi_php_slot *aps) -{ - dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); - - kfree(aps); -} - -static void free_a_bridge( struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps, *next; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - case BRIDGE_TYPE_P2P: - dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - }; - - /* free slots first */ - for (aps = ab->slots; aps; aps = next) { - next = aps->next; - free_a_slot(aps); - } - - kfree(ab); -} - -static void shpchprm_free_bridges ( struct acpi_bridge *ab) -{ - if (!ab) - return; - - if (ab->child) - shpchprm_free_bridges (ab->child); - - if (ab->next) - shpchprm_free_bridges (ab->next); - - free_a_bridge(ab); -} - -void shpchprm_cleanup(void) -{ - shpchprm_free_bridges (acpi_bridges_head); -} - -static int get_number_of_slots ( - struct acpi_bridge *ab, - int selfonly - ) -{ - struct acpi_php_slot *aps; - int prev_slot = -1; - int slot_num = 0; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->dev != prev_slot) { - prev_slot = aps->dev; - slot_num++; - } - - if (ab->child) - slot_num += get_number_of_slots (ab->child, 0); - - if (selfonly) - return slot_num; - - if (ab->next) - slot_num += get_number_of_slots (ab->next, 0); - - return slot_num; -} - -static struct acpi_php_slot * get_acpi_slot ( - struct acpi_bridge *ab, - u32 sun - ) -{ - struct acpi_php_slot *aps = NULL; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->sun == sun) - return aps; - - if (!aps && ab->child) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); - if (aps) - return aps; - } - - if (!aps && ab->next) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); - if (aps) - return aps; - } - - return aps; - } int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) @@ -755,108 +153,40 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type - ) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - struct acpi_bridge *ab; - struct pci_bus lpci_bus, *pci_bus; - int rc = 0; - unsigned int devfn; - u8 cls= 0x08; /* default cache line size */ - u8 lt = 0x40; /* default latency timer */ - u8 ep = 0; - u8 es = 0; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); - - if (ab) { - if (ab->_hpp) { - lt = (u8)ab->_hpp->latency_timer; - cls = (u8)ab->_hpp->cache_line_size; - ep = (u8)ab->_hpp->enable_perr; - es = (u8)ab->_hpp->enable_serr; - } else - dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - } else - dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); - } - - /* set base Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); - dbg(" set latency timer =0x%02x: %x\n", lt, rc); - - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); - dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); - - return rc; + /* + * OSHP is an optional ACPI firmware control method. If present, + * we need to run it to inform BIOS that we will control SHPC + * hardware from now on. + */ + acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); + if (!handle) + return; + acpi_run_oshp(handle); } -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - u16 command, cmd, bcommand, bcmd; - struct pci_bus lpci_bus, *pci_bus; - struct acpi_bridge *ab; - unsigned int devfn; - int rc; + acpi_status status = AE_NOT_FOUND; + struct pci_dev *pdev = dev; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - } - - cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); - if (ab) { - if (ab->_hpp) { - if (ab->_hpp->enable_perr) { - command |= PCI_COMMAND_PARITY; - bcommand |= PCI_BRIDGE_CTL_PARITY; - } else { - command &= ~PCI_COMMAND_PARITY; - bcommand &= ~PCI_BRIDGE_CTL_PARITY; - } - if (ab->_hpp->enable_serr) { - command |= PCI_COMMAND_SERR; - bcommand |= PCI_BRIDGE_CTL_SERR; - } else { - command &= ~PCI_COMMAND_SERR; - bcommand &= ~PCI_BRIDGE_CTL_SERR; - } - } else - dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - } else - dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - - if (command != cmd) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - } - if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + /* + * _HPP settings apply to all child buses, until another _HPP is + * encountered. If we don't find an _HPP for the input pci dev, + * look for it in the parent device scope since that would apply to + * this pci dev. If we don't find any _HPP, use hardcoded defaults + */ + while (pdev && (ACPI_FAILURE(status))) { + acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); + if (!handle) + break; + status = acpi_run_hpp(handle, hpp); + if (!(pdev->bus->parent)) + break; + /* Check if a parent object supports _HPP */ + pdev = pdev->bus->parent->self; } } diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index 6c27debe9522..cfc6092e2afd 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c @@ -37,10 +37,6 @@ #include "shpchp.h" #include "shpchprm.h" -void shpchprm_cleanup(void) -{ -} - int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { int offset = devnum - ctrl->slot_device_offset; @@ -49,97 +45,14 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - u32 rc; - u8 temp_byte; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - temp_byte = 0x40; /* hard coded value for LT */ - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - if (rc) { - dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, - func->device, func->function); - return rc; - } - } - - /* set base Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - if (rc) { - dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - return rc; - } - - /* set Cache Line size */ - temp_byte = 0x08; /* hard coded value for CLS */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - if (rc) { - dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - } - - /* set enable_perr */ - /* set enable_serr */ - - return rc; + return; } -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - u16 command, bcommand; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR - | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR - | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } + return; } -static int legacy_shpchprm_init_pci(void) -{ - return 0; -} - -int shpchprm_init(enum php_ctlr_type ctrl_type) -{ - int retval; - - switch (ctrl_type) { - case PCI: - retval = legacy_shpchprm_init_pci(); - break; - default: - retval = -ENODEV; - break; - } - - return retval; -} diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index 9d4ccae5f78e..f36c188c23eb 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c @@ -37,11 +37,6 @@ #include "shpchp.h" #include "shpchprm.h" -void shpchprm_cleanup(void) -{ - return; -} - int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { int offset = devnum - ctrl->slot_device_offset; @@ -51,106 +46,13 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - u32 rc; - u8 temp_byte; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - temp_byte = 0x40; /* hard coded value for LT */ - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, - func->device, func->function); - return rc; - } - } - - /* set base Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - return rc; - } - - /* set Cache Line size */ - temp_byte = 0x08; /* hard coded value for CLS */ - - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - - if (rc) { - dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - } - - /* set enable_perr */ - /* set enable_serr */ - - return rc; + return; } -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - u16 command, bcommand; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - - command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR - | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - - bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR - | PCI_BRIDGE_CTL_NO_ISA; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } -} - -static int legacy_shpchprm_init_pci(void) -{ - return 0; -} - -int shpchprm_init(enum php_ctlr_type ctrl_type) -{ - int retval; - - switch (ctrl_type) { - case PCI: - retval = legacy_shpchprm_init_pci(); - break; - default: - retval = -ENODEV; - break; - } - - return retval; + return; } From 1410dc1cef1e2f5e90c1fcb97041f42e0eee35b4 Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:39 -0700 Subject: [PATCH 1093/1939] [PATCH] shpchp: detect SHPC capability before doing a lot of work The shpc driver registers its probe function for all pci-pci bridges in the system. Not all of them will be shpc capable, so look for this capability early in the probe function and return if there's no work to do on this bridge. The old shpc driver did some initialization work on all bridges before detecting that shpc is not supported and unwinds the work it's already done in that case. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index e3c0c17295da..3132d60a79f5 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -351,6 +351,17 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp return 0; } +static int is_shpc_capable(struct pci_dev *dev) +{ + if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == + PCI_DEVICE_ID_AMD_GOLAM_7450)) + return 1; + if (pci_find_capability(dev, PCI_CAP_ID_SHPC)) + return 1; + + return 0; +} + static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; @@ -359,6 +370,9 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int first_device_num; /* first PCI device number supported by this SHPC */ int num_ctlr_slots; /* number of slots supported by this SHPC */ + if (!is_shpc_capable(pdev)) + return -ENODEV; + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); From 70b6091946ab486c4dab8abeb4a3fc2bf7d3e7fe Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:40 -0700 Subject: [PATCH 1094/1939] [PATCH] shpchp: dont save PCI config for hotplug slots/devices This patch eliminates saving the PCI config header for devices in hotplug capable slots. We now use the PCI core to get the specific parts of the config header as required. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 1 - drivers/pci/hotplug/shpchp_core.c | 7 - drivers/pci/hotplug/shpchp_ctrl.c | 48 +++-- drivers/pci/hotplug/shpchp_pci.c | 314 ------------------------------ 4 files changed, 32 insertions(+), 338 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 1b345ae81ddb..5e99260987e8 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -63,7 +63,6 @@ struct pci_func { u8 switch_save; u8 presence_save; u8 pwr_save; - u32 config_space[0x20]; struct pci_dev* pci_dev; }; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 3132d60a79f5..5d4fc28969d0 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -424,13 +424,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) first_device_num = ctrl->slot_device_offset; num_ctlr_slots = ctrl->num_slots; - /* Store PCI Config Space for all devices on this bus */ - rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); - if (rc) { - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_out_free_ctrl_bus; - } - ctrl->add_support = 1; /* Setup the slot information structures */ diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 23dd61c4c66c..c55103f3cebd 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -328,21 +328,20 @@ static int slot_remove(struct pci_func * old_slot) /** * bridge_slot_remove - Removes a node from the linked list of slots. * @bridge: bridge to remove + * @secondaryBus: secondary PCI bus number for bridge being removed + * @subordinateBus: subordinate PCI bus number for bridge being removed * * Returns 0 if successful, !0 otherwise. */ -static int bridge_slot_remove(struct pci_func *bridge) +static int bridge_slot_remove(struct pci_func *bridge, u8 secondaryBus, + u8 subordinateBus) { - u8 subordinateBus, secondaryBus; u8 tempBus; struct pci_func *next; if (bridge == NULL) return(1); - secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; - subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { next = shpchp_slot_list[tempBus]; @@ -410,16 +409,23 @@ struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) return(NULL); } -static int is_bridge(struct pci_func * func) +static int is_bridge(struct pci_func *func, struct controller *ctrl) { - /* Check the header type */ - if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + u8 hdr_type; + struct pci_bus *bus = ctrl->pci_dev->subordinate; + + /* + * Note: device may have just been hot-added and not yet scanned + * by the pci core, so its pci_dev structure may not exist yet + */ + pci_bus_read_config_byte(bus, PCI_DEVFN(func->device, func->function), + PCI_HEADER_TYPE, &hdr_type); + if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) return 1; else return 0; } - /* The following routines constitute the bulk of the hotplug controller logic */ @@ -709,8 +715,6 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) goto err_exit; } - shpchp_save_slot_config(ctrl, func); - func->status = 0; func->switch_save = 0x10; func->is_a_board = 0x01; @@ -769,10 +773,18 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) u8 hp_slot; u32 rc; struct slot *p_slot; + u8 secondary = 0, subordinate = 0; + int remove_bridge; if (func == NULL) return(1); + if ((remove_bridge = is_bridge(func, ctrl))) { + /* Stash away bus information before we destroy it */ + secondary = func->pci_dev->subordinate->secondary; + subordinate = func->pci_dev->subordinate->subordinate; + } + if (shpchp_unconfigure_device(func)) return(1); @@ -825,10 +837,11 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) if (ctrl->add_support) { while (func) { - if (is_bridge(func)) { + if (remove_bridge) { dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - bridge_slot_remove(func); + bridge_slot_remove(func, secondary, + subordinate); } else dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); @@ -1185,9 +1198,12 @@ int shpchp_enable_slot (struct slot *p_slot) rc = board_added(func, p_slot->ctrl); if (rc) { - if (is_bridge(func)) - bridge_slot_remove(func); - else + if (is_bridge(func, p_slot->ctrl)) { + u8 secondary = func->pci_dev->subordinate->secondary; + u8 subordinate = + func->pci_dev->subordinate->subordinate; + bridge_slot_remove(func, secondary, subordinate); + } else slot_remove(func); /* Setup slot structure with entry for empty slot */ diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 6209972313f3..f51a97d7611f 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -166,317 +166,3 @@ int shpchp_unconfigure_device(struct pci_func* func) return rc; } -/* More PCI configuration routines; this time centered around hotplug controller */ - - -/* - * shpchp_save_config - * - * Reads configuration for all slots in a PCI bus and saves info. - * - * Note: For non-hot plug busses, the slot # saved is the device # - * - * returns 0 if success - */ -int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) -{ - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - struct pci_func *new_slot; - int sub_bus; - int FirstSupported; - int LastSupported; - int max_functions; - int function; - u8 DevError; - int device = 0; - int cloop = 0; - int stop_it; - int index; - int is_hot_plug = num_ctlr_slots || first_device_num; - struct pci_bus lpci_bus, *pci_bus; - - dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, - num_ctlr_slots, first_device_num); - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, - num_ctlr_slots, first_device_num); - - /* Decide which slots are supported */ - if (is_hot_plug) { - /********************************* - * is_hot_plug is the slot mask - *********************************/ - FirstSupported = first_device_num; - LastSupported = FirstSupported + num_ctlr_slots - 1; - } else { - FirstSupported = 0; - LastSupported = 0x1F; - } - - dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, - LastSupported); - - /* Save PCI configuration space for all devices in supported slots */ - pci_bus->number = busnumber; - for (device = FirstSupported; device <= LastSupported; device++) { - ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", class_code, header_type); - - /* If multi-function device, set max_functions to 8 */ - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ - /* Recurse the subordinate bus - * get the subordinate bus number - */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - /* Save secondary bus cfg spc with this recursive call. */ - rc = shpchp_save_config(ctrl, sub_bus, 0, 0); - if (rc) - return rc; - } - } - - index = 0; - new_slot = shpchp_slot_find(busnumber, device, index++); - - dbg("new_slot = %p\n", new_slot); - - while (new_slot && (new_slot->function != (u8) function)) { - new_slot = shpchp_slot_find(busnumber, device, index++); - dbg("new_slot = %p\n", new_slot); - } - if (!new_slot) { - /* Setup slot structure. */ - new_slot = shpchp_slot_create(busnumber); - dbg("new_slot = %p\n", new_slot); - - if (new_slot == NULL) - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - new_slot->pwr_save = 1; - /* In case of unsupported board */ - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, - (new_slot->device << 3) | new_slot->function); - dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); - /* dbg("new_slot->config_space[%x] = %x\n", - cloop, new_slot->config_space[cloop]); */ - if (rc) - return rc; - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in Class Code and Header type. - */ - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - dbg("Nothing there\n"); - } else { /* Something there */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", - class_code, header_type); - stop_it++; - } - } - - } while (function < max_functions); - /* End of IF (device in slot?) */ - } else if (is_hot_plug) { - /* Setup slot structure with entry for empty slot */ - new_slot = shpchp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); - } - dbg("new_slot = %p\n", new_slot); - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } /* End of FOR loop */ - - return(0); -} - - -/* - * shpchp_save_slot_config - * - * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. - * - * returns 0 if success - */ -int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) -{ - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - int sub_bus; - int max_functions; - int function; - int cloop = 0; - int stop_it; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = new_slot->bus; - - ID = 0xFFFFFFFF; - - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - /* Recurse the subordinate bus */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - /* Save the config headers for the secondary bus. */ - rc = shpchp_save_config(ctrl, sub_bus, 0, 0); - - if (rc) - return rc; - - } /* End of IF */ - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in the Class Code and the Header type. - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - } else { /* Something there */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } /* End of IF (device in slot?) */ - else { - return 2; - } - - return 0; -} - From 2178bfad9ccb0cbeb79599dd1dc349dd4567aa49 Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:41 -0700 Subject: [PATCH 1095/1939] [PATCH] shpchp: remove redundant data structures State information is currently stored in per-slot as well as per-pci-function data structures in shpchp. There's a lot of overlap in the information kept, and some of it is never used. This patch consolidates the state information to per-slot and eliminates unused data structures. The biggest change is to eliminate the pci_func structure and the code around managing its lists. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 35 +-- drivers/pci/hotplug/shpchp_core.c | 20 -- drivers/pci/hotplug/shpchp_ctrl.c | 405 +++--------------------------- drivers/pci/hotplug/shpchp_pci.c | 27 +- 4 files changed, 63 insertions(+), 424 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 5e99260987e8..052c11f14a79 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -52,34 +52,18 @@ extern int shpchp_debug; #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) -struct pci_func { - struct pci_func *next; - u8 bus; - u8 device; - u8 function; - u8 is_a_board; - u16 status; - u8 configured; - u8 switch_save; - u8 presence_save; - u8 pwr_save; - struct pci_dev* pci_dev; -}; - #define SLOT_MAGIC 0x67267321 struct slot { u32 magic; struct slot *next; u8 bus; u8 device; + u16 status; u32 number; u8 is_a_board; - u8 configured; u8 state; - u8 switch_save; u8 presence_save; - u32 capabilities; - u16 reserved2; + u8 pwr_save; struct timer_list task_event; u8 hp_slot; struct controller *ctrl; @@ -106,19 +90,14 @@ struct controller { struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ u8 next_event; - u8 seg; u8 bus; u8 device; u8 function; - u8 rev; u8 slot_device_offset; u8 add_support; enum pci_bus_speed speed; u32 first_slot; /* First physical slot number */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 push_flag; - u16 ctlrcap; - u16 vendor_id; }; struct hotplug_params { @@ -169,13 +148,9 @@ struct hotplug_params { * error Messages */ #define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" -#define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" -#define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" #define msg_button_on "PCI slot #%d - powering on due to button press.\n" #define msg_button_off "PCI slot #%d - powering off due to button press.\n" #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" /* sysfs functions for the hotplug controller info */ extern void shpchp_create_ctrl_files (struct controller *ctrl); @@ -183,8 +158,6 @@ extern void shpchp_create_ctrl_files (struct controller *ctrl); /* controller functions */ extern int shpchp_event_start_thread(void); extern void shpchp_event_stop_thread(void); -extern struct pci_func *shpchp_slot_create(unsigned char busnumber); -extern struct pci_func *shpchp_slot_find(unsigned char bus, unsigned char device, unsigned char index); extern int shpchp_enable_slot(struct slot *slot); extern int shpchp_disable_slot(struct slot *slot); @@ -195,9 +168,8 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); /* pci functions */ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); extern int shpchp_configure_device(struct slot *p_slot); -extern int shpchp_unconfigure_device(struct pci_func* func); +extern int shpchp_unconfigure_device(struct slot *p_slot); extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); extern void get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp); @@ -207,7 +179,6 @@ extern int shpchprm_get_physical_slot_number(struct controller *ctrl, /* Global variables */ extern struct controller *shpchp_ctrl_list; -extern struct pci_func *shpchp_slot_list[256]; struct ctrl_reg { volatile u32 base_offset; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 5d4fc28969d0..b54edccbf2cc 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -45,7 +45,6 @@ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; struct controller *shpchp_ctrl_list; /* = NULL */ -struct pci_func *shpchp_slot_list[256]; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " @@ -475,7 +474,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int shpc_start_thread(void) { - int loop; int retval = 0; dbg("Initialize + Start the notification/polling mechanism \n"); @@ -486,20 +484,11 @@ static int shpc_start_thread(void) return retval; } - dbg("Initialize slot lists\n"); - /* One slot list for each bus in the system */ - for (loop = 0; loop < 256; loop++) { - shpchp_slot_list[loop] = NULL; - } - return retval; } static void __exit unload_shpchpd(void) { - struct pci_func *next; - struct pci_func *TempSlot; - int loop; struct controller *ctrl; struct controller *tctrl; @@ -519,15 +508,6 @@ static void __exit unload_shpchpd(void) kfree(tctrl); } - for (loop = 0; loop < 256; loop++) { - next = shpchp_slot_list[loop]; - while (next != NULL) { - TempSlot = next; - next = next->next; - kfree(TempSlot); - } - } - /* Stop the notification mechanism */ shpchp_event_stop_thread(); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index c55103f3cebd..b6fde3565e55 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -54,19 +54,16 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) struct slot *p_slot; u8 rc = 0; u8 getstatus; - struct pci_func *func; struct event_info *taskInfo; /* Attention Button Change */ dbg("shpchp: Attention button interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread what to do */ taskInfo = &(ctrl->event_queue[ctrl->next_event]); p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); ctrl->next_event = (ctrl->next_event + 1) % 10; @@ -111,14 +108,11 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) struct slot *p_slot; u8 rc = 0; u8 getstatus; - struct pci_func *func; struct event_info *taskInfo; /* Switch Change */ dbg("shpchp: Switch interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -128,19 +122,18 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) rc++; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); dbg("%s: Card present %x Power status %x\n", __FUNCTION__, - func->presence_save, func->pwr_save); + p_slot->presence_save, p_slot->pwr_save); if (getstatus) { /* * Switch opened */ info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; - if (func->pwr_save && func->presence_save) { + if (p_slot->pwr_save && p_slot->presence_save) { taskInfo->event_type = INT_POWER_FAULT; err("Surprise Removal of card\n"); } @@ -149,7 +142,6 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) * Switch closed */ info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0x10; taskInfo->event_type = INT_SWITCH_CLOSE; } @@ -165,14 +157,11 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) struct slot *p_slot; u8 rc = 0; /*u8 temp_byte;*/ - struct pci_func *func; struct event_info *taskInfo; /* Presence Change */ dbg("shpchp: Presence/Notify input change.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -186,8 +175,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) /* * Save the presence state */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - if (func->presence_save) { + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); + if (p_slot->presence_save) { /* * Card Present */ @@ -212,14 +201,11 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; - struct pci_func *func; struct event_info *taskInfo; /* Power fault */ dbg("shpchp: Power fault interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -235,7 +221,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) * Power fault Cleared */ info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->status = 0x00; + p_slot->status = 0x00; taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { /* @@ -244,7 +230,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); taskInfo->event_type = INT_POWER_FAULT; /* set power fault status for this board */ - func->status = 0xFF; + p_slot->status = 0xFF; info("power fault bit %x set\n", hp_slot); } if (rc) @@ -253,179 +239,6 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) return rc; } -/** - * shpchp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located - * - * Returns pointer to the new node or NULL if unsuccessful - */ -struct pci_func *shpchp_slot_create(u8 busnumber) -{ - struct pci_func *new_slot; - struct pci_func *next; - - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - - if (new_slot == NULL) { - return(new_slot); - } - - memset(new_slot, 0, sizeof(struct pci_func)); - - new_slot->next = NULL; - new_slot->configured = 1; - - if (shpchp_slot_list[busnumber] == NULL) { - shpchp_slot_list[busnumber] = new_slot; - } else { - next = shpchp_slot_list[busnumber]; - while (next->next != NULL) - next = next->next; - next->next = new_slot; - } - return(new_slot); -} - - -/* - * slot_remove - Removes a node from the linked list of slots. - * @old_slot: slot to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int slot_remove(struct pci_func * old_slot) -{ - struct pci_func *next; - - if (old_slot == NULL) - return(1); - - next = shpchp_slot_list[old_slot->bus]; - - if (next == NULL) { - return(1); - } - - if (next == old_slot) { - shpchp_slot_list[old_slot->bus] = old_slot->next; - kfree(old_slot); - return(0); - } - - while ((next->next != old_slot) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == old_slot) { - next->next = old_slot->next; - kfree(old_slot); - return(0); - } else - return(2); -} - - -/** - * bridge_slot_remove - Removes a node from the linked list of slots. - * @bridge: bridge to remove - * @secondaryBus: secondary PCI bus number for bridge being removed - * @subordinateBus: subordinate PCI bus number for bridge being removed - * - * Returns 0 if successful, !0 otherwise. - */ -static int bridge_slot_remove(struct pci_func *bridge, u8 secondaryBus, - u8 subordinateBus) -{ - u8 tempBus; - struct pci_func *next; - - if (bridge == NULL) - return(1); - - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { - next = shpchp_slot_list[tempBus]; - - while (!slot_remove(next)) { - next = shpchp_slot_list[tempBus]; - } - } - - next = shpchp_slot_list[bridge->bus]; - - if (next == NULL) { - return(1); - } - - if (next == bridge) { - shpchp_slot_list[bridge->bus] = bridge->next; - kfree(bridge); - return(0); - } - - while ((next->next != bridge) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == bridge) { - next->next = bridge->next; - kfree(bridge); - return(0); - } else - return(2); -} - - -/** - * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed - * @bus: bus to find - * @device: device to find - * @index: is 0 for first function found, 1 for the second... - * - * Returns pointer to the node if successful, %NULL otherwise. - */ -struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) -{ - int found = -1; - struct pci_func *func; - - func = shpchp_slot_list[bus]; - - if ((func == NULL) || ((func->device == device) && (index == 0))) - return(func); - - if (func->device == device) - found++; - - while (func->next != NULL) { - func = func->next; - - if (func->device == device) - found++; - - if (found == index) - return(func); - } - - return(NULL); -} - -static int is_bridge(struct pci_func *func, struct controller *ctrl) -{ - u8 hdr_type; - struct pci_bus *bus = ctrl->pci_dev->subordinate; - - /* - * Note: device may have just been hot-added and not yet scanned - * by the pci core, so its pci_dev structure may not exist yet - */ - pci_bus_read_config_byte(bus, PCI_DEVFN(func->device, func->function), - PCI_HEADER_TYPE, &hdr_type); - if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) - return 1; - else - return 0; -} - /* The following routines constitute the bulk of the hotplug controller logic */ @@ -495,19 +308,20 @@ enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) * Configures board * */ -static u32 board_added(struct pci_func * func, struct controller * ctrl) +static u32 board_added(struct slot *p_slot) { u8 hp_slot; u8 slots_not_empty = 0; u32 rc = 0; - struct slot *p_slot; enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; u8 pi, mode; + struct controller *ctrl = p_slot->ctrl; - p_slot = shpchp_find_slot(ctrl, func->device); - hp_slot = func->device - ctrl->slot_device_offset; + hp_slot = p_slot->device - ctrl->slot_device_offset; - dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", + __FUNCTION__, p_slot->device, + ctrl->slot_device_offset, hp_slot); /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); @@ -699,13 +513,13 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) wait_for_ctrl_irq (ctrl); dbg("%s: after long_delay\n", __FUNCTION__); - dbg("%s: func status = %x\n", __FUNCTION__, func->status); + dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); /* Check for a power fault */ - if (func->status == 0xFF) { + if (p_slot->status == 0xFF) { /* power fault occurred, but it was benign */ dbg("%s: power fault\n", __FUNCTION__); rc = POWER_FAILURE; - func->status = 0; + p_slot->status = 0; goto err_exit; } @@ -715,10 +529,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) goto err_exit; } - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - func->pwr_save = 1; + p_slot->status = 0; + p_slot->is_a_board = 0x01; + p_slot->pwr_save = 1; /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); @@ -767,38 +580,23 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) * remove_board - Turns off slot and LED's * */ -static u32 remove_board(struct pci_func *func, struct controller *ctrl) +static u32 remove_board(struct slot *p_slot) { - u8 device; + struct controller *ctrl = p_slot->ctrl; u8 hp_slot; u32 rc; - struct slot *p_slot; - u8 secondary = 0, subordinate = 0; - int remove_bridge; - if (func == NULL) + if (shpchp_unconfigure_device(p_slot)) return(1); - if ((remove_bridge = is_bridge(func, ctrl))) { - /* Stash away bus information before we destroy it */ - secondary = func->pci_dev->subordinate->secondary; - subordinate = func->pci_dev->subordinate->subordinate; - } - - if (shpchp_unconfigure_device(func)) - return(1); - - device = func->device; - - hp_slot = func->device - ctrl->slot_device_offset; + hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); /* Change status to shutdown */ - if (func->is_a_board) - func->status = 0x01; - func->configured = 0; + if (p_slot->is_a_board) + p_slot->status = 0x01; /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); @@ -835,36 +633,8 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) /* Done with exclusive hardware access */ up(&ctrl->crit_sect); - if (ctrl->add_support) { - while (func) { - if (remove_bridge) { - dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, - func->device, func->function); - bridge_slot_remove(func, secondary, - subordinate); - } else - dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, - func->device, func->function); - slot_remove(func); - - func = shpchp_slot_find(ctrl->slot_bus, device, 0); - } - - /* Setup slot structure with entry for empty slot */ - func = shpchp_slot_create(ctrl->slot_bus); - - if (func == NULL) { - return(1); - } - - func->bus = ctrl->slot_bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->switch_save = 0x10; - func->pwr_save = 0; - func->is_a_board = 0; - } + p_slot->pwr_save = 0; + p_slot->is_a_board = 0; return 0; } @@ -1006,7 +776,6 @@ static void interrupt_event_handler(struct controller *ctrl) { int loop = 0; int change = 1; - struct pci_func *func; u8 hp_slot; u8 getstatus; struct slot *p_slot; @@ -1021,11 +790,10 @@ static void interrupt_event_handler(struct controller *ctrl) ctrl->event_queue[loop].event_type); hp_slot = ctrl->event_queue[loop].hp_slot; - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot); + dbg("%s: hp_slot %d, p_slot %p\n", + __FUNCTION__, hp_slot, p_slot); if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { dbg("%s: button cancel\n", __FUNCTION__); @@ -1147,13 +915,6 @@ int shpchp_enable_slot (struct slot *p_slot) { u8 getstatus = 0; int rc; - struct pci_func *func; - - func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); - if (!func) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); - return -ENODEV; - } /* Check to see if (latch closed, card present, power off) */ down(&p_slot->ctrl->crit_sect); @@ -1177,75 +938,35 @@ int shpchp_enable_slot (struct slot *p_slot) } up(&p_slot->ctrl->crit_sect); - slot_remove(func); - - func = shpchp_slot_create(p_slot->bus); - if (func == NULL) - return -ENOMEM; - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; + p_slot->is_a_board = 1; /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save)); - dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); + p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); + dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; - rc = board_added(func, p_slot->ctrl); + rc = board_added(p_slot); if (rc) { - if (is_bridge(func, p_slot->ctrl)) { - u8 secondary = func->pci_dev->subordinate->secondary; - u8 subordinate = - func->pci_dev->subordinate->subordinate; - bridge_slot_remove(func, secondary, subordinate); - } else - slot_remove(func); - - /* Setup slot structure with entry for empty slot */ - func = shpchp_slot_create(p_slot->bus); - if (func == NULL) - return -ENOMEM; /* Out of memory */ - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, + &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; } - if (p_slot) - update_slot_info(p_slot); - + update_slot_info(p_slot); return rc; } int shpchp_disable_slot (struct slot *p_slot) { - u8 class_code, header_type, BCR; - u8 index = 0; u8 getstatus = 0; u32 rc = 0; int ret = 0; - unsigned int devfn; - struct pci_bus *pci_bus; - struct pci_func *func; if (!p_slot->ctrl) return -ENODEV; - pci_bus = p_slot->ctrl->pci_dev->subordinate; - /* Check to see if (latch closed, card present, power on) */ down(&p_slot->ctrl->crit_sect); @@ -1269,54 +990,8 @@ int shpchp_disable_slot (struct slot *p_slot) } up(&p_slot->ctrl->crit_sect); - func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); - - /* Make sure there are no video controllers here - * for all func of p_slot - */ - while (func && !rc) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check the Class Code */ - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (rc) - return -ENODEV; - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - /* Display/Video adapter (not supported) */ - rc = REMOVE_NOT_SUPPORTED; - } else { - /* See if it's a bridge */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if (rc) - return -ENODEV; - - /* If it's a bridge, check the VGA Enable bit */ - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); - if (rc) - return -ENODEV; - - /* If the VGA Enable bit is set, remove isn't supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { - rc = REMOVE_NOT_SUPPORTED; - } - } - } - - func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); - } - - func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); - if ((func != NULL) && !rc) { - rc = remove_board(func, p_slot->ctrl); - } else if (!rc) - rc = -ENODEV; - - if (p_slot) - update_slot_info(p_slot); - + rc = remove_board(p_slot); + update_slot_info(p_slot); return rc; } diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index f51a97d7611f..8f0a1667f2e6 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -148,20 +148,33 @@ int shpchp_configure_device(struct slot *p_slot) return 0; } -int shpchp_unconfigure_device(struct pci_func* func) +int shpchp_unconfigure_device(struct slot *p_slot) { int rc = 0; int j; + u8 bctl = 0; - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, - func->device, func->function); + dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, - (func->device << 3) | j); - if (temp) { - pci_remove_bus_device(temp); + struct pci_dev* temp = pci_find_slot(p_slot->bus, + (p_slot->device << 3) | j); + if (!temp) + continue; + if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + err("Cannot remove display device %s\n", + pci_name(temp)); + continue; } + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", + pci_name(temp)); + continue; + } + } + pci_remove_bus_device(temp); } return rc; } From ee138334d5eb5ca662b2d69228420c1ccc051e0e Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:42 -0700 Subject: [PATCH 1096/1939] [PATCH] shpchp: miscellaneous cleanups Remove un-necessary header includes, remove dead code, remove some type casts, receive function return in the correct data type... Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 14 +-- drivers/pci/hotplug/shpchp_core.c | 12 +-- drivers/pci/hotplug/shpchp_ctrl.c | 31 +++--- drivers/pci/hotplug/shpchp_hpc.c | 126 ++++++------------------- drivers/pci/hotplug/shpchp_pci.c | 4 - drivers/pci/hotplug/shpchp_sysfs.c | 3 - drivers/pci/hotplug/shpchprm_acpi.c | 6 -- drivers/pci/hotplug/shpchprm_legacy.c | 4 - drivers/pci/hotplug/shpchprm_nonacpi.c | 3 - 9 files changed, 46 insertions(+), 157 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 052c11f14a79..ade8ec145e1e 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include "pci_hotplug.h" #if !defined(MODULE) @@ -80,7 +78,7 @@ struct event_info { struct controller { struct controller *next; struct semaphore crit_sect; /* critical section semaphore */ - void * hpc_ctlr_handle; /* HPC controller handle */ + struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; @@ -234,7 +232,7 @@ enum ctrl_offsets { SLOT11 = offsetof(struct ctrl_reg, slot11), SLOT12 = offsetof(struct ctrl_reg, slot12), }; -typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); +typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); struct php_ctlr_state_s { struct php_ctlr_state_s *pnext; struct pci_dev *pci_dev; @@ -347,11 +345,7 @@ enum php_ctlr_type { ACPI }; -int shpc_init( struct controller *ctrl, struct pci_dev *pdev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback); +int shpc_init( struct controller *ctrl, struct pci_dev *pdev); int shpc_get_ctlr_slot_config( struct controller *ctrl, int *num_ctlr_slots, @@ -364,8 +358,6 @@ struct hpc_ops { int (*power_on_slot ) (struct slot *slot); int (*slot_enable ) (struct slot *slot); int (*slot_disable ) (struct slot *slot); - int (*enable_all_slots) (struct slot *slot); - int (*pwr_on_all_slots) (struct slot *slot); int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed); int (*get_power_status) (struct slot *slot, u8 *status); int (*get_attention_status) (struct slot *slot, u8 *status); diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index b54edccbf2cc..28ed2dc9388a 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -27,17 +27,11 @@ * */ -#include #include #include #include #include -#include -#include -#include #include -#include -#include #include "shpchp.h" /* Global variables */ @@ -381,11 +375,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dbg("DRV_thread pid = %d\n", current->pid); - rc = shpc_init(ctrl, pdev, - (php_intr_callback_t) shpchp_handle_attention_button, - (php_intr_callback_t) shpchp_handle_switch_change, - (php_intr_callback_t) shpchp_handle_presence_change, - (php_intr_callback_t) shpchp_handle_power_fault); + rc = shpc_init(ctrl, pdev); if (rc) { dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME); goto err_out_free_ctrl; diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index b6fde3565e55..8541180781e1 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -27,15 +27,9 @@ * */ -#include #include #include #include -#include -#include -#include -#include -#include #include #include #include "../pci.h" @@ -242,9 +236,10 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) /* The following routines constitute the bulk of the hotplug controller logic */ -static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) +static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, + enum pci_bus_speed speed) { - u32 rc = 0; + int rc = 0; dbg("%s: change to speed %d\n", __FUNCTION__, speed); down(&ctrl->crit_sect); @@ -266,10 +261,11 @@ static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum p return rc; } -static u32 fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, -enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) +static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, + u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, + enum pci_bus_speed msp) { - u32 rc = 0; + int rc = 0; if (flag != 0) { /* Other slots on the same bus are occupied */ if ( asp < bsp ) { @@ -308,11 +304,11 @@ enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) * Configures board * */ -static u32 board_added(struct slot *p_slot) +static int board_added(struct slot *p_slot) { u8 hp_slot; u8 slots_not_empty = 0; - u32 rc = 0; + int rc = 0; enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; u8 pi, mode; struct controller *ctrl = p_slot->ctrl; @@ -580,11 +576,11 @@ static u32 board_added(struct slot *p_slot) * remove_board - Turns off slot and LED's * */ -static u32 remove_board(struct slot *p_slot) +static int remove_board(struct slot *p_slot) { struct controller *ctrl = p_slot->ctrl; u8 hp_slot; - u32 rc; + int rc; if (shpchp_unconfigure_device(p_slot)) return(1); @@ -961,7 +957,6 @@ int shpchp_enable_slot (struct slot *p_slot) int shpchp_disable_slot (struct slot *p_slot) { u8 getstatus = 0; - u32 rc = 0; int ret = 0; if (!p_slot->ctrl) @@ -990,8 +985,8 @@ int shpchp_disable_slot (struct slot *p_slot) } up(&p_slot->ctrl->crit_sect); - rc = remove_board(p_slot); + ret = remove_board(p_slot); update_slot_info(p_slot); - return rc; + return ret; } diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index d55a9a7f8d2b..d46a47603386 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -27,17 +27,10 @@ * */ -#include #include #include #include -#include -#include -#include -#include -#include #include -#include #include "shpchp.h" #ifdef DEBUG @@ -282,7 +275,7 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u16 cmd_status; int retval = 0; u16 temp_word; @@ -328,7 +321,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) static int hpc_check_cmd_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u16 cmd_status; int retval = 0; @@ -368,7 +361,7 @@ static int hpc_check_cmd_status(struct controller *ctrl) static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 atten_led_state; @@ -408,7 +401,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) static int hpc_get_power_status(struct slot * slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 slot_state; @@ -450,7 +443,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; @@ -473,7 +466,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 card_state; @@ -496,7 +489,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -513,7 +506,7 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status, sec_bus_status; u8 m66_cap, pcix_cap, pi; @@ -594,7 +587,7 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u16 sec_bus_status; u8 pi; int retval = 0; @@ -623,7 +616,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) static int hpc_query_power_fault(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 pwr_fault_state, status; @@ -647,7 +640,7 @@ static int hpc_query_power_fault(struct slot * slot) static int hpc_set_attention_status(struct slot *slot, u8 value) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd = 0; int rc = 0; @@ -683,7 +676,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) static void hpc_set_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -705,7 +698,7 @@ static void hpc_set_green_led_on(struct slot *slot) static void hpc_set_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -727,7 +720,7 @@ static void hpc_set_green_led_off(struct slot *slot) static void hpc_set_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -754,7 +747,7 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, int *updown, /* physical_slot_num increament: 1 or -1 */ int *flags) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -776,7 +769,7 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, static void hpc_release_ctlr(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *p, *p_prev; DBG_ENTER_ROUTINE @@ -828,7 +821,7 @@ DBG_LEAVE_ROUTINE static int hpc_power_on_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -859,7 +852,7 @@ static int hpc_power_on_slot(struct slot * slot) static int hpc_slot_enable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -890,7 +883,7 @@ static int hpc_slot_enable(struct slot * slot) static int hpc_slot_disable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -920,51 +913,12 @@ static int hpc_slot_disable(struct slot * slot) return retval; } -static int hpc_enable_all_slots( struct slot *slot ) -{ - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL); - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - - DBG_LEAVE_ROUTINE - - return retval; -} - -static int hpc_pwr_on_all_slots(struct slot *slot) -{ - int retval = 0; - - DBG_ENTER_ROUTINE - - retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL); - - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - - DBG_LEAVE_ROUTINE - return retval; -} - static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) { u8 slot_cmd; u8 pi; int retval = 0; - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -1184,7 +1138,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; int retval = 0; u8 pi; @@ -1253,7 +1207,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; u16 sec_bus_status; int retval = 0; @@ -1367,8 +1321,6 @@ static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, - .enable_all_slots = hpc_enable_all_slots, - .pwr_on_all_slots = hpc_pwr_on_all_slots, .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, @@ -1391,12 +1343,7 @@ static struct hpc_ops shpchp_hpc_ops = { .check_cmd_status = hpc_check_cmd_status, }; -int shpc_init(struct controller * ctrl, - struct pci_dev * pdev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback) +int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; void *instance_id = ctrl; @@ -1405,7 +1352,6 @@ int shpc_init(struct controller * ctrl, static int first = 1; u32 shpc_cap_offset, shpc_base_offset; u32 tempdword, slot_reg; - u16 vendor_id, device_id; u8 i; DBG_ENTER_ROUTINE @@ -1422,21 +1368,8 @@ int shpc_init(struct controller * ctrl, php_ctlr->pci_dev = pdev; /* save pci_dev in context */ - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id); - if (rc) { - err("%s: unable to read PCI configuration data\n", __FUNCTION__); - goto abort_free_ctlr; - } - - rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); - dbg("%s: Device ID: %x\n",__FUNCTION__, device_id); - if (rc) { - err("%s: unable to read PCI configuration data\n", __FUNCTION__); - goto abort_free_ctlr; - } - - if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) { + if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == + PCI_DEVICE_ID_AMD_GOLAM_7450)) { shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ } else { if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { @@ -1514,11 +1447,10 @@ int shpc_init(struct controller * ctrl, php_ctlr->irq = pdev->irq; dbg("HPC interrupt = %d\n", php_ctlr->irq); - /* Save interrupt callback info */ - php_ctlr->attention_button_callback = attention_button_callback; - php_ctlr->switch_change_callback = switch_change_callback; - php_ctlr->presence_change_callback = presence_change_callback; - php_ctlr->power_fault_callback = power_fault_callback; + php_ctlr->attention_button_callback = shpchp_handle_attention_button, + php_ctlr->switch_change_callback = shpchp_handle_switch_change; + php_ctlr->presence_change_callback = shpchp_handle_presence_change; + php_ctlr->power_fault_callback = shpchp_handle_power_fault; php_ctlr->callback_instance_id = instance_id; /* Return PCI Controller Info */ diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 8f0a1667f2e6..b8e95acea3b6 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -27,13 +27,9 @@ * */ -#include #include #include #include -#include -#include -#include #include #include "../pci.h" #include "shpchp.h" diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index ce41719a88f7..807ef66899c7 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -26,12 +26,9 @@ * */ -#include #include #include #include -#include -#include #include #include "shpchp.h" diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 3be518c7d47a..17145e52223a 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -24,16 +24,10 @@ * */ -#include #include #include #include #include -#include -#include -#include -#include -#include #include #include #include diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index cfc6092e2afd..ed6c1254bf6f 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c @@ -27,15 +27,11 @@ * */ -#include #include #include #include #include -#include -#include #include "shpchp.h" -#include "shpchprm.h" int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index f36c188c23eb..d70fe5408417 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c @@ -32,10 +32,7 @@ #include #include #include -#include -#include #include "shpchp.h" -#include "shpchprm.h" int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { From 7c8942f993dc069db0e0327a343bbec8a6e96074 Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:43 -0700 Subject: [PATCH 1097/1939] [PATCH] shpchp: reduce debug message verbosity Reduce the number of debug messages generated if shpchp debug is enabled. I tried to restrict this to removing debug messages that are either early-driver-debug type messages, or print information that can be inferred through other debug prints. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 6 ---- drivers/pci/hotplug/shpchp_core.c | 8 ------ drivers/pci/hotplug/shpchp_ctrl.c | 11 -------- drivers/pci/hotplug/shpchp_hpc.c | 47 +++++-------------------------- 4 files changed, 7 insertions(+), 65 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index ade8ec145e1e..dae1543a4e28 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -293,12 +293,9 @@ static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device) p_slot = ctrl->slot; - dbg("p_slot = %p\n", p_slot); - while (p_slot && (p_slot->device != device)) { tmp_slot = p_slot; p_slot = p_slot->next; - dbg("In while loop, p_slot = %p\n", p_slot); } if (p_slot == NULL) { err("ERROR: shpchp_find_slot device=0x%x\n", device); @@ -313,8 +310,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) DECLARE_WAITQUEUE(wait, current); int retval = 0; - dbg("%s : start\n",__FUNCTION__); - add_wait_queue(&ctrl->queue, &wait); if (!shpchp_poll_mode) { @@ -328,7 +323,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) if (signal_pending(current)) retval = -EINTR; - dbg("%s : end\n", __FUNCTION__); return retval; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 28ed2dc9388a..6a2b4a0193aa 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -105,8 +105,6 @@ static int init_slots(struct controller *ctrl) u32 slot_number, sun; int result = -ENOMEM; - dbg("%s\n",__FUNCTION__); - number_of_slots = ctrl->num_slots; slot_device = ctrl->slot_device_offset; slot_number = ctrl->first_slot; @@ -373,15 +371,12 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } memset(ctrl, 0, sizeof(struct controller)); - dbg("DRV_thread pid = %d\n", current->pid); - rc = shpc_init(ctrl, pdev); if (rc) { dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME); goto err_out_free_ctrl; } - dbg("%s: controller initialization success\n", __FUNCTION__); ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ pci_set_drvdata(pdev, ctrl); @@ -488,8 +483,6 @@ static void __exit unload_shpchpd(void) cleanup_slots(ctrl); kfree (ctrl->pci_bus); - - dbg("%s: calling release_ctlr\n", __FUNCTION__); ctrl->hpc_ops->release_ctlr(ctrl); tctrl = ctrl; @@ -558,7 +551,6 @@ static void __exit shpcd_cleanup(void) dbg("unload_shpchpd()\n"); unload_shpchpd(); - dbg("pci_unregister_driver\n"); pci_unregister_driver(&shpc_driver); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 8541180781e1..58619359ad08 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -505,9 +505,7 @@ static int board_added(struct slot *p_slot) up(&ctrl->crit_sect); /* Wait for ~1 second */ - dbg("%s: before long_delay\n", __FUNCTION__); wait_for_ctrl_irq (ctrl); - dbg("%s: after long_delay\n", __FUNCTION__); dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); /* Check for a power fault */ @@ -666,13 +664,11 @@ static void shpchp_pushbutton_thread (unsigned long slot) p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = POWEROFF_STATE; - dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); shpchp_disable_slot(p_slot); p_slot->state = STATIC_STATE; } else { p_slot->state = POWERON_STATE; - dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); if (shpchp_enable_slot(p_slot)) { /* Wait for exclusive access to hardware */ @@ -734,7 +730,6 @@ int shpchp_event_start_thread (void) err ("Can't start up our event thread\n"); return -1; } - dbg("Our event thread pid = %d\n", pid); return 0; } @@ -742,9 +737,7 @@ int shpchp_event_start_thread (void) void shpchp_event_stop_thread (void) { event_finished = 1; - dbg("event_thread finish command given\n"); up(&event_semaphore); - dbg("wait for event_thread to exit\n"); down(&event_exit); } @@ -776,7 +769,6 @@ static void interrupt_event_handler(struct controller *ctrl) u8 getstatus; struct slot *p_slot; - dbg("%s:\n", __FUNCTION__); while (change) { change = 0; @@ -788,9 +780,6 @@ static void interrupt_event_handler(struct controller *ctrl) p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - dbg("%s: hp_slot %d, p_slot %p\n", - __FUNCTION__, hp_slot, p_slot); - if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { dbg("%s: button cancel\n", __FUNCTION__); del_timer(&p_slot->task_event); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index d46a47603386..40905a6c8094 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -313,7 +313,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) * command. */ writew(temp_word, php_ctlr->creg + CMD); - dbg("%s: temp_word written %x\n", __FUNCTION__, temp_word); DBG_LEAVE_ROUTINE return retval; @@ -789,10 +788,8 @@ static void hpc_release_ctlr(struct controller *ctrl) } } if (php_ctlr->pci_dev) { - dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); iounmap(php_ctlr->creg); release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); - dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); php_ctlr->pci_dev = NULL; } @@ -1043,18 +1040,13 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (!intr_loc) return IRQ_NONE; - dbg("%s: shpc_isr proceeds\n", __FUNCTION__); dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); if(!shpchp_poll_mode) { /* Mask Global Interrupt Mask - see implementation note on p. 139 */ /* of SHPC spec rev 1.0*/ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: Before masking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword |= 0x00000001; - dbg("%s: After masking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); intr_loc2 = readl(php_ctlr->creg + INTR_LOC); @@ -1068,11 +1060,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) * Detect bit in Controller SERR-INT register */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: Before clearing CCIP, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffeffff; - dbg("%s: After clearing CCIP, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); wake_up_interruptible(&ctrl->queue); } @@ -1080,11 +1068,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if ((intr_loc = (intr_loc >> 1)) == 0) { /* Unmask Global Interrupt Mask */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffffffe; - dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); return IRQ_NONE; @@ -1094,11 +1078,9 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* To find out which slot has interrupt pending */ if ((intr_loc >> hp_slot) & 0x01) { temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); - dbg("%s: Slot %x with intr, temp_dword = %x\n", - __FUNCTION__, hp_slot, temp_dword); + dbg("%s: Slot %x with intr, slot register = %x\n", + __FUNCTION__, hp_slot, temp_dword); temp_byte = (temp_dword >> 16) & 0xFF; - dbg("%s: Slot with intr, temp_byte = %x\n", - __FUNCTION__, temp_byte); if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) schedule_flag += php_ctlr->switch_change_callback( hp_slot, php_ctlr->callback_instance_id); @@ -1114,8 +1096,6 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all slot events */ temp_dword = 0xe01f3fff; - dbg("%s: Clearing slot events, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); intr_loc2 = readl(php_ctlr->creg + INTR_LOC); @@ -1125,11 +1105,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffffffe; - dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); } @@ -1402,7 +1378,8 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) err("%s : pci_read_config_dword failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword); + dbg("%s: offset %d: value %x\n", __FUNCTION__,i, + tempdword); } } @@ -1411,13 +1388,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) first = 0; } - dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc, - pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); @@ -1437,7 +1407,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) goto abort_free_ctlr; } dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); - dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0)); init_MUTEX(&ctrl->crit_sect); /* Setup wait queue */ @@ -1445,8 +1414,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* Find the IRQ */ php_ctlr->irq = pdev->irq; - dbg("HPC interrupt = %d\n", php_ctlr->irq); - php_ctlr->attention_button_callback = shpchp_handle_attention_button, php_ctlr->switch_change_callback = shpchp_handle_switch_change; php_ctlr->presence_change_callback = shpchp_handle_presence_change; @@ -1488,7 +1455,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) if (rc) { info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); - dbg("%s: rc = %x\n", __FUNCTION__, rc); } else php_ctlr->irq = pdev->irq; @@ -1499,8 +1465,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) goto abort_free_ctlr; } } + dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); get_hp_hw_control_from_firmware(pdev); - dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); /* Add this HPC instance into the HPC list */ spin_lock(&list_lock); @@ -1539,7 +1507,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); } - dbg("%s: Leaving shpc_init\n", __FUNCTION__); DBG_LEAVE_ROUTINE return 0; From c2608a111b621d5cf0e4c2876d79e67333ce5341 Mon Sep 17 00:00:00 2001 From: "rajesh.shah@intel.com" Date: Thu, 13 Oct 2005 12:05:44 -0700 Subject: [PATCH 1098/1939] [PATCH] shpchp: fix oops at driver unload At unload time, the shpchp driver does not remove sysfs files it had created in the driver's probe entry point. This patch fixes this problem. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 1 + drivers/pci/hotplug/shpchp_core.c | 1 + drivers/pci/hotplug/shpchp_sysfs.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index dae1543a4e28..abe2cf411e68 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -173,6 +173,7 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp); extern int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); +extern void shpchp_remove_ctrl_files(struct controller *ctrl); /* Global variables */ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 6a2b4a0193aa..63628e01dd43 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -480,6 +480,7 @@ static void __exit unload_shpchpd(void) ctrl = shpchp_ctrl_list; while (ctrl) { + shpchp_remove_ctrl_files(ctrl); cleanup_slots(ctrl); kfree (ctrl->pci_bus); diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index 807ef66899c7..f5cfbf2c047c 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -89,3 +89,8 @@ void shpchp_create_ctrl_files (struct controller *ctrl) { device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); } + +void shpchp_remove_ctrl_files(struct controller *ctrl) +{ + device_remove_file(&ctrl->pci_dev->dev, &dev_attr_ctrl); +} From d10211b278c70fbebb83fb9e4ee717ca13f69b2d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 15 Oct 2005 22:02:19 -0700 Subject: [PATCH 1099/1939] [PATCH] PCI: fix edac drivers for radisys 82600 borkage I told you that the pci_ids.h cleanup was a bad idea ;) Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 11fed60a928d..611e48a4e679 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1610,6 +1610,7 @@ #define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 +#define PCI_VENDOR_ID_RADISYS 0x1331 #define PCI_VENDOR_ID_DOMEX 0x134a #define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 From a1720fdbd0f90e64668a59a304d01c5ba001b450 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Oct 2005 21:31:36 +0100 Subject: [PATCH 1100/1939] [PATCH] PCI: Fixup PCI driver shutdown Add a warning to pci driver registration code so that we know whether we have drivers using the obsolete driver shutdown method. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 0d0d533894e0..f906f1a8fe6a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -377,6 +377,10 @@ int pci_register_driver(struct pci_driver *drv) * the pci shutdown function, this test can go away. */ if (!drv->driver.shutdown) drv->driver.shutdown = pci_device_shutdown; + else + printk(KERN_WARNING "Warning: PCI driver %s has a struct " + "device_driver shutdown method, please update!\n", + drv->name); drv->driver.owner = drv->owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; From 5457b6a6013516a73b8f48ec1adb9984b577a5c1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Oct 2005 21:32:46 +0100 Subject: [PATCH 1101/1939] [PATCH] PCI: Convert megaraid to use pci_driver shutdown method Convert megaraid to use pci_driver's shutdown method rather than the generic device_driver shutdown method. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_mbox.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index d47be8e0ea3a..c9e743ba09ec 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -76,7 +76,7 @@ static void megaraid_exit(void); static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); static void megaraid_detach_one(struct pci_dev *); -static void megaraid_mbox_shutdown(struct device *); +static void megaraid_mbox_shutdown(struct pci_dev *); static int megaraid_io_attach(adapter_t *); static void megaraid_io_detach(adapter_t *); @@ -369,9 +369,7 @@ static struct pci_driver megaraid_pci_driver_g = { .id_table = pci_id_table_g, .probe = megaraid_probe_one, .remove = __devexit_p(megaraid_detach_one), - .driver = { - .shutdown = megaraid_mbox_shutdown, - } + .shutdown = megaraid_mbox_shutdown, }; @@ -673,9 +671,9 @@ megaraid_detach_one(struct pci_dev *pdev) * Shutdown notification, perform flush cache */ static void -megaraid_mbox_shutdown(struct device *device) +megaraid_mbox_shutdown(struct pci_dev *pdev) { - adapter_t *adapter = pci_get_drvdata(to_pci_dev(device)); + adapter_t *adapter = pci_get_drvdata(pdev); static int counter; if (!adapter) { From 8e5dce35221850759671b2847a2e51030f7626bd Mon Sep 17 00:00:00 2001 From: Kristen Accardi Date: Tue, 18 Oct 2005 17:21:40 -0700 Subject: [PATCH 1102/1939] [PATCH] acpiphp: allocate resources for adapters with bridges Allocate resources for adapters with bridges on them. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 424e7de181ae..8e21f6ab89a1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -58,6 +58,9 @@ static LIST_HEAD(bridge_list); static void handle_hotplug_event_bridge (acpi_handle, u32, void *); static void handle_hotplug_event_func (acpi_handle, u32, void *); +static void acpiphp_sanitize_bus(struct pci_bus *bus); +static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); + /* * initialization & terminatation routines @@ -796,8 +799,13 @@ static int enable_device(struct acpiphp_slot *slot) } } + pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); + acpiphp_sanitize_bus(bus); + pci_enable_bridges(bus); pci_bus_add_devices(bus); + acpiphp_set_hpp_values(DEVICE_ACPI_HANDLE(&bus->self->dev), bus); + acpiphp_configure_ioapics(DEVICE_ACPI_HANDLE(&bus->self->dev)); /* associate pci_dev to our representation */ list_for_each (l, &slot->funcs) { From f05aab8ef653abcbd454739264a9f5cf63f6f9f8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 23 Oct 2005 11:58:19 -0700 Subject: [PATCH 1103/1939] [PATCH] kernel-doc: fix PCI hotplug PCI hotplug.c: does not contain kernel-doc, so don't process it for now. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/kernel-api.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index d650ce36485f..4d9b66d8b4db 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -286,7 +286,9 @@ X!Edrivers/pci/search.c --> !Edrivers/pci/msi.c !Edrivers/pci/bus.c -!Edrivers/pci/hotplug.c + !Edrivers/pci/probe.c !Edrivers/pci/rom.c From 8f7020d36374dda9366fee1343f8eacfe8f5e641 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 23 Oct 2005 11:57:38 -0700 Subject: [PATCH 1104/1939] [PATCH] kernel-doc: PCI fixes PCI: add descriptions for missing function parameters. Eliminate all kernel-doc warnings here. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 2 ++ drivers/pci/pci-driver.c | 13 +++++++++---- drivers/pci/pci.c | 7 ++++--- drivers/pci/probe.c | 1 + 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ee8677bda950..a2033552423c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -575,6 +575,8 @@ static int msi_capability_init(struct pci_dev *dev) /** * msix_capability_init - configure device's MSI-X capability * @dev: pointer to the pci_dev data structure of MSI-X device function + * @entries: pointer to an array of struct msix_entry entries + * @nvec: number of @entries * * Setup the MSI-X capability structure of device function with a * single MSI-X vector. A return of zero indicates the successful setup of diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f906f1a8fe6a..8972e6a3aac0 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -26,7 +26,10 @@ struct pci_dynid { #ifdef CONFIG_HOTPLUG /** - * store_new_id + * store_new_id - add a new PCI device ID to this driver and re-probe devices + * @driver: target device driver + * @buf: buffer for scanning device ID data + * @count: input size * * Adds a new dynamic pci device ID to this driver, * and causes the driver to probe for all devices again. @@ -194,8 +197,10 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, /** * __pci_device_probe() + * @drv: driver to call to check if it wants the PCI device + * @pci_dev: PCI device being probed * - * returns 0 on success, else error. + * returns 0 on success, else error. * side-effect: pci_dev->driver is set to drv when drv claims pci_dev. */ static int @@ -440,11 +445,11 @@ pci_dev_driver(const struct pci_dev *dev) /** * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure - * @ids: array of PCI device id structures to search in * @dev: the PCI device structure to match against + * @drv: the device driver to search for matching PCI device id structures * * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices.Returns the matching + * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no match. */ static int pci_bus_match(struct device *dev, struct device_driver *drv) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 39bdb938521d..61b855c99e39 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -252,6 +252,8 @@ pci_restore_bars(struct pci_dev *dev) pci_update_resource(dev, &dev->resource[i], i); } +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); + /** * pci_set_power_state - Set the power state of a PCI device * @dev: PCI device to be suspended @@ -266,7 +268,6 @@ pci_restore_bars(struct pci_dev *dev) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ -int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -808,8 +809,8 @@ pci_clear_mwi(struct pci_dev *dev) /** * pci_intx - enables/disables PCI INTx for device dev - * @dev: the PCI device to operate on - * @enable: boolean + * @pdev: the PCI device to operate on + * @enable: boolean: whether to enable or disable PCI INTx * * Enables/disables PCI INTx for device dev */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 005786416bb5..fce2cb2112d8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -669,6 +669,7 @@ static void pci_release_dev(struct device *dev) /** * pci_cfg_space_size - get the configuration space size of the PCI device. + * @dev: PCI device * * Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices * have 4096 bytes. Even if the device is capable, that doesn't mean we can From 2f028234f2c7f31dc0ff0784e20f14be11f7035c Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 20 Oct 2005 09:55:32 +1000 Subject: [PATCH 1105/1939] [PATCH] pci_ids: cleanup comments pci_ids.h cleanup: convert // comment to /* comment */ Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_ids.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 611e48a4e679..7d300f7469e3 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -444,7 +444,7 @@ #define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251 #define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252 -#define PCI_VENDOR_ID_COMPEX2 0x101a // pci.ids says "AT&T GIS (NCR)" +#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */ #define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 #define PCI_VENDOR_ID_WD 0x101c @@ -1158,10 +1158,10 @@ #define PCI_VENDOR_ID_INIT 0x1101 -#define PCI_VENDOR_ID_CREATIVE 0x1102 // duplicate: ECTIVA +#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 -#define PCI_VENDOR_ID_ECTIVA 0x1102 // duplicate: CREATIVE +#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ #define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 #define PCI_VENDOR_ID_TTI 0x1103 @@ -1171,7 +1171,7 @@ #define PCI_DEVICE_ID_TTI_HPT302 0x0006 #define PCI_DEVICE_ID_TTI_HPT371 0x0007 #define PCI_DEVICE_ID_TTI_HPT374 0x0008 -#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 // apparently a 372N variant? +#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */ #define PCI_VENDOR_ID_VIA 0x1106 #define PCI_DEVICE_ID_VIA_8763_0 0x0198 From f8977d0a9b7ac84cfe700278a2ca64cb33c93a13 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 25 Oct 2005 10:28:42 -0700 Subject: [PATCH 1106/1939] [PATCH] PCI fixup for Toshiba laptops and ohci1394 This is a fix for a bug I see on my Toshiba laptop, where the ohci1394 controller gets initialized improperly. The patch adds two PCI fixups to arch/i386/pci/fixup.c, one that happens early on to cache the value of the PCI_CACHE_LINE_SIZE config register, and another that later restores the value, along with a valid IRQ number and some BAR values. I've tested it on my laptop, and it prevents me from running into what I consider to be a major bug: IRQ 11 is disabled by the IRQ debug code, causing my wireless to break. Thanks to Rob for the original patch to ohci1394.c and Stefan for lots of proofreading (and a last minute bug caught in review!) and additional information collection. I think the DMI system list is correct, but we may need to add some more PCI IDs to the PCI_FIXUP macros over time. Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- arch/i386/pci/fixup.c | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index 8e8e895e1b5a..330fd2b68075 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -2,6 +2,8 @@ * Exceptions for specific devices. Usually work-arounds for fatal design flaws. */ +#include +#include #include #include #include "pci.h" @@ -384,3 +386,60 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) } } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); + +/* + * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. + * + * We pretend to bring them out of full D3 state, and restore the proper + * IRQ, PCI cache line size, and BARs, otherwise the device won't function + * properly. In some cases, the device will generate an interrupt on + * the wrong IRQ line, causing any devices sharing the the line it's + * *supposed* to use to be disabled by the kernel's IRQ debug code. + */ +static u16 toshiba_line_size; + +static struct dmi_system_id __devinit toshiba_ohci1394_dmi_table[] = { + { + .ident = "Toshiba PS5 based laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "PS5"), + }, + }, + { + .ident = "Toshiba PSM4 based laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"), + }, + }, + { } +}; + +static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) +{ + if (!dmi_check_system(toshiba_ohci1394_dmi_table)) + return; /* only applies to certain Toshibas (so far) */ + + dev->current_state = PCI_D3cold; + pci_read_config_word(dev, PCI_CACHE_LINE_SIZE, &toshiba_line_size); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032, + pci_pre_fixup_toshiba_ohci1394); + +static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) +{ + if (!dmi_check_system(toshiba_ohci1394_dmi_table)) + return; /* only applies to certain Toshibas (so far) */ + + /* Restore config space on Toshiba laptops */ + mdelay(10); + pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size); + pci_write_config_word(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + pci_resource_start(dev, 0)); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, + pci_resource_start(dev, 1)); +} +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032, + pci_post_fixup_toshiba_ohci1394); From a74968f8c3b1166cfe0942901b56165f06ab6f60 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Oct 2005 15:37:23 -0700 Subject: [PATCH 1107/1939] [IB] umad: Fix device lifetime problems Move ib_umad module to using cdev_alloc() and class_device_create() so that we can handle device lifetime properly. Now we can make sure we keep all of our data structures around until the last way to reach them is gone. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 272 +++++++++++++++++------------ 1 file changed, 161 insertions(+), 111 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 17ec0a19dbc0..9e49816d7282 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -64,18 +64,39 @@ enum { IB_UMAD_MINOR_BASE = 0 }; -struct ib_umad_port { - int devnum; - struct cdev dev; - struct class_device class_dev; +/* + * Our lifetime rules for these structs are the following: each time a + * device special file is opened, we look up the corresponding struct + * ib_umad_port by minor in the umad_port[] table while holding the + * port_lock. If this lookup succeeds, we take a reference on the + * ib_umad_port's struct ib_umad_device while still holding the + * port_lock; if the lookup fails, we fail the open(). We drop these + * references in the corresponding close(). + * + * In addition to references coming from open character devices, there + * is one more reference to each ib_umad_device representing the + * module's reference taken when allocating the ib_umad_device in + * ib_umad_add_one(). + * + * When destroying an ib_umad_device, we clear all of its + * ib_umad_ports from umad_port[] while holding port_lock before + * dropping the module's reference to the ib_umad_device. This is + * always safe because any open() calls will either succeed and obtain + * a reference before we clear the umad_port[] entries, or fail after + * we clear the umad_port[] entries. + */ - int sm_devnum; - struct cdev sm_dev; - struct class_device sm_class_dev; +struct ib_umad_port { + struct cdev *dev; + struct class_device *class_dev; + + struct cdev *sm_dev; + struct class_device *sm_class_dev; struct semaphore sm_sem; struct ib_device *ib_dev; struct ib_umad_device *umad_dev; + int dev_num; u8 port_num; }; @@ -102,13 +123,25 @@ struct ib_umad_packet { struct ib_user_mad mad; }; +static struct class *umad_class; + static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); -static spinlock_t map_lock; + +static DEFINE_SPINLOCK(port_lock); +static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS]; static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2); static void ib_umad_add_one(struct ib_device *device); static void ib_umad_remove_one(struct ib_device *device); +static void ib_umad_release_dev(struct kref *ref) +{ + struct ib_umad_device *dev = + container_of(ref, struct ib_umad_device, ref); + + kfree(dev); +} + static int queue_packet(struct ib_umad_file *file, struct ib_mad_agent *agent, struct ib_umad_packet *packet) @@ -534,13 +567,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, static int ib_umad_open(struct inode *inode, struct file *filp) { - struct ib_umad_port *port = - container_of(inode->i_cdev, struct ib_umad_port, dev); + struct ib_umad_port *port; struct ib_umad_file *file; + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); + + if (!port) + return -ENXIO; + file = kzalloc(sizeof *file, GFP_KERNEL); - if (!file) + if (!file) { + kref_put(&port->umad_dev->ref, ib_umad_release_dev); return -ENOMEM; + } spin_lock_init(&file->recv_lock); init_rwsem(&file->agent_mutex); @@ -556,6 +599,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) static int ib_umad_close(struct inode *inode, struct file *filp) { struct ib_umad_file *file = filp->private_data; + struct ib_umad_device *dev = file->port->umad_dev; struct ib_umad_packet *packet, *tmp; int i; @@ -570,6 +614,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp) kfree(file); + kref_put(&dev->ref, ib_umad_release_dev); + return 0; } @@ -586,30 +632,46 @@ static struct file_operations umad_fops = { static int ib_umad_sm_open(struct inode *inode, struct file *filp) { - struct ib_umad_port *port = - container_of(inode->i_cdev, struct ib_umad_port, sm_dev); + struct ib_umad_port *port; struct ib_port_modify props = { .set_port_cap_mask = IB_PORT_SM }; int ret; + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); + + if (!port) + return -ENXIO; + if (filp->f_flags & O_NONBLOCK) { - if (down_trylock(&port->sm_sem)) - return -EAGAIN; + if (down_trylock(&port->sm_sem)) { + ret = -EAGAIN; + goto fail; + } } else { - if (down_interruptible(&port->sm_sem)) - return -ERESTARTSYS; + if (down_interruptible(&port->sm_sem)) { + ret = -ERESTARTSYS; + goto fail; + } } ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); if (ret) { up(&port->sm_sem); - return ret; + goto fail; } filp->private_data = port; return 0; + +fail: + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return ret; } static int ib_umad_sm_close(struct inode *inode, struct file *filp) @@ -623,6 +685,8 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); up(&port->sm_sem); + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return ret; } @@ -642,6 +706,9 @@ static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { struct ib_umad_port *port = class_get_devdata(class_dev); + if (!port) + return -ENODEV; + return sprintf(buf, "%s\n", port->ib_dev->name); } static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); @@ -650,38 +717,13 @@ static ssize_t show_port(struct class_device *class_dev, char *buf) { struct ib_umad_port *port = class_get_devdata(class_dev); + if (!port) + return -ENODEV; + return sprintf(buf, "%d\n", port->port_num); } static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); -static void ib_umad_release_dev(struct kref *ref) -{ - struct ib_umad_device *dev = - container_of(ref, struct ib_umad_device, ref); - - kfree(dev); -} - -static void ib_umad_release_port(struct class_device *class_dev) -{ - struct ib_umad_port *port = class_get_devdata(class_dev); - - if (class_dev == &port->class_dev) { - cdev_del(&port->dev); - clear_bit(port->devnum, dev_map); - } else { - cdev_del(&port->sm_dev); - clear_bit(port->sm_devnum, dev_map); - } - - kref_put(&port->umad_dev->ref, ib_umad_release_dev); -} - -static struct class umad_class = { - .name = "infiniband_mad", - .release = ib_umad_release_port -}; - static ssize_t show_abi_version(struct class *class, char *buf) { return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); @@ -691,89 +733,102 @@ static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static int ib_umad_init_port(struct ib_device *device, int port_num, struct ib_umad_port *port) { - spin_lock(&map_lock); - port->devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); - if (port->devnum >= IB_UMAD_MAX_PORTS) { - spin_unlock(&map_lock); + spin_lock(&port_lock); + port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); + if (port->dev_num >= IB_UMAD_MAX_PORTS) { + spin_unlock(&port_lock); return -1; } - port->sm_devnum = find_next_zero_bit(dev_map, IB_UMAD_MAX_PORTS * 2, IB_UMAD_MAX_PORTS); - if (port->sm_devnum >= IB_UMAD_MAX_PORTS * 2) { - spin_unlock(&map_lock); - return -1; - } - set_bit(port->devnum, dev_map); - set_bit(port->sm_devnum, dev_map); - spin_unlock(&map_lock); + set_bit(port->dev_num, dev_map); + spin_unlock(&port_lock); port->ib_dev = device; port->port_num = port_num; init_MUTEX(&port->sm_sem); - cdev_init(&port->dev, &umad_fops); - port->dev.owner = THIS_MODULE; - kobject_set_name(&port->dev.kobj, "umad%d", port->devnum); - if (cdev_add(&port->dev, base_dev + port->devnum, 1)) + port->dev = cdev_alloc(); + if (!port->dev) return -1; - - port->class_dev.class = &umad_class; - port->class_dev.dev = device->dma_device; - port->class_dev.devt = port->dev.dev; - - snprintf(port->class_dev.class_id, BUS_ID_SIZE, "umad%d", port->devnum); - - if (class_device_register(&port->class_dev)) + port->dev->owner = THIS_MODULE; + port->dev->ops = &umad_fops; + kobject_set_name(&port->dev->kobj, "umad%d", port->dev_num); + if (cdev_add(port->dev, base_dev + port->dev_num, 1)) goto err_cdev; - class_set_devdata(&port->class_dev, port); - kref_get(&port->umad_dev->ref); + port->class_dev = class_device_create(umad_class, port->dev->dev, + device->dma_device, + "umad%d", port->dev_num); + if (IS_ERR(port->class_dev)) + goto err_cdev; - if (class_device_create_file(&port->class_dev, &class_device_attr_ibdev)) + if (class_device_create_file(port->class_dev, &class_device_attr_ibdev)) goto err_class; - if (class_device_create_file(&port->class_dev, &class_device_attr_port)) + if (class_device_create_file(port->class_dev, &class_device_attr_port)) goto err_class; - cdev_init(&port->sm_dev, &umad_sm_fops); - port->sm_dev.owner = THIS_MODULE; - kobject_set_name(&port->dev.kobj, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); - if (cdev_add(&port->sm_dev, base_dev + port->sm_devnum, 1)) - return -1; - - port->sm_class_dev.class = &umad_class; - port->sm_class_dev.dev = device->dma_device; - port->sm_class_dev.devt = port->sm_dev.dev; - - snprintf(port->sm_class_dev.class_id, BUS_ID_SIZE, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); - - if (class_device_register(&port->sm_class_dev)) + port->sm_dev = cdev_alloc(); + if (!port->sm_dev) + goto err_class; + port->sm_dev->owner = THIS_MODULE; + port->sm_dev->ops = &umad_sm_fops; + kobject_set_name(&port->dev->kobj, "issm%d", port->dev_num); + if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) goto err_sm_cdev; - class_set_devdata(&port->sm_class_dev, port); - kref_get(&port->umad_dev->ref); + port->sm_class_dev = class_device_create(umad_class, port->sm_dev->dev, + device->dma_device, + "issm%d", port->dev_num); + if (IS_ERR(port->sm_class_dev)) + goto err_sm_cdev; - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_ibdev)) + class_set_devdata(port->class_dev, port); + class_set_devdata(port->sm_class_dev, port); + + if (class_device_create_file(port->sm_class_dev, &class_device_attr_ibdev)) goto err_sm_class; - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_port)) + if (class_device_create_file(port->sm_class_dev, &class_device_attr_port)) goto err_sm_class; + spin_lock(&port_lock); + umad_port[port->dev_num] = port; + spin_unlock(&port_lock); + return 0; err_sm_class: - class_device_unregister(&port->sm_class_dev); + class_device_destroy(umad_class, port->sm_dev->dev); err_sm_cdev: - cdev_del(&port->sm_dev); + cdev_del(port->sm_dev); err_class: - class_device_unregister(&port->class_dev); + class_device_destroy(umad_class, port->dev->dev); err_cdev: - cdev_del(&port->dev); - clear_bit(port->devnum, dev_map); + cdev_del(port->dev); + clear_bit(port->dev_num, dev_map); return -1; } +static void ib_umad_kill_port(struct ib_umad_port *port) +{ + class_set_devdata(port->class_dev, NULL); + class_set_devdata(port->sm_class_dev, NULL); + + class_device_destroy(umad_class, port->dev->dev); + class_device_destroy(umad_class, port->sm_dev->dev); + + cdev_del(port->dev); + cdev_del(port->sm_dev); + + spin_lock(&port_lock); + umad_port[port->dev_num] = NULL; + spin_unlock(&port_lock); + + clear_bit(port->dev_num, dev_map); +} + static void ib_umad_add_one(struct ib_device *device) { struct ib_umad_device *umad_dev; @@ -809,10 +864,8 @@ static void ib_umad_add_one(struct ib_device *device) return; err: - while (--i >= s) { - class_device_unregister(&umad_dev->port[i - s].class_dev); - class_device_unregister(&umad_dev->port[i - s].sm_class_dev); - } + while (--i >= s) + ib_umad_kill_port(&umad_dev->port[i]); kref_put(&umad_dev->ref, ib_umad_release_dev); } @@ -825,10 +878,8 @@ static void ib_umad_remove_one(struct ib_device *device) if (!umad_dev) return; - for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) { - class_device_unregister(&umad_dev->port[i].class_dev); - class_device_unregister(&umad_dev->port[i].sm_class_dev); - } + for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) + ib_umad_kill_port(&umad_dev->port[i]); kref_put(&umad_dev->ref, ib_umad_release_dev); } @@ -837,8 +888,6 @@ static int __init ib_umad_init(void) { int ret; - spin_lock_init(&map_lock); - ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, "infiniband_mad"); if (ret) { @@ -846,13 +895,14 @@ static int __init ib_umad_init(void) goto out; } - ret = class_register(&umad_class); - if (ret) { + umad_class = class_create(THIS_MODULE, "infiniband_mad"); + if (IS_ERR(umad_class)) { + ret = PTR_ERR(umad_class); printk(KERN_ERR "user_mad: couldn't create class infiniband_mad\n"); goto out_chrdev; } - ret = class_create_file(&umad_class, &class_attr_abi_version); + ret = class_create_file(umad_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); goto out_class; @@ -867,7 +917,7 @@ static int __init ib_umad_init(void) return 0; out_class: - class_unregister(&umad_class); + class_destroy(umad_class); out_chrdev: unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); @@ -879,7 +929,7 @@ static int __init ib_umad_init(void) static void __exit ib_umad_cleanup(void) { ib_unregister_client(&umad_client); - class_unregister(&umad_class); + class_destroy(umad_class); unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); } From 70a30e16a8a9d22396a4d1e96af86e43594df584 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Oct 2005 15:38:26 -0700 Subject: [PATCH 1108/1939] [IB] uverbs: Fix device lifetime problems Move ib_uverbs module to using cdev_alloc() and class_device_create() so that we can handle device lifetime properly. Now we can make sure we keep all of our data structures around until the last way to reach them is gone. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 36 ++++- drivers/infiniband/core/uverbs_cmd.c | 38 +---- drivers/infiniband/core/uverbs_main.c | 205 +++++++++++++++++++------- 3 files changed, 183 insertions(+), 96 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 63c8085c0c98..031cdf3c066d 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -39,20 +39,38 @@ #ifndef UVERBS_H #define UVERBS_H -/* Include device.h and fs.h until cdev.h is self-sufficient */ -#include -#include -#include #include #include #include #include +/* + * Our lifetime rules for these structs are the following: + * + * struct ib_uverbs_device: One reference is held by the module and + * released in ib_uverbs_remove_one(). Another reference is taken by + * ib_uverbs_open() each time the character special file is opened, + * and released in ib_uverbs_release_file() when the file is released. + * + * struct ib_uverbs_file: One reference is held by the VFS and + * released when the file is closed. Another reference is taken when + * an asynchronous event queue file is created and released when the + * event file is closed. + * + * struct ib_uverbs_event_file: One reference is held by the VFS and + * released when the file is closed. For asynchronous event files, + * another reference is held by the corresponding main context file + * and released when that file is closed. For completion event files, + * a reference is taken when a CQ is created that uses the file, and + * released when the CQ is destroyed. + */ + struct ib_uverbs_device { + struct kref ref; int devnum; - struct cdev dev; - struct class_device class_dev; + struct cdev *dev; + struct class_device *class_dev; struct ib_device *ib_dev; int num_comp_vectors; }; @@ -115,6 +133,12 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, void ib_uverbs_release_event_file(struct kref *ref); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj); +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj); + void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 14583bb6e2c0..8c89abc8c764 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -35,6 +35,7 @@ */ #include +#include #include @@ -114,7 +115,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, kref_get(&file->async_file->ref); kref_get(&file->ref); - file->ucontext = ucontext; + file->ucontext = ucontext; fd_install(resp.async_fd, filp); @@ -761,7 +762,6 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, struct ib_cq *cq; struct ib_ucq_object *uobj; struct ib_uverbs_event_file *ev_file; - struct ib_uverbs_event *evt, *tmp; u64 user_handle; int ret = -EINVAL; @@ -790,23 +790,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - if (ev_file) { - spin_lock_irq(&ev_file->lock); - list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&ev_file->lock); - - kref_put(&ev_file->ref, ib_uverbs_release_event_file); - } - - spin_lock_irq(&file->async_file->lock); - list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file->lock); + ib_uverbs_release_ucq(file, ev_file, uobj); resp.comp_events_reported = uobj->comp_events_reported; resp.async_events_reported = uobj->async_events_reported; @@ -1043,7 +1027,6 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, struct ib_uverbs_destroy_qp_resp resp; struct ib_qp *qp; struct ib_uevent_object *uobj; - struct ib_uverbs_event *evt, *tmp; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1069,12 +1052,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file->lock); - list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file->lock); + ib_uverbs_release_uevent(file, uobj); resp.events_reported = uobj->events_reported; @@ -1741,7 +1719,6 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, struct ib_uverbs_destroy_srq_resp resp; struct ib_srq *srq; struct ib_uevent_object *uobj; - struct ib_uverbs_event *evt, *tmp; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1767,12 +1744,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file->lock); - list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file->lock); + ib_uverbs_release_uevent(file, uobj); resp.events_reported = uobj->events_reported; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 251c752a7ae6..ac08d2c93ea1 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -63,6 +64,8 @@ enum { #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) +static struct class *uverbs_class; + DECLARE_MUTEX(ib_uverbs_idr_mutex); DEFINE_IDR(ib_uverbs_pd_idr); DEFINE_IDR(ib_uverbs_mr_idr); @@ -73,6 +76,7 @@ DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); static spinlock_t map_lock; +static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, @@ -110,7 +114,54 @@ static struct vfsmount *uverbs_event_mnt; static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); -static int ib_dealloc_ucontext(struct ib_ucontext *context) +static void ib_uverbs_release_dev(struct kref *ref) +{ + struct ib_uverbs_device *dev = + container_of(ref, struct ib_uverbs_device, ref); + + kfree(dev); +} + +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + if (ev_file) { + spin_lock_irq(&ev_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&ev_file->lock); + + kref_put(&ev_file->ref, ib_uverbs_release_event_file); + } + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, + struct ib_ucontext *context) { struct ib_uobject *uobj, *tmp; @@ -129,26 +180,36 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); + struct ib_uevent_object *uevent = + container_of(uobj, struct ib_uevent_object, uobject); idr_remove(&ib_uverbs_qp_idr, uobj->id); ib_destroy_qp(qp); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_uevent_object, uobject)); + ib_uverbs_release_uevent(file, uevent); + kfree(uevent); } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); + struct ib_uverbs_event_file *ev_file = cq->cq_context; + struct ib_ucq_object *ucq = + container_of(uobj, struct ib_ucq_object, uobject); idr_remove(&ib_uverbs_cq_idr, uobj->id); ib_destroy_cq(cq); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_ucq_object, uobject)); + ib_uverbs_release_ucq(file, ev_file, ucq); + kfree(ucq); } list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); + struct ib_uevent_object *uevent = + container_of(uobj, struct ib_uevent_object, uobject); idr_remove(&ib_uverbs_srq_idr, uobj->id); ib_destroy_srq(srq); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_uevent_object, uobject)); + ib_uverbs_release_uevent(file, uevent); + kfree(uevent); } /* XXX Free MWs */ @@ -187,6 +248,8 @@ static void ib_uverbs_release_file(struct kref *ref) container_of(ref, struct ib_uverbs_file, ref); module_put(file->device->ib_dev->owner); + kref_put(&file->device->ref, ib_uverbs_release_dev); + kfree(file); } @@ -552,36 +615,58 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) static int ib_uverbs_open(struct inode *inode, struct file *filp) { - struct ib_uverbs_device *dev = - container_of(inode->i_cdev, struct ib_uverbs_device, dev); + struct ib_uverbs_device *dev; struct ib_uverbs_file *file; + int ret; - if (!try_module_get(dev->ib_dev->owner)) - return -ENODEV; + spin_lock(&map_lock); + dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR]; + if (dev) + kref_get(&dev->ref); + spin_unlock(&map_lock); + + if (!dev) + return -ENXIO; + + if (!try_module_get(dev->ib_dev->owner)) { + ret = -ENODEV; + goto err; + } file = kmalloc(sizeof *file, GFP_KERNEL); if (!file) { - module_put(dev->ib_dev->owner); - return -ENOMEM; + ret = -ENOMEM; + goto err_module; } - file->device = dev; - file->ucontext = NULL; + file->device = dev; + file->ucontext = NULL; + file->async_file = NULL; kref_init(&file->ref); init_MUTEX(&file->mutex); filp->private_data = file; return 0; + +err_module: + module_put(dev->ib_dev->owner); + +err: + kref_put(&dev->ref, ib_uverbs_release_dev); + + return ret; } static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; - ib_dealloc_ucontext(file->ucontext); + ib_uverbs_cleanup_ucontext(file, file->ucontext); + + if (file->async_file) + kref_put(&file->async_file->ref, ib_uverbs_release_event_file); - kref_put(&file->async_file->ref, ib_uverbs_release_event_file); kref_put(&file->ref, ib_uverbs_release_file); return 0; @@ -610,8 +695,10 @@ static struct ib_client uverbs_client = { static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { - struct ib_uverbs_device *dev = - container_of(class_dev, struct ib_uverbs_device, class_dev); + struct ib_uverbs_device *dev = class_get_devdata(class_dev); + + if (!dev) + return -ENODEV; return sprintf(buf, "%s\n", dev->ib_dev->name); } @@ -619,28 +706,15 @@ static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); static ssize_t show_dev_abi_version(struct class_device *class_dev, char *buf) { - struct ib_uverbs_device *dev = - container_of(class_dev, struct ib_uverbs_device, class_dev); + struct ib_uverbs_device *dev = class_get_devdata(class_dev); + + if (!dev) + return -ENODEV; return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); } static CLASS_DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); -static void ib_uverbs_release_class_dev(struct class_device *class_dev) -{ - struct ib_uverbs_device *dev = - container_of(class_dev, struct ib_uverbs_device, class_dev); - - cdev_del(&dev->dev); - clear_bit(dev->devnum, dev_map); - kfree(dev); -} - -static struct class uverbs_class = { - .name = "infiniband_verbs", - .release = ib_uverbs_release_class_dev -}; - static ssize_t show_abi_version(struct class *class, char *buf) { return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); @@ -660,6 +734,8 @@ static void ib_uverbs_add_one(struct ib_device *device) memset(uverbs_dev, 0, sizeof *uverbs_dev); + kref_init(&uverbs_dev->ref); + spin_lock(&map_lock); uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { @@ -672,40 +748,45 @@ static void ib_uverbs_add_one(struct ib_device *device) uverbs_dev->ib_dev = device; uverbs_dev->num_comp_vectors = 1; - if (device->mmap) - cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); - else - cdev_init(&uverbs_dev->dev, &uverbs_fops); - uverbs_dev->dev.owner = THIS_MODULE; - kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + uverbs_dev->dev = cdev_alloc(); + if (!uverbs_dev->dev) goto err; - - uverbs_dev->class_dev.class = &uverbs_class; - uverbs_dev->class_dev.dev = device->dma_device; - uverbs_dev->class_dev.devt = uverbs_dev->dev.dev; - snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum); - if (class_device_register(&uverbs_dev->class_dev)) + uverbs_dev->dev->owner = THIS_MODULE; + uverbs_dev->dev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + kobject_set_name(&uverbs_dev->dev->kobj, "uverbs%d", uverbs_dev->devnum); + if (cdev_add(uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) goto err_cdev; - if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) + uverbs_dev->class_dev = class_device_create(uverbs_class, uverbs_dev->dev->dev, + device->dma_device, + "uverbs%d", uverbs_dev->devnum); + if (IS_ERR(uverbs_dev->class_dev)) + goto err_cdev; + + class_set_devdata(uverbs_dev->class_dev, uverbs_dev); + + if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_ibdev)) goto err_class; - if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_abi_version)) + if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_abi_version)) goto err_class; + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = uverbs_dev; + spin_unlock(&map_lock); + ib_set_client_data(device, &uverbs_client, uverbs_dev); return; err_class: - class_device_unregister(&uverbs_dev->class_dev); + class_device_destroy(uverbs_class, uverbs_dev->dev->dev); err_cdev: - cdev_del(&uverbs_dev->dev); + cdev_del(uverbs_dev->dev); clear_bit(uverbs_dev->devnum, dev_map); err: - kfree(uverbs_dev); + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); return; } @@ -716,7 +797,16 @@ static void ib_uverbs_remove_one(struct ib_device *device) if (!uverbs_dev) return; - class_device_unregister(&uverbs_dev->class_dev); + class_set_devdata(uverbs_dev->class_dev, NULL); + class_device_destroy(uverbs_class, uverbs_dev->dev->dev); + cdev_del(uverbs_dev->dev); + + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = NULL; + spin_unlock(&map_lock); + + clear_bit(uverbs_dev->devnum, dev_map); + 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, @@ -746,13 +836,14 @@ static int __init ib_uverbs_init(void) goto out; } - ret = class_register(&uverbs_class); - if (ret) { + uverbs_class = class_create(THIS_MODULE, "infiniband_verbs"); + if (IS_ERR(uverbs_class)) { + ret = PTR_ERR(uverbs_class); printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); goto out_chrdev; } - ret = class_create_file(&uverbs_class, &class_attr_abi_version); + ret = class_create_file(uverbs_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); goto out_class; @@ -786,7 +877,7 @@ static int __init ib_uverbs_init(void) unregister_filesystem(&uverbs_event_fs); out_class: - class_unregister(&uverbs_class); + class_destroy(uverbs_class); out_chrdev: unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); @@ -800,7 +891,7 @@ static void __exit ib_uverbs_cleanup(void) ib_unregister_client(&uverbs_client); mntput(uverbs_event_mnt); unregister_filesystem(&uverbs_event_fs); - class_unregister(&uverbs_class); + class_destroy(uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); idr_destroy(&ib_uverbs_pd_idr); idr_destroy(&ib_uverbs_mr_idr); From 64a0c1c81e300f0f56f26604c81040784e3717f0 Mon Sep 17 00:00:00 2001 From: Ivan Skytte Jorgensen Date: Fri, 28 Oct 2005 15:39:02 -0700 Subject: [PATCH 1109/1939] [SCTP] Do not allow unprivileged programs initiating new associations on privileged ports. Signed-off-by: Ivan Skytte Jorgensen Signed-off-by: Sridhar Samudrala --- net/sctp/socket.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 97b556c1c450..b529af5e6f2a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1010,6 +1010,19 @@ static int __sctp_connect(struct sock* sk, err = -EAGAIN; goto out_free; } + } else { + /* + * If an unprivileged user inherits a 1-many + * style socket with open associations on a + * privileged port, it MAY be permitted to + * accept new associations, but it SHOULD NOT + * be permitted to open new associations. + */ + if (ep->base.bind_addr.port < PROT_SOCK && + !capable(CAP_NET_BIND_SERVICE)) { + err = -EACCES; + goto out_free; + } } scope = sctp_scope(&to); @@ -1515,6 +1528,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, err = -EAGAIN; goto out_unlock; } + } else { + /* + * If an unprivileged user inherits a one-to-many + * style socket with open associations on a privileged + * port, it MAY be permitted to accept new associations, + * but it SHOULD NOT be permitted to open new + * associations. + */ + if (ep->base.bind_addr.port < PROT_SOCK && + !capable(CAP_NET_BIND_SERVICE)) { + err = -EACCES; + goto out_unlock; + } } scope = sctp_scope(&to); From 0e1f60609258e18ec0a0477c646101212822d387 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 28 Oct 2005 15:52:13 -0700 Subject: [PATCH 1110/1939] [IA64] fix warning unused variable `g' 4ac0068f44f192f2de95a7bb36df3e19767a45fb forgot to delete the declaration of this variable which is no longer used. Signed-off-by: Tony Luck --- arch/ia64/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 9a9c1bd01dbc..4b19d0410632 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -587,7 +587,7 @@ thread_matches (struct task_struct *thread, unsigned long addr) static struct task_struct * find_thread_for_addr (struct task_struct *child, unsigned long addr) { - struct task_struct *g, *p; + struct task_struct *p; struct mm_struct *mm; struct list_head *this, *next; int mm_users; From b6a1d5f88473138497d8694ddf174e8e91300068 Mon Sep 17 00:00:00 2001 From: "Martin J. Bligh" Date: Fri, 28 Oct 2005 15:14:44 -0700 Subject: [PATCH 1111/1939] [PATCH] e1000: remove warning about e1000_suspend e1000_suspend is only used under #ifdef CONFIG_PM. Move the declaration of it to be the same way, just like e1000_resume, otherwise gcc whines on compile. I offer as evidence: static struct pci_driver e1000_driver = { .name = e1000_driver_name, .id_table = e1000_pci_tbl, .probe = e1000_probe, .remove = __devexit_p(e1000_remove), /* Power Managment Hooks */ #ifdef CONFIG_PM .suspend = e1000_suspend, .resume = e1000_resume #endif }; Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 6b72f6acdd54..a0023f357cb1 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4193,6 +4193,7 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) return 0; } +#ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -4289,7 +4290,6 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev) { From a1bfcd97414d3e9b3c96f27d9b1a1e76c9543ba6 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Fri, 28 Oct 2005 15:14:46 -0700 Subject: [PATCH 1112/1939] [PATCH] eepro.c: module_param_array cleanup num_params is unused (and unusable in this form). Signed-off-by: Florin Malita Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/eepro.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index dcb3028bb60f..1ce2c675b8a7 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1797,10 +1797,9 @@ MODULE_AUTHOR("Pascal Dupuis and others"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); MODULE_LICENSE("GPL"); -static int num_params; -module_param_array(io, int, &num_params, 0); -module_param_array(irq, int, &num_params, 0); -module_param_array(mem, int, &num_params, 0); +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(mem, int, NULL, 0); module_param(autodetect, int, 0); MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)"); MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); From 46e178535836dcd7ef92f179218628d101892c59 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 28 Oct 2005 15:14:47 -0700 Subject: [PATCH 1113/1939] [PATCH] b44: fix suspend/resume Fix suspend/resume on b44 by freeing/reacquiring irq. Otherwise it hangs on resume. Signed-off-by: Pavel Machek Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 5485e3b1cd35..0ee3e27969c6 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2041,6 +2041,8 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); + + free_irq(dev->irq, dev); pci_disable_device(pdev); return 0; } @@ -2057,6 +2059,9 @@ static int b44_resume(struct pci_dev *pdev) if (!netif_running(dev)) return 0; + if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev)) + printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); + spin_lock_irq(&bp->lock); b44_init_rings(bp); From a7ec15da65ab64c5f97beedc4ff21cf3e0ae71c0 Mon Sep 17 00:00:00 2001 From: Ravikiran G Thirumalai Date: Fri, 28 Oct 2005 15:14:49 -0700 Subject: [PATCH 1114/1939] [PATCH] e1000: use vmalloc_node() Allocate node local tx and rx descriptors for the e1000 driver Signed-off-by: Ravikiran Thirumalai Cc: Christoph Lameter Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a0023f357cb1..d97ad89f5dd2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1149,7 +1149,8 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, int size; size = sizeof(struct e1000_buffer) * txdr->count; - txdr->buffer_info = vmalloc(size); + + txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); if(!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit descriptor ring\n"); @@ -1366,7 +1367,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = vmalloc(size); + rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); From 63f57fb69b017230c77c40f1713e40885ae6d159 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 28 Oct 2005 15:14:51 -0700 Subject: [PATCH 1115/1939] [PATCH] revert "orinoco: Information leakage due to incorrect padding" Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/wireless/orinoco.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index d3d4ec9e242e..70a3477a2061 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -490,7 +490,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - /* Check packet length, pad short packets, round up odd length */ + /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); skb = skb_padto(skb, len); if (skb == NULL) @@ -547,7 +548,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) p = skb->data; } - err = hermes_bap_pwrite(hw, USER_BAP, p, data_len, + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), txfid, data_off); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", From 2c36ed22c6f64de94c6c3b7258dd7285bb093401 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 28 Oct 2005 15:14:52 -0700 Subject: [PATCH 1116/1939] [PATCH] Better fixup for the orinoco driver The latest kernel added a pretty ugly fix for the orinoco etherleak bug which contains bogus skb->len checks already done by the caller and causes copies of all odd sized frames (which are quite common) While the skb->len check should be ripped out the other fix is harder to do properly so I'm proposing for this the -mm tree only until next 2.6.x so that it gets tested. Instead of copying buffers around blindly this code implements a padding aware version of the hermes buffer writing function which does padding as the buffer is loaded and thus more cleanly and without bogus 1.5K copies. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/wireless/hermes.c | 38 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/hermes.h | 2 ++ drivers/net/wireless/orinoco.c | 11 ++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index eba0d9d2b7c5..579480dad374 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -444,6 +444,43 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, return err; } +/* Write a block of data to the chip's buffer with padding if + * neccessary, via the BAP. Synchronization/serialization is the + * caller's problem. len must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len < 0 || len % 2 || data_len > len) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Transfer all the complete words of data */ + hermes_write_words(hw, dreg, buf, data_len/2); + /* If there is an odd byte left over pad and transfer it */ + if (data_len & 1) { + u8 end[2]; + end[1] = 0; + end[0] = ((unsigned char *)buf)[data_len - 1]; + hermes_write_words(hw, dreg, end, 1); + data_len ++; + } + /* Now send zeros for the padding */ + if (data_len < len) + hermes_clear_words(hw, dreg, (len - data_len) / 2); + /* Complete */ + out: + return err; +} + /* Read a Length-Type-Value record from the card. * * If length is NULL, we ignore the length read from the card, and @@ -531,6 +568,7 @@ EXPORT_SYMBOL(hermes_allocate); EXPORT_SYMBOL(hermes_bap_pread); EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_bap_pwrite_pad); EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index ad28e3294360..a6bd472d75d4 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -376,6 +376,8 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, u16 id, u16 offset); int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset); +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, + unsigned data_len, unsigned len, u16 id, u16 offset); int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 70a3477a2061..488ab06fb79f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -542,14 +542,21 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_errors++; goto fail; } + /* Actual xfer length - allow for padding */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN - ETH_HLEN) + len = ETH_ZLEN - ETH_HLEN; } else { /* IEEE 802.3 frame */ data_len = len + ETH_HLEN; data_off = HERMES_802_3_OFFSET; p = skb->data; + /* Actual xfer length - round up for odd length packets */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN) + len = ETH_ZLEN; } - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), + err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, txfid, data_off); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", From 977e74b5f60de3df9831897b726c16870878eee4 Mon Sep 17 00:00:00 2001 From: Ashutosh Naik Date: Fri, 28 Oct 2005 15:14:53 -0700 Subject: [PATCH 1117/1939] [PATCH] e1000: Fixes e1000_suspend warning when CONFIG_PM is not enabled drivers/net/e1000/e1000_main.c:3645: warning: `e1000_suspend' defined but not used Signed-off-by: Ashutosh Naik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d97ad89f5dd2..efbbda7cbcbf 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -191,8 +191,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); -static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); #ifdef CONFIG_PM +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); static int e1000_resume(struct pci_dev *pdev); #endif From 4cce3390c998600f6648e075e475cf8f6dd8cebe Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Oct 2005 16:38:15 -0700 Subject: [PATCH 1118/1939] [IB] fix up class_device_create() calls Fix class_device_create() calls to match the new prototype which takes a parent device pointer. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 4 ++-- drivers/infiniband/core/uverbs_main.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 9e49816d7282..97128e25f78b 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -755,7 +755,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (cdev_add(port->dev, base_dev + port->dev_num, 1)) goto err_cdev; - port->class_dev = class_device_create(umad_class, port->dev->dev, + port->class_dev = class_device_create(umad_class, NULL, port->dev->dev, device->dma_device, "umad%d", port->dev_num); if (IS_ERR(port->class_dev)) @@ -775,7 +775,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) goto err_sm_cdev; - port->sm_class_dev = class_device_create(umad_class, port->sm_dev->dev, + port->sm_class_dev = class_device_create(umad_class, NULL, port->sm_dev->dev, device->dma_device, "issm%d", port->dev_num); if (IS_ERR(port->sm_class_dev)) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index ac08d2c93ea1..0eb38f479b39 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -757,7 +757,8 @@ static void ib_uverbs_add_one(struct ib_device *device) if (cdev_add(uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) goto err_cdev; - uverbs_dev->class_dev = class_device_create(uverbs_class, uverbs_dev->dev->dev, + uverbs_dev->class_dev = class_device_create(uverbs_class, NULL, + uverbs_dev->dev->dev, device->dma_device, "uverbs%d", uverbs_dev->devnum); if (IS_ERR(uverbs_dev->class_dev)) From 72f30b6f2f5f68dd426e9fe83817b882c2d04e50 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 27 Sep 2005 10:19:39 -0700 Subject: [PATCH 1119/1939] [PATCH] USB: ehci.patch (earlier irq disable) This tweaks the EHCI reboot notifier to also halt the EHCI controller, and makes that halt code force IRQs off. Both should always have been done. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/host/ehci-hcd.c | 8 ++++++++ 1 file changed, 8 insertions(+) --- drivers/usb/host/ehci-hcd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index f5eb9e7b5b18..b3eb02613bff 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -182,6 +182,9 @@ static int ehci_halt (struct ehci_hcd *ehci) { u32 temp = readl (&ehci->regs->status); + /* disable any irqs left enabled by previous code */ + writel (0, &ehci->regs->intr_enable); + if ((temp & STS_HALT) != 0) return 0; @@ -335,12 +338,17 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) #endif +/* Reboot notifiers kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. + */ static int ehci_reboot (struct notifier_block *self, unsigned long code, void *null) { struct ehci_hcd *ehci; ehci = container_of (self, struct ehci_hcd, reboot_notifier); + (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ writel (0, &ehci->regs->configured_flag); From c9c7746dd333c12f482af2f1e63ea7eafc7cd529 Mon Sep 17 00:00:00 2001 From: Rui Santos Date: Fri, 23 Sep 2005 20:06:50 +0100 Subject: [PATCH 1120/1939] [PATCH] USB: ftdi: Artemis and ATIK based USB astronomical CCD cameras This patch enables direct kernel support for the Artemis and ATIK astronomical based USB CCD cameras. Since all communications with this camera are done via an FTDI 245BM chip, it was only needed to specify the ProductID and VendorID of all three devices. In what tests are concerned, data was transfered from and to the FTDI at the chips Top speed (360KB/s). Signed-off-by: Rui Santos Signed-off-by: Greg Kroah-Hartman drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio.h | 13 +++++++++++++ 2 files changed, 16 insertions(+) --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio.h | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5a8631c8a4a7..8c12a0acf10d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -471,6 +471,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 2c35d74cc6d6..7c65d46c7598 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -198,6 +198,19 @@ /* an infrared receiver for user access control with IR tags */ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ +/* + * Definitions for Artemis astronomical USB based cameras + * Check it at http://www.artemisccd.co.uk/ + */ +#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ + +/* + * Definitions for ATIK Instruments astronomical USB based cameras + * Check it at http://www.atik-instruments.com/ + */ +#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Camera */ +#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Camera */ + /* * Protego product ids */ From 8da608caa07d5c9745ec86bf7c25ad423352f9a4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1121/1939] [PATCH] USB: disable tasklet if rtl8150 device is removed while active. This fixes a oops seen in the wild. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/rtl8150.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index c3d4e3589e30..787dd3591d6a 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -909,6 +909,7 @@ static void rtl8150_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (dev) { set_bit(RTL8150_UNPLUG, &dev->flags); + tasklet_disable(&dev->tl); unregister_netdev(dev->netdev); unlink_all_urbs(dev); free_all_urbs(dev); From 094f1649577dfc7f2c7407a8380e05a506b31f7f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1122/1939] [PATCH] USB: add endpoint information to sysfs This patch adds endpoint information for both devices and interfaces to sysfs. Previously it was only possible to get the endpoint information from usbfs, and never possible to get any information on endpoint 0. Signed-off-by: Greg Kroah-Hartman drivers/usb/core/sysfs.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++- include/linux/usb.h | 4 2 files changed, 197 insertions(+), 2 deletions(-) --- drivers/usb/core/sysfs.c | 195 ++++++++++++++++++++++++++++++++++++++- include/linux/usb.h | 4 + 2 files changed, 197 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 00297f113849..eae413bf8c2a 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -22,6 +22,174 @@ #include "usb.h" +/* endpoint stuff */ +struct endpoint_attribute { + struct device_attribute dev_attr; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev; +}; +#define to_endpoint_attr(_dev_attr) \ + container_of(_dev_attr, struct endpoint_attribute, dev_attr) + +#define usb_ep_attr(field, format_string) \ +static ssize_t show_ep_##field(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); \ + \ + return sprintf(buf, format_string, endpoint_attr->endpoint->field); \ +} +usb_ep_attr(bLength, "%02x\n") +usb_ep_attr(bDescriptorType, "%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 device *dev, + struct device_attribute *attr, char *buf) +{ + struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); + + return sprintf(buf, "%04x\n", + le16_to_cpu(endpoint_attr->endpoint->wMaxPacketSize) & 0x07ff); +} + +static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); + char *type = "unknown"; + + switch (endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + type = "Control"; + break; + case USB_ENDPOINT_XFER_ISOC: + type = "Isoc"; + break; + case USB_ENDPOINT_XFER_BULK: + type = "Bulk"; + break; + case USB_ENDPOINT_XFER_INT: + type = "Interrupt"; + break; + } + return sprintf(buf, "%s\n", type); +} + +static ssize_t show_ep_interval(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); + struct usb_device *udev = endpoint_attr->udev; + struct usb_endpoint_descriptor *endpoint = endpoint_attr->endpoint; + char unit; + unsigned interval = 0; + unsigned in; + + in = (endpoint->bEndpointAddress & USB_DIR_IN); + + switch (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ + interval = endpoint->bInterval; + break; + case USB_ENDPOINT_XFER_ISOC: + interval = 1 << (endpoint->bInterval - 1); + break; + case USB_ENDPOINT_XFER_BULK: + if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + interval = endpoint->bInterval; + break; + case USB_ENDPOINT_XFER_INT: + if (udev->speed == USB_SPEED_HIGH) { + interval = 1 << (endpoint->bInterval - 1); + } else + interval = endpoint->bInterval; + break; + } + interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; + if (interval % 1000) + unit = 'u'; + else { + unit = 'm'; + interval /= 1000; + } + + return sprintf(buf, "%d%cs\n", interval, unit); +} + +static ssize_t show_ep_direction(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); + char *direction; + + if ((endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) + direction = "both"; + else if (endpoint_attr->endpoint->bEndpointAddress & USB_DIR_IN) + direction = "in"; + else + direction = "out"; + return sprintf(buf, "%s\n", direction); +} + +static struct endpoint_attribute *create_ep_attr(struct usb_endpoint_descriptor *endpoint, + struct usb_device *udev, char *name, + ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf)) +{ + struct endpoint_attribute *ep_attr; + + ep_attr = kzalloc(sizeof(*ep_attr), GFP_KERNEL); + if (ep_attr) { + ep_attr->endpoint = endpoint; + ep_attr->udev = udev; + ep_attr->dev_attr.attr.name = name; + ep_attr->dev_attr.attr.mode = 0444; + ep_attr->dev_attr.attr.owner = THIS_MODULE; + ep_attr->dev_attr.show = show; + } + return ep_attr; +} + +static void usb_create_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint, struct usb_device *udev) +{ + struct usb_endpoint_descriptor *ep; + + ep = &endpoint->desc; + + endpoint->attrs = kzalloc(sizeof(struct attribute *) * 10, GFP_KERNEL); + endpoint->attrs[0] = &(create_ep_attr(ep, udev, "direction", show_ep_direction)->dev_attr.attr); + endpoint->attrs[1] = &(create_ep_attr(ep, udev, "type", show_ep_type)->dev_attr.attr); + endpoint->attrs[2] = &(create_ep_attr(ep, udev, "bLength", show_ep_bLength)->dev_attr.attr); + endpoint->attrs[3] = &(create_ep_attr(ep, udev, "bDescriptorType", show_ep_bDescriptorType)->dev_attr.attr); + endpoint->attrs[4] = &(create_ep_attr(ep, udev, "bEndpointAddress", show_ep_bEndpointAddress)->dev_attr.attr); + endpoint->attrs[5] = &(create_ep_attr(ep, udev, "bmAttributes", show_ep_bmAttributes)->dev_attr.attr); + endpoint->attrs[6] = &(create_ep_attr(ep, udev, "wMaxPacketSize", show_ep_wMaxPacketSize)->dev_attr.attr); + endpoint->attrs[7] = &(create_ep_attr(ep, udev, "bInterval", show_ep_bInterval)->dev_attr.attr); + endpoint->attrs[8] = &(create_ep_attr(ep, udev, "interval", show_ep_interval)->dev_attr.attr); + endpoint->attrs[9] = NULL; + endpoint->num_attrs = 9; + + endpoint->attr_group = kzalloc(sizeof(*endpoint->attr_group), GFP_KERNEL); + endpoint->attr_name = kzalloc(10, GFP_KERNEL); + sprintf(endpoint->attr_name, "ep_%02x", endpoint->desc.bEndpointAddress); + + endpoint->attr_group->attrs = endpoint->attrs; + endpoint->attr_group->name = endpoint->attr_name; + sysfs_create_group(kobj, endpoint->attr_group); +} + +static void usb_remove_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint) +{ + int i; + + sysfs_remove_group(kobj, endpoint->attr_group); + kfree(endpoint->attr_group); + kfree(endpoint->attr_name); + for (i = 0; i < endpoint->num_attrs; ++i) + kfree(endpoint->attrs[i]); + kfree(endpoint->attrs); +} + /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ @@ -236,12 +404,14 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) if (udev->serial) device_create_file (dev, &dev_attr_serial); device_create_file (dev, &dev_attr_configuration); + usb_create_ep_files(&dev->kobj, &udev->ep0, udev); } void usb_remove_sysfs_dev_files (struct usb_device *udev) { struct device *dev = &udev->dev; + usb_remove_ep_files(&dev->kobj, &udev->ep0); sysfs_remove_group(&dev->kobj, &dev_attr_grp); if (udev->descriptor.iManufacturer) @@ -333,20 +503,41 @@ static struct attribute_group intf_attr_grp = { .attrs = intf_attrs, }; +static void usb_create_intf_ep_files(struct usb_interface *intf) +{ + struct usb_host_interface *iface_desc; + int i; + + iface_desc = intf->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) + usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], + interface_to_usbdev(intf)); +} + +static void usb_remove_intf_ep_files(struct usb_interface *intf) +{ + struct usb_host_interface *iface_desc; + int i; + + iface_desc = intf->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) + usb_remove_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i]); +} + void usb_create_sysfs_intf_files (struct usb_interface *intf) { sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); if (intf->cur_altsetting->string) device_create_file(&intf->dev, &dev_attr_interface); - + usb_create_intf_ep_files(intf); } void usb_remove_sysfs_intf_files (struct usb_interface *intf) { + usb_remove_intf_ep_files(intf); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); if (intf->cur_altsetting->string) device_remove_file(&intf->dev, &dev_attr_interface); - } diff --git a/include/linux/usb.h b/include/linux/usb.h index 8f731e8f2821..4512210e97e7 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -57,6 +57,10 @@ struct usb_host_endpoint { struct usb_endpoint_descriptor desc; struct list_head urb_list; void *hcpriv; + char *attr_name; + struct attribute_group *attr_group; + struct attribute **attrs; + int num_attrs; unsigned char *extra; /* Extra descriptors */ int extralen; From d6e5bcf4a7ebbe258124a931f1449338340a99b5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1123/1939] [PATCH] devfs: Remove the mode field from usb_class_driver as it's no longer needed Also fixes all drivers that set this field, and removes some other devfs specfic USB logic. Signed-off-by: Greg Kroah-Hartman drivers/usb/class/usblp.c | 3 +-- drivers/usb/core/file.c | 19 ++++--------------- drivers/usb/image/mdc800.c | 3 +-- drivers/usb/input/aiptek.c | 2 +- drivers/usb/input/hiddev.c | 3 +-- drivers/usb/media/dabusb.c | 3 +-- drivers/usb/misc/auerswald.c | 3 +-- drivers/usb/misc/idmouse.c | 5 ++--- drivers/usb/misc/legousbtower.c | 5 ++--- drivers/usb/misc/rio500.c | 3 +-- drivers/usb/misc/sisusbvga/sisusb.c | 5 ----- drivers/usb/misc/usblcd.c | 9 ++++----- drivers/usb/usb-skeleton.c | 3 +-- include/linux/usb.h | 7 ++----- 14 files changed, 22 insertions(+), 51 deletions(-) --- drivers/usb/class/usblp.c | 3 +-- drivers/usb/core/file.c | 19 ++++--------------- drivers/usb/image/mdc800.c | 3 +-- drivers/usb/input/aiptek.c | 2 +- drivers/usb/input/hiddev.c | 3 +-- drivers/usb/media/dabusb.c | 3 +-- drivers/usb/misc/auerswald.c | 3 +-- drivers/usb/misc/idmouse.c | 5 ++--- drivers/usb/misc/legousbtower.c | 5 ++--- drivers/usb/misc/rio500.c | 3 +-- drivers/usb/misc/sisusbvga/sisusb.c | 5 ----- drivers/usb/misc/usblcd.c | 9 ++++----- drivers/usb/usb-skeleton.c | 3 +-- include/linux/usb.h | 7 ++----- 14 files changed, 22 insertions(+), 51 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e195709c9c7f..357e75335f17 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -844,9 +844,8 @@ static struct file_operations usblp_fops = { }; static struct usb_class_driver usblp_class = { - .name = "usb/lp%d", + .name = "lp%d", .fops = &usblp_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = USBLP_MINOR_BASE, }; diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 78cb4be9529f..e695308095ae 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -88,8 +87,6 @@ int usb_major_init(void) goto out; } - devfs_mk_dir("usb"); - out: return error; } @@ -97,7 +94,6 @@ int usb_major_init(void) void usb_major_cleanup(void) { class_destroy(usb_class); - devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } @@ -112,8 +108,7 @@ void usb_major_cleanup(void) * enabled, the minor number will be based on the next available free minor, * starting at the class_driver->minor_base. * - * This function also creates the devfs file for the usb device, if devfs - * is enabled, and creates a usb class device in the sysfs tree. + * This function also creates a usb class device in the sysfs tree. * * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. @@ -162,11 +157,8 @@ int usb_register_dev(struct usb_interface *intf, intf->minor = minor; - /* handle the devfs registration */ - snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); - devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); - /* create a usb class device for this usb interface */ + snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); temp = strrchr(name, '/'); if (temp && (temp[1] != 0x00)) ++temp; @@ -179,7 +171,6 @@ int usb_register_dev(struct usb_interface *intf, spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - devfs_remove (name); retval = PTR_ERR(intf->class_dev); } exit: @@ -197,9 +188,8 @@ EXPORT_SYMBOL(usb_register_dev); * call to usb_register_dev() (usually when the device is disconnected * from the system.) * - * This function also cleans up the devfs file for the usb device, if devfs - * is enabled, and removes the usb class device from the sysfs tree. - * + * This function also removes the usb class device from the sysfs tree. + * * This should be called by all drivers that use the USB major number. */ void usb_deregister_dev(struct usb_interface *intf, @@ -222,7 +212,6 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - devfs_remove (name); class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); intf->class_dev = NULL; intf->minor = -1; diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index a330a4b50e16..e4ec133ee74a 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -425,9 +425,8 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res) static struct usb_driver mdc800_usb_driver; static struct file_operations mdc800_device_ops; static struct usb_class_driver mdc800_class = { - .name = "usb/mdc800%d", + .name = "mdc800%d", .fops = &mdc800_device_ops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = MDC800_DEVICE_MINOR_BASE, }; diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 1c5205321d83..1c3b472a3bca 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -2154,7 +2154,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) * input_handles associated with this input device. * What identifies an evdev input_handler is that it begins * with 'event', continues with a digit, and that in turn - * is mapped to /{devfs}/input/eventN. + * is mapped to input/eventN. */ list_for_each_safe(node, next, &inputdev->h_list) { inputhandle = to_handle(node); diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index d32427818af7..440377c7a0da 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -732,9 +732,8 @@ static struct file_operations hiddev_fops = { }; static struct usb_class_driver hiddev_class = { - .name = "usb/hid/hiddev%d", + .name = "hiddev%d", .fops = &hiddev_fops, - .mode = S_IFCHR | S_IRUGO | S_IWUSR, .minor_base = HIDDEV_MINOR_BASE, }; diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 6ca2fae99d2d..27b23c55bbc7 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -707,9 +707,8 @@ static struct file_operations dabusb_fops = }; static struct usb_class_driver dabusb_class = { - .name = "usb/dabusb%d", + .name = "dabusb%d", .fops = &dabusb_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = DABUSB_MINOR, }; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index ae4681f9f0ea..5f33f7c64885 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1873,9 +1873,8 @@ static struct file_operations auerswald_fops = }; static struct usb_class_driver auerswald_class = { - .name = "usb/auer%d", + .name = "auer%d", .fops = &auerswald_fops, - .mode = S_IFCHR | S_IRUGO | S_IWUGO, .minor_base = AUER_MINOR_BASE, }; diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 733acc213726..3944a55ed74c 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -105,11 +105,10 @@ static struct file_operations idmouse_fops = { .release = idmouse_release, }; -/* class driver information for devfs */ +/* class driver information */ static struct usb_class_driver idmouse_class = { - .name = "usb/idmouse%d", + .name = "idmouse%d", .fops = &idmouse_fops, - .mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */ .minor_base = USB_IDMOUSE_MINOR_BASE, }; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 7d06105763d4..2703e205bc8f 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -271,12 +271,11 @@ static struct file_operations tower_fops = { /* * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core + * and to have the device registered with the driver core */ static struct usb_class_driver tower_class = { - .name = "usb/legousbtower%d", + .name = "legousbtower%d", .fops = &tower_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = LEGO_USB_TOWER_MINOR_BASE, }; diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 26f77e29c7a6..7d02d8ec6b1a 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -443,9 +443,8 @@ file_operations usb_rio_fops = { }; static struct usb_class_driver usb_rio_class = { - .name = "usb/rio500%d", + .name = "rio500%d", .fops = &usb_rio_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = RIO_MINOR, }; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 39db3155723a..222ae9cd4c7c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3239,12 +3239,7 @@ static struct file_operations usb_sisusb_fops = { }; static struct usb_class_driver usb_sisusb_class = { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) - .name = "usb/sisusbvga%d", - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, -#else .name = "sisusbvga%d", -#endif .fops = &usb_sisusb_fops, .minor_base = SISUSB_MINOR }; diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 096ab3029676..85f3725334b0 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -251,13 +251,12 @@ static struct file_operations lcd_fops = { }; /* - * * usb class driver info in order to get a minor number from the usb core, - * * and to have the device registered with devfs and the driver core - * */ + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with the driver core + */ static struct usb_class_driver lcd_class = { - .name = "usb/lcd%d", + .name = "lcd%d", .fops = &lcd_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = USBLCD_MINOR, }; diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 353f24d45bc1..6c3a53f8f26c 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -223,9 +223,8 @@ static struct file_operations skel_fops = { * and to have the device registered with devfs and the driver core */ static struct usb_class_driver skel_class = { - .name = "usb/skel%d", + .name = "skel%d", .fops = &skel_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = USB_SKEL_MINOR_BASE, }; diff --git a/include/linux/usb.h b/include/linux/usb.h index 4512210e97e7..04502e183dd1 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -576,10 +576,8 @@ extern struct bus_type usb_bus_type; /** * struct usb_class_driver - identifies a USB driver that wants to use the USB major number - * @name: devfs name for this driver. Will also be used by the driver - * class code to create a usb class device. + * @name: the usb class device name for this driver. Will show up in sysfs. * @fops: pointer to the struct file_operations of this driver. - * @mode: the mode for the devfs file to be created for this driver. * @minor_base: the start of the minor range for this driver. * * This structure is used for the usb_register_dev() and @@ -589,8 +587,7 @@ extern struct bus_type usb_bus_type; struct usb_class_driver { char *name; struct file_operations *fops; - mode_t mode; - int minor_base; + int minor_base; }; /* From e639dd3f4edd4847d160899b19e95ee1a06a6dcb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1124/1939] [PATCH] USB: add more snooping hooks in devio.c Now we can log the urbs travelling through usbfs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 55 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index befe0c7f63d1..6c15dabcfc0b 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -279,6 +279,28 @@ static inline struct async *async_getpending(struct dev_state *ps, void __user * return NULL; } +static void snoop_urb(struct urb *urb, void __user *userurb) +{ + int j; + unsigned char *data = urb->transfer_buffer; + + if (!usbfs_snoop) + return; + + if (urb->pipe & USB_DIR_IN) + dev_info(&urb->dev->dev, "direction=IN\n"); + else + dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "userurb=%p\n", userurb); + dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", + urb->transfer_buffer_length); + dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); + dev_info(&urb->dev->dev, "data: "); + for (j = 0; j < urb->transfer_buffer_length; ++j) + printk ("%02x ", data[j]); + printk("\n"); +} + static void async_completed(struct urb *urb, struct pt_regs *regs) { struct async *as = (struct async *)urb->context; @@ -296,7 +318,9 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, as->euid); } - wake_up(&ps->wait); + snoop(&urb->dev->dev, "urb complete\n"); + snoop_urb(urb, as->userurb); + wake_up(&ps->wait); } static void destroy_async (struct dev_state *ps, struct list_head *list) @@ -601,7 +625,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); for (j = 0; j < i; ++j) - printk ("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } if (copy_to_user(ctrl.data, tbuf, i)) { @@ -624,7 +648,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "control write: data: "); for (j = 0; j < ctrl.wLength; ++j) - printk ("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } usb_unlock_device(dev); @@ -649,7 +673,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) unsigned int tmo, len1, pipe; int len2; unsigned char *tbuf; - int i, ret; + int i, j, ret; if (copy_from_user(&bulk, arg, sizeof(bulk))) return -EFAULT; @@ -674,10 +698,18 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) kfree(tbuf); return -EINVAL; } + snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", + bulk.len, bulk.timeout); usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); usb_lock_device(dev); if (!i && len2) { + if (usbfs_snoop) { + dev_info(&dev->dev, "bulk read: data "); + for (j = 0; j < len2; ++j) + printk("%02x ", (unsigned char)(tbuf)[j]); + printk("\n"); + } if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); return -EFAULT; @@ -690,6 +722,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) return -EFAULT; } } + snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", + bulk.len, bulk.timeout); + if (usbfs_snoop) { + dev_info(&dev->dev, "bulk write: data: "); + for (j = 0; j < len1; ++j) + printk("%02x ", (unsigned char)(tbuf)[j]); + printk("\n"); + } usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); usb_lock_device(dev); @@ -835,7 +875,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) return status; } - static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usbdevfs_iso_packet_desc __user *iso_frame_desc, void __user *arg) @@ -896,6 +935,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EFAULT; } + snoop(&ps->dev->dev, "control urb\n"); break; case USBDEVFS_URB_TYPE_BULK: @@ -910,6 +950,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; + snoop(&ps->dev->dev, "bulk urb\n"); break; case USBDEVFS_URB_TYPE_ISO: @@ -939,6 +980,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; } uurb->buffer_length = totlen; + snoop(&ps->dev->dev, "iso urb\n"); break; case USBDEVFS_URB_TYPE_INTERRUPT: @@ -954,6 +996,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; + snoop(&ps->dev->dev, "interrupt urb\n"); break; default: @@ -1003,6 +1046,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EFAULT; } } + snoop(&as->urb->dev->dev, "submit urb\n"); + snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); From 38ffdd62b0f466ef9126ac9f060ade5f218b4887 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 24 Sep 2005 13:10:16 -0700 Subject: [PATCH 1125/1939] [PATCH] ub: suppress gcc warnings for pointer casts When building on a 64-bit platform, gcc produces a warning "cast of a pointer to an integer of a different size". The scatterlist.offset on the LHS is unsigned int, so I used that originally. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman drivers/block/ub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- drivers/block/ub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index ed4d5006fe62..bfb23d543ff7 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1512,7 +1512,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) scmd->nsg = 1; sg = &scmd->sgv[0]; sg->page = virt_to_page(sc->top_sense); - sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1); + sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1); sg->length = UB_SENSE_SIZE; scmd->len = UB_SENSE_SIZE; scmd->lun = cmd->lun; @@ -1891,7 +1891,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, cmd->nsg = 1; sg = &cmd->sgv[0]; sg->page = virt_to_page(p); - sg->offset = (unsigned int)p & (PAGE_SIZE-1); + sg->offset = (unsigned long)p & (PAGE_SIZE-1); sg->length = 8; cmd->len = 8; cmd->lun = lun; From 7586269c0b52970f60bb69fcb86e765fc1d72309 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 23 Sep 2005 17:14:37 -0700 Subject: [PATCH 1126/1939] [PATCH] USB: move handoff code This moves the PCI quirk handling for USB host controllers from the PCI directory to the USB directory. Follow-on patches will need to: (a) merge these copies with the originals in the HCD reset methods. they don't wholly agree, despite doing the very same thing; and (b) eventually change it so "usb-handoff" is the default, to help get more robust USB/BIOS/input/... interactions. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/Makefile | 2 drivers/pci/quirks.c | 253 --------------------------------------- drivers/usb/Makefile | 1 drivers/usb/host/Makefile | 5 drivers/usb/host/pci-quirks.c | 272 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 253 deletions(-) --- drivers/Makefile | 2 +- drivers/pci/quirks.c | 253 +------------------------------ drivers/usb/Makefile | 1 + drivers/usb/host/Makefile | 5 +- drivers/usb/host/pci-quirks.c | 272 ++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 253 deletions(-) create mode 100644 drivers/usb/host/pci-quirks.c diff --git a/drivers/Makefile b/drivers/Makefile index 1a109a6dd953..65670be6ff1a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -5,7 +5,7 @@ # Rewritten to use lists instead of if-statements. # -obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_PCI) += pci/ usb/ obj-$(CONFIG_PARISC) += parisc/ obj-y += video/ obj-$(CONFIG_ACPI) += acpi/ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ee1605906a3e..bbd9c2323d8c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -7,6 +7,9 @@ * * Copyright (c) 1999 Martin Mares * + * Init/reset quirks for USB host controllers should be in the + * USB quirks file, where their drivers can access reuse it. + * * The bridge optimization stuff has been removed. If you really * have a silly BIOS which is unable to set your host bridge right, * use the PowerTweak utility (see http://powertweak.sourceforge.net). @@ -644,28 +647,6 @@ static void quirk_via_irq(struct pci_dev *dev) } DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); -/* - * PIIX3 USB: We have to disable USB interrupts that are - * hardwired to PIRQD# and may be shared with an - * external device. - * - * Legacy Support Register (LEGSUP): - * bit13: USB PIRQ Enable (USBPIRQDEN), - * bit4: Trap/SMI On IRQ Enable (USBSMIEN). - * - * We mask out all r/wc bits, too. - */ -static void __devinit quirk_piix3_usb(struct pci_dev *dev) -{ - u16 legsup; - - pci_read_config_word(dev, 0xc0, &legsup); - legsup &= 0x50ef; - pci_write_config_word(dev, 0xc0, legsup); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); - /* * VIA VT82C598 has its device ID settable and many BIOSes * set it to the ID of VT82C597 for backward compatibility. @@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev) pci_read_config_byte(dev, 0x77, &val); } - -#define UHCI_USBLEGSUP 0xc0 /* legacy support */ -#define UHCI_USBCMD 0 /* command register */ -#define UHCI_USBSTS 2 /* status register */ -#define UHCI_USBINTR 4 /* interrupt register */ -#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ -#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ -#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ -#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ - -#define OHCI_CONTROL 0x04 -#define OHCI_CMDSTATUS 0x08 -#define OHCI_INTRSTATUS 0x0c -#define OHCI_INTRENABLE 0x10 -#define OHCI_INTRDISABLE 0x14 -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ - -#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ -#define EHCI_USBCMD 0 /* command register */ -#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define EHCI_USBSTS 4 /* status register */ -#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ -#define EHCI_USBINTR 8 /* interrupt register */ -#define EHCI_USBLEGSUP 0 /* legacy support register */ -#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ -#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ -#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ -#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ - -int usb_early_handoff __devinitdata = 0; -static int __init usb_handoff_early(char *str) -{ - usb_early_handoff = 1; - return 0; -} -__setup("usb-handoff", usb_handoff_early); - -static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) -{ - unsigned long base = 0; - int wait_time, delta; - u16 val, sts; - int i; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { - base = pci_resource_start(pdev, i); - break; - } - - if (!base) - return; - - /* - * stop controller - */ - sts = inw(base + UHCI_USBSTS); - val = inw(base + UHCI_USBCMD); - val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); - outw(val, base + UHCI_USBCMD); - - /* - * wait while it stops if it was running - */ - if ((sts & UHCI_USBSTS_HALTED) == 0) - { - wait_time = 1000; - delta = 100; - - do { - outw(0x1f, base + UHCI_USBSTS); - udelay(delta); - wait_time -= delta; - val = inw(base + UHCI_USBSTS); - if (val & UHCI_USBSTS_HALTED) - break; - } while (wait_time > 0); - } - - /* - * disable interrupts & legacy support - */ - outw(0, base + UHCI_USBINTR); - outw(0x1f, base + UHCI_USBSTS); - pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); - if (val & 0xbf) - pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); - -} - -static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) -{ - void __iomem *base; - int wait_time; - - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (base == NULL) return; - - if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time = 500; /* 0.5 seconds */ - writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); - writel(OHCI_OCR, base + OHCI_CMDSTATUS); - while (wait_time > 0 && - readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time -= 10; - msleep(10); - } - } - - /* - * disable interrupts - */ - writel(~(u32)0, base + OHCI_INTRDISABLE); - writel(~(u32)0, base + OHCI_INTRSTATUS); - - iounmap(base); -} - -static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) -{ - int wait_time, delta; - void __iomem *base, *op_reg_base; - u32 hcc_params, val, temp; - u8 cap_length; - - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (base == NULL) return; - - cap_length = readb(base); - op_reg_base = base + cap_length; - hcc_params = readl(base + EHCI_HCC_PARAMS); - hcc_params = (hcc_params >> 8) & 0xff; - if (hcc_params) { - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - &val); - if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { - /* - * Ok, BIOS is in smm mode, try to hand off... - */ - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - &temp); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - temp | EHCI_USBLEGCTLSTS_SOOE); - val |= EHCI_USBLEGSUP_OS; - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - val); - - wait_time = 500; - do { - msleep(10); - wait_time -= 10; - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - &val); - } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); - if (!wait_time) { - /* - * well, possibly buggy BIOS... - */ - printk(KERN_WARNING "EHCI early BIOS handoff " - "failed (BIOS bug ?)\n"); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - EHCI_USBLEGSUP_OS); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - 0); - } - } - } - - /* - * halt EHCI & disable its interrupts in any case - */ - val = readl(op_reg_base + EHCI_USBSTS); - if ((val & EHCI_USBSTS_HALTED) == 0) { - val = readl(op_reg_base + EHCI_USBCMD); - val &= ~EHCI_USBCMD_RUN; - writel(val, op_reg_base + EHCI_USBCMD); - - wait_time = 2000; - delta = 100; - do { - writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); - wait_time -= delta; - val = readl(op_reg_base + EHCI_USBSTS); - if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { - break; - } - } while (wait_time > 0); - } - writel(0, op_reg_base + EHCI_USBINTR); - writel(0x3f, op_reg_base + EHCI_USBSTS); - - iounmap(base); - - return; -} - - - -static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) -{ - if (!usb_early_handoff) - return; - - if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ - quirk_usb_handoff_uhci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ - quirk_usb_handoff_ohci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ - quirk_usb_disable_ehci(pdev); - } - - return; -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); - /* * ... This is further complicated by the fact that some SiS96x south * bridges pretend to be 85C503/5513 instead. In that case see if we diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index df014c2a7c54..aa554f9805ee 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_MON) += mon/ +obj-$(CONFIG_PCI) += host/ obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 350d14fc1cc9..58321d3f314c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -1,8 +1,9 @@ # -# Makefile for USB Host Controller Driver -# framework and drivers +# Makefile for USB Host Controller Drivers # +obj-$(CONFIG_PCI) += pci-quirks.o + obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c new file mode 100644 index 000000000000..8ee5c3ed4cd6 --- /dev/null +++ b/drivers/usb/host/pci-quirks.c @@ -0,0 +1,272 @@ +/* + * This file contains code to reset and initialize USB host controllers. + * Some of it includes work-arounds for PCI hardware and BIOS quirks. + * It may need to run early during booting -- before USB would normally + * initialize -- to ensure that Linux doesn't use any legacy modes. + * + * Copyright (c) 1999 Martin Mares + * (and others) + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * PIIX3 USB: We have to disable USB interrupts that are + * hardwired to PIRQD# and may be shared with an + * external device. + * + * Legacy Support Register (LEGSUP): + * bit13: USB PIRQ Enable (USBPIRQDEN), + * bit4: Trap/SMI On IRQ Enable (USBSMIEN). + * + * We mask out all r/wc bits, too. + */ +static void __devinit quirk_piix3_usb(struct pci_dev *dev) +{ + u16 legsup; + + pci_read_config_word(dev, 0xc0, &legsup); + legsup &= 0x50ef; + pci_write_config_word(dev, 0xc0, legsup); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); + + +/* FIXME these should be the guts of hcd->reset() methods; resolve all + * the differences between this version and the HCD's version. + */ + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBSTS 2 /* status register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ +#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ +#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRSTATUS 0x0c +#define OHCI_INTRENABLE 0x10 +#define OHCI_INTRDISABLE 0x14 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ +#define EHCI_USBCMD 0 /* command register */ +#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define EHCI_USBSTS 4 /* status register */ +#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ +#define EHCI_USBINTR 8 /* interrupt register */ +#define EHCI_USBLEGSUP 0 /* legacy support register */ +#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ +#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ +#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ +#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + +int usb_early_handoff __devinitdata = 0; +static int __init usb_handoff_early(char *str) +{ + usb_early_handoff = 1; + return 0; +} +__setup("usb-handoff", usb_handoff_early); + +static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) +{ + unsigned long base = 0; + int wait_time, delta; + u16 val, sts; + int i; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (!base) + return; + + /* + * stop controller + */ + sts = inw(base + UHCI_USBSTS); + val = inw(base + UHCI_USBCMD); + val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); + outw(val, base + UHCI_USBCMD); + + /* + * wait while it stops if it was running + */ + if ((sts & UHCI_USBSTS_HALTED) == 0) + { + wait_time = 1000; + delta = 100; + + do { + outw(0x1f, base + UHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = inw(base + UHCI_USBSTS); + if (val & UHCI_USBSTS_HALTED) + break; + } while (wait_time > 0); + } + + /* + * disable interrupts & legacy support + */ + outw(0, base + UHCI_USBINTR); + outw(0x1f, base + UHCI_USBSTS); + pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); + if (val & 0xbf) + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); + +} + +static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) +{ + void __iomem *base; + int wait_time; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time = 500; /* 0.5 seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while (wait_time > 0 && + readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time -= 10; + msleep(10); + } + } + + /* + * disable interrupts + */ + writel(~(u32)0, base + OHCI_INTRDISABLE); + writel(~(u32)0, base + OHCI_INTRSTATUS); + + iounmap(base); +} + +static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) +{ + int wait_time, delta; + void __iomem *base, *op_reg_base; + u32 hcc_params, val, temp; + u8 cap_length; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + cap_length = readb(base); + op_reg_base = base + cap_length; + hcc_params = readl(base + EHCI_HCC_PARAMS); + hcc_params = (hcc_params >> 8) & 0xff; + if (hcc_params) { + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { + /* + * Ok, BIOS is in smm mode, try to hand off... + */ + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + &temp); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + temp | EHCI_USBLEGCTLSTS_SOOE); + val |= EHCI_USBLEGSUP_OS; + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + val); + + wait_time = 500; + do { + msleep(10); + wait_time -= 10; + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); + if (!wait_time) { + /* + * well, possibly buggy BIOS... + */ + printk(KERN_WARNING "EHCI early BIOS handoff " + "failed (BIOS bug ?)\n"); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + EHCI_USBLEGSUP_OS); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + 0); + } + } + } + + /* + * halt EHCI & disable its interrupts in any case + */ + val = readl(op_reg_base + EHCI_USBSTS); + if ((val & EHCI_USBSTS_HALTED) == 0) { + val = readl(op_reg_base + EHCI_USBCMD); + val &= ~EHCI_USBCMD_RUN; + writel(val, op_reg_base + EHCI_USBCMD); + + wait_time = 2000; + delta = 100; + do { + writel(0x3f, op_reg_base + EHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = readl(op_reg_base + EHCI_USBSTS); + if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { + break; + } + } while (wait_time > 0); + } + writel(0, op_reg_base + EHCI_USBINTR); + writel(0x3f, op_reg_base + EHCI_USBSTS); + + iounmap(base); + + return; +} + + + +static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) +{ + if (!usb_early_handoff) + return; + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + quirk_usb_handoff_uhci(pdev); + } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ + quirk_usb_handoff_ohci(pdev); + } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ + quirk_usb_disable_ehci(pdev); + } + + return; +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); From db69087437dd5135a9362da1c37fe072070e8f60 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Sep 2005 19:56:33 -0700 Subject: [PATCH 1127/1939] [PATCH] usb_interface power state This updates the handling of power state for USB interfaces. - Formalizes an existing invariant: interface "power state" is a boolean: ON when I/O is allowed, and FREEZE otherwise. It does so by defining some inlined helpers, then using them. - Adds a useful invariant: the only interfaces marked active are those bound to non-suspended drivers. Later patches build on this invariant. - Simplifies the interface driver API (and removes some error paths) by removing the requirement that they record power state changes during suspend and resume callbacks. Now usbcore does that. A few drivers were simplified to address that last change. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hub.c | 33 +++++++++------------ drivers/usb/core/message.c | 1 drivers/usb/core/usb.c | 65 +++++++++++++++++++++++++++++++++---------- drivers/usb/core/usb.h | 18 +++++++++++ drivers/usb/input/hid-core.c | 2 - drivers/usb/misc/usbtest.c | 10 ------ drivers/usb/net/pegasus.c | 2 - drivers/usb/net/usbnet.c | 2 - 8 files changed, 85 insertions(+), 48 deletions(-) --- drivers/usb/core/hub.c | 33 +++++++++--------- drivers/usb/core/message.c | 1 + drivers/usb/core/usb.c | 65 ++++++++++++++++++++++++++++-------- drivers/usb/core/usb.h | 18 ++++++++++ drivers/usb/input/hid-core.c | 2 -- drivers/usb/misc/usbtest.c | 10 ------ drivers/usb/net/pegasus.c | 2 -- drivers/usb/net/usbnet.c | 2 -- 8 files changed, 85 insertions(+), 48 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c3e2024c4347..61341d2f3c0e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1624,7 +1624,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (state.event <= intf->dev.power.power_state.event) + if (!is_active(intf)) continue; if (!intf->dev.driver) continue; @@ -1632,11 +1632,12 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, if (driver->suspend) { status = driver->suspend(intf, state); - if (intf->dev.power.power_state.event != state.event - || status) + if (status == 0) + mark_quiesced(intf); + else dev_err(&intf->dev, - "suspend %d fail, code %d\n", - state.event, status); + "suspend error %d\n", + status); } /* only drivers with suspend() can ever resume(); @@ -1787,7 +1788,7 @@ static int finish_port_resume(struct usb_device *udev) struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (intf->dev.power.power_state.event == PM_EVENT_ON) + if (is_active(intf)) continue; if (!intf->dev.driver) { /* FIXME maybe force to alt 0 */ @@ -1800,12 +1801,14 @@ static int finish_port_resume(struct usb_device *udev) continue; /* can we do better than just logging errors? */ + mark_active(intf); status = driver->resume(intf); - if (intf->dev.power.power_state.event != PM_EVENT_ON - || status) + if (status < 0) { + mark_quiesced(intf); dev_dbg(&intf->dev, - "resume fail, state %d code %d\n", - intf->dev.power.power_state.event, status); + "resume error %d\n", + status); + } } status = 0; @@ -1952,7 +1955,7 @@ static int remote_wakeup(struct usb_device *udev) return status; } -static int hub_suspend(struct usb_interface *intf, pm_message_t state) +static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; @@ -1970,14 +1973,13 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t state) if (!udev) continue; down(&udev->serialize); - status = __usb_suspend_device(udev, port1, state); + status = __usb_suspend_device(udev, port1, msg); up(&udev->serialize); if (status < 0) dev_dbg(&intf->dev, "suspend port %d --> %d\n", port1, status); } - intf->dev.power.power_state = state; return 0; } @@ -1988,9 +1990,6 @@ static int hub_resume(struct usb_interface *intf) unsigned port1; int status; - if (intf->dev.power.power_state.event == PM_EVENT_ON) - return 0; - for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; u16 portstat, portchange; @@ -2024,8 +2023,6 @@ static int hub_resume(struct usb_interface *intf) } up(&udev->serialize); } - intf->dev.power.power_state = PMSG_ON; - hub->resume_root_hub = 0; hub_activate(hub); return 0; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f9a81e84dbdf..ebf59ea99263 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1393,6 +1393,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.release = release_interface; device_initialize (&intf->dev); + mark_quiesced(intf); sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4c57f3f649ed..6ecfdce4f848 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev) id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); + + /* Interface "power state" doesn't correspond to any hardware + * state whatsoever. We use it to record when it's bound to + * a driver that may start I/0: it's not frozen/quiesced. + */ + mark_active(intf); intf->condition = USB_INTERFACE_BINDING; error = driver->probe (intf, id); - intf->condition = error ? USB_INTERFACE_UNBOUND : - USB_INTERFACE_BOUND; + if (error) { + mark_quiesced(intf); + intf->condition = USB_INTERFACE_UNBOUND; + } else + intf->condition = USB_INTERFACE_BOUND; } return error; @@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev) 0); usb_set_intfdata(intf, NULL); intf->condition = USB_INTERFACE_UNBOUND; + mark_quiesced(intf); return 0; } @@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, dev->driver = &driver->driver; usb_set_intfdata(iface, priv); iface->condition = USB_INTERFACE_BOUND; + mark_active(iface); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); iface->condition = USB_INTERFACE_UNBOUND; + mark_quiesced(iface); } /** @@ -1404,8 +1416,9 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, static int usb_generic_suspend(struct device *dev, pm_message_t message) { - struct usb_interface *intf; - struct usb_driver *driver; + struct usb_interface *intf; + struct usb_driver *driver; + int status; if (dev->driver == &usb_generic_driver) return usb_suspend_device (to_usb_device(dev), message); @@ -1417,21 +1430,34 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); - /* there's only one USB suspend state */ - if (intf->dev.power.power_state.event) + /* with no hardware, USB interfaces only use FREEZE and ON states */ + if (!is_active(intf)) return 0; - if (driver->suspend) - return driver->suspend(intf, message); - return 0; + if (driver->suspend && driver->resume) { + status = driver->suspend(intf, message); + if (status) + dev_err(dev, "%s error %d\n", "suspend", status); + else + mark_quiesced(intf); + } else { + // FIXME else if there's no suspend method, disconnect... + dev_warn(dev, "no %s?\n", "suspend"); + status = 0; + } + return status; } static int usb_generic_resume(struct device *dev) { - struct usb_interface *intf; - struct usb_driver *driver; + struct usb_interface *intf; + struct usb_driver *driver; + int status; - /* devices resume through their hub */ + if (dev->power.power_state.event == PM_EVENT_ON) + return 0; + + /* devices resume through their hubs */ if (dev->driver == &usb_generic_driver) return usb_resume_device (to_usb_device(dev)); @@ -1442,8 +1468,19 @@ static int usb_generic_resume(struct device *dev) intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); - if (driver->resume) - return driver->resume(intf); + /* if driver was suspended, it has a resume method; + * however, sysfs can wrongly mark things as suspended + * (on the "no suspend method" FIXME path above) + */ + mark_active(intf); + if (driver->resume) { + status = driver->resume(intf); + if (status) { + dev_err(dev, "%s error %d\n", "resume", status); + mark_quiesced(intf); + } + } else + dev_warn(dev, "no %s?\n", "resume"); return 0; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e6504f3370ad..3741a990403e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -28,6 +28,24 @@ extern void usb_major_cleanup(void); extern int usb_host_init(void); extern void usb_host_cleanup(void); +/* Interfaces and their "power state" are owned by usbcore */ + +static inline void mark_active(struct usb_interface *f) +{ + f->dev.power.power_state.event = PM_EVENT_ON; +} + +static inline void mark_quiesced(struct usb_interface *f) +{ + f->dev.power.power_state.event = PM_EVENT_FREEZE; +} + +static inline int is_active(struct usb_interface *f) +{ + return f->dev.power.power_state.event == PM_EVENT_ON; +} + + /* for labeling diagnostics */ extern const char *usbcore_name; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 411a0645a7a3..f7fcce731f54 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1887,7 +1887,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) struct hid_device *hid = usb_get_intfdata (intf); usb_kill_urb(hid->urbin); - intf->dev.power.power_state = PMSG_SUSPEND; dev_dbg(&intf->dev, "suspend\n"); return 0; } @@ -1897,7 +1896,6 @@ static int hid_resume(struct usb_interface *intf) struct hid_device *hid = usb_get_intfdata (intf); int status; - intf->dev.power.power_state = PMSG_ON; if (hid->open) status = usb_submit_urb(hid->urbin, GFP_NOIO); else diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 54799eb0bc60..d055196533af 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1948,21 +1948,11 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) { - struct usbtest_dev *dev = usb_get_intfdata (intf); - - down (&dev->sem); - intf->dev.power.power_state = PMSG_SUSPEND; - up (&dev->sem); return 0; } static int usbtest_resume (struct usb_interface *intf) { - struct usbtest_dev *dev = usb_get_intfdata (intf); - - down (&dev->sem); - intf->dev.power.power_state = PMSG_ON; - up (&dev->sem); return 0; } diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 6a4ffe6c3977..537eb181d985 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1384,7 +1384,6 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->intr_urb); } - intf->dev.power.power_state = PMSG_SUSPEND; return 0; } @@ -1392,7 +1391,6 @@ static int pegasus_resume (struct usb_interface *intf) { struct pegasus *pegasus = usb_get_intfdata(intf); - intf->dev.power.power_state = PMSG_ON; netif_device_attach (pegasus->net); if (netif_running(pegasus->net)) { pegasus->rx_urb->status = 0; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index fce81d738933..74f05c9c84d5 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1185,7 +1185,6 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) netif_device_detach (dev->net); (void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->txq); - intf->dev.power.power_state = PMSG_SUSPEND; return 0; } EXPORT_SYMBOL_GPL(usbnet_suspend); @@ -1194,7 +1193,6 @@ int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); - intf->dev.power.power_state = PMSG_ON; netif_device_attach (dev->net); tasklet_schedule (&dev->bh); return 0; From c9f89fa40cf274130b56475175a35af961d4b165 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Sep 2005 19:57:04 -0700 Subject: [PATCH 1128/1939] [PATCH] remove suspend-path recursion This patch removes some recursion in the CONFIG_USB_SUSPEND logic, which suspended children (of devices or hubs) that weren't already suspended. When it sees such cases, suspend now just fails cleanly. That logic was not needed during system-wide sleep state transitions; and given the current notions of how to manage selective suspend transitions, we don't want it there either. Where it was particularly handy was coping with various limitations of the sysfs "echo -n N > power/state" support. (These include assuming that "N" is always meaningful to the driver; and that drivers can only transition to state N from state zero.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 76 +++++++----------------------------------- 1 file changed, 12 insertions(+), 64 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 61341d2f3c0e..d3337d9c31dc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -453,6 +453,7 @@ static void hub_quiesce(struct usb_hub *hub) { /* stop khubd and related activity */ hub->quiescing = 1; + hub->activating = 0; usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -1613,68 +1614,21 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, return 0; } - /* suspend interface drivers; if this is a hub, it - * suspends the child devices - */ + /* all interfaces must already be suspended */ if (udev->actconfig) { int i; for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *intf; - struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (!is_active(intf)) - continue; - if (!intf->dev.driver) - continue; - driver = to_usb_driver(intf->dev.driver); - - if (driver->suspend) { - status = driver->suspend(intf, state); - if (status == 0) - mark_quiesced(intf); - else - dev_err(&intf->dev, - "suspend error %d\n", - status); - } - - /* only drivers with suspend() can ever resume(); - * and after power loss, even they won't. - * bus_rescan_devices() can rebind drivers later. - * - * FIXME the PM core self-deadlocks when unbinding - * drivers during suspend/resume ... everything grabs - * dpm_sem (not a spinlock, ugh). we want to unbind, - * since we know every driver's probe/disconnect works - * even for drivers that can't suspend. - */ - if (!driver->suspend || state.event > PM_EVENT_FREEZE) { -#if 1 - dev_warn(&intf->dev, "resume is unsafe!\n"); -#else - down_write(&usb_bus_type.rwsem); - device_release_driver(&intf->dev); - up_write(&usb_bus_type.rwsem); -#endif + if (is_active(intf)) { + dev_dbg(&intf->dev, "nyet suspended\n"); + return -EBUSY; } } } - /* - * FIXME this needs port power off call paths too, to help force - * USB into the "generic" PM model. At least for devices on - * ports that aren't using ganged switching (usually root hubs). - * - * NOTE: SRP-capable links should adopt more aggressive poweroff - * policies (when HNP doesn't apply) once we have mechanisms to - * turn power back on! (Likely not before 2.7...) - */ - if (state.event > PM_EVENT_FREEZE) { - dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); - } - /* "global suspend" of the HC-to-USB interface (root hub), or * "selective suspend" of just one hub-device link. */ @@ -1960,26 +1914,20 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; - int status; - /* stop khubd and related activity */ - hub_quiesce(hub); - - /* then suspend every port */ + /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; udev = hdev->children [port1-1]; - if (!udev) - continue; - down(&udev->serialize); - status = __usb_suspend_device(udev, port1, msg); - up(&udev->serialize); - if (status < 0) - dev_dbg(&intf->dev, "suspend port %d --> %d\n", - port1, status); + if (udev && udev->state != USB_STATE_SUSPENDED) { + dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); + return -EBUSY; + } } + /* stop khubd and related activity */ + hub_quiesce(hub); return 0; } From 390a8c345e6415cbf811232feedac70b56c9fc8d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Sep 2005 19:57:27 -0700 Subject: [PATCH 1129/1939] [PATCH] remove usb_suspend_device() parameter This patch removes the extra usb_suspend_device() parameter. The original reason to pass that parameter was so that this routine could suspend any active children. A previous patch removed that functionality ... leaving no reason to pass the parameter. A close analogy is pci_set_power_state, which doesn't need a pm_message_t either. On the internal code path that comes through the driver model, the parameter is now used to distinguish cases where USB devices need to "freeze" but not suspend. It also checks for an error case that's accessible through sysfs: attempting to suspend a device before its interfaces (or for hubs, ports). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hub.c | 34 +++++++++++++++++++++------------- drivers/usb/core/usb.c | 23 +++++++++++++++++++++-- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/ohci-pci.c | 2 +- include/linux/usb.h | 2 +- 6 files changed, 46 insertions(+), 19 deletions(-) --- drivers/usb/core/hub.c | 34 +++++++++++++++++++++------------- drivers/usb/core/usb.c | 23 +++++++++++++++++++++-- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/ohci-pci.c | 2 +- include/linux/usb.h | 2 +- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d3337d9c31dc..33127b828d60 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1323,11 +1323,9 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_suspend_device (struct usb_device *, - int port1, pm_message_t state); - err = __usb_suspend_device(udev, - udev->bus->otg_port, - PMSG_SUSPEND); + static int __usb_suspend_device(struct usb_device *, + int port1); + err = __usb_suspend_device(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } @@ -1517,7 +1515,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) /* FIXME let caller ask to power down the port: * - some devices won't enumerate without a VBUS power cycle * - SRP saves power that way - * - usb_suspend_device(dev, PMSG_SUSPEND) + * - ... new call, TBD ... * That's easy if this hub can switch power per-port, and * khubd reactivates the port later (timer, SRP, etc). * Powerdown must be optional, because of reset/DFU. @@ -1599,9 +1597,12 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * Other than re-initializing the hub (plug/unplug, except for root hubs), * Linux (2.6) currently has NO mechanisms to initiate that: no khubd * timer, no SRP, no requests through sysfs. + * + * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when + * the root hub for their bus goes into global suspend ... so we don't + * (falsely) update the device power state to say it suspended. */ -static int __usb_suspend_device (struct usb_device *udev, int port1, - pm_message_t state) +static int __usb_suspend_device (struct usb_device *udev, int port1) { int status; @@ -1648,14 +1649,13 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, udev); if (status == 0) - udev->dev.power.power_state = state; + udev->dev.power.power_state = PMSG_SUSPEND; return status; } /** * usb_suspend_device - suspend a usb device * @udev: device that's no longer in active use - * @state: PMSG_SUSPEND to suspend * Context: must be able to sleep; device not locked * * Suspends a USB device that isn't in active use, conserving power. @@ -1664,13 +1664,16 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, * suspend by the host, using usb_resume_device(). It's also routine * to disconnect devices while they are suspended. * + * This only affects the USB hardware for a device; its interfaces + * (and, for hubs, child devices) must already have been suspended. + * * Suspending OTG devices may trigger HNP, if that's been enabled * between a pair of dual-role devices. That will change roles, such * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. * * Returns 0 on success, else negative errno. */ -int usb_suspend_device(struct usb_device *udev, pm_message_t state) +int usb_suspend_device(struct usb_device *udev) { int port1, status; @@ -1678,12 +1681,15 @@ int usb_suspend_device(struct usb_device *udev, pm_message_t state) if (port1 < 0) return port1; - status = __usb_suspend_device(udev, port1, state); + status = __usb_suspend_device(udev, port1); usb_unlock_device(udev); return status; } /* + * If the USB "suspend" state is in use (rather than "global suspend"), + * many devices will be individually taken out of suspend state using + * special" resume" signaling. These routines kick in shortly after * hardware resume signaling is finished, either because of selective * resume (by host) or remote wakeup (by device) ... now see what changed * in the tree that's rooted at this device. @@ -1986,13 +1992,15 @@ void usb_resume_root_hub(struct usb_device *hdev) #else /* !CONFIG_USB_SUSPEND */ -int usb_suspend_device(struct usb_device *udev, pm_message_t state) +int usb_suspend_device(struct usb_device *udev) { + /* state does NOT lie by saying it's USB_STATE_SUSPENDED! */ return 0; } int usb_resume_device(struct usb_device *udev) { + udev->dev.power_state.event = PM_EVENT_ON; return 0; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 6ecfdce4f848..e89dbd43e952 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1414,14 +1414,33 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +static int verify_suspended(struct device *dev, void *unused) +{ + return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0; +} + static int usb_generic_suspend(struct device *dev, pm_message_t message) { struct usb_interface *intf; struct usb_driver *driver; int status; - if (dev->driver == &usb_generic_driver) - return usb_suspend_device (to_usb_device(dev), message); + /* USB devices enter SUSPEND state through their hubs, but can be + * marked for FREEZE as soon as their children are already idled. + */ + if (dev->driver == &usb_generic_driver) { + if (dev->power.power_state.event == message.event) + return 0; + /* we need to rule out bogus requests through sysfs */ + status = device_for_each_child(dev, NULL, verify_suspended); + if (status) + return status; + if (message.event == PM_EVENT_FREEZE) { + dev->power.power_state = message; + return 0; + } + return usb_suspend_device (to_usb_device(dev)); + } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b3eb02613bff..513fccbb8e43 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -759,7 +759,7 @@ static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message) msleep (100); #ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub, message); + (void) usb_suspend_device (hcd->self.root_hub); #else usb_lock_device (hcd->self.root_hub); (void) ehci_hub_suspend (hcd); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 642f35068ce2..554d60282a9d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1781,7 +1781,7 @@ static int isp116x_suspend(struct device *dev, pm_message_t state) VDBG("%s: state %x\n", __func__, state); - ret = usb_suspend_device(hcd->self.root_hub, state); + ret = usb_suspend_device(hcd->self.root_hub); if (!ret) { dev->power.power_state = state; INFO("%s suspended\n", hcd_name); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index eede6be098d2..41e85980fa7a 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -119,7 +119,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) msleep (100); #ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub, message); + (void) usb_suspend_device (hcd->self.root_hub); #else usb_lock_device (hcd->self.root_hub); (void) ohci_hub_suspend (hcd); diff --git a/include/linux/usb.h b/include/linux/usb.h index 04502e183dd1..25ec91ddcd04 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -976,7 +976,7 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, int timeout); /* selective suspend/resume */ -extern int usb_suspend_device(struct usb_device *dev, pm_message_t message); +extern int usb_suspend_device(struct usb_device *dev); extern int usb_resume_device(struct usb_device *dev); From dbc3887e7df4be78b33a83b97fde5d5f9a389859 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Sep 2005 19:57:36 -0700 Subject: [PATCH 1130/1939] [PATCH] remove duplicated resume path code This gets rid of some inconsistently duplicated logic to resume interfaces. Similar code was in both finish_port_resume() and in usb_generic_resume(). Now there is just one copy of that code, accessed regardless of whether CONFIG_USB_SUSPEND is enabled. Fault handling is also more consistent. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 33127b828d60..b2ae9b6ca4db 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1723,6 +1723,7 @@ static int finish_port_resume(struct usb_device *udev) status); else if (udev->actconfig) { unsigned i; + int (*resume)(struct device *); le16_to_cpus(&devstatus); if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { @@ -1741,35 +1742,11 @@ static int finish_port_resume(struct usb_device *udev) } /* resume interface drivers; if this is a hub, it - * resumes the child devices + * may have a child resume event to deal with soon */ - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf; - struct usb_driver *driver; - - intf = udev->actconfig->interface[i]; - if (is_active(intf)) - continue; - if (!intf->dev.driver) { - /* FIXME maybe force to alt 0 */ - continue; - } - driver = to_usb_driver(intf->dev.driver); - - /* bus_rescan_devices() may rebind drivers */ - if (!driver->resume) - continue; - - /* can we do better than just logging errors? */ - mark_active(intf); - status = driver->resume(intf); - if (status < 0) { - mark_quiesced(intf); - dev_dbg(&intf->dev, - "resume error %d\n", - status); - } - } + resume = udev->dev.bus->resume; + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) + (void) resume(&udev->actconfig->interface[i]->dev); status = 0; } else if (udev->devnum <= 0) { From 8ad7fe16df5e07320626be83fbba6d1c6bda5ec0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Sep 2005 19:59:11 -0700 Subject: [PATCH 1131/1939] [PATCH] remove some USB_SUSPEND dependencies This simplifies some of the PM-related #ifdeffing by recognizing that USB_SUSPEND depends on PM. Also, OHCI drivers were often testing for USB_SUSPEND when they should have tested just PM. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hcd.c | 2 ++ drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-hub.c | 4 ++-- drivers/usb/host/ohci-omap.c | 2 +- drivers/usb/host/ohci-pci.c | 2 +- drivers/usb/host/ohci-ppc-soc.c | 4 ++-- drivers/usb/host/ohci-pxa27x.c | 2 +- drivers/usb/host/ohci-s3c2410.c | 3 +-- drivers/usb/host/ohci-sa1111.c | 2 +- 9 files changed, 12 insertions(+), 11 deletions(-) --- drivers/usb/core/hcd.c | 2 ++ drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-hub.c | 4 ++-- drivers/usb/host/ohci-omap.c | 2 +- drivers/usb/host/ohci-pci.c | 2 +- drivers/usb/host/ohci-ppc-soc.c | 4 ++-- drivers/usb/host/ohci-pxa27x.c | 2 +- drivers/usb/host/ohci-s3c2410.c | 3 +-- drivers/usb/host/ohci-sa1111.c | 2 +- 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 14c47a10da86..5e8ade07d7f9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1431,6 +1431,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) /*-------------------------------------------------------------------------*/ +/* FIXME make this #ifdef CONFIG_PM ... update root hubs, retest */ + #ifdef CONFIG_USB_SUSPEND static int hcd_hub_suspend (struct usb_bus *bus) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f8da8c7af7c6..c26ab5f2a403 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -791,7 +791,7 @@ static void ohci_stop (struct usb_hcd *hcd) /* must not be called from interrupt context */ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM static int ohci_restart (struct ohci_hcd *ohci) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ce7b28da7a15..b96948ea3005 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -36,7 +36,7 @@ /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) @@ -294,7 +294,7 @@ static void ohci_rh_resume (void *_hcd) ohci_dbg(ohci, "rh_resume ??\n"); } -#endif /* CONFIG_USB_SUSPEND || CONFIG_PM */ +#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index a574216625a0..e67c07dc426d 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -420,7 +420,7 @@ static const struct hc_driver ohci_omap_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 41e85980fa7a..0afa237b02ad 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -218,7 +218,7 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 251533363028..ec20710e99fe 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -163,7 +163,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif @@ -196,7 +196,7 @@ static struct device_driver ohci_hcd_ppc_soc_driver = { .bus = &platform_bus_type, .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ #endif diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index f042261ecb8e..986c4f656e22 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -278,7 +278,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index da7d5478f74d..8cf12b2be2a3 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -448,8 +448,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .hub_status_data = ohci_s3c2410_hub_status_data, .hub_control = ohci_s3c2410_hub_control, - -#if defined(CONFIG_USB_SUSPEND) && 0 +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 814d2be4ee7b..7dd1f410b7f1 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -235,7 +235,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif From e08fb39b771dd7dcba405669b5384fe9929e1caf Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Mon, 19 Sep 2005 09:40:24 -0700 Subject: [PATCH 1132/1939] [PATCH] USB: Fix usb hub build Signed-off-by: Matt Porter Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b2ae9b6ca4db..660064466791 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1977,7 +1977,7 @@ int usb_suspend_device(struct usb_device *udev) int usb_resume_device(struct usb_device *udev) { - udev->dev.power_state.event = PM_EVENT_ON; + udev->dev.power.power_state.event = PM_EVENT_ON; return 0; } From 8b4cd42134fbd3c9a9a5c3467d31717798219b1b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 16 Sep 2005 14:17:45 -0400 Subject: [PATCH 1133/1939] [PATCH] USB: UHCI: Remove unused fields and unneeded tests for NULL This patch (as562) removes from the uhci-hcd driver a few unused fields and some unnecessary tests against NULL and assignments to NULL. In fact it wasn't until fairly recently that the tests became unnecessary. Before last winter it was possible that the driver's stop() routine would get called even if the start() routine returned an error, but now that can't happen. Hence there's no longer any need to check for partial initialization. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 1 - drivers/usb/host/uhci-hcd.c | 44 ++++++++--------------------------- drivers/usb/host/uhci-hcd.h | 3 --- drivers/usb/host/uhci-q.c | 5 ---- 4 files changed, 10 insertions(+), 43 deletions(-) diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 4538a98b6f9d..04eddd7995c3 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -348,7 +348,6 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu if (urbp->urb->status != -EINPROGRESS) out += sprintf(out, "Status=%d ", urbp->urb->status); - //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); count = 0; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 0c024898cbea..17de9ee910f6 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -437,36 +437,18 @@ static void release_uhci(struct uhci_hcd *uhci) int i; for (i = 0; i < UHCI_NUM_SKELQH; i++) - if (uhci->skelqh[i]) { - uhci_free_qh(uhci, uhci->skelqh[i]); - uhci->skelqh[i] = NULL; - } + uhci_free_qh(uhci, uhci->skelqh[i]); - if (uhci->term_td) { - uhci_free_td(uhci, uhci->term_td); - uhci->term_td = NULL; - } + uhci_free_td(uhci, uhci->term_td); - if (uhci->qh_pool) { - dma_pool_destroy(uhci->qh_pool); - uhci->qh_pool = NULL; - } + dma_pool_destroy(uhci->qh_pool); - if (uhci->td_pool) { - dma_pool_destroy(uhci->td_pool); - uhci->td_pool = NULL; - } + dma_pool_destroy(uhci->td_pool); - if (uhci->fl) { - dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - uhci->fl, uhci->fl->dma_handle); - uhci->fl = NULL; - } + dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), + uhci->fl, uhci->fl->dma_handle); - if (uhci->dentry) { - debugfs_remove(uhci->dentry); - uhci->dentry = NULL; - } + debugfs_remove(uhci->dentry); } static int uhci_reset(struct usb_hcd *hcd) @@ -690,31 +672,25 @@ static int uhci_start(struct usb_hcd *hcd) * error exits: */ err_alloc_skelqh: - for (i = 0; i < UHCI_NUM_SKELQH; i++) - if (uhci->skelqh[i]) { + for (i = 0; i < UHCI_NUM_SKELQH; i++) { + if (uhci->skelqh[i]) uhci_free_qh(uhci, uhci->skelqh[i]); - uhci->skelqh[i] = NULL; - } + } uhci_free_td(uhci, uhci->term_td); - uhci->term_td = NULL; err_alloc_term_td: dma_pool_destroy(uhci->qh_pool); - uhci->qh_pool = NULL; err_create_qh_pool: dma_pool_destroy(uhci->td_pool); - uhci->td_pool = NULL; err_create_td_pool: dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle); - uhci->fl = NULL; err_alloc_fl: debugfs_remove(uhci->dentry); - uhci->dentry = NULL; err_create_debug_entry: return retval; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 282f40b75881..1c161b4f5bcf 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -205,8 +205,6 @@ struct uhci_td { /* Software fields */ dma_addr_t dma_handle; - struct urb *urb; - struct list_head list; /* P: urb->lock */ struct list_head remove_list; /* P: uhci->td_remove_list_lock */ @@ -434,7 +432,6 @@ struct urb_priv { /* a control transfer, retrigger */ /* the status phase */ - unsigned long inserttime; /* In jiffies */ unsigned long fsbrtime; /* In jiffies */ struct list_head queue_list; /* P: uhci->frame_list_lock */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 4e0fbe2c1a9a..d54038211ca6 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -443,7 +443,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u memset((void *)urbp, 0, sizeof(*urbp)); - urbp->inserttime = jiffies; urbp->fsbrtime = jiffies; urbp->urb = urb; @@ -462,8 +461,6 @@ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - td->urb = urb; - list_add_tail(&td->list, &urbp->td_list); } @@ -473,8 +470,6 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) return; list_del_init(&td->list); - - td->urb = NULL; } static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) From a1d59ce842a35b552f22868404e4e7c923242257 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 16 Sep 2005 14:22:51 -0400 Subject: [PATCH 1134/1939] [PATCH] USB: UHCI: Split apart the physical and logical framelist arrays This patch (as563) splits the physical and logical framelist arrays in uhci-hcd into two separate pieces. This will allow slightly better memory utilization, since each piece is no larger than a single page whereas before the whole thing was a little bigger than two pages. It also allows the logical array to be allocated in non-DMA-coherent memory. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 4 ++-- drivers/usb/host/uhci-hcd.c | 42 ++++++++++++++++++++++------------- drivers/usb/host/uhci-hcd.h | 6 ++++- drivers/usb/host/uhci-q.c | 20 ++++++++--------- 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 04eddd7995c3..151154df37fa 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -445,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) out += sprintf(out, "Frame List\n"); for (i = 0; i < UHCI_NUMFRAMES; ++i) { int shown = 0; - td = uhci->fl->frame_cpu[i]; + td = uhci->frame_cpu[i]; if (!td) continue; - if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) { + if (td->dma_handle != (dma_addr_t)uhci->frame[i]) { show_frame_num(); out += sprintf(out, " frame list does not match td->dma_handle!\n"); } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 17de9ee910f6..b44094fcd779 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -212,7 +212,7 @@ static void configure_hc(struct uhci_hcd *uhci) outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); /* Store the frame list base address */ - outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); + outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); /* Set the current frame number */ outw(uhci->frame_number, uhci->io_addr + USBFRNUM); @@ -445,8 +445,11 @@ static void release_uhci(struct uhci_hcd *uhci) dma_pool_destroy(uhci->td_pool); - dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - uhci->fl, uhci->fl->dma_handle); + kfree(uhci->frame_cpu); + + dma_free_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + uhci->frame, uhci->frame_dma_handle); debugfs_remove(uhci->dentry); } @@ -527,7 +530,6 @@ static int uhci_start(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); int retval = -EBUSY; int i; - dma_addr_t dma_handle; struct dentry *dentry; hcd->uses_new_polling = 1; @@ -561,17 +563,23 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); - uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - &dma_handle, 0); - if (!uhci->fl) { + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + &uhci->frame_dma_handle, 0); + if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate " "consistent memory for frame list\n"); - goto err_alloc_fl; + goto err_alloc_frame; } + memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame)); - memset((void *)uhci->fl, 0, sizeof(*uhci->fl)); - - uhci->fl->dma_handle = dma_handle; + uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu), + GFP_KERNEL); + if (!uhci->frame_cpu) { + dev_err(uhci_dev(uhci), "unable to allocate " + "memory for frame pointers\n"); + goto err_alloc_frame_cpu; + } uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci), sizeof(struct uhci_td), 16, 0); @@ -654,7 +662,7 @@ static int uhci_start(struct usb_hcd *hcd) irq = 7; /* Only place we don't use the frame list routines */ - uhci->fl->frame[i] = UHCI_PTR_QH | + uhci->frame[i] = UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[irq]->dma_handle); } @@ -686,10 +694,14 @@ static int uhci_start(struct usb_hcd *hcd) dma_pool_destroy(uhci->td_pool); err_create_td_pool: - dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - uhci->fl, uhci->fl->dma_handle); + kfree(uhci->frame_cpu); -err_alloc_fl: +err_alloc_frame_cpu: + dma_free_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + uhci->frame, uhci->frame_dma_handle); + +err_alloc_frame: debugfs_remove(uhci->dentry); err_create_debug_entry: diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1c161b4f5bcf..b04d99df0a0e 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -359,7 +359,11 @@ struct uhci_hcd { struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ spinlock_t lock; - struct uhci_frame_list *fl; /* P: uhci->lock */ + + dma_addr_t frame_dma_handle; /* Hardware frame list */ + __le32 *frame; /* P: uhci->lock */ + void **frame_cpu; /* CPU's frame list */ + int fsbr; /* Full-speed bandwidth reclamation */ unsigned long fsbrtimeout; /* FSBR delay */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index d54038211ca6..51de06bc438d 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, td->frame = framenum; /* Is there a TD already mapped there? */ - if (uhci->fl->frame_cpu[framenum]) { + if (uhci->frame_cpu[framenum]) { struct uhci_td *ftd, *ltd; - ftd = uhci->fl->frame_cpu[framenum]; + ftd = uhci->frame_cpu[framenum]; ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); list_add_tail(&td->fl_list, &ftd->fl_list); @@ -101,10 +101,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, wmb(); ltd->link = cpu_to_le32(td->dma_handle); } else { - td->link = uhci->fl->frame[framenum]; + td->link = uhci->frame[framenum]; wmb(); - uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); - uhci->fl->frame_cpu[framenum] = td; + uhci->frame[framenum] = cpu_to_le32(td->dma_handle); + uhci->frame_cpu[framenum] = td; } } @@ -114,16 +114,16 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) if (td->frame == -1 && list_empty(&td->fl_list)) return; - if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { + if (td->frame != -1 && uhci->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { - uhci->fl->frame[td->frame] = td->link; - uhci->fl->frame_cpu[td->frame] = NULL; + uhci->frame[td->frame] = td->link; + uhci->frame_cpu[td->frame] = NULL; } else { struct uhci_td *ntd; ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); - uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); - uhci->fl->frame_cpu[td->frame] = ntd; + uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle); + uhci->frame_cpu[td->frame] = ntd; } } else { struct uhci_td *ptd; From e9b7bd4ee7f6e3ee002dc72c5211cd97c7186d00 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:30:48 -0700 Subject: [PATCH 1135/1939] [PATCH] one less word in struct device This saves a word from "struct device" ... there's a refcounting mechanism stub that's rather ineffective (the values are never even tested!), which can safely be deleted. With this patch it uses normal device refcounting, so any potential users of the pm_parent mechanism will be more correct. (That mechanism is actually unusable for now though; it does nothing.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/base/power/main.c | 26 +++----------------------- include/linux/pm.h | 1 - 2 files changed, 3 insertions(+), 24 deletions(-) --- drivers/base/power/main.c | 26 +++----------------------- include/linux/pm.h | 1 - 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 15e6a8f951f1..0d2e101e4f15 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -30,23 +30,6 @@ LIST_HEAD(dpm_off_irq); DECLARE_MUTEX(dpm_sem); DECLARE_MUTEX(dpm_list_sem); -/* - * PM Reference Counting. - */ - -static inline void device_pm_hold(struct device * dev) -{ - if (dev) - atomic_inc(&dev->power.pm_users); -} - -static inline void device_pm_release(struct device * dev) -{ - if (dev) - atomic_dec(&dev->power.pm_users); -} - - /** * device_pm_set_parent - Specify power dependency. * @dev: Device who needs power. @@ -62,10 +45,8 @@ static inline void device_pm_release(struct device * dev) void device_pm_set_parent(struct device * dev, struct device * parent) { - struct device * old_parent = dev->power.pm_parent; - device_pm_release(old_parent); - dev->power.pm_parent = parent; - device_pm_hold(parent); + put_device(dev->power.pm_parent); + dev->power.pm_parent = get_device(parent); } EXPORT_SYMBOL_GPL(device_pm_set_parent); @@ -75,7 +56,6 @@ int device_pm_add(struct device * dev) pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); - atomic_set(&dev->power.pm_users, 0); down(&dpm_list_sem); list_add_tail(&dev->power.entry, &dpm_active); device_pm_set_parent(dev, dev->parent); @@ -91,7 +71,7 @@ void device_pm_remove(struct device * dev) dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); down(&dpm_list_sem); dpm_sysfs_remove(dev); - device_pm_release(dev->power.pm_parent); + put_device(dev->power.pm_parent); list_del_init(&dev->power.entry); up(&dpm_list_sem); } diff --git a/include/linux/pm.h b/include/linux/pm.h index 7897cf500c51..83bae1cbe55b 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -224,7 +224,6 @@ struct dev_pm_info { unsigned should_wakeup:1; pm_message_t prev_state; void * saved_state; - atomic_t pm_users; struct device * pm_parent; struct list_head entry; #endif From 7ff71d6adf81a43505b7cbaa034e4063d3439182 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Thu, 22 Sep 2005 22:31:15 -0700 Subject: [PATCH 1136/1939] [PATCH] EHCI, split out PCI glue This splits BIOS and PCI specific support out of ehci-hcd.c into ehci-pci.c. It follows the model already used in the OHCI driver so support for non-PCI EHCI controllers can be more easily added. Signed-off-by: Matt Porter Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/host/ehci-hcd.c | 543 ++++++-------------------------------------- drivers/usb/host/ehci-pci.c | 414 +++++++++++++++++++++++++++++++++ drivers/usb/host/ehci.h | 1 3 files changed, 492 insertions(+), 466 deletions(-) --- drivers/usb/host/ehci-hcd.c | 559 ++++++------------------------------ drivers/usb/host/ehci-pci.c | 414 ++++++++++++++++++++++++++ drivers/usb/host/ehci.h | 1 + 3 files changed, 500 insertions(+), 474 deletions(-) create mode 100644 drivers/usb/host/ehci-pci.c diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 513fccbb8e43..af3c05eb86fc 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -300,44 +300,6 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } -#ifdef CONFIG_PCI - -/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... - * off the controller (maybe it can boot from highspeed USB disks). - */ -static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) -{ - struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - - /* always say Linux will own the hardware */ - pci_write_config_byte(pdev, where + 3, 1); - - /* maybe wait a while for BIOS to respond */ - if (cap & (1 << 16)) { - int msec = 5000; - - do { - msleep(10); - msec -= 10; - pci_read_config_dword(pdev, where, &cap); - } while ((cap & (1 << 16)) && msec); - if (cap & (1 << 16)) { - ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", - where, cap); - // some BIOS versions seem buggy... - // return 1; - ehci_warn (ehci, "continuing after BIOS bug...\n"); - /* disable all SMIs, and clear "BIOS owns" flag */ - pci_write_config_dword(pdev, where + 4, 0); - pci_write_config_byte(pdev, where + 2, 0); - } else - ehci_dbg(ehci, "BIOS handoff succeeded\n"); - } - return 0; -} - -#endif - /* Reboot notifiers kick in for silicon on any bus (not just pci, etc). * This forcibly disables dma and IRQs, helping kexec and other cases * where the next system software may expect clean state. @@ -371,156 +333,90 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) msleep(20); } +/*-------------------------------------------------------------------------*/ -/* called by khubd or root hub init threads */ - -static int ehci_hc_reset (struct usb_hcd *hcd) +/* + * ehci_work is called from some interrupts, timers, and so on. + * it calls driver completion functions, after dropping ehci->lock. + */ +static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) { - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp; - unsigned count = 256/4; + timer_action_done (ehci, TIMER_IO_WATCHDOG); + if (ehci->reclaim_ready) + end_unlink_async (ehci, regs); - spin_lock_init (&ehci->lock); + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; + scan_async (ehci, regs); + if (ehci->next_uframe != -1) + scan_periodic (ehci, regs); + ehci->scanning = 0; - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); - dbg_hcs_params (ehci, "reset"); - dbg_hcc_params (ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl (&ehci->caps->hcs_params); - -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - switch (pdev->vendor) { - case PCI_VENDOR_ID_TDI: - if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { - ehci->is_tdi_rh_tt = 1; - tdi_reset (ehci); - } - break; - case PCI_VENDOR_ID_AMD: - /* AMD8111 EHCI doesn't work, according to AMD errata */ - if (pdev->device == 0x7463) { - ehci_info (ehci, "ignoring AMD8111 (errata)\n"); - return -EIO; - } - break; - case PCI_VENDOR_ID_NVIDIA: - /* NVidia reports that certain chips don't handle - * QH, ITD, or SITD addresses above 2GB. (But TD, - * data buffer, and periodic schedule are normal.) - */ - switch (pdev->device) { - case 0x003c: /* MCP04 */ - case 0x005b: /* CK804 */ - case 0x00d8: /* CK8 */ - case 0x00e8: /* CK8S */ - if (pci_set_consistent_dma_mask(pdev, - DMA_31BIT_MASK) < 0) - ehci_warn (ehci, "can't enable NVidia " - "workaround for >2GB RAM\n"); - break; - } - break; - } - - /* optional debug port, normally in the first BAR */ - temp = pci_find_capability (pdev, 0x0a); - if (temp) { - pci_read_config_dword(pdev, temp, &temp); - temp >>= 16; - if ((temp & (3 << 13)) == (1 << 13)) { - temp &= 0x1fff; - ehci->debug = hcd->regs + temp; - temp = readl (&ehci->debug->control); - ehci_info (ehci, "debug port %d%s\n", - HCS_DEBUG_PORT(ehci->hcs_params), - (temp & DBGP_ENABLED) - ? " IN USE" - : ""); - if (!(temp & DBGP_ENABLED)) - ehci->debug = NULL; - } - } - - temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); - } else - temp = 0; - - /* EHCI 0.96 and later may have "extended capabilities" */ - while (temp && count--) { - u32 cap; - - pci_read_config_dword (to_pci_dev(hcd->self.controller), - temp, &cap); - ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); - switch (cap & 0xff) { - case 1: /* BIOS/SMM/... handoff */ - if (bios_handoff (ehci, temp, cap) != 0) - return -EOPNOTSUPP; - break; - case 0: /* illegal reserved capability */ - ehci_warn (ehci, "illegal capability!\n"); - cap = 0; - /* FALLTHROUGH */ - default: /* unknown */ - break; - } - temp = (cap >> 8) & 0xff; - } - if (!count) { - ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); - return -EIO; - } - if (ehci_is_TDI(ehci)) - ehci_reset (ehci); -#endif - - ehci_port_power (ehci, 0); - - /* at least the Genesys GL880S needs fixup here */ - temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); - temp &= 0x0f; - if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { - ehci_dbg (ehci, "bogus port configuration: " - "cc=%d x pcc=%d < ports=%d\n", - HCS_N_CC(ehci->hcs_params), - HCS_N_PCC(ehci->hcs_params), - HCS_N_PORTS(ehci->hcs_params)); - -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev; - - pdev = to_pci_dev(hcd->self.controller); - switch (pdev->vendor) { - case 0x17a0: /* GENESYS */ - /* GL880S: should be PORTS=2 */ - temp |= (ehci->hcs_params & ~0xf); - ehci->hcs_params = temp; - break; - case PCI_VENDOR_ID_NVIDIA: - /* NF4: should be PCC=10 */ - break; - } - } -#endif - } - - /* force HC to halt state */ - return ehci_halt (ehci); + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. + */ + if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && + (ehci->async->qh_next.ptr != NULL || + ehci->periodic_sched != 0)) + timer_action (ehci, TIMER_IO_WATCHDOG); } -static int ehci_start (struct usb_hcd *hcd) +static void ehci_stop (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + + ehci_dbg (ehci, "stop\n"); + + /* Turn off port power on all root hub ports. */ + ehci_port_power (ehci, 0); + + /* no more interrupts ... */ + del_timer_sync (&ehci->watchdog); + + spin_lock_irq(&ehci->lock); + if (HC_IS_RUNNING (hcd->state)) + ehci_quiesce (ehci); + + ehci_reset (ehci); + writel (0, &ehci->regs->intr_enable); + spin_unlock_irq(&ehci->lock); + + /* let companion controllers work when we aren't */ + writel (0, &ehci->regs->configured_flag); + unregister_reboot_notifier (&ehci->reboot_notifier); + + remove_debug_files (ehci); + + /* root hub is shut down separately (first, when possible) */ + spin_lock_irq (&ehci->lock); + if (ehci->async) + ehci_work (ehci, NULL); + spin_unlock_irq (&ehci->lock); + ehci_mem_cleanup (ehci); + +#ifdef EHCI_STATS + ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", + ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, + ehci->stats.lost_iaa); + ehci_dbg (ehci, "complete %ld unlink %ld\n", + ehci->stats.complete, ehci->stats.unlink); +#endif + + dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); +} + +static int ehci_run (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; int retval; u32 hcc_params; - u8 sbrn = 0; int first; /* skip some things on restart paths */ @@ -559,27 +455,6 @@ static int ehci_start (struct usb_hcd *hcd) } writel (ehci->periodic_dma, &ehci->regs->frame_list); -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev; - u16 port_wake; - - pdev = to_pci_dev(hcd->self.controller); - - /* Serial Bus Release Number is at PCI 0x60 offset */ - pci_read_config_byte(pdev, 0x60, &sbrn); - - /* port wake capability, reported by boot firmware */ - pci_read_config_word(pdev, 0x62, &port_wake); - hcd->can_wakeup = (port_wake & 1) != 0; - - /* help hc dma work well with cachelines */ - retval = pci_set_mwi(pdev); - if (retval) - ehci_dbg(ehci, "unable to enable MWI - not fatal.\n"); - } -#endif - /* * dedicate a qh for the async ring head, since we couldn't unlink * a 'real' qh without stopping the async schedule [4.8]. use it @@ -675,7 +550,7 @@ static int ehci_start (struct usb_hcd *hcd) temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x %s, EHCI %x.%02x, driver %s\n", - ((sbrn & 0xf0)>>4), (sbrn & 0x0f), + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), first ? "initialized" : "restarted", temp >> 8, temp & 0xff, DRIVER_VERSION); @@ -687,188 +562,6 @@ static int ehci_start (struct usb_hcd *hcd) return 0; } -/* always called by thread; normally rmmod */ - -static void ehci_stop (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - - ehci_dbg (ehci, "stop\n"); - - /* Turn off port power on all root hub ports. */ - ehci_port_power (ehci, 0); - - /* no more interrupts ... */ - del_timer_sync (&ehci->watchdog); - - spin_lock_irq(&ehci->lock); - if (HC_IS_RUNNING (hcd->state)) - ehci_quiesce (ehci); - - ehci_reset (ehci); - writel (0, &ehci->regs->intr_enable); - spin_unlock_irq(&ehci->lock); - - /* let companion controllers work when we aren't */ - writel (0, &ehci->regs->configured_flag); - unregister_reboot_notifier (&ehci->reboot_notifier); - - remove_debug_files (ehci); - - /* root hub is shut down separately (first, when possible) */ - spin_lock_irq (&ehci->lock); - if (ehci->async) - ehci_work (ehci, NULL); - spin_unlock_irq (&ehci->lock); - ehci_mem_cleanup (ehci); - -#ifdef EHCI_STATS - ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", - ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, - ehci->stats.lost_iaa); - ehci_dbg (ehci, "complete %ld unlink %ld\n", - ehci->stats.complete, ehci->stats.unlink); -#endif - - dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); -} - -static int ehci_get_frame (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -/* suspend/resume, section 4.3 */ - -/* These routines rely on the bus (pci, platform, etc) - * to handle powerdown and wakeup, and currently also on - * transceivers that don't need any software attention to set up - * the right sort of wakeup. - */ - -static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - - if (time_before (jiffies, ehci->next_statechange)) - msleep (100); - -#ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub); -#else - usb_lock_device (hcd->self.root_hub); - (void) ehci_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - // save (PCI) FLADJ in case of Vaux power loss - // ... we'd only use it to handle clock skew - - return 0; -} - -static int ehci_resume (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - unsigned port; - struct usb_device *root = hcd->self.root_hub; - int retval = -EINVAL; - - // maybe restore (PCI) FLADJ - - if (time_before (jiffies, ehci->next_statechange)) - msleep (100); - - /* If any port is suspended (or owned by the companion), - * we know we can/must resume the HC (and mustn't reset it). - */ - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { - u32 status; - port--; - status = readl (&ehci->regs->port_status [port]); - if (!(status & PORT_POWER)) - continue; - if (status & (PORT_SUSPEND | PORT_OWNER)) { - down (&hcd->self.root_hub->serialize); - retval = ehci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); - break; - } - if (!root->children [port]) - continue; - dbg_port (ehci, __FUNCTION__, port + 1, status); - usb_set_device_state (root->children[port], - USB_STATE_NOTATTACHED); - } - - /* Else reset, to cope with power loss or flush-to-storage - * style "resume" having activated BIOS during reboot. - */ - if (port == 0) { - (void) ehci_halt (ehci); - (void) ehci_reset (ehci); - (void) ehci_hc_reset (hcd); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq (&ehci->lock); - if (ehci->reclaim) - ehci->reclaim_ready = 1; - ehci_work (ehci, NULL); - spin_unlock_irq (&ehci->lock); - - /* restart; khubd will disconnect devices */ - retval = ehci_start (hcd); - - /* here we "know" root ports should always stay powered; - * but some controllers may lose all power. - */ - ehci_port_power (ehci, 1); - } - - return retval; -} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * ehci_work is called from some interrupts, timers, and so on. - * it calls driver completion functions, after dropping ehci->lock. - */ -static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) -{ - timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci, regs); - - /* another CPU may drop ehci->lock during a schedule scan while - * it reports urb completions. this flag guards against bogus - * attempts at re-entrant schedule scanning. - */ - if (ehci->scanning) - return; - ehci->scanning = 1; - scan_async (ehci, regs); - if (ehci->next_uframe != -1) - scan_periodic (ehci, regs); - ehci->scanning = 0; - - /* the IO watchdog guards against hardware or driver bugs that - * misplace IRQs, and should let us run completely without IRQs. - * such lossage has been observed on both VT6202 and VT8235. - */ - if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && - (ehci->async->qh_next.ptr != NULL || - ehci->periodic_sched != 0)) - timer_action (ehci, TIMER_IO_WATCHDOG); -} - /*-------------------------------------------------------------------------*/ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) @@ -1179,106 +872,24 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) return; } -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ehci_driver = { - .description = hcd_name, - .product_desc = "EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_hc_reset, - .start = ehci_start, -#ifdef CONFIG_PM - .suspend = ehci_suspend, - .resume = ehci_resume, -#endif - .stop = ehci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -}; +static int ehci_get_frame (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; +} /*-------------------------------------------------------------------------*/ -/* EHCI 1.0 doesn't require PCI */ - -#ifdef CONFIG_PCI - -/* PCI driver selection metadata; PCI hotplugging uses this */ -static const struct pci_device_id pci_ids [] = { { - /* handle any USB 2.0 EHCI controller */ - PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), - .driver_data = (unsigned long) &ehci_driver, - }, - { /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE (pci, pci_ids); - -/* pci driver glue; this is a "new style" PCI driver module */ -static struct pci_driver ehci_pci_driver = { - .name = (char *) hcd_name, - .id_table = pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif -}; - -#endif /* PCI */ - - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_DESCRIPTION (DRIVER_INFO); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_LICENSE ("GPL"); -static int __init init (void) -{ - if (usb_disabled()) - return -ENODEV; +#ifdef CONFIG_PCI +#include "ehci-pci.c" +#endif - pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", - hcd_name, - sizeof (struct ehci_qh), sizeof (struct ehci_qtd), - sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); - - return pci_register_driver (&ehci_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&ehci_pci_driver); -} -module_exit (cleanup); +#if !defined(CONFIG_PCI) +#error "missing bus glue for ehci-hcd" +#endif diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c new file mode 100644 index 000000000000..66ebf75b2037 --- /dev/null +++ b/drivers/usb/host/ehci-pci.c @@ -0,0 +1,414 @@ +/* + * EHCI HCD (Host Controller Driver) PCI Bus Glue. + * + * Copyright (c) 2000-2004 by 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. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CONFIG_PCI +#error "This file is PCI bus glue. CONFIG_PCI must be defined." +#endif + +/*-------------------------------------------------------------------------*/ + +/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... + * off the controller (maybe it can boot from highspeed USB disks). + */ +static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) +{ + struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); + + /* always say Linux will own the hardware */ + pci_write_config_byte(pdev, where + 3, 1); + + /* maybe wait a while for BIOS to respond */ + if (cap & (1 << 16)) { + int msec = 5000; + + do { + msleep(10); + msec -= 10; + pci_read_config_dword(pdev, where, &cap); + } while ((cap & (1 << 16)) && msec); + if (cap & (1 << 16)) { + ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", + where, cap); + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + /* disable all SMIs, and clear "BIOS owns" flag */ + pci_write_config_dword(pdev, where + 4, 0); + pci_write_config_byte(pdev, where + 2, 0); + } else + ehci_dbg(ehci, "BIOS handoff succeeded\n"); + } + return 0; +} + +/* called by khubd or root hub init threads */ +static int ehci_pci_reset (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp; + unsigned count = 256/4; + + spin_lock_init (&ehci->lock); + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); + dbg_hcs_params (ehci, "reset"); + dbg_hcc_params (ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl (&ehci->caps->hcs_params); + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + switch (pdev->vendor) { + case PCI_VENDOR_ID_TDI: + if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { + ehci->is_tdi_rh_tt = 1; + tdi_reset (ehci); + } + break; + case PCI_VENDOR_ID_AMD: + /* AMD8111 EHCI doesn't work, according to AMD errata */ + if (pdev->device == 0x7463) { + ehci_info (ehci, "ignoring AMD8111 (errata)\n"); + return -EIO; + } + break; + case PCI_VENDOR_ID_NVIDIA: + /* NVidia reports that certain chips don't handle + * QH, ITD, or SITD addresses above 2GB. (But TD, + * data buffer, and periodic schedule are normal.) + */ + switch (pdev->device) { + case 0x003c: /* MCP04 */ + case 0x005b: /* CK804 */ + case 0x00d8: /* CK8 */ + case 0x00e8: /* CK8S */ + if (pci_set_consistent_dma_mask(pdev, + DMA_31BIT_MASK) < 0) + ehci_warn (ehci, "can't enable NVidia " + "workaround for >2GB RAM\n"); + break; + } + break; + } + + /* optional debug port, normally in the first BAR */ + temp = pci_find_capability (pdev, 0x0a); + if (temp) { + pci_read_config_dword(pdev, temp, &temp); + temp >>= 16; + if ((temp & (3 << 13)) == (1 << 13)) { + temp &= 0x1fff; + ehci->debug = hcd->regs + temp; + temp = readl (&ehci->debug->control); + ehci_info (ehci, "debug port %d%s\n", + HCS_DEBUG_PORT(ehci->hcs_params), + (temp & DBGP_ENABLED) + ? " IN USE" + : ""); + if (!(temp & DBGP_ENABLED)) + ehci->debug = NULL; + } + } + + temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + } else + temp = 0; + + /* EHCI 0.96 and later may have "extended capabilities" */ + while (temp && count--) { + u32 cap; + + pci_read_config_dword (to_pci_dev(hcd->self.controller), + temp, &cap); + ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); + switch (cap & 0xff) { + case 1: /* BIOS/SMM/... handoff */ + if (bios_handoff (ehci, temp, cap) != 0) + return -EOPNOTSUPP; + break; + case 0: /* illegal reserved capability */ + ehci_warn (ehci, "illegal capability!\n"); + cap = 0; + /* FALLTHROUGH */ + default: /* unknown */ + break; + } + temp = (cap >> 8) & 0xff; + } + if (!count) { + ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); + return -EIO; + } + if (ehci_is_TDI(ehci)) + ehci_reset (ehci); + + ehci_port_power (ehci, 0); + + /* at least the Genesys GL880S needs fixup here */ + temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); + temp &= 0x0f; + if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { + ehci_dbg (ehci, "bogus port configuration: " + "cc=%d x pcc=%d < ports=%d\n", + HCS_N_CC(ehci->hcs_params), + HCS_N_PCC(ehci->hcs_params), + HCS_N_PORTS(ehci->hcs_params)); + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + + pdev = to_pci_dev(hcd->self.controller); + switch (pdev->vendor) { + case 0x17a0: /* GENESYS */ + /* GL880S: should be PORTS=2 */ + temp |= (ehci->hcs_params & ~0xf); + ehci->hcs_params = temp; + break; + case PCI_VENDOR_ID_NVIDIA: + /* NF4: should be PCC=10 */ + break; + } + } + } + + /* force HC to halt state */ + return ehci_halt (ehci); +} + +static int ehci_pci_start (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + int result = 0; + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + u16 port_wake; + + pdev = to_pci_dev(hcd->self.controller); + + /* Serial Bus Release Number is at PCI 0x60 offset */ + pci_read_config_byte(pdev, 0x60, &ehci->sbrn); + + /* port wake capability, reported by boot firmware */ + pci_read_config_word(pdev, 0x62, &port_wake); + hcd->can_wakeup = (port_wake & 1) != 0; + + /* help hc dma work well with cachelines */ + result = pci_set_mwi(pdev); + if (result) + ehci_dbg(ehci, "unable to enable MWI - not fatal.\n"); + } + + return ehci_run (hcd); +} + +/* always called by thread; normally rmmod */ + +static void ehci_pci_stop (struct usb_hcd *hcd) +{ + ehci_stop (hcd); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM + +/* suspend/resume, section 4.3 */ + +/* These routines rely on the bus (pci, platform, etc) + * to handle powerdown and wakeup, and currently also on + * transceivers that don't need any software attention to set up + * the right sort of wakeup. + */ + +static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + + if (time_before (jiffies, ehci->next_statechange)) + msleep (100); + +#ifdef CONFIG_USB_SUSPEND + (void) usb_suspend_device (hcd->self.root_hub); +#else + usb_lock_device (hcd->self.root_hub); + (void) ehci_hub_suspend (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + // save (PCI) FLADJ in case of Vaux power loss + // ... we'd only use it to handle clock skew + + return 0; +} + +static int ehci_pci_resume (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + unsigned port; + struct usb_device *root = hcd->self.root_hub; + int retval = -EINVAL; + + // maybe restore (PCI) FLADJ + + if (time_before (jiffies, ehci->next_statechange)) + msleep (100); + + /* If any port is suspended (or owned by the companion), + * we know we can/must resume the HC (and mustn't reset it). + */ + for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { + u32 status; + port--; + status = readl (&ehci->regs->port_status [port]); + if (!(status & PORT_POWER)) + continue; + if (status & (PORT_SUSPEND | PORT_OWNER)) { + down (&hcd->self.root_hub->serialize); + retval = ehci_hub_resume (hcd); + up (&hcd->self.root_hub->serialize); + break; + } + if (!root->children [port]) + continue; + dbg_port (ehci, __FUNCTION__, port + 1, status); + usb_set_device_state (root->children[port], + USB_STATE_NOTATTACHED); + } + + /* Else reset, to cope with power loss or flush-to-storage + * style "resume" having activated BIOS during reboot. + */ + if (port == 0) { + (void) ehci_halt (ehci); + (void) ehci_reset (ehci); + (void) ehci_pci_reset (hcd); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq (&ehci->lock); + if (ehci->reclaim) + ehci->reclaim_ready = 1; + ehci_work (ehci, NULL); + spin_unlock_irq (&ehci->lock); + + /* restart; khubd will disconnect devices */ + retval = ehci_run (hcd); + + /* here we "know" root ports should always stay powered; + * but some controllers may lose all power. + */ + ehci_port_power (ehci, 1); + } + + return retval; +} +#endif + +static const struct hc_driver ehci_pci_hc_driver = { + .description = hcd_name, + .product_desc = "EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_pci_reset, + .start = ehci_pci_start, +#ifdef CONFIG_PM + .suspend = ehci_pci_suspend, + .resume = ehci_pci_resume, +#endif + .stop = ehci_pci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .hub_suspend = ehci_hub_suspend, + .hub_resume = ehci_hub_resume, +}; + +/*-------------------------------------------------------------------------*/ + +/* PCI driver selection metadata; PCI hotplugging uses this */ +static const struct pci_device_id pci_ids [] = { { + /* handle any USB 2.0 EHCI controller */ + PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), + .driver_data = (unsigned long) &ehci_pci_hc_driver, + }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver ehci_pci_driver = { + .name = (char *) hcd_name, + .id_table = pci_ids, + + .probe = usb_hcd_pci_probe, + .remove = usb_hcd_pci_remove, + +#ifdef CONFIG_PM + .suspend = usb_hcd_pci_suspend, + .resume = usb_hcd_pci_resume, +#endif +}; + +static int __init ehci_hcd_pci_init (void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, + sizeof (struct ehci_qh), sizeof (struct ehci_qtd), + sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); + + return pci_register_driver (&ehci_pci_driver); +} +module_init (ehci_hcd_pci_init); + +static void __exit ehci_hcd_pci_cleanup (void) +{ + pci_unregister_driver (&ehci_pci_driver); +} +module_exit (ehci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index f34a0516d35f..18e257c2bdb5 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -97,6 +97,7 @@ struct ehci_hcd { /* one per controller */ #else # define COUNT(x) do {} while (0) #endif + u8 sbrn; /* packed release number */ }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ From 9293677af3dace2645dec0d0808efa02d36bf47b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:32:11 -0700 Subject: [PATCH 1137/1939] [PATCH] all HCDs provide root hub suspend/resume methods This cleans up a small recent FIXME, ensuring that all the HCDs provide root hub suspend/resume methods. It also wraps the calls to those root suspend routines just like on the PCI "USB_SUSPEND not defined" cases, so non-PCI bus glue won't be as tempted to behave very differently. Several of the SOC based OHCI drivers forgot to list those methods; the patch also adds those missing declarations. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hcd.c | 42 +++++++++++++++++++++++++--------------- drivers/usb/host/ohci-au1xxx.c | 5 ++++ drivers/usb/host/ohci-lh7a404.c | 5 ++++ drivers/usb/host/ohci-pxa27x.c | 1 drivers/usb/host/ohci-s3c2410.c | 1 drivers/usb/host/ohci-sa1111.c | 1 6 files changed, 40 insertions(+), 15 deletions(-) --- drivers/usb/core/hcd.c | 44 +++++++++++++++++++++------------ drivers/usb/host/ohci-au1xxx.c | 5 ++++ drivers/usb/host/ohci-lh7a404.c | 5 ++++ drivers/usb/host/ohci-pxa27x.c | 1 + drivers/usb/host/ohci-s3c2410.c | 1 + drivers/usb/host/ohci-sa1111.c | 1 + 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 5e8ade07d7f9..375382f9d671 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1431,28 +1431,44 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) /*-------------------------------------------------------------------------*/ -/* FIXME make this #ifdef CONFIG_PM ... update root hubs, retest */ - -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM static int hcd_hub_suspend (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_suspend) - return hcd->driver->hub_suspend (hcd); - return 0; + if (!hcd->driver->hub_suspend) + return -ENOENT; + hcd->state = HC_STATE_QUIESCING; + status = hcd->driver->hub_suspend (hcd); + if (status == 0) + hcd->state = HC_STATE_SUSPENDED; + else + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "suspend", status); + return status; } static int hcd_hub_resume (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_resume) - return hcd->driver->hub_resume (hcd); - return 0; + if (!hcd->driver->hub_resume) + return -ENOENT; + hcd->state = HC_STATE_RESUMING; + status = hcd->driver->hub_resume (hcd); + if (status == 0) + hcd->state = HC_STATE_RUNNING; + else { + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "resume", status); + usb_hc_died(hcd); + } + return status; } /** @@ -1473,14 +1489,10 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) usb_resume_root_hub (hcd->self.root_hub); spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } - -#else -void usb_hcd_resume_root_hub (struct usb_hcd *hcd) -{ -} -#endif EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); +#endif + /*-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_OTG @@ -1532,7 +1544,7 @@ static struct usb_operations usb_hcd_operations = { .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, .disable = hcd_endpoint_disable, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM .hub_suspend = hcd_hub_suspend, .hub_resume = hcd_hub_resume, #endif diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 3981bf15c8c7..550d67a554f6 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -214,6 +214,11 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .hub_suspend = ohci_hub_suspend, + .hub_resume = ohci_hub_resume, +#endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 859aca7be753..71d975ae78bd 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -193,6 +193,11 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .hub_suspend = ohci_hub_suspend, + .hub_resume = ohci_hub_resume, +#endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 986c4f656e22..2e7b48502a3d 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -282,6 +282,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 8cf12b2be2a3..922e2a6f46ef 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -452,6 +452,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /* device driver */ diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 7dd1f410b7f1..13324b7f9c59 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -239,6 +239,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = { .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ From 979d5199fee9e80290ddeb532e5993bd15506712 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:32:24 -0700 Subject: [PATCH 1138/1939] [PATCH] root hub changes (lesser half) This patch collects various small updates related to root hubs, to shrink later patches which build on them. - For root hub suspend/resume support: * Make the existing usb_hcd_resume_root_hub() routine respect pmcore locking, exporting and using the dpm_runtime_resume() method. * Add a new usb_hcd_suspend_root_hub() to pair with that routine. (Essential to make OHCI autosuspend behave again...) * HC_SUSPENDED by itself only refers to the root hub's downstream ports. So let HCDs see root hub URBs unless the parent device is suspended. - Remove an assertion we no longer need (and now, also don't want). - Generic suspend/resume updates to work better with swsusp. * Ignore the FREEZE vs SUSPEND distinction for hardware; trying to use it breaks the swsusp snapshots it's supposed to help (sigh). * On resume, mark devices as resumed right away, but then do nothing else if the device is marked NOTATTACHED. These changes shouldn't be very noticable by themselves. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/base/power/runtime.c | 1 drivers/usb/core/hcd.c | 64 ++++++++++++++++++++++++++++++++++++++----- drivers/usb/core/hcd.h | 1 drivers/usb/core/hub.c | 45 ++++++++++++++++++++++++------ drivers/usb/core/usb.c | 20 +++++++++---- drivers/usb/core/usb.h | 1 6 files changed, 111 insertions(+), 21 deletions(-) --- drivers/base/power/runtime.c | 1 + drivers/usb/core/hcd.c | 64 ++++++++++++++++++++++++++++++++---- drivers/usb/core/hcd.h | 1 + drivers/usb/core/hub.c | 45 ++++++++++++++++++++----- drivers/usb/core/usb.c | 20 +++++++---- drivers/usb/core/usb.h | 1 + 6 files changed, 111 insertions(+), 21 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index e8f0519f5dfa..adbc3148c039 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev) runtime_resume(dev); up(&dpm_sem); } +EXPORT_SYMBOL(dpm_runtime_resume); /** diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 375382f9d671..de59bb515315 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1143,10 +1143,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) else switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: +doit: usb_get_dev (urb->dev); list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; + case HC_STATE_SUSPENDED: + /* HC upstream links (register access, wakeup signaling) can work + * even when the downstream links (and DMA etc) are quiesced; let + * usbcore talk to the root hub. + */ + if (hcd->self.controller->power.power_state.event == PM_EVENT_ON + && urb->dev->parent == NULL) + goto doit; + /* FALL THROUGH */ default: status = -ESHUTDOWN; break; @@ -1294,12 +1304,6 @@ static int hcd_unlink_urb (struct urb *urb, int status) goto done; } - /* running ~= hc unlink handshake works (irq, timer, etc) - * halted ~= no unlink handshake is needed - * suspended, resuming == should never happen - */ - WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); - /* insist the urb is still queued */ list_for_each(tmp, &ep->urb_list) { if (tmp == &urb->urb_list) @@ -1459,6 +1463,8 @@ static int hcd_hub_resume (struct usb_bus *bus) hcd = container_of (bus, struct usb_hcd, self); if (!hcd->driver->hub_resume) return -ENOENT; + if (hcd->state == HC_STATE_RUNNING) + return 0; hcd->state = HC_STATE_RESUMING; status = hcd->driver->hub_resume (hcd); if (status == 0) @@ -1471,6 +1477,50 @@ static int hcd_hub_resume (struct usb_bus *bus) return status; } +/* + * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports + * @hcd: host controller for this root hub + * + * This call arranges that usb_hcd_resume_root_hub() is safe to call later; + * that the HCD's root hub polling is deactivated; and that the root's hub + * driver is suspended. HCDs may call this to autosuspend when their root + * hub's downstream ports are all inactive: unpowered, disconnected, + * disabled, or suspended. + * + * The HCD will autoresume on device connect change detection (using SRP + * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling + * from any ports that are suspended (if that is enabled). In most cases, + * overcurrent signaling (on powered ports) will also start autoresume. + * + * Always called with IRQs blocked. + */ +void usb_hcd_suspend_root_hub (struct usb_hcd *hcd) +{ + struct urb *urb; + + spin_lock (&hcd_root_hub_lock); + usb_suspend_root_hub (hcd->self.root_hub); + + /* force status urb to complete/unlink while suspended */ + if (hcd->status_urb) { + urb = hcd->status_urb; + urb->status = -ECONNRESET; + urb->hcpriv = NULL; + urb->actual_length = 0; + + del_timer (&hcd->rh_timer); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + } else + urb = NULL; + spin_unlock (&hcd_root_hub_lock); + hcd->state = HC_STATE_SUSPENDED; + + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); +} +EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub); + /** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub @@ -1478,7 +1528,7 @@ static int hcd_hub_resume (struct usb_bus *bus) * The USB host controller calls this function when its root hub is * suspended (with the remote wakeup feature enabled) and a remote * wakeup request is received. It queues a request for khubd to - * resume the root hub. + * resume the root hub (that is, manage its downstream ports again). */ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) { diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1f1ed6211af8..eb21f13c5c74 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -355,6 +355,7 @@ extern long usb_calc_bus_time (int speed, int is_input, extern struct usb_bus *usb_alloc_bus (struct usb_operations *); +extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_set_device_state(struct usb_device *udev, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 660064466791..3c8d8d1f993c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -449,11 +449,18 @@ static void hub_power_on(struct usb_hub *hub) msleep(max(pgood_delay, (unsigned) 100)); } -static void hub_quiesce(struct usb_hub *hub) +static inline void __hub_quiesce(struct usb_hub *hub) { - /* stop khubd and related activity */ + /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; hub->activating = 0; + hub->resume_root_hub = 0; +} + +static void hub_quiesce(struct usb_hub *hub) +{ + /* (blocking) stop khubd and related activity */ + __hub_quiesce(hub); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -467,6 +474,7 @@ static void hub_activate(struct usb_hub *hub) hub->quiescing = 0; hub->activating = 1; + hub->resume_root_hub = 0; status = usb_submit_urb(hub->urb, GFP_NOIO); if (status < 0) dev_err(hub->intfdev, "activate --> %d\n", status); @@ -1959,6 +1967,18 @@ static int hub_resume(struct usb_interface *intf) return 0; } +void usb_suspend_root_hub(struct usb_device *hdev) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + /* This also makes any led blinker stop retriggering. We're called + * from irq, so the blinker might still be scheduled. Caller promises + * that the root hub status URB will be canceled. + */ + __hub_quiesce(hub); + mark_quiesced(to_usb_interface(hub->intfdev)); +} + void usb_resume_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); @@ -2616,21 +2636,30 @@ static void hub_events(void) intf = to_usb_interface(hub->intfdev); hub_dev = &intf->dev; - dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", + i = hub->resume_root_hub; + + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n", hdev->state, hub->descriptor ? hub->descriptor->bNbrPorts : 0, /* NOTE: expects max 15 ports... */ (u16) hub->change_bits[0], - (u16) hub->event_bits[0]); + (u16) hub->event_bits[0], + i ? ", resume root" : ""); usb_get_intf(intf); - i = hub->resume_root_hub; spin_unlock_irq(&hub_event_lock); - /* Is this is a root hub wanting to be resumed? */ - if (i) - usb_resume_device(hdev); + /* Is this is a root hub wanting to reactivate the downstream + * ports? If so, be sure the interface resumes even if its + * stub "device" node was never suspended. + */ + if (i) { + extern void dpm_runtime_resume(struct device *); + + dpm_runtime_resume(&hdev->dev); + dpm_runtime_resume(&intf->dev); + } /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e89dbd43e952..2493e7d9f5b3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1427,6 +1427,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) /* USB devices enter SUSPEND state through their hubs, but can be * marked for FREEZE as soon as their children are already idled. + * But those semantics are useless, so we equate the two (sigh). */ if (dev->driver == &usb_generic_driver) { if (dev->power.power_state.event == message.event) @@ -1435,10 +1436,6 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) status = device_for_each_child(dev, NULL, verify_suspended); if (status) return status; - if (message.event == PM_EVENT_FREEZE) { - dev->power.power_state = message; - return 0; - } return usb_suspend_device (to_usb_device(dev)); } @@ -1471,14 +1468,22 @@ static int usb_generic_resume(struct device *dev) { struct usb_interface *intf; struct usb_driver *driver; + struct usb_device *udev; int status; if (dev->power.power_state.event == PM_EVENT_ON) return 0; + /* mark things as "on" immediately, no matter what errors crop up */ + dev->power.power_state.event = PM_EVENT_ON; + /* devices resume through their hubs */ - if (dev->driver == &usb_generic_driver) + if (dev->driver == &usb_generic_driver) { + udev = to_usb_device(dev); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; return usb_resume_device (to_usb_device(dev)); + } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) @@ -1487,11 +1492,14 @@ static int usb_generic_resume(struct device *dev) intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); + udev = interface_to_usbdev(intf); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; + /* if driver was suspended, it has a resume method; * however, sysfs can wrongly mark things as suspended * (on the "no suspend method" FIXME path above) */ - mark_active(intf); if (driver->resume) { status = driver->resume(intf); if (status) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3741a990403e..7add46ecc6a2 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -19,6 +19,7 @@ extern void usb_lock_all_devices(void); extern void usb_unlock_all_devices(void); extern void usb_kick_khubd(struct usb_device *dev); +extern void usb_suspend_root_hub(struct usb_device *hdev); extern void usb_resume_root_hub(struct usb_device *dev); extern int usb_hub_init(void); From f3f3253d644d36a2ea5464005a9c2cf28804d200 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:37:29 -0700 Subject: [PATCH 1139/1939] [PATCH] root hub updates (greater half) This patch associates hub suspend and resume logic (including for root hubs) with CONFIG_PM -- instead of CONFIG_USB_SUSPEND as before -- thereby unifying two troublesome versions of suspend logic into just one. It'll be easier to keep things right from now on. - Now usbcore _always_ calls hcd->hub_suspend as needed, instead of only when USB_SUSPEND is enabled: * Those root hub methods are now called from hub suspend/resume; no more skipping between layers during device suspend/resume; * It now handles cases allowed by sysfs or autosuspended root hubs, by forcing the hub interface to resume too. - All devices, including virtual root hubs, now get the same treatment on their resume paths ... including re-activating all their interfaces. Plus it gets rid of those stub copies of usb_{suspend,resume}_device(), and updates the Kconfig to match the new definition of USB_SUSPEND: it provides (a) selective suspend, downstream from hubs; and (b) remote wakeup, upstream from any device configuration which supports it. This calls for minor followup patches for most HCDs (and their PCI glue). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/Kconfig | 11 ++- drivers/usb/core/hub.c | 163 +++++++++++++++++++++++++---------------------- 2 files changed, 97 insertions(+), 77 deletions(-) --- drivers/usb/core/Kconfig | 11 ++- drivers/usb/core/hub.c | 163 +++++++++++++++++++++------------------ 2 files changed, 97 insertions(+), 77 deletions(-) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 1a9ff6184943..ff03184da403 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS If you are unsure about this, say N here. config USB_SUSPEND - bool "USB suspend/resume (EXPERIMENTAL)" + bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)" depends on USB && PM && EXPERIMENTAL help If you say Y here, you can use driver calls or the sysfs "power/state" file to suspend or resume individual USB - peripherals. There are many related features, such as - remote wakeup and driver-specific suspend processing, that - may not yet work as expected. + peripherals. + + Also, USB "remote wakeup" signaling is supported, whereby some + USB devices (like keyboards and network adapters) can wake up + their parent hub. That wakeup cascades up the USB tree, and + could wake the system from states like suspend-to-RAM. If you are unsure about this, say N here. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3c8d8d1f993c..6a601a4547e7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1612,7 +1612,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, */ static int __usb_suspend_device (struct usb_device *udev, int port1) { - int status; + int status = 0; /* caller owns the udev device lock */ if (port1 < 0) @@ -1638,21 +1638,10 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) } } - /* "global suspend" of the HC-to-USB interface (root hub), or - * "selective suspend" of just one hub-device link. + /* we only change a device's upstream USB link. + * root hubs have no upstream USB link. */ - if (!udev->parent) { - struct usb_bus *bus = udev->bus; - if (bus && bus->op->hub_suspend) { - status = bus->op->hub_suspend (bus); - if (status == 0) { - dev_dbg(&udev->dev, "usb suspend\n"); - usb_set_device_state(udev, - USB_STATE_SUSPENDED); - } - } else - status = -EOPNOTSUPP; - } else + if (udev->parent) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); @@ -1661,6 +1650,8 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) return status; } +#endif + /** * usb_suspend_device - suspend a usb device * @udev: device that's no longer in active use @@ -1683,6 +1674,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) */ int usb_suspend_device(struct usb_device *udev) { +#ifdef CONFIG_USB_SUSPEND int port1, status; port1 = locktree(udev); @@ -1692,8 +1684,14 @@ int usb_suspend_device(struct usb_device *udev) status = __usb_suspend_device(udev, port1); usb_unlock_device(udev); return status; +#else + /* NOTE: udev->state unchanged, it's not lying ... */ + udev->dev.power.power_state = PMSG_SUSPEND; + return 0; +#endif } + /* * If the USB "suspend" state is in use (rather than "global suspend"), * many devices will be individually taken out of suspend state using @@ -1702,13 +1700,13 @@ int usb_suspend_device(struct usb_device *udev) * resume (by host) or remote wakeup (by device) ... now see what changed * in the tree that's rooted at this device. */ -static int finish_port_resume(struct usb_device *udev) +static int finish_device_resume(struct usb_device *udev) { int status; u16 devstatus; /* caller owns the udev device lock */ - dev_dbg(&udev->dev, "usb resume\n"); + dev_dbg(&udev->dev, "finish resume\n"); /* usb ch9 identifies four variants of SUSPENDED, based on what * state the device resumes to. Linux currently won't see the @@ -1718,7 +1716,6 @@ static int finish_port_resume(struct usb_device *udev) usb_set_device_state(udev, udev->actconfig ? USB_STATE_CONFIGURED : USB_STATE_ADDRESS); - udev->dev.power.power_state = PMSG_ON; /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, @@ -1734,7 +1731,8 @@ static int finish_port_resume(struct usb_device *udev) int (*resume)(struct device *); le16_to_cpus(&devstatus); - if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP) + && udev->parent) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_CLEAR_FEATURE, @@ -1764,6 +1762,8 @@ static int finish_port_resume(struct usb_device *udev) return status; } +#ifdef CONFIG_USB_SUSPEND + static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) { @@ -1809,7 +1809,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* TRSMRCY = 10 msec */ msleep(10); if (udev) - status = finish_port_resume(udev); + status = finish_device_resume(udev); } } if (status < 0) @@ -1818,7 +1818,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) return status; } -static int hub_resume (struct usb_interface *intf); +#endif /** * usb_resume_device - re-activate a suspended usb device @@ -1841,35 +1841,22 @@ int usb_resume_device(struct usb_device *udev) if (port1 < 0) return port1; - /* "global resume" of the HC-to-USB interface (root hub), or - * selective resume of one hub-to-device port - */ - if (!udev->parent) { - struct usb_bus *bus = udev->bus; - if (bus && bus->op->hub_resume) { - status = bus->op->hub_resume (bus); +#ifdef CONFIG_USB_SUSPEND + /* selective resume of one downstream hub-to-device port */ + if (udev->parent) { + if (udev->state == USB_STATE_SUSPENDED) { + // NOTE swsusp may bork us, device state being wrong... + // NOTE this fails if parent is also suspended... + status = hub_port_resume(hdev_to_hub(udev->parent), + port1, udev); } else - status = -EOPNOTSUPP; - if (status == 0) { - dev_dbg(&udev->dev, "usb resume\n"); - /* TRSMRCY = 10 msec */ - msleep(10); - usb_set_device_state (udev, USB_STATE_CONFIGURED); - udev->dev.power.power_state = PMSG_ON; - status = hub_resume (udev - ->actconfig->interface[0]); - } - } else if (udev->state == USB_STATE_SUSPENDED) { - // NOTE this fails if parent is also suspended... - status = hub_port_resume(hdev_to_hub(udev->parent), - port1, udev); - } else { - status = 0; - } - if (status < 0) { + status = 0; + } else +#endif + status = finish_device_resume(udev); + if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); - } usb_unlock_device(udev); @@ -1886,6 +1873,8 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; +#ifdef CONFIG_USB_SUSPEND + /* don't repeat RESUME sequence if this device * was already woken up by some other task */ @@ -1894,9 +1883,10 @@ static int remote_wakeup(struct usb_device *udev) dev_dbg(&udev->dev, "RESUME (wakeup)\n"); /* TRSMRCY = 10 msec */ msleep(10); - status = finish_port_resume(udev); + status = finish_device_resume(udev); } up(&udev->serialize); +#endif return status; } @@ -1911,12 +1901,32 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && udev->state != USB_STATE_SUSPENDED) { + if (udev && (udev->dev.power.power_state.event + == PM_EVENT_ON +#ifdef CONFIG_USB_SUSPEND + || udev->state != USB_STATE_SUSPENDED +#endif + )) { dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); return -EBUSY; } } + /* "global suspend" of the downstream HC-to-USB interface */ + if (!hdev->parent) { + struct usb_bus *bus = hdev->bus; + if (bus && bus->op->hub_suspend) { + int status = bus->op->hub_suspend (bus); + + if (status != 0) { + dev_dbg(&hdev->dev, "'global' suspend %d\n", + status); + return status; + } + } else + return -EOPNOTSUPP; + } + /* stop khubd and related activity */ hub_quiesce(hub); return 0; @@ -1926,9 +1936,36 @@ static int hub_resume(struct usb_interface *intf) { struct usb_device *hdev = interface_to_usbdev(intf); struct usb_hub *hub = usb_get_intfdata (intf); - unsigned port1; int status; + /* "global resume" of the downstream HC-to-USB interface */ + if (!hdev->parent) { + struct usb_bus *bus = hdev->bus; + if (bus && bus->op->hub_resume) { + status = bus->op->hub_resume (bus); + if (status) { + dev_dbg(&intf->dev, "'global' resume %d\n", + status); + return status; + } + } else + return -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + } + } + + hub_activate(hub); + + /* REVISIT: this recursion probably shouldn't exist. Remove + * this code sometime, after retesting with different root and + * external hubs. + */ +#ifdef CONFIG_USB_SUSPEND + { + unsigned port1; + for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; u16 portstat, portchange; @@ -1953,7 +1990,7 @@ static int hub_resume(struct usb_interface *intf) if (portstat & USB_PORT_STAT_SUSPEND) status = hub_port_resume(hub, port1, udev); else { - status = finish_port_resume(udev); + status = finish_device_resume(udev); if (status < 0) { dev_dbg(&intf->dev, "resume port %d --> %d\n", port1, status); @@ -1962,8 +1999,8 @@ static int hub_resume(struct usb_interface *intf) } up(&udev->serialize); } - hub->resume_root_hub = 0; - hub_activate(hub); + } +#endif return 0; } @@ -1987,26 +2024,6 @@ void usb_resume_root_hub(struct usb_device *hdev) kick_khubd(hub); } -#else /* !CONFIG_USB_SUSPEND */ - -int usb_suspend_device(struct usb_device *udev) -{ - /* state does NOT lie by saying it's USB_STATE_SUSPENDED! */ - return 0; -} - -int usb_resume_device(struct usb_device *udev) -{ - udev->dev.power.power_state.event = PM_EVENT_ON; - return 0; -} - -#define hub_suspend NULL -#define hub_resume NULL -#define remote_wakeup(x) 0 - -#endif /* CONFIG_USB_SUSPEND */ - EXPORT_SYMBOL(usb_suspend_device); EXPORT_SYMBOL(usb_resume_device); From 5f827ea3c3820cd8e0a1a35e4d275c8b78ee94e1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:38:16 -0700 Subject: [PATCH 1140/1939] [PATCH] usbcore PCI glue updates for PM This updates the PCI glue to address the new and simplified usbcore suspend semantics, where CONFIG_USB_SUSPEND becomes irrelevant to HCDs because hcd->hub_suspend() will always be called. - Removes now-unneeded recursion support - Go back to ignoring faults reported by the wakeup calls; we expect them to fail sometimes, and that's just fine. The PCI HCDs will need simple changes to catch up to this, like being able to ignore the setting of CONFIG_USB_SUSPEND. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hcd-pci.c | 106 +++++++++++++++++++++------------------------ drivers/usb/core/hcd.h | 6 +- 2 files changed, 53 insertions(+), 59 deletions(-) --- drivers/usb/core/hcd-pci.c | 106 +++++++++++++++++-------------------- drivers/usb/core/hcd.h | 6 +-- 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 6385d1a99b60..84d9e69329bb 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -30,6 +30,8 @@ #include #include #include + +#include "usb.h" #include "hcd.h" @@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) hcd = pci_get_drvdata(dev); + /* Root hub suspend should have stopped all downstream traffic, + * and all bus master traffic. And done so for both the interface + * and the stub usb_device (which we check here). But maybe it + * didn't; writing sysfs power/state files ignores such rules... + * + * We must ignore the FREEZE vs SUSPEND distinction here, because + * otherwise the swsusp will save (and restore) garbage state. + */ + if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON) + return -EBUSY; + + if (hcd->driver->suspend) { + retval = hcd->driver->suspend(hcd, message); + if (retval) { + dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n", + retval); + goto done; + } + } + /* FIXME until the generic PM interfaces change a lot more, this * can't use PCI D1 and D2 states. For example, the confusion * between messages and states will need to vanish, and messages @@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) */ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); - switch (hcd->state) { - - /* entry if root hub wasn't yet suspended ... from sysfs, - * without autosuspend, or if USB_SUSPEND isn't configured. + /* Downstream ports from this root hub should already be quiesced, so + * there will be no DMA activity. Now we can shut down the upstream + * link (except maybe for PME# resume signaling) and enter some PCI + * low power state, if the hardware allows. */ - case HC_STATE_RUNNING: - hcd->state = HC_STATE_QUIESCING; - retval = hcd->driver->suspend (hcd, message); - if (retval) { - dev_dbg (hcd->self.controller, - "suspend fail, retval %d\n", - retval); - break; - } - hcd->state = HC_STATE_SUSPENDED; - /* FALLTHROUGH */ + if (hcd->state == HC_STATE_SUSPENDED) { - /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the - * controller and/or root hub will already have been suspended, - * but it won't be ready for a PCI resume call. - * - * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will - * have been called, otherwise root hub timers still run ... - */ - case HC_STATE_SUSPENDED: /* no DMA or IRQs except when HC is active */ if (dev->current_state == PCI_D0) { pci_save_state (dev); @@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) if (!has_pci_pm) { dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); - break; + goto done; } /* NOTE: dev->current_state becomes nonzero only here, and @@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) retval = pci_set_power_state (dev, PCI_D3hot); if (retval == 0) { dev_dbg (hcd->self.controller, "--> PCI D3\n"); - retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); - if (retval) - break; - retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); - } else if (retval < 0) { + + /* Ignore these return values. We rely on pci code to + * reject requests the hardware can't implement, rather + * than coding the same thing. + */ + (void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); + (void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); + } else { dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", retval); (void) usb_hcd_pci_resume (dev); - break; } - break; - default: + + } else { dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", hcd->state); WARN_ON(1); retval = -EINVAL; - break; } - /* update power_state **ONLY** to make sysfs happier */ +done: if (retval == 0) - dev->dev.power.power_state = message; + dev->dev.power.power_state = PMSG_SUSPEND; return retval; } EXPORT_SYMBOL (usb_hcd_pci_suspend); @@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) dev->current_state); } #endif - retval = pci_enable_wake (dev, dev->current_state, 0); - if (retval) { - dev_err(hcd->self.controller, - "can't enable_wake to %d, %d!\n", - dev->current_state, retval); - return retval; - } - retval = pci_enable_wake (dev, PCI_D3cold, 0); - if (retval) { - dev_err(hcd->self.controller, - "can't enable_wake to %d, %d!\n", - PCI_D3cold, retval); - return retval; - } + /* yes, ignore these results too... */ + (void) pci_enable_wake (dev, dev->current_state, 0); + (void) pci_enable_wake (dev, PCI_D3cold, 0); } else { /* Same basic cases: clean (powered/not), dirty */ dev_dbg(hcd->self.controller, "PCI legacy resume\n"); @@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev) dev->dev.power.power_state = PMSG_ON; - hcd->state = HC_STATE_RESUMING; hcd->saw_irq = 0; - retval = hcd->driver->resume (hcd); - if (!HC_IS_RUNNING (hcd->state)) { - dev_dbg (hcd->self.controller, - "resume fail, retval %d\n", retval); - usb_hc_died (hcd); + if (hcd->driver->resume) { + retval = hcd->driver->resume(hcd); + if (retval) { + dev_err (hcd->self.controller, + "PCI post-resume error %d!\n", retval); + usb_hc_died (hcd); + } } - retval = pci_enable_device(dev); return retval; } EXPORT_SYMBOL (usb_hcd_pci_resume); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index eb21f13c5c74..74757fc1a99f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -182,12 +182,12 @@ struct hc_driver { int (*start) (struct usb_hcd *hcd); /* NOTE: these suspend/resume calls relate to the HC as - * a whole, not just the root hub; they're for bus glue. + * a whole, not just the root hub; they're for PCI bus glue. */ - /* called after all devices were suspended */ + /* called after suspending the hub, before entering D3 etc */ int (*suspend) (struct usb_hcd *hcd, pm_message_t message); - /* called before any devices get resumed */ + /* called after entering D0 (etc), before resuming the hub */ int (*resume) (struct usb_hcd *hcd); /* cleanly make HCD stop writing memory and doing I/O */ From f197b2c54b9d9a133a9a8ff92f35cadf8945ea14 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:42:53 -0700 Subject: [PATCH 1141/1939] [PATCH] OHCI PM updates This simplifies the OHCI root hub suspend logic: - Uses new usbcore root hub calls to make autosuspend work again: * Uses a newish usbcore root hub wakeup mechanism, making requests to khubd not keventd. * Uses an even newer sibling suspend hook. - Expect someone always made usbcore call ohci_hub_suspend() before bus glue fires; and that ohci_hub_resume() is only called after that bus glue ran. Previously, only CONFIG_USB_SUSPEND promised those things. (Includes updates to PCI and OMAP bus glue.) - Handle a not-noticed-before special case during resume from one of the swsusp snapshots when using "usb-handoff": the controller isn't left in RESET state. (A bug to fix in the usb-handoff code...) Also cleans up a minor debug printk glitch, and switches an mdelay over to an msleep (how did that stick around for so long?). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/host/ohci-dbg.c | 4 ---- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-hub.c | 42 ++++++++++++------------------------------ drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-omap.c | 36 ++++++++++++------------------------ drivers/usb/host/ohci-pci.c | 40 ++++++++-------------------------------- drivers/usb/host/ohci.h | 1 - 7 files changed, 33 insertions(+), 93 deletions(-) --- drivers/usb/host/ohci-dbg.c | 4 ---- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-hub.c | 42 +++++++++++------------------------- drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-omap.c | 36 +++++++++++-------------------- drivers/usb/host/ohci-pci.c | 40 +++++++--------------------------- drivers/usb/host/ohci.h | 1 - 7 files changed, 33 insertions(+), 93 deletions(-) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 7924c74f958e..7bfffcbbd226 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -193,10 +193,6 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) maybe_print_eds (controller, "donehead", ohci_readl (controller, ®s->donehead), next, size); - - /* broken fminterval means traffic won't flow! */ - ohci_dbg (controller, "fminterval %08x\n", - ohci_readl (controller, ®s->fminterval)); } #define dbg_port_sw(hc,num,value,next,size) \ diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c26ab5f2a403..5c0c6c8a7a82 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -723,7 +723,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ohci_vdbg (ohci, "resume detect\n"); ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); if (hcd->state != HC_STATE_QUIESCING) - schedule_work(&ohci->rh_resume); + usb_hcd_resume_root_hub(hcd); } if (ints & OHCI_INTR_WDH) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index b96948ea3005..39a60e731ec2 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -73,7 +73,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ - hcd->state = HC_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; @@ -108,7 +107,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) else ohci->hc_control &= ~OHCI_CTRL_RWE; - /* Suspend hub */ + /* Suspend hub ... this is the "global (to this bus) suspend" mode, + * which doesn't imply ports will first be individually suspended. + */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); @@ -118,8 +119,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ohci->next_statechange = jiffies + msecs_to_jiffies (5); done: + /* external suspend vs self autosuspend ... same effect */ if (status == 0) - hcd->state = HC_STATE_SUSPENDED; + usb_hcd_suspend_root_hub(hcd); spin_unlock_irqrestore (&ohci->lock, flags); return status; } @@ -146,7 +148,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - /* this can happen after suspend-to-disk */ + /* this can happen after resuming a swsusp snapshot */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); @@ -169,11 +171,12 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: - ohci_dbg (ohci, "already resumed\n"); - status = 0; + /* this can happen after resuming a swsusp snapshot */ + ohci_dbg (ohci, "snapshot resume? reinit\n"); + status = -EBUSY; break; default: /* RESET, we lost power */ - ohci_dbg (ohci, "root hub hardware reset\n"); + ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } spin_unlock_irq (&ohci->lock); @@ -198,8 +201,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) } /* Some controllers (lucent erratum) need extra-long delays */ - hcd->state = HC_STATE_RESUMING; - mdelay (20 /* usb 11.5.1.10 */ + 15); + msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; @@ -273,27 +275,9 @@ static int ohci_hub_resume (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } - hcd->state = HC_STATE_RUNNING; return 0; } -static void ohci_rh_resume (void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - - usb_lock_device (hcd->self.root_hub); - (void) ohci_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -} - -#else - -static void ohci_rh_resume (void *_hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (_hcd); - ohci_dbg(ohci, "rh_resume ??\n"); -} - #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -367,7 +351,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) #ifdef CONFIG_PM /* save power by suspending idle root hubs; * INTR_RD wakes us when there's work - * NOTE: if we can do this, we don't need a root hub timer! */ if (can_suspend && !changed @@ -380,7 +363,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_hub_suspend (hcd); - hcd->state = HC_STATE_RUNNING; usb_unlock_device (hcd->self.root_hub); } #endif @@ -554,7 +536,7 @@ static int ohci_hub_control ( temp = RH_PS_POCI; if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) - schedule_work (&ohci->rh_resume); + usb_hcd_resume_root_hub(hcd); break; case USB_PORT_FEAT_C_SUSPEND: temp = RH_PS_PSSC; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 9fb83dfb1eb4..bfbe328a4788 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci)); ohci->reboot_notifier.notifier_call = ohci_reboot; } diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index e67c07dc426d..b3498b9b965f 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -458,41 +458,29 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) static int ohci_omap_suspend(struct device *dev, pm_message_t message) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = -EINVAL; - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_suspend(ohci_to_hcd(ohci)); - if (status == 0) { - omap_ohci_clock_power(0); - ohci_to_hcd(ohci)->self.root_hub->state = - USB_STATE_SUSPENDED; - ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = PMSG_SUSPEND; - } - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); - return status; + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->power.power_state = PMSG_SUSPEND; + return 0; } static int ohci_omap_resume(struct device *dev) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = 0; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; + omap_ohci_clock_power(1); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); -#else - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_resume(ohci_to_hcd(ohci)); - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); -#endif - if (status == 0) - dev->power.power_state = PMSG_ON; - return status; + dev->power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(dev_get_drvdata(dev)); + return 0; } #endif diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 0afa237b02ad..99a0ad41aec5 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -112,23 +112,13 @@ ohci_pci_start (struct usb_hcd *hcd) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); + /* root hub was already suspended */ - /* suspend root hub, hoping it keeps power during suspend */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); - -#ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub); -#else - usb_lock_device (hcd->self.root_hub); - (void) ohci_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - /* let things settle down a bit */ - msleep (100); - + /* FIXME these PMAC things get called in the wrong places. ASIC + * clocks should be turned off AFTER entering D3, and on BEFORE + * trying to enter D0. Evidently the PCI layer doesn't currently + * provide the right sort of platform hooks for this ... + */ #ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -145,9 +135,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) static int ohci_pci_resume (struct usb_hcd *hcd) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int retval = 0; - #ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -159,19 +146,8 @@ static int ohci_pci_resume (struct usb_hcd *hcd) } #endif /* CONFIG_PPC_PMAC */ - /* resume root hub */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - retval = usb_resume_device (hcd->self.root_hub); -#else - usb_lock_device (hcd->self.root_hub); - retval = ohci_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - return retval; + usb_hcd_resume_root_hub(hcd); + return 0; } #endif /* CONFIG_PM */ diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 8a9b9d9209e9..caacf14371f5 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -389,7 +389,6 @@ struct ohci_hcd { unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ - struct work_struct rh_resume; struct notifier_block reboot_notifier; unsigned long flags; /* for HC bugs */ From f2cb36c1df427431a8c6096b4ad113df767c1bd9 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:43:30 -0700 Subject: [PATCH 1142/1939] [PATCH] update PCI early-handoff handling for OHCI The PCI "early usb handoff" quirk logic didn't work like "ohci-hcd" ... This patch makes it do so by: - Resetting the controller after kicking BIOS off, matching the normal "chip in hardware reset" startup mode; - Reporting any BIOS that borks this simple handoff; it's likely got a few other surprises for us too. - Ignoring that handoff on HPPA; The diagnostic string is mostly shared with EHCI, saving a few bytes. Signed-off-by: Greg Kroah-Hartman drivers/usb/host/pci-quirks.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) --- drivers/usb/host/pci-quirks.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 8ee5c3ed4cd6..49f7381a6fd3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -60,6 +60,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, qui #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 #define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ #define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ #define OHCI_INTR_OC (1 << 30) /* ownership change */ @@ -140,13 +141,17 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; int wait_time; + u32 control; base = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (base == NULL) return; - if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time = 500; /* 0.5 seconds */ +/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ +#ifndef __hppa__ + control = readl(base + OHCI_CONTROL); + if (control & OHCI_CTRL_IR) { + wait_time = 500; /* arbitrary; 5 seconds */ writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); writel(OHCI_OCR, base + OHCI_CMDSTATUS); while (wait_time > 0 && @@ -154,7 +159,15 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) wait_time -= 10; msleep(10); } + if (wait_time <= 0) + printk(KERN_WARNING "%s %s: early BIOS handoff " + "failed (BIOS bug ?)\n", + pdev->dev.bus_id, "OHCI"); + + /* reset controller, preserving RWC */ + writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL); } +#endif /* * disable interrupts @@ -211,8 +224,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) /* * well, possibly buggy BIOS... */ - printk(KERN_WARNING "EHCI early BIOS handoff " - "failed (BIOS bug ?)\n"); + printk(KERN_WARNING "%s %s: early BIOS handoff " + "failed (BIOS bug ?)\n", + pdev->dev.bus_id, "EHCI"); pci_write_config_dword(pdev, hcc_params + EHCI_USBLEGSUP, EHCI_USBLEGSUP_OS); From a7f72abe8fac9b919135005e06216be8eef945a2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:44:56 -0700 Subject: [PATCH 1143/1939] [PATCH] UHCI PM updates This removes suspend and resume path recursion in UHCI. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/host/uhci-hcd.c | 9 --------- 1 file changed, 9 deletions(-) --- drivers/usb/host/uhci-hcd.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index b44094fcd779..34c9dbc6a156 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -762,11 +762,6 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) if (uhci->hc_inaccessible) /* Dead or already suspended */ goto done; -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - suspend_rh(uhci, UHCI_RH_SUSPENDED); -#endif - if (uhci->rh_state > UHCI_RH_SUSPENDED) { dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); hcd->state = HC_STATE_RUNNING; @@ -808,10 +803,6 @@ static int uhci_resume(struct usb_hcd *hcd) check_and_reset_hc(uhci); configure_hc(uhci); -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - wakeup_rh(uhci); -#endif if (uhci->rh_state == UHCI_RH_RESET) suspend_rh(uhci, UHCI_RH_SUSPENDED); From ccdcf77ae32e3d3347fdf3810b27f899e98c34fb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:45:13 -0700 Subject: [PATCH 1144/1939] [PATCH] ISP116x PM updates This makes the isp116x driver stop using usb_suspend_device() and usb_resume_device() ... usbcore now calls to the root hub methods, removing the need for this. It also switches from keventd to khubd for remote wakeup. (Compile tested.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/host/isp116x-hcd.c | 29 ++++------------------------- drivers/usb/host/isp116x.h | 1 - 2 files changed, 4 insertions(+), 26 deletions(-) --- drivers/usb/host/isp116x-hcd.c | 29 ++++------------------------- drivers/usb/host/isp116x.h | 1 - 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 554d60282a9d..f68220fc53fd 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -638,7 +638,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) + msecs_to_jiffies(20) + 1); if (intstat & HCINT_RD) { DBG("---- remote wakeup\n"); - schedule_work(&isp116x->rh_resume); + usb_hcd_resume_root_hub(hcd); ret = IRQ_HANDLED; } irqstat &= ~HCuPINT_OPR; @@ -1263,22 +1263,12 @@ static int isp116x_hub_resume(struct usb_hcd *hcd) return 0; } -static void isp116x_rh_resume(void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - - usb_resume_device(hcd->self.root_hub); -} #else #define isp116x_hub_suspend NULL #define isp116x_hub_resume NULL -static void isp116x_rh_resume(void *_hcd) -{ -} - #endif /*-----------------------------------------------------------------*/ @@ -1732,7 +1722,6 @@ static int __init isp116x_probe(struct device *dev) isp116x->addr_reg = addr_reg; spin_lock_init(&isp116x->lock); INIT_LIST_HEAD(&isp116x->async); - INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd); isp116x->board = dev->platform_data; if (!isp116x->board) { @@ -1777,16 +1766,10 @@ static int __init isp116x_probe(struct device *dev) static int isp116x_suspend(struct device *dev, pm_message_t state) { int ret = 0; - struct usb_hcd *hcd = dev_get_drvdata(dev); VDBG("%s: state %x\n", __func__, state); - ret = usb_suspend_device(hcd->self.root_hub); - if (!ret) { - dev->power.power_state = state; - INFO("%s suspended\n", hcd_name); - } else - ERR("%s suspend failed\n", hcd_name); + dev->power.power_state = state; return ret; } @@ -1797,15 +1780,11 @@ static int isp116x_suspend(struct device *dev, pm_message_t state) static int isp116x_resume(struct device *dev) { int ret = 0; - struct usb_hcd *hcd = dev_get_drvdata(dev); VDBG("%s: state %x\n", __func__, dev->power.power_state); - ret = usb_resume_device(hcd->self.root_hub); - if (!ret) { - dev->power.power_state = PMSG_ON; - VDBG("%s resumed\n", (char *)hcd_name); - } + dev->power.power_state = PMSG_ON; + return ret; } diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index 58873470dcf5..c6fec96785fe 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -253,7 +253,6 @@ static const int cc_to_error[16] = { struct isp116x { spinlock_t lock; - struct work_struct rh_resume; void __iomem *addr_reg; void __iomem *data_reg; From 5edbfb7c8af0577097dae87cdd4dfdba82bb9579 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 22 Sep 2005 22:45:26 -0700 Subject: [PATCH 1145/1939] [PATCH] stop exporting two functions The way we're looking at USB suspend lately doesn't expect drivers to call usb_suspend_device() or usb_resume_device() directly; that'll be implicit when no interfaces are in use. This patch removes those APIs from visibility outside usbcore. Signed-off-by: David Brownell drivers/usb/core/hub.c | 12 ++++-------- drivers/usb/core/usb.h | 4 ++++ include/linux/usb.h | 5 ----- 3 files changed, 8 insertions(+), 13 deletions(-) --- drivers/usb/core/hub.c | 12 ++++-------- drivers/usb/core/usb.h | 4 ++++ include/linux/usb.h | 5 ----- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6a601a4547e7..15db5e490aa2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1652,10 +1652,10 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) #endif -/** +/* * usb_suspend_device - suspend a usb device * @udev: device that's no longer in active use - * Context: must be able to sleep; device not locked + * Context: must be able to sleep; device not locked; pm locks held * * Suspends a USB device that isn't in active use, conserving power. * Devices may wake out of a suspend, if anything important happens, @@ -1820,10 +1820,10 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) #endif -/** +/* * usb_resume_device - re-activate a suspended usb device * @udev: device to re-activate - * Context: must be able to sleep; device not locked + * Context: must be able to sleep; device not locked; pm locks held * * This will re-activate the suspended device, increasing power usage * while letting drivers communicate again with its endpoints. @@ -2024,10 +2024,6 @@ void usb_resume_root_hub(struct usb_device *hdev) kick_khubd(hub); } -EXPORT_SYMBOL(usb_suspend_device); -EXPORT_SYMBOL(usb_resume_device); - - /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 7add46ecc6a2..4d59f6e07999 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -29,6 +29,10 @@ extern void usb_major_cleanup(void); extern int usb_host_init(void); extern void usb_host_cleanup(void); +extern int usb_suspend_device(struct usb_device *dev); +extern int usb_resume_device(struct usb_device *dev); + + /* Interfaces and their "power state" are owned by usbcore */ static inline void mark_active(struct usb_interface *f) diff --git a/include/linux/usb.h b/include/linux/usb.h index 25ec91ddcd04..207b1ad9d990 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -975,11 +975,6 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout); -/* selective suspend/resume */ -extern int usb_suspend_device(struct usb_device *dev); -extern int usb_resume_device(struct usb_device *dev); - - /* wrappers around usb_control_msg() for the most common standard requests */ extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size); From b13296c6617f22e8c0174a7af32780617db0e680 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 27 Sep 2005 10:38:54 -0700 Subject: [PATCH 1146/1939] [PATCH] updates for "controller suspended" handling Reject URBs to _all_ devices when their host controllers are suspended; even root hub registers will be unavailable. Also, don't reject urbs to root hubs in other cases; the only upstream link is through that controller (on PCI or whatever SOC bus is in use). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hcd.c | 28 ++++++++++++---------------- drivers/usb/core/urb.c | 3 ++- 2 files changed, 14 insertions(+), 17 deletions(-) --- drivers/usb/core/hcd.c | 28 ++++++++++++---------------- drivers/usb/core/urb.c | 3 ++- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index de59bb515315..b7bb8dd1894a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -458,22 +458,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) default: /* non-generic request */ - if (HC_IS_SUSPENDED (hcd->state)) - status = -EAGAIN; - else { - switch (typeReq) { - case GetHubStatus: - case GetPortStatus: - len = 4; - break; - case GetHubDescriptor: - len = sizeof (struct usb_hub_descriptor); - break; - } - status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - tbuf, wLength); + switch (typeReq) { + case GetHubStatus: + case GetPortStatus: + len = 4; + break; + case GetHubDescriptor: + len = sizeof (struct usb_hub_descriptor); + break; } + status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + tbuf, wLength); break; error: /* "protocol stall" on error */ @@ -487,7 +483,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) "CTRL: TypeReq=0x%x val=0x%x " "idx=0x%x len=%d ==> %d\n", typeReq, wValue, wIndex, - wLength, urb->status); + wLength, status); } } if (len) { diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index b32898e0a27d..f2a1fed2a802 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -237,7 +237,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) (dev->state < USB_STATE_DEFAULT) || (!dev->bus) || (dev->devnum <= 0)) return -ENODEV; - if (dev->state == USB_STATE_SUSPENDED) + if (dev->bus->controller->power.power_state.event != PM_EVENT_ON + || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; if (!(op = dev->bus->op) || !op->submit_urb) return -ENODEV; From d09d36a91c70cb3cc609d693bf6a7e7a266ff9e6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Sep 2005 16:22:45 -0400 Subject: [PATCH 1147/1939] [PATCH] USB: usb_bulk_message() handles interrupts endpoints Because there is no bulk_interrupt_message() routine and no USBDEVFS_INTERRUPT ioctl, people have been forced to abuse the usb_bulk_message() routine and USBDEVFS_BULK by using them for interrupt transfers as well as bulk transfers. This patch (as567) formalizes this practice and adds code to usb_bulk_message() for detecting when the target is really an interrupt endpoint. If it is, the routine submits an interrupt URB (using the default interval) instead of a bulk URB. In theory this should help HCDs that don't like it when people try to mix transfer types, queuing both periodic and non-periodic types for the same endpoint. Not fully tested -- I don't have any programs that use USBDEVFS_BULK for interrupt transfers -- but it compiles okay and normal bulk messages work as well as before. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/core/message.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) --- drivers/usb/core/message.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ebf59ea99263..574d0d4b3401 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -187,21 +187,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * 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. + * + * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT + * ioctl, users are forced to abuse this routine by using it to submit + * URBs for interrupt endpoints. We will take the liberty of creating + * an interrupt URB (with the default interval) if the target is an + * interrupt endpoint. */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) { struct urb *urb; + struct usb_host_endpoint *ep; - if (len < 0) + ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out) + [usb_pipeendpoint(pipe)]; + if (!ep || len < 0) return -EINVAL; - urb=usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; - usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, NULL); + if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT) { + pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); + usb_fill_int_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL, + ep->desc.bInterval); + } else + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL); return usb_start_wait_urb(urb, timeout, actual_length); } From 8b262bd25580e165710e8a27df19cd60c2ef58a3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Sep 2005 16:31:15 -0400 Subject: [PATCH 1148/1939] [PATCH] USB: UHCI: Spruce up some comments This patch (as570) changes some comments in the uhci-hcd header file and removes an unused declaration (something I forgot to erase in an earlier patch). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/host/uhci-hcd.h | 91 +++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 42 deletions(-) --- drivers/usb/host/uhci-hcd.h | 91 ++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index b04d99df0a0e..e576db57a926 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -7,6 +7,7 @@ #define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT) #define PIPE_DEVEP_MASK 0x0007ff00 + /* * Universal Host Controller Interface data structures and defines */ @@ -82,15 +83,10 @@ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ -struct uhci_frame_list { - __le32 frame[UHCI_NUMFRAMES]; - void *frame_cpu[UHCI_NUMFRAMES]; - - dma_addr_t dma_handle; -}; - -struct urb_priv; +/* + * Queue Headers + */ /* * One role of a QH is to hold a queue of TDs for some endpoint. Each QH is @@ -116,13 +112,13 @@ struct uhci_qh { struct urb_priv *urbp; - struct list_head list; /* P: uhci->frame_list_lock */ - struct list_head remove_list; /* P: uhci->remove_list_lock */ + struct list_head list; + struct list_head remove_list; } __attribute__((aligned(16))); /* * We need a special accessor for the element pointer because it is - * subject to asynchronous updates by the controller + * subject to asynchronous updates by the controller. */ static __le32 inline qh_element(struct uhci_qh *qh) { __le32 element = qh->element; @@ -131,6 +127,11 @@ static __le32 inline qh_element(struct uhci_qh *qh) { return element; } + +/* + * Transfer Descriptors + */ + /* * for TD : */ @@ -183,17 +184,10 @@ static __le32 inline qh_element(struct uhci_qh *qh) { * * That's silly, the hardware doesn't care. The hardware only cares that * the hardware words are 16-byte aligned, and we can have any amount of - * sw space after the TD entry as far as I can tell. - * - * But let's just go with the documentation, at least for 32-bit machines. - * On 64-bit machines we probably want to take advantage of the fact that - * hw doesn't really care about the size of the sw-only area. - * - * Alas, not anymore, we have more than 4 words for software, woops. - * Everything still works tho, surprise! -jerdfelt + * sw space after the TD entry. * * td->link points to either another TD (not necessarily for the same urb or - * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs) + * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs). */ struct uhci_td { /* Hardware fields */ @@ -205,16 +199,16 @@ struct uhci_td { /* Software fields */ dma_addr_t dma_handle; - struct list_head list; /* P: urb->lock */ - struct list_head remove_list; /* P: uhci->td_remove_list_lock */ + struct list_head list; + struct list_head remove_list; int frame; /* for iso: what frame? */ - struct list_head fl_list; /* P: uhci->frame_list_lock */ + struct list_head fl_list; } __attribute__((aligned(16))); /* * We need a special accessor for the control/status word because it is - * subject to asynchronous updates by the controller + * subject to asynchronous updates by the controller. */ static u32 inline td_status(struct uhci_td *td) { __le32 status = td->status; @@ -224,6 +218,10 @@ static u32 inline td_status(struct uhci_td *td) { } +/* + * Skeleton Queue Headers + */ + /* * The UHCI driver places Interrupt, Control and Bulk into QH's both * to group together TD's for one transfer, and also to faciliate queuing @@ -254,15 +252,15 @@ static u32 inline td_status(struct uhci_td *td) { * * The terminating QH is used for 2 reasons: * - To place a terminating TD which is used to workaround a PIIX bug - * (see Intel errata for explanation) + * (see Intel errata for explanation), and * - To loop back to the full-speed control queue for full-speed bandwidth - * reclamation + * reclamation. * * Isochronous transfers are stored before the start of the skeleton * schedule and don't use QH's. While the UHCI spec doesn't forbid the - * use of QH's for Isochronous, it doesn't use them either. Since we don't - * need to use them either, we follow the spec diagrams in hope that it'll - * be more compatible with future UHCI implementations. + * use of QH's for Isochronous, it doesn't use them either. And the spec + * says that queues never advance on an error completion status, which + * makes them totally unsuitable for Isochronous transfers. */ #define UHCI_NUM_SKELQH 12 @@ -312,8 +310,13 @@ static inline int __interval_to_skel(int interval) return 0; /* int128 for 128-255 ms (Max.) */ } + /* - * States for the root hub. + * The UHCI controller and root hub + */ + +/* + * States for the root hub: * * To prevent "bouncing" in the presence of electrical noise, * when there are no devices attached we delay for 1 second in the @@ -324,7 +327,7 @@ static inline int __interval_to_skel(int interval) */ enum uhci_rh_state { /* In the following states the HC must be halted. - * These two must come first */ + * These two must come first. */ UHCI_RH_RESET, UHCI_RH_SUSPENDED, @@ -336,13 +339,13 @@ enum uhci_rh_state { UHCI_RH_SUSPENDING, /* In the following states it's an error if the HC is halted. - * These two must come last */ + * These two must come last. */ UHCI_RH_RUNNING, /* The normal state */ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ }; /* - * This describes the full uhci information. + * The full UHCI controller information: */ struct uhci_hcd { @@ -361,7 +364,7 @@ struct uhci_hcd { spinlock_t lock; dma_addr_t frame_dma_handle; /* Hardware frame list */ - __le32 *frame; /* P: uhci->lock */ + __le32 *frame; void **frame_cpu; /* CPU's frame list */ int fsbr; /* Full-speed bandwidth reclamation */ @@ -387,22 +390,22 @@ struct uhci_hcd { unsigned long ports_timeout; /* Time to stop signalling */ /* Main list of URB's currently controlled by this HC */ - struct list_head urb_list; /* P: uhci->lock */ + struct list_head urb_list; /* List of QH's that are done, but waiting to be unlinked (race) */ - struct list_head qh_remove_list; /* P: uhci->lock */ + struct list_head qh_remove_list; unsigned int qh_remove_age; /* Age in frames */ /* List of TD's that are done, but waiting to be freed (race) */ - struct list_head td_remove_list; /* P: uhci->lock */ + struct list_head td_remove_list; unsigned int td_remove_age; /* Age in frames */ /* List of asynchronously unlinked URB's */ - struct list_head urb_remove_list; /* P: uhci->lock */ + struct list_head urb_remove_list; unsigned int urb_remove_age; /* Age in frames */ /* List of URB's awaiting completion callback */ - struct list_head complete_list; /* P: uhci->lock */ + struct list_head complete_list; int rh_numports; /* Number of root-hub ports */ @@ -421,13 +424,17 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) + +/* + * Private per-URB data + */ struct urb_priv { struct list_head urb_list; struct urb *urb; struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; /* P: urb->lock */ + struct list_head td_list; unsigned fsbr : 1; /* URB turned on FSBR */ unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -438,9 +445,10 @@ struct urb_priv { unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; /* P: uhci->frame_list_lock */ + struct list_head queue_list; }; + /* * Locking in uhci.c * @@ -460,6 +468,5 @@ struct urb_priv { #define PCI_VENDOR_ID_GENESYS 0x17a0 #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 -#define PCI_DEVICE_ID_GL880S_EHCI 0x8084 #endif From dabb592816444fcba1a771e27d4f72a2b8218374 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 22 Sep 2005 23:55:22 -0700 Subject: [PATCH 1149/1939] [PATCH] USB: sisusb warning fix drivers/usb/misc/sisusbvga/sisusb.c: In function `sisusb_reset_text_mode': drivers/usb/misc/sisusbvga/sisusb.c:2461: warning: assignment discards qualifiers from pointer target type Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman drivers/usb/misc/sisusbvga/sisusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- drivers/usb/misc/sisusbvga/sisusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 222ae9cd4c7c..c946c9a538a0 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2440,7 +2440,7 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) { int ret = 0, slot = sisusb->font_slot, i; - struct font_desc *myfont; + const struct font_desc *myfont; u8 *tempbuf; u16 *tempbufb; size_t written; From 22efcf4adec4262e0f49e6225f6cd070e4a85d20 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Sep 2005 16:12:02 -0400 Subject: [PATCH 1150/1939] [PATCH] USB: File-Storage gadget: use the kthread API This patch (as566) converts the File-Storage gadget over to the kthread API. The new code doesn't use kthread_stop because the control thread needs to terminate asynchronously when it receives a signal. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/gadget/file_storage.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) --- drivers/usb/gadget/file_storage.c | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a41d9d4baee3..241c570e541c 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -224,6 +224,7 @@ #include #include #include +#include #include #include #include @@ -669,7 +670,6 @@ struct fsg_dev { wait_queue_head_t thread_wqh; int thread_wakeup_needed; struct completion thread_notifier; - int thread_pid; struct task_struct *thread_task; sigset_t thread_signal_mask; @@ -1084,7 +1084,6 @@ static void wakeup_thread(struct fsg_dev *fsg) static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) { unsigned long flags; - struct task_struct *thread_task; /* Do nothing if a higher-priority exception is already in progress. * If a lower-or-equal priority exception is in progress, preempt it @@ -1093,9 +1092,9 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) if (fsg->state <= new_state) { fsg->exception_req_tag = fsg->ep0_req_tag; fsg->state = new_state; - thread_task = fsg->thread_task; - if (thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task); + if (fsg->thread_task) + send_sig_info(SIGUSR1, SEND_SIG_FORCED, + fsg->thread_task); } spin_unlock_irqrestore(&fsg->lock, flags); } @@ -3383,11 +3382,6 @@ static int fsg_main_thread(void *fsg_) { struct fsg_dev *fsg = (struct fsg_dev *) fsg_; - fsg->thread_task = current; - - /* Release all our userspace resources */ - daemonize("file-storage-gadget"); - /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | @@ -3400,9 +3394,6 @@ static int fsg_main_thread(void *fsg_) * that expects a __user pointer and it will work okay. */ set_fs(get_ds()); - /* Wait for the gadget registration to finish up */ - wait_for_completion(&fsg->thread_notifier); - /* The main loop */ while (fsg->state != FSG_STATE_TERMINATED) { if (exception_in_progress(fsg) || signal_pending(current)) { @@ -3440,8 +3431,9 @@ static int fsg_main_thread(void *fsg_) spin_unlock_irq(&fsg->lock); } + spin_lock_irq(&fsg->lock); fsg->thread_task = NULL; - flush_signals(current); + spin_unlock_irq(&fsg->lock); /* In case we are exiting because of a signal, unregister the * gadget driver and close the backing file. */ @@ -3959,10 +3951,12 @@ static int __init fsg_bind(struct usb_gadget *gadget) sprintf(&serial[i], "%02X", c); } - if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS | - CLONE_FILES))) < 0) + fsg->thread_task = kthread_create(fsg_main_thread, fsg, + "file-storage-gadget"); + if (IS_ERR(fsg->thread_task)) { + rc = PTR_ERR(fsg->thread_task); goto out; - fsg->thread_pid = rc; + } INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); @@ -3994,7 +3988,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", mod_data.removable, mod_data.can_stall, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); + DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); return 0; autoconf_fail: @@ -4093,7 +4087,7 @@ static int __init fsg_init(void) set_bit(REGISTERED, &fsg->atomic_bitflags); /* Tell the thread to start working */ - complete(&fsg->thread_notifier); + wake_up_process(fsg->thread_task); return 0; } module_init(fsg_init); From 74ad9bd2fcf0fa203655e0d904809b06c4202bf8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1151/1939] [PATCH] USB: make wHubCharacteristics __le16 to match other usb descriptor fields Also has the nice benefit of making sparc alignment issues go away. Thanks to David Miller for pointing out the problems here. Signed-off-by: Greg Kroah-Hartman drivers/usb/core/hub.c | 22 ++++++++++++---------- drivers/usb/core/hub.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) --- drivers/usb/core/hub.c | 22 ++++++++++++---------- drivers/usb/core/hub.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 15db5e490aa2..e2802bf18095 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -436,9 +436,10 @@ static void hub_power_on(struct usb_hub *hub) { int port1; unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; + u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); /* if hub supports power switching, enable power on each port */ - if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) { dev_dbg(hub->intfdev, "enabling power on all ports\n"); for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) set_port_feature(hub->hdev, port1, @@ -525,6 +526,7 @@ static int hub_configure(struct usb_hub *hub, struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; u16 hubstatus, hubchange; + u16 wHubCharacteristics; unsigned int pipe; int maxp, ret; char *message; @@ -570,9 +572,9 @@ static int hub_configure(struct usb_hub *hub, dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, (hdev->maxchild == 1) ? "" : "s"); - le16_to_cpus(&hub->descriptor->wHubCharacteristics); + wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) { + if (wHubCharacteristics & HUB_CHAR_COMPOUND) { int i; char portstr [USB_MAXCHILDREN + 1]; @@ -585,7 +587,7 @@ static int hub_configure(struct usb_hub *hub, } else dev_dbg(hub_dev, "standalone hub\n"); - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { + switch (wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: dev_dbg(hub_dev, "ganged power switching\n"); break; @@ -598,7 +600,7 @@ static int hub_configure(struct usb_hub *hub, break; } - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { + switch (wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: dev_dbg(hub_dev, "global over-current protection\n"); break; @@ -638,7 +640,7 @@ static int hub_configure(struct usb_hub *hub, } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { + switch (wHubCharacteristics & HUB_CHAR_TTTT) { case HUB_TTTT_8_BITS: if (hdev->descriptor.bDeviceProtocol != 0) { hub->tt.think_time = 666; @@ -668,7 +670,7 @@ static int hub_configure(struct usb_hub *hub, } /* probe() zeroes hub->indicator[] */ - if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) { + if (wHubCharacteristics & HUB_CHAR_PORTIND) { hub->has_indicators = 1; dev_dbg(hub_dev, "Port indicators are supported\n"); } @@ -713,7 +715,7 @@ static int hub_configure(struct usb_hub *hub, (hubstatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); - if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0) + if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0) dev_dbg(hub_dev, "%sover-current condition exists\n", (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); @@ -2432,6 +2434,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; + u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); int status, i; dev_dbg (hub_dev, @@ -2469,8 +2472,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (!(portstatus & USB_PORT_STAT_CONNECTION)) { /* maybe switch power back on (e.g. root hub was reset) */ - if ((hub->descriptor->wHubCharacteristics - & HUB_CHAR_LPSM) < 2 + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 && !(portstatus & (1 << USB_PORT_FEAT_POWER))) set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index e7fa9b5a521e..bf23f8978024 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -131,7 +131,7 @@ struct usb_hub_descriptor { __u8 bDescLength; __u8 bDescriptorType; __u8 bNbrPorts; - __u16 wHubCharacteristics; + __le16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; /* add 1 bit for hub status change; round to bytes */ From 207c47e1fbc8d51500997bfa67c26c00114fab04 Mon Sep 17 00:00:00 2001 From: Thomas Riewe Date: Thu, 29 Sep 2005 14:57:29 +0200 Subject: [PATCH 1152/1939] [PATCH] drivers/usb/serial/ftdi_sio: add PID/VID We would like to add a PID for the Pyramid Appliance Display, which works on USB via FTDI_SIO. Signed-off-by: Thomas Riewe Signed-off-by: Greg Kroah-Hartman drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 3 +++ 2 files changed, 4 insertions(+) --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8c12a0acf10d..b713113c1650 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -411,6 +411,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, /* * These will probably use user-space drivers. Uncomment them if * you need them or use the user-specified vendor/product module diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 7c65d46c7598..ddb63df31ce6 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -342,6 +342,9 @@ #define EVOLUTION_VID 0xDEEE /* Vendor ID */ #define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ +/* Pyramid Computer GmbH */ +#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ From ddcad752f206be7a0091a041403c3188f2febd16 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Mon, 3 Oct 2005 17:24:11 +0300 Subject: [PATCH 1153/1939] [PATCH] pegasus.h This one is a tiny patch adding one more device to the list. Please apply. :) Signed-off-by: Greg Kroah-Hartman drivers/usb/net/pegasus.h | 2 ++ 1 file changed, 2 insertions(+) --- drivers/usb/net/pegasus.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index b98f2a833442..9fbd59b55cb6 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -181,6 +181,8 @@ PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", VENDOR_ADMTEK, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) From 521daed8db4443a1574a98fc3abae8e230f09eaa Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Oct 2005 17:15:33 -0700 Subject: [PATCH 1154/1939] [PATCH] safe_serial: use preprocessor directive for error Use valid #preprocessor instruction to generate an error. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman drivers/usb/serial/safe_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- drivers/usb/serial/safe_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 96a17568cbf1..88bf14abfa7a 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -92,7 +92,7 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); #if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" +#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" #endif #if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) From d40ece1dc8dcc89ab921755cbc93a5cfb46d0766 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 28 Sep 2005 18:06:04 +0200 Subject: [PATCH 1155/1939] [PATCH] USB: make usb storage note visible in Kconfig the following patch splits the NOTE: in the Device Drivers->USB submenu of Kconfig thus making the whole of it readable on 600x800 terminals. (Otherwise, the line was too big and disappeared into nowhere.) Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- drivers/usb/storage/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index bb9819cc8826..1a9679f76f5a 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -2,7 +2,8 @@ # USB Storage driver configuration # -comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information" +comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'" +comment "may also be needed; see USB_STORAGE Help for more information" depends on USB config USB_STORAGE From a8798533c1f876b97566588cf2bf52458cb4a35d Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 29 Sep 2005 00:14:21 +0100 Subject: [PATCH 1156/1939] [PATCH] USB Storage: HP8200: Another device type detection fix There appears to be one more case where the HP8200 CD writer devices are detected as flash readers - when the USB cable is replugged after use, with the power cable still connected. Oddly enough, the identify device command appears to 'fall through' when the devices are in this state, the status register reading exactly the same opcode as the command (0xA1) that was just executed. I think it's safe to label this behaviour as specific to HP8200 devices, I can't get the flash devices to respond like this. This patch should solve the last of the HP8200 issues which have cropped up recently. Signed-off-by: Daniel Drake Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/shuttle_usbat.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) --- drivers/usb/storage/shuttle_usbat.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 356342c6e7a2..bd448d6c3185 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -855,15 +855,15 @@ static int usbat_identify_device(struct us_data *us, if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Check for error bit - if (status & 0x01) { - // Device is a CompactFlash reader/writer - US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); - info->devicetype = USBAT_DEV_FLASH; - } else { + // Check for error bit, or if the command 'fell through' + if (status == 0xA1 || !(status & 0x01)) { // Device is HP 8200 US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); info->devicetype = USBAT_DEV_HP8200; + } else { + // Device is a CompactFlash reader/writer + US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); + info->devicetype = USBAT_DEV_FLASH; } return USB_STOR_TRANSPORT_GOOD; From b7b1e65588b8576c66a429a2623c91504efcf751 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 30 Sep 2005 12:49:36 +0100 Subject: [PATCH 1157/1939] [PATCH] usb-storage: Some minor shuttle_usbat cleanups A while ago, Matthew Dharm wrote: > Looks good. Tho, I would like to see a future patch to do two things: > 1) Change comments from C++ style to C-style > 2) Make sure we're naming consistently everywhere SCM, USBAT, > USBAT-02 (most noticably needing fixing is the string used at > transport-selection time, but a sweep of all uses to be consistent > would be in order). Sorry for the long delay, here is a patch to address this. I also clarified some ATA/ATAPI wording + function names. Signed-off-by: Daniel Drake Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/shuttle_usbat.c | 306 ++++++++++++++++++++---------------- drivers/usb/storage/shuttle_usbat.h | 66 +++---- drivers/usb/storage/transport.h | 2 drivers/usb/storage/unusual_devs.h | 10 - drivers/usb/storage/usb.c | 4 5 files changed, 213 insertions(+), 175 deletions(-) --- drivers/usb/storage/shuttle_usbat.c | 306 ++++++++++++++++------------ drivers/usb/storage/shuttle_usbat.h | 66 +++--- drivers/usb/storage/transport.h | 2 +- drivers/usb/storage/unusual_devs.h | 10 +- drivers/usb/storage/usb.c | 4 +- 5 files changed, 213 insertions(+), 175 deletions(-) diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index bd448d6c3185..33c55a6261bb 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1,4 +1,4 @@ -/* Driver for SCM Microsystems USB-ATAPI cable +/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable * * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $ * @@ -67,10 +67,10 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us); static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); /* - * Convenience function to produce an ATAPI read/write sectors command + * Convenience function to produce an ATA read/write sectors command * Use cmd=0x20 for read, cmd=0x30 for write */ -static void usbat_pack_atapi_sector_cmd(unsigned char *buf, +static void usbat_pack_ata_sector_cmd(unsigned char *buf, unsigned char thistime, u32 sector, unsigned char cmd) { @@ -196,10 +196,12 @@ static int usbat_check_status(struct us_data *us) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; - if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok) + /* error/check condition (0x51 is ok) */ + if (*reply & 0x01 && *reply != 0x51) return USB_STOR_TRANSPORT_FAILED; - if (*reply & 0x20) // device fault + /* device fault */ + if (*reply & 0x20) return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_GOOD; @@ -222,29 +224,39 @@ static int usbat_set_shuttle_features(struct us_data *us, command[0] = 0x40; command[1] = USBAT_CMD_SET_FEAT; - // The only bit relevant to ATA access is bit 6 - // which defines 8 bit data access (set) or 16 bit (unset) + /* + * The only bit relevant to ATA access is bit 6 + * which defines 8 bit data access (set) or 16 bit (unset) + */ command[2] = epp_control; - // If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, - // ET1 and ET2 define an external event to be checked for on event of a - // _read_blocks or _write_blocks operation. The read/write will not take - // place unless the defined trigger signal is active. + /* + * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, + * ET1 and ET2 define an external event to be checked for on event of a + * _read_blocks or _write_blocks operation. The read/write will not take + * place unless the defined trigger signal is active. + */ command[3] = external_trigger; - // The resultant byte of the mask operation (see mask_byte) is compared for - // equivalence with this test pattern. If equal, the read/write will take - // place. + /* + * The resultant byte of the mask operation (see mask_byte) is compared for + * equivalence with this test pattern. If equal, the read/write will take + * place. + */ command[4] = test_pattern; - // This value is logically ANDed with the status register field specified - // in the read/write command. + /* + * This value is logically ANDed with the status register field specified + * in the read/write command. + */ command[5] = mask_byte; - // If ALQ is set in the qualifier, this field contains the address of the - // registers where the byte count should be read for transferring the data. - // If ALQ is not set, then this field contains the number of bytes to be - // transferred. + /* + * If ALQ is set in the qualifier, this field contains the address of the + * registers where the byte count should be read for transferring the data. + * If ALQ is not set, then this field contains the number of bytes to be + * transferred. + */ command[6] = subcountL; command[7] = subcountH; @@ -273,26 +285,26 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) { // check condition + if (*status & 0x01) { /* check condition */ result = usbat_read(us, USBAT_ATA, 0x10, status); return USB_STOR_TRANSPORT_FAILED; } - if (*status & 0x20) // device fault + if (*status & 0x20) /* device fault */ return USB_STOR_TRANSPORT_FAILED; - if ((*status & 0x80)==0x00) { // not busy + if ((*status & 0x80)==0x00) { /* not busy */ US_DEBUGP("Waited not busy for %d steps\n", i); return USB_STOR_TRANSPORT_GOOD; } if (i<500) - msleep(10); // 5 seconds + msleep(10); /* 5 seconds */ else if (i<700) - msleep(50); // 10 seconds + msleep(50); /* 10 seconds */ else if (i<1200) - msleep(100); // 50 seconds + msleep(100); /* 50 seconds */ else - msleep(1000); // X minutes + msleep(1000); /* X minutes */ } US_DEBUGP("Waited not busy for %d minutes, timing out.\n", @@ -412,9 +424,12 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, if (i==0) { cmdlen = 16; - // Write to multiple registers - // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, - // but that's what came out of the trace every single time. + /* + * Write to multiple registers + * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is + * necessary here, but that's what came out of the + * trace every single time. + */ command[0] = 0x40; command[1] = access | USBAT_CMD_WRITE_REGS; command[2] = 0x07; @@ -426,7 +441,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } else cmdlen = 8; - // Conditionally read or write blocks + /* Conditionally read or write blocks */ command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | (direction==DMA_TO_DEVICE ? @@ -456,11 +471,6 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } - - //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == DMA_TO_DEVICE ? "out" : "in", - // len, use_sg); - result = usb_stor_bulk_transfer_sg(us, pipe, content, len, use_sg, NULL); @@ -508,9 +518,9 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) // check condition + if (*status & 0x01) /* check condition */ return USB_STOR_TRANSPORT_FAILED; - if (*status & 0x20) // device fault + if (*status & 0x20) /* device fault */ return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", @@ -547,32 +557,32 @@ static int usbat_multiple_write(struct us_data *us, BUG_ON(num_registers > US_IOBUF_SIZE/2); - // Write to multiple registers, ATA access + /* Write to multiple registers, ATA access */ command[0] = 0x40; command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS; - // No relevance + /* No relevance */ command[2] = 0; command[3] = 0; command[4] = 0; command[5] = 0; - // Number of bytes to be transferred (incl. addresses and data) + /* Number of bytes to be transferred (incl. addresses and data) */ command[6] = LSB_of(num_registers*2); command[7] = MSB_of(num_registers*2); - // The setup command + /* The setup command */ result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Create the reg/data, reg/data sequence + /* Create the reg/data, reg/data sequence */ for (i=0; isense_key = 0x02; @@ -795,11 +809,11 @@ static int usbat_flash_check_media(struct us_data *us, return USB_STOR_TRANSPORT_FAILED; } - // Check for media change + /* Check for media change */ rc = usbat_flash_check_media_changed(uio); if (rc == USBAT_FLASH_MEDIA_CHANGED) { - // Reset and re-enable card detect + /* Reset and re-enable card detect */ rc = usbat_device_reset(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; @@ -855,13 +869,13 @@ static int usbat_identify_device(struct us_data *us, if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Check for error bit, or if the command 'fell through' + /* Check for error bit, or if the command 'fell through' */ if (status == 0xA1 || !(status & 0x01)) { - // Device is HP 8200 + /* Device is HP 8200 */ US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); info->devicetype = USBAT_DEV_HP8200; } else { - // Device is a CompactFlash reader/writer + /* Device is a CompactFlash reader/writer */ US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); info->devicetype = USBAT_DEV_FLASH; } @@ -916,7 +930,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, if (!reply) return USB_STOR_TRANSPORT_ERROR; - // ATAPI command : IDENTIFY DEVICE + /* ATA command : IDENTIFY DEVICE */ rc = usbat_multiple_write(us, registers, command, 3); if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); @@ -924,7 +938,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, goto leave; } - // Read device status + /* Read device status */ if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { rc = USB_STOR_TRANSPORT_ERROR; goto leave; @@ -932,7 +946,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, msleep(100); - // Read the device identification data + /* Read the device identification data */ rc = usbat_read_block(us, reply, 512); if (rc != USB_STOR_TRANSPORT_GOOD) goto leave; @@ -977,19 +991,23 @@ static int usbat_flash_read_data(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) return result; - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. + /* + * we're working in LBA mode. according to the ATA spec, + * we can support up to 28-bit addressing. I don't know if Jumpshot + * supports beyond 24-bit addressing. It's kind of hard to test + * since it requires > 8GB CF card. + */ if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; - // Since we don't read more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we don't read more than 64 KB at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); @@ -997,27 +1015,29 @@ static int usbat_flash_read_data(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) + /* + * loop, never allocate or transfer more than 64k at once + * (min(128k, 255*info->ssize) is the real limit) + */ len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; - // ATAPI command 0x20 (READ SECTORS) - usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20); + /* ATA command 0x20 (READ SECTORS) */ + usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20); - // Write/execute ATAPI read command + /* Write/execute ATA read command */ result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; - // Read the data we just requested + /* Read the data we just requested */ result = usbat_read_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; US_DEBUGP("usbat_flash_read_data: %d bytes\n", len); - // Store the data in the transfer buffer + /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, TO_XFER_BUF); @@ -1061,19 +1081,23 @@ static int usbat_flash_write_data(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) return result; - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. + /* + * we're working in LBA mode. according to the ATA spec, + * we can support up to 28-bit addressing. I don't know if the device + * supports beyond 24-bit addressing. It's kind of hard to test + * since it requires > 8GB media. + */ if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; - // Since we don't write more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we don't write more than 64 KB at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); @@ -1081,24 +1105,26 @@ static int usbat_flash_write_data(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) + /* + * loop, never allocate or transfer more than 64k at once + * (min(128k, 255*info->ssize) is the real limit) + */ len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; - // Get the data from the transfer buffer + /* Get the data from the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, FROM_XFER_BUF); - // ATAPI command 0x30 (WRITE SECTORS) - usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30); + /* ATA command 0x30 (WRITE SECTORS) */ + usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); - // Write/execute ATAPI write command + /* Write/execute ATA write command */ result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; - // Write the data + /* Write the data */ result = usbat_write_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; @@ -1169,42 +1195,44 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, srb->transfersize); } - // Since we only read in one block at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we only read in one block at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); len = min(len, srb->request_bufflen); buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) // bloody hell! + if (buffer == NULL) /* bloody hell! */ return USB_STOR_TRANSPORT_FAILED; sector = short_pack(data[7+3], data[7+2]); sector <<= 16; sector |= short_pack(data[7+5], data[7+4]); transferred = 0; - sg_segment = 0; // for keeping track of where we are in - sg_offset = 0; // the scatter/gather list + sg_segment = 0; /* for keeping track of where we are in */ + sg_offset = 0; /* the scatter/gather list */ while (transferred != srb->request_bufflen) { if (len > srb->request_bufflen - transferred) len = srb->request_bufflen - transferred; - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) + data[3] = len&0xFF; /* (cylL) = expected length (L) */ + data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ - // Fix up the SCSI command sector and num sectors + /* Fix up the SCSI command sector and num sectors */ - data[7+2] = MSB_of(sector>>16); // SCSI command sector + data[7+2] = MSB_of(sector>>16); /* SCSI command sector */ data[7+3] = LSB_of(sector>>16); data[7+4] = MSB_of(sector&0xFFFF); data[7+5] = LSB_of(sector&0xFFFF); if (data[7+0] == GPCMD_READ_CD) data[7+6] = 0; - data[7+7] = MSB_of(len / srb->transfersize); // SCSI command - data[7+8] = LSB_of(len / srb->transfersize); // num sectors + data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */ + data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */ result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, registers, data, 19, @@ -1217,16 +1245,16 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) break; - // Store the data in the transfer buffer + /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, srb, &sg_segment, &sg_offset, TO_XFER_BUF); - // Update the amount transferred and the sector number + /* Update the amount transferred and the sector number */ transferred += len; sector += len / srb->transfersize; - } // while transferred != srb->request_bufflen + } /* while transferred != srb->request_bufflen */ kfree(buffer); return result; @@ -1237,7 +1265,7 @@ static int usbat_select_and_test_registers(struct us_data *us) int selector; unsigned char *status = us->iobuf; - // try device = master, then device = slave. + /* try device = master, then device = slave. */ for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != USB_STOR_XFER_GOOD) @@ -1298,7 +1326,7 @@ int init_usbat(struct us_data *us) memset(us->extra, 0, sizeof(struct usbat_info)); info = (struct usbat_info *) (us->extra); - // Enable peripheral control signals + /* Enable peripheral control signals */ rc = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); @@ -1337,7 +1365,7 @@ int init_usbat(struct us_data *us) US_DEBUGP("INIT 5\n"); - // Enable peripheral control signals and card detect + /* Enable peripheral control signals and card detect */ rc = usbat_device_enable_cdt(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; @@ -1364,7 +1392,7 @@ int init_usbat(struct us_data *us) US_DEBUGP("INIT 9\n"); - // At this point, we need to detect which device we are using + /* At this point, we need to detect which device we are using */ if (usbat_set_transport(us, info)) return USB_STOR_TRANSPORT_ERROR; @@ -1414,10 +1442,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) - data[5] = 0xB0; // (device sel) = slave - data[6] = 0xA0; // (command) = ATA PACKET COMMAND + data[3] = len&0xFF; /* (cylL) = expected length (L) */ + data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ + data[5] = 0xB0; /* (device sel) = slave */ + data[6] = 0xA0; /* (command) = ATA PACKET COMMAND */ for (i=7; i<19; i++) { registers[i] = 0x10; @@ -1466,13 +1494,15 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) return result; } - // Write the 12-byte command header. - - // If the command is BLANK then set the timer for 75 minutes. - // Otherwise set it for 10 minutes. - - // NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW - // AT SPEED 4 IS UNRELIABLE!!! + /* + * Write the 12-byte command header. + * + * If the command is BLANK then set the timer for 75 minutes. + * Otherwise set it for 10 minutes. + * + * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW + * AT SPEED 4 IS UNRELIABLE!!! + */ if ( (result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12, @@ -1481,19 +1511,18 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) return result; } - // If there is response data to be read in - // then do it here. + /* If there is response data to be read in then do it here. */ if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { - // How many bytes to read in? Check cylL register + /* How many bytes to read in? Check cylL register */ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != USB_STOR_XFER_GOOD) { return USB_STOR_TRANSPORT_ERROR; } - if (len > 0xFF) { // need to read cylH also + if (len > 0xFF) { /* need to read cylH also */ len = *status; if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != USB_STOR_XFER_GOOD) { @@ -1556,13 +1585,16 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec + /* hard coded 512 byte sectors as per ATA spec */ + info->ssize = 0x200; US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", info->sectors, info->ssize); - // build the reply - // note: must return the sector number of the last sector, - // *not* the total number of sectors + /* + * build the reply + * note: must return the sector number of the last sector, + * *not* the total number of sectors + */ ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); @@ -1586,7 +1618,9 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == READ_12) { - // I don't think we'll ever see a READ_12 but support it anyway... + /* + * I don't think we'll ever see a READ_12 but support it anyway + */ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); @@ -1608,7 +1642,9 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == WRITE_12) { - // I don't think we'll ever see a WRITE_12 but support it anyway... + /* + * I don't think we'll ever see a WRITE_12 but support it anyway + */ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); @@ -1645,8 +1681,10 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from popping - // the media out of the device (no locking doors, etc) + /* + * sure. whatever. not like we can stop the user from popping + * the media out of the device (no locking doors, etc) + */ return USB_STOR_TRANSPORT_GOOD; } diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index 5b8e867e2ae5..25e7d8b340b8 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h @@ -55,8 +55,8 @@ #define USBAT_UIO_WRITE 0 /* Qualifier bits */ -#define USBAT_QUAL_FCQ 0x20 // full compare -#define USBAT_QUAL_ALQ 0x10 // auto load subcount +#define USBAT_QUAL_FCQ 0x20 /* full compare */ +#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */ /* USBAT Flash Media status types */ #define USBAT_FLASH_MEDIA_NONE 0 @@ -67,39 +67,39 @@ #define USBAT_FLASH_MEDIA_CHANGED 1 /* USBAT ATA registers */ -#define USBAT_ATA_DATA 0x10 // read/write data (R/W) -#define USBAT_ATA_FEATURES 0x11 // set features (W) -#define USBAT_ATA_ERROR 0x11 // error (R) -#define USBAT_ATA_SECCNT 0x12 // sector count (R/W) -#define USBAT_ATA_SECNUM 0x13 // sector number (R/W) -#define USBAT_ATA_LBA_ME 0x14 // cylinder low (R/W) -#define USBAT_ATA_LBA_HI 0x15 // cylinder high (R/W) -#define USBAT_ATA_DEVICE 0x16 // head/device selection (R/W) -#define USBAT_ATA_STATUS 0x17 // device status (R) -#define USBAT_ATA_CMD 0x17 // device command (W) -#define USBAT_ATA_ALTSTATUS 0x0E // status (no clear IRQ) (R) +#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */ +#define USBAT_ATA_FEATURES 0x11 /* set features (W) */ +#define USBAT_ATA_ERROR 0x11 /* error (R) */ +#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */ +#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */ +#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */ +#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */ +#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */ +#define USBAT_ATA_STATUS 0x17 /* device status (R) */ +#define USBAT_ATA_CMD 0x17 /* device command (W) */ +#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */ /* USBAT User I/O Data registers */ -#define USBAT_UIO_EPAD 0x80 // Enable Peripheral Control Signals -#define USBAT_UIO_CDT 0x40 // Card Detect (Read Only) - // CDT = ACKD & !UI1 & !UI0 -#define USBAT_UIO_1 0x20 // I/O 1 -#define USBAT_UIO_0 0x10 // I/O 0 -#define USBAT_UIO_EPP_ATA 0x08 // 1=EPP mode, 0=ATA mode -#define USBAT_UIO_UI1 0x04 // Input 1 -#define USBAT_UIO_UI0 0x02 // Input 0 -#define USBAT_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP) +#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */ +#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */ + /* CDT = ACKD & !UI1 & !UI0 */ +#define USBAT_UIO_1 0x20 /* I/O 1 */ +#define USBAT_UIO_0 0x10 /* I/O 0 */ +#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */ +#define USBAT_UIO_UI1 0x04 /* Input 1 */ +#define USBAT_UIO_UI0 0x02 /* Input 0 */ +#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */ /* USBAT User I/O Enable registers */ -#define USBAT_UIO_DRVRST 0x80 // Reset Peripheral -#define USBAT_UIO_ACKD 0x40 // Enable Card Detect -#define USBAT_UIO_OE1 0x20 // I/O 1 set=output/clr=input - // If ACKD=1, set OE1 to 1 also. -#define USBAT_UIO_OE0 0x10 // I/O 0 set=output/clr=input -#define USBAT_UIO_ADPRST 0x01 // Reset SCM chip +#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */ +#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */ +#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */ + /* If ACKD=1, set OE1 to 1 also. */ +#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */ +#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */ /* USBAT Features */ -#define USBAT_FEAT_ETEN 0x80 // External trigger enable +#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */ #define USBAT_FEAT_U1 0x08 #define USBAT_FEAT_U0 0x04 #define USBAT_FEAT_ET1 0x02 @@ -112,12 +112,12 @@ struct usbat_info { int devicetype; /* Used for Flash readers only */ - unsigned long sectors; // total sector count - unsigned long ssize; // sector size in bytes + unsigned long sectors; /* total sector count */ + unsigned long ssize; /* sector size in bytes */ unsigned char sense_key; - unsigned long sense_asc; // additional sense code - unsigned long sense_ascq; // additional sense code qualifier + unsigned long sense_asc; /* additional sense code */ + unsigned long sense_ascq; /* additional sense code qualifier */ }; #endif diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 8d9e0663f8fe..0a362cc781ad 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -50,7 +50,7 @@ #define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */ #define US_PR_BULK 0x50 /* bulk only */ #ifdef CONFIG_USB_STORAGE_USBAT -#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */ +#define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */ #endif #ifdef CONFIG_USB_STORAGE_SDDR09 #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b79dad1b598c..71d051d97b77 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -71,12 +71,12 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, "HP", "CD-Writer+ 8200e", - US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), + US_SC_8070, US_PR_USBAT, init_usbat, 0), UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, "HP", "CD-Writer+ CD-4e", - US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), + US_SC_8070, US_PR_USBAT, init_usbat, 0), #endif /* Patch submitted by Mihnea-Costin Grigore */ @@ -333,9 +333,9 @@ UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100, #ifdef CONFIG_USB_STORAGE_USBAT UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, - "SCM", - "SCM USBAT-02", - US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat, + "Shuttle/SCM", + "USBAT-02", + US_SC_SCSI, US_PR_USBAT, init_usbat, US_FL_SINGLE_LUN), #endif diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index f9a9bfa1aef5..5164900e40c1 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -555,8 +555,8 @@ static int get_transport(struct us_data *us) break; #ifdef CONFIG_USB_STORAGE_USBAT - case US_PR_SCM_ATAPI: - us->transport_name = "SCM/ATAPI"; + case US_PR_USBAT: + us->transport_name = "Shuttle USBAT"; us->transport = usbat_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 1; From 094ec604721ed2a9a7ed6dfe40fd699b2f53a4c3 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 30 Sep 2005 12:58:13 +0100 Subject: [PATCH 1158/1939] [PATCH] usb-storage: Readd missing SDDR-05b unusual_devs entry Just noticed that the SDDR-05b entry is missing for the shuttle_usbat driver. Looking through BK history it was removed in this patch: http://linux.bkbits.net:8080/linux-2.6/gnupatch@42435730FZQ2XCA6Qv5GPGD4pC4laQ However, at merge time, it looks like the duplicate was already removed, compare these two revisions: http://linux.bkbits.net:8080/linux-2.6/anno/drivers/usb/storage/unusual_devs.h@1.152 http://linux.bkbits.net:8080/linux-2.6/anno/drivers/usb/storage/unusual_devs.h@1.153 Signed-off-by: Daniel Drake Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/unusual_devs.h | 8 ++++++++ 1 file changed, 8 insertions(+) --- drivers/usb/storage/unusual_devs.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 71d051d97b77..ee9f0502e055 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -702,6 +702,14 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +#ifdef CONFIG_USB_STORAGE_USBAT +UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, + "Sandisk", + "ImageMate SDDR-05b", + US_SC_SCSI, US_PR_USBAT, init_usbat, + US_FL_SINGLE_LUN ), +#endif + UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", "ImageMate SDDR-12", From e4a16e0c10a272e53c4a129b155dd711196b1d93 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Fri, 30 Sep 2005 00:20:15 -0700 Subject: [PATCH 1159/1939] [PATCH] Add unusual_dev for iBeat This patch adds the US_FL_IGNORE_RESIDUE flag for the TrekStor i.Beat Joy 2.0. Original version of this patch was sent by Stefan Werner with test/rediff/etc. by me. Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ee9f0502e055..730ba8dde9bd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -106,6 +106,13 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Stefan Werner */ +UNUSUAL_DEV( 0x0419, 0xaaf6, 0x0100, 0x0100, + "TrekStor", + "i.Beat Joy 2.0", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Olaf Hering from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", From 880a9b5e7f70632ab60131ce3027da1c63fcd39e Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Fri, 30 Sep 2005 00:27:36 -0700 Subject: [PATCH 1160/1939] [PATCH] Add unusual_devs for iPod Nano This adds US_FL_FIX_CAPACITY for yet _another_ entire block of Apple productIds. They really can't seem to get this right. This one is for the iPod Nano. Reported by Tyson Vinson . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman drivers/usb/storage/unusual_devs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) --- drivers/usb/storage/unusual_devs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 730ba8dde9bd..a11701840262 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -605,6 +605,16 @@ UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* + * Reported by Tyson Vinson + * This particular productId is the iPod Nano + */ +UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999, + "Apple", + "iPod", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + #ifdef CONFIG_USB_STORAGE_JUMPSHOT UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, "Lexar", From 3f8c03ee05801bf8539dd136d9246a416c45052a Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Wed, 28 Sep 2005 21:30:12 +0200 Subject: [PATCH 1161/1939] [PATCH] usb/input/touchkit: add more device IDs add two more device IDs from eGalax' programming guide. thanks to Jonathan Hopper for pointing out. Signed-off-by: Daniel Ritz Signed-off-by: Greg Kroah-Hartman drivers/usb/input/touchkitusb.c | 2 ++ 1 file changed, 2 insertions(+) --- drivers/usb/input/touchkitusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 3766ccc271be..0043e6ebcd1f 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -75,7 +75,9 @@ struct touchkit_usb { static struct usb_device_id touchkit_devices[] = { {USB_DEVICE(0x3823, 0x0001)}, + {USB_DEVICE(0x0123, 0x0001)}, {USB_DEVICE(0x0eef, 0x0001)}, + {USB_DEVICE(0x0eef, 0x0002)}, {} }; From a922c68732725866c88457026cf06a7620846506 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 6 Oct 2005 16:38:45 -0400 Subject: [PATCH 1162/1939] [PATCH] g_file_storage: fix obscure race condition This patch (as575) fixes an unlikely race in the g_file_storage driver. The problem can occur only when the driver is unbound before its initialization routine has finished. I also took the opportunity to replace kmalloc/memset with kzalloc. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 241c570e541c..86a6aeb9ed76 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3823,12 +3823,11 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); + fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; goto out; } - memset(fsg->luns, 0, i * sizeof(struct lun)); fsg->nluns = i; for (i = 0; i < fsg->nluns; ++i) { @@ -3989,6 +3988,11 @@ static int __init fsg_bind(struct usb_gadget *gadget) mod_data.removable, mod_data.can_stall, mod_data.buflen); DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); + + set_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Tell the thread to start working */ + wake_up_process(fsg->thread_task); return 0; autoconf_fail: @@ -4051,10 +4055,9 @@ static int __init fsg_alloc(void) { struct fsg_dev *fsg; - fsg = kmalloc(sizeof *fsg, GFP_KERNEL); + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); if (!fsg) return -ENOMEM; - memset(fsg, 0, sizeof *fsg); spin_lock_init(&fsg->lock); init_rwsem(&fsg->filesem); init_waitqueue_head(&fsg->thread_wqh); @@ -4080,15 +4083,9 @@ static int __init fsg_init(void) if ((rc = fsg_alloc()) != 0) return rc; fsg = the_fsg; - if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) { + if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) fsg_free(fsg); - return rc; - } - set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Tell the thread to start working */ - wake_up_process(fsg->thread_task); - return 0; + return rc; } module_init(fsg_init); From bb200f6eac6372839921be1fe87c1f5c292a7bd6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 3 Oct 2005 16:36:29 -0400 Subject: [PATCH 1163/1939] [PATCH] UHCI: unify BIOS handoff and driver reset code This patch (as574) updates the PCI BIOS usb-handoff code for UHCI controllers, making it work like the reset routines in uhci-hcd. This allows uhci-hcd to drop its own routines in favor of the new ones (code-sharing). Once the patch is merged we can turn the usb-handoff option on permanently, as far as UHCI is concerned. OHCI and EHCI may still have some issues. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 142 +++++++++++++++++++++++----------- drivers/usb/host/uhci-hcd.c | 76 +++--------------- 2 files changed, 106 insertions(+), 112 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 49f7381a6fd3..f7411ca48835 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -9,6 +9,12 @@ */ #include +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#else +#undef DEBUG +#endif + #include #include #include @@ -46,13 +52,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, qui #define UHCI_USBLEGSUP 0xc0 /* legacy support */ #define UHCI_USBCMD 0 /* command register */ -#define UHCI_USBSTS 2 /* status register */ #define UHCI_USBINTR 4 /* interrupt register */ -#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ -#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ -#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ -#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ +#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ +#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ +#define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ +#define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ +#define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ +#define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ #define OHCI_CONTROL 0x04 #define OHCI_CMDSTATUS 0x08 @@ -84,11 +91,90 @@ static int __init usb_handoff_early(char *str) } __setup("usb-handoff", usb_handoff_early); +/* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. + */ +void uhci_reset_hc(struct pci_dev *pdev, unsigned long base) +{ + /* Turn off PIRQ enable and SMI enable. (This also turns off the + * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. + */ + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); + + /* Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); + mb(); + udelay(5); + if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) + dev_warn(&pdev->dev, "HCRESET not completed yet!\n"); + + /* Just to be safe, disable interrupt requests and + * make sure the controller is stopped. + */ + outw(0, base + UHCI_USBINTR); + outw(0, base + UHCI_USBCMD); +} +EXPORT_SYMBOL_GPL(uhci_reset_hc); + +/* + * Initialize a controller that was newly discovered or has just been + * resumed. In either case we can't be sure of its previous state. + * + * Returns: 1 if the controller was reset, 0 otherwise. + */ +int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) +{ + u16 legsup; + unsigned int cmd, intr; + + /* + * When restarting a suspended controller, we expect all the + * settings to be the same as we left them: + * + * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; + * Controller is stopped and configured with EGSM set; + * No interrupts enabled except possibly Resume Detect. + * + * If any of these conditions are violated we do a complete reset. + */ + pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); + if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { + dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", + __FUNCTION__, legsup); + goto reset_needed; + } + + cmd = inw(base + UHCI_USBCMD); + if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || + !(cmd & UHCI_USBCMD_EGSM)) { + dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", + __FUNCTION__, cmd); + goto reset_needed; + } + + intr = inw(base + UHCI_USBINTR); + if (intr & (~UHCI_USBINTR_RESUME)) { + dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n", + __FUNCTION__, intr); + goto reset_needed; + } + return 0; + +reset_needed: + dev_dbg(&pdev->dev, "Performing full reset\n"); + uhci_reset_hc(pdev, base); + return 1; +} +EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) { unsigned long base = 0; - int wait_time, delta; - u16 val, sts; int i; for (i = 0; i < PCI_ROM_RESOURCE; i++) @@ -97,44 +183,8 @@ static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) break; } - if (!base) - return; - - /* - * stop controller - */ - sts = inw(base + UHCI_USBSTS); - val = inw(base + UHCI_USBCMD); - val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); - outw(val, base + UHCI_USBCMD); - - /* - * wait while it stops if it was running - */ - if ((sts & UHCI_USBSTS_HALTED) == 0) - { - wait_time = 1000; - delta = 100; - - do { - outw(0x1f, base + UHCI_USBSTS); - udelay(delta); - wait_time -= delta; - val = inw(base + UHCI_USBSTS); - if (val & UHCI_USBSTS_HALTED) - break; - } while (wait_time > 0); - } - - /* - * disable interrupts & legacy support - */ - outw(0, base + UHCI_USBINTR); - outw(0x1f, base + UHCI_USBSTS); - pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); - if (val & 0xbf) - pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); - + if (base) + uhci_check_and_reset_hc(pdev, base); } static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 34c9dbc6a156..6df555e3d97c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -101,37 +101,16 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); #include "uhci-q.c" #include "uhci-hub.c" +extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); +extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); + /* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. + * Finish up a host controller reset and update the recorded state. */ -static void reset_hc(struct uhci_hcd *uhci) +static void finish_reset(struct uhci_hcd *uhci) { int port; - /* Turn off PIRQ enable and SMI enable. (This also turns off the - * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. - */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_RWC); - - /* Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. - */ - outw(USBCMD_HCRESET, uhci->io_addr + USBCMD); - mb(); - udelay(5); - if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET) - dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n"); - - /* Just to be safe, disable interrupt requests and - * make sure the controller is stopped. - */ - outw(0, uhci->io_addr + USBINTR); - outw(0, uhci->io_addr + USBCMD); - /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect * bits in the port status and control registers. * We have to clear them by hand. @@ -153,7 +132,8 @@ static void reset_hc(struct uhci_hcd *uhci) */ static void hc_died(struct uhci_hcd *uhci) { - reset_hc(uhci); + uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); + finish_reset(uhci); uhci->hc_inaccessible = 1; } @@ -163,44 +143,8 @@ static void hc_died(struct uhci_hcd *uhci) */ static void check_and_reset_hc(struct uhci_hcd *uhci) { - u16 legsup; - unsigned int cmd, intr; - - /* - * When restarting a suspended controller, we expect all the - * settings to be the same as we left them: - * - * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; - * Controller is stopped and configured with EGSM set; - * No interrupts enabled except possibly Resume Detect. - * - * If any of these conditions are violated we do a complete reset. - */ - pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup); - if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) { - dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n", - __FUNCTION__, legsup); - goto reset_needed; - } - - cmd = inw(uhci->io_addr + USBCMD); - if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) { - dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n", - __FUNCTION__, cmd); - goto reset_needed; - } - - intr = inw(uhci->io_addr + USBINTR); - if (intr & (~USBINTR_RESUME)) { - dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n", - __FUNCTION__, intr); - goto reset_needed; - } - return; - -reset_needed: - dev_dbg(uhci_dev(uhci), "Performing full reset\n"); - reset_hc(uhci); + if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr)) + finish_reset(uhci); } /* @@ -714,7 +658,7 @@ static void uhci_stop(struct usb_hcd *hcd) spin_lock_irq(&uhci->lock); if (!uhci->hc_inaccessible) - reset_hc(uhci); + hc_died(uhci); uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); From 0c0382e32d46f606951010b202382be14d180a17 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 13 Oct 2005 17:08:02 -0400 Subject: [PATCH 1164/1939] [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 16 ++++++---------- drivers/usb/core/hcd.h | 23 +++++++++++++++++------ drivers/usb/core/hub.c | 8 ++++---- drivers/usb/gadget/dummy_hcd.c | 22 ++++------------------ drivers/usb/host/ehci-hub.c | 8 ++++---- drivers/usb/host/ehci-pci.c | 4 ++-- drivers/usb/host/isp116x-hcd.c | 12 ++++++------ drivers/usb/host/ohci-au1xxx.c | 4 ++-- drivers/usb/host/ohci-hub.c | 6 +++--- drivers/usb/host/ohci-lh7a404.c | 4 ++-- drivers/usb/host/ohci-omap.c | 4 ++-- drivers/usb/host/ohci-pci.c | 4 ++-- drivers/usb/host/ohci-ppc-soc.c | 4 ++-- drivers/usb/host/ohci-pxa27x.c | 4 ++-- drivers/usb/host/ohci-s3c2410.c | 4 ++-- drivers/usb/host/ohci-sa1111.c | 4 ++-- drivers/usb/host/sl811-hcd.c | 16 ++++++++-------- drivers/usb/host/uhci-hcd.c | 4 ++-- 18 files changed, 72 insertions(+), 79 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index b7bb8dd1894a..9ad3912a5ed7 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1433,16 +1433,16 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) #ifdef CONFIG_PM -static int hcd_hub_suspend (struct usb_bus *bus) +int hcd_bus_suspend (struct usb_bus *bus) { struct usb_hcd *hcd; int status; hcd = container_of (bus, struct usb_hcd, self); - if (!hcd->driver->hub_suspend) + if (!hcd->driver->bus_suspend) return -ENOENT; hcd->state = HC_STATE_QUIESCING; - status = hcd->driver->hub_suspend (hcd); + status = hcd->driver->bus_suspend (hcd); if (status == 0) hcd->state = HC_STATE_SUSPENDED; else @@ -1451,18 +1451,18 @@ static int hcd_hub_suspend (struct usb_bus *bus) return status; } -static int hcd_hub_resume (struct usb_bus *bus) +int hcd_bus_resume (struct usb_bus *bus) { struct usb_hcd *hcd; int status; hcd = container_of (bus, struct usb_hcd, self); - if (!hcd->driver->hub_resume) + if (!hcd->driver->bus_resume) return -ENOENT; if (hcd->state == HC_STATE_RUNNING) return 0; hcd->state = HC_STATE_RESUMING; - status = hcd->driver->hub_resume (hcd); + status = hcd->driver->bus_resume (hcd); if (status == 0) hcd->state = HC_STATE_RUNNING; else { @@ -1590,10 +1590,6 @@ static struct usb_operations usb_hcd_operations = { .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, .disable = hcd_endpoint_disable, -#ifdef CONFIG_PM - .hub_suspend = hcd_hub_suspend, - .hub_resume = hcd_hub_resume, -#endif }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 74757fc1a99f..d8f0d29a45b7 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -154,10 +154,6 @@ struct usb_operations { void (*disable)(struct usb_device *udev, struct usb_host_endpoint *ep); - - /* global suspend/resume of bus */ - int (*hub_suspend)(struct usb_bus *); - int (*hub_resume)(struct usb_bus *); }; /* each driver provides one of these, and hardware init support */ @@ -212,8 +208,8 @@ struct hc_driver { int (*hub_control) (struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); - int (*hub_suspend)(struct usb_hcd *); - int (*hub_resume)(struct usb_hcd *); + int (*bus_suspend)(struct usb_hcd *); + int (*bus_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); void (*hub_irq_enable)(struct usb_hcd *); /* Needed only if port-change IRQs are level-triggered */ @@ -379,6 +375,21 @@ extern int usb_find_interface_driver (struct usb_device *dev, #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) +#ifdef CONFIG_PM +extern int hcd_bus_suspend (struct usb_bus *bus); +extern int hcd_bus_resume (struct usb_bus *bus); +#else +static inline int hcd_bus_suspend(struct usb_bus *bus) +{ + return 0; +} + +static inline int hcd_bus_resume (struct usb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_PM */ + /* * USB device fs stuff */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e2802bf18095..273e6ccca213 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1917,8 +1917,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { struct usb_bus *bus = hdev->bus; - if (bus && bus->op->hub_suspend) { - int status = bus->op->hub_suspend (bus); + if (bus) { + int status = hcd_bus_suspend (bus); if (status != 0) { dev_dbg(&hdev->dev, "'global' suspend %d\n", @@ -1943,8 +1943,8 @@ static int hub_resume(struct usb_interface *intf) /* "global resume" of the downstream HC-to-USB interface */ if (!hdev->parent) { struct usb_bus *bus = hdev->bus; - if (bus && bus->op->hub_resume) { - status = bus->op->hub_resume (bus); + if (bus) { + status = hcd_bus_resume (bus); if (status) { dev_dbg(&intf->dev, "'global' resume %d\n", status); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 503201764f6b..c605aaeed636 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1751,7 +1751,7 @@ static int dummy_hub_control ( return retval; } -static int dummy_hub_suspend (struct usb_hcd *hcd) +static int dummy_bus_suspend (struct usb_hcd *hcd) { struct dummy *dum = hcd_to_dummy (hcd); @@ -1762,7 +1762,7 @@ static int dummy_hub_suspend (struct usb_hcd *hcd) return 0; } -static int dummy_hub_resume (struct usb_hcd *hcd) +static int dummy_bus_resume (struct usb_hcd *hcd) { struct dummy *dum = hcd_to_dummy (hcd); @@ -1894,8 +1894,8 @@ static const struct hc_driver dummy_hcd = { .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, - .hub_suspend = dummy_hub_suspend, - .hub_resume = dummy_hub_resume, + .bus_suspend = dummy_bus_suspend, + .bus_resume = dummy_bus_resume, }; static int dummy_hcd_probe (struct device *dev) @@ -1936,13 +1936,6 @@ static int dummy_hcd_suspend (struct device *dev, pm_message_t state) dev_dbg (dev, "%s\n", __FUNCTION__); hcd = dev_get_drvdata (dev); -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - usb_lock_device (hcd->self.root_hub); - dummy_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - hcd->state = HC_STATE_SUSPENDED; return 0; } @@ -1955,13 +1948,6 @@ static int dummy_hcd_resume (struct device *dev) hcd = dev_get_drvdata (dev); hcd->state = HC_STATE_RUNNING; -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - usb_lock_device (hcd->self.root_hub); - dummy_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - usb_hcd_poll_rh_status (hcd); return 0; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 18d3f2270316..88cb4ada686e 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -30,7 +30,7 @@ #ifdef CONFIG_PM -static int ehci_hub_suspend (struct usb_hcd *hcd) +static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int port; @@ -83,7 +83,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) /* caller has locked the root hub, and should reset/reinit on error */ -static int ehci_hub_resume (struct usb_hcd *hcd) +static int ehci_bus_resume (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; @@ -159,8 +159,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd) #else -#define ehci_hub_suspend NULL -#define ehci_hub_resume NULL +#define ehci_bus_suspend NULL +#define ehci_bus_resume NULL #endif /* CONFIG_PM */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 66ebf75b2037..8bbc8dfe19f3 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -363,8 +363,8 @@ static const struct hc_driver ehci_pci_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index f68220fc53fd..ddb8fc591466 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1160,7 +1160,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd, #ifdef CONFIG_PM -static int isp116x_hub_suspend(struct usb_hcd *hcd) +static int isp116x_bus_suspend(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); unsigned long flags; @@ -1200,7 +1200,7 @@ static int isp116x_hub_suspend(struct usb_hcd *hcd) return ret; } -static int isp116x_hub_resume(struct usb_hcd *hcd) +static int isp116x_bus_resume(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); u32 val; @@ -1266,8 +1266,8 @@ static int isp116x_hub_resume(struct usb_hcd *hcd) #else -#define isp116x_hub_suspend NULL -#define isp116x_hub_resume NULL +#define isp116x_bus_suspend NULL +#define isp116x_bus_resume NULL #endif @@ -1626,8 +1626,8 @@ static struct hc_driver isp116x_hc_driver = { .hub_status_data = isp116x_hub_status_data, .hub_control = isp116x_hub_control, - .hub_suspend = isp116x_hub_suspend, - .hub_resume = isp116x_hub_resume, + .bus_suspend = isp116x_bus_suspend, + .bus_resume = isp116x_bus_resume, }; /*----------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 550d67a554f6..ac463c493035 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -215,8 +215,8 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 39a60e731ec2..e01e77bc324b 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -45,7 +45,7 @@ static void dl_done_list (struct ohci_hcd *, struct pt_regs *); static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); static int ohci_restart (struct ohci_hcd *ohci); -static int ohci_hub_suspend (struct usb_hcd *hcd) +static int ohci_bus_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; @@ -135,7 +135,7 @@ static inline struct ed *find_head (struct ed *ed) } /* caller has locked the root hub */ -static int ohci_hub_resume (struct usb_hcd *hcd) +static int ohci_bus_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; @@ -362,7 +362,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) && usb_trylock_device (hcd->self.root_hub) ) { ohci_vdbg (ohci, "autosuspend\n"); - (void) ohci_hub_suspend (hcd); + (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); } #endif diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 71d975ae78bd..e2ed55b69f86 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -194,8 +194,8 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b3498b9b965f..982cdca22516 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -421,8 +421,8 @@ static const struct hc_driver ohci_omap_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 99a0ad41aec5..a8dde8b75691 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -195,8 +195,8 @@ static const struct hc_driver ohci_pci_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index ec20710e99fe..228845eb7eab 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -164,8 +164,8 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2e7b48502a3d..d287dcccd415 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -279,8 +279,8 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 922e2a6f46ef..3225d455f459 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -449,8 +449,8 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { .hub_status_data = ohci_s3c2410_hub_status_data, .hub_control = ohci_s3c2410_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 13324b7f9c59..fb3221ebbb29 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -236,8 +236,8 @@ static const struct hc_driver ohci_sa1111_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index b5e7a478bc01..1e47c1f86e70 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1363,7 +1363,7 @@ sl811h_hub_control( #ifdef CONFIG_PM static int -sl811h_hub_suspend(struct usb_hcd *hcd) +sl811h_bus_suspend(struct usb_hcd *hcd) { // SOFs off DBG("%s\n", __FUNCTION__); @@ -1371,7 +1371,7 @@ sl811h_hub_suspend(struct usb_hcd *hcd) } static int -sl811h_hub_resume(struct usb_hcd *hcd) +sl811h_bus_resume(struct usb_hcd *hcd) { // SOFs on DBG("%s\n", __FUNCTION__); @@ -1380,8 +1380,8 @@ sl811h_hub_resume(struct usb_hcd *hcd) #else -#define sl811h_hub_suspend NULL -#define sl811h_hub_resume NULL +#define sl811h_bus_suspend NULL +#define sl811h_bus_resume NULL #endif @@ -1623,8 +1623,8 @@ static struct hc_driver sl811h_hc_driver = { */ .hub_status_data = sl811h_hub_status_data, .hub_control = sl811h_hub_control, - .hub_suspend = sl811h_hub_suspend, - .hub_resume = sl811h_hub_resume, + .bus_suspend = sl811h_bus_suspend, + .bus_resume = sl811h_bus_resume, }; /*-------------------------------------------------------------------------*/ @@ -1791,7 +1791,7 @@ sl811h_suspend(struct device *dev, pm_message_t state) int retval = 0; if (state.event == PM_EVENT_FREEZE) - retval = sl811h_hub_suspend(hcd); + retval = sl811h_bus_suspend(hcd); else if (state.event == PM_EVENT_SUSPEND) port_power(sl811, 0); if (retval == 0) @@ -1816,7 +1816,7 @@ sl811h_resume(struct device *dev) } dev->power.power_state = PMSG_ON; - return sl811h_hub_resume(hcd); + return sl811h_bus_resume(hcd); } #else diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6df555e3d97c..72cd1576d20c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -804,8 +804,8 @@ static const struct hc_driver uhci_driver = { #ifdef CONFIG_PM .suspend = uhci_suspend, .resume = uhci_resume, - .hub_suspend = uhci_rh_suspend, - .hub_resume = uhci_rh_resume, + .bus_suspend = uhci_rh_suspend, + .bus_resume = uhci_rh_resume, #endif .stop = uhci_stop, From b81d34363c0b17c47f4ef63d5888c4f47f315d29 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 13 Oct 2005 17:00:24 -0400 Subject: [PATCH 1165/1939] [PATCH] UHCI: Improve handling of iso TDs The uhci-hcd driver is fairly lax about the way it handles isochronous transfers. This patch (as579) improves it in three respects: TDs for a new URB aren't added to the schedule until all of them have been allocated. This way there's no risk of the controller executing some of them when an allocation fails. TDs for an unlinked URB are removed from the schedule as soon as the URB is unlinked, rather than waiting until the URB is given back. This way there's no risk of the controller still executing a TD after the URB completes. The urb->error_count values are now reported correctly. Although since they aren't used in any drivers except for debug messages in the system log, probably nobody cares. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-q.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 51de06bc438d..7e46887d9e12 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -108,13 +108,16 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, } } -static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) +static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, + struct uhci_td *td) { /* If it's not inserted, don't remove it */ - if (td->frame == -1 && list_empty(&td->fl_list)) + if (td->frame == -1) { + WARN_ON(!list_empty(&td->fl_list)); return; + } - if (td->frame != -1 && uhci->frame_cpu[td->frame] == td) { + if (uhci->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { uhci->frame[td->frame] = td->link; uhci->frame_cpu[td->frame] = NULL; @@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) ptd->link = td->link; } - wmb(); - td->link = UHCI_PTR_TERM; - list_del_init(&td->fl_list); td->frame = -1; } +static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + struct uhci_td *td; + + list_for_each_entry(td, &urbp->td_list, list) + uhci_remove_td_frame_list(uhci, td); + wmb(); +} + /* * Inserts a td list into qh. */ @@ -498,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { uhci_remove_td_from_urb(td); - uhci_remove_td(uhci, td); list_add(&td->remove_list, &uhci->td_remove_list); } @@ -1068,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) struct uhci_td *td; int i, ret, frame; int status, destination; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); @@ -1076,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) if (ret) return ret; - frame = urb->start_frame; - for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) { - if (!urb->iso_frame_desc[i].length) - continue; - + for (i = 0; i < urb->number_of_packets; i++) { td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -1091,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) if (i + 1 >= urb->number_of_packets) td->status |= cpu_to_le32(TD_CTRL_IOC); + } + frame = urb->start_frame; + list_for_each_entry(td, &urbp->td_list, list) { uhci_insert_td_frame_list(uhci, td, frame); + frame += urb->interval; } return -EINPROGRESS; @@ -1105,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) int status; int i, ret = 0; - urb->actual_length = 0; + urb->actual_length = urb->error_count = 0; i = 0; list_for_each_entry(td, &urbp->td_list, list) { @@ -1129,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) i++; } + unlink_isochronous_tds(uhci, urb); return ret; } @@ -1361,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) goto done; list_del_init(&urbp->urb_list); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + unlink_isochronous_tds(uhci, urb); uhci_unlink_generic(uhci, urb); uhci_get_current_frame_number(uhci); From af64a5ebb817532965d18b792d6d74afecfb0bcf Mon Sep 17 00:00:00 2001 From: Henk Date: Wed, 12 Oct 2005 15:02:56 +0200 Subject: [PATCH 1166/1939] [PATCH] USB: Buffer overflow patch for Yealink driver Just a small patch that fixes a small parameter validation bug. drivers/usb/input/map_to_7segment.h: This patch fixes the broken parameter validation in the char to seg7 conversion. This could cause out-of-bounds memory references. MAINTAINERS: Yealink maintainer info now in sorted order. Documentation/input/yealink.txt: Added a Q&A section that answers some common questions. Signed-off-by: Henk Signed-off-by: Greg Kroah-Hartman 006491df1a13f85ad245d1039dfdf20e49c394fd --- Documentation/input/yealink.txt | 19 ++++++++++++++++--- MAINTAINERS | 12 ++++++------ drivers/usb/input/map_to_7segment.h | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt index 85f095a7ad04..0962c5c948be 100644 --- a/Documentation/input/yealink.txt +++ b/Documentation/input/yealink.txt @@ -2,7 +2,6 @@ Driver documentation for yealink usb-p1k phones 0. Status ~~~~~~~~~ - The p1k is a relatively cheap usb 1.1 phone with: - keyboard full support, yealink.ko / input event API - LCD full support, yealink.ko / sysfs API @@ -17,9 +16,8 @@ For vendor documentation see http://www.yealink.com 1. Compilation (stand alone version) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Currently only kernel 2.6.x.y versions are supported. -In order to build the yealink.ko module do: +In order to build the yealink.ko module do make @@ -28,6 +26,21 @@ the Makefile is pointing to the location where your kernel sources are located, default /usr/src/linux. +1.1 Troubleshooting +~~~~~~~~~~~~~~~~~~~ +Q: Module yealink compiled and installed without any problem but phone + is not initialized and does not react to any actions. +A: If you see something like: + hiddev0: USB HID v1.00 Device [Yealink Network Technology Ltd. VOIP USB Phone + in dmesg, it means that the hid driver has grabbed the device first. Try to + load module yealink before any other usb hid driver. Please see the + instructions provided by your distribution on module configuration. + +Q: Phone is working now (displays version and accepts keypad input) but I can't + find the sysfs files. +A: The sysfs files are located on the particular usb endpoint. On most + distributions you can do: "find /sys/ -name get_icons" for a hint. + 2. keyboard features ~~~~~~~~~~~~~~~~~~~~ diff --git a/MAINTAINERS b/MAINTAINERS index 3928dc7d6ea9..2868b2879755 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -116,12 +116,6 @@ M: ajk@iehk.rwth-aachen.de L: linux-hams@vger.kernel.org S: Maintained -YEALINK PHONE DRIVER -P: Henk Vergonet -M: Henk.Vergonet@gmail.com -L: usbb2k-api-dev@nongnu.org -S: Maintained - 8139CP 10/100 FAST ETHERNET DRIVER P: Jeff Garzik M: jgarzik@pobox.com @@ -2863,6 +2857,12 @@ M: jpr@f6fbb.org L: linux-hams@vger.kernel.org S: Maintained +YEALINK PHONE DRIVER +P: Henk Vergonet +M: Henk.Vergonet@gmail.com +L: usbb2k-api-dev@nongnu.org +S: Maintained + YMFPCI YAMAHA PCI SOUND (Use ALSA instead) P: Pete Zaitcev M: zaitcev@yahoo.com diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/usb/input/map_to_7segment.h index 52ff27f15127..a424094d9fe2 100644 --- a/drivers/usb/input/map_to_7segment.h +++ b/drivers/usb/input/map_to_7segment.h @@ -79,7 +79,7 @@ struct seg7_conversion_map { static inline int map_to_seg7(struct seg7_conversion_map *map, int c) { - return c & 0x7f ? map->table[c] : -EINVAL; + return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL; } #define SEG7_CONVERSION_MAP(_name, _map) \ From 1fcb4454cbada6dc495302172ac0412aa7d35fd4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 15 Oct 2005 22:03:30 -0700 Subject: [PATCH 1167/1939] [PATCH] usb doc: fix kernel-doc warning usb/core/buffer.c doesn't export any symbols, so it should use !I instead of !E to eliminate this warning message: Warning(/var/linsrc/linux-2614-rc4//drivers/usb/core/buffer.c): no structured comments found Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/usb.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl index 705c442c7bf4..15ce0f21e5e0 100644 --- a/Documentation/DocBook/usb.tmpl +++ b/Documentation/DocBook/usb.tmpl @@ -291,7 +291,7 @@ !Edrivers/usb/core/hcd.c !Edrivers/usb/core/hcd-pci.c -!Edrivers/usb/core/buffer.c +!Idrivers/usb/core/buffer.c From cb97c5c9d0789d65d7ec42a80946fa9eb2ec5182 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 16 Oct 2005 15:06:51 -0700 Subject: [PATCH 1168/1939] [PATCH] omap_udc dma off-by-one fix The change to make DMA work two bytes at a time omitted an important tweak that affects the file_storage gadget: it needs to recognize when the host writes an odd number of bytes. (The network layer ignores such extra bytes.) This patch resolves that issue by checking the relevant bit and adjusting the rx byte count, so that for example a legal 13 byte request doesn't morph into an illegal 14 byte one any more. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b7885dc0f42f..de8a89ae4bc3 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -691,7 +691,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) } static void -finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) +finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one) { u16 count; @@ -699,6 +699,8 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) ep->dma_counter = (u16) (req->req.dma + req->req.actual); count = dma_dest_len(ep, req->req.dma + req->req.actual); count += req->req.actual; + if (one) + count--; if (count <= req->req.length) req->req.actual = count; @@ -747,7 +749,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src) if (!list_empty(&ep->queue)) { req = container_of(ep->queue.next, struct omap_req, queue); - finish_out_dma(ep, req, 0); + finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB); } UDC_IRQ_SRC_REG = UDC_RXN_EOT; @@ -925,7 +927,7 @@ static void dma_channel_release(struct omap_ep *ep) while (UDC_RXDMA_CFG_REG & mask) udelay(10); if (req) - finish_out_dma(ep, req, -ECONNRESET); + finish_out_dma(ep, req, -ECONNRESET, 0); } omap_free_dma(ep->lch); ep->dma_channel = 0; From f37be9b9be3ebc02d2d075d7f53f7802f3e005db Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 17 Oct 2005 10:42:06 -0400 Subject: [PATCH 1169/1939] [PATCH] Fix hcd->state assignments in uhci-hcd This patch (as581) changes the assignments to hcd->state in the uhci-hcd driver. It fixes part of bugzilla entry #5227. The problem was revealed by David's large suite of USB suspend/resume patches; this patch should go to Linus at the same time those do. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 72cd1576d20c..d33ce3982a5f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -161,8 +161,8 @@ static void configure_hc(struct uhci_hcd *uhci) /* Set the current frame number */ outw(uhci->frame_number, uhci->io_addr + USBFRNUM); - /* Mark controller as running before we enable interrupts */ - uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; + /* Mark controller as not halted before we enable interrupts */ + uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; mb(); /* Enable PIRQ */ @@ -263,6 +263,7 @@ __acquires(uhci->lock) static void start_rh(struct uhci_hcd *uhci) { + uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; uhci->is_stopped = 0; smp_wmb(); @@ -708,7 +709,6 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) if (uhci->rh_state > UHCI_RH_SUSPENDED) { dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); - hcd->state = HC_STATE_RUNNING; rc = -EBUSY; goto done; }; From 4e67185a7ac3ecb1710e636e2f7e318e99298c7a Mon Sep 17 00:00:00 2001 From: Juha Yrj?l? Date: Sun, 16 Oct 2005 15:47:04 -0700 Subject: [PATCH 1170/1939] [PATCH] add usb transceiver set_suspend() method When a USB device is put into suspend mode, the current drawn from VBUS has to be less than 500 uA. Some transceivers need to be put into a special power-saving mode to accomplish this, and won't have a separate OTG driver handling that. This adds a suspend method to the "otg_transceiver" struct -- misnamed, it's not only for OTG -- and calls it from the OMAP UDC driver. Signed-off-by: Juha Yrj?l? Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 4 ++++ include/linux/usb_otg.h | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index de8a89ae4bc3..b42799bc747a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1788,8 +1788,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src) udc->driver->suspend(&udc->gadget); spin_lock(&udc->lock); } + if (udc->transceiver) + otg_set_suspend(udc->transceiver, 1); } else { VDBG("resume\n"); + if (udc->transceiver) + otg_set_suspend(udc->transceiver, 0); if (udc->gadget.speed == USB_SPEED_FULL && udc->driver->resume) { spin_unlock(&udc->lock); diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h index c6683146e9b0..f827f6e203c2 100644 --- a/include/linux/usb_otg.h +++ b/include/linux/usb_otg.h @@ -63,6 +63,10 @@ struct otg_transceiver { int (*set_power)(struct otg_transceiver *otg, unsigned mA); + /* for non-OTG B devices: set transceiver into suspend mode */ + int (*set_suspend)(struct otg_transceiver *otg, + int suspend); + /* for B devices only: start session with A-Host */ int (*start_srp)(struct otg_transceiver *otg); @@ -107,6 +111,15 @@ otg_set_power(struct otg_transceiver *otg, unsigned mA) return otg->set_power(otg, mA); } +static inline int +otg_set_suspend(struct otg_transceiver *otg, int suspend) +{ + if (otg->set_suspend != NULL) + return otg->set_suspend(otg, suspend); + else + return 0; +} + static inline int otg_start_srp(struct otg_transceiver *otg) { From a85ee6b50c8a1fca4034c8d6b21c91a8de171e01 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 10 Oct 2005 01:23:50 +0100 Subject: [PATCH 1171/1939] [PATCH] USB: S3C2410 OHCI - add driver owner field Initialise the .owner field of the driver with the module that owns it, to aid in linking drivers to modules. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-s3c2410.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 3225d455f459..fab420a2ce71 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -474,6 +474,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct device *dev) static struct device_driver ohci_hcd_s3c2410_driver = { .name = "s3c2410-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, From d0d5049fb02fc1082c17e08deecd6fed8db549b6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 10 Oct 2005 10:52:33 +0100 Subject: [PATCH 1172/1939] [PATCH] USB: gadget drivers - add .owner initialisation Ensure the the device_driver and usb_gadget_driver have their .owner fields initialised to associate the module owner to the driver. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 2 ++ drivers/usb/gadget/ether.c | 1 + drivers/usb/gadget/file_storage.c | 1 + drivers/usb/gadget/goku_udc.c | 1 + drivers/usb/gadget/lh7a40x_udc.c | 1 + drivers/usb/gadget/net2280.c | 1 + drivers/usb/gadget/omap_udc.c | 1 + drivers/usb/gadget/pxa2xx_udc.c | 1 + drivers/usb/gadget/zero.c | 1 + 9 files changed, 10 insertions(+) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c605aaeed636..02106bebd5c1 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -967,6 +967,7 @@ static int dummy_udc_resume (struct device *dev) static struct device_driver dummy_udc_driver = { .name = (char *) gadget_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = dummy_udc_probe, .remove = dummy_udc_remove, @@ -1954,6 +1955,7 @@ static int dummy_hcd_resume (struct device *dev) static struct device_driver dummy_hcd_driver = { .name = (char *) driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = dummy_hcd_probe, .remove = dummy_hcd_remove, diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f1024e804d5c..8f402f85e1ca 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2533,6 +2533,7 @@ static struct usb_gadget_driver eth_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .shutdown = ... // .suspend = ... // .resume = ... diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 86a6aeb9ed76..ea09aaa3cab6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -4044,6 +4044,7 @@ static struct usb_gadget_driver fsg_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .release = ... // .suspend = ... // .resume = ... diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index b0f3cd63e3b9..654469778ab5 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1970,6 +1970,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver goku_pci_driver = { .name = (char *) driver_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = goku_probe, .remove = goku_remove, diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 012d1e5f1524..9b3673904daf 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -2140,6 +2140,7 @@ static int lh7a40x_udc_remove(struct device *_dev) static struct device_driver udc_driver = { .name = (char *)driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = lh7a40x_udc_probe, .remove = lh7a40x_udc_remove diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c32e1f7476da..0dc6bb00bf72 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2948,6 +2948,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver net2280_pci_driver = { .name = (char *) driver_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = net2280_probe, .remove = net2280_remove, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b42799bc747a..41c96b0afbb3 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2949,6 +2949,7 @@ static int omap_udc_resume(struct device *dev) static struct device_driver udc_driver = { .name = (char *) driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = omap_udc_probe, .remove = __exit_p(omap_udc_remove), diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 647028590b23..f83a9262f953 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -2631,6 +2631,7 @@ static int pxa2xx_udc_resume(struct device *dev) static struct device_driver udc_driver = { .name = "pxa2xx-udc", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, .shutdown = pxa2xx_udc_shutdown, diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ec9c424f1d97..6c58636e914b 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1302,6 +1302,7 @@ static struct usb_gadget_driver zero_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .shutdown = ... // .suspend = ... // .resume = ... From efa400db5332ba341cc354c9d8a5298ff57faa98 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 10 Oct 2005 02:32:15 +0100 Subject: [PATCH 1173/1939] [PATCH] USB: add owner initialisation to host drivers Add .owner initialisation to the device drivers in drivers/usb/host so that when built as module the device_driver refers to the owning module Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 1 + drivers/usb/host/ohci-au1xxx.c | 1 + drivers/usb/host/ohci-lh7a404.c | 1 + drivers/usb/host/ohci-omap.c | 1 + drivers/usb/host/ohci-pci.c | 1 + drivers/usb/host/ohci-ppc-soc.c | 1 + drivers/usb/host/sl811-hcd.c | 1 + drivers/usb/host/uhci-hcd.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 8bbc8dfe19f3..7872469ccbb1 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -383,6 +383,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver ehci_pci_driver = { .name = (char *) hcd_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index ac463c493035..a277e258eb6c 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -264,6 +264,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct device *dev) static struct device_driver ohci_hcd_au1xxx_driver = { .name = "au1xxx-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e2ed55b69f86..238fa4ade615 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -244,6 +244,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct device *dev) static struct device_driver ohci_hcd_lh7a404_driver = { .name = "lh7a404-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_lh7a404_drv_probe, .remove = ohci_hcd_lh7a404_drv_remove, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 982cdca22516..45efeed1fcc3 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -492,6 +492,7 @@ static int ohci_omap_resume(struct device *dev) */ static struct device_driver ohci_hcd_omap_driver = { .name = "ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a8dde8b75691..bf1d5ab4aa3a 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -216,6 +216,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver ohci_pci_driver = { .name = (char *) hcd_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 228845eb7eab..4832e57ae579 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -193,6 +193,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct device *dev) static struct device_driver ohci_hcd_ppc_soc_driver = { .name = "ppc-soc-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 1e47c1f86e70..40169d9cf2b1 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1831,6 +1831,7 @@ sl811h_resume(struct device *dev) struct device_driver sl811h_driver = { .name = (char *) hcd_name, .bus = &platform_bus_type, + .owner = THIS_MODULE, .probe = sl811h_probe, .remove = __devexit_p(sl811h_remove), diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d33ce3982a5f..15e0a511069b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -831,6 +831,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids); static struct pci_driver uhci_pci_driver = { .name = (char *)hcd_name, .id_table = uhci_pci_ids, + .owner = THIS_MODULE, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, From 3e8a556a02d5aa16375d4d74aad0f67cd844c047 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 18 Oct 2005 10:08:31 -0400 Subject: [PATCH 1174/1939] [PATCH] Missing transfer_flags setting in usbtest This patch (as582) adds a missing transfer_flags setting to the usbtest driver. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index d055196533af..90a96257d6ce 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -983,6 +983,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) reqp->number = i % NUM_SUBCASES; reqp->expected = expected; u->setup_packet = (char *) &reqp->setup; + u->transfer_flags |= URB_NO_SETUP_DMA_MAP; u->context = &context; u->complete = ctrl_complete; From 4592bf5a22593704bb9e8c584a81bf6ca4f6cfec Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1175/1939] [PATCH] USB: remove the global function usbdev_lookup_minor It's only used locally. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 34 +++++++++++++++++----------------- drivers/usb/core/usb.h | 1 - 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6c15dabcfc0b..9222b7a13430 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -517,6 +517,23 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig return ret; } +static struct usb_device *usbdev_lookup_minor(int minor) +{ + struct class_device *class_dev; + struct usb_device *dev = 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; + break; + } + } + up(&usb_device_class->sem); + + return dev; +}; + /* * file operations */ @@ -1533,23 +1550,6 @@ struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -struct usb_device *usbdev_lookup_minor(int minor) -{ - struct class_device *class_dev; - struct usb_device *dev = 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; - break; - } - } - up(&usb_device_class->sem); - - return dev; -}; - void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 4d59f6e07999..3dc8096c0f92 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -64,7 +64,6 @@ extern int usbdev_init(void); extern void usbdev_cleanup(void); extern void usbdev_add(struct usb_device *dev); extern void usbdev_remove(struct usb_device *dev); -extern struct usb_device *usbdev_lookup_minor(int minor); struct dev_state { struct list_head list; /* state list */ From 3099e75a7ccc3c5b0a4cf988a76d9c4a7fa5e91a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1176/1939] [PATCH] USB: add notifier functions to the USB core for devices and busses This should let us get rid of all of the different hooks in the USB core for when something has changed. Also, some other parts of the kernel have wanted to know this kind of information at times. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Makefile | 2 +- drivers/usb/core/hcd.c | 2 + drivers/usb/core/hub.c | 3 + drivers/usb/core/notify.c | 120 ++++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 6 ++ include/linux/usb.h | 8 +++ 6 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/core/notify.c diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index d5503cf0bf74..dd1c4d2a0c31 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -3,7 +3,7 @@ # usbcore-objs := usb.o hub.o hcd.o urb.o message.o \ - config.o file.o buffer.o sysfs.o devio.o + config.o file.o buffer.o sysfs.o devio.o notify.o ifeq ($(CONFIG_PCI),y) usbcore-objs += hcd-pci.o diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9ad3912a5ed7..b700b6cdb683 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -792,6 +792,7 @@ static int usb_register_bus(struct usb_bus *bus) list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); + usb_notify_add_bus(bus); usbfs_add_bus (bus); usbmon_notify_bus_add (bus); @@ -820,6 +821,7 @@ static void usb_deregister_bus (struct usb_bus *bus) list_del (&bus->bus_list); up (&usb_bus_list_lock); + usb_notify_remove_bus(bus); usbmon_notify_bus_remove (bus); usbfs_remove_bus (bus); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 273e6ccca213..4f1a8c8cf92b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1128,6 +1128,8 @@ void usb_disconnect(struct usb_device **pdev) */ usb_disable_device(udev, 0); + usb_notify_remove_device(udev); + /* Free the device number, remove the /proc/bus/usb entry and * the sysfs attributes, and delete the parent's children[] * (or root_hub) pointer. @@ -1371,6 +1373,7 @@ int usb_new_device(struct usb_device *udev) } /* USB device state == configured ... usable */ + usb_notify_add_device(udev); /* add a /proc/bus/usb entry */ usbdev_add(udev); diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c new file mode 100644 index 000000000000..37da059eced7 --- /dev/null +++ b/drivers/usb/core/notify.c @@ -0,0 +1,120 @@ +/* + * All the USB notify logic + * + * (C) Copyright 2005 Greg Kroah-Hartman + * + * notifier functions originally based on those in kernel/sys.c + * but fixed up to not be so broken. + * + */ + + +#include +#include +#include +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include + +#include "usb.h" + + +static struct notifier_block *usb_notifier_list; +static DECLARE_MUTEX(usb_notifier_lock); + +static void usb_notifier_chain_register(struct notifier_block **list, + struct notifier_block *n) +{ + down(&usb_notifier_lock); + while (*list) { + if (n->priority > (*list)->priority) + break; + list = &((*list)->next); + } + n->next = *list; + *list = n; + up(&usb_notifier_lock); +} + +static void usb_notifier_chain_unregister(struct notifier_block **nl, + struct notifier_block *n) +{ + down(&usb_notifier_lock); + while ((*nl)!=NULL) { + if ((*nl)==n) { + *nl = n->next; + goto exit; + } + nl=&((*nl)->next); + } +exit: + up(&usb_notifier_lock); +} + +static int usb_notifier_call_chain(struct notifier_block **n, + unsigned long val, void *v) +{ + int ret=NOTIFY_DONE; + struct notifier_block *nb = *n; + + down(&usb_notifier_lock); + while (nb) { + ret = nb->notifier_call(nb,val,v); + if (ret&NOTIFY_STOP_MASK) { + goto exit; + } + nb = nb->next; + } +exit: + up(&usb_notifier_lock); + return ret; +} + +/** + * usb_register_notify - register a notifier callback whenever a usb change happens + * @nb: pointer to the notifier block for the callback events. + * + * These changes are either USB devices or busses being added or removed. + */ +void usb_register_notify(struct notifier_block *nb) +{ + usb_notifier_chain_register(&usb_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(usb_register_notify); + +/** + * usb_unregister_notify - unregister a notifier callback + * @nb: pointer to the notifier block for the callback events. + * + * usb_register_notifier() must have been previously called for this function + * to work properly. + */ +void usb_unregister_notify(struct notifier_block *nb) +{ + usb_notifier_chain_unregister(&usb_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(usb_unregister_notify); + + +void usb_notify_add_device(struct usb_device *udev) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); +} + +void usb_notify_remove_device(struct usb_device *udev) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); +} + +void usb_notify_add_bus(struct usb_bus *ubus) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); +} + +void usb_notify_remove_bus(struct usb_bus *ubus) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); +} diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3dc8096c0f92..811cf4482e0d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -80,3 +80,9 @@ struct dev_state { unsigned long ifclaimed; }; +/* internal notify stuff */ +extern void usb_notify_add_device(struct usb_device *udev); +extern void usb_notify_remove_device(struct usb_device *udev); +extern void usb_notify_add_bus(struct usb_bus *ubus); +extern void usb_notify_remove_bus(struct usb_bus *ubus); + diff --git a/include/linux/usb.h b/include/linux/usb.h index 207b1ad9d990..a2d923fd54f9 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1135,6 +1135,14 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out) /* -------------------------------------------------------------------------- */ +/* Events from the usb core */ +#define USB_DEVICE_ADD 0x0001 +#define USB_DEVICE_REMOVE 0x0002 +#define USB_BUS_ADD 0x0003 +#define USB_BUS_REMOVE 0x0004 +extern void usb_register_notify(struct notifier_block *nb); +extern void usb_unregister_notify(struct notifier_block *nb); + #ifdef DEBUG #define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg) #else From a7b986b3e107727dd1c1af0ead0b5e52d7726db3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1177/1939] [PATCH] USB: convert usbfs/devio.c to use usb notifiers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 41 +++++++++++++++++++++++++++++++++------- drivers/usb/core/hub.c | 2 -- drivers/usb/core/usb.h | 2 -- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 9222b7a13430..2bd742ba812d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -1550,7 +1551,7 @@ struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -void usbdev_add(struct usb_device *dev) +static void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); @@ -1561,11 +1562,29 @@ void usbdev_add(struct usb_device *dev) dev->class_dev->class_data = dev; } -void usbdev_remove(struct usb_device *dev) +static void usbdev_remove(struct usb_device *dev) { class_device_unregister(dev->class_dev); } +static int usbdev_notify(struct notifier_block *self, unsigned long action, + void *dev) +{ + switch (action) { + case USB_DEVICE_ADD: + usbdev_add(dev); + break; + case USB_DEVICE_REMOVE: + usbdev_remove(dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block usbdev_nb = { + .notifier_call = usbdev_notify, +}; + static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE, @@ -1585,24 +1604,32 @@ int __init usbdev_init(void) retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); if (retval) { err("unable to get usb_device major %d", USB_DEVICE_MAJOR); - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); - goto out; + goto error_cdev; } usb_device_class = class_create(THIS_MODULE, "usb_device"); if (IS_ERR(usb_device_class)) { err("unable to register usb_device class"); retval = PTR_ERR(usb_device_class); - usb_device_class = NULL; - cdev_del(&usb_device_cdev); - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); + goto error_class; } + usb_register_notify(&usbdev_nb); + out: return retval; + +error_class: + usb_device_class = NULL; + cdev_del(&usb_device_cdev); + +error_cdev: + unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); + goto out; } void usbdev_cleanup(void) { + usb_unregister_notify(&usbdev_nb); class_destroy(usb_device_class); cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4f1a8c8cf92b..a9d16aff5de5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1137,7 +1137,6 @@ void usb_disconnect(struct usb_device **pdev) dev_dbg (&udev->dev, "unregistering device\n"); release_address(udev); usbfs_remove_device(udev); - usbdev_remove(udev); usb_remove_sysfs_dev_files(udev); /* Avoid races with recursively_mark_NOTATTACHED() */ @@ -1376,7 +1375,6 @@ int usb_new_device(struct usb_device *udev) usb_notify_add_device(udev); /* add a /proc/bus/usb entry */ - usbdev_add(udev); usbfs_add_device(udev); return 0; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 811cf4482e0d..888dbe443695 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -62,8 +62,6 @@ extern void usbfs_conn_disc_event(void); extern int usbdev_init(void); extern void usbdev_cleanup(void); -extern void usbdev_add(struct usb_device *dev); -extern void usbdev_remove(struct usb_device *dev); struct dev_state { struct list_head list; /* state list */ From 54a5c4cd2e4ec0b27c2c3731727f52591456086c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1178/1939] [PATCH] USB: convert usbfs/inode.c to use usb notifiers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 -- drivers/usb/core/hcd.h | 10 --------- drivers/usb/core/hub.c | 3 --- drivers/usb/core/inode.c | 44 ++++++++++++++++++++++++++++------------ 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index b700b6cdb683..16790ad0e2e4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -793,7 +793,6 @@ static int usb_register_bus(struct usb_bus *bus) up (&usb_bus_list_lock); usb_notify_add_bus(bus); - usbfs_add_bus (bus); usbmon_notify_bus_add (bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); @@ -823,7 +822,6 @@ static void usb_deregister_bus (struct usb_bus *bus) usb_notify_remove_bus(bus); usbmon_notify_bus_remove (bus); - usbfs_remove_bus (bus); clear_bit (bus->busnum, busmap.busmap); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index d8f0d29a45b7..cc33886260cd 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -400,23 +400,13 @@ static inline int hcd_bus_resume (struct usb_bus *bus) * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbfs_add_bus(struct usb_bus *bus); -extern void usbfs_remove_bus(struct usb_bus *bus); -extern void usbfs_add_device(struct usb_device *dev); -extern void usbfs_remove_device(struct usb_device *dev); extern void usbfs_update_special (void); - extern int usbfs_init(void); extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbfs_add_bus(struct usb_bus *bus) {} -static inline void usbfs_remove_bus(struct usb_bus *bus) {} -static inline void usbfs_add_device(struct usb_device *dev) {} -static inline void usbfs_remove_device(struct usb_device *dev) {} static inline void usbfs_update_special (void) {} - static inline int usbfs_init(void) { return 0; } static inline void usbfs_cleanup(void) { } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a9d16aff5de5..6a2ebd89916f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1136,7 +1136,6 @@ void usb_disconnect(struct usb_device **pdev) */ dev_dbg (&udev->dev, "unregistering device\n"); release_address(udev); - usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); /* Avoid races with recursively_mark_NOTATTACHED() */ @@ -1374,8 +1373,6 @@ int usb_new_device(struct usb_device *udev) /* USB device state == configured ... usable */ usb_notify_add_device(udev); - /* add a /proc/bus/usb entry */ - usbfs_add_device(udev); return 0; fail: diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index d07bba01995b..12f490fdee8f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "usb.h" #include "hcd.h" @@ -619,7 +620,7 @@ void usbfs_update_special (void) } } -void usbfs_add_bus(struct usb_bus *bus) +static void usbfs_add_bus(struct usb_bus *bus) { struct dentry *parent; char name[8]; @@ -642,12 +643,9 @@ void usbfs_add_bus(struct usb_bus *bus) err ("error creating usbfs bus entry"); return; } - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_remove_bus(struct usb_bus *bus) +static void usbfs_remove_bus(struct usb_bus *bus) { if (bus->usbfs_dentry) { fs_remove_file (bus->usbfs_dentry); @@ -659,12 +657,9 @@ void usbfs_remove_bus(struct usb_bus *bus) remove_special_files(); num_buses = 0; } - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_add_device(struct usb_device *dev) +static void usbfs_add_device(struct usb_device *dev) { char name[8]; int i; @@ -690,12 +685,9 @@ void usbfs_add_device(struct usb_device *dev) } if (dev->usbfs_dentry->d_inode) dev->usbfs_dentry->d_inode->i_size = i_size; - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_remove_device(struct usb_device *dev) +static void usbfs_remove_device(struct usb_device *dev) { struct dev_state *ds; struct siginfo sinfo; @@ -716,10 +708,33 @@ void usbfs_remove_device(struct usb_device *dev) kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid); } } +} + +static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) +{ + switch (action) { + case USB_DEVICE_ADD: + usbfs_add_device(dev); + break; + case USB_DEVICE_REMOVE: + usbfs_remove_device(dev); + break; + case USB_BUS_ADD: + usbfs_add_bus(dev); + break; + case USB_BUS_REMOVE: + usbfs_remove_bus(dev); + } + usbfs_update_special(); usbfs_conn_disc_event(); + return NOTIFY_OK; } +static struct notifier_block usbfs_nb = { + .notifier_call = usbfs_notify, +}; + /* --------------------------------------------------------------------- */ static struct proc_dir_entry *usbdir = NULL; @@ -732,6 +747,8 @@ int __init usbfs_init(void) if (retval) return retval; + usb_register_notify(&usbfs_nb); + /* create mount point for usbfs */ usbdir = proc_mkdir("usb", proc_bus); @@ -740,6 +757,7 @@ int __init usbfs_init(void) void usbfs_cleanup(void) { + usb_unregister_notify(&usbfs_nb); unregister_filesystem(&usb_fs_type); if (usbdir) remove_proc_entry("usb", proc_bus); From 72adaa962741e8e910300b66bb123b1a9c31a8a8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1179/1939] [PATCH] USB: convert usbmon to use usb notifiers This also removes 2 usbmon callbacks. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 -- drivers/usb/core/hcd.h | 16 ---------------- drivers/usb/mon/mon_main.c | 23 +++++++++++++++++++++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 16790ad0e2e4..e8f2b8d8f14d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -793,7 +793,6 @@ static int usb_register_bus(struct usb_bus *bus) up (&usb_bus_list_lock); usb_notify_add_bus(bus); - usbmon_notify_bus_add (bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); return 0; @@ -821,7 +820,6 @@ static void usb_deregister_bus (struct usb_bus *bus) up (&usb_bus_list_lock); usb_notify_remove_bus(bus); - usbmon_notify_bus_remove (bus); clear_bit (bus->busnum, busmap.busmap); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index cc33886260cd..a5d92943ff95 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -421,8 +421,6 @@ struct usb_mon_operations { void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); void (*urb_complete)(struct usb_bus *bus, struct urb *urb); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ - void (*bus_add)(struct usb_bus *bus); - void (*bus_remove)(struct usb_bus *bus); }; extern struct usb_mon_operations *mon_ops; @@ -445,18 +443,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) if (bus->monitored) (*mon_ops->urb_complete)(bus, urb); } - -static inline void usbmon_notify_bus_add(struct usb_bus *bus) -{ - if (mon_ops) - (*mon_ops->bus_add)(bus); -} - -static inline void usbmon_notify_bus_remove(struct usb_bus *bus) -{ - if (mon_ops) - (*mon_ops->bus_remove)(bus); -} int usb_mon_register(struct usb_mon_operations *ops); void usb_mon_deregister(void); @@ -467,8 +453,6 @@ static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} -static inline void usbmon_notify_bus_add(struct usb_bus *bus) {} -static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {} #endif /* CONFIG_USB_MON */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 508a21028db4..c34944c75047 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "usb_mon.h" #include "../core/hcd.h" @@ -205,6 +206,23 @@ static void mon_bus_remove(struct usb_bus *ubus) up(&mon_lock); } +static int mon_notify(struct notifier_block *self, unsigned long action, + void *dev) +{ + switch (action) { + case USB_BUS_ADD: + mon_bus_add(dev); + break; + case USB_BUS_REMOVE: + mon_bus_remove(dev); + } + return NOTIFY_OK; +} + +static struct notifier_block mon_nb = { + .notifier_call = mon_notify, +}; + /* * Ops */ @@ -212,8 +230,6 @@ static struct usb_mon_operations mon_ops_0 = { .urb_submit = mon_submit, .urb_submit_error = mon_submit_error, .urb_complete = mon_complete, - .bus_add = mon_bus_add, - .bus_remove = mon_bus_remove, }; /* @@ -329,6 +345,8 @@ static int __init mon_init(void) } // MOD_INC_USE_COUNT(which_module?); + usb_register_notify(&mon_nb); + down(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { mon_bus_init(mondir, ubus); @@ -342,6 +360,7 @@ static void __exit mon_exit(void) struct mon_bus *mbus; struct list_head *p; + usb_unregister_notify(&mon_nb); usb_mon_deregister(); down(&mon_lock); From c36fc889b5a4fd66cfd9ba80d9e038745d349567 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 17 Oct 2005 18:15:54 -0700 Subject: [PATCH 1180/1939] [PATCH] usb: Patch for USBDEVFS_IOCTL from 32-bit programs Dell supplied me with the following test: #include #include #include #include #include main(int argc,char*argv[]) { struct usbdevfs_hub_portinfo hubPortInfo = {0}; struct usbdevfs_ioctl command = {0}; command.ifno = 0; command.ioctl_code = USBDEVFS_HUB_PORTINFO; command.data = (void*)&hubPortInfo; int fd, ret; if(argc != 2) { fprintf(stderr,"Usage: %s /proc/bus/usb//\n",argv[0]); fprintf(stderr,"Example: %s /proc/bus/usb/001/001\n",argv[0]); exit(1); } errno = 0; fd = open(argv[1],O_RDWR); if(fd < 0) { perror("open failed:"); exit(errno); } errno = 0; ret = ioctl(fd,USBDEVFS_IOCTL,&command); printf("IOCTL return status:%d\n",ret); if(ret<0) { perror("IOCTL failed:"); close(fd); exit(3); } else { printf("IOCTL passed:Num of ports %d\n",hubPortInfo.nports); close(fd); exit(0); } return 0; } I have verified that it breaks if built in 32 bit mode on x86_64 and that the patch below fixes it. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 56 +++++++++++++++++++++++++++--------- fs/compat_ioctl.c | 1 + include/linux/usbdevice_fs.h | 7 +++++ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2bd742ba812d..ffb2e242b100 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1301,23 +1301,20 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg) return 0; } -static int proc_ioctl (struct dev_state *ps, void __user *arg) +static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) { - struct usbdevfs_ioctl ctrl; int size; void *buf = NULL; int retval = 0; struct usb_interface *intf = NULL; struct usb_driver *driver = NULL; - /* get input parameters and alloc buffer */ - if (copy_from_user(&ctrl, arg, sizeof (ctrl))) - return -EFAULT; - if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { + /* alloc buffer */ + if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) return -ENOMEM; - if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { - if (copy_from_user (buf, ctrl.data, size)) { + if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { + if (copy_from_user (buf, ctl->data, size)) { kfree(buf); return -EFAULT; } @@ -1333,9 +1330,9 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) if (ps->dev->state != USB_STATE_CONFIGURED) retval = -EHOSTUNREACH; - else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) retval = -EINVAL; - else switch (ctrl.ioctl_code) { + else switch (ctl->ioctl_code) { /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: @@ -1367,7 +1364,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { - retval = driver->ioctl (intf, ctrl.ioctl_code, buf); + retval = driver->ioctl (intf, ctl->ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -1376,15 +1373,42 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) /* cleanup and return */ if (retval >= 0 - && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 + && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 && size > 0 - && copy_to_user (ctrl.data, buf, size) != 0) + && copy_to_user (ctl->data, buf, size) != 0) retval = -EFAULT; kfree(buf); return retval; } +static int proc_ioctl_default(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_ioctl ctrl; + + if (copy_from_user(&ctrl, arg, sizeof (ctrl))) + return -EFAULT; + return proc_ioctl(ps, &ctrl); +} + +#ifdef CONFIG_COMPAT +static int proc_ioctl_compat(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_ioctl32 __user *uioc; + struct usbdevfs_ioctl ctrl; + u32 udata; + + uioc = compat_ptr(arg); + if (get_user(ctrl.ifno, &uioc->ifno) || + get_user(ctrl.ioctl_code, &uioc->ioctl_code) || + __get_user(udata, &uioc->data)) + return -EFAULT; + ctrl.data = compat_ptr(udata); + + return proc_ioctl(ps, &ctrl); +} +#endif + /* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from @@ -1485,6 +1509,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ret = proc_reapurbnonblock_compat(ps, p); break; + case USBDEVFS_IOCTL32: + snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + ret = proc_ioctl_compat(ps, p); + break; #endif case USBDEVFS_DISCARDURB: @@ -1519,7 +1547,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd case USBDEVFS_IOCTL: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); - ret = proc_ioctl(ps, p); + ret = proc_ioctl_default(ps, p); break; } usb_unlock_device(dev); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e28a74203f3b..a327e03753ac 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -3050,6 +3050,7 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl) HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control) HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk) HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) +COMPATIBLE_IOCTL(USBDEVFS_IOCTL32) /* i2c */ HANDLE_IOCTL(I2C_FUNCS, w_long) HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index 9facf733800c..8859f0b41543 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -140,6 +140,12 @@ struct usbdevfs_urb32 { compat_caddr_t usercontext; /* unused */ struct usbdevfs_iso_packet_desc iso_frame_desc[0]; }; + +struct usbdevfs_ioctl32 { + s32 ifno; + s32 ioctl_code; + compat_caddr_t data; +}; #endif #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) @@ -160,6 +166,7 @@ struct usbdevfs_urb32 { #define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) #define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo) #define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl) +#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32) #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) #define USBDEVFS_RESET _IO('U', 20) #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) From a6c82600d4058346ea6fd801bc21d7abcc1350d8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1181/1939] [PATCH] USB: delete the bluetty driver We have a real Bluetooth system in Linux, lets finally delete this driver as no one is using it (and if they are, they are using a closed source bluetooth stack, which I can't support anyway.) Marcel, you owe me a beer :) Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 8 - drivers/usb/Makefile | 1 - drivers/usb/class/Kconfig | 23 - drivers/usb/class/Makefile | 1 - drivers/usb/class/bluetty.c | 1279 ----------------------------------- 5 files changed, 1312 deletions(-) delete mode 100644 drivers/usb/class/bluetty.c diff --git a/MAINTAINERS b/MAINTAINERS index 2868b2879755..770155a01523 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2489,14 +2489,6 @@ L: linux-kernel@vger.kernel.org L: linux-usb-devel@lists.sourceforge.net S: Supported -USB BLUETOOTH TTY CONVERTER DRIVER -P: Greg Kroah-Hartman -M: greg@kroah.com -L: linux-usb-users@lists.sourceforge.net -L: linux-usb-devel@lists.sourceforge.net -S: Maintained -W: http://www.kroah.com/linux-usb/ - USB CDC ETHERNET DRIVER P: Greg Kroah-Hartman M: greg@kroah.com diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index aa554f9805ee..a50c2bc506f2 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_AUDIO) += class/ -obj-$(CONFIG_USB_BLUETOOTH_TTY) += class/ obj-$(CONFIG_USB_MIDI) += class/ obj-$(CONFIG_USB_PRINTER) += class/ diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 333e39bb105f..ef105a92a7bd 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -28,29 +28,6 @@ config USB_AUDIO To compile this driver as a module, choose M here: the module will be called audio. -comment "USB Bluetooth TTY can only be used with disabled Bluetooth subsystem" - depends on USB && BT - -config USB_BLUETOOTH_TTY - tristate "USB Bluetooth TTY support" - depends on USB && BT=n - ---help--- - This driver implements a nonstandard tty interface to a Bluetooth - device that can be used only by specialized Bluetooth HCI software. - - Say Y here if you want to use OpenBT Bluetooth stack (available - at ), or other TTY based - Bluetooth stacks, and want to connect a USB Bluetooth device - to your computer's USB port. - - Do *not* enable this driver if you want to use generic Linux - Bluetooth support. - - If in doubt, say N here. - - To compile this driver as a module, choose M here: the - module will be called bluetty. - config USB_MIDI tristate "USB MIDI support" depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile index 971e5497a3fd..229471247751 100644 --- a/drivers/usb/class/Makefile +++ b/drivers/usb/class/Makefile @@ -5,6 +5,5 @@ obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_AUDIO) += audio.o -obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o obj-$(CONFIG_USB_MIDI) += usb-midi.o obj-$(CONFIG_USB_PRINTER) += usblp.o diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c deleted file mode 100644 index 524023327c49..000000000000 --- a/drivers/usb/class/bluetty.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * bluetty.c Version 0.13 - * - * Copyright (C) 2000, 2001 Greg Kroah-Hartman - * Copyright (C) 2000 Mark Douglas Corner - * - * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B - * - * (2001/11/30) Version 0.13 gkh - * - added locking patch from Masoodur Rahman - * - removed active variable, as open_count will do. - * - * (2001/07/09) Version 0.12 gkh - * - removed in_interrupt() call, as it doesn't make sense to do - * that anymore. - * - * (2001/06/05) Version 0.11 gkh - * - Fixed problem with read urb status saying that we have shutdown, - * and that we shouldn't resubmit the urb. Patch from unknown. - * - * (2001/05/28) Version 0.10 gkh - * - Fixed problem with using data from userspace in the bluetooth_write - * function as found by the CHECKER project. - * - Added a buffer to the write_urb_pool which reduces the number of - * buffers being created and destroyed for ever write. Also cleans - * up the logic a bit. - * - Added a buffer to the control_urb_pool which fixes a memory leak - * when the device is removed from the system. - * - * (2001/05/28) Version 0.9 gkh - * Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback - * which was found by both the CHECKER project and Mikko Rahkonen. - * - * (08/04/2001) gb - * Identify version on module load. - * - * (2001/03/10) Version 0.8 gkh - * Fixed problem with not unlinking interrupt urb on device close - * and resubmitting the read urb on error with bluetooth struct. - * Thanks to Narayan Mohanram for the - * fixes. - * - * (11/29/2000) Version 0.7 gkh - * Fixed problem with overrunning the tty flip buffer. - * Removed unneeded NULL pointer initialization. - * - * (10/05/2000) Version 0.6 gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * Got a real major id number and name. - * - * (08/06/2000) Version 0.5 gkh - * Fixed problem of not resubmitting the bulk read urb if there is - * an error in the callback. Ericsson devices seem to need this. - * - * (07/11/2000) Version 0.4 gkh - * Fixed bug in disconnect for when we call tty_hangup - * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not - * getting attached to the control urb properly. - * Fixed bug in bluetooth_write where we pay attention to the result - * of bluetooth_ctrl_msg. - * - * (08/03/2000) Version 0.3 gkh mdc - * Merged in Mark's changes to make the driver play nice with the Axis - * stack. - * Made the write bulk use an urb pool to enable larger transfers with - * fewer calls to the driver. - * Fixed off by one bug in acl pkt receive - * Made packet counters specific to each bluetooth device - * Added checks for zero length callbacks - * Added buffers for int and bulk packets. Had to do this otherwise - * packet types could intermingle. - * Made a control urb pool for the control messages. - * - * (07/11/2000) Version 0.2 gkh - * Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe - * function. - * - * (07/09/2000) Version 0.1 gkh - * Initial release. Has support for sending ACL data (which is really just - * a HCI frame.) Raw HCI commands and HCI events are not supported. - * A ioctl will probably be needed for the HCI commands and events in the - * future. All isoch endpoints are ignored at this time also. - * This driver should work for all currently shipping USB Bluetooth - * devices at this time :) - * - */ - -/* - * 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 - -#define DEBUG -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.13" -#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner" -#define DRIVER_DESC "USB Bluetooth tty driver" - -/* define this if you have hardware that is not good */ -/*#define BTBUGGYHARDWARE */ - -/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ -#define WIRELESS_CLASS_CODE 0xe0 -#define RF_SUBCLASS_CODE 0x01 -#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE 0x01 - - -#define BLUETOOTH_TTY_MAJOR 216 /* real device node major id */ -#define BLUETOOTH_TTY_MINORS 256 /* whole lotta bluetooth devices */ - -#define USB_BLUETOOTH_MAGIC 0x6d02 /* magic number for bluetooth struct */ - -#define BLUETOOTH_CONTROL_REQUEST_TYPE 0x20 - -/* Bluetooth packet types */ -#define CMD_PKT 0x01 -#define ACL_PKT 0x02 -#define SCO_PKT 0x03 -#define EVENT_PKT 0x04 -#define ERROR_PKT 0x05 -#define NEG_PKT 0x06 - -/* Message sizes */ -#define MAX_EVENT_SIZE 0xFF -#define EVENT_HDR_SIZE 3 /* 2 for the header + 1 for the type indicator */ -#define EVENT_BUFFER_SIZE (MAX_EVENT_SIZE + EVENT_HDR_SIZE) - -#define MAX_ACL_SIZE 0xFFFF -#define ACL_HDR_SIZE 5 /* 4 for the header + 1 for the type indicator */ -#define ACL_BUFFER_SIZE (MAX_ACL_SIZE + ACL_HDR_SIZE) - -/* parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -#define CHAR2INT16(c1,c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff)) - -#define NUM_BULK_URBS 24 -#define NUM_CONTROL_URBS 16 - -struct usb_bluetooth { - int magic; - struct usb_device * dev; - struct tty_driver * tty_driver; /* the tty_driver for this device */ - struct tty_struct * tty; /* the corresponding tty for this port */ - - unsigned char minor; /* the starting minor number for this device */ - int throttle; /* throttled by tty layer */ - int open_count; - - __u8 control_out_bInterfaceNum; - struct urb * control_urb_pool[NUM_CONTROL_URBS]; - struct usb_ctrlrequest dr[NUM_CONTROL_URBS]; - - unsigned char * interrupt_in_buffer; - struct urb * interrupt_in_urb; - __u8 interrupt_in_endpointAddress; - __u8 interrupt_in_interval; - int interrupt_in_buffer_size; - - unsigned char * bulk_in_buffer; - struct urb * read_urb; - __u8 bulk_in_endpointAddress; - int bulk_in_buffer_size; - - int bulk_out_buffer_size; - __u8 bulk_out_endpointAddress; - - wait_queue_head_t write_wait; - - struct work_struct work; /* work queue entry for line discipline waking up */ - - unsigned int int_packet_pos; - unsigned char int_buffer[EVENT_BUFFER_SIZE]; - unsigned int bulk_packet_pos; - unsigned char bulk_buffer[ACL_BUFFER_SIZE]; /* 64k preallocated, fix? */ - struct semaphore lock; -}; - - -/* local function prototypes */ -static int bluetooth_open (struct tty_struct *tty, struct file *filp); -static void bluetooth_close (struct tty_struct *tty, struct file *filp); -static int bluetooth_write (struct tty_struct *tty, const unsigned char *buf, int count); -static int bluetooth_write_room (struct tty_struct *tty); -static int bluetooth_chars_in_buffer (struct tty_struct *tty); -static void bluetooth_throttle (struct tty_struct *tty); -static void bluetooth_unthrottle (struct tty_struct *tty); -static int bluetooth_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void bluetooth_set_termios (struct tty_struct *tty, struct termios *old); - -static void bluetooth_int_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_ctrl_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs); - -static int usb_bluetooth_probe (struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_bluetooth_disconnect (struct usb_interface *intf); - - -static struct usb_device_id usb_bluetooth_ids [] = { - { USB_DEVICE_INFO(WIRELESS_CLASS_CODE, RF_SUBCLASS_CODE, BLUETOOTH_PROGRAMMING_PROTOCOL_CODE) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); - -static struct usb_driver usb_bluetooth_driver = { - .owner = THIS_MODULE, - .name = "bluetty", - .probe = usb_bluetooth_probe, - .disconnect = usb_bluetooth_disconnect, - .id_table = usb_bluetooth_ids, -}; - -static struct tty_driver *bluetooth_tty_driver; -static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS]; - - -static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function) -{ - if (!bluetooth) { - dbg("%s - bluetooth == NULL", function); - return -1; - } - if (bluetooth->magic != USB_BLUETOOTH_MAGIC) { - dbg("%s - bad magic number for bluetooth", function); - return -1; - } - - return 0; -} - - -static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function) -{ - if (!bluetooth || - bluetooth_paranoia_check (bluetooth, function)) { - /* then say that we don't have a valid usb_bluetooth thing, which will - * end up generating -ENODEV return values */ - return NULL; - } - - return bluetooth; -} - - -static inline struct usb_bluetooth *get_bluetooth_by_index (int index) -{ - return bluetooth_table[index]; -} - - -static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len) -{ - struct urb *urb = NULL; - struct usb_ctrlrequest *dr = NULL; - int i; - int status; - - dbg ("%s", __FUNCTION__); - - /* try to find a free urb in our list */ - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) { - urb = bluetooth->control_urb_pool[i]; - dr = &bluetooth->dr[i]; - break; - } - } - if (urb == NULL) { - dbg ("%s - no free urbs", __FUNCTION__); - return -ENOMEM; - } - - /* keep increasing the urb transfer buffer to fit the size of the message */ - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (len, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - err ("%s - out of memory", __FUNCTION__); - return -ENOMEM; - } - } - if (urb->transfer_buffer_length < len) { - kfree(urb->transfer_buffer); - urb->transfer_buffer = kmalloc (len, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - err ("%s - out of memory", __FUNCTION__); - return -ENOMEM; - } - } - memcpy (urb->transfer_buffer, buf, len); - - dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE; - dr->bRequest = request; - dr->wValue = cpu_to_le16((u16) value); - dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum); - dr->wLength = cpu_to_le16((u16) len); - - usb_fill_control_urb (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), - (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) - dbg("%s - usb_submit_urb(control) failed with status = %d", __FUNCTION__, status); - - return status; -} - - - - - -/***************************************************************************** - * Driver tty interface functions - *****************************************************************************/ -static int bluetooth_open (struct tty_struct *tty, struct file * filp) -{ - struct usb_bluetooth *bluetooth; - int result; - - dbg("%s", __FUNCTION__); - - /* initialize the pointer incase something fails */ - tty->driver_data = NULL; - - /* get the bluetooth object associated with this tty pointer */ - bluetooth = get_bluetooth_by_index (tty->index); - - if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) { - return -ENODEV; - } - - down (&bluetooth->lock); - - ++bluetooth->open_count; - if (bluetooth->open_count == 1) { - /* set up our structure making the tty driver remember our object, and us it */ - tty->driver_data = bluetooth; - bluetooth->tty = tty; - - /* force low_latency on so that our tty_push actually forces the data through, - * otherwise it is scheduled, and with high data rates (like with OHCI) data - * can get lost. */ - bluetooth->tty->low_latency = 1; - - /* Reset the packet position counters */ - bluetooth->int_packet_pos = 0; - bluetooth->bulk_packet_pos = 0; - -#ifndef BTBUGGYHARDWARE - /* Start reading from the device */ - usb_fill_bulk_urb (bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, - bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result); -#endif - usb_fill_int_urb (bluetooth->interrupt_in_urb, bluetooth->dev, - usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress), - bluetooth->interrupt_in_buffer, - bluetooth->interrupt_in_buffer_size, - bluetooth_int_callback, bluetooth, - bluetooth->interrupt_in_interval); - result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL); - if (result) - dbg("%s - usb_submit_urb(interrupt in) failed with status %d", __FUNCTION__, result); - } - - up(&bluetooth->lock); - - return 0; -} - - -static void bluetooth_close (struct tty_struct *tty, struct file * filp) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not opened", __FUNCTION__); - return; - } - - down (&bluetooth->lock); - - --bluetooth->open_count; - if (bluetooth->open_count <= 0) { - bluetooth->open_count = 0; - - /* shutdown any in-flight urbs that we know about */ - usb_kill_urb (bluetooth->read_urb); - usb_kill_urb (bluetooth->interrupt_in_urb); - } - up(&bluetooth->lock); -} - - -static int bluetooth_write (struct tty_struct * tty, const unsigned char *buf, int count) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - struct urb *urb = NULL; - unsigned char *temp_buffer = NULL; - const unsigned char *current_buffer; - unsigned char *urb_buffer; - int i; - int retval = 0; - - if (!bluetooth) { - return -ENODEV; - } - - dbg("%s - %d byte(s)", __FUNCTION__, count); - - if (!bluetooth->open_count) { - dbg ("%s - device not opened", __FUNCTION__); - return -EINVAL; - } - - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); - return 0; - } - if (count == 1) { - dbg("%s - write request only included type %d", __FUNCTION__, buf[0]); - return 1; - } - -#ifdef DEBUG - printk (KERN_DEBUG __FILE__ ": %s - length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); -#endif - - current_buffer = buf; - - switch (*current_buffer) { - /* First byte indicates the type of packet */ - case CMD_PKT: - /* dbg("%s- Send cmd_pkt len:%d", __FUNCTION__, count);*/ - - retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, ¤t_buffer[1], count-1); - if (retval) { - goto exit; - } - retval = count; - break; - - case ACL_PKT: - ++current_buffer; - --count; - - urb_buffer = kmalloc (count, GFP_ATOMIC); - if (!urb_buffer) { - dev_err(&bluetooth->dev->dev, "out of memory\n"); - retval = -ENOMEM; - goto exit; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&bluetooth->dev->dev, "no more free urbs\n"); - kfree(urb_buffer); - retval = -ENOMEM; - goto exit; - } - memcpy (urb_buffer, current_buffer, count); - - /* build up our urb */ - usb_fill_bulk_urb(urb, bluetooth->dev, - usb_sndbulkpipe(bluetooth->dev, - bluetooth->bulk_out_endpointAddress), - urb_buffer, - count, - bluetooth_write_bulk_callback, - bluetooth); - - - /* send it down the pipe */ - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, retval); - goto exit; - } - - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb (urb); - retval = count + 1; - break; - - default : - dbg("%s - unsupported (at this time) write type", __FUNCTION__); - retval = -EINVAL; - break; - } - -exit: - kfree(temp_buffer); - - return retval; -} - - -static int bluetooth_write_room (struct tty_struct *tty) -{ - dbg("%s", __FUNCTION__); - - /* - * We really can take anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space - */ - return 2048; -} - - -static int bluetooth_chars_in_buffer (struct tty_struct *tty) -{ - dbg("%s", __FUNCTION__); - - /* - * We can't really account for how much data we - * have sent out, but hasn't made it through to the - * device, so just tell the tty layer that everything - * is flushed. - */ - return 0; -} - - -static void bluetooth_throttle (struct tty_struct * tty) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - dbg("%s unsupported (at this time)", __FUNCTION__); - - return; -} - - -static void bluetooth_unthrottle (struct tty_struct * tty) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - dbg("%s unsupported (at this time)", __FUNCTION__); -} - - -static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return -ENODEV; - } - - dbg("%s - cmd 0x%.4x", __FUNCTION__, cmd); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return -ENODEV; - } - - /* FIXME!!! */ - return -ENOIOCTLCMD; -} - - -static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - /* FIXME!!! */ - - return; -} - - -#ifdef BTBUGGYHARDWARE -void btusb_enable_bulk_read(struct tty_struct *tty){ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - int result; - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - if (bluetooth->read_urb) { - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed submitting read urb, error %d", __FUNCTION__, result); - } -} - -void btusb_disable_bulk_read(struct tty_struct *tty){ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length)) - usb_kill_urb(bluetooth->read_urb); -} -#endif - - -/***************************************************************************** - * urb callback functions - *****************************************************************************/ - - -static void bluetooth_int_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - unsigned char *data = urb->transfer_buffer; - unsigned int i; - unsigned int count = urb->actual_length; - unsigned int packet_size; - int status; - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - if (!count) { - dbg("%s - zero length int", __FUNCTION__); - goto exit; - } - - -#ifdef DEBUG - if (count) { - printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif - -#ifdef BTBUGGYHARDWARE - if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) { - data += 2; - count -= 2; - } - if (count == 0) { - urb->actual_length = 0; - goto exit; - } -#endif - /* We add a packet type identifier to the beginning of each - HCI frame. This makes the data in the tty look like a - serial USB devices. Each HCI frame can be broken across - multiple URBs so we buffer them until we have a full hci - packet */ - - if (!bluetooth->int_packet_pos) { - bluetooth->int_buffer[0] = EVENT_PKT; - bluetooth->int_packet_pos++; - } - - if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) { - err("%s - exceeded EVENT_BUFFER_SIZE", __FUNCTION__); - bluetooth->int_packet_pos = 0; - goto exit; - } - - memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos], - urb->transfer_buffer, count); - bluetooth->int_packet_pos += count; - urb->actual_length = 0; - - if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE) - packet_size = bluetooth->int_buffer[2]; - else - goto exit; - - if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) { - err("%s - packet was too long", __FUNCTION__); - bluetooth->int_packet_pos = 0; - goto exit; - } - - if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) { - for (i = 0; i < bluetooth->int_packet_pos; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */ - if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(bluetooth->tty); - } - tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0); - } - tty_flip_buffer_push(bluetooth->tty); - - bluetooth->int_packet_pos = 0; - } - -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - - -static void bluetooth_ctrl_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - return; - } -} - - -static void bluetooth_read_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - unsigned char *data = urb->transfer_buffer; - unsigned int count = urb->actual_length; - unsigned int i; - unsigned int packet_size; - int result; - - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - if (urb->status == -ENOENT) { - dbg("%s - URB canceled, won't reschedule", __FUNCTION__); - return; - } - goto exit; - } - - if (!count) { - dbg("%s - zero length read bulk", __FUNCTION__); - goto exit; - } - -#ifdef DEBUG - if (count) { - printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif -#ifdef BTBUGGYHARDWARE - if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00) - && (data[2] == 0x00) && (data[3] == 0x00)) { - urb->actual_length = 0; - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - - return; - } -#endif - /* We add a packet type identifier to the beginning of each - HCI frame. This makes the data in the tty look like a - serial USB devices. Each HCI frame can be broken across - multiple URBs so we buffer them until we have a full hci - packet */ - - if (!bluetooth->bulk_packet_pos) { - bluetooth->bulk_buffer[0] = ACL_PKT; - bluetooth->bulk_packet_pos++; - } - - if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) { - err("%s - exceeded ACL_BUFFER_SIZE", __FUNCTION__); - bluetooth->bulk_packet_pos = 0; - goto exit; - } - - memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos], - urb->transfer_buffer, count); - bluetooth->bulk_packet_pos += count; - urb->actual_length = 0; - - if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) { - packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]); - } else { - goto exit; - } - - if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) { - err("%s - packet was too long", __FUNCTION__); - bluetooth->bulk_packet_pos = 0; - goto exit; - } - - if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) { - for (i = 0; i < bluetooth->bulk_packet_pos; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ - if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(bluetooth->tty); - } - tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0); - } - tty_flip_buffer_push(bluetooth->tty); - bluetooth->bulk_packet_pos = 0; - } - -exit: - if (!bluetooth || !bluetooth->open_count) - return; - - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - - return; -} - - -static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - /* wake up our little function to let the tty layer know that something happened */ - schedule_work(&bluetooth->work); -} - - -static void bluetooth_softint(void *private) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - if (!bluetooth) - return; - - tty_wakeup(bluetooth->tty); -} - - -static int usb_bluetooth_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev (intf); - struct usb_bluetooth *bluetooth = NULL; - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[8]; - struct usb_endpoint_descriptor *bulk_in_endpoint[8]; - struct usb_endpoint_descriptor *bulk_out_endpoint[8]; - int control_out_endpoint; - - int minor; - int buffer_size; - int i; - int num_interrupt_in = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; - - interface = intf->cur_altsetting; - control_out_endpoint = interface->desc.bInterfaceNumber; - - /* find the endpoints that we need */ - for (i = 0; i < interface->desc.bNumEndpoints; ++i) { - endpoint = &interface->endpoint[i].desc; - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - dbg("found bulk in"); - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk out endpoint */ - dbg("found bulk out"); - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x03)) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in"); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - } - - /* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */ - if ((num_bulk_in != 1) || - (num_bulk_out != 1) || - (num_interrupt_in != 1)) { - dbg ("%s - improper number of endpoints. Bluetooth driver not bound.", __FUNCTION__); - return -EIO; - } - - info("USB Bluetooth converter detected"); - - for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor) - ; - if (bluetooth_table[minor]) { - err("No more free Bluetooth devices"); - return -ENODEV; - } - - if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) { - err("Out of memory"); - return -ENOMEM; - } - - memset(bluetooth, 0, sizeof(struct usb_bluetooth)); - - bluetooth->magic = USB_BLUETOOTH_MAGIC; - bluetooth->dev = dev; - bluetooth->minor = minor; - INIT_WORK(&bluetooth->work, bluetooth_softint, bluetooth); - init_MUTEX(&bluetooth->lock); - - /* record the interface number for the control out */ - bluetooth->control_out_bInterfaceNum = control_out_endpoint; - - /* create our control out urb pool */ - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); - if (urb == NULL) { - err("No free urbs available"); - goto probe_error; - } - urb->transfer_buffer = NULL; - bluetooth->control_urb_pool[i] = urb; - } - - /* set up the endpoint information */ - endpoint = bulk_in_endpoint[0]; - bluetooth->read_urb = usb_alloc_urb (0, GFP_KERNEL); - if (!bluetooth->read_urb) { - err("No free urbs available"); - goto probe_error; - } - bluetooth->bulk_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - bluetooth->bulk_in_endpointAddress = endpoint->bEndpointAddress; - bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!bluetooth->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); - goto probe_error; - } - usb_fill_bulk_urb(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), - bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth); - - endpoint = bulk_out_endpoint[0]; - bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress; - bluetooth->bulk_out_buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2; - - endpoint = interrupt_in_endpoint[0]; - bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!bluetooth->interrupt_in_urb) { - err("No free urbs available"); - goto probe_error; - } - bluetooth->interrupt_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - bluetooth->interrupt_in_endpointAddress = endpoint->bEndpointAddress; - bluetooth->interrupt_in_interval = endpoint->bInterval; - bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!bluetooth->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); - goto probe_error; - } - usb_fill_int_urb(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback, - bluetooth, endpoint->bInterval); - - /* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */ - tty_register_device (bluetooth_tty_driver, minor, &intf->dev); - info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor); - - bluetooth_table[minor] = bluetooth; - - /* success */ - usb_set_intfdata (intf, bluetooth); - return 0; - -probe_error: - if (bluetooth->read_urb) - usb_free_urb (bluetooth->read_urb); - if (bluetooth->bulk_in_buffer) - kfree (bluetooth->bulk_in_buffer); - if (bluetooth->interrupt_in_urb) - usb_free_urb (bluetooth->interrupt_in_urb); - if (bluetooth->interrupt_in_buffer) - kfree (bluetooth->interrupt_in_buffer); - for (i = 0; i < NUM_CONTROL_URBS; ++i) - if (bluetooth->control_urb_pool[i]) { - if (bluetooth->control_urb_pool[i]->transfer_buffer) - kfree (bluetooth->control_urb_pool[i]->transfer_buffer); - usb_free_urb (bluetooth->control_urb_pool[i]); - } - - bluetooth_table[minor] = NULL; - - /* free up any memory that we allocated */ - kfree (bluetooth); - return -EIO; -} - - -static void usb_bluetooth_disconnect(struct usb_interface *intf) -{ - struct usb_bluetooth *bluetooth = usb_get_intfdata (intf); - int i; - - usb_set_intfdata (intf, NULL); - if (bluetooth) { - if ((bluetooth->open_count) && (bluetooth->tty)) - tty_hangup(bluetooth->tty); - - bluetooth->open_count = 0; - - if (bluetooth->read_urb) { - usb_kill_urb (bluetooth->read_urb); - usb_free_urb (bluetooth->read_urb); - } - if (bluetooth->bulk_in_buffer) - kfree (bluetooth->bulk_in_buffer); - - if (bluetooth->interrupt_in_urb) { - usb_kill_urb (bluetooth->interrupt_in_urb); - usb_free_urb (bluetooth->interrupt_in_urb); - } - if (bluetooth->interrupt_in_buffer) - kfree (bluetooth->interrupt_in_buffer); - - tty_unregister_device (bluetooth_tty_driver, bluetooth->minor); - - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - if (bluetooth->control_urb_pool[i]) { - usb_kill_urb (bluetooth->control_urb_pool[i]); - if (bluetooth->control_urb_pool[i]->transfer_buffer) - kfree (bluetooth->control_urb_pool[i]->transfer_buffer); - usb_free_urb (bluetooth->control_urb_pool[i]); - } - } - - info("Bluetooth converter now disconnected from ttyUB%d", bluetooth->minor); - - bluetooth_table[bluetooth->minor] = NULL; - - /* free up any memory that we allocated */ - kfree (bluetooth); - } else { - info("device disconnected"); - } -} - -static struct tty_operations bluetooth_ops = { - .open = bluetooth_open, - .close = bluetooth_close, - .write = bluetooth_write, - .write_room = bluetooth_write_room, - .ioctl = bluetooth_ioctl, - .set_termios = bluetooth_set_termios, - .throttle = bluetooth_throttle, - .unthrottle = bluetooth_unthrottle, - .chars_in_buffer = bluetooth_chars_in_buffer, -}; - -static int usb_bluetooth_init(void) -{ - int i; - int result; - - /* Initialize our global data */ - for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) { - bluetooth_table[i] = NULL; - } - - info ("USB Bluetooth support registered"); - - bluetooth_tty_driver = alloc_tty_driver(BLUETOOTH_TTY_MINORS); - if (!bluetooth_tty_driver) - return -ENOMEM; - - bluetooth_tty_driver->owner = THIS_MODULE; - bluetooth_tty_driver->driver_name = "usb-bluetooth"; - bluetooth_tty_driver->name = "ttyUB"; - bluetooth_tty_driver->devfs_name = "usb/ttub/"; - bluetooth_tty_driver->major = BLUETOOTH_TTY_MAJOR; - bluetooth_tty_driver->minor_start = 0; - bluetooth_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - bluetooth_tty_driver->subtype = SERIAL_TYPE_NORMAL; - bluetooth_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - bluetooth_tty_driver->init_termios = tty_std_termios; - bluetooth_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(bluetooth_tty_driver, &bluetooth_ops); - if (tty_register_driver (bluetooth_tty_driver)) { - err("%s - failed to register tty driver", __FUNCTION__); - put_tty_driver(bluetooth_tty_driver); - return -1; - } - - /* register the USB driver */ - result = usb_register(&usb_bluetooth_driver); - if (result < 0) { - tty_unregister_driver(bluetooth_tty_driver); - put_tty_driver(bluetooth_tty_driver); - err("usb_register failed for the USB bluetooth driver. Error number %d", result); - return -1; - } - - info(DRIVER_DESC " " DRIVER_VERSION); - - return 0; -} - - -static void usb_bluetooth_exit(void) -{ - usb_deregister(&usb_bluetooth_driver); - tty_unregister_driver(bluetooth_tty_driver); - put_tty_driver(bluetooth_tty_driver); -} - - -module_init(usb_bluetooth_init); -module_exit(usb_bluetooth_exit); - -/* Module information */ -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - From ea65370d025f5005649e5cb37c4d025e92c6fc38 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1182/1939] [PATCH] USB Serial: rename usb_serial_device_type to usb_serial_driver I'm tired of trying to explain why a "device_type" is really a driver. This better describes exactly what this structure is. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 2 +- drivers/usb/serial/belkin_sa.c | 2 +- drivers/usb/serial/bus.c | 28 ++++++++++++------------- drivers/usb/serial/cp2101.c | 2 +- drivers/usb/serial/cyberjack.c | 2 +- drivers/usb/serial/cypress_m8.c | 4 ++-- drivers/usb/serial/digi_acceleport.c | 4 ++-- drivers/usb/serial/empeg.c | 2 +- drivers/usb/serial/ftdi_sio.c | 2 +- drivers/usb/serial/garmin_gps.c | 7 +------ drivers/usb/serial/generic.c | 2 +- drivers/usb/serial/hp4x.c | 2 +- drivers/usb/serial/io_tables.h | 6 +++--- drivers/usb/serial/io_ti.c | 4 ++-- drivers/usb/serial/ipaq.c | 2 +- drivers/usb/serial/ipw.c | 2 +- drivers/usb/serial/ir-usb.c | 2 +- drivers/usb/serial/keyspan.h | 8 +++---- drivers/usb/serial/keyspan_pda.c | 6 +++--- drivers/usb/serial/kl5kusb105.c | 2 +- drivers/usb/serial/kobil_sct.c | 2 +- drivers/usb/serial/mct_u232.c | 2 +- drivers/usb/serial/omninet.c | 2 +- drivers/usb/serial/option.c | 2 +- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/safe_serial.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 4 ++-- drivers/usb/serial/usb-serial.c | 30 +++++++++++++-------------- drivers/usb/serial/usb-serial.h | 28 ++++++++++++------------- drivers/usb/serial/visor.c | 6 +++--- drivers/usb/serial/whiteheat.c | 4 ++-- 31 files changed, 85 insertions(+), 90 deletions(-) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 926d4c2c1600..104c04385bb9 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -30,7 +30,7 @@ static struct usb_driver airprime_driver = { .id_table = id_table, }; -static struct usb_serial_device_type airprime_device = { +static struct usb_serial_driver airprime_device = { .owner = THIS_MODULE, .name = "airprime", .id_table = id_table, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index abb1b2c543bb..6d84de40cb7b 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -121,7 +121,7 @@ static struct usb_driver belkin_driver = { }; /* All of the device info needed for the serial converters */ -static struct usb_serial_device_type belkin_device = { +static struct usb_serial_driver belkin_device = { .owner = THIS_MODULE, .name = "Belkin / Peracom / GoHubs USB Serial Adapter", .short_name = "belkin", diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 2f612c2d894b..5a0bcd34bb6d 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -18,7 +18,7 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *drv) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; const struct usb_serial_port *port; /* @@ -44,7 +44,7 @@ struct bus_type usb_serial_bus_type = { static int usb_serial_device_probe (struct device *dev) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; int minor; @@ -80,7 +80,7 @@ static int usb_serial_device_probe (struct device *dev) static int usb_serial_device_remove (struct device *dev) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; int minor; @@ -109,26 +109,26 @@ static int usb_serial_device_remove (struct device *dev) return retval; } -int usb_serial_bus_register(struct usb_serial_device_type *device) +int usb_serial_bus_register(struct usb_serial_driver *driver) { int retval; - if (device->short_name) - device->driver.name = (char *)device->short_name; + if (driver->short_name) + driver->driver.name = (char *)driver->short_name; else - device->driver.name = (char *)device->name; - device->driver.bus = &usb_serial_bus_type; - device->driver.probe = usb_serial_device_probe; - device->driver.remove = usb_serial_device_remove; - device->driver.owner = device->owner; + driver->driver.name = (char *)driver->name; + driver->driver.bus = &usb_serial_bus_type; + driver->driver.probe = usb_serial_device_probe; + driver->driver.remove = usb_serial_device_remove; + driver->driver.owner = driver->owner; - retval = driver_register(&device->driver); + retval = driver_register(&driver->driver); return retval; } -void usb_serial_bus_deregister(struct usb_serial_device_type *device) +void usb_serial_bus_deregister(struct usb_serial_driver *driver) { - driver_unregister (&device->driver); + driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 97c78c21e8d1..0b45b58bef5f 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -73,7 +73,7 @@ static struct usb_driver cp2101_driver = { .id_table = id_table, }; -static struct usb_serial_device_type cp2101_device = { +static struct usb_serial_driver cp2101_device = { .owner = THIS_MODULE, .name = "CP2101", .id_table = id_table, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index b5b431067b08..9f421a3c47e8 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -83,7 +83,7 @@ static struct usb_driver cyberjack_driver = { .id_table = id_table, }; -static struct usb_serial_device_type cyberjack_device = { +static struct usb_serial_driver cyberjack_device = { .owner = THIS_MODULE, .name = "Reiner SCT Cyberjack USB card reader", .short_name = "cyberjack", diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 9ee1aaff2fcd..4fb8e59d1527 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -176,7 +176,7 @@ static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, u static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count); -static struct usb_serial_device_type cypress_earthmate_device = { +static struct usb_serial_driver cypress_earthmate_device = { .owner = THIS_MODULE, .name = "DeLorme Earthmate USB", .short_name = "earthmate", @@ -203,7 +203,7 @@ static struct usb_serial_device_type cypress_earthmate_device = { .write_int_callback = cypress_write_int_callback, }; -static struct usb_serial_device_type cypress_hidcom_device = { +static struct usb_serial_driver cypress_hidcom_device = { .owner = THIS_MODULE, .name = "HID->COM RS232 Adapter", .short_name = "cyphidcom", diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index a19a47f6cf12..66feb88b4316 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -503,7 +503,7 @@ static struct usb_driver digi_driver = { /* device info needed for the Digi serial converter */ -static struct usb_serial_device_type digi_acceleport_2_device = { +static struct usb_serial_driver digi_acceleport_2_device = { .owner = THIS_MODULE, .name = "Digi 2 port USB adapter", .short_name = "digi_2", @@ -530,7 +530,7 @@ static struct usb_serial_device_type digi_acceleport_2_device = { .shutdown = digi_shutdown, }; -static struct usb_serial_device_type digi_acceleport_4_device = { +static struct usb_serial_driver digi_acceleport_4_device = { .owner = THIS_MODULE, .name = "Digi 4 port USB adapter", .short_name = "digi_4", diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 8d562ab454a8..cbea8b38b60e 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -112,7 +112,7 @@ static struct usb_driver empeg_driver = { .id_table = id_table, }; -static struct usb_serial_device_type empeg_device = { +static struct usb_serial_driver empeg_device = { .owner = THIS_MODULE, .name = "Empeg", .id_table = id_table, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b713113c1650..529e1a7ccfa0 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -562,7 +562,7 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud); static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); -static struct usb_serial_device_type ftdi_sio_device = { +static struct usb_serial_driver ftdi_sio_device = { .owner = THIS_MODULE, .name = "FTDI USB Serial Device", .short_name = "ftdi_sio", diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 2ef614d5c8f2..7361194f1d66 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1468,13 +1468,8 @@ static void garmin_shutdown (struct usb_serial *serial) } - - - - - /* All of the device info needed */ -static struct usb_serial_device_type garmin_device = { +static struct usb_serial_driver garmin_device = { .owner = THIS_MODULE, .name = "Garmin GPS usb/tty", .short_name = "garmin_gps", diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 5f7d3193d355..7f567bf96549 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -36,7 +36,7 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ /* All of the device info needed for the Generic Serial Converter */ -struct usb_serial_device_type usb_serial_generic_device = { +struct usb_serial_driver usb_serial_generic_device = { .owner = THIS_MODULE, .name = "Generic", .short_name = "generic", diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 64d55fbd206e..b49469907a87 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -44,7 +44,7 @@ static struct usb_driver hp49gp_driver = { .id_table = id_table, }; -static struct usb_serial_device_type hp49gp_device = { +static struct usb_serial_driver hp49gp_device = { .owner = THIS_MODULE, .name = "HP4X", .id_table = id_table, diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index e7ffe02408bd..7314c04727fe 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -75,7 +75,7 @@ static struct usb_device_id id_table_combined [] = { MODULE_DEVICE_TABLE (usb, id_table_combined); -static struct usb_serial_device_type edgeport_2port_device = { +static struct usb_serial_driver edgeport_2port_device = { .owner = THIS_MODULE, .name = "Edgeport 2 port adapter", .short_name = "edgeport_2", @@ -103,7 +103,7 @@ static struct usb_serial_device_type edgeport_2port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; -static struct usb_serial_device_type edgeport_4port_device = { +static struct usb_serial_driver edgeport_4port_device = { .owner = THIS_MODULE, .name = "Edgeport 4 port adapter", .short_name = "edgeport_4", @@ -131,7 +131,7 @@ static struct usb_serial_device_type edgeport_4port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; -static struct usb_serial_device_type edgeport_8port_device = { +static struct usb_serial_driver edgeport_8port_device = { .owner = THIS_MODULE, .name = "Edgeport 8 port adapter", .short_name = "edgeport_8", diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ebf9967f7c86..4328cc702ef7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2982,7 +2982,7 @@ static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, } -static struct usb_serial_device_type edgeport_1port_device = { +static struct usb_serial_driver edgeport_1port_device = { .owner = THIS_MODULE, .name = "Edgeport TI 1 port adapter", .short_name = "edgeport_ti_1", @@ -3010,7 +3010,7 @@ static struct usb_serial_device_type edgeport_1port_device = { .write_bulk_callback = edge_bulk_out_callback, }; -static struct usb_serial_device_type edgeport_2port_device = { +static struct usb_serial_driver edgeport_2port_device = { .owner = THIS_MODULE, .name = "Edgeport TI 2 port adapter", .short_name = "edgeport_ti_2", diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c05c2a2a0f31..9a79ad8d7a5f 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -547,7 +547,7 @@ static struct usb_driver ipaq_driver = { /* All of the device info needed for the Compaq iPAQ */ -static struct usb_serial_device_type ipaq_device = { +static struct usb_serial_driver ipaq_device = { .owner = THIS_MODULE, .name = "PocketPC PDA", .id_table = ipaq_id_table, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 85e242459c27..04524d34de3b 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -443,7 +443,7 @@ static int ipw_disconnect(struct usb_serial_port *port) return 0; } -static struct usb_serial_device_type ipw_device = { +static struct usb_serial_driver ipw_device = { .owner = THIS_MODULE, .name = "IPWireless converter", .short_name = "ipw", diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 937b2fdd7171..ecfb2060ea0f 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -133,7 +133,7 @@ static struct usb_driver ir_driver = { }; -static struct usb_serial_device_type ir_device = { +static struct usb_serial_driver ir_device = { .owner = THIS_MODULE, .name = "IR Dongle", .id_table = id_table, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index e9b45b768aca..97e7d9e53e39 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -570,7 +570,7 @@ static struct usb_device_id keyspan_4port_ids[] = { }; /* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_device_type keyspan_pre_device = { +static struct usb_serial_driver keyspan_pre_device = { .owner = THIS_MODULE, .name = "Keyspan - (without firmware)", .short_name = "keyspan_no_firm", @@ -582,7 +582,7 @@ static struct usb_serial_device_type keyspan_pre_device = { .attach = keyspan_fake_startup, }; -static struct usb_serial_device_type keyspan_1port_device = { +static struct usb_serial_driver keyspan_1port_device = { .owner = THIS_MODULE, .name = "Keyspan 1 port adapter", .short_name = "keyspan_1", @@ -607,7 +607,7 @@ static struct usb_serial_device_type keyspan_1port_device = { .shutdown = keyspan_shutdown, }; -static struct usb_serial_device_type keyspan_2port_device = { +static struct usb_serial_driver keyspan_2port_device = { .owner = THIS_MODULE, .name = "Keyspan 2 port adapter", .short_name = "keyspan_2", @@ -632,7 +632,7 @@ static struct usb_serial_device_type keyspan_2port_device = { .shutdown = keyspan_shutdown, }; -static struct usb_serial_device_type keyspan_4port_device = { +static struct usb_serial_driver keyspan_4port_device = { .owner = THIS_MODULE, .name = "Keyspan 4 port adapter", .short_name = "keyspan_4", diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 635c384cb15a..8fad0e963dd3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -783,7 +783,7 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) } #ifdef KEYSPAN -static struct usb_serial_device_type keyspan_pda_fake_device = { +static struct usb_serial_driver keyspan_pda_fake_device = { .owner = THIS_MODULE, .name = "Keyspan PDA - (prerenumeration)", .short_name = "keyspan_pda_pre", @@ -797,7 +797,7 @@ static struct usb_serial_device_type keyspan_pda_fake_device = { #endif #ifdef XIRCOM -static struct usb_serial_device_type xircom_pgs_fake_device = { +static struct usb_serial_driver xircom_pgs_fake_device = { .owner = THIS_MODULE, .name = "Xircom / Entregra PGS - (prerenumeration)", .short_name = "xircom_no_firm", @@ -810,7 +810,7 @@ static struct usb_serial_device_type xircom_pgs_fake_device = { }; #endif -static struct usb_serial_device_type keyspan_pda_device = { +static struct usb_serial_driver keyspan_pda_device = { .owner = THIS_MODULE, .name = "Keyspan PDA", .short_name = "keyspan_pda", diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index a11e829e38c8..be082706b952 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -123,7 +123,7 @@ static struct usb_driver kl5kusb105d_driver = { .id_table = id_table, }; -static struct usb_serial_device_type kl5kusb105d_device = { +static struct usb_serial_driver kl5kusb105d_device = { .owner = THIS_MODULE, .name = "KL5KUSB105D / PalmConnect", .short_name = "kl5kusb105d", diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index fe4c98a75171..94944340bb8d 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -105,7 +105,7 @@ static struct usb_driver kobil_driver = { }; -static struct usb_serial_device_type kobil_device = { +static struct usb_serial_driver kobil_device = { .owner = THIS_MODULE, .name = "KOBIL USB smart card terminal", .id_table = id_table, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 50b6369647d2..9470964316a7 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -132,7 +132,7 @@ static struct usb_driver mct_u232_driver = { .id_table = id_table_combined, }; -static struct usb_serial_device_type mct_u232_device = { +static struct usb_serial_driver mct_u232_device = { .owner = THIS_MODULE, .name = "MCT U232", .short_name = "mct_u232", diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 6a99ae192df1..53c0588877c0 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -88,7 +88,7 @@ static struct usb_driver omninet_driver = { }; -static struct usb_serial_device_type zyxel_omninet_device = { +static struct usb_serial_driver zyxel_omninet_device = { .owner = THIS_MODULE, .name = "ZyXEL - omni.net lcd plus usb", .short_name = "omninet", diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4989e5740d18..6ec9266e2e96 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -105,7 +105,7 @@ static struct usb_driver option_driver = { /* The card has three separate interfaces, wich the serial driver * recognizes separately, thus num_port=1. */ -static struct usb_serial_device_type option_3port_device = { +static struct usb_serial_driver option_3port_device = { .owner = THIS_MODULE, .name = "Option 3G data card", .short_name = "option", diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 3cf245bdda54..7134648e078d 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -175,7 +175,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, /* All of the device info needed for the PL2303 SIO serial converter */ -static struct usb_serial_device_type pl2303_device = { +static struct usb_serial_driver pl2303_device = { .owner = THIS_MODULE, .name = "PL-2303", .id_table = id_table, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 88bf14abfa7a..87871bb647df 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -397,7 +397,7 @@ static int safe_startup (struct usb_serial *serial) return 0; } -static struct usb_serial_device_type safe_device = { +static struct usb_serial_driver safe_device = { .owner = THIS_MODULE, .name = "Safe", .id_table = id_table, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 59c88de3e7ae..f2efaf6f3d76 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -255,7 +255,7 @@ static struct usb_driver ti_usb_driver = { .id_table = ti_id_table_combined, }; -static struct usb_serial_device_type ti_1port_device = { +static struct usb_serial_driver ti_1port_device = { .owner = THIS_MODULE, .name = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, @@ -282,7 +282,7 @@ static struct usb_serial_device_type ti_1port_device = { .write_bulk_callback = ti_bulk_out_callback, }; -static struct usb_serial_device_type ti_2port_device = { +static struct usb_serial_driver ti_2port_device = { .owner = THIS_MODULE, .name = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e77fbdfc782d..cf083da15eb4 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -823,7 +823,7 @@ static void port_release(struct device *dev) static struct usb_serial * create_serial (struct usb_device *dev, struct usb_interface *interface, - struct usb_serial_device_type *type) + struct usb_serial_driver *driver) { struct usb_serial *serial; @@ -834,22 +834,22 @@ static struct usb_serial * create_serial (struct usb_device *dev, } memset (serial, 0, sizeof(*serial)); serial->dev = usb_get_dev(dev); - serial->type = type; + serial->type = driver; serial->interface = interface; kref_init(&serial->kref); return serial; } -static struct usb_serial_device_type *search_serial_device(struct usb_interface *iface) +static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; const struct usb_device_id *id; - struct usb_serial_device_type *t; + struct usb_serial_driver *t; /* List trough know devices and see if the usb id matches */ list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_device_type, driver_list); + t = list_entry(p, struct usb_serial_driver, driver_list); id = usb_match_id(iface, t->id_table); if (id != NULL) { dbg("descriptor matches"); @@ -872,7 +872,7 @@ int usb_serial_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; - struct usb_serial_device_type *type = NULL; + struct usb_serial_driver *type = NULL; int retval; int minor; int buffer_size; @@ -1375,7 +1375,7 @@ module_exit(usb_serial_exit); } \ } while (0) -static void fixup_generic(struct usb_serial_device_type *device) +static void fixup_generic(struct usb_serial_driver *device) { set_to_generic_if_null(device, open); set_to_generic_if_null(device, write); @@ -1387,28 +1387,28 @@ static void fixup_generic(struct usb_serial_device_type *device) set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_device_type *new_device) +int usb_serial_register(struct usb_serial_driver *driver) { int retval; - fixup_generic(new_device); + fixup_generic(driver); /* Add this device to our list of devices */ - list_add(&new_device->driver_list, &usb_serial_driver_list); + list_add(&driver->driver_list, &usb_serial_driver_list); - retval = usb_serial_bus_register(new_device); + retval = usb_serial_bus_register(driver); if (retval) { - err("problem %d when registering driver %s", retval, new_device->name); - list_del(&new_device->driver_list); + err("problem %d when registering driver %s", retval, driver->name); + list_del(&driver->driver_list); } else - info("USB Serial support registered for %s", new_device->name); + info("USB Serial support registered for %s", driver->name); return retval; } -void usb_serial_deregister(struct usb_serial_device_type *device) +void usb_serial_deregister(struct usb_serial_driver *device) { info("USB Serial deregistering driver %s", device->name); list_del(&device->driver_list); diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 57f92f054c75..d6738b1b0429 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -143,7 +143,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void /** * usb_serial - structure used by the usb-serial core for a device * @dev: pointer to the struct usb_device for this device - * @type: pointer to the struct usb_serial_device_type for this device + * @type: pointer to the struct usb_serial_driver for this device * @interface: pointer to the struct usb_interface for this device * @minor: the starting minor number for this device * @num_ports: the number of ports this device has @@ -159,7 +159,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void */ struct usb_serial { struct usb_device * dev; - struct usb_serial_device_type * type; + struct usb_serial_driver * type; struct usb_interface * interface; unsigned char minor; unsigned char num_ports; @@ -188,11 +188,11 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) } /** - * usb_serial_device_type - a structure that defines a usb serial device - * @owner: pointer to the module that owns this device. - * @name: pointer to a string that describes this device. This string used + * usb_serial_driver - describes a usb serial driver + * @owner: pointer to the module that owns this driver. + * @name: pointer to a string that describes this driver. This string used * in the syslog messages when a device is inserted or removed. - * @short_name: a pointer to a string that describes this device in + * @short_name: a pointer to a string that describes this driver in * KOBJ_NAME_LEN characters or less. This is used for the sysfs interface * to describe the driver. * @id_table: pointer to a list of usb_device_id structures that define all @@ -221,13 +221,13 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * @shutdown: pointer to the driver's shutdown function. This will be * called when the device is removed from the system. * - * This structure is defines a USB Serial device. It provides all of + * This structure is defines a USB Serial driver. It provides all of * the information that the USB serial core code needs. If the function * pointers are defined, then the USB serial core code will call them when * the corresponding tty port functions are called. If they are not * called, the generic serial function will be used instead. */ -struct usb_serial_device_type { +struct usb_serial_driver { struct module *owner; char *name; char *short_name; @@ -269,10 +269,10 @@ struct usb_serial_device_type { void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); }; -#define to_usb_serial_driver(d) container_of(d, struct usb_serial_device_type, driver) +#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver) -extern int usb_serial_register(struct usb_serial_device_type *new_device); -extern void usb_serial_deregister(struct usb_serial_device_type *device); +extern int usb_serial_register(struct usb_serial_driver *driver); +extern void usb_serial_deregister(struct usb_serial_driver *driver); extern void usb_serial_port_softint(void *private); extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); @@ -303,10 +303,10 @@ extern void usb_serial_generic_shutdown (struct usb_serial *serial); extern int usb_serial_generic_register (int debug); extern void usb_serial_generic_deregister (void); -extern int usb_serial_bus_register (struct usb_serial_device_type *device); -extern void usb_serial_bus_deregister (struct usb_serial_device_type *device); +extern int usb_serial_bus_register (struct usb_serial_driver *device); +extern void usb_serial_bus_deregister (struct usb_serial_driver *device); -extern struct usb_serial_device_type usb_serial_generic_device; +extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 31c57adcb623..825451b3788c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -311,7 +311,7 @@ static struct usb_driver visor_driver = { }; /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ -static struct usb_serial_device_type handspring_device = { +static struct usb_serial_driver handspring_device = { .owner = THIS_MODULE, .name = "Handspring Visor / Palm OS", .short_name = "visor", @@ -339,7 +339,7 @@ static struct usb_serial_device_type handspring_device = { }; /* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ -static struct usb_serial_device_type clie_5_device = { +static struct usb_serial_driver clie_5_device = { .owner = THIS_MODULE, .name = "Sony Clie 5.0", .short_name = "clie_5", @@ -367,7 +367,7 @@ static struct usb_serial_device_type clie_5_device = { }; /* device info for the Sony Clie OS version 3.5 */ -static struct usb_serial_device_type clie_3_5_device = { +static struct usb_serial_driver clie_3_5_device = { .owner = THIS_MODULE, .name = "Sony Clie 3.5", .short_name = "clie_3.5", diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index cf3bc30675a1..dc06664bfa0e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -156,7 +156,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port); static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs); static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs); -static struct usb_serial_device_type whiteheat_fake_device = { +static struct usb_serial_driver whiteheat_fake_device = { .owner = THIS_MODULE, .name = "Connect Tech - WhiteHEAT - (prerenumeration)", .short_name = "whiteheatnofirm", @@ -169,7 +169,7 @@ static struct usb_serial_device_type whiteheat_fake_device = { .attach = whiteheat_firmware_attach, }; -static struct usb_serial_device_type whiteheat_device = { +static struct usb_serial_driver whiteheat_device = { .owner = THIS_MODULE, .name = "Connect Tech - WhiteHEAT", .short_name = "whiteheat", From 18fcac353fdc7cd072b0d24c8667042e675a4c11 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1183/1939] [PATCH] USB Serial: get rid of the .owner field in usb_serial_driver Don't duplicate something that's already in struct driver. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 4 +++- drivers/usb/serial/belkin_sa.c | 4 +++- drivers/usb/serial/bus.c | 9 ++++----- drivers/usb/serial/cp2101.c | 4 +++- drivers/usb/serial/cyberjack.c | 4 +++- drivers/usb/serial/cypress_m8.c | 8 ++++++-- drivers/usb/serial/digi_acceleport.c | 8 ++++++-- drivers/usb/serial/empeg.c | 4 +++- drivers/usb/serial/ftdi_sio.c | 4 +++- drivers/usb/serial/garmin_gps.c | 4 +++- drivers/usb/serial/generic.c | 4 +++- drivers/usb/serial/hp4x.c | 4 +++- drivers/usb/serial/io_tables.h | 12 +++++++++--- drivers/usb/serial/io_ti.c | 8 ++++++-- drivers/usb/serial/ipaq.c | 4 +++- drivers/usb/serial/ipw.c | 4 +++- drivers/usb/serial/ir-usb.c | 4 +++- drivers/usb/serial/keyspan.h | 16 ++++++++++++---- drivers/usb/serial/keyspan_pda.c | 12 +++++++++--- drivers/usb/serial/kl5kusb105.c | 4 +++- drivers/usb/serial/kobil_sct.c | 4 +++- drivers/usb/serial/mct_u232.c | 4 +++- drivers/usb/serial/omninet.c | 4 +++- drivers/usb/serial/option.c | 4 +++- drivers/usb/serial/pl2303.c | 4 +++- drivers/usb/serial/safe_serial.c | 4 +++- drivers/usb/serial/ti_usb_3410_5052.c | 8 ++++++-- drivers/usb/serial/usb-serial.c | 22 +++++++++++----------- drivers/usb/serial/usb-serial.h | 5 +++-- drivers/usb/serial/visor.c | 12 +++++++++--- drivers/usb/serial/whiteheat.c | 8 ++++++-- 31 files changed, 144 insertions(+), 60 deletions(-) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 104c04385bb9..fbc5b9b44749 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -31,7 +31,9 @@ static struct usb_driver airprime_driver = { }; static struct usb_serial_driver airprime_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "airprime", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 6d84de40cb7b..4878961a0900 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -122,7 +122,9 @@ static struct usb_driver belkin_driver = { /* All of the device info needed for the serial converters */ static struct usb_serial_driver belkin_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Belkin / Peracom / GoHubs USB Serial Adapter", .short_name = "belkin", .id_table = id_table_combined, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 5a0bcd34bb6d..b8364a8de7df 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -57,13 +57,13 @@ static int usb_serial_device_probe (struct device *dev) driver = port->serial->type; if (driver->port_probe) { - if (!try_module_get(driver->owner)) { + if (!try_module_get(driver->driver.owner)) { dev_err(dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } retval = driver->port_probe (port); - module_put(driver->owner); + module_put(driver->driver.owner); if (retval) goto exit; } @@ -92,13 +92,13 @@ static int usb_serial_device_remove (struct device *dev) driver = port->serial->type; if (driver->port_remove) { - if (!try_module_get(driver->owner)) { + if (!try_module_get(driver->driver.owner)) { dev_err(dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } retval = driver->port_remove (port); - module_put(driver->owner); + module_put(driver->driver.owner); } exit: minor = port->number; @@ -120,7 +120,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) driver->driver.bus = &usb_serial_bus_type; driver->driver.probe = usb_serial_device_probe; driver->driver.remove = usb_serial_device_remove; - driver->driver.owner = driver->owner; retval = driver_register(&driver->driver); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 0b45b58bef5f..81dd720a122b 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -74,7 +74,9 @@ static struct usb_driver cp2101_driver = { }; static struct usb_serial_driver cp2101_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "CP2101", .id_table = id_table, .num_interrupt_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 9f421a3c47e8..3441bad74f7b 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -84,7 +84,9 @@ static struct usb_driver cyberjack_driver = { }; static struct usb_serial_driver cyberjack_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Reiner SCT Cyberjack USB card reader", .short_name = "cyberjack", .id_table = id_table, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 4fb8e59d1527..b4069af4d565 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -177,7 +177,9 @@ static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigne static struct usb_serial_driver cypress_earthmate_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "DeLorme Earthmate USB", .short_name = "earthmate", .id_table = id_table_earthmate, @@ -204,7 +206,9 @@ static struct usb_serial_driver cypress_earthmate_device = { }; static struct usb_serial_driver cypress_hidcom_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "HID->COM RS232 Adapter", .short_name = "cyphidcom", .id_table = id_table_cyphidcomrs232, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 66feb88b4316..be9b495d2491 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -504,7 +504,9 @@ static struct usb_driver digi_driver = { /* device info needed for the Digi serial converter */ static struct usb_serial_driver digi_acceleport_2_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Digi 2 port USB adapter", .short_name = "digi_2", .id_table = id_table_2, @@ -531,7 +533,9 @@ static struct usb_serial_driver digi_acceleport_2_device = { }; static struct usb_serial_driver digi_acceleport_4_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Digi 4 port USB adapter", .short_name = "digi_4", .id_table = id_table_4, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index cbea8b38b60e..3e6c4ba7667b 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -113,7 +113,9 @@ static struct usb_driver empeg_driver = { }; static struct usb_serial_driver empeg_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Empeg", .id_table = id_table, .num_interrupt_in = 0, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 529e1a7ccfa0..9d945de0acac 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -563,7 +563,9 @@ static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); static struct usb_serial_driver ftdi_sio_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "FTDI USB Serial Device", .short_name = "ftdi_sio", .id_table = id_table_combined, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 7361194f1d66..3fd98c00cd6a 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1470,7 +1470,9 @@ static void garmin_shutdown (struct usb_serial *serial) /* All of the device info needed */ static struct usb_serial_driver garmin_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Garmin GPS usb/tty", .short_name = "garmin_gps", .id_table = id_table, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 7f567bf96549..779bea0c6242 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -37,7 +37,9 @@ static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Generic", .short_name = "generic", .id_table = generic_device_ids, diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index b49469907a87..4f3cbc08c4ee 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -45,7 +45,9 @@ static struct usb_driver hp49gp_driver = { }; static struct usb_serial_driver hp49gp_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "HP4X", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 7314c04727fe..28fb0d42a166 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -76,7 +76,9 @@ static struct usb_device_id id_table_combined [] = { MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_serial_driver edgeport_2port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Edgeport 2 port adapter", .short_name = "edgeport_2", .id_table = edgeport_2port_id_table, @@ -104,7 +106,9 @@ static struct usb_serial_driver edgeport_2port_device = { }; static struct usb_serial_driver edgeport_4port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Edgeport 4 port adapter", .short_name = "edgeport_4", .id_table = edgeport_4port_id_table, @@ -132,7 +136,9 @@ static struct usb_serial_driver edgeport_4port_device = { }; static struct usb_serial_driver edgeport_8port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Edgeport 8 port adapter", .short_name = "edgeport_8", .id_table = edgeport_8port_id_table, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 4328cc702ef7..74228a072643 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2983,7 +2983,9 @@ static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, static struct usb_serial_driver edgeport_1port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Edgeport TI 1 port adapter", .short_name = "edgeport_ti_1", .id_table = edgeport_1port_id_table, @@ -3011,7 +3013,9 @@ static struct usb_serial_driver edgeport_1port_device = { }; static struct usb_serial_driver edgeport_2port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Edgeport TI 2 port adapter", .short_name = "edgeport_ti_2", .id_table = edgeport_2port_id_table, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 9a79ad8d7a5f..9aedfb91b20c 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -548,7 +548,9 @@ static struct usb_driver ipaq_driver = { /* All of the device info needed for the Compaq iPAQ */ static struct usb_serial_driver ipaq_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "PocketPC PDA", .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 04524d34de3b..2ba69623ac05 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -444,7 +444,9 @@ static int ipw_disconnect(struct usb_serial_port *port) } static struct usb_serial_driver ipw_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "IPWireless converter", .short_name = "ipw", .id_table = usb_ipw_ids, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index ecfb2060ea0f..bf079059819e 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -134,7 +134,9 @@ static struct usb_driver ir_driver = { static struct usb_serial_driver ir_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "IR Dongle", .id_table = id_table, .num_interrupt_in = 1, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 97e7d9e53e39..124d46e76a2e 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -571,7 +571,9 @@ static struct usb_device_id keyspan_4port_ids[] = { /* Structs for the devices, pre and post renumeration. */ static struct usb_serial_driver keyspan_pre_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan - (without firmware)", .short_name = "keyspan_no_firm", .id_table = keyspan_pre_ids, @@ -583,7 +585,9 @@ static struct usb_serial_driver keyspan_pre_device = { }; static struct usb_serial_driver keyspan_1port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan 1 port adapter", .short_name = "keyspan_1", .id_table = keyspan_1port_ids, @@ -608,7 +612,9 @@ static struct usb_serial_driver keyspan_1port_device = { }; static struct usb_serial_driver keyspan_2port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan 2 port adapter", .short_name = "keyspan_2", .id_table = keyspan_2port_ids, @@ -633,7 +639,9 @@ static struct usb_serial_driver keyspan_2port_device = { }; static struct usb_serial_driver keyspan_4port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan 4 port adapter", .short_name = "keyspan_4", .id_table = keyspan_4port_ids, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 8fad0e963dd3..389b7833e3ae 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -784,7 +784,9 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) #ifdef KEYSPAN static struct usb_serial_driver keyspan_pda_fake_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan PDA - (prerenumeration)", .short_name = "keyspan_pda_pre", .id_table = id_table_fake, @@ -798,7 +800,9 @@ static struct usb_serial_driver keyspan_pda_fake_device = { #ifdef XIRCOM static struct usb_serial_driver xircom_pgs_fake_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Xircom / Entregra PGS - (prerenumeration)", .short_name = "xircom_no_firm", .id_table = id_table_fake_xircom, @@ -811,7 +815,9 @@ static struct usb_serial_driver xircom_pgs_fake_device = { #endif static struct usb_serial_driver keyspan_pda_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Keyspan PDA", .short_name = "keyspan_pda", .id_table = id_table_std, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index be082706b952..586108ce7897 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,7 +124,9 @@ static struct usb_driver kl5kusb105d_driver = { }; static struct usb_serial_driver kl5kusb105d_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "KL5KUSB105D / PalmConnect", .short_name = "kl5kusb105d", .id_table = id_table, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 94944340bb8d..a9578e05b22f 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -106,7 +106,9 @@ static struct usb_driver kobil_driver = { static struct usb_serial_driver kobil_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "KOBIL USB smart card terminal", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 9470964316a7..7dcf91c5f83d 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -133,7 +133,9 @@ static struct usb_driver mct_u232_driver = { }; static struct usb_serial_driver mct_u232_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "MCT U232", .short_name = "mct_u232", .id_table = id_table_combined, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 53c0588877c0..f6327cc1b2e7 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -89,7 +89,9 @@ static struct usb_driver omninet_driver = { static struct usb_serial_driver zyxel_omninet_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "ZyXEL - omni.net lcd plus usb", .short_name = "omninet", .id_table = id_table, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6ec9266e2e96..a2b5adf34868 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -106,7 +106,9 @@ static struct usb_driver option_driver = { * recognizes separately, thus num_port=1. */ static struct usb_serial_driver option_3port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Option 3G data card", .short_name = "option", .id_table = option_ids, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7134648e078d..beef3c4cee6e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -176,7 +176,9 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, /* All of the device info needed for the PL2303 SIO serial converter */ static struct usb_serial_driver pl2303_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "PL-2303", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 87871bb647df..42a86ab689f4 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -398,7 +398,9 @@ static int safe_startup (struct usb_serial *serial) } static struct usb_serial_driver safe_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Safe", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index f2efaf6f3d76..eab8a6de0925 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -256,7 +256,9 @@ static struct usb_driver ti_usb_driver = { }; static struct usb_serial_driver ti_1port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, .num_interrupt_in = 1, @@ -283,7 +285,9 @@ static struct usb_serial_driver ti_1port_device = { }; static struct usb_serial_driver ti_2port_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, .num_interrupt_in = 1, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index cf083da15eb4..08f600327db4 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -507,7 +507,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) /* lock this module before we call it * this may fail, which means we must bail out, * safe because we are called with BKL held */ - if (!try_module_get(serial->type->owner)) { + if (!try_module_get(serial->type->driver.owner)) { retval = -ENODEV; goto bailout_kref_put; } @@ -522,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) return 0; bailout_module_put: - module_put(serial->type->owner); + module_put(serial->type->driver.owner); bailout_kref_put: kref_put(&serial->kref, destroy_serial); port->open_count = 0; @@ -553,7 +553,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) port->tty = NULL; } - module_put(port->serial->type->owner); + module_put(port->serial->type->driver.owner); } kref_put(&port->serial->kref, destroy_serial); @@ -718,8 +718,8 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int continue; length += sprintf (page+length, "%d:", i); - if (serial->type->owner) - length += sprintf (page+length, " module:%s", module_name(serial->type->owner)); + if (serial->type->driver.owner) + length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner)); length += sprintf (page+length, " name:\"%s\"", serial->type->name); length += sprintf (page+length, " vendor:%04x product:%04x", le16_to_cpu(serial->dev->descriptor.idVendor), @@ -900,7 +900,7 @@ int usb_serial_probe(struct usb_interface *interface, if (type->probe) { const struct usb_device_id *id; - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -908,7 +908,7 @@ int usb_serial_probe(struct usb_interface *interface, id = usb_match_id(interface, type->id_table); retval = type->probe(serial, id); - module_put(type->owner); + module_put(type->driver.owner); if (retval) { dbg ("sub driver rejected device"); @@ -1007,13 +1007,13 @@ int usb_serial_probe(struct usb_interface *interface, if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } num_ports = type->calc_num_ports (serial); - module_put(type->owner); + module_put(type->driver.owner); } if (!num_ports) num_ports = type->num_ports; @@ -1158,12 +1158,12 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); goto probe_error; } retval = type->attach (serial); - module_put(type->owner); + module_put(type->driver.owner); if (retval < 0) goto probe_error; if (retval > 0) { diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index d6738b1b0429..4ca5e0c05611 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -189,7 +189,6 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) /** * usb_serial_driver - describes a usb serial driver - * @owner: pointer to the module that owns this driver. * @name: pointer to a string that describes this driver. This string used * in the syslog messages when a device is inserted or removed. * @short_name: a pointer to a string that describes this driver in @@ -226,9 +225,11 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * pointers are defined, then the USB serial core code will call them when * the corresponding tty port functions are called. If they are not * called, the generic serial function will be used instead. + * + * The driver.owner field should be set to the module owner of this driver. + * */ struct usb_serial_driver { - struct module *owner; char *name; char *short_name; const struct usb_device_id *id_table; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 825451b3788c..0ac0377e8683 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -312,7 +312,9 @@ static struct usb_driver visor_driver = { /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ static struct usb_serial_driver handspring_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Handspring Visor / Palm OS", .short_name = "visor", .id_table = id_table, @@ -340,7 +342,9 @@ static struct usb_serial_driver handspring_device = { /* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ static struct usb_serial_driver clie_5_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Sony Clie 5.0", .short_name = "clie_5", .id_table = clie_id_5_table, @@ -368,7 +372,9 @@ static struct usb_serial_driver clie_5_device = { /* device info for the Sony Clie OS version 3.5 */ static struct usb_serial_driver clie_3_5_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Sony Clie 3.5", .short_name = "clie_3.5", .id_table = clie_id_3_5_table, diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index dc06664bfa0e..fb95a34a1cf7 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -157,7 +157,9 @@ static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs); static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs); static struct usb_serial_driver whiteheat_fake_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Connect Tech - WhiteHEAT - (prerenumeration)", .short_name = "whiteheatnofirm", .id_table = id_table_prerenumeration, @@ -170,7 +172,9 @@ static struct usb_serial_driver whiteheat_fake_device = { }; static struct usb_serial_driver whiteheat_device = { - .owner = THIS_MODULE, + .driver = { + .owner = THIS_MODULE, + }, .name = "Connect Tech - WhiteHEAT", .short_name = "whiteheat", .id_table = id_table_std, From 502b95c1cc9e2c855a26f90fc999c5211b8ba957 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1184/1939] [PATCH] USB Serial: move old changelog comments out of source code Create a new file just for these things, as they just get in the way in the source files. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ChangeLog.old | 730 +++++++++++++++++++++++++++++++ drivers/usb/serial/io_edgeport.c | 219 ---------- drivers/usb/serial/pl2303.c | 23 +- drivers/usb/serial/usb-serial.c | 309 +------------ drivers/usb/serial/usb-serial.h | 44 +- drivers/usb/serial/visor.c | 131 +----- 6 files changed, 736 insertions(+), 720 deletions(-) create mode 100644 drivers/usb/serial/ChangeLog.old diff --git a/drivers/usb/serial/ChangeLog.old b/drivers/usb/serial/ChangeLog.old new file mode 100644 index 000000000000..c1b279939bbf --- /dev/null +++ b/drivers/usb/serial/ChangeLog.old @@ -0,0 +1,730 @@ +This is the contents of some of the drivers/usb/serial/ files that had old +changelog comments. They were quite old, and out of date, and we don't keep +them anymore, so I've put them here, away from the source files, in case +people still care to see them. + +- Greg Kroah-Hartman October 20, 2005 + +----------------------------------------------------------------------- +usb-serial.h Change Log comments: + + (03/26/2002) gkh + removed the port->tty check from port_paranoia_check() due to serial + consoles not having a tty device assigned to them. + + (12/03/2001) gkh + removed active from the port structure. + added documentation to the usb_serial_device_type structure + + (10/10/2001) gkh + added vendor and product to serial structure. Needed to determine device + owner when the device is disconnected. + + (05/30/2001) gkh + added sem to port structure and removed port_lock + + (10/05/2000) gkh + Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help + fix bug with urb->dev not being set properly, now that the usb core + needs it. + + (09/11/2000) gkh + Added usb_serial_debug_data function to help get rid of #DEBUG in the + drivers. + + (08/28/2000) gkh + Added port_lock to port structure. + + (08/08/2000) gkh + Added open_count to port structure. + + (07/23/2000) gkh + Added bulk_out_endpointAddress to port structure. + + (07/19/2000) gkh, pberger, and borchers + Modifications to allow usb-serial drivers to be modules. + +----------------------------------------------------------------------- +usb-serial.c Change Log comments: + + (12/10/2002) gkh + Split the ports off into their own struct device, and added a + usb-serial bus driver. + + (11/19/2002) gkh + removed a few #ifdefs for the generic code and cleaned up the failure + logic in initialization. + + (10/02/2002) gkh + moved the console code to console.c and out of this file. + + (06/05/2002) gkh + moved location of startup() call in serial_probe() until after all + of the port information and endpoints are initialized. This makes + things easier for some drivers. + + (04/10/2002) gkh + added serial_read_proc function which creates a + /proc/tty/driver/usb-serial file. + + (03/27/2002) gkh + Got USB serial console code working properly and merged into the main + version of the tree. Thanks to Randy Dunlap for the initial version + of this code, and for pushing me to finish it up. + The USB serial console works with any usb serial driver device. + + (03/21/2002) gkh + Moved all manipulation of port->open_count into the core. Now the + individual driver's open and close functions are called only when the + first open() and last close() is called. Making the drivers a bit + smaller and simpler. + Fixed a bug if a driver didn't have the owner field set. + + (02/26/2002) gkh + Moved all locking into the main serial_* functions, instead of having + the individual drivers have to grab the port semaphore. This should + reduce races. + Reworked the MOD_INC logic a bit to always increment and decrement, even + if the generic driver is being used. + + (10/10/2001) gkh + usb_serial_disconnect() now sets the serial->dev pointer is to NULL to + help prevent child drivers from accessing the device since it is now + gone. + + (09/13/2001) gkh + Moved generic driver initialize after we have registered with the USB + core. Thanks to Randy Dunlap for pointing this problem out. + + (07/03/2001) gkh + Fixed module paramater size. Thanks to John Brockmeyer for the pointer. + Fixed vendor and product getting defined through the MODULE_PARM macro + if the Generic driver wasn't compiled in. + Fixed problem with generic_shutdown() not being called for drivers that + don't have a shutdown() function. + + (06/06/2001) gkh + added evil hack that is needed for the prolific pl2303 device due to the + crazy way its endpoints are set up. + + (05/30/2001) gkh + switched from using spinlock to a semaphore, which fixes lots of problems. + + (04/08/2001) gb + Identify version on module load. + + 2001_02_05 gkh + Fixed buffer overflows bug with the generic serial driver. Thanks to + Todd Squires for fixing this. + + (01/10/2001) gkh + Fixed bug where the generic serial adaptor grabbed _any_ device that was + offered to it. + + (12/12/2000) gkh + Removed MOD_INC and MOD_DEC from poll and disconnect functions, and + moved them to the serial_open and serial_close functions. + Also fixed bug with there not being a MOD_DEC for the generic driver + (thanks to Gary Brubaker for finding this.) + + (11/29/2000) gkh + Small NULL pointer initialization cleanup which saves a bit of disk image + + (11/01/2000) Adam J. Richter + instead of using idVendor/idProduct pairs, usb serial drivers + now identify their hardware interest with usb_device_id tables, + which they usually have anyhow for use with MODULE_DEVICE_TABLE. + + (10/05/2000) gkh + Fixed bug with urb->dev not being set properly, now that the usb + core needs it. + + (09/11/2000) gkh + Removed DEBUG #ifdefs with call to usb_serial_debug_data + + (08/28/2000) gkh + Added port_lock to port structure. + Added locks for SMP safeness to generic driver + Fixed the ability to open a generic device's port more than once. + + (07/23/2000) gkh + Added bulk_out_endpointAddress to port structure. + + (07/19/2000) gkh, pberger, and borchers + Modifications to allow usb-serial drivers to be modules. + + (07/03/2000) gkh + Added more debugging to serial_ioctl call + + (06/25/2000) gkh + Changed generic_write_bulk_callback to not call wake_up_interruptible + directly, but to have port_softint do it at a safer time. + + (06/23/2000) gkh + Cleaned up debugging statements in a quest to find UHCI timeout bug. + + (05/22/2000) gkh + Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be + removed from the individual device source files. + + (05/03/2000) gkh + Added the Digi Acceleport driver from Al Borchers and Peter Berger. + + (05/02/2000) gkh + Changed devfs and tty register code to work properly now. This was based on + the ACM driver changes by Vojtech Pavlik. + + (04/27/2000) Ryan VanderBijl + Put calls to *_paranoia_checks into one function. + + (04/23/2000) gkh + Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. + Moved when the startup code printed out the devices that are supported. + + (04/19/2000) gkh + Added driver for ZyXEL omni.net lcd plus ISDN TA + Made startup info message specify which drivers were compiled in. + + (04/03/2000) gkh + Changed the probe process to remove the module unload races. + Changed where the tty layer gets initialized to have devfs work nicer. + Added initial devfs support. + + (03/26/2000) gkh + Split driver up into device specific pieces. + + (03/19/2000) gkh + Fixed oops that could happen when device was removed while a program + was talking to the device. + Removed the static urbs and now all urbs are created and destroyed + dynamically. + Reworked the internal interface. Now everything is based on the + usb_serial_port structure instead of the larger usb_serial structure. + This fixes the bug that a multiport device could not have more than + one port open at one time. + + (03/17/2000) gkh + Added config option for debugging messages. + Added patch for keyspan pda from Brian Warner. + + (03/06/2000) gkh + Added the keyspan pda code from Brian Warner + Moved a bunch of the port specific stuff into its own structure. This + is in anticipation of the true multiport devices (there's a bug if you + try to access more than one port of any multiport device right now) + + (02/21/2000) gkh + Made it so that any serial devices only have to specify which functions + they want to overload from the generic function calls (great, + inheritance in C, in a driver, just what I wanted...) + Added support for set_termios and ioctl function calls. No drivers take + advantage of this yet. + Removed the #ifdef MODULE, now there is no module specific code. + Cleaned up a few comments in usb-serial.h that were wrong (thanks again + to Miles Lott). + Small fix to get_free_serial. + + (02/14/2000) gkh + Removed the Belkin and Peracom functionality from the driver due to + the lack of support from the vendor, and me not wanting people to + accidenatly buy the device, expecting it to work with Linux. + Added read_bulk_callback and write_bulk_callback to the type structure + for the needs of the FTDI and WhiteHEAT driver. + Changed all reverences to FTDI to FTDI_SIO at the request of Bill + Ryder. + Changed the output urb size back to the max endpoint size to make + the ftdi_sio driver have it easier, and due to the fact that it didn't + really increase the speed any. + + (02/11/2000) gkh + Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a + patch from Miles Lott (milos@insync.net). + Fixed bug with not restoring the minor range that a device grabs, if + the startup function fails (thanks Miles for finding this). + + (02/05/2000) gkh + Added initial framework for the Keyspan PDA serial converter so that + Brian Warner has a place to put his code. + Made the ezusb specific functions generic enough that different + devices can use them (whiteheat and keyspan_pda both need them). + Split out a whole bunch of structure and other stuff to a separate + usb-serial.h file. + Made the Visor connection messages a little more understandable, now + that Miles Lott (milos@insync.net) has gotten the Generic channel to + work. Also made them always show up in the log file. + + (01/25/2000) gkh + Added initial framework for FTDI serial converter so that Bill Ryder + has a place to put his code. + Added the vendor specific info from Handspring. Now we can print out + informational debug messages as well as understand what is happening. + + (01/23/2000) gkh + Fixed problem of crash when trying to open a port that didn't have a + device assigned to it. Made the minor node finding a little smarter, + now it looks to find a continuous space for the new device. + + (01/21/2000) gkh + Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) + Fixed get_serial_by_minor which was all messed up for multi port + devices. Fixed multi port problem for generic devices. Now the number + of ports is determined by the number of bulk out endpoints for the + generic device. + + (01/19/2000) gkh + Removed lots of cruft that was around from the old (pre urb) driver + interface. + Made the serial_table dynamic. This should save lots of memory when + the number of minor nodes goes up to 256. + Added initial support for devices that have more than one port. + Added more debugging comments for the Visor, and added a needed + set_configuration call. + + (01/17/2000) gkh + Fixed the WhiteHEAT firmware (my processing tool had a bug) + and added new debug loader firmware for it. + Removed the put_char function as it isn't really needed. + Added visor startup commands as found by the Win98 dump. + + (01/13/2000) gkh + Fixed the vendor id for the generic driver to the one I meant it to be. + + (01/12/2000) gkh + Forget the version numbering...that's pretty useless... + Made the driver able to be compiled so that the user can select which + converter they want to use. This allows people who only want the Visor + support to not pay the memory size price of the WhiteHEAT. + Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) + grabbed the root hub. Not good. + + version 0.4.0 (01/10/2000) gkh + Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT + device. Added startup function to allow firmware to be downloaded to + a device if it needs to be. + Added firmware download logic to the WhiteHEAT device. + Started to add #defines to split up the different drivers for potential + configuration option. + + version 0.3.1 (12/30/99) gkh + Fixed problems with urb for bulk out. + Added initial support for multiple sets of endpoints. This enables + the Handspring Visor to be attached successfully. Only the first + bulk in / bulk out endpoint pair is being used right now. + + version 0.3.0 (12/27/99) gkh + Added initial support for the Handspring Visor based on a patch from + Miles Lott (milos@sneety.insync.net) + Cleaned up the code a bunch and converted over to using urbs only. + + version 0.2.3 (12/21/99) gkh + Added initial support for the Connect Tech WhiteHEAT converter. + Incremented the number of ports in expectation of getting the + WhiteHEAT to work properly (4 ports per connection). + Added notification on insertion and removal of what port the + device is/was connected to (and what kind of device it was). + + version 0.2.2 (12/16/99) gkh + Changed major number to the new allocated number. We're legal now! + + version 0.2.1 (12/14/99) gkh + Fixed bug that happens when device node is opened when there isn't a + device attached to it. Thanks to marek@webdesign.no for noticing this. + + version 0.2.0 (11/10/99) gkh + Split up internals to make it easier to add different types of serial + converters to the code. + Added a "generic" driver that gets it's vendor and product id + from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) + for the idea and sample code (from the usb scanner driver.) + Cleared up any licensing questions by releasing it under the GNU GPL. + + version 0.1.2 (10/25/99) gkh + Fixed bug in detecting device. + + version 0.1.1 (10/05/99) gkh + Changed the major number to not conflict with anything else. + + version 0.1 (09/28/99) gkh + Can recognize the two different devices and start up a read from + device when asked to. Writes also work. No control signals yet, this + all is vendor specific data (i.e. no spec), also no control for + different baud rates or other bit settings. + Currently we are using the same devid as the acm driver. This needs + to change. + +----------------------------------------------------------------------- +visor.c Change Log comments: + + (06/03/2003) Judd Montgomery + Added support for module parameter options for untested/unknown + devices. + + (03/09/2003) gkh + Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl + for the information. + + (03/05/2003) gkh + Think Treo support is now working. + + (04/03/2002) gkh + Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI + for the information. + + (03/27/2002) gkh + Removed assumptions that port->tty was always valid (is not true + for usb serial console devices.) + + (03/23/2002) gkh + Added support for the Palm i705 device, thanks to Thomas Riemer + for the information. + + (03/21/2002) gkh + Added support for the Palm m130 device, thanks to Udo Eisenbarth + for the information. + + (02/27/2002) gkh + Reworked the urb handling logic. We have no more pool, but dynamically + allocate the urb and the transfer buffer on the fly. In testing this + does not incure any measurable overhead. This also relies on the fact + that we have proper reference counting logic for urbs. + + (02/21/2002) SilaS + Added initial support for the Palm m515 devices. + + (02/14/2002) gkh + Added support for the Clie S-360 device. + + (12/18/2001) gkh + Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand + for the patch. + + (11/11/2001) gkh + Added support for the m125 devices, and added check to prevent oopses + for Clié devices that lie about the number of ports they have. + + (08/30/2001) gkh + Added support for the Clie devices, both the 3.5 and 4.0 os versions. + Many thanks to Daniel Burke, and Bryan Payne for helping with this. + + (08/23/2001) gkh + fixed a few potential bugs pointed out by Oliver Neukum. + + (05/30/2001) gkh + switched from using spinlock to a semaphore, which fixes lots of problems. + + (05/28/2000) gkh + Added initial support for the Palm m500 and Palm m505 devices. + + (04/08/2001) gb + Identify version on module load. + + (01/21/2000) gkh + Added write_room and chars_in_buffer, as they were previously using the + generic driver versions which is all wrong now that we are using an urb + pool. Thanks to Wolfgang Grandegger for pointing this out to me. + Removed count assignment in the write function, which was not needed anymore + either. Thanks to Al Borchers for pointing this out. + + (12/12/2000) gkh + Moved MOD_DEC to end of visor_close to be nicer, as the final write + message can sleep. + + (11/12/2000) gkh + Fixed bug with data being dropped on the floor by forcing tty->low_latency + to be on. Hopefully this fixes the OHCI issue! + + (11/01/2000) Adam J. Richter + usb_device_id table support + + (10/05/2000) gkh + Fixed bug with urb->dev not being set properly, now that the usb + core needs it. + + (09/11/2000) gkh + Got rid of always calling kmalloc for every urb we wrote out to the + device. + Added visor_read_callback so we can keep track of bytes in and out for + those people who like to know the speed of their device. + Removed DEBUG #ifdefs with call to usb_serial_debug_data + + (09/06/2000) gkh + Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ + the host controller drivers set urb->dev = NULL when the urb is finished. + + (08/28/2000) gkh + Added locks for SMP safeness. + + (08/08/2000) gkh + Fixed endian problem in visor_startup. + Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + than once. + + (07/23/2000) gkh + Added pool of write urbs to speed up transfers to the visor. + + (07/19/2000) gkh + Added module_init and module_exit functions to handle the fact that this + driver is a loadable module now. + + (07/03/2000) gkh + Added visor_set_ioctl and visor_set_termios functions (they don't do much + of anything, but are good for debugging.) + + (06/25/2000) gkh + Fixed bug in visor_unthrottle that should help with the disconnect in PPP + bug that people have been reporting. + + (06/23/2000) gkh + Cleaned up debugging statements in a quest to find UHCI timeout bug. + + (04/27/2000) Ryan VanderBijl + Fixed memory leak in visor_close + + (03/26/2000) gkh + Split driver up into device specific pieces. + +----------------------------------------------------------------------- +pl2303.c Change Log comments: + + 2002_Mar_26 gkh + allowed driver to work properly if there is no tty assigned to a port + (this happens for serial console devices.) + + 2001_Oct_06 gkh + Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. + + 2001_Sep_19 gkh + Added break support. + + 2001_Aug_30 gkh + fixed oops in write_bulk_callback. + + 2001_Aug_28 gkh + reworked buffer logic to be like other usb-serial drivers. Hopefully + removing some reported problems. + + 2001_Jun_06 gkh + finished porting to 2.4 format. + + +----------------------------------------------------------------------- +io_edgeport.c Change Log comments: + + 2003_04_03 al borchers + - fixed a bug (that shows up with dosemu) where the tty struct is + used in a callback after it has been freed + + 2.3 2002_03_08 greg kroah-hartman + - fixed bug when multiple devices were attached at the same time. + + 2.2 2001_11_14 greg kroah-hartman + - fixed bug in edge_close that kept the port from being used more + than once. + - fixed memory leak on device removal. + - fixed potential double free of memory when command urb submitting + failed. + - other small cleanups when the device is removed + + 2.1 2001_07_09 greg kroah-hartman + - added support for TIOCMBIS and TIOCMBIC. + + (04/08/2001) gb + - Identify version on module load. + + 2.0 2001_03_05 greg kroah-hartman + - reworked entire driver to fit properly in with the other usb-serial + drivers. Occasional oopses still happen, but it's a good start. + + 1.2.3 (02/23/2001) greg kroah-hartman + - changed device table to work properly for 2.4.x final format. + - fixed problem with dropping data at high data rates. + + 1.2.2 (11/27/2000) greg kroah-hartman + - cleaned up more NTisms. + - Added device table for 2.4.0-test11 + + 1.2.1 (11/08/2000) greg kroah-hartman + - Started to clean up NTisms. + - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 + + 1.2 (10/17/2000) David Iacovelli + Remove all EPIC code and GPL source + Fix RELEVANT_IFLAG macro to include flow control + changes port configuration changes. + Fix redefinition of SERIAL_MAGIC + Change all timeout values to 5 seconds + Tried to fix the UHCI multiple urb submission, but failed miserably. + it seems to work fine with OHCI. + ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must + find a way to work arount this UHCI bug ) + + 1.1 (10/11/2000) David Iacovelli + Fix XON/XOFF flow control to support both IXON and IXOFF + + 0.9.27 (06/30/2000) David Iacovelli + Added transmit queue and now allocate urb for command writes. + + 0.9.26 (06/29/2000) David Iacovelli + Add support for 80251 based edgeport + + 0.9.25 (06/27/2000) David Iacovelli + Do not close the port if it has multiple opens. + + 0.9.24 (05/26/2000) David Iacovelli + Add IOCTLs to support RXTX and JAVA POS + and first cut at running BlackBox Demo + + 0.9.23 (05/24/2000) David Iacovelli + Add IOCTLs to support RXTX and JAVA POS + + 0.9.22 (05/23/2000) David Iacovelli + fixed bug in enumeration. If epconfig turns on mapping by + path after a device is already plugged in, we now update + the mapping correctly + + 0.9.21 (05/16/2000) David Iacovelli + Added BlockUntilChaseResp() to also wait for txcredits + Updated the way we allocate and handle write URBs + Add debug code to dump buffers + + 0.9.20 (05/01/2000) David Iacovelli + change driver to use usb/tts/ + + 0.9.19 (05/01/2000) David Iacovelli + Update code to compile if DEBUG is off + + 0.9.18 (04/28/2000) David Iacovelli + cleanup and test tty_register with devfs + + 0.9.17 (04/27/2000) greg kroah-hartman + changed tty_register around to be like the way it + was before, but now it works properly with devfs. + + 0.9.16 (04/26/2000) david iacovelli + Fixed bug in GetProductInfo() + + 0.9.15 (04/25/2000) david iacovelli + Updated enumeration + + 0.9.14 (04/24/2000) david iacovelli + Removed all config/status IOCTLS and + converted to using /proc/edgeport + still playing with devfs + + 0.9.13 (04/24/2000) david iacovelli + Removed configuration based on ttyUSB0 + Added support for configuration using /prod/edgeport + first attempt at using devfs (not working yet!) + Added IOCTL to GetProductInfo() + Added support for custom baud rates + Add support for random port numbers + + 0.9.12 (04/18/2000) david iacovelli + added additional configuration IOCTLs + use ttyUSB0 for configuration + + 0.9.11 (04/17/2000) greg kroah-hartman + fixed module initialization race conditions. + made all urbs dynamically allocated. + made driver devfs compatible. now it only registers the tty device + when the device is actually plugged in. + + 0.9.10 (04/13/2000) greg kroah-hartman + added proc interface framework. + + 0.9.9 (04/13/2000) david iacovelli + added enumeration code and ioctls to configure the device + + 0.9.8 (04/12/2000) david iacovelli + Change interrupt read start when device is plugged in + and stop when device is removed + process interrupt reads when all ports are closed + (keep value of rxBytesAvail consistent with the edgeport) + set the USB_BULK_QUEUE flag so that we can shove a bunch + of urbs at once down the pipe + + 0.9.7 (04/10/2000) david iacovelli + start to add enumeration code. + generate serial number for epic devices + add support for kdb + + 0.9.6 (03/30/2000) david iacovelli + add IOCTL to get string, manufacture, and boot descriptors + + 0.9.5 (03/14/2000) greg kroah-hartman + more error checking added to SerialOpen to try to fix UHCI open problem + + 0.9.4 (03/09/2000) greg kroah-hartman + added more error checking to handle oops when data is hanging + around and tty is abruptly closed. + + 0.9.3 (03/09/2000) david iacovelli + Add epic support for xon/xoff chars + play with performance + + 0.9.2 (03/08/2000) greg kroah-hartman + changed most "info" calls to "dbg" + implemented flow control properly in the termios call + + 0.9.1 (03/08/2000) david iacovelli + added EPIC support + enabled bootloader update + + 0.9 (03/08/2000) greg kroah-hartman + Release to IO networks. + Integrated changes that David made + made getting urbs for writing SMP safe + + 0.8 (03/07/2000) greg kroah-hartman + Release to IO networks. + Fixed problems that were seen in code by David. + Now both Edgeport/4 and Edgeport/2 works properly. + Changed most of the functions to use port instead of serial. + + 0.7 (02/27/2000) greg kroah-hartman + Milestone 3 release. + Release to IO Networks + ioctl for waiting on line change implemented. + ioctl for getting statistics implemented. + multiport support working. + lsr and msr registers are now handled properly. + change break now hooked up and working. + support for all known Edgeport devices. + + 0.6 (02/22/2000) greg kroah-hartman + Release to IO networks. + CHASE is implemented correctly when port is closed. + SerialOpen now blocks correctly until port is fully opened. + + 0.5 (02/20/2000) greg kroah-hartman + Release to IO networks. + Known problems: + modem status register changes are not sent on to the user + CHASE is not implemented when the port is closed. + + 0.4 (02/16/2000) greg kroah-hartman + Second cut at the CeBit demo. + Doesn't leak memory on every write to the port + Still small leaks on startup. + Added support for Edgeport/2 and Edgeport/8 + + 0.3 (02/15/2000) greg kroah-hartman + CeBit demo release. + Force the line settings to 4800, 8, 1, e for the demo. + Warning! This version leaks memory like crazy! + + 0.2 (01/30/2000) greg kroah-hartman + Milestone 1 release. + Device is found by USB subsystem, enumerated, fimware is downloaded + and the descriptors are printed to the debug log, config is set, and + green light starts to blink. Open port works, and data can be sent + and received at the default settings of the UART. Loopback connector + and debug log confirms this. + + 0.1 (01/23/2000) greg kroah-hartman + Initial release to help IO Networks try to set up their test system. + Edgeport4 is recognized, firmware is downloaded, config is set so + device blinks green light every 3 sec. Port is bound, but opening, + closing, and sending data do not work properly. + + diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 04bfe279d763..dc4c498bd1ed 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -27,225 +27,6 @@ * Networks technical support, or Peter Berger , * or Al Borchers . * - * Version history: - * - * 2003_04_03 al borchers - * - fixed a bug (that shows up with dosemu) where the tty struct is - * used in a callback after it has been freed - * - * 2.3 2002_03_08 greg kroah-hartman - * - fixed bug when multiple devices were attached at the same time. - * - * 2.2 2001_11_14 greg kroah-hartman - * - fixed bug in edge_close that kept the port from being used more - * than once. - * - fixed memory leak on device removal. - * - fixed potential double free of memory when command urb submitting - * failed. - * - other small cleanups when the device is removed - * - * 2.1 2001_07_09 greg kroah-hartman - * - added support for TIOCMBIS and TIOCMBIC. - * - * (04/08/2001) gb - * - Identify version on module load. - * - * 2.0 2001_03_05 greg kroah-hartman - * - reworked entire driver to fit properly in with the other usb-serial - * drivers. Occasional oopses still happen, but it's a good start. - * - * 1.2.3 (02/23/2001) greg kroah-hartman - * - changed device table to work properly for 2.4.x final format. - * - fixed problem with dropping data at high data rates. - * - * 1.2.2 (11/27/2000) greg kroah-hartman - * - cleaned up more NTisms. - * - Added device table for 2.4.0-test11 - * - * 1.2.1 (11/08/2000) greg kroah-hartman - * - Started to clean up NTisms. - * - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 - * - * 1.2 (10/17/2000) David Iacovelli - * Remove all EPIC code and GPL source - * Fix RELEVANT_IFLAG macro to include flow control - * changes port configuration changes. - * Fix redefinition of SERIAL_MAGIC - * Change all timeout values to 5 seconds - * Tried to fix the UHCI multiple urb submission, but failed miserably. - * it seems to work fine with OHCI. - * ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must - * find a way to work arount this UHCI bug ) - * - * 1.1 (10/11/2000) David Iacovelli - * Fix XON/XOFF flow control to support both IXON and IXOFF - * - * 0.9.27 (06/30/2000) David Iacovelli - * Added transmit queue and now allocate urb for command writes. - * - * 0.9.26 (06/29/2000) David Iacovelli - * Add support for 80251 based edgeport - * - * 0.9.25 (06/27/2000) David Iacovelli - * Do not close the port if it has multiple opens. - * - * 0.9.24 (05/26/2000) David Iacovelli - * Add IOCTLs to support RXTX and JAVA POS - * and first cut at running BlackBox Demo - * - * 0.9.23 (05/24/2000) David Iacovelli - * Add IOCTLs to support RXTX and JAVA POS - * - * 0.9.22 (05/23/2000) David Iacovelli - * fixed bug in enumeration. If epconfig turns on mapping by - * path after a device is already plugged in, we now update - * the mapping correctly - * - * 0.9.21 (05/16/2000) David Iacovelli - * Added BlockUntilChaseResp() to also wait for txcredits - * Updated the way we allocate and handle write URBs - * Add debug code to dump buffers - * - * 0.9.20 (05/01/2000) David Iacovelli - * change driver to use usb/tts/ - * - * 0.9.19 (05/01/2000) David Iacovelli - * Update code to compile if DEBUG is off - * - * 0.9.18 (04/28/2000) David Iacovelli - * cleanup and test tty_register with devfs - * - * 0.9.17 (04/27/2000) greg kroah-hartman - * changed tty_register around to be like the way it - * was before, but now it works properly with devfs. - * - * 0.9.16 (04/26/2000) david iacovelli - * Fixed bug in GetProductInfo() - * - * 0.9.15 (04/25/2000) david iacovelli - * Updated enumeration - * - * 0.9.14 (04/24/2000) david iacovelli - * Removed all config/status IOCTLS and - * converted to using /proc/edgeport - * still playing with devfs - * - * 0.9.13 (04/24/2000) david iacovelli - * Removed configuration based on ttyUSB0 - * Added support for configuration using /prod/edgeport - * first attempt at using devfs (not working yet!) - * Added IOCTL to GetProductInfo() - * Added support for custom baud rates - * Add support for random port numbers - * - * 0.9.12 (04/18/2000) david iacovelli - * added additional configuration IOCTLs - * use ttyUSB0 for configuration - * - * 0.9.11 (04/17/2000) greg kroah-hartman - * fixed module initialization race conditions. - * made all urbs dynamically allocated. - * made driver devfs compatible. now it only registers the tty device - * when the device is actually plugged in. - * - * 0.9.10 (04/13/2000) greg kroah-hartman - * added proc interface framework. - * - * 0.9.9 (04/13/2000) david iacovelli - * added enumeration code and ioctls to configure the device - * - * 0.9.8 (04/12/2000) david iacovelli - * Change interrupt read start when device is plugged in - * and stop when device is removed - * process interrupt reads when all ports are closed - * (keep value of rxBytesAvail consistent with the edgeport) - * set the USB_BULK_QUEUE flag so that we can shove a bunch - * of urbs at once down the pipe - * - * 0.9.7 (04/10/2000) david iacovelli - * start to add enumeration code. - * generate serial number for epic devices - * add support for kdb - * - * 0.9.6 (03/30/2000) david iacovelli - * add IOCTL to get string, manufacture, and boot descriptors - * - * 0.9.5 (03/14/2000) greg kroah-hartman - * more error checking added to SerialOpen to try to fix UHCI open problem - * - * 0.9.4 (03/09/2000) greg kroah-hartman - * added more error checking to handle oops when data is hanging - * around and tty is abruptly closed. - * - * 0.9.3 (03/09/2000) david iacovelli - * Add epic support for xon/xoff chars - * play with performance - * - * 0.9.2 (03/08/2000) greg kroah-hartman - * changed most "info" calls to "dbg" - * implemented flow control properly in the termios call - * - * 0.9.1 (03/08/2000) david iacovelli - * added EPIC support - * enabled bootloader update - * - * 0.9 (03/08/2000) greg kroah-hartman - * Release to IO networks. - * Integrated changes that David made - * made getting urbs for writing SMP safe - * - * 0.8 (03/07/2000) greg kroah-hartman - * Release to IO networks. - * Fixed problems that were seen in code by David. - * Now both Edgeport/4 and Edgeport/2 works properly. - * Changed most of the functions to use port instead of serial. - * - * 0.7 (02/27/2000) greg kroah-hartman - * Milestone 3 release. - * Release to IO Networks - * ioctl for waiting on line change implemented. - * ioctl for getting statistics implemented. - * multiport support working. - * lsr and msr registers are now handled properly. - * change break now hooked up and working. - * support for all known Edgeport devices. - * - * 0.6 (02/22/2000) greg kroah-hartman - * Release to IO networks. - * CHASE is implemented correctly when port is closed. - * SerialOpen now blocks correctly until port is fully opened. - * - * 0.5 (02/20/2000) greg kroah-hartman - * Release to IO networks. - * Known problems: - * modem status register changes are not sent on to the user - * CHASE is not implemented when the port is closed. - * - * 0.4 (02/16/2000) greg kroah-hartman - * Second cut at the CeBit demo. - * Doesn't leak memory on every write to the port - * Still small leaks on startup. - * Added support for Edgeport/2 and Edgeport/8 - * - * 0.3 (02/15/2000) greg kroah-hartman - * CeBit demo release. - * Force the line settings to 4800, 8, 1, e for the demo. - * Warning! This version leaks memory like crazy! - * - * 0.2 (01/30/2000) greg kroah-hartman - * Milestone 1 release. - * Device is found by USB subsystem, enumerated, fimware is downloaded - * and the descriptors are printed to the debug log, config is set, and - * green light starts to blink. Open port works, and data can be sent - * and received at the default settings of the UART. Loopback connector - * and debug log confirms this. - * - * 0.1 (01/23/2000) greg kroah-hartman - * Initial release to help IO Networks try to set up their test system. - * Edgeport4 is recognized, firmware is downloaded, config is set so - * device blinks green light every 3 sec. Port is bound, but opening, - * closing, and sending data do not work properly. - * */ #include diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index beef3c4cee6e..29719ceab19a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -8,31 +8,10 @@ * * 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. + * the Free Software Foundation; either version 2 of the License. * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * 2002_Mar_26 gkh - * allowed driver to work properly if there is no tty assigned to a port - * (this happens for serial console devices.) - * - * 2001_Oct_06 gkh - * Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. - * - * 2001_Sep_19 gkh - * Added break support. - * - * 2001_Aug_30 gkh - * fixed oops in write_bulk_callback. - * - * 2001_Aug_28 gkh - * reworked buffer logic to be like other usb-serial drivers. Hopefully - * removing some reported problems. - * - * 2001_Jun_06 gkh - * finished porting to 2.4 format. - * */ #include diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 08f600327db4..fde09fba8790 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -9,316 +9,11 @@ * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * - * This driver was originally based on the ACM driver by Armin Fuerst (which was + * This driver was originally based on the ACM driver by Armin Fuerst (which was * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * (12/10/2002) gkh - * Split the ports off into their own struct device, and added a - * usb-serial bus driver. - * - * (11/19/2002) gkh - * removed a few #ifdefs for the generic code and cleaned up the failure - * logic in initialization. - * - * (10/02/2002) gkh - * moved the console code to console.c and out of this file. - * - * (06/05/2002) gkh - * moved location of startup() call in serial_probe() until after all - * of the port information and endpoints are initialized. This makes - * things easier for some drivers. - * - * (04/10/2002) gkh - * added serial_read_proc function which creates a - * /proc/tty/driver/usb-serial file. - * - * (03/27/2002) gkh - * Got USB serial console code working properly and merged into the main - * version of the tree. Thanks to Randy Dunlap for the initial version - * of this code, and for pushing me to finish it up. - * The USB serial console works with any usb serial driver device. - * - * (03/21/2002) gkh - * Moved all manipulation of port->open_count into the core. Now the - * individual driver's open and close functions are called only when the - * first open() and last close() is called. Making the drivers a bit - * smaller and simpler. - * Fixed a bug if a driver didn't have the owner field set. - * - * (02/26/2002) gkh - * Moved all locking into the main serial_* functions, instead of having - * the individual drivers have to grab the port semaphore. This should - * reduce races. - * Reworked the MOD_INC logic a bit to always increment and decrement, even - * if the generic driver is being used. - * - * (10/10/2001) gkh - * usb_serial_disconnect() now sets the serial->dev pointer is to NULL to - * help prevent child drivers from accessing the device since it is now - * gone. - * - * (09/13/2001) gkh - * Moved generic driver initialize after we have registered with the USB - * core. Thanks to Randy Dunlap for pointing this problem out. - * - * (07/03/2001) gkh - * Fixed module paramater size. Thanks to John Brockmeyer for the pointer. - * Fixed vendor and product getting defined through the MODULE_PARM macro - * if the Generic driver wasn't compiled in. - * Fixed problem with generic_shutdown() not being called for drivers that - * don't have a shutdown() function. - * - * (06/06/2001) gkh - * added evil hack that is needed for the prolific pl2303 device due to the - * crazy way its endpoints are set up. - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * 2001_02_05 gkh - * Fixed buffer overflows bug with the generic serial driver. Thanks to - * Todd Squires for fixing this. - * - * (01/10/2001) gkh - * Fixed bug where the generic serial adaptor grabbed _any_ device that was - * offered to it. - * - * (12/12/2000) gkh - * Removed MOD_INC and MOD_DEC from poll and disconnect functions, and - * moved them to the serial_open and serial_close functions. - * Also fixed bug with there not being a MOD_DEC for the generic driver - * (thanks to Gary Brubaker for finding this.) - * - * (11/29/2000) gkh - * Small NULL pointer initialization cleanup which saves a bit of disk image - * - * (11/01/2000) Adam J. Richter - * instead of using idVendor/idProduct pairs, usb serial drivers - * now identify their hardware interest with usb_device_id tables, - * which they usually have anyhow for use with MODULE_DEVICE_TABLE. - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (08/28/2000) gkh - * Added port_lock to port structure. - * Added locks for SMP safeness to generic driver - * Fixed the ability to open a generic device's port more than once. - * - * (07/23/2000) gkh - * Added bulk_out_endpointAddress to port structure. - * - * (07/19/2000) gkh, pberger, and borchers - * Modifications to allow usb-serial drivers to be modules. - * - * (07/03/2000) gkh - * Added more debugging to serial_ioctl call - * - * (06/25/2000) gkh - * Changed generic_write_bulk_callback to not call wake_up_interruptible - * directly, but to have port_softint do it at a safer time. - * - * (06/23/2000) gkh - * Cleaned up debugging statements in a quest to find UHCI timeout bug. - * - * (05/22/2000) gkh - * Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be - * removed from the individual device source files. - * - * (05/03/2000) gkh - * Added the Digi Acceleport driver from Al Borchers and Peter Berger. - * - * (05/02/2000) gkh - * Changed devfs and tty register code to work properly now. This was based on - * the ACM driver changes by Vojtech Pavlik. - * - * (04/27/2000) Ryan VanderBijl - * Put calls to *_paranoia_checks into one function. - * - * (04/23/2000) gkh - * Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. - * Moved when the startup code printed out the devices that are supported. - * - * (04/19/2000) gkh - * Added driver for ZyXEL omni.net lcd plus ISDN TA - * Made startup info message specify which drivers were compiled in. - * - * (04/03/2000) gkh - * Changed the probe process to remove the module unload races. - * Changed where the tty layer gets initialized to have devfs work nicer. - * Added initial devfs support. - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * - * (03/19/2000) gkh - * Fixed oops that could happen when device was removed while a program - * was talking to the device. - * Removed the static urbs and now all urbs are created and destroyed - * dynamically. - * Reworked the internal interface. Now everything is based on the - * usb_serial_port structure instead of the larger usb_serial structure. - * This fixes the bug that a multiport device could not have more than - * one port open at one time. - * - * (03/17/2000) gkh - * Added config option for debugging messages. - * Added patch for keyspan pda from Brian Warner. - * - * (03/06/2000) gkh - * Added the keyspan pda code from Brian Warner - * Moved a bunch of the port specific stuff into its own structure. This - * is in anticipation of the true multiport devices (there's a bug if you - * try to access more than one port of any multiport device right now) - * - * (02/21/2000) gkh - * Made it so that any serial devices only have to specify which functions - * they want to overload from the generic function calls (great, - * inheritance in C, in a driver, just what I wanted...) - * Added support for set_termios and ioctl function calls. No drivers take - * advantage of this yet. - * Removed the #ifdef MODULE, now there is no module specific code. - * Cleaned up a few comments in usb-serial.h that were wrong (thanks again - * to Miles Lott). - * Small fix to get_free_serial. - * - * (02/14/2000) gkh - * Removed the Belkin and Peracom functionality from the driver due to - * the lack of support from the vendor, and me not wanting people to - * accidenatly buy the device, expecting it to work with Linux. - * Added read_bulk_callback and write_bulk_callback to the type structure - * for the needs of the FTDI and WhiteHEAT driver. - * Changed all reverences to FTDI to FTDI_SIO at the request of Bill - * Ryder. - * Changed the output urb size back to the max endpoint size to make - * the ftdi_sio driver have it easier, and due to the fact that it didn't - * really increase the speed any. - * - * (02/11/2000) gkh - * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a - * patch from Miles Lott (milos@insync.net). - * Fixed bug with not restoring the minor range that a device grabs, if - * the startup function fails (thanks Miles for finding this). - * - * (02/05/2000) gkh - * Added initial framework for the Keyspan PDA serial converter so that - * Brian Warner has a place to put his code. - * Made the ezusb specific functions generic enough that different - * devices can use them (whiteheat and keyspan_pda both need them). - * Split out a whole bunch of structure and other stuff to a separate - * usb-serial.h file. - * Made the Visor connection messages a little more understandable, now - * that Miles Lott (milos@insync.net) has gotten the Generic channel to - * work. Also made them always show up in the log file. - * - * (01/25/2000) gkh - * Added initial framework for FTDI serial converter so that Bill Ryder - * has a place to put his code. - * Added the vendor specific info from Handspring. Now we can print out - * informational debug messages as well as understand what is happening. - * - * (01/23/2000) gkh - * Fixed problem of crash when trying to open a port that didn't have a - * device assigned to it. Made the minor node finding a little smarter, - * now it looks to find a continuous space for the new device. - * - * (01/21/2000) gkh - * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) - * Fixed get_serial_by_minor which was all messed up for multi port - * devices. Fixed multi port problem for generic devices. Now the number - * of ports is determined by the number of bulk out endpoints for the - * generic device. - * - * (01/19/2000) gkh - * Removed lots of cruft that was around from the old (pre urb) driver - * interface. - * Made the serial_table dynamic. This should save lots of memory when - * the number of minor nodes goes up to 256. - * Added initial support for devices that have more than one port. - * Added more debugging comments for the Visor, and added a needed - * set_configuration call. - * - * (01/17/2000) gkh - * Fixed the WhiteHEAT firmware (my processing tool had a bug) - * and added new debug loader firmware for it. - * Removed the put_char function as it isn't really needed. - * Added visor startup commands as found by the Win98 dump. - * - * (01/13/2000) gkh - * Fixed the vendor id for the generic driver to the one I meant it to be. - * - * (01/12/2000) gkh - * Forget the version numbering...that's pretty useless... - * Made the driver able to be compiled so that the user can select which - * converter they want to use. This allows people who only want the Visor - * support to not pay the memory size price of the WhiteHEAT. - * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) - * grabbed the root hub. Not good. - * - * version 0.4.0 (01/10/2000) gkh - * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT - * device. Added startup function to allow firmware to be downloaded to - * a device if it needs to be. - * Added firmware download logic to the WhiteHEAT device. - * Started to add #defines to split up the different drivers for potential - * configuration option. - * - * version 0.3.1 (12/30/99) gkh - * Fixed problems with urb for bulk out. - * Added initial support for multiple sets of endpoints. This enables - * the Handspring Visor to be attached successfully. Only the first - * bulk in / bulk out endpoint pair is being used right now. - * - * version 0.3.0 (12/27/99) gkh - * Added initial support for the Handspring Visor based on a patch from - * Miles Lott (milos@sneety.insync.net) - * Cleaned up the code a bunch and converted over to using urbs only. - * - * version 0.2.3 (12/21/99) gkh - * Added initial support for the Connect Tech WhiteHEAT converter. - * Incremented the number of ports in expectation of getting the - * WhiteHEAT to work properly (4 ports per connection). - * Added notification on insertion and removal of what port the - * device is/was connected to (and what kind of device it was). - * - * version 0.2.2 (12/16/99) gkh - * Changed major number to the new allocated number. We're legal now! - * - * version 0.2.1 (12/14/99) gkh - * Fixed bug that happens when device node is opened when there isn't a - * device attached to it. Thanks to marek@webdesign.no for noticing this. - * - * version 0.2.0 (11/10/99) gkh - * Split up internals to make it easier to add different types of serial - * converters to the code. - * Added a "generic" driver that gets it's vendor and product id - * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) - * for the idea and sample code (from the usb scanner driver.) - * Cleared up any licensing questions by releasing it under the GNU GPL. - * - * version 0.1.2 (10/25/99) gkh - * Fixed bug in detecting device. - * - * version 0.1.1 (10/05/99) gkh - * Changed the major number to not conflict with anything else. - * - * version 0.1 (09/28/99) gkh - * Can recognize the two different devices and start up a read from - * device when asked to. Writes also work. No control signals yet, this - * all is vendor specific data (i.e. no spec), also no control for - * different baud rates or other bit settings. - * Currently we are using the same devid as the acm driver. This needs - * to change. - * */ #include diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 4ca5e0c05611..1cedc1999508 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -1,53 +1,13 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2004 + * Copyright (C) 1999 - 2005 * Greg Kroah-Hartman (greg@kroah.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. + * the Free Software Foundation; either version 2 of the License. * - * See Documentation/usb/usb-serial.txt for more information on using this driver - * - * (03/26/2002) gkh - * removed the port->tty check from port_paranoia_check() due to serial - * consoles not having a tty device assigned to them. - * - * (12/03/2001) gkh - * removed active from the port structure. - * added documentation to the usb_serial_device_type structure - * - * (10/10/2001) gkh - * added vendor and product to serial structure. Needed to determine device - * owner when the device is disconnected. - * - * (05/30/2001) gkh - * added sem to port structure and removed port_lock - * - * (10/05/2000) gkh - * Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help - * fix bug with urb->dev not being set properly, now that the usb core - * needs it. - * - * (09/11/2000) gkh - * Added usb_serial_debug_data function to help get rid of #DEBUG in the - * drivers. - * - * (08/28/2000) gkh - * Added port_lock to port structure. - * - * (08/08/2000) gkh - * Added open_count to port structure. - * - * (07/23/2000) gkh - * Added bulk_out_endpointAddress to port structure. - * - * (07/19/2000) gkh, pberger, and borchers - * Modifications to allow usb-serial drivers to be modules. - * - * */ diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 0ac0377e8683..39ad0cab8635 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -7,139 +7,10 @@ * * 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. + * the Free Software Foundation; either version 2 of the License. * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * (06/03/2003) Judd Montgomery - * Added support for module parameter options for untested/unknown - * devices. - * - * (03/09/2003) gkh - * Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl - * for the information. - * - * (03/05/2003) gkh - * Think Treo support is now working. - * - * (04/03/2002) gkh - * Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI - * for the information. - * - * (03/27/2002) gkh - * Removed assumptions that port->tty was always valid (is not true - * for usb serial console devices.) - * - * (03/23/2002) gkh - * Added support for the Palm i705 device, thanks to Thomas Riemer - * for the information. - * - * (03/21/2002) gkh - * Added support for the Palm m130 device, thanks to Udo Eisenbarth - * for the information. - * - * (02/27/2002) gkh - * Reworked the urb handling logic. We have no more pool, but dynamically - * allocate the urb and the transfer buffer on the fly. In testing this - * does not incure any measurable overhead. This also relies on the fact - * that we have proper reference counting logic for urbs. - * - * (02/21/2002) SilaS - * Added initial support for the Palm m515 devices. - * - * (02/14/2002) gkh - * Added support for the Clie S-360 device. - * - * (12/18/2001) gkh - * Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand - * for the patch. - * - * (11/11/2001) gkh - * Added support for the m125 devices, and added check to prevent oopses - * for Clié devices that lie about the number of ports they have. - * - * (08/30/2001) gkh - * Added support for the Clie devices, both the 3.5 and 4.0 os versions. - * Many thanks to Daniel Burke, and Bryan Payne for helping with this. - * - * (08/23/2001) gkh - * fixed a few potential bugs pointed out by Oliver Neukum. - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of problems. - * - * (05/28/2000) gkh - * Added initial support for the Palm m500 and Palm m505 devices. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (01/21/2000) gkh - * Added write_room and chars_in_buffer, as they were previously using the - * generic driver versions which is all wrong now that we are using an urb - * pool. Thanks to Wolfgang Grandegger for pointing this out to me. - * Removed count assignment in the write function, which was not needed anymore - * either. Thanks to Al Borchers for pointing this out. - * - * (12/12/2000) gkh - * Moved MOD_DEC to end of visor_close to be nicer, as the final write - * message can sleep. - * - * (11/12/2000) gkh - * Fixed bug with data being dropped on the floor by forcing tty->low_latency - * to be on. Hopefully this fixes the OHCI issue! - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Got rid of always calling kmalloc for every urb we wrote out to the - * device. - * Added visor_read_callback so we can keep track of bytes in and out for - * those people who like to know the speed of their device. - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (09/06/2000) gkh - * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ - * the host controller drivers set urb->dev = NULL when the urb is finished. - * - * (08/28/2000) gkh - * Added locks for SMP safeness. - * - * (08/08/2000) gkh - * Fixed endian problem in visor_startup. - * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - * than once. - * - * (07/23/2000) gkh - * Added pool of write urbs to speed up transfers to the visor. - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * - * (07/03/2000) gkh - * Added visor_set_ioctl and visor_set_termios functions (they don't do much - * of anything, but are good for debugging.) - * - * (06/25/2000) gkh - * Fixed bug in visor_unthrottle that should help with the disconnect in PPP - * bug that people have been reporting. - * - * (06/23/2000) gkh - * Cleaned up debugging statements in a quest to find UHCI timeout bug. - * - * (04/27/2000) Ryan VanderBijl - * Fixed memory leak in visor_close - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * */ #include From 269bda1c123c7caf88e1deb2264f9086f0344192 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1185/1939] [PATCH] USB Serial: move name to driver structure This fixes up a lot of problems in sysfs with some of the usb serial drivers, they had incorrect driver names. Also saves a tiny ammount of memory. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 2 +- drivers/usb/serial/belkin_sa.c | 4 ++-- drivers/usb/serial/bus.c | 8 ++----- drivers/usb/serial/cp2101.c | 4 ++-- drivers/usb/serial/cyberjack.c | 4 ++-- drivers/usb/serial/cypress_m8.c | 8 +++---- drivers/usb/serial/digi_acceleport.c | 12 +++++------ drivers/usb/serial/empeg.c | 2 +- drivers/usb/serial/ftdi_sio.c | 4 ++-- drivers/usb/serial/garmin_gps.c | 4 ++-- drivers/usb/serial/generic.c | 3 +-- drivers/usb/serial/hp4x.c | 4 ++-- drivers/usb/serial/io_tables.h | 12 +++++------ drivers/usb/serial/io_ti.c | 12 +++++------ drivers/usb/serial/ipaq.c | 3 ++- drivers/usb/serial/ipw.c | 4 ++-- drivers/usb/serial/ir-usb.c | 3 ++- drivers/usb/serial/keyspan.h | 16 +++++++------- drivers/usb/serial/keyspan_pda.c | 12 +++++------ drivers/usb/serial/kl5kusb105.c | 4 ++-- drivers/usb/serial/kobil_sct.c | 3 ++- drivers/usb/serial/mct_u232.c | 4 ++-- drivers/usb/serial/omninet.c | 4 ++-- drivers/usb/serial/option.c | 4 ++-- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/safe_serial.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 10 +++++---- drivers/usb/serial/usb-serial.c | 15 ++++++++------ drivers/usb/serial/usb-serial.h | 12 +++++------ drivers/usb/serial/visor.c | 18 ++++++++-------- drivers/usb/serial/whiteheat.c | 30 +++++++++++++-------------- 31 files changed, 115 insertions(+), 114 deletions(-) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index fbc5b9b44749..1f29d8837327 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -33,8 +33,8 @@ static struct usb_driver airprime_driver = { static struct usb_serial_driver airprime_device = { .driver = { .owner = THIS_MODULE, + .name = "airprime", }, - .name = "airprime", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 4878961a0900..84bc0ee4f061 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -124,9 +124,9 @@ static struct usb_driver belkin_driver = { static struct usb_serial_driver belkin_device = { .driver = { .owner = THIS_MODULE, + .name = "belkin", }, - .name = "Belkin / Peracom / GoHubs USB Serial Adapter", - .short_name = "belkin", + .description = "Belkin / Peracom / GoHubs USB Serial Adapter", .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index b8364a8de7df..664139afcfa9 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -72,7 +72,7 @@ static int usb_serial_device_probe (struct device *dev) tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", - driver->name, minor); + driver->description, minor); exit: return retval; @@ -104,7 +104,7 @@ static int usb_serial_device_remove (struct device *dev) minor = port->number; tty_unregister_device (usb_serial_tty_driver, minor); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", - driver->name, minor); + driver->description, minor); return retval; } @@ -113,10 +113,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) { int retval; - if (driver->short_name) - driver->driver.name = (char *)driver->short_name; - else - driver->driver.name = (char *)driver->name; driver->driver.bus = &usb_serial_bus_type; driver->driver.probe = usb_serial_device_probe; driver->driver.remove = usb_serial_device_remove; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 81dd720a122b..c5334dd89b12 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -67,7 +67,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver cp2101_driver = { .owner = THIS_MODULE, - .name = "CP2101", + .name = "cp2101", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, @@ -76,8 +76,8 @@ static struct usb_driver cp2101_driver = { static struct usb_serial_driver cp2101_device = { .driver = { .owner = THIS_MODULE, + .name = "cp2101", }, - .name = "CP2101", .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 3441bad74f7b..e581e4ae8483 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -86,9 +86,9 @@ static struct usb_driver cyberjack_driver = { static struct usb_serial_driver cyberjack_device = { .driver = { .owner = THIS_MODULE, + .name = "cyberjack", }, - .name = "Reiner SCT Cyberjack USB card reader", - .short_name = "cyberjack", + .description = "Reiner SCT Cyberjack USB card reader", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index b4069af4d565..af9290ed257b 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -179,9 +179,9 @@ static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigne static struct usb_serial_driver cypress_earthmate_device = { .driver = { .owner = THIS_MODULE, + .name = "earthmate", }, - .name = "DeLorme Earthmate USB", - .short_name = "earthmate", + .description = "DeLorme Earthmate USB", .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -208,9 +208,9 @@ static struct usb_serial_driver cypress_earthmate_device = { static struct usb_serial_driver cypress_hidcom_device = { .driver = { .owner = THIS_MODULE, + .name = "cyphidcom", }, - .name = "HID->COM RS232 Adapter", - .short_name = "cyphidcom", + .description = "HID->COM RS232 Adapter", .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index be9b495d2491..dc74644a603d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -505,10 +505,10 @@ static struct usb_driver digi_driver = { static struct usb_serial_driver digi_acceleport_2_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "digi_2", }, - .name = "Digi 2 port USB adapter", - .short_name = "digi_2", + .description = "Digi 2 port USB adapter", .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -534,10 +534,10 @@ static struct usb_serial_driver digi_acceleport_2_device = { static struct usb_serial_driver digi_acceleport_4_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "digi_4", }, - .name = "Digi 4 port USB adapter", - .short_name = "digi_4", + .description = "Digi 4 port USB adapter", .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 3e6c4ba7667b..0b0546dcc7b9 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -115,8 +115,8 @@ static struct usb_driver empeg_driver = { static struct usb_serial_driver empeg_device = { .driver = { .owner = THIS_MODULE, + .name = "empeg", }, - .name = "Empeg", .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9d945de0acac..77d54ac39a0e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -565,9 +565,9 @@ static __u32 ftdi_232bm_baud_to_divisor (int baud); static struct usb_serial_driver ftdi_sio_device = { .driver = { .owner = THIS_MODULE, + .name = "ftdi_sio", }, - .name = "FTDI USB Serial Device", - .short_name = "ftdi_sio", + .description = "FTDI USB Serial Device", .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 3fd98c00cd6a..35820bda7ae1 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1472,9 +1472,9 @@ static void garmin_shutdown (struct usb_serial *serial) static struct usb_serial_driver garmin_device = { .driver = { .owner = THIS_MODULE, + .name = "garmin_gps", }, - .name = "Garmin GPS usb/tty", - .short_name = "garmin_gps", + .description = "Garmin GPS usb/tty", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 779bea0c6242..8909208f506a 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -39,9 +39,8 @@ static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ struct usb_serial_driver usb_serial_generic_device = { .driver = { .owner = THIS_MODULE, + .name = "generic", }, - .name = "Generic", - .short_name = "generic", .id_table = generic_device_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 4f3cbc08c4ee..8eadfb705601 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -38,7 +38,7 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_driver hp49gp_driver = { .owner = THIS_MODULE, - .name = "HP4X", + .name = "hp4X", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, @@ -47,8 +47,8 @@ static struct usb_driver hp49gp_driver = { static struct usb_serial_driver hp49gp_device = { .driver = { .owner = THIS_MODULE, + .name = "hp4X", }, - .name = "HP4X", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 28fb0d42a166..fad561c04c76 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -78,9 +78,9 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, + .name = "edgeport_2", }, - .name = "Edgeport 2 port adapter", - .short_name = "edgeport_2", + .description = "Edgeport 2 port adapter", .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -108,9 +108,9 @@ static struct usb_serial_driver edgeport_2port_device = { static struct usb_serial_driver edgeport_4port_device = { .driver = { .owner = THIS_MODULE, + .name = "edgeport_4", }, - .name = "Edgeport 4 port adapter", - .short_name = "edgeport_4", + .description = "Edgeport 4 port adapter", .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -138,9 +138,9 @@ static struct usb_serial_driver edgeport_4port_device = { static struct usb_serial_driver edgeport_8port_device = { .driver = { .owner = THIS_MODULE, + .name = "edgeport_8", }, - .name = "Edgeport 8 port adapter", - .short_name = "edgeport_8", + .description = "Edgeport 8 port adapter", .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 74228a072643..832b6d6734c0 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2984,10 +2984,10 @@ static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, static struct usb_serial_driver edgeport_1port_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "edgeport_ti_1", }, - .name = "Edgeport TI 1 port adapter", - .short_name = "edgeport_ti_1", + .description = "Edgeport TI 1 port adapter", .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3014,10 +3014,10 @@ static struct usb_serial_driver edgeport_1port_device = { static struct usb_serial_driver edgeport_2port_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "edgeport_ti_2", }, - .name = "Edgeport TI 2 port adapter", - .short_name = "edgeport_ti_2", + .description = "Edgeport TI 2 port adapter", .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 9aedfb91b20c..1abaebe6dbc1 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -550,8 +550,9 @@ static struct usb_driver ipaq_driver = { static struct usb_serial_driver ipaq_device = { .driver = { .owner = THIS_MODULE, + .name = "ipaq", }, - .name = "PocketPC PDA", + .description = "PocketPC PDA", .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 2ba69623ac05..a02fada85362 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -446,9 +446,9 @@ static int ipw_disconnect(struct usb_serial_port *port) static struct usb_serial_driver ipw_device = { .driver = { .owner = THIS_MODULE, + .name = "ipw", }, - .name = "IPWireless converter", - .short_name = "ipw", + .description = "IPWireless converter", .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index bf079059819e..19f329e9bdcf 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -136,8 +136,9 @@ static struct usb_driver ir_driver = { static struct usb_serial_driver ir_device = { .driver = { .owner = THIS_MODULE, + .name = "ir-usb", }, - .name = "IR Dongle", + .description = "IR Dongle", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 124d46e76a2e..5cfc13b5e56f 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -573,9 +573,9 @@ static struct usb_device_id keyspan_4port_ids[] = { static struct usb_serial_driver keyspan_pre_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_no_firm", }, - .name = "Keyspan - (without firmware)", - .short_name = "keyspan_no_firm", + .description = "Keyspan - (without firmware)", .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -587,9 +587,9 @@ static struct usb_serial_driver keyspan_pre_device = { static struct usb_serial_driver keyspan_1port_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_1", }, - .name = "Keyspan 1 port adapter", - .short_name = "keyspan_1", + .description = "Keyspan 1 port adapter", .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -614,9 +614,9 @@ static struct usb_serial_driver keyspan_1port_device = { static struct usb_serial_driver keyspan_2port_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_2", }, - .name = "Keyspan 2 port adapter", - .short_name = "keyspan_2", + .description = "Keyspan 2 port adapter", .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -641,9 +641,9 @@ static struct usb_serial_driver keyspan_2port_device = { static struct usb_serial_driver keyspan_4port_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_4", }, - .name = "Keyspan 4 port adapter", - .short_name = "keyspan_4", + .description = "Keyspan 4 port adapter", .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 389b7833e3ae..cd4f48bd83b6 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -786,9 +786,9 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) static struct usb_serial_driver keyspan_pda_fake_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_pda_pre", }, - .name = "Keyspan PDA - (prerenumeration)", - .short_name = "keyspan_pda_pre", + .description = "Keyspan PDA - (prerenumeration)", .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -802,9 +802,9 @@ static struct usb_serial_driver keyspan_pda_fake_device = { static struct usb_serial_driver xircom_pgs_fake_device = { .driver = { .owner = THIS_MODULE, + .name = "xircom_no_firm", }, - .name = "Xircom / Entregra PGS - (prerenumeration)", - .short_name = "xircom_no_firm", + .description = "Xircom / Entregra PGS - (prerenumeration)", .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -817,9 +817,9 @@ static struct usb_serial_driver xircom_pgs_fake_device = { static struct usb_serial_driver keyspan_pda_device = { .driver = { .owner = THIS_MODULE, + .name = "keyspan_pda", }, - .name = "Keyspan PDA", - .short_name = "keyspan_pda", + .description = "Keyspan PDA", .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 586108ce7897..a8951c0fd020 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -126,9 +126,9 @@ static struct usb_driver kl5kusb105d_driver = { static struct usb_serial_driver kl5kusb105d_device = { .driver = { .owner = THIS_MODULE, + .name = "kl5kusb105d", }, - .name = "KL5KUSB105D / PalmConnect", - .short_name = "kl5kusb105d", + .description = "KL5KUSB105D / PalmConnect", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index a9578e05b22f..9456dd9dd136 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -108,8 +108,9 @@ static struct usb_driver kobil_driver = { static struct usb_serial_driver kobil_device = { .driver = { .owner = THIS_MODULE, + .name = "kobil", }, - .name = "KOBIL USB smart card terminal", + .description = "KOBIL USB smart card terminal", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 7dcf91c5f83d..ca5dbadb9b7e 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -135,9 +135,9 @@ static struct usb_driver mct_u232_driver = { static struct usb_serial_driver mct_u232_device = { .driver = { .owner = THIS_MODULE, + .name = "mct_u232", }, - .name = "MCT U232", - .short_name = "mct_u232", + .description = "MCT U232", .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index f6327cc1b2e7..3caf97072ac0 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -91,9 +91,9 @@ static struct usb_driver omninet_driver = { static struct usb_serial_driver zyxel_omninet_device = { .driver = { .owner = THIS_MODULE, + .name = "omninet", }, - .name = "ZyXEL - omni.net lcd plus usb", - .short_name = "omninet", + .description = "ZyXEL - omni.net lcd plus usb", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index a2b5adf34868..7716000045b7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -108,9 +108,9 @@ static struct usb_driver option_driver = { static struct usb_serial_driver option_3port_device = { .driver = { .owner = THIS_MODULE, + .name = "option", }, - .name = "Option 3G data card", - .short_name = "option", + .description = "Option 3G data card", .id_table = option_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 29719ceab19a..f8f4e93e8c0b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -157,8 +157,8 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, static struct usb_serial_driver pl2303_device = { .driver = { .owner = THIS_MODULE, + .name = "pl2303", }, - .name = "PL-2303", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 42a86ab689f4..c22bdc0c4dfd 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -400,8 +400,8 @@ static int safe_startup (struct usb_serial *serial) static struct usb_serial_driver safe_device = { .driver = { .owner = THIS_MODULE, + .name = "safe_serial", }, - .name = "Safe", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index eab8a6de0925..205dbf7201da 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -257,9 +257,10 @@ static struct usb_driver ti_usb_driver = { static struct usb_serial_driver ti_1port_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "ti_usb_3410_5052_1", }, - .name = "TI USB 3410 1 port adapter", + .description = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -286,9 +287,10 @@ static struct usb_serial_driver ti_1port_device = { static struct usb_serial_driver ti_2port_device = { .driver = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + .name = "ti_usb_3410_5052_2", }, - .name = "TI USB 5052 2 port adapter", + .description = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index fde09fba8790..13f6592be685 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -122,7 +122,7 @@ static void destroy_serial(struct kref *kref) serial = to_usb_serial(kref); - dbg ("%s - %s", __FUNCTION__, serial->type->name); + dbg("%s - %s", __FUNCTION__, serial->type->description); serial->type->shutdown(serial); @@ -415,7 +415,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int length += sprintf (page+length, "%d:", i); if (serial->type->driver.owner) length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner)); - length += sprintf (page+length, " name:\"%s\"", serial->type->name); + length += sprintf (page+length, " name:\"%s\"", serial->type->description); length += sprintf (page+length, " vendor:%04x product:%04x", le16_to_cpu(serial->dev->descriptor.idVendor), le16_to_cpu(serial->dev->descriptor.idProduct)); @@ -687,7 +687,7 @@ int usb_serial_probe(struct usb_interface *interface, #endif /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->name); + dev_info(&interface->dev, "%s converter detected\n", type->description); #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { @@ -1088,16 +1088,19 @@ int usb_serial_register(struct usb_serial_driver *driver) fixup_generic(driver); + if (!driver->description) + driver->description = driver->driver.name; + /* Add this device to our list of devices */ list_add(&driver->driver_list, &usb_serial_driver_list); retval = usb_serial_bus_register(driver); if (retval) { - err("problem %d when registering driver %s", retval, driver->name); + err("problem %d when registering driver %s", retval, driver->description); list_del(&driver->driver_list); } else - info("USB Serial support registered for %s", driver->name); + info("USB Serial support registered for %s", driver->description); return retval; } @@ -1105,7 +1108,7 @@ int usb_serial_register(struct usb_serial_driver *driver) void usb_serial_deregister(struct usb_serial_driver *device) { - info("USB Serial deregistering driver %s", device->name); + info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); usb_serial_bus_deregister(device); } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 1cedc1999508..238a5a871ed6 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -149,11 +149,8 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) /** * usb_serial_driver - describes a usb serial driver - * @name: pointer to a string that describes this driver. This string used + * @description: pointer to a string that describes this driver. This string used * in the syslog messages when a device is inserted or removed. - * @short_name: a pointer to a string that describes this driver in - * KOBJ_NAME_LEN characters or less. This is used for the sysfs interface - * to describe the driver. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. * @num_interrupt_in: the number of interrupt in endpoints this device will @@ -187,11 +184,12 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * called, the generic serial function will be used instead. * * The driver.owner field should be set to the module owner of this driver. - * + * The driver.name field should be set to the name of this driver (remember + * it will show up in sysfs, so it needs to be short and to the point. + * Useing the module name is a good idea.) */ struct usb_serial_driver { - char *name; - char *short_name; + const char *description; const struct usb_device_id *id_table; char num_interrupt_in; char num_interrupt_out; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 39ad0cab8635..baa2acb28bd8 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -185,9 +185,9 @@ static struct usb_driver visor_driver = { static struct usb_serial_driver handspring_device = { .driver = { .owner = THIS_MODULE, + .name = "visor", }, - .name = "Handspring Visor / Palm OS", - .short_name = "visor", + .description = "Handspring Visor / Palm OS", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -215,9 +215,9 @@ static struct usb_serial_driver handspring_device = { static struct usb_serial_driver clie_5_device = { .driver = { .owner = THIS_MODULE, + .name = "clie_5", }, - .name = "Sony Clie 5.0", - .short_name = "clie_5", + .description = "Sony Clie 5.0", .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -245,9 +245,9 @@ static struct usb_serial_driver clie_5_device = { static struct usb_serial_driver clie_3_5_device = { .driver = { .owner = THIS_MODULE, + .name = "clie_3.5", }, - .name = "Sony Clie 3.5", - .short_name = "clie_3.5", + .description = "Sony Clie 3.5", .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, @@ -659,7 +659,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i break; } dev_info(dev, "%s: port %d, is for %s use\n", - serial->type->name, + serial->type->description, connection_info->connections[i].port, string); } } @@ -668,11 +668,11 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i */ if (num_ports == 0 || num_ports > 2) { dev_warn (dev, "%s: No valid connect info available\n", - serial->type->name); + serial->type->description); num_ports = 2; } - dev_info(dev, "%s: Number of ports: %d\n", serial->type->name, + dev_info(dev, "%s: Number of ports: %d\n", serial->type->description, num_ports); /* diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index fb95a34a1cf7..18c3183be769 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -159,9 +159,9 @@ static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs); static struct usb_serial_driver whiteheat_fake_device = { .driver = { .owner = THIS_MODULE, + .name = "whiteheatnofirm", }, - .name = "Connect Tech - WhiteHEAT - (prerenumeration)", - .short_name = "whiteheatnofirm", + .description = "Connect Tech - WhiteHEAT - (prerenumeration)", .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -174,9 +174,9 @@ static struct usb_serial_driver whiteheat_fake_device = { static struct usb_serial_driver whiteheat_device = { .driver = { .owner = THIS_MODULE, + .name = "whiteheat", }, - .name = "Connect Tech - WhiteHEAT", - .short_name = "whiteheat", + .description = "Connect Tech - WhiteHEAT", .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -386,10 +386,10 @@ static int whiteheat_attach (struct usb_serial *serial) usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS); if (ret) { - err("%s: Couldn't send command [%d]", serial->type->name, ret); + err("%s: Couldn't send command [%d]", serial->type->description, ret); goto no_firmware; } else if (alen != sizeof(command)) { - err("%s: Send command incomplete [%d]", serial->type->name, alen); + err("%s: Send command incomplete [%d]", serial->type->description, alen); goto no_firmware; } @@ -398,19 +398,19 @@ static int whiteheat_attach (struct usb_serial *serial) usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS); if (ret) { - err("%s: Couldn't get results [%d]", serial->type->name, ret); + err("%s: Couldn't get results [%d]", serial->type->description, ret); goto no_firmware; } else if (alen != sizeof(result)) { - err("%s: Get results incomplete [%d]", serial->type->name, alen); + err("%s: Get results incomplete [%d]", serial->type->description, alen); goto no_firmware; } else if (result[0] != command[0]) { - err("%s: Command failed [%d]", serial->type->name, result[0]); + err("%s: Command failed [%d]", serial->type->description, result[0]); goto no_firmware; } hw_info = (struct whiteheat_hw_info *)&result[1]; - info("%s: Driver %s: Firmware v%d.%02d", serial->type->name, + info("%s: Driver %s: Firmware v%d.%02d", serial->type->description, DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev); for (i = 0; i < serial->num_ports; i++) { @@ -418,7 +418,7 @@ static int whiteheat_attach (struct usb_serial *serial) info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); if (info == NULL) { - err("%s: Out of memory for port structures\n", serial->type->name); + err("%s: Out of memory for port structures\n", serial->type->description); goto no_private; } @@ -488,7 +488,7 @@ static int whiteheat_attach (struct usb_serial *serial) command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); if (command_info == NULL) { - err("%s: Out of memory for port structures\n", serial->type->name); + err("%s: Out of memory for port structures\n", serial->type->description); goto no_command_private; } @@ -505,9 +505,9 @@ static int whiteheat_attach (struct usb_serial *serial) no_firmware: /* Firmware likely not running */ - err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name); - err("%s: If the firmware is not running (status led not blinking)\n", serial->type->name); - err("%s: please contact support@connecttech.com\n", serial->type->name); + err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description); + err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description); + err("%s: please contact support@connecttech.com\n", serial->type->description); return -ENODEV; no_command_private: From 17a882fc0c91477b2582a6dfd4ca93ae7eb58cd3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1186/1939] [PATCH] USB Serial: remove driver version from a few drivers These numbers are pointless, as they have not been changed in _years_, so we should just remove them to stop pretending there is an actual "version number" for these drivers. This should also help reduce confusion when people try to ask for support of a specific driver version, as there has been no way to tell what they are talking about. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 4 +--- drivers/usb/serial/usb-serial.c | 6 ++---- drivers/usb/serial/visor.c | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f8f4e93e8c0b..165c119bf10e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -34,7 +34,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" static int debug; @@ -1176,7 +1175,7 @@ static int __init pl2303_init (void) retval = usb_register(&pl2303_driver); if (retval) goto failed_usb_register; - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return 0; failed_usb_register: usb_serial_deregister(&pl2303_device); @@ -1196,7 +1195,6 @@ module_init(pl2303_init); module_exit(pl2303_exit); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 13f6592be685..0c4881d18cd5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -37,7 +37,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" @@ -406,7 +405,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int char tmp[40]; dbg("%s", __FUNCTION__); - length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION); + length += sprintf (page, "usbserinfo:1.0 driver:2.0\n"); for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { serial = usb_serial_get_by_index(i); if (serial == NULL) @@ -1025,7 +1024,7 @@ static int __init usb_serial_init(void) goto exit_generic; } - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return result; @@ -1127,7 +1126,6 @@ EXPORT_SYMBOL_GPL(usb_serial_port_softint); /* Module information */ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_VERSION( DRIVER_VERSION ); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index baa2acb28bd8..a473c1c34559 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -32,7 +32,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB HandSpring Visor / Palm OS driver" @@ -1002,7 +1001,7 @@ static int __init visor_init (void) retval = usb_register(&visor_driver); if (retval) goto failed_usb_register; - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return 0; failed_usb_register: From 7521803dcc0137668bb30483383092a647671d8b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1187/1939] [PATCH] USB: always export interface information for modalias This fixes a problem with some cdc acm devices that were not getting automatically loaded as the module alias was not being reported properly. This check was for back in the days when we only reported hotplug events for the main usb device, not the interfaces. We should always give the interface information for MODALIAS/modalias as it can be needed. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 33 +++++++++------------ drivers/usb/core/usb.c | 63 +++++++++++++++------------------------- 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index eae413bf8c2a..4bdbc9df6e03 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -462,30 +462,23 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, { struct usb_interface *intf; struct usb_device *udev; - int len; + struct usb_host_interface *alt; intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + alt = intf->cur_altsetting; - len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - le16_to_cpu(udev->descriptor.bcdDevice), - udev->descriptor.bDeviceClass, - udev->descriptor.bDeviceSubClass, - udev->descriptor.bDeviceProtocol); - buf += len; - - if (udev->descriptor.bDeviceClass == 0) { - struct usb_host_interface *alt = intf->cur_altsetting; - - return len + sprintf(buf, "%02Xisc%02Xip%02X\n", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol); - } else { - return len + sprintf(buf, "*isc*ip*\n"); - } + return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" + "ic%02Xisc%02Xip%02X\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + le16_to_cpu(udev->descriptor.bcdDevice), + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol); } static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 2493e7d9f5b3..4eca4904938f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -569,6 +569,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, { struct usb_interface *intf; struct usb_device *usb_dev; + struct usb_host_interface *alt; int i = 0; int length = 0; @@ -585,7 +586,8 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, intf = to_usb_interface(dev); usb_dev = interface_to_usbdev (intf); - + alt = intf->cur_altsetting; + if (usb_dev->devnum < 0) { pr_debug ("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; @@ -627,46 +629,27 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (usb_dev->descriptor.bDeviceClass == 0) { - struct usb_host_interface *alt = intf->cur_altsetting; + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "INTERFACE=%d/%d/%d", + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; - /* 2.4 only exposed interface zero. in 2.5, hotplug - * agents are called for all interfaces, and can use - * $DEVPATH/bInterfaceNumber if necessary. - */ - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - } else { - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol)) - return -ENOMEM; - } + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + le16_to_cpu(usb_dev->descriptor.bcdDevice), + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; envp[i] = NULL; From dcab4eaf77ccd8779c715da3c5db0a82874fa645 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Wed, 19 Oct 2005 11:32:14 -0400 Subject: [PATCH 1188/1939] [PATCH] USB: storage patch for LEICA camera On Tue, 18 Oct 2005, Simeon Simeonov wrote: > Attached is a patch that solves mounting problems for > LEICA D-LUX camera with FC4 2.6.13 kernel. > > Let me know if you have some questions. Looks okay to me. Given that the previous entry uses the full 0000 - 9999 range, I guess this one can also. The vendor name is a little odd (it will give us three different vendor names all in entries with the same vendor ID) but that doesn't really matter either. Signed-off-by: Alan Stern Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a11701840262..d0f6a7e2fe31 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -251,6 +251,13 @@ UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), +/* Reported by Simeon Simeonov */ +UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999, + "LEICA", + "D-LUX Camera", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ From 61eded6e06a1f4bdbf707b69da904ba9f3eb2f0a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 24 Oct 2005 22:37:20 +0200 Subject: [PATCH 1189/1939] [PATCH] USB: microtek patch to use kzalloc here is another one to use kzalloc. Please apply. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/microtek.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index c84e1486054f..c89d0769b3da 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -773,11 +773,10 @@ static int mts_usb_probe(struct usb_interface *intf, } - new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL); + new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL); if (!new_desc) goto out; - memset(new_desc, 0, sizeof(*new_desc)); new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); if (!new_desc->urb) goto out_kfree; From f2d45cd976682a3566c8cf30cefe91eb43ab6005 Mon Sep 17 00:00:00 2001 From: Guillaume GOURAT / Date: Fri, 21 Oct 2005 14:01:35 +0200 Subject: [PATCH 1190/1939] [PATCH] USB: Kaweth.c udelay patch On some arch (like arm) udelay cannot be called with value greater that 2000. Signed-off-by: Guillaume GOURAT / guillaume.gourat@nexvision.fr Signed-off-by: Oliver Neukum --- drivers/usb/net/kaweth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index c82655d3d448..6bef1be6b36c 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -469,7 +469,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) 0, KAWETH_CONTROL_TIMEOUT); - udelay(10000); + mdelay(10); kaweth_dbg("kaweth_reset() returns %d.",result); From eb3c5ed8617d0aa67648cb7d1a486d14099129f2 Mon Sep 17 00:00:00 2001 From: David Eriksson Date: Tue, 18 Oct 2005 20:12:24 +0200 Subject: [PATCH 1191/1939] [PATCH] USB: Improving the set of vendor/product IDs in the ipaq driver This is a patch improving the set of vendor/product IDs used in the "ipaq" USB serial device driver. The patch size is because I sorted the ids this time, forgot about that last time. Changes: - Added vendor/product identifiers for Psion Teklogix devices - Restored Microsoft's identifier pair 045e/00ce - Sorted list of vendor/product identifiers Signed-off-by: David Eriksson Signed-off-by: Ganesh Varadarajan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 246 +++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 121 deletions(-) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 1abaebe6dbc1..d5d066488100 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -92,24 +92,7 @@ static void ipaq_destroy_lists(struct usb_serial_port *port); static struct usb_device_id ipaq_id_table [] = { /* The first entry is a placeholder for the insmod-specified device */ { USB_DEVICE(0x049F, 0x0003) }, - { USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */ - { USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */ - { USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */ - { USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */ - { USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */ - { USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */ - { USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */ - { USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ { USB_DEVICE(0x03F0, 0x1216) }, /* HP USB Sync 1612 */ @@ -125,7 +108,13 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x03F0, 0x5016) }, /* HP USB Sync 1650 */ { USB_DEVICE(0x03F0, 0x5116) }, /* HP USB Sync 1651 */ { USB_DEVICE(0x03F0, 0x5216) }, /* HP USB Sync 1652 */ - { USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */ + { USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */ + { USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */ + { USB_DEVICE(0x045E, 0x00CE) }, /* Microsoft USB Sync */ { USB_DEVICE(0x045E, 0x0400) }, /* Windows Powered Pocket PC 2002 */ { USB_DEVICE(0x045E, 0x0401) }, /* Windows Powered Pocket PC 2002 */ { USB_DEVICE(0x045E, 0x0402) }, /* Windows Powered Pocket PC 2002 */ @@ -251,17 +240,81 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x045E, 0x04E8) }, /* Windows Powered Smartphone 2003 */ { USB_DEVICE(0x045E, 0x04E9) }, /* Windows Powered Smartphone 2003 */ { USB_DEVICE(0x045E, 0x04EA) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */ - { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */ - { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ + { USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */ + { USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */ + { USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */ + { USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */ + { USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */ + { USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */ + { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ + { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ + { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ + { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */ + { USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */ + { USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */ + { USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */ + { USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */ + { USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */ + { USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */ + { USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */ + { USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */ + { USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */ + { USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */ + { USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */ + { USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */ + { USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */ + { USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */ + { USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */ + { USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */ + { USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */ + { USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */ + { USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */ + { USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */ + { USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */ + { USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */ + { USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */ + { USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */ + { USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */ + { USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */ + { USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */ + { USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */ + { USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */ + { USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */ { USB_DEVICE(0x0930, 0x0700) }, /* TOSHIBA USB Sync 0700 */ { USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */ + { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */ { USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */ { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */ - { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */ { USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */ { USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */ { USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */ + { USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */ + { USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */ + { USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */ + { USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */ + { USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */ + { USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */ + { USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */ + { USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ { USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */ @@ -422,116 +475,67 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */ - { USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */ { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */ - { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */ - { USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */ - { USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */ - { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */ - { USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */ - { USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */ - { USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */ - { USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */ - { USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */ - { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */ - { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */ - { USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */ - { USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */ - { USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */ - { USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */ - { USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */ - { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ - { USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */ - { USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */ - { USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */ - { USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */ - { USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */ - { USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */ - { USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */ - { USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */ - { USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */ - { USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */ - { USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */ - { USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */ - { USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */ - { USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */ { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */ - { USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */ - { USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */ - { USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */ - { USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */ - { USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */ - { USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */ - { USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */ - { USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */ - { USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */ - { USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */ - { USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */ - { USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */ - { USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */ - { USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */ - { USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */ - { USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */ - { USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */ - { USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */ - { USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */ - { USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */ - { USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */ - { USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */ - { USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */ - { USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */ + { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */ + { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */ + { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */ + { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */ { USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */ { USB_DEVICE(0x0FB8, 0x3002) }, /* Wistron USB Sync */ { USB_DEVICE(0x0FB8, 0x3003) }, /* Wistron USB Sync */ { USB_DEVICE(0x0FB8, 0x4001) }, /* Wistron USB Sync */ - { USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */ + { USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */ + { USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */ + { USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */ + { USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */ + { USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */ + { USB_DEVICE(0x1114, 0x0001) }, /* Psion Teklogix Sync 753x */ + { USB_DEVICE(0x1114, 0x0004) }, /* Psion Teklogix Sync netBookPro */ + { USB_DEVICE(0x1114, 0x0006) }, /* Psion Teklogix Sync 7525 */ + { USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */ { USB_DEVICE(0x11D9, 0x1002) }, /* Rugged Pocket PC 2003 */ + { USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */ + { USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */ + { USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */ + { USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */ { USB_DEVICE(0x22B8, 0x4204) }, /* Motorola MPx200 Smartphone */ { USB_DEVICE(0x22B8, 0x4214) }, /* Motorola MPc GSM */ { USB_DEVICE(0x22B8, 0x4224) }, /* Motorola MPx220 Smartphone */ { USB_DEVICE(0x22B8, 0x4234) }, /* Motorola MPc CDMA */ { USB_DEVICE(0x22B8, 0x4244) }, /* Motorola MPx100 Smartphone */ - { USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */ - { USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */ + { USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */ + { USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */ + { USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */ + { USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */ + { USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */ + { USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */ + { USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */ + { USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */ + { USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */ + { USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */ + { USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */ + { USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */ + { USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */ + { USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */ + { USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */ + { USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */ + { USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */ + { USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */ + { USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */ + { USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */ + { USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */ + { USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */ + { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */ { } /* Terminating entry */ }; From 46f116eab81b21c6ae8c4f169498c632b1f94bf1 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 24 Oct 2005 22:42:35 +0200 Subject: [PATCH 1192/1939] [PATCH] USB: cdc-acm patch to use kzalloc another one to use kzalloc. Please apply. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 16ecad30e29c..1b4751412970 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -827,11 +827,10 @@ static int acm_probe (struct usb_interface *intf, return -ENODEV; } - if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); + if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { + dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } - memset(acm, 0, sizeof(struct acm)); ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize); From 478a3bab8c87a9ba4a4ba338314e32bb0c378e62 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 19 Oct 2005 12:52:02 -0400 Subject: [PATCH 1193/1939] [PATCH] USB: Always do usb-handoff This revised patch (as586b) makes usb-handoff permanently true and no longer a kernel boot parameter. It also removes the piix3_usb quirk code; that was nothing more than an early version of the USB handoff code (written at a time when Intel's PIIX3 was about the only motherboard with USB support). And it adds identifiers for the three PCI USB controller classes to pci_ids.h. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 - drivers/usb/host/pci-quirks.c | 46 ++------------------- include/asm-i386/mach-summit/mach_mpparse.h | 3 -- include/linux/pci_ids.h | 3 ++ 4 files changed, 6 insertions(+), 48 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 971589a9752d..90766b75d1b7 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1517,8 +1517,6 @@ running once the system is up. uart6850= [HW,OSS] Format: , - usb-handoff [HW] Enable early USB BIOS -> OS handoff - usbhid.mousepoll= [USBHID] The interval which mice are to be polled at. diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index f7411ca48835..b7fd3f644e1e 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -23,33 +23,6 @@ #include -/* - * PIIX3 USB: We have to disable USB interrupts that are - * hardwired to PIRQD# and may be shared with an - * external device. - * - * Legacy Support Register (LEGSUP): - * bit13: USB PIRQ Enable (USBPIRQDEN), - * bit4: Trap/SMI On IRQ Enable (USBSMIEN). - * - * We mask out all r/wc bits, too. - */ -static void __devinit quirk_piix3_usb(struct pci_dev *dev) -{ - u16 legsup; - - pci_read_config_word(dev, 0xc0, &legsup); - legsup &= 0x50ef; - pci_write_config_word(dev, 0xc0, legsup); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); - - -/* FIXME these should be the guts of hcd->reset() methods; resolve all - * the differences between this version and the HCD's version. - */ - #define UHCI_USBLEGSUP 0xc0 /* legacy support */ #define UHCI_USBCMD 0 /* command register */ #define UHCI_USBINTR 4 /* interrupt register */ @@ -83,13 +56,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, qui #define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ #define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ -int usb_early_handoff __devinitdata = 0; -static int __init usb_handoff_early(char *str) -{ - usb_early_handoff = 1; - return 0; -} -__setup("usb-handoff", usb_handoff_early); /* * Make sure the controller is completely inactive, unable to @@ -320,17 +286,11 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) { - if (!usb_early_handoff) - return; - - if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) quirk_usb_handoff_uhci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ + else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) quirk_usb_handoff_ohci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ + else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) quirk_usb_disable_ehci(pdev); - } - - return; } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h index 2b9e6d55bef1..1cce2b924a80 100644 --- a/include/asm-i386/mach-summit/mach_mpparse.h +++ b/include/asm-i386/mach-summit/mach_mpparse.h @@ -22,7 +22,6 @@ static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, { } -extern int usb_early_handoff; static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { @@ -32,7 +31,6 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, || !strncmp(productid, "RUTHLESS SMP", 12))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); - usb_early_handoff = 1; return 1; } return 0; @@ -46,7 +44,6 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) || !strncmp(oem_table_id, "EXA", 3))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); - usb_early_handoff = 1; return 1; } return 0; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 7d300f7469e3..467a096c3b81 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -96,6 +96,9 @@ #define PCI_CLASS_SERIAL_ACCESS 0x0c01 #define PCI_CLASS_SERIAL_SSA 0x0c02 #define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300 +#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310 +#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320 #define PCI_CLASS_SERIAL_FIBER 0x0c04 #define PCI_CLASS_SERIAL_SMBUS 0x0c05 From 423e489d704d05c6e8c2927fb1854db85914912a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 19 Oct 2005 13:06:13 -0400 Subject: [PATCH 1194/1939] [PATCH] hid-core: Add Clear-Halt on the Interrupt-in endpoint This patch (as577) adds a Clear-Halt call on the Interrupt-in endpoint during input device configuration. Without it my HP USB keyboard doesn't work. Vojtech says it's worth trying, since it might help with some recalcitrant devices. On the other hand, it might interfere with others. I'm submitting it so that it can get tested by a range of users. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index f7fcce731f54..79ddce4555ab 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1784,6 +1784,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + /* May be needed for some devices */ + usb_clear_halt(hid->dev, hid->urbin->pipe); + return hid; fail: From b876aef7f890d8c59a45b78858a36cf60fddf522 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 23 Oct 2005 19:38:56 -0700 Subject: [PATCH 1195/1939] [PATCH] PATCH: usb-storage: move GetMaxLUN later in time This patch is originally from Alan Stern (as557). It has been re-diffed against a current tree, and I also corrected a minor merging error. Some time ago we introduced a delay before device scanning, because many devices do not like to receive SCSI commands right after enumeration. Now it turns out there's a device that doesn't like to receive Get-Max-LUN right after enumeration either. Accordingly this patch delays the Get-Max-LUN request until the beginning of the scanning procedure. This fixes Bugzilla entry #5010. Three things are worth noting. First, I removed the locking code from usb_stor_acquire_resources. It's not needed, because the locking is to protect against disconnect events and acquire_resources is only called during probe (so the disconnect routine can't be called). Second, I initialized to 0 the buffer used for the Get-Max-LUN response. It's not really necessary, but it will prevent random values from showing up in the debugging log when the request fails. Third, I added a test against the SINGLE_LUN flag. This will allow us to use the flag to indicate Bulk-only devices that can't handle Get-Max-LUN. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 1 + drivers/usb/storage/usb.c | 30 +++++++++++++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c1ba5301ebfc..e89e945fc4a7 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -923,6 +923,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) int result; /* issue the command */ + us->iobuf[0] = 0; result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5164900e40c1..92ee079d9172 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -747,25 +747,13 @@ static int usb_stor_acquire_resources(struct us_data *us) return -ENOMEM; } - /* Lock the device while we carry out the next two operations */ - down(&us->dev_semaphore); - - /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == US_PR_BULK) { - p = usb_stor_Bulk_max_lun(us); - if (p < 0) { - up(&us->dev_semaphore); - return p; - } - us->max_lun = p; - } - /* Just before we start our control thread, initialize * the device if it needs initialization */ - if (us->unusual_dev->initFunction) - us->unusual_dev->initFunction(us); - - up(&us->dev_semaphore); + if (us->unusual_dev->initFunction) { + p = us->unusual_dev->initFunction(us); + if (p) + return p; + } /* Start up our control thread */ p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); @@ -904,6 +892,14 @@ static int usb_stor_scan_thread(void * __us) /* If the device is still connected, perform the scanning */ if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + + /* For bulk-only devices, determine the max LUN value */ + if (us->protocol == US_PR_BULK && + !(us->flags & US_FL_SINGLE_LUN)) { + down(&us->dev_semaphore); + us->max_lun = usb_stor_Bulk_max_lun(us); + up(&us->dev_semaphore); + } scsi_scan_host(us_to_host(us)); printk(KERN_DEBUG "usb-storage: device scan complete\n"); From bbafa4668f37f5093a3ae2a8b0cbe327e24e12da Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 23 Oct 2005 19:40:22 -0700 Subject: [PATCH 1196/1939] [PATCH] PATCH: usb-storage: allocate separate sense buffer This patch is from Alan Stern (as560). It has been rediffed against a current tree. This patch allocates a separate buffer for usb-storage to use when auto-sensing. Up to now we have been using the sense buffer embedded in a scsi_cmnd struct, which is dangerous on hosts that (a) don't do cache-coherent DMA or (b) have DMA alignment restrictions. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 5 +++-- drivers/usb/storage/usb.c | 8 ++++++++ drivers/usb/storage/usb.h | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index e89e945fc4a7..7ca896a342e3 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -636,11 +636,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* use the new buffer we have */ old_request_buffer = srb->request_buffer; - srb->request_buffer = srb->sense_buffer; + srb->request_buffer = us->sensebuf; /* set the buffer length for transfer */ old_request_bufflen = srb->request_bufflen; - srb->request_bufflen = 18; + srb->request_bufflen = US_SENSE_SIZE; /* set up for no scatter-gather use */ old_sg = srb->use_sg; @@ -652,6 +652,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) temp_result = us->transport(us->srb, us); /* let's clean up right away */ + memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE); srb->resid = old_resid; srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 92ee079d9172..eb901817b7d2 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -467,6 +467,12 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) US_DEBUGP("I/O buffer allocation failed\n"); return -ENOMEM; } + + us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL); + if (!us->sensebuf) { + US_DEBUGP("Sense buffer allocation failed\n"); + return -ENOMEM; + } return 0; } @@ -800,6 +806,8 @@ static void dissociate_dev(struct us_data *us) { US_DEBUGP("-- %s\n", __FUNCTION__); + kfree(us->sensebuf); + /* Free the device-related DMA-mapped buffers */ if (us->cr) usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr, diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index a195adae57b6..dfa4dc71dd3e 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -117,6 +117,7 @@ enum { US_DO_ALL_FLAGS }; */ #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ +#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */ typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); typedef int (*trans_reset)(struct us_data*); @@ -168,6 +169,7 @@ struct us_data { struct usb_ctrlrequest *cr; /* control requests */ struct usb_sg_request current_sg; /* scatter-gather req. */ unsigned char *iobuf; /* I/O buffer */ + unsigned char *sensebuf; /* sense data buffer */ dma_addr_t cr_dma; /* buffer DMA addresses */ dma_addr_t iobuf_dma; From ce2596df79ddbac605a290f4c7cf011cb40524fc Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 23 Oct 2005 19:41:39 -0700 Subject: [PATCH 1197/1939] [PATCH] PATCH: usb-storage: implement minimal PM This patch from Alan Stern started as as568. It has been rediffed against a current tree. This patch adds minimal suspend/resume support to usb-storage. Just enough for it to qualify as PM-aware. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 58 +++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index eb901817b7d2..c1a902691bc6 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -111,11 +111,6 @@ static atomic_t total_threads = ATOMIC_INIT(0); static DECLARE_COMPLETION(threads_gone); -static int storage_probe(struct usb_interface *iface, - const struct usb_device_id *id); - -static void storage_disconnect(struct usb_interface *iface); - /* The entries in this table, except for final ones here * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, * line for line with the entries of us_unsuaul_dev_list[]. @@ -233,13 +228,40 @@ static struct us_unusual_dev us_unusual_dev_list[] = { { NULL } }; -static struct usb_driver usb_storage_driver = { - .owner = THIS_MODULE, - .name = "usb-storage", - .probe = storage_probe, - .disconnect = storage_disconnect, - .id_table = storage_usb_ids, -}; + +#ifdef CONFIG_PM /* Minimal support for suspend and resume */ + +static int storage_suspend(struct usb_interface *iface, pm_message_t message) +{ + struct us_data *us = usb_get_intfdata(iface); + + /* Wait until no command is running */ + down(&us->dev_semaphore); + + US_DEBUGP("%s\n", __FUNCTION__); + iface->dev.power.power_state.event = message.event; + + /* When runtime PM is working, we'll set a flag to indicate + * whether we should autoresume when a SCSI request arrives. */ + + up(&us->dev_semaphore); + return 0; +} + +static int storage_resume(struct usb_interface *iface) +{ + struct us_data *us = usb_get_intfdata(iface); + + down(&us->dev_semaphore); + + US_DEBUGP("%s\n", __FUNCTION__); + iface->dev.power.power_state.event = PM_EVENT_ON; + + up(&us->dev_semaphore); + return 0; +} + +#endif /* CONFIG_PM */ /* * fill_inquiry_response takes an unsigned char array (which must @@ -1042,6 +1064,18 @@ static void storage_disconnect(struct usb_interface *intf) * Initialization and registration ***********************************************************************/ +static struct usb_driver usb_storage_driver = { + .owner = THIS_MODULE, + .name = "usb-storage", + .probe = storage_probe, + .disconnect = storage_disconnect, +#ifdef CONFIG_PM + .suspend = storage_suspend, + .resume = storage_resume, +#endif + .id_table = storage_usb_ids, +}; + static int __init usb_stor_init(void) { int retval; From 3f13e66e219238e025ff561d69826da9342c3f4a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 23 Oct 2005 19:43:36 -0700 Subject: [PATCH 1198/1939] [PATCH] PATCH: usb-storage: use kthread API This patch is originally from Alan Stern (as569). It has been rediffed against a current tree. This patch converts usb-storage to use the kthread API for creating its control and scanning threads. The new code doesn't use kthread_stop because the threads need (or will need in the future) to exit asynchronously. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 63 +++++++++++++-------------------------- drivers/usb/storage/usb.h | 3 -- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index c1a902691bc6..3847ebed2aa4 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -310,22 +311,7 @@ static int usb_stor_control_thread(void * __us) struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources. - */ - daemonize("usb-storage"); current->flags |= PF_NOFREEZE; - unlock_kernel(); - - /* acquire a reference to the host, so it won't be deallocated - * until we're ready to exit */ - scsi_host_get(host); - - /* signal that we've started the thread */ - complete(&(us->notify)); for(;;) { US_DEBUGP("*** thread sleeping.\n"); @@ -768,6 +754,7 @@ static int get_pipes(struct us_data *us) static int usb_stor_acquire_resources(struct us_data *us) { int p; + struct task_struct *th; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) { @@ -784,17 +771,19 @@ static int usb_stor_acquire_resources(struct us_data *us) } /* Start up our control thread */ - p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); - if (p < 0) { + th = kthread_create(usb_stor_control_thread, us, "usb-storage"); + if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); - return p; + return PTR_ERR(th); } - us->pid = p; - atomic_inc(&total_threads); - /* Wait for the thread to start */ - wait_for_completion(&(us->notify)); + /* Take a reference to the host for the control thread and + * count it among all the threads we have launched. Then + * start it up. */ + scsi_host_get(us_to_host(us)); + atomic_inc(&total_threads); + wake_up_process(th); return 0; } @@ -890,21 +879,6 @@ static int usb_stor_scan_thread(void * __us) { struct us_data *us = (struct us_data *)__us; - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources. - */ - lock_kernel(); - daemonize("usb-stor-scan"); - unlock_kernel(); - - /* Acquire a reference to the host, so it won't be deallocated - * until we're ready to exit */ - scsi_host_get(us_to_host(us)); - - /* Signal that we've started the thread */ - complete(&(us->notify)); - printk(KERN_DEBUG "usb-storage: device found at %d\n", us->pusb_dev->devnum); @@ -949,6 +923,7 @@ static int storage_probe(struct usb_interface *intf, struct us_data *us; const int id_index = id - storage_usb_ids; int result; + struct task_struct *th; US_DEBUGP("USB Mass Storage device detected\n"); @@ -1029,17 +1004,21 @@ static int storage_probe(struct usb_interface *intf, } /* Start up the thread for delayed SCSI-device scanning */ - result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM); - if (result < 0) { + th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); + if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start the device-scanning thread\n"); quiesce_and_remove_host(us); + result = PTR_ERR(th); goto BadDevice; } - atomic_inc(&total_threads); - /* Wait for the thread to start */ - wait_for_completion(&(us->notify)); + /* Take a reference to the host for the scanning thread and + * count it among all the threads we have launched. Then + * start it up. */ + scsi_host_get(us_to_host(us)); + atomic_inc(&total_threads); + wake_up_process(th); return 0; diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index dfa4dc71dd3e..98b09711a739 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -161,9 +161,6 @@ struct us_data { struct scsi_cmnd *srb; /* current srb */ unsigned int tag; /* current dCBWTag */ - /* thread information */ - int pid; /* control thread */ - /* control and bulk communications data */ struct urb *current_urb; /* USB requests */ struct usb_ctrlrequest *cr; /* control requests */ From 72129cd6577793408ff546b0ddd5794c33f32399 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 25 Oct 2005 23:34:03 +0400 Subject: [PATCH 1199/1939] [PATCH] mdc800: remove embrions of C++ exceptions Signed-off-by: Alexey Dobriyan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/mdc800.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index e4ec133ee74a..1d973bcf56aa 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -975,13 +975,13 @@ static struct usb_driver mdc800_usb_driver = Init and Cleanup this driver (Main Functions) *************************************************************************/ -#define try(A) if (!(A)) goto cleanup_on_fail; - static int __init usb_mdc800_init (void) { int retval = -ENODEV; /* Allocate Memory */ - try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); + mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL); + if (!mdc800) + goto cleanup_on_fail; memset(mdc800, 0, sizeof(struct mdc800_data)); mdc800->dev = NULL; @@ -997,13 +997,25 @@ static int __init usb_mdc800_init (void) mdc800->downloaded = 0; mdc800->written = 0; - try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL)); - try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL)); - try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL)); + mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL); + if (!mdc800->irq_urb_buffer) + goto cleanup_on_fail; + mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL); + if (!mdc800->write_urb_buffer) + goto cleanup_on_fail; + mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL); + if (!mdc800->download_urb_buffer) + goto cleanup_on_fail; - try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL)); - try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL)); - try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL)); + mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->irq_urb) + goto cleanup_on_fail; + mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->download_urb) + goto cleanup_on_fail; + mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->write_urb) + goto cleanup_on_fail; /* Register the driver */ retval = usb_register(&mdc800_usb_driver); From e52783206ada0c0276c8dd74c0ecd0007ead7c00 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sun, 23 Oct 2005 23:52:39 -0700 Subject: [PATCH 1200/1939] [PATCH] USB Storage: Expand range of Freecom unusual_devs entry Freecom seems to be one of those vendors that can't get the GET CAPACITY thing right. This expands the US_FL_FIX_CAPACITY flag for the entire range of their fccd product line. This is based on a patch sent by Stuart Black . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d0f6a7e2fe31..9e926a8f2116 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -756,7 +756,7 @@ UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, #endif /* Reported by Eero Volotinen */ -UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0406, 0x0406, +UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999, "Freecom Technologies", "FHD-Classic", US_SC_DEVICE, US_PR_DEVICE, NULL, From be69e5b1900a19a545becda822b18d6f09168ba5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 25 Oct 2005 15:56:06 -0400 Subject: [PATCH 1201/1939] [PATCH] usbcore: Improve endpoint sysfs file handling This revised patch (as587b) improves the implementation of USB endpoint sysfs files. Instead of storing a whole bunch of attributes for every single endpoint, each endpoint now gets its own kobject and they can share a static list of attributes. The number of extra fields added to struct usb_host_endpoint has been reduced from 4 to 1. The bEndpointAddress field is retained even though it is redundant (it repeats the same information as the attributes' directory name). The code avoids calling kobject_register, to prevent generating unwanted hotplug events. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 227 ++++++++++++++++++++++----------------- include/linux/usb.h | 5 +- 2 files changed, 129 insertions(+), 103 deletions(-) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4bdbc9df6e03..f18317fb49ee 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -23,43 +23,56 @@ #include "usb.h" /* endpoint stuff */ -struct endpoint_attribute { - struct device_attribute dev_attr; - struct usb_endpoint_descriptor *endpoint; +struct ep_object { + struct usb_endpoint_descriptor *desc; struct usb_device *udev; + struct kobject kobj; }; -#define to_endpoint_attr(_dev_attr) \ - container_of(_dev_attr, struct endpoint_attribute, dev_attr) +#define to_ep_object(_kobj) \ + container_of(_kobj, struct ep_object, kobj) + +struct ep_attribute { + struct attribute attr; + ssize_t (*show)(struct usb_device *, + struct usb_endpoint_descriptor *, char *); +}; +#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) \ +{ \ + return sprintf(buf, format_string, desc->field); \ +} \ +static EP_ATTR(field); -#define usb_ep_attr(field, format_string) \ -static ssize_t show_ep_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); \ - \ - return sprintf(buf, format_string, endpoint_attr->endpoint->field); \ -} usb_ep_attr(bLength, "%02x\n") -usb_ep_attr(bDescriptorType, "%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 device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) { - struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); - return sprintf(buf, "%04x\n", - le16_to_cpu(endpoint_attr->endpoint->wMaxPacketSize) & 0x07ff); + le16_to_cpu(desc->wMaxPacketSize) & 0x07ff); } +static EP_ATTR(wMaxPacketSize); -static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_ep_type(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) { - struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); char *type = "unknown"; - switch (endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_CONTROL: type = "Control"; break; @@ -75,35 +88,34 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, c } return sprintf(buf, "%s\n", type); } +static EP_ATTR(type); -static ssize_t show_ep_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_ep_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) { - struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); - struct usb_device *udev = endpoint_attr->udev; - struct usb_endpoint_descriptor *endpoint = endpoint_attr->endpoint; char unit; unsigned interval = 0; unsigned in; - in = (endpoint->bEndpointAddress & USB_DIR_IN); + in = (desc->bEndpointAddress & USB_DIR_IN); - switch (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_CONTROL: if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ - interval = endpoint->bInterval; + interval = desc->bInterval; break; case USB_ENDPOINT_XFER_ISOC: - interval = 1 << (endpoint->bInterval - 1); + interval = 1 << (desc->bInterval - 1); break; case USB_ENDPOINT_XFER_BULK: - if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ - interval = endpoint->bInterval; + if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + interval = desc->bInterval; break; case USB_ENDPOINT_XFER_INT: - if (udev->speed == USB_SPEED_HIGH) { - interval = 1 << (endpoint->bInterval - 1); - } else - interval = endpoint->bInterval; + if (udev->speed == USB_SPEED_HIGH) + interval = 1 << (desc->bInterval - 1); + else + interval = desc->bInterval; break; } interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; @@ -116,78 +128,95 @@ static ssize_t show_ep_interval(struct device *dev, struct device_attribute *att return sprintf(buf, "%d%cs\n", interval, unit); } +static EP_ATTR(interval); -static ssize_t show_ep_direction(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_ep_direction(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) { - struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); char *direction; - if ((endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL) + if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) direction = "both"; - else if (endpoint_attr->endpoint->bEndpointAddress & USB_DIR_IN) + else if (desc->bEndpointAddress & USB_DIR_IN) direction = "in"; else direction = "out"; return sprintf(buf, "%s\n", direction); } +static EP_ATTR(direction); -static struct endpoint_attribute *create_ep_attr(struct usb_endpoint_descriptor *endpoint, - struct usb_device *udev, char *name, - ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf)) +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, + NULL, +}; + +static void ep_object_release(struct kobject *kobj) { - struct endpoint_attribute *ep_attr; + kfree(to_ep_object(kobj)); +} - ep_attr = kzalloc(sizeof(*ep_attr), GFP_KERNEL); - if (ep_attr) { - ep_attr->endpoint = endpoint; - ep_attr->udev = udev; - ep_attr->dev_attr.attr.name = name; - ep_attr->dev_attr.attr.mode = 0444; - ep_attr->dev_attr.attr.owner = THIS_MODULE; - ep_attr->dev_attr.show = show; +static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct ep_object *ep_obj = to_ep_object(kobj); + struct ep_attribute *ep_attr = to_ep_attribute(attr); + + return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf); +} + +static struct sysfs_ops ep_object_sysfs_ops = { + .show = ep_object_show, +}; + +static struct kobj_type ep_object_ktype = { + .release = ep_object_release, + .sysfs_ops = &ep_object_sysfs_ops, + .default_attrs = ep_attrs, +}; + +static void usb_create_ep_files(struct kobject *parent, + struct usb_host_endpoint *endpoint, + struct usb_device *udev) +{ + struct ep_object *ep_obj; + struct kobject *kobj; + + ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL); + if (!ep_obj) + return; + + ep_obj->desc = &endpoint->desc; + ep_obj->udev = udev; + + kobj = &ep_obj->kobj; + kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress); + kobj->parent = parent; + kobj->ktype = &ep_object_ktype; + + /* 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); +} + +static void usb_remove_ep_files(struct usb_host_endpoint *endpoint) +{ + + if (endpoint->kobj) { + kobject_del(endpoint->kobj); + kobject_put(endpoint->kobj); + endpoint->kobj = NULL; } - return ep_attr; -} - -static void usb_create_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint, struct usb_device *udev) -{ - struct usb_endpoint_descriptor *ep; - - ep = &endpoint->desc; - - endpoint->attrs = kzalloc(sizeof(struct attribute *) * 10, GFP_KERNEL); - endpoint->attrs[0] = &(create_ep_attr(ep, udev, "direction", show_ep_direction)->dev_attr.attr); - endpoint->attrs[1] = &(create_ep_attr(ep, udev, "type", show_ep_type)->dev_attr.attr); - endpoint->attrs[2] = &(create_ep_attr(ep, udev, "bLength", show_ep_bLength)->dev_attr.attr); - endpoint->attrs[3] = &(create_ep_attr(ep, udev, "bDescriptorType", show_ep_bDescriptorType)->dev_attr.attr); - endpoint->attrs[4] = &(create_ep_attr(ep, udev, "bEndpointAddress", show_ep_bEndpointAddress)->dev_attr.attr); - endpoint->attrs[5] = &(create_ep_attr(ep, udev, "bmAttributes", show_ep_bmAttributes)->dev_attr.attr); - endpoint->attrs[6] = &(create_ep_attr(ep, udev, "wMaxPacketSize", show_ep_wMaxPacketSize)->dev_attr.attr); - endpoint->attrs[7] = &(create_ep_attr(ep, udev, "bInterval", show_ep_bInterval)->dev_attr.attr); - endpoint->attrs[8] = &(create_ep_attr(ep, udev, "interval", show_ep_interval)->dev_attr.attr); - endpoint->attrs[9] = NULL; - endpoint->num_attrs = 9; - - endpoint->attr_group = kzalloc(sizeof(*endpoint->attr_group), GFP_KERNEL); - endpoint->attr_name = kzalloc(10, GFP_KERNEL); - sprintf(endpoint->attr_name, "ep_%02x", endpoint->desc.bEndpointAddress); - - endpoint->attr_group->attrs = endpoint->attrs; - endpoint->attr_group->name = endpoint->attr_name; - sysfs_create_group(kobj, endpoint->attr_group); -} - -static void usb_remove_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint) -{ - int i; - - sysfs_remove_group(kobj, endpoint->attr_group); - kfree(endpoint->attr_group); - kfree(endpoint->attr_name); - for (i = 0; i < endpoint->num_attrs; ++i) - kfree(endpoint->attrs[i]); - kfree(endpoint->attrs); } /* Active configuration fields */ @@ -411,7 +440,7 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) { struct device *dev = &udev->dev; - usb_remove_ep_files(&dev->kobj, &udev->ep0); + usb_remove_ep_files(&udev->ep0); sysfs_remove_group(&dev->kobj, &dev_attr_grp); if (udev->descriptor.iManufacturer) @@ -496,7 +525,7 @@ static struct attribute_group intf_attr_grp = { .attrs = intf_attrs, }; -static void usb_create_intf_ep_files(struct usb_interface *intf) +static inline void usb_create_intf_ep_files(struct usb_interface *intf) { struct usb_host_interface *iface_desc; int i; @@ -504,17 +533,17 @@ static void usb_create_intf_ep_files(struct usb_interface *intf) iface_desc = intf->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], - interface_to_usbdev(intf)); + interface_to_usbdev(intf)); } -static void usb_remove_intf_ep_files(struct usb_interface *intf) +static inline void usb_remove_intf_ep_files(struct usb_interface *intf) { struct usb_host_interface *iface_desc; int i; iface_desc = intf->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) - usb_remove_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i]); + usb_remove_ep_files(&iface_desc->endpoint[i]); } void usb_create_sysfs_intf_files (struct usb_interface *intf) diff --git a/include/linux/usb.h b/include/linux/usb.h index a2d923fd54f9..465ff4585ca5 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -57,10 +57,7 @@ struct usb_host_endpoint { struct usb_endpoint_descriptor desc; struct list_head urb_list; void *hcpriv; - char *attr_name; - struct attribute_group *attr_group; - struct attribute **attrs; - int num_attrs; + struct kobject *kobj; /* For sysfs info */ unsigned char *extra; /* Extra descriptors */ int extralen; From 0e6c8e8db508fcb292836b23d039649c5de29090 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 24 Oct 2005 15:33:03 -0400 Subject: [PATCH 1202/1939] [PATCH] usbcore: endpoint attributes track altsetting changes This patch (as588) fixes the way endpoint attribute files are registered and unregistered. Now they will correctly track along with altsetting changes. This fixes bugzilla entry #5467. In a separate but related change, when a usb_reset_configuration call fails, the device state is not changed to USB_STATE_ADDRESS. In the first place, failure means that we don't know what the state is, not that we know the device is unconfigured. In the second place, doing this can potentially lead to a memory leak, since usbcore might not realize there still is a current configuration that needs to be destroyed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 574d0d4b3401..5ad0d5e28119 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1149,6 +1149,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ + if (device_is_registered(&iface->dev)) + usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); iface->cur_altsetting = alt; @@ -1184,6 +1186,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); + if (device_is_registered(&iface->dev)) + usb_create_sysfs_intf_files(iface); return 0; } @@ -1233,10 +1237,8 @@ int usb_reset_configuration(struct usb_device *dev) USB_REQ_SET_CONFIGURATION, 0, config->desc.bConfigurationValue, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (retval < 0) { - usb_set_device_state(dev, USB_STATE_ADDRESS); + if (retval < 0) return retval; - } dev->toggle[0] = dev->toggle[1] = 0; @@ -1245,6 +1247,8 @@ int usb_reset_configuration(struct usb_device *dev) struct usb_interface *intf = config->interface[i]; struct usb_host_interface *alt; + if (device_is_registered(&intf->dev)) + usb_remove_sysfs_intf_files(intf); alt = usb_altnum_to_altsetting(intf, 0); /* No altsetting 0? We'll assume the first altsetting. @@ -1257,6 +1261,8 @@ int usb_reset_configuration(struct usb_device *dev) intf->cur_altsetting = alt; usb_enable_interface(dev, intf); + if (device_is_registered(&intf->dev)) + usb_create_sysfs_intf_files(intf); } return 0; } From b724ae77969fd832be71419dca74bece9af287ff Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 24 Oct 2005 15:36:00 -0400 Subject: [PATCH 1203/1939] [PATCH] usbcore: Wrap lines before column 80 I can't stand text lines that wrap-around in my 80-column windows. This patch (as589) makes cosmetic changes to a couple of source files. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 30 ++++++--- include/linux/usb.h | 132 +++++++++++++++++++++++++-------------- 2 files changed, 106 insertions(+), 56 deletions(-) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index f18317fb49ee..4cca77cf0c48 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -221,7 +221,8 @@ static void usb_remove_ep_files(struct usb_host_endpoint *endpoint) /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##field (struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ @@ -243,7 +244,8 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") -static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_configuration_string(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; @@ -266,7 +268,8 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +set_bConfigurationValue (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = udev = to_usb_device (dev); int config, value; @@ -284,7 +287,8 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, /* String fields */ #define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ int len; \ @@ -364,7 +368,8 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_device *udev; \ \ @@ -380,7 +385,8 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_device *udev; \ \ @@ -455,11 +461,13 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_interface *intf = to_usb_interface (dev); \ \ - return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ + return sprintf (buf, format_string, \ + intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); @@ -470,7 +478,8 @@ usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") -static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_interface_string(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; @@ -487,7 +496,8 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute } static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); -static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_modalias(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; diff --git a/include/linux/usb.h b/include/linux/usb.h index 465ff4585ca5..c500d6b5a16d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -137,7 +137,8 @@ struct usb_interface { * active alternate setting */ unsigned num_altsetting; /* number of alternate settings */ - int minor; /* minor number this interface is bound to */ + int minor; /* minor number this interface is + * bound to */ enum usb_interface_condition condition; /* state of binding */ struct device dev; /* interface specific device info */ struct class_device *class_dev; @@ -249,7 +250,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\ type,(void**)ptr) -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ struct usb_operations; @@ -269,7 +270,8 @@ struct usb_bus { unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ - int devnum_next; /* Next open device number in round-robin allocation */ + int devnum_next; /* Next open device number in + * round-robin allocation */ struct usb_devmap devmap; /* device address allocation map */ struct usb_operations *op; /* Operations (specific to the HC) */ @@ -290,15 +292,16 @@ struct usb_bus { struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ struct class_device *class_dev; /* class device for this bus */ - struct kref kref; /* handles reference counting this bus */ - void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */ + struct kref kref; /* reference counting for this bus */ + void (*release)(struct usb_bus *bus); + #if defined(CONFIG_USB_MON) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif }; -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /* This is arbitrary. * From USB 2.0 spec Table 11-13, offset 7, a hub can @@ -327,7 +330,8 @@ struct usb_device { struct semaphore serialize; - unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ + unsigned int toggle[2]; /* one bit for each endpoint + * ([0] = IN, [1] = OUT) */ struct usb_device *parent; /* our hub, unless we're the root */ struct usb_bus *bus; /* Bus we're part of */ @@ -344,7 +348,7 @@ struct usb_device { char **rawdescriptors; /* Raw descriptors for each config */ - int have_langid; /* whether string_langid is valid yet */ + int have_langid; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ char *product; @@ -441,22 +445,31 @@ extern struct usb_host_interface *usb_altnum_to_altsetting( * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are * high speed, and a different one if they are full or low speed. */ -static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) +static inline int usb_make_path (struct usb_device *dev, char *buf, + size_t size) { int actual; - actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath); + actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, + dev->devpath); return (actual >= (int)size) ? -1 : actual; } /*-------------------------------------------------------------------------*/ -#define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) -#define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) -#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) +#define USB_DEVICE_ID_MATCH_DEVICE \ + (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) +#define USB_DEVICE_ID_MATCH_DEV_RANGE \ + (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) +#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION \ + (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) #define USB_DEVICE_ID_MATCH_DEV_INFO \ - (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL) + (USB_DEVICE_ID_MATCH_DEV_CLASS | \ + USB_DEVICE_ID_MATCH_DEV_SUBCLASS | \ + USB_DEVICE_ID_MATCH_DEV_PROTOCOL) #define USB_DEVICE_ID_MATCH_INT_INFO \ - (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL) + (USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_SUBCLASS | \ + USB_DEVICE_ID_MATCH_INT_PROTOCOL) /** * USB_DEVICE - macro used to describe a specific usb device @@ -467,9 +480,11 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * specific device. */ #define USB_DEVICE(vend,prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod) + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \ + .idProduct = (prod) /** - * USB_DEVICE_VER - macro used to describe a specific usb device with a version range + * USB_DEVICE_VER - macro used to describe a specific usb device with a + * version range * @vend: the 16 bit USB Vendor ID * @prod: the 16 bit USB Product ID * @lo: the bcdDevice_lo value @@ -479,7 +494,9 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * specific device, with a version range. */ #define USB_DEVICE_VER(vend,prod,lo,hi) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \ + .idVendor = (vend), .idProduct = (prod), \ + .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) /** * USB_DEVICE_INFO - macro used to describe a class of usb devices @@ -491,7 +508,8 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * specific class of devices. */ #define USB_DEVICE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) + .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \ + .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) /** * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces @@ -503,9 +521,10 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * specific class of interfaces. */ #define USB_INTERFACE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /** * struct usb_driver - identifies USB driver to usbcore @@ -558,7 +577,8 @@ struct usb_driver { void (*disconnect) (struct usb_interface *intf); - int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); + int (*ioctl) (struct usb_interface *intf, unsigned int code, + void *buf); int (*suspend) (struct usb_interface *intf, pm_message_t message); int (*resume) (struct usb_interface *intf); @@ -601,7 +621,7 @@ extern void usb_deregister_dev(struct usb_interface *intf, extern int usb_disabled(void); -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /* * URB support, for asynchronous request completions @@ -611,12 +631,14 @@ extern int usb_disabled(void); * urb->transfer_flags: */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ -#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ +#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame + * ignored */ #define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ #define URB_NO_SETUP_DMA_MAP 0x0008 /* urb->setup_dma valid on submit */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */ -#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ -#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ +#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */ +#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt + * needed */ struct usb_iso_packet_descriptor { unsigned int offset; @@ -804,7 +826,8 @@ struct urb u8 reject; /* submissions will fail */ /* public, documented fields in the urb that can be used by drivers */ - struct list_head urb_list; /* list head for use by the urb owner */ + struct list_head urb_list; /* list head for use by the urb's + * current owner */ struct usb_device *dev; /* (in) pointer to associated device */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ @@ -817,14 +840,16 @@ struct urb dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ int start_frame; /* (modify) start frame (ISO) */ int number_of_packets; /* (in) number of ISO packets */ - int interval; /* (modify) transfer interval (INT/ISO) */ + int interval; /* (modify) transfer interval + * (INT/ISO) */ int error_count; /* (return) number of ISO errors */ void *context; /* (in) context for completion */ usb_complete_t complete; /* (in) completion routine */ - struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ + struct usb_iso_packet_descriptor iso_frame_desc[0]; + /* (in) ISO ONLY */ }; -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /** * usb_fill_control_urb - initializes a control urb @@ -1049,7 +1074,7 @@ void usb_sg_cancel (struct usb_sg_request *io); void usb_sg_wait (struct usb_sg_request *io); -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /* * For various legacy reasons, Linux has a small cookie that's paired with @@ -1090,23 +1115,34 @@ void usb_sg_wait (struct usb_sg_request *io); /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) #define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) -#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep))) +#define usb_settoggle(dev, ep, out, bit) \ + ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ + ((bit) << (ep))) -static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) +static inline unsigned int __create_pipe(struct usb_device *dev, + unsigned int endpoint) { return (dev->devnum << 8) | (endpoint << 15); } /* Create various pipes... */ -#define usb_sndctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndctrlpipe(dev,endpoint) \ + ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvctrlpipe(dev,endpoint) \ + ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndisocpipe(dev,endpoint) \ + ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvisocpipe(dev,endpoint) \ + ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndbulkpipe(dev,endpoint) \ + ((PIPE_BULK << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvbulkpipe(dev,endpoint) \ + ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndintpipe(dev,endpoint) \ + ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvintpipe(dev,endpoint) \ + ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) /*-------------------------------------------------------------------------*/ @@ -1130,7 +1166,7 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out) return le16_to_cpu(ep->desc.wMaxPacketSize); } -/* -------------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ /* Events from the usb core */ #define USB_DEVICE_ADD 0x0001 @@ -1141,14 +1177,18 @@ extern void usb_register_notify(struct notifier_block *nb); extern void usb_unregister_notify(struct notifier_block *nb); #ifdef DEBUG -#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg) +#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \ + __FILE__ , ## arg) #else #define dbg(format, arg...) do {} while (0) #endif -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ + __FILE__ , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , \ + __FILE__ , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , \ + __FILE__ , ## arg) #endif /* __KERNEL__ */ From 0a1ef3b5a765a6f20e7b8caf295aad3276243966 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 24 Oct 2005 15:38:24 -0400 Subject: [PATCH 1204/1939] [PATCH] usbcore: Use kzalloc instead of kmalloc/memset This patch (as590) fixes up all the remaining places where usbcore can use kzalloc rather than kmalloc/memset. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 12 ++++-------- drivers/usb/core/devio.c | 4 ++-- drivers/usb/core/hcd.c | 3 +-- drivers/usb/core/hub.c | 4 +--- drivers/usb/core/message.c | 3 +-- drivers/usb/core/usb.c | 4 +--- 6 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 99595e07b653..63f374e62db2 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -188,10 +188,9 @@ static int usb_parse_interface(struct device *ddev, int cfgno, } len = sizeof(struct usb_host_endpoint) * num_ep; - alt->endpoint = kmalloc(len, GFP_KERNEL); + alt->endpoint = kzalloc(len, GFP_KERNEL); if (!alt->endpoint) return -ENOMEM; - memset(alt->endpoint, 0, len); /* Parse all the endpoint descriptors */ n = 0; @@ -353,10 +352,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, } len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kmalloc(len, GFP_KERNEL); + config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); if (!intfc) return -ENOMEM; - memset(intfc, 0, len); kref_init(&intfc->ref); } @@ -459,16 +457,14 @@ int usb_get_configuration(struct usb_device *dev) } length = ncfg * sizeof(struct usb_host_config); - dev->config = kmalloc(length, GFP_KERNEL); + dev->config = kzalloc(length, GFP_KERNEL); if (!dev->config) goto err2; - memset(dev->config, 0, length); length = ncfg * sizeof(char *); - dev->rawdescriptors = kmalloc(length, GFP_KERNEL); + dev->rawdescriptors = kzalloc(length, GFP_KERNEL); if (!dev->rawdescriptors) goto err2; - memset(dev->rawdescriptors, 0, length); buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); if (!buffer) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ffb2e242b100..942cd437dc48 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -210,10 +210,10 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l static struct async *alloc_async(unsigned int numisoframes) { unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); - struct async *as = kmalloc(assize, GFP_KERNEL); + struct async *as = kzalloc(assize, GFP_KERNEL); + if (!as) return NULL; - memset(as, 0, assize); as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); if (!as->urb) { kfree(as); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e8f2b8d8f14d..61ef9943757e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -744,10 +744,9 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) { struct usb_bus *bus; - bus = kmalloc (sizeof *bus, GFP_KERNEL); + bus = kzalloc (sizeof *bus, GFP_KERNEL); if (!bus) return NULL; - memset(bus, 0, sizeof(struct usb_bus)); usb_bus_init (bus); bus->op = op; return bus; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6a2ebd89916f..8ba5854e5387 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -865,14 +865,12 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) /* We found a hub */ dev_info (&intf->dev, "USB hub found\n"); - hub = kmalloc(sizeof(*hub), GFP_KERNEL); + hub = kzalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); return -ENOMEM; } - memset(hub, 0, sizeof(*hub)); - INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; hub->hdev = hdev; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5ad0d5e28119..3519f317898e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1350,7 +1350,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } for (; n < nintf; ++n) { - new_interfaces[n] = kmalloc( + new_interfaces[n] = kzalloc( sizeof(struct usb_interface), GFP_KERNEL); if (!new_interfaces[n]) { @@ -1391,7 +1391,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_host_interface *alt; cp->interface[i] = intf = new_interfaces[i]; - memset(intf, 0, sizeof(*intf)); intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4eca4904938f..0eefff7bcb3c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -704,12 +704,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - memset(dev, 0, sizeof(*dev)); - bus = usb_bus_get(bus); if (!bus) { kfree(dev); From 16f16d117c1eb99451e4c73c87546eef05c66790 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 24 Oct 2005 15:41:19 -0400 Subject: [PATCH 1205/1939] [PATCH] USB: Fix maxpacket length for ep0 on root hubs This patch (as591) fixes a rather innocuous bug that has been around for quite a long time: Virtual root hubs should have a maxpacket length of 64 for endpoint 0. I didn't realize it was wrong until I started looking through the endpoint attribute files. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 61ef9943757e..6c7ca5b08cd6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -130,7 +130,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idProduct; */ @@ -153,7 +153,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idProduct; */ From 4f62efe67f077db17dad03a1d4c9665000a3eb45 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 24 Oct 2005 16:24:14 -0400 Subject: [PATCH 1206/1939] [PATCH] usbcore: Fix handling of sysfs strings and other attributes This patch (as592) makes a few small improvements to the way device strings are handled, and it fixes some bugs in a couple of other sysfs attribute routines. (Look at show_configuration_string() to see what I mean.) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 10 ++++---- drivers/usb/core/hub.c | 22 ++++------------- drivers/usb/core/message.c | 48 ++++++++++++++++++++++++-------------- drivers/usb/core/sysfs.c | 36 ++++++++++++---------------- drivers/usb/core/usb.h | 1 + include/linux/usb.h | 10 ++++---- 6 files changed, 62 insertions(+), 65 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 63f374e62db2..993019500cc3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref) struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); int j; - for (j = 0; j < intfc->num_altsetting; j++) - kfree(intfc->altsetting[j].endpoint); + for (j = 0; j < intfc->num_altsetting; j++) { + struct usb_host_interface *alt = &intfc->altsetting[j]; + + kfree(alt->endpoint); + kfree(alt->string); + } kfree(intfc); } @@ -420,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev) struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - cf->string = NULL; - for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8ba5854e5387..1bacb374b007 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1204,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) {} #endif -static void get_string(struct usb_device *udev, char **string, int index) -{ - char *buf; - - if (!index) - return; - buf = kmalloc(256, GFP_KERNEL); - if (!buf) - return; - if (usb_string(udev, index, buf, 256) > 0) - *string = buf; - else - kfree(buf); -} - #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" @@ -1257,9 +1242,10 @@ int usb_new_device(struct usb_device *udev) } /* read the standard strings and cache them if present */ - get_string(udev, &udev->product, udev->descriptor.iProduct); - get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer); - get_string(udev, &udev->serial, udev->descriptor.iSerialNumber); + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); /* Tell the world! */ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3519f317898e..644a3d4f12aa 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -787,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) return err; } +/** + * usb_cache_string - read a string descriptor and cache it for later use + * @udev: the device whose string descriptor is being read + * @index: the descriptor index + * + * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, + * or NULL if the index is 0 or the string could not be read. + */ +char *usb_cache_string(struct usb_device *udev, int index) +{ + char *buf; + char *smallbuf = NULL; + int len; + + if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) { + if ((len = usb_string(udev, index, buf, 256)) > 0) { + if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL) + return buf; + memcpy(smallbuf, buf, len); + } + kfree(buf); + } + return smallbuf; +} + /* * usb_get_device_descriptor - (re)reads the device descriptor (usbcore) * @dev: the device whose device descriptor is being updated @@ -1008,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); - kfree(interface->cur_altsetting->string); - interface->cur_altsetting->string = NULL; device_del (&interface->dev); } @@ -1422,12 +1445,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } kfree(new_interfaces); - if ((cp->desc.iConfiguration) && - (cp->string == NULL)) { - cp->string = kmalloc(256, GFP_KERNEL); - if (cp->string) - usb_string(dev, cp->desc.iConfiguration, cp->string, 256); - } + if (cp->string == NULL) + cp->string = usb_cache_string(dev, + cp->desc.iConfiguration); /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() @@ -1437,13 +1457,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration) */ for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; - struct usb_interface_descriptor *desc; + struct usb_host_interface *alt = intf->cur_altsetting; - desc = &intf->altsetting [0].desc; dev_dbg (&dev->dev, "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - desc->bInterfaceNumber); + alt->desc.bInterfaceNumber); ret = device_add (&intf->dev); if (ret != 0) { dev_err(&dev->dev, @@ -1452,13 +1471,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ret); continue; } - if ((intf->cur_altsetting->desc.iInterface) && - (intf->cur_altsetting->string == NULL)) { - intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL); - if (intf->cur_altsetting->string) - usb_string(dev, intf->cur_altsetting->desc.iInterface, - intf->cur_altsetting->string, 256); - } usb_create_sysfs_intf_files (intf); } } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4cca77cf0c48..edd83e014452 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -249,18 +249,12 @@ static ssize_t show_configuration_string(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; - int len; udev = to_usb_device (dev); actconfig = udev->actconfig; if ((!actconfig) || (!actconfig->string)) return 0; - len = sprintf(buf, actconfig->string, PAGE_SIZE); - if (len < 0) - return 0; - buf[len] = '\n'; - buf[len+1] = 0; - return len+1; + return sprintf(buf, "%s\n", actconfig->string); } static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); @@ -291,15 +285,9 @@ static ssize_t show_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ - int len; \ \ udev = to_usb_device (dev); \ - len = snprintf(buf, 256, "%s", udev->name); \ - if (len < 0) \ - return 0; \ - buf[len] = '\n'; \ - buf[len+1] = 0; \ - return len+1; \ + return sprintf(buf, "%s\n", udev->name); \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -449,11 +437,11 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) usb_remove_ep_files(&udev->ep0); sysfs_remove_group(&dev->kobj, &dev_attr_grp); - if (udev->descriptor.iManufacturer) + if (udev->manufacturer) device_remove_file(dev, &dev_attr_manufacturer); - if (udev->descriptor.iProduct) + if (udev->product) device_remove_file(dev, &dev_attr_product); - if (udev->descriptor.iSerialNumber) + if (udev->serial) device_remove_file(dev, &dev_attr_serial); device_remove_file (dev, &dev_attr_configuration); } @@ -535,7 +523,8 @@ static struct attribute_group intf_attr_grp = { .attrs = intf_attrs, }; -static inline void usb_create_intf_ep_files(struct usb_interface *intf) +static inline void usb_create_intf_ep_files(struct usb_interface *intf, + struct usb_device *udev) { struct usb_host_interface *iface_desc; int i; @@ -543,7 +532,7 @@ static inline void usb_create_intf_ep_files(struct usb_interface *intf) iface_desc = intf->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], - interface_to_usbdev(intf)); + udev); } static inline void usb_remove_intf_ep_files(struct usb_interface *intf) @@ -558,11 +547,16 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf) void usb_create_sysfs_intf_files (struct usb_interface *intf) { + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *alt = intf->cur_altsetting; + sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); - if (intf->cur_altsetting->string) + if (alt->string == NULL) + alt->string = usb_cache_string(udev, alt->desc.iInterface); + if (alt->string) device_create_file(&intf->dev, &dev_attr_interface); - usb_create_intf_ep_files(intf); + usb_create_intf_ep_files(intf, udev); } void usb_remove_sysfs_intf_files (struct usb_interface *intf) diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 888dbe443695..1c4a68499dce 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -13,6 +13,7 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_lock_all_devices(void); diff --git a/include/linux/usb.h b/include/linux/usb.h index c500d6b5a16d..748d04385256 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -231,7 +231,7 @@ struct usb_interface_cache { struct usb_host_config { struct usb_config_descriptor desc; - char *string; + char *string; /* iConfiguration string, if present */ /* the interfaces associated with this configuration, * stored in no particular order */ struct usb_interface *interface[USB_MAXINTERFACES]; @@ -351,9 +351,11 @@ struct usb_device { int have_langid; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ - char *product; - char *manufacturer; - char *serial; /* static strings from the device */ + /* static strings from the device */ + char *product; /* iProduct string, if present */ + char *manufacturer; /* iManufacturer string, if present */ + char *serial; /* iSerialNumber string, if present */ + struct list_head filelist; struct class_device *class_dev; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ From db2d55b7f7f11823b8d2e5f0c706c7a264320d1b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 23 Oct 2005 23:04:25 -0700 Subject: [PATCH 1207/1939] [PATCH] USB: fix pm patches with CONFIG_PM off part 1 With CONFIG_PM=n: drivers/built-in.o(.text+0x2a69c): In function `ohci_hub_control': drivers/usb/host/ohci-hub.c:539: undefined reference to `.usb_hcd_resume_root_hub' drivers/built-in.o(.text+0x2b920): In function `ohci_irq': drivers/usb/host/ohci-hcd.c:726: undefined reference to `.usb_hcd_resume_root_hub' Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index a5d92943ff95..24a62a2ff86d 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -351,9 +351,6 @@ extern long usb_calc_bus_time (int speed, int is_input, extern struct usb_bus *usb_alloc_bus (struct usb_operations *); -extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); -extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); - extern void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state); @@ -376,9 +373,21 @@ extern int usb_find_interface_driver (struct usb_device *dev, #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #ifdef CONFIG_PM +extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); +extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern int hcd_bus_suspend (struct usb_bus *bus); extern int hcd_bus_resume (struct usb_bus *bus); #else +static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd) +{ + return; +} + +static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) +{ + return; +} + static inline int hcd_bus_suspend(struct usb_bus *bus) { return 0; From 9a7834d06d553d02cc6e659e94772f69a8b5367f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 23 Oct 2005 23:02:20 -0700 Subject: [PATCH 1208/1939] [PATCH] USB: fix pm patches with CONFIG_PM off part 2 With CONFIG_PM=n: drivers/built-in.o(.text+0x1098c): In function `hub_thread': drivers/usb/core/hub.c:2673: undefined reference to `.dpm_runtime_resume' drivers/built-in.o(.text+0x10998):drivers/usb/core/hub.c:2674: undefined reference to `.dpm_runtime_resume' Please, never ever ever put extern decls into .c files. Use the darn header files :( Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/power.h | 13 ------------- drivers/usb/core/hub.c | 2 -- include/linux/pm.h | 13 +++++++++++++ 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 2e700d795cf1..fb3d35a9e101 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -67,9 +67,6 @@ extern int suspend_device(struct device *, pm_message_t); * runtime.c */ -extern int dpm_runtime_suspend(struct device *, pm_message_t); -extern void dpm_runtime_resume(struct device *); - #else /* CONFIG_PM */ @@ -82,14 +79,4 @@ static inline void device_pm_remove(struct device * dev) } -static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) -{ - return 0; -} - -static inline void dpm_runtime_resume(struct device * dev) -{ - -} - #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1bacb374b007..9660a8909b7c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2652,8 +2652,6 @@ static void hub_events(void) * stub "device" node was never suspended. */ if (i) { - extern void dpm_runtime_resume(struct device *); - dpm_runtime_resume(&hdev->dev); dpm_runtime_resume(&intf->dev); } diff --git a/include/linux/pm.h b/include/linux/pm.h index 83bae1cbe55b..c61d5de837ef 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -243,6 +243,9 @@ extern int device_suspend(pm_message_t state); #define device_may_wakeup(dev) \ (device_can_wakeup(dev) && (dev)->power.should_wakeup) +extern int dpm_runtime_suspend(struct device *, pm_message_t); +extern void dpm_runtime_resume(struct device *); + #else /* !CONFIG_PM */ static inline int device_suspend(pm_message_t state) @@ -253,6 +256,16 @@ static inline int device_suspend(pm_message_t state) #define device_set_wakeup_enable(dev,val) do{}while(0) #define device_may_wakeup(dev) (0) +static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) +{ + return 0; +} + +static inline void dpm_runtime_resume(struct device * dev) +{ + +} + #endif /* changes to device_may_wakeup take effect on the next pm state change. From 46a0cf81828535fb3c200bc4fffdb8d69f4bf396 Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Wed, 26 Oct 2005 19:42:53 +0200 Subject: [PATCH 1209/1939] [PATCH] USB: fix correct wording in drivers/usb/net/KConfig Signed-off-by: Koen Kooi --- drivers/usb/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 8c010bb44eb8..efd6ca7e4ac5 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -294,7 +294,7 @@ config USB_NET_ZAURUS This also supports some related device firmware, as used in some PDAs from Olympus and some cell phones from Motorola. - If you install an alternate ROM image, such as the Linux 2.6 based + If you install an alternate image, such as the Linux 2.6 based versions of OpenZaurus, you should no longer need to support this protocol. Only the "eth-fd" or "net_fd" drivers in these devices really need this non-conformant variant of CDC Ethernet (or in From bde621854f1958a6000834c7c089b528118e5a9a Mon Sep 17 00:00:00 2001 From: Martin Hagelin Date: Wed, 26 Oct 2005 21:10:41 +0200 Subject: [PATCH 1210/1939] [PATCH] USB: add new device id to ftdi_sio module This is a patch to get the ELV FHZ1000 Home Automation control device to work with Linux. The patch adds a new device ID to the ftdi_sio driver. It is for kernel version 2.6.13.4. Signed-off-by: Martin Hagelin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 77d54ac39a0e..61204bf7cd78 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -412,6 +412,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, /* * These will probably use user-space drivers. Uncomment them if * you need them or use the user-specified vendor/product module @@ -429,7 +430,6 @@ static struct usb_device_id id_table_combined [] = { /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */ From 50260b69bbec383058875de26dbde28b1a6f8d00 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 1211/1939] [PATCH] USB: add nokia_dku2 driver This driver comes from the gnokii project. Was further cleaned up by me to match recent usb-serial core changes. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 9 ++ drivers/usb/serial/Makefile | 1 + drivers/usb/serial/nokia_dku2.c | 142 ++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/usb/serial/nokia_dku2.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 9438909e87a5..7b5e8e4ee2bb 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -394,6 +394,15 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_NOKIA_DKU2 + tristate "USB Nokia DKU2 Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Nokia DKU2 device. + + To compile this driver as a module, choose M here: the + module will be called nokia_dku2. + config USB_SERIAL_PL2303 tristate "USB Prolific 2303 Single Port Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 6c7cdcc99a9e..55fd461793b7 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_NOKIA_DKU2) += nokia_dku2.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTION) += option.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o diff --git a/drivers/usb/serial/nokia_dku2.c b/drivers/usb/serial/nokia_dku2.c new file mode 100644 index 000000000000..fad01bef3a64 --- /dev/null +++ b/drivers/usb/serial/nokia_dku2.c @@ -0,0 +1,142 @@ +/* + * Nokia DKU2 USB driver + * + * Copyright (C) 2004 + * Author: C Kemp + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * 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. + * + * 20.09.2005 - Matthias Blaesing + * Added short name to device structure to make driver load into kernel 2.6.13 + * + * 20.09.2005 - Matthias Blaesing + * Added usb_deregister to exit code - to allow remove and reinsert of module + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usb-serial.h" + + +#define NOKIA_VENDOR_ID 0x0421 +#define NOKIA7600_PRODUCT_ID 0x0400 +#define NOKIA6230_PRODUCT_ID 0x040f +#define NOKIA6170_PRODUCT_ID 0x0416 +#define NOKIA6670_PRODUCT_ID 0x041d +#define NOKIA6680_PRODUCT_ID 0x041e +#define NOKIA6230i_PRODUCT_ID 0x0428 + +#define NOKIA_AT_PORT 0x82 +#define NOKIA_FBUS_PORT 0x86 + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.2" +#define DRIVER_AUTHOR "C Kemp" +#define DRIVER_DESC "Nokia DKU2 Driver" + +static struct usb_device_id id_table [] = { + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA7600_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6170_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6670_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6680_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230i_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* The only thing which makes this device different from a generic + * device is that we have to set an alternative configuration to make + * the relevant endpoints available. In 2.6 this is really easy... */ +static int nokia_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + int retval = -ENODEV; + + if (serial->interface->altsetting[0].endpoint[0].desc.bEndpointAddress == NOKIA_AT_PORT) { + /* the AT port */ + dev_info(&serial->dev->dev, "Nokia AT Port:\n"); + retval = 0; + } else if (serial->interface->num_altsetting == 2 && + serial->interface->altsetting[1].endpoint[0].desc.bEndpointAddress == NOKIA_FBUS_PORT) { + /* the FBUS port */ + dev_info(&serial->dev->dev, "Nokia FBUS Port:\n"); + usb_set_interface(serial->dev, 10, 1); + retval = 0; + } + + return retval; +} + +static struct usb_driver nokia_driver = { + .owner = THIS_MODULE, + .name = "nokia_dku2", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_driver nokia_serial_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "nokia_dku2", + }, + .description = "Nokia 7600/6230(i)/6170/66x0 DKU2 driver", + .id_table = id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .probe = nokia_probe, +}; + +static int __init nokia_init(void) +{ + int retval; + + retval = usb_serial_register(&nokia_serial_driver); + if (retval) + return retval; + + retval = usb_register(&nokia_driver); + if (retval) { + usb_serial_deregister(&nokia_serial_driver); + return retval; + } + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + + return retval; +} + +static void __exit nokia_exit(void) +{ + usb_deregister(&nokia_driver); + usb_serial_deregister(&nokia_serial_driver); +} + +module_init(nokia_init); +module_exit(nokia_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); From 4303fc6f055cf1a7ec63c3c3fd777b91b7d576f1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 28 Oct 2005 19:59:31 -0700 Subject: [PATCH 1212/1939] USB: fix up some odd parts due to partial merges Thanks to Andrew for doing the hard work on this. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- drivers/usb/host/ehci-pci.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 9660a8909b7c..256d9f698715 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1674,7 +1674,7 @@ int usb_suspend_device(struct usb_device *udev) return 0; #endif } - +EXPORT_SYMBOL_GPL(usb_suspend_device); /* * If the USB "suspend" state is in use (rather than "global suspend"), diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 7872469ccbb1..145008853966 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -252,7 +252,7 @@ static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) (void) usb_suspend_device (hcd->self.root_hub); #else usb_lock_device (hcd->self.root_hub); - (void) ehci_hub_suspend (hcd); + (void) ehci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); #endif @@ -285,7 +285,7 @@ static int ehci_pci_resume (struct usb_hcd *hcd) continue; if (status & (PORT_SUSPEND | PORT_OWNER)) { down (&hcd->self.root_hub->serialize); - retval = ehci_hub_resume (hcd); + retval = ehci_bus_resume (hcd); up (&hcd->self.root_hub->serialize); break; } From 9e3699ea7b8d63eabde7fefa9892e3a258c9c27d Mon Sep 17 00:00:00 2001 From: Lee Nicks Date: Fri, 28 Oct 2005 17:46:09 -0700 Subject: [PATCH 1213/1939] [PATCH] ppc: prevent GCC 4 from generating AltiVec instructions in kernel Depending on how GCC is built, GCC 4 may generate altivec instructions without user explicitly requesting vector operations in the code. Although this is a performance booster for user applications, it is a problem for kernel. This patch explicitly instruct GCC to NOT generate altivec instructions while building the kernel. Here are some test cases I ran. (1) build gcc 4.0.1 with '--with-cpu=7450 --enable-altivec --enable-cxx-flags=-mcpu=7450', and use this gcc to build kernel WITHOUT this kernel patch. Kernel fail to boot up on a 7450 board because of altivec instructions in kernel. (2) build gcc 4.0.1 with "--with-cpu=7450 --enable-altivec --enable-cxx-flags=-mcpu=7450", and use this gcc to build kernel WITH this kernel patch. Kernel boot up on a 7450 board without any problem. (3) build gcc 4.0.1 with "--with-cpu=750 --enable-cxx-flags=-mcpu=750", and use this gcc to build kernel with or without this kernel patch. Kernel boot up on a 7450 board without any problem. This patch should also work with GCC 3 or even earlier GCC 2.95.3. Signed-off-by: Lee Nicks Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/Makefile | 4 ++++ arch/ppc64/Makefile | 3 +++ 2 files changed, 7 insertions(+) diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 121d2347b89f..94d5716fa7c3 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -26,6 +26,10 @@ CPPFLAGS += -Iarch/$(ARCH) -Iarch/$(ARCH)/include AFLAGS += -Iarch/$(ARCH) CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe \ -ffixed-r2 -mmultiple + +# No AltiVec instruction when building kernel +CFLAGS += $(call cc-option, -mno-altivec) + CPP = $(CC) -E $(CFLAGS) # Temporary hack until we have migrated to asm-powerpc LINUXINCLUDE += -Iarch/$(ARCH)/include diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 743f0dbdebf3..db1b25cdb5be 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -75,6 +75,9 @@ else CFLAGS += $(call cc-option,-mtune=power4) endif +# No AltiVec instruction when building kernel +CFLAGS += $(call cc-option, -mno-altivec) + # Enable unit-at-a-time mode when possible. It shrinks the # kernel considerably. CFLAGS += $(call cc-option,-funit-at-a-time) From e37b0c9670fed2264661ade1beb5c228dec29c96 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 28 Oct 2005 17:46:10 -0700 Subject: [PATCH 1214/1939] [PATCH] ppc32 8xx: use io accessor macros instead of direct memory reference Convert core 8xx drivers to use in_xxxbe/in_xxx macros instead of direct memory references. Other than making IO accesses explicit (which is a plus for readability), a common set of macros provides a unified place for the volatile flag to constraint compiler code reordering. There are several unlucky places at the moment which lack the volatile flag. Signed-off-by: Marcelo Tosatti Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/8xx_io/commproc.c | 20 ++++++++-------- arch/ppc/syslib/m8xx_setup.c | 45 ++++++++++++++++-------------------- arch/ppc/syslib/m8xx_wdt.c | 14 +++++------ arch/ppc/syslib/ppc8xx_pic.c | 17 ++++++-------- 4 files changed, 44 insertions(+), 52 deletions(-) diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 11726e2a4ec8..b42789f8eb76 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -73,7 +73,7 @@ cpm_mask_irq(unsigned int irq) { int cpm_vec = irq - CPM_IRQ_OFFSET; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec); + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) & ~(1 << cpm_vec)); } static void @@ -81,7 +81,7 @@ cpm_unmask_irq(unsigned int irq) { int cpm_vec = irq - CPM_IRQ_OFFSET; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec); + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) | (1 << cpm_vec)); } static void @@ -95,7 +95,7 @@ cpm_eoi(unsigned int irq) { int cpm_vec = irq - CPM_IRQ_OFFSET; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec); + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr, (1 << cpm_vec)); } struct hw_interrupt_type cpm_pic = { @@ -133,7 +133,7 @@ m8xx_cpm_reset(void) * manual recommends it. * Bit 25, FAM can also be set to use FEC aggressive mode (860T). */ - imp->im_siu_conf.sc_sdcr = 1; + out_be32(&imp->im_siu_conf.sc_sdcr, 1), /* Reclaim the DP memory for our use. */ m8xx_cpm_dpinit(); @@ -178,10 +178,10 @@ cpm_interrupt_init(void) /* Initialize the CPM interrupt controller. */ - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | - ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; + ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK); + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, 0); /* install the CPM interrupt controller routines for the CPM * interrupt vectors @@ -198,7 +198,7 @@ cpm_interrupt_init(void) if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction)) panic("Could not allocate CPM error IRQ!"); - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr) | CICR_IEN); } /* @@ -212,8 +212,8 @@ cpm_get_irq(struct pt_regs *regs) /* Get the vector by setting the ACK bit and then reading * the register. */ - ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; - cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; + out_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr, 1); + cpm_vec = in_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr); cpm_vec >>= 11; return cpm_vec; diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index c88e2d4dceb7..a192719929d3 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -144,12 +144,12 @@ void __init m8xx_calibrate_decr(void) int freq, fp, divisor; /* Unlock the SCCR. */ - ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY; + out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, ~KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, KAPWR_KEY); /* Force all 8xx processors to use divide by 16 processor clock. */ - ((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000; - + out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr, + in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr)|0x02000000); /* Processor frequency is MHz. * The value 'fp' is the number of decrementer ticks per second. */ @@ -175,28 +175,24 @@ void __init m8xx_calibrate_decr(void) * we guarantee the registers are locked, then we unlock them * for our use. */ - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = KAPWR_KEY; + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk, ~KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, ~KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, ~KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk, KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY); /* Disable the RTC one second and alarm interrupts. */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &= - ~(RTCSC_SIE | RTCSC_ALE); + out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE)); /* Enable the RTC */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |= - (RTCSC_RTF | RTCSC_RTE); + out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE)); /* Enabling the decrementer also enables the timebase interrupts * (or from the other point of view, to get decrementer interrupts * we have to enable the timebase). The decrementer interrupt * is wired into the vector table, nothing to do here for that. */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = - ((mk_int_int_mask(DEC_INTERRUPT) << 8) | - (TBSCR_TBF | TBSCR_TBE)); + out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr, (mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); if (setup_irq(DEC_INTERRUPT, &tbint_irqaction)) panic("Could not allocate timer IRQ!"); @@ -216,9 +212,9 @@ void __init m8xx_calibrate_decr(void) static int m8xx_set_rtc_time(unsigned long time) { - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck, KAPWR_KEY); + out_be32(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtc, time); + out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck, ~KAPWR_KEY); return(0); } @@ -226,7 +222,7 @@ static unsigned long m8xx_get_rtc_time(void) { /* Get time from the RTC. */ - return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc)); + return (unsigned long) in_be32(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtc); } static void @@ -235,13 +231,13 @@ m8xx_restart(char *cmd) __volatile__ unsigned char dummy; local_irq_disable(); - ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080; + out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr) | 0x00000080); /* Clear the ME bit in MSR to cause checkstop on machine check */ mtmsr(mfmsr() & ~0x1000); - dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0]; + dummy = in_8(&((immap_t *)IMAP_ADDR)->im_clkrst.res[0]); printk("Restart failed\n"); while(1); } @@ -306,8 +302,7 @@ m8xx_init_IRQ(void) i8259_init(0); /* The i8259 cascade interrupt must be level sensitive. */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &= - ~(0x80000000 >> ISA_BRIDGE_INT); + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel & ~(0x80000000 >> ISA_BRIDGE_INT))); if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction)) enable_irq(ISA_BRIDGE_INT); diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c index 2ddc857e7fc7..c5ac5ce5d7d2 100644 --- a/arch/ppc/syslib/m8xx_wdt.c +++ b/arch/ppc/syslib/m8xx_wdt.c @@ -29,8 +29,8 @@ void m8xx_wdt_reset(void) { volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; - imap->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */ - imap->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */ + out_be16(imap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ + out_be16(imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ } static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) @@ -39,7 +39,7 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) m8xx_wdt_reset(); - imap->im_sit.sit_piscr |= PISCR_PS; /* clear irq */ + out_be16(imap->im_sit.sit_piscr, in_be16(imap->im_sit.sit_piscr | PISCR_PS)); /* clear irq */ return IRQ_HANDLED; } @@ -51,7 +51,7 @@ void __init m8xx_wdt_handler_install(bd_t * binfo) u32 sypcr; u32 pitrtclk; - sypcr = imap->im_siu_conf.sc_sypcr; + sypcr = in_be32(imap->im_siu_conf.sc_sypcr); if (!(sypcr & 0x04)) { printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", @@ -87,9 +87,9 @@ void __init m8xx_wdt_handler_install(bd_t * binfo) else pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2; - imap->im_sit.sit_pitc = pitc << 16; - imap->im_sit.sit_piscr = - (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE; + out_be32(imap->im_sit.sit_pitc, pitc << 16); + + out_be16(imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE); if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction)) panic("m8xx_wdt: error setting up the watchdog irq!"); diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c index d3b01c6c97de..3e6f51a61d46 100644 --- a/arch/ppc/syslib/ppc8xx_pic.c +++ b/arch/ppc/syslib/ppc8xx_pic.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "ppc8xx_pic.h" @@ -29,8 +30,7 @@ static void m8xx_mask_irq(unsigned int irq_nr) word = irq_nr >> 5; ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - ppc_cached_irq_mask[word]; + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]); } static void m8xx_unmask_irq(unsigned int irq_nr) @@ -41,8 +41,7 @@ static void m8xx_unmask_irq(unsigned int irq_nr) word = irq_nr >> 5; ppc_cached_irq_mask[word] |= (1 << (31-bit)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - ppc_cached_irq_mask[word]; + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]); } static void m8xx_end_irq(unsigned int irq_nr) @@ -55,8 +54,7 @@ static void m8xx_end_irq(unsigned int irq_nr) word = irq_nr >> 5; ppc_cached_irq_mask[word] |= (1 << (31-bit)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - ppc_cached_irq_mask[word]; + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]); } } @@ -69,9 +67,8 @@ static void m8xx_mask_and_ack(unsigned int irq_nr) word = irq_nr >> 5; ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - ppc_cached_irq_mask[word]; - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit); + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]); + out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend, 1 << (31-bit)); } struct hw_interrupt_type ppc8xx_pic = { @@ -93,7 +90,7 @@ m8xx_get_irq(struct pt_regs *regs) /* For MPC8xx, read the SIVEC register and shift the bits down * to get the irq number. */ - irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26; + irq = in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec) >> 26; /* * When we read the sivec without an interrupt to process, we will From de957c89b7dadb3147e885d7b6eb9db73d0eea57 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 28 Oct 2005 17:46:13 -0700 Subject: [PATCH 1215/1939] [PATCH] MPC8xx PCMCIA driver Here is an uptodated version of the MPC8xx PCMCIA driver for v2.6, addressing comments by Jeff and Dominik: - use IO accessors instead of direct device memory referencing - avoid usage of non-standard "uint/uchar" data types - kill struct typedef's Will submit it for inclusion once v2.6.14 is out. Testing on 8xx platforms is more than welcome! Works like a charm on our custom hardware (CONFIG_PRxK). Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/pcmcia/Kconfig | 10 + drivers/pcmcia/Makefile | 1 + drivers/pcmcia/m8xx_pcmcia.c | 1290 ++++++++++++++++++++++++++++++++++ 3 files changed, 1301 insertions(+) create mode 100644 drivers/pcmcia/m8xx_pcmcia.c diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 36cc9a96a338..ccf20039e909 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -154,6 +154,16 @@ config TCIC "Bridge" is the name used for the hardware inside your computer that PCMCIA cards are plugged into. If unsure, say N. +config PCMCIA_M8XX + tristate "MPC8xx PCMCIA support" + depends on PCMCIA && PPC + select PCCARD_NONSTATIC + help + Say Y here to include support for PowerPC 8xx series PCMCIA + controller. + + This driver is also available as a module called m8xx_pcmcia. + config HD64465_PCMCIA tristate "HD64465 host bridge support" depends on HD64465 && PCMCIA diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index a41fbb38fdcb..cb4861d9cb80 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PD6729) += pd6729.o obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o obj-$(CONFIG_TCIC) += tcic.o +obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c new file mode 100644 index 000000000000..f8bed87cf2f1 --- /dev/null +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -0,0 +1,1290 @@ +/* + * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. + * + * (C) 1999-2000 Magnus Damm + * (C) 2001-2002 Montavista Software, Inc. + * + * + * Support for two slots by Cyclades Corporation + * + * Further fixes, v2.6 kernel port + * + * + * "The ExCA standard specifies that socket controllers should provide + * two IO and five memory windows per socket, which can be independently + * configured and positioned in the host address space and mapped to + * arbitrary segments of card address space. " - David A Hinds. 1999 + * + * This controller does _not_ meet the ExCA standard. + * + * m8xx pcmcia controller brief info: + * + 8 windows (attrib, mem, i/o) + * + up to two slots (SLOT_A and SLOT_B) + * + inputpins, outputpins, event and mask registers. + * - no offset register. sigh. + * + * Because of the lacking offset register we must map the whole card. + * We assign each memory window PCMCIA_MEM_WIN_SIZE address space. + * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO + * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE. + * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE. + * They are maximum 64KByte each... + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args); +#else +#define dprintk(args...) +#endif + +#define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args) +#define pcmcia_error(args...) printk(KERN_ERR "m8xx_pcmcia: "args) + +static const char *version = "Version 0.06, Aug 2005"; +MODULE_LICENSE("Dual MPL/GPL"); + +#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) + +/* The RPX series use SLOT_B */ +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) +#define CONFIG_PCMCIA_SLOT_B +#define CONFIG_BD_IS_MHZ +#endif + +/* The ADS board use SLOT_A */ +#ifdef CONFIG_ADS +#define CONFIG_PCMCIA_SLOT_A +#define CONFIG_BD_IS_MHZ +#endif + +/* The FADS series are a mess */ +#ifdef CONFIG_FADS +#if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821) +#define CONFIG_PCMCIA_SLOT_A +#else +#define CONFIG_PCMCIA_SLOT_B +#endif +#endif + +/* Cyclades ACS uses both slots */ +#ifdef CONFIG_PRxK +#define CONFIG_PCMCIA_SLOT_A +#define CONFIG_PCMCIA_SLOT_B +#endif + +#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */ + +#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B) + +#define PCMCIA_SOCKETS_NO 2 +/* We have only 8 windows, dualsocket support will be limited. */ +#define PCMCIA_MEM_WIN_NO 2 +#define PCMCIA_IO_WIN_NO 2 +#define PCMCIA_SLOT_MSG "SLOT_A and SLOT_B" + +#elif defined(CONFIG_PCMCIA_SLOT_A) || defined(CONFIG_PCMCIA_SLOT_B) + +#define PCMCIA_SOCKETS_NO 1 +/* full support for one slot */ +#define PCMCIA_MEM_WIN_NO 5 +#define PCMCIA_IO_WIN_NO 2 + +/* define _slot_ to be able to optimize macros */ + +#ifdef CONFIG_PCMCIA_SLOT_A +#define _slot_ 0 +#define PCMCIA_SLOT_MSG "SLOT_A" +#else +#define _slot_ 1 +#define PCMCIA_SLOT_MSG "SLOT_B" +#endif + +#else +#error m8xx_pcmcia: Bad configuration! +#endif + +/* ------------------------------------------------------------------------- */ + +#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ +#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ +#define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ + +#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */ + +/* ------------------------------------------------------------------------- */ + +/* 2.4.x and newer has this always in HZ */ +#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq)) + +static int pcmcia_schlvl = PCMCIA_SCHLVL; + +static spinlock_t events_lock = SPIN_LOCK_UNLOCKED; + + +#define PCMCIA_SOCKET_KEY_5V 1 +#define PCMCIA_SOCKET_KEY_LV 2 + +/* look up table for pgcrx registers */ +static u32 *m8xx_pgcrx[2] = { + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, + &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb +}; + +/* + * This structure is used to address each window in the PCMCIA controller. + * + * Keep in mind that we assume that pcmcia_win[n+1] is mapped directly + * after pcmcia_win[n]... + */ + +struct pcmcia_win { + u32 br; + u32 or; +}; + +/* + * For some reason the hardware guys decided to make both slots share + * some registers. + * + * Could someone invent object oriented hardware ? + * + * The macros are used to get the right bit from the registers. + * SLOT_A : slot = 0 + * SLOT_B : slot = 1 + */ + +#define M8XX_PCMCIA_VS1(slot) (0x80000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS2(slot) (0x40000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_MASK(slot) (0xc0000000 >> (slot << 4)) +#define M8XX_PCMCIA_VS_SHIFT(slot) (30 - (slot << 4)) + +#define M8XX_PCMCIA_WP(slot) (0x20000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4)) +#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD2(slot) (0x04000000 >> (slot << 4)) +#define M8XX_PCMCIA_BVD1(slot) (0x02000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY(slot) (0x01000000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_L(slot) (0x00800000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_H(slot) (0x00400000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_R(slot) (0x00200000 >> (slot << 4)) +#define M8XX_PCMCIA_RDY_F(slot) (0x00100000 >> (slot << 4)) +#define M8XX_PCMCIA_MASK(slot) (0xFFFF0000 >> (slot << 4)) + +#define M8XX_PCMCIA_POR_VALID 0x00000001 +#define M8XX_PCMCIA_POR_WRPROT 0x00000002 +#define M8XX_PCMCIA_POR_ATTRMEM 0x00000010 +#define M8XX_PCMCIA_POR_IO 0x00000018 +#define M8XX_PCMCIA_POR_16BIT 0x00000040 + +#define M8XX_PGCRX(slot) m8xx_pgcrx[slot] + +#define M8XX_PGCRX_CXOE 0x00000080 +#define M8XX_PGCRX_CXRESET 0x00000040 + +/* we keep one lookup table per socket to check flags */ + +#define PCMCIA_EVENTS_MAX 5 /* 4 max at a time + termination */ + +struct event_table { + u32 regbit; + u32 eventbit; +}; + +struct socket_info { + void (*handler)(void *info, u32 events); + void *info; + + u32 slot; + + socket_state_t state; + struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; + struct pccard_io_map io_win[PCMCIA_IO_WIN_NO]; + struct event_table events[PCMCIA_EVENTS_MAX]; + struct pcmcia_socket socket; +}; + +static struct socket_info socket[PCMCIA_SOCKETS_NO]; + +/* + * Search this table to see if the windowsize is + * supported... + */ + +#define M8XX_SIZES_NO 32 + +static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = +{ + 0x00000001, 0x00000002, 0x00000008, 0x00000004, + 0x00000080, 0x00000040, 0x00000010, 0x00000020, + 0x00008000, 0x00004000, 0x00001000, 0x00002000, + 0x00000100, 0x00000200, 0x00000800, 0x00000400, + + 0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x01000000, 0x02000000, 0xffffffff, 0x04000000, + 0x00010000, 0x00020000, 0x00080000, 0x00040000, + 0x00800000, 0x00400000, 0x00100000, 0x00200000 +}; + +/* ------------------------------------------------------------------------- */ + +static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs); + +#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */ + +/* ------------------------------------------------------------------------- */ +/* board specific stuff: */ +/* voltage_set(), hardware_enable() and hardware_disable() */ +/* ------------------------------------------------------------------------- */ +/* RPX Boards from Embedded Planet */ + +#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE) + +/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks. + * SYPCR is write once only, therefore must the slowest memory be faster + * than the bus monitor or we will get a machine check due to the bus timeout. + */ + +#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE" + +#undef PCMCIA_BMT_LIMIT +#define PCMCIA_BMT_LIMIT (6*8) + +static int voltage_set(int slot, int vcc, int vpp) +{ + u32 reg = 0; + + switch(vcc) { + case 0: break; + case 33: + reg |= BCSR1_PCVCTL4; + break; + case 50: + reg |= BCSR1_PCVCTL5; + break; + default: + return 1; + } + + switch(vpp) { + case 0: break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCVCTL6; + else + return 1; + break; + case 120: + reg |= BCSR1_PCVCTL7; + default: + return 1; + } + + if(!((vcc == 50) || (vcc == 0))) + return 1; + + /* first, turn off all power */ + + out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 | BCSR1_PCVCTL6 | BCSR1_PCVCTL7)); + + /* enable new powersettings */ + + out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_RPXCLASSIC */ + +/* FADS Boards from Motorola */ + +#if defined(CONFIG_FADS) + +#define PCMCIA_BOARD_MSG "FADS" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u32 reg = 0; + + switch(vcc) { + case 0: + break; + case 33: + reg |= BCSR1_PCCVCC0; + break; + case 50: + reg |= BCSR1_PCCVCC1; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCCVPP1; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= BCSR1_PCCVPP0; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); + + /* enable new powersettings */ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V + +static void hardware_enable(int slot) +{ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~BCSR1_PCCEN); +} + +static void hardware_disable(int slot) +{ + out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | BCSR1_PCCEN); +} + +#endif + +/* ------------------------------------------------------------------------- */ +/* Motorola MBX860 */ + +#if defined(CONFIG_MBX) + +#define PCMCIA_BOARD_MSG "MBX" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u8 reg = 0; + + switch(vcc) { + case 0: + break; + case 33: + reg |= CSR2_VCC_33; + break; + case 50: + reg |= CSR2_VCC_50; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= CSR2_VPP_VCC; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= CSR2_VPP_12; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK)); + + /* enable new powersettings */ + out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) | reg); + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_MBX */ + +#if defined(CONFIG_PRxK) +#include +extern volatile fpga_pc_regs *fpga_pc; + +#define PCMCIA_BOARD_MSG "MPC855T" + +static int voltage_set(int slot, int vcc, int vpp) +{ + u8 reg = 0; + u8 regread; + cpld_regs *ccpld = get_cpld(); + + switch(vcc) { + case 0: + break; + case 33: + reg |= PCMCIA_VCC_33; + break; + case 50: + reg |= PCMCIA_VCC_50; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= PCMCIA_VPP_VCC; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= PCMCIA_VPP_12; + else + return 1; + default: + return 1; + } + + reg = reg >> (slot << 2); + regread = in_8(&ccpld->fpga_pc_ctl); + if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) { + /* enable new powersettings */ + regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)); + out_8(&ccpld->fpga_pc_ctl, reg | regread); + msleep(100); + } + + return 0; +} + +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV +#define hardware_enable(_slot_) /* No hardware to enable */ +#define hardware_disable(_slot_) /* No hardware to disable */ + +#endif /* CONFIG_PRxK */ + +static void m8xx_shutdown(void) +{ + u32 m, i; + struct pcmcia_win *w; + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i)); + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i)); + + /* turn off interrupt and disable CxOE */ + out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); + + /* turn off memory windows */ + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + out_be32(&w->or, 0); /* set to not valid */ + w++; + } + + /* turn off voltage */ + voltage_set(i, 0, 0); + + /* disable external hardware */ + hardware_disable(i); + } + + free_irq(pcmcia_schlvl, NULL); +} + +/* copied from tcic.c */ + +static int m8xx_drv_suspend(struct device *dev, pm_message_t state, u32 level) +{ + int ret = 0; + if (level == SUSPEND_SAVE_STATE) + ret = pcmcia_socket_dev_suspend(dev, state); + return ret; +} + +static int m8xx_drv_resume(struct device *dev, u32 level) +{ + int ret = 0; + if (level == RESUME_RESTORE_STATE) + ret = pcmcia_socket_dev_resume(dev); + return ret; +} + +static struct device_driver m8xx_driver = { + .name = "m8xx-pcmcia", + .bus = &platform_bus_type, + .suspend = m8xx_drv_suspend, + .resume = m8xx_drv_resume, +}; + +static struct platform_device m8xx_device = { + .name = "m8xx-pcmcia", + .id = 0, +}; + +static u32 pending_events[PCMCIA_SOCKETS_NO]; +static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED; + +static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + struct socket_info *s; + struct event_table *e; + unsigned int i, events, pscr, pipr, per; + + dprintk("Interrupt!\n"); + /* get interrupt sources */ + + pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr); + pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); + per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per); + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++) { + s = &socket[i]; + e = &s->events[0]; + events = 0; + + while(e->regbit) { + if(pscr & e->regbit) + events |= e->eventbit; + + e++; + } + + /* + * report only if both card detect signals are the same + * not too nice done, + * we depend on that CD2 is the bit to the left of CD1... + */ + if(events & SS_DETECT) + if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^ + (pipr & M8XX_PCMCIA_CD1(i))) + { + events &= ~SS_DETECT; + } + +#ifdef PCMCIA_GLITCHY_CD + /* + * I've experienced CD problems with my ADS board. + * We make an extra check to see if there was a + * real change of Card detection. + */ + + if((events & SS_DETECT) && + ((pipr & + (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) && + (s->state.Vcc | s->state.Vpp)) { + events &= ~SS_DETECT; + /*printk( "CD glitch workaround - CD = 0x%08x!\n", + (pipr & (M8XX_PCMCIA_CD2(i) + | M8XX_PCMCIA_CD1(i))));*/ + } +#endif + + /* call the handler */ + + dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, " + "pipr = 0x%08x\n", + i, events, pscr, pipr); + + if(events) { + spin_lock(&pending_event_lock); + pending_events[i] |= events; + spin_unlock(&pending_event_lock); + /* + * Turn off RDY_L bits in the PER mask on + * CD interrupt receival. + * + * They can generate bad interrupts on the + * ACS4,8,16,32. - marcelo + */ + per &= ~M8XX_PCMCIA_RDY_L(0); + per &= ~M8XX_PCMCIA_RDY_L(1); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per); + + if (events) + pcmcia_parse_events(&socket[i].socket, events); + } + } + + /* clear the interrupt sources */ + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr); + + dprintk("Interrupt done.\n"); + + return IRQ_HANDLED; +} + +static u32 m8xx_get_graycode(u32 size) +{ + u32 k; + + for(k = 0; k < M8XX_SIZES_NO; k++) + if(m8xx_size_to_gray[k] == size) + break; + + if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1)) + k = -1; + + return k; +} + +static u32 m8xx_get_speed(u32 ns, u32 is_io) +{ + u32 reg, clocks, psst, psl, psht; + + if(!ns) { + + /* + * We get called with IO maps setup to 0ns + * if not specified by the user. + * They should be 255ns. + */ + + if(is_io) + ns = 255; + else + ns = 100; /* fast memory if 0 */ + } + + /* + * In PSST, PSL, PSHT fields we tell the controller + * timing parameters in CLKOUT clock cycles. + * CLKOUT is the same as GCLK2_50. + */ + +/* how we want to adjust the timing - in percent */ + +#define ADJ 180 /* 80 % longer accesstime - to be sure */ + + clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; + clocks = (clocks * ADJ) / (100*1000); + if(clocks >= PCMCIA_BMT_LIMIT) { + printk( "Max access time limit reached\n"); + clocks = PCMCIA_BMT_LIMIT-1; + } + + psst = clocks / 7; /* setup time */ + psht = clocks / 7; /* hold time */ + psl = (clocks * 5) / 7; /* strobe length */ + + psst += clocks - (psst + psht + psl); + + reg = psst << 12; + reg |= psl << 7; + reg |= psht << 16; + + return reg; +} + +static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + unsigned int pipr, reg; + + pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); + + *value = ((pipr & (M8XX_PCMCIA_CD1(lsock) + | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0; + *value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0; + + if (s->state.flags & SS_IOCARD) + *value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_STSCHG : 0; + else { + *value |= (pipr & M8XX_PCMCIA_RDY(lsock)) ? SS_READY : 0; + *value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_BATDEAD : 0; + *value |= (pipr & M8XX_PCMCIA_BVD2(lsock)) ? SS_BATWARN : 0; + } + + if (s->state.Vcc | s->state.Vpp) + *value |= SS_POWERON; + + /* + * Voltage detection: + * This driver only supports 16-Bit pc-cards. + * Cardbus is not handled here. + * + * To determine what voltage to use we must read the VS1 and VS2 pin. + * Depending on what socket type is present, + * different combinations mean different things. + * + * Card Key Socket Key VS1 VS2 Card Vcc for CIS parse + * + * 5V 5V, LV* NC NC 5V only 5V (if available) + * + * 5V 5V, LV* GND NC 5 or 3.3V as low as possible + * + * 5V 5V, LV* GND GND 5, 3.3, x.xV as low as possible + * + * LV* 5V - - shall not fit into socket + * + * LV* LV* GND NC 3.3V only 3.3V + * + * LV* LV* NC GND x.xV x.xV (if avail.) + * + * LV* LV* GND GND 3.3 or x.xV as low as possible + * + * *LV means Low Voltage + * + * + * That gives us the following table: + * + * Socket VS1 VS2 Voltage + * + * 5V NC NC 5V + * 5V NC GND none (should not be possible) + * 5V GND NC >= 3.3V + * 5V GND GND >= x.xV + * + * LV NC NC 5V (if available) + * LV NC GND x.xV (if available) + * LV GND NC 3.3V + * LV GND GND >= x.xV + * + * So, how do I determine if I have a 5V or a LV + * socket on my board? Look at the socket! + * + * + * Socket with 5V key: + * ++--------------------------------------------+ + * || | + * || || + * || || + * | | + * +---------------------------------------------+ + * + * Socket with LV key: + * ++--------------------------------------------+ + * || | + * | || + * | || + * | | + * +---------------------------------------------+ + * + * + * With other words - LV only cards does not fit + * into the 5V socket! + */ + + /* read out VS1 and VS2 */ + + reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock)) + >> M8XX_PCMCIA_VS_SHIFT(lsock); + + if(socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) { + switch(reg) { + case 1: + *value |= SS_3VCARD; + break; /* GND, NC - 3.3V only */ + case 2: + *value |= SS_XVCARD; + break; /* NC. GND - x.xV only */ + }; + } + + dprintk("GetStatus(%d) = %#2.2x\n", lsock, *value); + return 0; +} + +static int m8xx_get_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + *state = socket[lsock].state; /* copy the whole structure */ + + dprintk("GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} + +static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + struct event_table *e; + unsigned int reg; + unsigned long flags; + + dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + + /* First, set voltage - bail out if invalid */ + if(voltage_set(lsock, state->Vcc, state->Vpp)) + return -EINVAL; + + /* Take care of reset... */ + if(state->flags & SS_RESET) + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */ + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET); + + /* ... and output enable. */ + + /* The CxOE signal is connected to a 74541 on the ADS. + I guess most other boards used the ADS as a reference. + I tried to control the CxOE signal with SS_OUTPUT_ENA, + but the reset signal seems connected via the 541. + If the CxOE is left high are some signals tristated and + no pullups are present -> the cards act wierd. + So right now the buffers are enabled if the power is on. */ + + if(state->Vcc || state->Vpp) + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */ + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE); + + /* + * We'd better turn off interrupts before + * we mess with the events-table.. + */ + + spin_lock_irqsave(&events_lock, flags); + + /* + * Play around with the interrupt mask to be able to + * give the events the generic pcmcia driver wants us to. + */ + + e = &s->events[0]; + reg = 0; + + if(state->csc_mask & SS_DETECT) { + e->eventbit = SS_DETECT; + reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock) + | M8XX_PCMCIA_CD1(lsock)); + e++; + } + if(state->flags & SS_IOCARD) { + /* + * I/O card + */ + if(state->csc_mask & SS_STSCHG) { + e->eventbit = SS_STSCHG; + reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock); + e++; + } + /* + * If io_irq is non-zero we should enable irq. + */ + if(state->io_irq) { + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24); + /* + * Strange thing here: + * The manual does not tell us which interrupt + * the sources generate. + * Anyhow, I found out that RDY_L generates IREQLVL. + * + * We use level triggerd interrupts, and they don't + * have to be cleared in PSCR in the interrupt handler. + */ + reg |= M8XX_PCMCIA_RDY_L(lsock); + } + else + out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff); + } + else { + /* + * Memory card + */ + if(state->csc_mask & SS_BATDEAD) { + e->eventbit = SS_BATDEAD; + reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock); + e++; + } + if(state->csc_mask & SS_BATWARN) { + e->eventbit = SS_BATWARN; + reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock); + e++; + } + /* What should I trigger on - low/high,raise,fall? */ + if(state->csc_mask & SS_READY) { + e->eventbit = SS_READY; + reg |= e->regbit = 0; //?? + e++; + } + } + + e->regbit = 0; /* terminate list */ + + /* + * Clear the status changed . + * Port A and Port B share the same port. + * Writing ones will clear the bits. + */ + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg); + + /* + * Write the mask. + * Port A and Port B share the same port. + * Need for read-modify-write. + * Ones will enable the interrupt. + */ + + /* + reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + & M8XX_PCMCIA_MASK(lsock); + */ + + reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & + (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg); + + spin_unlock_irqrestore(&events_lock, flags); + + /* copy the struct and modify the copy */ + + s->state = *state; + + return 0; +} + +static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + + struct socket_info *s = &socket[lsock]; + struct pcmcia_win *w; + unsigned int reg, winnr; + +#define M8XX_SIZE (io->stop - io->start + 1) +#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) + + dprintk( "SetIOMap(%d, %d, %#2.2x, %d ns, " + "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + + if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff) + || (io->stop > 0xffff) || (io->stop < io->start)) + return -EINVAL; + + if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1) + return -EINVAL; + + if(io->flags & MAP_ACTIVE) { + + dprintk( "io->flags & MAP_ACTIVE\n"); + + winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + + (lsock * PCMCIA_IO_WIN_NO) + io->map; + + /* setup registers */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + out_be32(&w->or, 0); /* turn off window first */ + out_be32(&w->br, M8XX_BASE); + + reg <<= 27; + reg |= M8XX_PCMCIA_POR_IO |(lsock << 2); + + reg |= m8xx_get_speed(io->speed, 1); + + if(io->flags & MAP_WRPROT) + reg |= M8XX_PCMCIA_POR_WRPROT; + + /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/ + if(io->flags & MAP_16BIT) + reg |= M8XX_PCMCIA_POR_16BIT; + + if(io->flags & MAP_ACTIVE) + reg |= M8XX_PCMCIA_POR_VALID; + + out_be32(&w->or, reg); + + dprintk("Socket %u: Mapped io window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + } else { + /* shutdown IO window */ + winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + + (lsock * PCMCIA_IO_WIN_NO) + io->map; + + /* setup registers */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + out_be32(&w->or, 0); /* turn off window */ + out_be32(&w->br, 0); /* turn off base address */ + + dprintk("Socket %u: Unmapped io window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + } + + /* copy the struct and modify the copy */ + s->io_win[io->map] = *io; + s->io_win[io->map].flags &= (MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + dprintk("SetIOMap exit\n"); + + return 0; +} + +static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) +{ + int lsock = container_of(sock, struct socket_info, socket)->slot; + struct socket_info *s = &socket[lsock]; + struct pcmcia_win *w; + struct pccard_mem_map *old; + unsigned int reg, winnr; + + dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->static_start, mem->card_start); + + if ((mem->map >= PCMCIA_MEM_WIN_NO) +// || ((mem->s) >= PCMCIA_MEM_WIN_SIZE) + || (mem->card_start >= 0x04000000) + || (mem->static_start & 0xfff) /* 4KByte resolution */ + || (mem->card_start & 0xfff)) + return -EINVAL; + + if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) { + printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE); + return -EINVAL; + } + reg <<= 27; + + winnr = (lsock * PCMCIA_MEM_WIN_NO) + mem->map; + + /* Setup the window in the pcmcia controller */ + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w += winnr; + + reg |= lsock << 2; + + reg |= m8xx_get_speed(mem->speed, 0); + + if(mem->flags & MAP_ATTRIB) + reg |= M8XX_PCMCIA_POR_ATTRMEM; + + if(mem->flags & MAP_WRPROT) + reg |= M8XX_PCMCIA_POR_WRPROT; + + if(mem->flags & MAP_16BIT) + reg |= M8XX_PCMCIA_POR_16BIT; + + if(mem->flags & MAP_ACTIVE) + reg |= M8XX_PCMCIA_POR_VALID; + + out_be32(&w->or, reg); + + dprintk("Socket %u: Mapped memory window %u at %#8.8x, " + "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or); + + if(mem->flags & MAP_ACTIVE) { + /* get the new base address */ + mem->static_start = PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE * winnr) + + mem->card_start; + } + + dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->static_start, mem->card_start); + + /* copy the struct and modify the copy */ + + old = &s->mem_win[mem->map]; + + *old = *mem; + old->flags &= (MAP_ATTRIB + | MAP_WRPROT + | MAP_16BIT + | MAP_ACTIVE); + + return 0; +} + +static int m8xx_sock_init(struct pcmcia_socket *sock) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + dprintk( "sock_init(%d)\n", s); + + m8xx_set_socket(sock, &dead_socket); + for (i = 0; i < PCMCIA_IO_WIN_NO; i++) { + io.map = i; + m8xx_set_io_map(sock, &io); + } + for (i = 0; i < PCMCIA_MEM_WIN_NO; i++) { + mem.map = i; + m8xx_set_mem_map(sock, &mem); + } + + return 0; + +} + +static int m8xx_suspend(struct pcmcia_socket *sock) +{ + return m8xx_set_socket(sock, &dead_socket); +} + +static struct pccard_operations m8xx_services = { + .init = m8xx_sock_init, + .suspend = m8xx_suspend, + .get_status = m8xx_get_status, + .get_socket = m8xx_get_socket, + .set_socket = m8xx_set_socket, + .set_io_map = m8xx_set_io_map, + .set_mem_map = m8xx_set_mem_map, +}; + +static int __init m8xx_init(void) +{ + struct pcmcia_win *w; + unsigned int i,m; + + pcmcia_info("%s\n", version); + + if (driver_register(&m8xx_driver)) + return -1; + + pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG + " with IRQ %u.\n", pcmcia_schlvl); + + /* Configure Status change interrupt */ + + if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0, + "m8xx_pcmcia", NULL)) { + pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", + pcmcia_schlvl); + return -1; + } + + w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, + M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); + + out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, + in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & + ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1))); + +/* connect interrupt and disable CxOE */ + + out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); + out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); + +/* intialize the fixed memory windows */ + + for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ + for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + out_be32(&w->br, PCMCIA_MEM_WIN_BASE + + (PCMCIA_MEM_WIN_SIZE + * (m + i * PCMCIA_MEM_WIN_NO))); + + out_be32(&w->or, 0); /* set to not valid */ + + w++; + } + } + +/* turn off voltage */ + voltage_set(0, 0, 0); + voltage_set(1, 0, 0); + +/* Enable external hardware */ + hardware_enable(0); + hardware_enable(1); + + platform_device_register(&m8xx_device); + + for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) { + socket[i].slot = i; + socket[i].socket.owner = THIS_MODULE; + socket[i].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP; + socket[i].socket.irq_mask = 0x000; + socket[i].socket.map_size = 0x1000; + socket[i].socket.io_offset = 0; + socket[i].socket.pci_irq = i ? 7 : 9; + socket[i].socket.ops = &m8xx_services; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; + socket[i].socket.cb_dev = NULL; + socket[i].socket.dev.dev = &m8xx_device.dev; + } + + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) + pcmcia_register_socket(&socket[i].socket); + + return 0; +} + +static void __exit m8xx_exit(void) +{ + int i; + + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) + pcmcia_unregister_socket(&socket[i].socket); + + m8xx_shutdown(); + + platform_device_unregister(&m8xx_device); + driver_unregister(&m8xx_driver); +} + +module_init(m8xx_init); +module_exit(m8xx_exit); From d5f7b06b036afc2cb250decb2c76b7f82c5de639 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 28 Oct 2005 17:46:14 -0700 Subject: [PATCH 1216/1939] [PATCH] ppc32: Cleanup AMCC PPC44x eval board U-Boot support Cleanup PPC440 eval boards (bamboo, ebony, luan and ocotea) to better support U-Boot as bootloader. Signed-off-by: Stefan Roese Signed-off-by: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/platforms/4xx/bamboo.c | 14 ++----------- arch/ppc/platforms/4xx/ebony.c | 13 ++---------- arch/ppc/platforms/4xx/luan.c | 13 ++---------- arch/ppc/platforms/4xx/ocotea.c | 31 +++++++++++------------------ arch/ppc/syslib/ibm44x_common.c | 35 ++++++++++++++++++++++++++++++++- arch/ppc/syslib/ibm44x_common.h | 3 ++- 6 files changed, 53 insertions(+), 56 deletions(-) diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c index 78a403b48dba..159b228eca1e 100644 --- a/arch/ppc/platforms/4xx/bamboo.c +++ b/arch/ppc/platforms/4xx/bamboo.c @@ -51,7 +51,7 @@ #include #include -bd_t __res; +extern bd_t __res; static struct ibm44x_clocks clocks __initdata; @@ -425,17 +425,7 @@ bamboo_setup_arch(void) void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo(find_bootinfo()); - - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) - __res = *(bd_t *)(r3 + KERNELBASE); - - - ibm44x_platform_init(); + ibm44x_platform_init(r3, r4, r5, r6, r7); ppc_md.setup_arch = bamboo_setup_arch; ppc_md.show_cpuinfo = bamboo_show_cpuinfo; diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index d32ae112f639..64ebae19cdbb 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -54,7 +54,7 @@ #include #include -bd_t __res; +extern bd_t __res; static struct ibm44x_clocks clocks __initdata; @@ -317,16 +317,7 @@ ebony_setup_arch(void) void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo(find_bootinfo()); - - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) - __res = *(bd_t *)(r3 + KERNELBASE); - - ibm44x_platform_init(); + ibm44x_platform_init(r3, r4, r5, r6, r7); ppc_md.setup_arch = ebony_setup_arch; ppc_md.show_cpuinfo = ebony_show_cpuinfo; diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c index 16d953bda22c..d810b736d9bf 100644 --- a/arch/ppc/platforms/4xx/luan.c +++ b/arch/ppc/platforms/4xx/luan.c @@ -52,7 +52,7 @@ #include #include -bd_t __res; +extern bd_t __res; static struct ibm44x_clocks clocks __initdata; @@ -355,16 +355,7 @@ luan_setup_arch(void) void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo(find_bootinfo()); - - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) - __res = *(bd_t *)(r3 + KERNELBASE); - - ibm44x_platform_init(); + ibm44x_platform_init(r3, r4, r5, r6, r7); ppc_md.setup_arch = luan_setup_arch; ppc_md.show_cpuinfo = luan_show_cpuinfo; diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c index 506949c5dd29..73b2c98158f6 100644 --- a/arch/ppc/platforms/4xx/ocotea.c +++ b/arch/ppc/platforms/4xx/ocotea.c @@ -52,7 +52,7 @@ #include #include -bd_t __res; +extern bd_t __res; static struct ibm44x_clocks clocks __initdata; @@ -286,6 +286,15 @@ ocotea_setup_arch(void) ibm440gx_tah_enable(); + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + /* Setup TODC access */ TODC_INIT(TODC_TYPE_DS1743, 0, @@ -324,25 +333,7 @@ static void __init ocotea_init(void) void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - parse_bootinfo(find_bootinfo()); - - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) - __res = *(bd_t *)(r3 + KERNELBASE); - - /* - * Determine various clocks. - * To be completely correct we should get SysClk - * from FPGA, because it can be changed by on-board switches - * --ebs - */ - ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); - ocp_sys_info.opb_bus_freq = clocks.opb; - - ibm44x_platform_init(); + ibm44x_platform_init(r3, r4, r5, r6, r7); ppc_md.setup_arch = ocotea_setup_arch; ppc_md.show_cpuinfo = ocotea_show_cpuinfo; diff --git a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c index 95e11f93c15d..5152c8e41340 100644 --- a/arch/ppc/syslib/ibm44x_common.c +++ b/arch/ppc/syslib/ibm44x_common.c @@ -27,9 +27,14 @@ #include #include #include +#include +#include #include +/* Global Variables */ +bd_t __res; + phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size) { phys_addr_t page_4gb = 0; @@ -150,8 +155,36 @@ static unsigned long __init ibm44x_find_end_of_memory(void) return mem_size; } -void __init ibm44x_platform_init(void) +void __init ibm44x_platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) { + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + ppc_md.init_IRQ = ppc4xx_pic_init; ppc_md.find_end_of_memory = ibm44x_find_end_of_memory; ppc_md.restart = ibm44x_restart; diff --git a/arch/ppc/syslib/ibm44x_common.h b/arch/ppc/syslib/ibm44x_common.h index c16b6a5ac6ab..b25a8995e4e9 100644 --- a/arch/ppc/syslib/ibm44x_common.h +++ b/arch/ppc/syslib/ibm44x_common.h @@ -36,7 +36,8 @@ struct ibm44x_clocks { }; /* common 44x platform init */ -void ibm44x_platform_init(void) __init; +void ibm44x_platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) __init; /* initialize decrementer and tick-related variables */ void ibm44x_calibrate_decr(unsigned int freq) __init; From 434cc69fbb02dd7ca64c5029dc6a6f9636f77e02 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 28 Oct 2005 17:46:15 -0700 Subject: [PATCH 1217/1939] [PATCH] ppc32: #ifdef out ALTIVEC specific code in __switch_to #ifdef out an ALTIVEC specific tweak in __switch_to() Signed-off-by: Marcelo Tosatti Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/kernel/process.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 78ea10197a0b..cb1c7b92f8c6 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -347,11 +347,13 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif /* CONFIG_SPE */ #endif /* CONFIG_SMP */ +#ifdef CONFIG_ALTIVEC /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_altivec -- Cort */ if (new->thread.regs && last_task_used_altivec == new) new->thread.regs->msr |= MSR_VEC; +#endif #ifdef CONFIG_SPE /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_spe From d49b340124a34fcb8bceda472558ccef7232c16f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:17 -0700 Subject: [PATCH 1218/1939] [PATCH] ppc32: update xmon help text Mention a few more commands in xmon. System.map processing was replaced with kallsyms. Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/xmon/xmon.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index be7869e39465..66bfaa3211a2 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -148,9 +148,14 @@ Commands:\n\ r print registers\n\ S print special registers\n\ t print backtrace\n\ - la lookup address in system.map\n\ - ls lookup symbol in system.map\n\ + la lookup address\n\ + ls lookup symbol\n\ + C checksum\n\ + p call function with arguments\n\ + T print time\n\ x exit monitor\n\ + zr reboot\n\ + zh halt\n\ "; static int xmon_trace[NR_CPUS]; From e83b860539d0ac1b3cff868178fa79c457e0c21f Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 21 Oct 2005 18:00:48 +0900 Subject: [PATCH 1219/1939] [TCP]: fix tcp_tso_win_divisor documentation The default value for tcp_tso_win_divisor is 3. Signed-off-by: Akinobu Mita Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/ip-sysctl.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index b433c8a27e2d..65895bb51414 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -309,7 +309,7 @@ tcp_tso_win_divisor - INTEGER can be consumed by a single TSO frame. The setting of this parameter is a choice between burstiness and building larger TSO frames. - Default: 8 + Default: 3 tcp_frto - BOOLEAN Enables F-RTO, an enhanced recovery algorithm for TCP retransmission From 360ac8e2f1a38c3497739636c3b702352d1ad0ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 25 Oct 2005 15:03:41 -0700 Subject: [PATCH 1220/1939] [ETH]: ether address compare Expose faster ether compare for use by protocols and other driver. And change name to be more consistent with other ether address manipulation routines in same file Signed-off-by: Stephen Hemminger Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/etherdevice.h | 16 ++++++++++++++++ net/ethernet/eth.c | 17 ++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 4522c7186bf3..cc84934f9059 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -104,6 +104,22 @@ static inline void random_ether_addr(u8 *addr) addr [0] &= 0xfe; /* clear multicast bit */ addr [0] |= 0x02; /* set local assignment bit (IEEE802) */ } + +/** + * compare_ether_addr - Compare two Ethernet addresses + * @addr1: Pointer to a six-byte array containing the Ethernet address + * @addr2 Pointer other six-byte array containing the Ethernet address + * + * Compare two ethernet addresses, returns 0 if equal + */ +static inline unsigned compare_ether_addr(const u8 *_a, const u8 *_b) +{ + const u16 *a = (const u16 *) _a; + const u16 *b = (const u16 *) _b; + + BUILD_BUG_ON(ETH_ALEN != 6); + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +} #endif /* __KERNEL__ */ #endif /* _LINUX_ETHERDEVICE_H */ diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 68a5ca866442..e24577367274 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -146,19 +146,6 @@ int eth_rebuild_header(struct sk_buff *skb) return 0; } -static inline unsigned int compare_eth_addr(const unsigned char *__a, const unsigned char *__b) -{ - const unsigned short *dest = (unsigned short *) __a; - const unsigned short *devaddr = (unsigned short *) __b; - unsigned int res; - - BUILD_BUG_ON(ETH_ALEN != 6); - res = ((dest[0] ^ devaddr[0]) | - (dest[1] ^ devaddr[1]) | - (dest[2] ^ devaddr[2])) != 0; - - return res; -} /* * Determine the packet's protocol ID. The rule here is that we @@ -176,7 +163,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) eth = eth_hdr(skb); if (*eth->h_dest&1) { - if (!compare_eth_addr(eth->h_dest, dev->broadcast)) + if (!compare_ether_addr(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; @@ -191,7 +178,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) */ else if(1 /*dev->flags&IFF_PROMISC*/) { - if (unlikely(compare_eth_addr(eth->h_dest, dev->dev_addr))) + if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) skb->pkt_type = PACKET_OTHERHOST; } From 8b150478aeb1a8edb9015c2f7ac4da637ff65c45 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Oct 2005 17:46:18 -0700 Subject: [PATCH 1221/1939] [PATCH] ppc: make phys_mem_access_prot() work with pfns instead of addresses Change the phys_mem_access_prot() function to take a pfn instead of an address. This allows mmap64() to work on /dev/mem for addresses above 4G on 32-bit architectures. We start with a pfn in mmap_mem(), so there's no need to convert to an address; in fact, it's actively bad, since the conversion can overflow when the address is above 4G. Similarly fix the ppc32 page_is_ram() function to avoid a conversion to an address by directly comparing to max_pfn. Working with max_pfn instead of high_memory fixes page_is_ram() to give the right answer for highmem pages. Signed-off-by: Roland Dreier Cc: Anton Blanchard Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mem.c | 6 +++--- arch/ppc/kernel/pci.c | 5 +++-- arch/ppc/mm/init.c | 10 ++++------ arch/ppc64/kernel/pci.c | 5 +++-- drivers/char/mem.c | 4 +--- drivers/video/fbmem.c | 2 +- include/asm-powerpc/machdep.h | 2 +- include/asm-ppc/machdep.h | 2 +- include/asm-ppc/pci.h | 2 +- include/asm-ppc/pgtable.h | 2 +- include/asm-ppc64/pci.h | 2 +- include/asm-ppc64/pgtable.h | 2 +- 12 files changed, 21 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 695db6a588ce..3ca331728d21 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -88,13 +88,13 @@ int page_is_ram(unsigned long pfn) } EXPORT_SYMBOL(page_is_ram); -pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, +pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { if (ppc_md.phys_mem_access_prot) - return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); + return ppc_md.phys_mem_access_prot(file, pfn, size, vma_prot); - if (!page_is_ram(addr >> PAGE_SHIFT)) + if (!page_is_ram(pfn)) vma_prot = __pgprot(pgprot_val(vma_prot) | _PAGE_GUARDED | _PAGE_NO_CACHE); return vma_prot; diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index ad4ef2aaa6ab..e8f4e576750a 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1594,16 +1594,17 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, * above routine */ pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t protection) { struct pci_dev *pdev = NULL; struct resource *found = NULL; unsigned long prot = pgprot_val(protection); + unsigned long offset = pfn << PAGE_SHIFT; int i; - if (page_is_ram(offset >> PAGE_SHIFT)) + if (page_is_ram(pfn)) return prot; prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index db94efd25369..99b48abd3296 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -637,18 +637,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, */ int page_is_ram(unsigned long pfn) { - unsigned long paddr = (pfn << PAGE_SHIFT); - - return paddr < __pa(high_memory); + return pfn < max_pfn; } -pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, +pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { if (ppc_md.phys_mem_access_prot) - return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot); + return ppc_md.phys_mem_access_prot(file, pfn, size, vma_prot); - if (!page_is_ram(addr >> PAGE_SHIFT)) + if (!page_is_ram(pfn)) vma_prot = __pgprot(pgprot_val(vma_prot) | _PAGE_GUARDED | _PAGE_NO_CACHE); return vma_prot; diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index b2fb6746f00b..3d2106b022a1 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -726,16 +726,17 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, * above routine */ pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t protection) { struct pci_dev *pdev = NULL; struct resource *found = NULL; unsigned long prot = pgprot_val(protection); + unsigned long offset = pfn << PAGE_SHIFT; int i; - if (page_is_ram(offset >> PAGE_SHIFT)) + if (page_is_ram(pfn)) return __pgprot(prot); prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f182752fe918..9df928d4f68d 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -231,9 +231,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf, static int mmap_mem(struct file * file, struct vm_area_struct * vma) { #if defined(__HAVE_PHYS_MEM_ACCESS_PROT) - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - - vma->vm_page_prot = phys_mem_access_prot(file, offset, + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); #elif defined(pgprot_noncached) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 70be7009f8af..ca02aa2bfcec 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -918,7 +918,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) } #endif #elif defined(__powerpc__) - vma->vm_page_prot = phys_mem_access_prot(file, off, + vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); #elif defined(__alpha__) diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 706508b1b04b..451b345cfc78 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -144,7 +144,7 @@ struct machdep_calls { /* Get access protection for /dev/mem */ pgprot_t (*phys_mem_access_prot)(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t vma_prot); diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 6c6d23abbe91..f01255bd1dc3 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -98,7 +98,7 @@ struct machdep_calls { /* Get access protection for /dev/mem */ pgprot_t (*phys_mem_access_prot)(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t vma_prot); diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index 643740dd727b..61434edbad7b 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -126,7 +126,7 @@ extern void pcibios_add_platform_entries(struct pci_dev *dev); struct file; extern pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t prot); diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index eee601bb9ada..b28a713ba862 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -705,7 +705,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) #define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) struct file; -extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, +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 diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index a88bbfc26967..342e2d755550 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -168,7 +168,7 @@ extern void pcibios_add_platform_entries(struct pci_dev *dev); struct file; extern pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long offset, + unsigned long pfn, unsigned long size, pgprot_t prot); diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h index c83679c9d2b0..8cf5991540e3 100644 --- a/include/asm-ppc64/pgtable.h +++ b/include/asm-ppc64/pgtable.h @@ -471,7 +471,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) #define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) struct file; -extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, +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 From 35e95e63995f3e52178db4b769120ce60deb6b54 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:19 -0700 Subject: [PATCH 1222/1939] [PATCH] ppc32: nvram driver for chrp This implements a nvram acccess method, similar to arch/ppc64/kernel/pSeries_nvram.c tested on CHRP B50. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/chrp/Makefile | 1 + arch/powerpc/platforms/chrp/chrp.h | 12 ++++ arch/powerpc/platforms/chrp/nvram.c | 84 ++++++++++++++++++++++++++++ arch/powerpc/platforms/chrp/setup.c | 11 ++-- arch/ppc/platforms/Makefile | 3 + arch/ppc/platforms/chrp_nvram.c | 83 +++++++++++++++++++++++++++ arch/ppc/platforms/chrp_setup.c | 3 +- include/asm-ppc/system.h | 1 + 8 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 arch/powerpc/platforms/chrp/chrp.h create mode 100644 arch/powerpc/platforms/chrp/nvram.c create mode 100644 arch/ppc/platforms/chrp_nvram.c diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile index 1fde4e68414f..902feb1ac431 100644 --- a/arch/powerpc/platforms/chrp/Makefile +++ b/arch/powerpc/platforms/chrp/Makefile @@ -1,3 +1,4 @@ obj-y += setup.o time.o pegasos_eth.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_NVRAM) += nvram.o diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h new file mode 100644 index 000000000000..3a2057fa314a --- /dev/null +++ b/arch/powerpc/platforms/chrp/chrp.h @@ -0,0 +1,12 @@ +/* + * Declarations of CHRP platform-specific things. + */ + +extern void chrp_nvram_init(void); +extern void chrp_get_rtc_time(struct rtc_time *); +extern int chrp_set_rtc_time(struct rtc_time *); +extern void chrp_calibrate_decr(void); +extern long chrp_time_init(void); + +extern void chrp_find_bridges(void); +extern void chrp_event_scan(void); diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c new file mode 100644 index 000000000000..4ac7125aa09c --- /dev/null +++ b/arch/powerpc/platforms/chrp/nvram.c @@ -0,0 +1,84 @@ +/* + * c 2001 PPC 64 Team, 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. + * + * /dev/nvram driver for PPC + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "chrp.h" + +static unsigned int nvram_size; +static unsigned char nvram_buf[4]; +static DEFINE_SPINLOCK(nvram_lock); + +static unsigned char chrp_nvram_read(int addr) +{ + unsigned long done, flags; + unsigned char ret; + + if (addr >= nvram_size) { + printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n", + current->comm, addr, nvram_size); + return 0xff; + } + spin_lock_irqsave(&nvram_lock, flags); + if ((call_rtas("nvram-fetch", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) + ret = 0xff; + else + ret = nvram_buf[0]; + spin_unlock_irqrestore(&nvram_lock, flags); + + return ret; +} + +static void chrp_nvram_write(int addr, unsigned char val) +{ + unsigned long done, flags; + + if (addr >= nvram_size) { + printk(KERN_DEBUG "%s: write addr %d > nvram_size %u\n", + current->comm, addr, nvram_size); + return; + } + spin_lock_irqsave(&nvram_lock, flags); + nvram_buf[0] = val; + if ((call_rtas("nvram-store", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) + printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr); + spin_unlock_irqrestore(&nvram_lock, flags); +} + +void __init chrp_nvram_init(void) +{ + struct device_node *nvram; + unsigned int *nbytes_p, proplen; + + nvram = of_find_node_by_type(NULL, "nvram"); + if (nvram == NULL) + return; + + nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen); + if (nbytes_p == NULL || proplen != sizeof(unsigned int)) + return; + + nvram_size = *nbytes_p; + + printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size); + of_node_put(nvram); + + ppc_md.nvram_read_val = chrp_nvram_read; + ppc_md.nvram_write_val = chrp_nvram_write; + + return; +} diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 5145990e6a01..ecd32d5d85f4 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -55,13 +55,8 @@ #include #include -void chrp_get_rtc_time(struct rtc_time *); -int chrp_set_rtc_time(struct rtc_time *); -void chrp_calibrate_decr(void); -long chrp_time_init(void); +#include "chrp.h" -void chrp_find_bridges(void); -void chrp_event_scan(void); void rtas_indicator_progress(char *, unsigned short); void btext_progress(char *, unsigned short); @@ -469,6 +464,10 @@ void __init chrp_init_IRQ(void) void __init chrp_init2(void) { +#ifdef CONFIG_NVRAM + chrp_nvram_init(); +#endif + request_region(0x20,0x20,"pic1"); request_region(0xa0,0x20,"pic2"); request_region(0x00,0x20,"dma1"); diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index ff7452e5d8e5..7c5cdabf6f3c 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -14,6 +14,9 @@ obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ pmac_low_i2c.o pmac_cache.o obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o \ chrp_pegasos_eth.o +ifeq ($(CONFIG_PPC_CHRP),y) +obj-$(CONFIG_NVRAM) += chrp_nvram.o +endif obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o ifeq ($(CONFIG_PPC_PMAC),y) obj-$(CONFIG_NVRAM) += pmac_nvram.o diff --git a/arch/ppc/platforms/chrp_nvram.c b/arch/ppc/platforms/chrp_nvram.c new file mode 100644 index 000000000000..465ba9b090ef --- /dev/null +++ b/arch/ppc/platforms/chrp_nvram.c @@ -0,0 +1,83 @@ +/* + * c 2001 PPC 64 Team, 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. + * + * /dev/nvram driver for PPC + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned int nvram_size; +static unsigned char nvram_buf[4]; +static DEFINE_SPINLOCK(nvram_lock); + +static unsigned char chrp_nvram_read(int addr) +{ + unsigned long done, flags; + unsigned char ret; + + if (addr >= nvram_size) { + printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n", + current->comm, addr, nvram_size); + return 0xff; + } + spin_lock_irqsave(&nvram_lock, flags); + if ((call_rtas("nvram-fetch", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) + ret = 0xff; + else + ret = nvram_buf[0]; + spin_unlock_irqrestore(&nvram_lock, flags); + + return ret; +} + +static void chrp_nvram_write(int addr, unsigned char val) +{ + unsigned long done, flags; + + if (addr >= nvram_size) { + printk(KERN_DEBUG "%s: write addr %d > nvram_size %u\n", + current->comm, addr, nvram_size); + return; + } + spin_lock_irqsave(&nvram_lock, flags); + nvram_buf[0] = val; + if ((call_rtas("nvram-store", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) + printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr); + spin_unlock_irqrestore(&nvram_lock, flags); +} + +void __init chrp_nvram_init(void) +{ + struct device_node *nvram; + unsigned int *nbytes_p, proplen; + + nvram = of_find_node_by_type(NULL, "nvram"); + if (nvram == NULL) + return; + + nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen); + if (nbytes_p == NULL || proplen != sizeof(unsigned int)) + return; + + nvram_size = *nbytes_p; + + printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size); + of_node_put(nvram); + + ppc_md.nvram_read_val = chrp_nvram_read; + ppc_md.nvram_write_val = chrp_nvram_write; + + return; +} diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index dad81ffd4013..f1b70ab3c6fd 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -454,8 +454,7 @@ void __init chrp_init2(void) { #ifdef CONFIG_NVRAM -// XX replace this in a more saner way -// pmac_nvram_init(); + chrp_nvram_init(); #endif request_region(0x20,0x20,"pic1"); diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index eb30c09516ae..bd99cb53a19f 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -70,6 +70,7 @@ extern void _set_L3CR(unsigned long); #endif extern void via_cuda_init(void); extern void pmac_nvram_init(void); +extern void chrp_nvram_init(void); extern void read_rtc_time(void); extern void pmac_find_display(void); extern void giveup_fpu(struct task_struct *); From dcb34abb4d9bae0588c5c11101ed6afcee71f895 Mon Sep 17 00:00:00 2001 From: "scwhab@suse.de" Date: Fri, 28 Oct 2005 17:46:20 -0700 Subject: [PATCH 1223/1939] [PATCH] Add modalias to macio sysfs attributes Provide a "compatible" entry in /sys/bus/macio/devices/*/ This can be used to load drivers via the modules.alias file. Signed-off-by: Olaf Hering Acked-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/macintosh/macio_sysfs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c index 97d22bb4516a..7f7d4eaca870 100644 --- a/drivers/macintosh/macio_sysfs.c +++ b/drivers/macintosh/macio_sysfs.c @@ -39,6 +39,31 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf) return length; } +static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct of_device *of; + char *compat; + int cplen; + int length; + + of = &to_macio_device (dev)->ofdev; + compat = (char *) get_property (of->node, "compatible", &cplen); + if (!compat) compat = "", cplen = 1; + length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type); + buf += length; + while (cplen > 0) { + int l; + length += sprintf (buf, "C%s", compat); + buf += length; + l = strlen (compat) + 1; + compat += l; + cplen -= l; + } + + return length; +} + macio_config_of_attr (name, "%s\n"); macio_config_of_attr (type, "%s\n"); @@ -46,5 +71,6 @@ struct device_attribute macio_dev_attrs[] = { __ATTR_RO(name), __ATTR_RO(type), __ATTR_RO(compatible), + __ATTR_RO(modalias), __ATTR_NULL }; From 8c9795ba01d02b043ce2d9eeb0fa908c07e5fb42 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:21 -0700 Subject: [PATCH 1224/1939] [PATCH] Add modalias for pmac network drivers mesh, mac53c94 and airport already have an entry. Add the network drivers for pmac. Signed-off-by: Olaf Hering Acked-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/net/bmac.c | 1 + drivers/net/mace.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 60dba4a1ca5c..0ee28899fb8d 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1658,6 +1658,7 @@ static struct of_device_id bmac_match[] = }, {}, }; +MODULE_DEVICE_TABLE (of, bmac_match); static struct macio_driver bmac_driver = { diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 81d0a26e4f41..f2fc1f26cd4b 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -1016,6 +1016,7 @@ static struct of_device_id mace_match[] = }, {}, }; +MODULE_DEVICE_TABLE (of, mace_match); static struct macio_driver mace_driver = { From dd03d25fac90ee6f394874fb4e6995866304e4ba Mon Sep 17 00:00:00 2001 From: Nicolas DET Date: Fri, 28 Oct 2005 17:46:25 -0700 Subject: [PATCH 1225/1939] [PATCH] chrp_pegasos_eth: Added Marvell Discovery II SRAM support Add proper entry to support the Marvell MV64361 (Marvell Discovery II) SRAM. This feature may be used by the mv643xx_eth driver. Signed-off-by: Nicolas DET Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/chrp/pegasos_eth.c | 124 ++++++++++++++++++++-- arch/ppc/platforms/chrp_pegasos_eth.c | 124 ++++++++++++++++++++-- 2 files changed, 236 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/platforms/chrp/pegasos_eth.c b/arch/powerpc/platforms/chrp/pegasos_eth.c index cad5bfa153b2..a9052305c35d 100644 --- a/arch/powerpc/platforms/chrp/pegasos_eth.c +++ b/arch/powerpc/platforms/chrp/pegasos_eth.c @@ -17,7 +17,20 @@ #include #include -/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */ +#define PEGASOS2_MARVELL_REGBASE (0xf1000000) +#define PEGASOS2_MARVELL_REGSIZE (0x00004000) +#define PEGASOS2_SRAM_BASE (0xf2000000) +#define PEGASOS2_SRAM_SIZE (256*1024) + +#define PEGASOS2_SRAM_BASE_ETH0 (PEGASOS2_SRAM_BASE) +#define PEGASOS2_SRAM_BASE_ETH1 (PEGASOS2_SRAM_BASE_ETH0 + (PEGASOS2_SRAM_SIZE / 2) ) + + +#define PEGASOS2_SRAM_RXRING_SIZE (PEGASOS2_SRAM_SIZE/4) +#define PEGASOS2_SRAM_TXRING_SIZE (PEGASOS2_SRAM_SIZE/4) + +#undef BE_VERBOSE + static struct resource mv643xx_eth_shared_resources[] = { [0] = { .name = "ethernet shared base", @@ -44,7 +57,16 @@ static struct resource mv643xx_eth0_resources[] = { }, }; -static struct mv643xx_eth_platform_data eth0_pd; + +static struct mv643xx_eth_platform_data eth0_pd = { + .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0, + .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, + .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, + + .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH0 + PEGASOS2_SRAM_TXRING_SIZE, + .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, + .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, +}; static struct platform_device eth0_device = { .name = MV643XX_ETH_NAME, @@ -65,7 +87,15 @@ static struct resource mv643xx_eth1_resources[] = { }, }; -static struct mv643xx_eth_platform_data eth1_pd; +static struct mv643xx_eth_platform_data eth1_pd = { + .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1, + .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, + .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, + + .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH1 + PEGASOS2_SRAM_TXRING_SIZE, + .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, + .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, +}; static struct platform_device eth1_device = { .name = MV643XX_ETH_NAME, @@ -83,9 +113,62 @@ static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { ð1_device, }; +/***********/ +/***********/ +#define MV_READ(offset,val) { val = readl(mv643xx_reg_base + offset); } +#define MV_WRITE(offset,data) writel(data, mv643xx_reg_base + offset) -int -mv643xx_eth_add_pds(void) +static void __iomem *mv643xx_reg_base; + +static int Enable_SRAM(void) +{ + u32 ALong; + + if (mv643xx_reg_base == NULL) + mv643xx_reg_base = ioremap(PEGASOS2_MARVELL_REGBASE, + PEGASOS2_MARVELL_REGSIZE); + + if (mv643xx_reg_base == NULL) + return -ENOMEM; + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: register remapped from %p to %p\n", + (void *)PEGASOS2_MARVELL_REGBASE, (void *)mv643xx_reg_base); +#endif + + MV_WRITE(MV64340_SRAM_CONFIG, 0); + + MV_WRITE(MV64340_INTEGRATED_SRAM_BASE_ADDR, PEGASOS2_SRAM_BASE >> 16); + + MV_READ(MV64340_BASE_ADDR_ENABLE, ALong); + ALong &= ~(1 << 19); + MV_WRITE(MV64340_BASE_ADDR_ENABLE, ALong); + + ALong = 0x02; + ALong |= PEGASOS2_SRAM_BASE & 0xffff0000; + MV_WRITE(MV643XX_ETH_BAR_4, ALong); + + MV_WRITE(MV643XX_ETH_SIZE_REG_4, (PEGASOS2_SRAM_SIZE-1) & 0xffff0000); + + MV_READ(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); + ALong &= ~(1 << 4); + MV_WRITE(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: register unmapped\n"); + printk("Pegasos II/Marvell MV64361: SRAM at %p, size=%x\n", (void*) PEGASOS2_SRAM_BASE, PEGASOS2_SRAM_SIZE); +#endif + + iounmap(mv643xx_reg_base); + mv643xx_reg_base = NULL; + + return 1; +} + + +/***********/ +/***********/ +int mv643xx_eth_add_pds(void) { int ret = 0; static struct pci_device_id pci_marvell_mv64360[] = { @@ -93,9 +176,38 @@ mv643xx_eth_add_pds(void) { } }; +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: init\n"); +#endif + if (pci_dev_present(pci_marvell_mv64360)) { - ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs)); + ret = platform_add_devices(mv643xx_eth_pd_devs, + ARRAY_SIZE(mv643xx_eth_pd_devs)); + + if ( Enable_SRAM() < 0) + { + eth0_pd.tx_sram_addr = 0; + eth0_pd.tx_sram_size = 0; + eth0_pd.rx_sram_addr = 0; + eth0_pd.rx_sram_size = 0; + + eth1_pd.tx_sram_addr = 0; + eth1_pd.tx_sram_size = 0; + eth1_pd.rx_sram_addr = 0; + eth1_pd.rx_sram_size = 0; + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: Can't enable the " + "SRAM\n"); +#endif + } } + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: init is over\n"); +#endif + return ret; } + device_initcall(mv643xx_eth_add_pds); diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c index cad5bfa153b2..a9052305c35d 100644 --- a/arch/ppc/platforms/chrp_pegasos_eth.c +++ b/arch/ppc/platforms/chrp_pegasos_eth.c @@ -17,7 +17,20 @@ #include #include -/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */ +#define PEGASOS2_MARVELL_REGBASE (0xf1000000) +#define PEGASOS2_MARVELL_REGSIZE (0x00004000) +#define PEGASOS2_SRAM_BASE (0xf2000000) +#define PEGASOS2_SRAM_SIZE (256*1024) + +#define PEGASOS2_SRAM_BASE_ETH0 (PEGASOS2_SRAM_BASE) +#define PEGASOS2_SRAM_BASE_ETH1 (PEGASOS2_SRAM_BASE_ETH0 + (PEGASOS2_SRAM_SIZE / 2) ) + + +#define PEGASOS2_SRAM_RXRING_SIZE (PEGASOS2_SRAM_SIZE/4) +#define PEGASOS2_SRAM_TXRING_SIZE (PEGASOS2_SRAM_SIZE/4) + +#undef BE_VERBOSE + static struct resource mv643xx_eth_shared_resources[] = { [0] = { .name = "ethernet shared base", @@ -44,7 +57,16 @@ static struct resource mv643xx_eth0_resources[] = { }, }; -static struct mv643xx_eth_platform_data eth0_pd; + +static struct mv643xx_eth_platform_data eth0_pd = { + .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0, + .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, + .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, + + .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH0 + PEGASOS2_SRAM_TXRING_SIZE, + .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, + .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, +}; static struct platform_device eth0_device = { .name = MV643XX_ETH_NAME, @@ -65,7 +87,15 @@ static struct resource mv643xx_eth1_resources[] = { }, }; -static struct mv643xx_eth_platform_data eth1_pd; +static struct mv643xx_eth_platform_data eth1_pd = { + .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1, + .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, + .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, + + .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH1 + PEGASOS2_SRAM_TXRING_SIZE, + .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, + .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, +}; static struct platform_device eth1_device = { .name = MV643XX_ETH_NAME, @@ -83,9 +113,62 @@ static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { ð1_device, }; +/***********/ +/***********/ +#define MV_READ(offset,val) { val = readl(mv643xx_reg_base + offset); } +#define MV_WRITE(offset,data) writel(data, mv643xx_reg_base + offset) -int -mv643xx_eth_add_pds(void) +static void __iomem *mv643xx_reg_base; + +static int Enable_SRAM(void) +{ + u32 ALong; + + if (mv643xx_reg_base == NULL) + mv643xx_reg_base = ioremap(PEGASOS2_MARVELL_REGBASE, + PEGASOS2_MARVELL_REGSIZE); + + if (mv643xx_reg_base == NULL) + return -ENOMEM; + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: register remapped from %p to %p\n", + (void *)PEGASOS2_MARVELL_REGBASE, (void *)mv643xx_reg_base); +#endif + + MV_WRITE(MV64340_SRAM_CONFIG, 0); + + MV_WRITE(MV64340_INTEGRATED_SRAM_BASE_ADDR, PEGASOS2_SRAM_BASE >> 16); + + MV_READ(MV64340_BASE_ADDR_ENABLE, ALong); + ALong &= ~(1 << 19); + MV_WRITE(MV64340_BASE_ADDR_ENABLE, ALong); + + ALong = 0x02; + ALong |= PEGASOS2_SRAM_BASE & 0xffff0000; + MV_WRITE(MV643XX_ETH_BAR_4, ALong); + + MV_WRITE(MV643XX_ETH_SIZE_REG_4, (PEGASOS2_SRAM_SIZE-1) & 0xffff0000); + + MV_READ(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); + ALong &= ~(1 << 4); + MV_WRITE(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: register unmapped\n"); + printk("Pegasos II/Marvell MV64361: SRAM at %p, size=%x\n", (void*) PEGASOS2_SRAM_BASE, PEGASOS2_SRAM_SIZE); +#endif + + iounmap(mv643xx_reg_base); + mv643xx_reg_base = NULL; + + return 1; +} + + +/***********/ +/***********/ +int mv643xx_eth_add_pds(void) { int ret = 0; static struct pci_device_id pci_marvell_mv64360[] = { @@ -93,9 +176,38 @@ mv643xx_eth_add_pds(void) { } }; +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: init\n"); +#endif + if (pci_dev_present(pci_marvell_mv64360)) { - ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs)); + ret = platform_add_devices(mv643xx_eth_pd_devs, + ARRAY_SIZE(mv643xx_eth_pd_devs)); + + if ( Enable_SRAM() < 0) + { + eth0_pd.tx_sram_addr = 0; + eth0_pd.tx_sram_size = 0; + eth0_pd.rx_sram_addr = 0; + eth0_pd.rx_sram_size = 0; + + eth1_pd.tx_sram_addr = 0; + eth1_pd.tx_sram_size = 0; + eth1_pd.rx_sram_addr = 0; + eth1_pd.rx_sram_size = 0; + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: Can't enable the " + "SRAM\n"); +#endif + } } + +#ifdef BE_VERBOSE + printk("Pegasos II/Marvell MV64361: init is over\n"); +#endif + return ret; } + device_initcall(mv643xx_eth_add_pds); From b37665e0ba1d3f05697bfae249b09a2e9cc95132 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 28 Oct 2005 17:46:27 -0700 Subject: [PATCH 1226/1939] [PATCH] ppc32: 85xx PHY Platform Update This patch updates the 85xx platform code to support the new PHY Layer. Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/platforms/85xx/mpc8540_ads.c | 30 ++++--- arch/ppc/platforms/85xx/mpc8560_ads.c | 25 ++++-- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 34 ++++---- arch/ppc/platforms/85xx/sbc8560.c | 22 +++-- arch/ppc/platforms/85xx/stx_gp3.c | 21 +++-- arch/ppc/syslib/mpc85xx_devices.c | 17 ++-- arch/ppc/syslib/mpc85xx_sys.c | 88 +++++++++++--------- include/asm-ppc/mpc85xx.h | 3 + include/linux/fsl_devices.h | 13 ++- 9 files changed, 153 insertions(+), 100 deletions(-) diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index 7dc8a68acfd0..7e952c1228cb 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -52,6 +52,10 @@ #include +static const char *GFAR_PHY_0 = "phy0:0"; +static const char *GFAR_PHY_1 = "phy0:1"; +static const char *GFAR_PHY_3 = "phy0:3"; + /* ************************************************************************ * * Setup the architecture @@ -63,6 +67,7 @@ mpc8540ads_setup_arch(void) bd_t *binfo = (bd_t *) __res; unsigned int freq; struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; /* get the core frequency */ freq = binfo->bi_intfreq; @@ -89,34 +94,35 @@ mpc8540ads_setup_arch(void) invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[0] = MPC85xx_IRQ_EXT5; + mdata->irq[1] = MPC85xx_IRQ_EXT5; + mdata->irq[2] = -1; + mdata->irq[3] = MPC85xx_IRQ_EXT5; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_0; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_1; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC); if (pdata) { pdata->board_flags = 0; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 3; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_3; memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6); } diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index 8841fd7da6ee..208433f1e93a 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -56,6 +56,10 @@ #include +static const char *GFAR_PHY_0 = "phy0:0"; +static const char *GFAR_PHY_1 = "phy0:1"; +static const char *GFAR_PHY_3 = "phy0:3"; + /* ************************************************************************ * * Setup the architecture @@ -68,6 +72,7 @@ mpc8560ads_setup_arch(void) bd_t *binfo = (bd_t *) __res; unsigned int freq; struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; cpm2_reset(); @@ -86,24 +91,28 @@ mpc8560ads_setup_arch(void) mpc85xx_setup_hose(); #endif + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[0] = MPC85xx_IRQ_EXT5; + mdata->irq[1] = MPC85xx_IRQ_EXT5; + mdata->irq[2] = -1; + mdata->irq[3] = MPC85xx_IRQ_EXT5; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_0; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_1; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index eda659916f24..a21156967a5e 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -391,6 +391,9 @@ mpc85xx_cds_pcibios_fixup(void) TODC_ALLOC(); +static const char *GFAR_PHY_0 = "phy0:0"; +static const char *GFAR_PHY_1 = "phy0:1"; + /* ************************************************************************ * * Setup the architecture @@ -402,6 +405,7 @@ mpc85xx_cds_setup_arch(void) bd_t *binfo = (bd_t *) __res; unsigned int freq; struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; /* get the core frequency */ freq = binfo->bi_intfreq; @@ -445,44 +449,42 @@ mpc85xx_cds_setup_arch(void) invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[0] = MPC85xx_IRQ_EXT5; + mdata->irq[1] = MPC85xx_IRQ_EXT5; + mdata->irq[2] = -1; + mdata->irq[3] = -1; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_0; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_1; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC1); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_0; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC2); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_1; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index c76760a781c1..b4ee1707a836 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -91,6 +91,9 @@ sbc8560_early_serial_map(void) } #endif +static const char *GFAR_PHY_25 = "phy0:25"; +static const char *GFAR_PHY_26 = "phy0:26"; + /* ************************************************************************ * * Setup the architecture @@ -102,6 +105,7 @@ sbc8560_setup_arch(void) bd_t *binfo = (bd_t *) __res; unsigned int freq; struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; /* get the core frequency */ freq = binfo->bi_intfreq; @@ -126,24 +130,26 @@ sbc8560_setup_arch(void) invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[25] = MPC85xx_IRQ_EXT6; + mdata->irq[26] = MPC85xx_IRQ_EXT7; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT6; - pdata->phyid = 25; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_25; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); if (pdata) { pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT7; - pdata->phyid = 26; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_26; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 20940f4044f4..1e1b85f8193a 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -91,6 +91,9 @@ static u8 gp3_openpic_initsenses[] __initdata = { 0x0, /* External 11: */ }; +static const char *GFAR_PHY_2 = "phy0:2"; +static const char *GFAR_PHY_4 = "phy0:4"; + /* * Setup the architecture */ @@ -100,6 +103,7 @@ gp3_setup_arch(void) bd_t *binfo = (bd_t *) __res; unsigned int freq; struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; cpm2_reset(); @@ -118,23 +122,26 @@ gp3_setup_arch(void) mpc85xx_setup_hose(); #endif + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[2] = MPC85xx_IRQ_EXT5; + mdata->irq[4] = MPC85xx_IRQ_EXT5; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); if (pdata) { /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 2; - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_2; memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); if (pdata) { /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 4; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; + pdata->bus_id = GFAR_PHY_4; memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index bbc5ac0de878..2ede677a0a53 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -25,19 +25,20 @@ /* We use offsets for IORESOURCE_MEM since we do not know at compile time * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup */ +struct gianfar_mdio_data mpc85xx_mdio_pdata = { + .paddr = MPC85xx_MIIM_OFFSET, +}; static struct gianfar_platform_data mpc85xx_tsec1_pdata = { .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_tsec2_pdata = { .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_etsec1_pdata = { @@ -46,7 +47,6 @@ static struct gianfar_platform_data mpc85xx_etsec1_pdata = { FSL_GIANFAR_DEV_HAS_MULTI_INTR | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_etsec2_pdata = { @@ -55,7 +55,6 @@ static struct gianfar_platform_data mpc85xx_etsec2_pdata = { FSL_GIANFAR_DEV_HAS_MULTI_INTR | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_etsec3_pdata = { @@ -64,7 +63,6 @@ static struct gianfar_platform_data mpc85xx_etsec3_pdata = { FSL_GIANFAR_DEV_HAS_MULTI_INTR | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_etsec4_pdata = { @@ -73,11 +71,10 @@ static struct gianfar_platform_data mpc85xx_etsec4_pdata = { FSL_GIANFAR_DEV_HAS_MULTI_INTR | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, - .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; static struct gianfar_platform_data mpc85xx_fec_pdata = { - .phy_reg_addr = MPC85xx_ENET1_OFFSET, + .device_flags = 0, }; static struct fsl_i2c_platform_data mpc85xx_fsl_i2c_pdata = { @@ -719,6 +716,12 @@ struct platform_device ppc_sys_platform_devices[] = { }, }, }, + [MPC85xx_MDIO] = { + .name = "fsl-gianfar_mdio", + .id = 0, + .dev.platform_data = &mpc85xx_mdio_pdata, + .num_resources = 0, + }, }; static int __init mach_mpc85xx_fixup(struct platform_device *pdev) diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c index 6e3184ab354f..cb68d8c58348 100644 --- a/arch/ppc/syslib/mpc85xx_sys.c +++ b/arch/ppc/syslib/mpc85xx_sys.c @@ -24,19 +24,19 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "8540", .mask = 0xFFFF0000, .value = 0x80300000, - .num_devices = 10, + .num_devices = 11, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_FEC, MPC85xx_IIC1, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, - MPC85xx_PERFMON, MPC85xx_DUART, + MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_MDIO, }, }, { .ppc_sys_name = "8560", .mask = 0xFFFF0000, .value = 0x80700000, - .num_devices = 19, + .num_devices = 20, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1, @@ -45,14 +45,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1, MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3, MPC85xx_CPM_SCC4, MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3, - MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2, + MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2, MPC85xx_MDIO, }, }, { .ppc_sys_name = "8541", .mask = 0xFFFF0000, .value = 0x80720000, - .num_devices = 13, + .num_devices = 14, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1, @@ -60,13 +60,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8541E", .mask = 0xFFFF0000, .value = 0x807A0000, - .num_devices = 14, + .num_devices = 15, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1, @@ -74,13 +75,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8555", .mask = 0xFFFF0000, .value = 0x80710000, - .num_devices = 19, + .num_devices = 20, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1, @@ -91,13 +93,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2, MPC85xx_CPM_USB, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8555E", .mask = 0xFFFF0000, .value = 0x80790000, - .num_devices = 20, + .num_devices = 21, .device_list = (enum ppc_sys_devices[]) { MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1, @@ -108,6 +111,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2, MPC85xx_CPM_USB, + MPC85xx_MDIO, }, }, /* SVRs on 8548 rev1.0 matches for 8548/8547/8545 */ @@ -115,104 +119,112 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "8548E", .mask = 0xFFFF00F0, .value = 0x80390010, - .num_devices = 13, + .num_devices = 14, .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8548", .mask = 0xFFFF00F0, .value = 0x80310010, - .num_devices = 12, - .device_list = (enum ppc_sys_devices[]) - { - MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, - MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, - MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, - MPC85xx_PERFMON, MPC85xx_DUART, - }, - }, - { - .ppc_sys_name = "8547E", - .mask = 0xFFFF00F0, - .value = 0x80390010, .num_devices = 13, .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, + MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + MPC85xx_MDIO, + }, + }, + { + .ppc_sys_name = "8547E", + .mask = 0xFFFF00F0, + .value = 0x80390010, + .num_devices = 14, + .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8547", .mask = 0xFFFF00F0, .value = 0x80310010, - .num_devices = 12, + .num_devices = 13, .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8545E", .mask = 0xFFFF00F0, .value = 0x80390010, - .num_devices = 11, + .num_devices = 12, .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8545", .mask = 0xFFFF00F0, .value = 0x80310010, - .num_devices = 10, - .device_list = (enum ppc_sys_devices[]) - { - MPC85xx_eTSEC1, MPC85xx_eTSEC2, - MPC85xx_IIC1, MPC85xx_IIC2, - MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, - MPC85xx_PERFMON, MPC85xx_DUART, - }, - }, - { - .ppc_sys_name = "8543E", - .mask = 0xFFFF00F0, - .value = 0x803A0010, .num_devices = 11, .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, + MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + MPC85xx_MDIO, + }, + }, + { + .ppc_sys_name = "8543E", + .mask = 0xFFFF00F0, + .value = 0x803A0010, + .num_devices = 12, + .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + MPC85xx_MDIO, }, }, { .ppc_sys_name = "8543", .mask = 0xFFFF00F0, .value = 0x80320010, - .num_devices = 10, + .num_devices = 11, .device_list = (enum ppc_sys_devices[]) { MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_IIC1, MPC85xx_IIC2, MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, MPC85xx_PERFMON, MPC85xx_DUART, + MPC85xx_MDIO, }, }, { /* default match */ diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 516984ee14b5..d98db980cd49 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -67,6 +67,8 @@ extern unsigned char __res[]; #define MPC85xx_DMA3_SIZE (0x00080) #define MPC85xx_ENET1_OFFSET (0x24000) #define MPC85xx_ENET1_SIZE (0x01000) +#define MPC85xx_MIIM_OFFSET (0x24520) +#define MPC85xx_MIIM_SIZE (0x00018) #define MPC85xx_ENET2_OFFSET (0x25000) #define MPC85xx_ENET2_SIZE (0x01000) #define MPC85xx_ENET3_OFFSET (0x26000) @@ -132,6 +134,7 @@ enum ppc_sys_devices { MPC85xx_eTSEC3, MPC85xx_eTSEC4, MPC85xx_IIC2, + MPC85xx_MDIO, }; /* Internal interrupts are all Level Sensitive, and Positive Polarity */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 70f54af87b9f..114d5d59f695 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -47,16 +47,21 @@ struct gianfar_platform_data { /* device specific information */ u32 device_flags; - u32 phy_reg_addr; /* board specific information */ u32 board_flags; - u32 phy_flags; - u32 phyid; - u32 interruptPHY; + const char *bus_id; u8 mac_addr[6]; }; +struct gianfar_mdio_data { + /* device specific information */ + u32 paddr; + + /* board specific information */ + int irq[32]; +}; + /* Flags related to gianfar device features */ #define FSL_GIANFAR_DEV_HAS_GIGABIT 0x00000001 #define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002 From 1461b4ea2bcdfb2a386ad3f3095eeb9d73e4bf55 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Fri, 28 Oct 2005 17:46:28 -0700 Subject: [PATCH 1227/1939] [PATCH] ppc32: ppc_sys fixes for 8xx and 82xx This patch fixes a numbers of issues regarding to that both 8xx and 82xx began to use ppc_sys model: - Platform is now identified by default deviceless SOC, if no BOARD_CHIP_NAME is specified in the bard-specific header. For the list of supported names refer to (arch/ppc/syslib/) mpc8xx_sys.c and mpc82xx_sys.c for 8xx and 82xx respectively. - Fixed a bug in identification by name - if the name was not found, it returned -1 instead of default deviceless ppc_spec. - fixed devices amount in the 8xx platform system descriptions Signed-off-by: Vitaly Bordug Signed-off-by: Marcelo Tosatti Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/platforms/fads.h | 2 ++ arch/ppc/platforms/mpc885ads.h | 2 ++ arch/ppc/syslib/m8260_setup.c | 4 ++++ arch/ppc/syslib/m8xx_setup.c | 2 ++ arch/ppc/syslib/mpc8xx_sys.c | 4 ++-- arch/ppc/syslib/ppc_sys.c | 3 +++ include/asm-ppc/cpm2.h | 3 +++ include/asm-ppc/mpc8260.h | 4 ++++ include/asm-ppc/mpc8xx.h | 4 ++++ 9 files changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h index b60c56450b67..a48fb8d723e4 100644 --- a/arch/ppc/platforms/fads.h +++ b/arch/ppc/platforms/fads.h @@ -25,6 +25,8 @@ #if defined(CONFIG_MPC86XADS) +#define BOARD_CHIP_NAME "MPC86X" + /* U-Boot maps BCSR to 0xff080000 */ #define BCSR_ADDR ((uint)0xff080000) diff --git a/arch/ppc/platforms/mpc885ads.h b/arch/ppc/platforms/mpc885ads.h index eb386635b0fd..a80b7d116b49 100644 --- a/arch/ppc/platforms/mpc885ads.h +++ b/arch/ppc/platforms/mpc885ads.h @@ -88,5 +88,7 @@ #define SICR_ENET_MASK ((uint)0x00ff0000) #define SICR_ENET_CLKRT ((uint)0x002c0000) +#define BOARD_CHIP_NAME "MPC885" + #endif /* __ASM_MPC885ADS_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c index 8f80a42dfdb7..76a2aa4ce65e 100644 --- a/arch/ppc/syslib/m8260_setup.c +++ b/arch/ppc/syslib/m8260_setup.c @@ -62,6 +62,10 @@ m8260_setup_arch(void) if (initrd_start) ROOT_DEV = Root_RAM0; #endif + + identify_ppc_sys_by_name_and_id(BOARD_CHIP_NAME, + in_be32(CPM_MAP_ADDR + CPM_IMMR_OFFSET)); + m82xx_board_setup(); } diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index a192719929d3..97ffbc70574f 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -399,6 +399,8 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, strcpy(cmd_line, (char *)(r6+KERNELBASE)); } + identify_ppc_sys_by_name(BOARD_CHIP_NAME); + ppc_md.setup_arch = m8xx_setup_arch; ppc_md.show_percpuinfo = m8xx_show_percpuinfo; ppc_md.init_IRQ = m8xx_init_IRQ; diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c index a532ccc861c0..3cc27d29e3af 100644 --- a/arch/ppc/syslib/mpc8xx_sys.c +++ b/arch/ppc/syslib/mpc8xx_sys.c @@ -24,7 +24,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "MPC86X", .mask = 0xFFFFFFFF, .value = 0x00000000, - .num_devices = 2, + .num_devices = 7, .device_list = (enum ppc_sys_devices[]) { MPC8xx_CPM_FEC1, @@ -40,7 +40,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "MPC885", .mask = 0xFFFFFFFF, .value = 0x00000000, - .num_devices = 3, + .num_devices = 8, .device_list = (enum ppc_sys_devices[]) { MPC8xx_CPM_FEC1, diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c index 52ba0c68078d..62ee86e80711 100644 --- a/arch/ppc/syslib/ppc_sys.c +++ b/arch/ppc/syslib/ppc_sys.c @@ -69,6 +69,9 @@ static int __init find_chip_by_name_and_id(char *name, u32 id) matched[j++] = i; i++; } + + ret = i; + if (j != 0) { for (i = 0; i < j; i++) { if ((ppc_sys_specs[matched[i]].mask & id) == diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h index 9483d4bfacf7..43d2ebbc7748 100644 --- a/include/asm-ppc/cpm2.h +++ b/include/asm-ppc/cpm2.h @@ -1087,6 +1087,9 @@ typedef struct im_idma { #define SCCR_PCIDF_MSK 0x00000078 /* PCI division factor */ #define SCCR_PCIDF_SHIFT 3 +#ifndef CPM_IMMR_OFFSET +#define CPM_IMMR_OFFSET 0x101a8 +#endif #endif /* __CPM2__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h index 9694eca16e92..321452695039 100644 --- a/include/asm-ppc/mpc8260.h +++ b/include/asm-ppc/mpc8260.h @@ -92,6 +92,10 @@ enum ppc_sys_devices { extern unsigned char __res[]; #endif +#ifndef BOARD_CHIP_NAME +#define BOARD_CHIP_NAME "" +#endif + #endif /* CONFIG_8260 */ #endif /* !__ASM_PPC_MPC8260_H__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h index 208a2e11daee..46f159cf589e 100644 --- a/include/asm-ppc/mpc8xx.h +++ b/include/asm-ppc/mpc8xx.h @@ -113,6 +113,10 @@ enum ppc_sys_devices { MPC8xx_CPM_USB, }; +#ifndef BOARD_CHIP_NAME +#define BOARD_CHIP_NAME "" +#endif + #endif /* !__ASSEMBLY__ */ #endif /* CONFIG_8xx */ #endif /* __CONFIG_8xx_DEFS */ From b1529871f4270d10a0d1a9c998be162f0123d8f1 Mon Sep 17 00:00:00 2001 From: Nicolas DET Date: Fri, 28 Oct 2005 17:46:30 -0700 Subject: [PATCH 1228/1939] [PATCH] mv643xx_eth_showsram: Added information message when using the SRAM Added information message when using the SRAM in mv643xx_eth_probe() Signed-off-by: Nicolas DET Signed-off-by: Sven Luther Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/net/mv643xx_eth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 25c9a99c377b..8fbba21d975b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1533,6 +1533,9 @@ static int mv643xx_eth_probe(struct device *ddev) printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name); #endif + if (mp->tx_sram_size > 0) + printk(KERN_NOTICE "%s: Using SRAM\n", dev->name); + return 0; out: From 9fcc2e8a752f7d3d889114221b67c459557823e9 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Thu, 27 Oct 2005 15:10:01 -0700 Subject: [PATCH 1229/1939] [IPV4]: Fix issue reported by Coverity in ipv4/fib_frontend.c fib_del_ifaddr() dereferences ifa->ifa_dev, so the code already assumes that ifa->ifa_dev is non-NULL, the check is unnecessary. Signed-off-by: Jayachandran C. Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/fib_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e61bc7177eb1..990633c09dfe 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -591,7 +591,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, break; case NETDEV_DOWN: fib_del_ifaddr(ifa); - if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) { + if (ifa->ifa_dev->ifa_list == NULL) { /* Last address was deleted from this interface. Disable IP. */ From 27ac801a2e513708e2da648722326349514976d5 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:35 -0700 Subject: [PATCH 1230/1939] [PATCH] ppc64 boot: remove include from lib/zlib_inflate/inflate.c There is no need to include module.h in inflate.c Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- lib/zlib_inflate/inflate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 3d94cb90c1d3..31b9e9054bf7 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c @@ -3,7 +3,6 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ -#include #include #include "infblock.h" #include "infutil.h" From 146c98782b57531ce6ba89dfa9d3771c0fd0a94d Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:37 -0700 Subject: [PATCH 1231/1939] [PATCH] ppc64 boot: remove include from include/linux/zutil.h zutil.h does not need errno.h Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- include/linux/zutil.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/zutil.h b/include/linux/zutil.h index fdfd5ed41ec4..ee0c59cf2136 100644 --- a/include/linux/zutil.h +++ b/include/linux/zutil.h @@ -15,7 +15,6 @@ #include #include -#include #include typedef unsigned char uch; From 8afe31c9eb92389f091a40def9650278ca66befd Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:37 -0700 Subject: [PATCH 1232/1939] [PATCH] ppc64 boot: missing include for size_t string.h needs definition of size_t, but not the one from linux/include Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/string.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ppc64/boot/string.h b/arch/ppc64/boot/string.h index 9289258bcbd6..9fdff1cc0d70 100644 --- a/arch/ppc64/boot/string.h +++ b/arch/ppc64/boot/string.h @@ -1,5 +1,6 @@ #ifndef _PPC_BOOT_STRING_H_ #define _PPC_BOOT_STRING_H_ +#include extern char *strcpy(char *dest, const char *src); extern char *strncpy(char *dest, const char *src, size_t n); From 7054036fc526b741ba90ff1d077ac900362f30ed Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:38 -0700 Subject: [PATCH 1233/1939] [PATCH] ppc64 boot: remove zlib Switch ppc64 to the in-kernel zlib, it has less bugs than the current one. The code in arch/ppc64/boot is compiled as 32bit, so it can not use the includes from include/asm. Copy all zlib related header files and convert them with sed. Reduce the scratch size to 47k, check possible changes at runtime. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/Makefile | 33 +- arch/ppc64/boot/main.c | 82 +- arch/ppc64/boot/zlib.c | 2195 -------------------------------------- arch/ppc64/boot/zlib.h | 432 -------- 4 files changed, 44 insertions(+), 2698 deletions(-) delete mode 100644 arch/ppc64/boot/zlib.c delete mode 100644 arch/ppc64/boot/zlib.h diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 33fdc8710891..3c78d72a84bb 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -27,10 +27,41 @@ BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds OBJCOPYFLAGS := contents,alloc,load,readonly,data -src-boot := crt0.S string.S prom.c main.c zlib.c imagesize.c div64.S +zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c +zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h +zliblinuxheader := zlib.h zconf.h zutil.h + +$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) +#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h) + +src-boot := crt0.S string.S prom.c main.c imagesize.c div64.S +src-boot += $(zlib) src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) +BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) + +quiet_cmd_copy_zlib = COPY $@ + cmd_copy_zlib = sed "s@__attribute_used__@@;s@]\+\).*@\"\1\"@" $< > $@ + +quiet_cmd_copy_zlibheader = COPY $@ + cmd_copy_zlibheader = sed "s@]\+\).*@\"\1\"@" $< > $@ +# stddef.h for NULL +quiet_cmd_copy_zliblinuxheader = COPY $@ + cmd_copy_zliblinuxheader = sed "s@@\"string.h\"@;s@@@;s@]\+\).*@\"\1\"@" $< > $@ + +$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/% + $(call cmd,copy_zlib) + +$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/% + $(call cmd,copy_zlibheader) + +$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/% + $(call cmd,copy_zliblinuxheader) + +clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) + + quiet_cmd_bootcc = BOOTCC $@ cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index f7ec19a2d0b0..0b95ccfb143c 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -26,12 +26,6 @@ extern void flush_cache(void *, unsigned long); #define RAM_END (512<<20) // Fixme: use OF */ #define ONE_MB 0x100000 -static char *avail_ram; -static char *begin_avail, *end_avail; -static char *avail_high; -static unsigned int heap_use; -static unsigned int heap_max; - extern char _start[]; extern char _end[]; extern char _vmlinux_start[]; @@ -50,7 +44,8 @@ static struct addr_range vmlinux = {0, 0, 0}; static struct addr_range vmlinuz = {0, 0, 0}; static struct addr_range initrd = {0, 0, 0}; -static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ +static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */ + typedef void (*kernel_entry_t)( unsigned long, unsigned long, @@ -161,17 +156,12 @@ void start(unsigned long a1, unsigned long a2, void *promptr) /* Eventually gunzip the kernel */ if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { int len; - avail_ram = scratch; - begin_avail = avail_high = avail_ram; - end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); len = vmlinuz.size; gunzip((void *)vmlinux.addr, vmlinux.size, (unsigned char *)vmlinuz.addr, &len); printf("done 0x%lx bytes\n\r", len); - printf("0x%x bytes of heap consumed, max in use 0x%x\n\r", - (unsigned)(avail_high - begin_avail), heap_max); } else { memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size); } @@ -225,64 +215,12 @@ void start(unsigned long a1, unsigned long a2, void *promptr) exit(); } -struct memchunk { - unsigned int size; - unsigned int pad; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size *= items; - size = _ALIGN(size, sizeof(struct memchunk)); - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n\r"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = _ALIGN(nb, sizeof(struct memchunk)); - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - #define HEAD_CRC 2 #define EXTRA_FIELD 4 #define ORIG_NAME 8 #define COMMENT 0x10 #define RESERVED 0xe0 -#define DEFLATED 8 - static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { z_stream s; @@ -291,7 +229,7 @@ static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) /* skip header */ i = 10; flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { printf("bad gzipped data\n\r"); exit(); } @@ -310,9 +248,13 @@ static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) exit(); } - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); + if (zlib_inflate_workspacesize() > sizeof(scratch)) { + printf("gunzip needs more mem\n"); + exit(); + } + memset(&s, 0, sizeof(s)); + s.workspace = scratch; + r = zlib_inflateInit2(&s, -MAX_WBITS); if (r != Z_OK) { printf("inflateInit2 returned %d\n\r", r); exit(); @@ -321,12 +263,12 @@ static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); + r = zlib_inflate(&s, Z_FINISH); if (r != Z_OK && r != Z_STREAM_END) { printf("inflate returned %d msg: %s\n\r", r, s.msg); exit(); } *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + zlib_inflateEnd(&s); } diff --git a/arch/ppc64/boot/zlib.c b/arch/ppc64/boot/zlib.c deleted file mode 100644 index 0d910cd2079d..000000000000 --- a/arch/ppc64/boot/zlib.c +++ /dev/null @@ -1,2195 +0,0 @@ -/* - * This file is derived from various .h and .c files from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. See zlib.h for conditions of - * distribution and use. - * - * Changes that have been made include: - * - changed functions not used outside this file to "local" - * - added minCompression parameter to deflateInit2 - * - added Z_PACKET_FLUSH (see zlib.h for details) - * - added inflateIncomp - * - Copyright (C) 1995 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 - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu - - * - * - */ - -/*+++++*/ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * 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. - */ - -/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ - -#define _Z_UTIL_H - -#include "zlib.h" - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#define FAR - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern char *z_errmsg[]; /* indexed by 1-zlib_error */ - -#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) -/* To be used only when the state is known to be valid */ - -#ifndef NULL -#define NULL ((void *) 0) -#endif - - /* common constants */ - -#define DEFLATED 8 - -#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 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - - /* functions */ - -extern void *memcpy(void *, const void *, unsigned long); -#define zmemcpy memcpy - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include "stdio.h" -# ifndef verbose -# define verbose 0 -# endif -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); - -/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ -/* void zcfree OF((voidpf opaque, voidpf ptr)); */ - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr, size) \ - (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) -#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} - -/* deflate.h -- internal compression state - * Copyright (C) 1995 Jean-loup Gailly - * 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. - */ - -/*+++++*/ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995 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. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -local inflate_blocks_statef * inflate_blocks_new OF(( - z_stream *z, - check_func c, /* check function */ - uInt w)); /* window size */ - -local int inflate_blocks OF(( - inflate_blocks_statef *, - z_stream *, - int)); /* initial return code */ - -local void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_addhistory OF(( - inflate_blocks_statef *, - z_stream *)); - -local int inflate_packet_flush OF(( - inflate_blocks_statef *)); - -/*+++++*/ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995 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. - */ - -/* 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). */ - -typedef struct inflate_huft_s FAR 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 Nalloc; /* number of these allocated here */ - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - local uInt inflate_hufts; -#endif - -local int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -local int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_stream *)); /* for zfree function */ - - -/*+++++*/ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995 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. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -local inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_stream *)); - -local int inflate_codes OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -local void inflate_codes_free OF(( - inflate_codes_statef *, - z_stream *)); - - -/*+++++*/ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - 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 */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - 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 */ - -}; - - -int inflateReset( - z_stream *z -) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd( - z_stream *z -) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state, sizeof(struct internal_state)); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2( - z_stream *z, - int w -) -{ - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; -/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ -/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_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) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit( - z_stream *z -) -{ - return inflateInit2(z, DEF_WBITS); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate( - z_stream *z, - int f -) -{ - int r; - uInt b; - - if (z == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) - { - z->state->mode = BAD; - z->msg = "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 = BAD; - z->msg = "invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - if ((b = NEXTBYTE) & 0x20) - { - z->state->mode = BAD; - z->msg = "invalid reserved bit"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = "incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - z->state->mode = BLOCKS; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = 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 = BAD; - z->msg = "incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - -/* - * 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 inflateIncomp( - z_stream *z -) -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync( - z_stream *z -) -{ - uInt n; /* number of bytes to look at */ - Bytef *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 == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = 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) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - 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; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE - -/*+++++*/ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995 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. - */ - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - 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 */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ - 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) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - int nblens; /* # elements allocated at blens */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl, *td; /* trees to free */ - 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 */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *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 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 (qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} -#define FLUSH {UPDOUT r=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} - -/* And'ing with mask[n] masks the lower n bits */ -local uInt inflate_mask[] = { - 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 */ -local int inflate_flush OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -/*+++++*/ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995 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. - */ - -local int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_stream *)); - - -/*+++++*/ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* Table for deflate from PKZIP's appnote.txt. */ -local 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. - */ - - -local void inflate_blocks_reset( - inflate_blocks_statef *s, - z_stream *z, - uLongf *c -) -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -local inflate_blocks_statef *inflate_blocks_new( - z_stream *z, - check_func c, - uInt w -) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -local int inflate_blocks( - inflate_blocks_statef *s, - z_stream *z, - int r -) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *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 */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = "invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if (((~b) >> 16) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : TYPE; - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - 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 = BADB; - z->msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.trees.nblens = t; - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - 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 = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - s->mode = BADB; - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - 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 & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.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 & 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 = BADB; - z->msg = "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; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_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 = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BADB; - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local int inflate_blocks_free( - inflate_blocks_statef *s, - z_stream *z, - uLongf *c -) -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window, s->end - s->window); - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - Trace((stderr, "inflate: blocks freed\n")); - 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. - */ -local int 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 */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *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 != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WRAP */ /* expand WRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * 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. - */ -local int inflate_packet_flush( - inflate_blocks_statef *s -) -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} - - -/*+++++*/ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - uIntf *, /* list of base values for non-simple codes */ - uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_stream *)); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -local void ffree OF(( - voidpf q, /* opaque pointer (not used) */ - voidpf p, /* what to free (not used) */ - uInt n)); /* number of bytes (not used) */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local uInt cplens[] = { /* 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}; - /* actually lengths - 2; also see note #13 above about 258 */ -local uInt cplext[] = { /* 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, 192, 192}; /* 192==invalid */ -local uInt cpdist[] = { /* 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}; -local uInt cpdext[] = { /* 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. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build( - uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ - uInt n, /* number of codes (assumed <= N_MAX) */ - uInt s, /* number of simple-valued codes (0..s-1) */ - uIntf *d, /* list of base values for non-simple codes */ - uIntf *e, /* list of extra bits for non-simple codes */ - inflate_huft * FAR *t, /* result: starting table */ - uIntf *m, /* maximum lookup bits, returns actual */ - z_stream *zs /* for zalloc function */ -) -/* 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 (all zero length codes or an - over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - 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) */ - register uIntf *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 */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *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 = (inflate_huft *)Z_NULL; - *m = 0; - return Z_DATA_ERROR; - } - - - /* 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] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_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 = (z = g - w) > (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 */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } - q->word.Nalloc = z + 1; -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* 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 */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* 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 */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -local int inflate_trees_bits( - uIntf *c, /* 19 code lengths */ - uIntf *bb, /* bits tree desired/actual depth */ - inflate_huft * FAR *tb, /* bits tree result */ - z_stream *z /* for zfree function */ -) -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tb, z); - z->msg = "incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -local int inflate_trees_dynamic( - uInt nl, /* number of literal/length codes */ - uInt nd, /* number of distance codes */ - uIntf *c, /* that many (total) code lengths */ - uIntf *bl, /* literal desired/actual bit depth */ - uIntf *bd, /* distance desired/actual bit depth */ - inflate_huft * FAR *tl, /* literal/length tree result */ - inflate_huft * FAR *td, /* distance tree result */ - z_stream *z /* for zfree function */ -) -{ - int r; - - /* build literal/length tree */ - if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_lock = 0; -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local uInt fixed_left = FIXEDH; -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc( - voidpf q, /* opaque pointer (not used) */ - uInt n, /* number of items */ - uInt s /* size of item */ -) -{ - Assert(s == sizeof(inflate_huft) && n <= fixed_left, - "inflate_trees falloc overflow"); - if (q) s++; /* to make some compilers happy */ - fixed_left -= n; - return (voidpf)(fixed_mem + fixed_left); -} - - -local void ffree( - voidpf q, - voidpf p, - uInt n -) -{ - Assert(0, "inflate_trees ffree called!"); - if (q) q = p; /* to make some compilers happy */ -} - - -local int inflate_trees_fixed( - uIntf *bl, /* literal desired/actual bit depth */ - uIntf *bd, /* distance desired/actual bit depth */ - inflate_huft * FAR *tl, /* literal/length tree result */ - inflate_huft * FAR *td /* distance tree result */ -) -{ - /* build fixed tables if not built already--lock out other instances */ - while (++fixed_lock > 1) - fixed_lock--; - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = ffree; - z.opaque = Z_NULL; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - fixed_built = 1; - } - fixed_lock--; - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -local int inflate_trees_free( - inflate_huft *t, /* table to free */ - z_stream *z /* for zfree function */ -) -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); - p = q; - } - return Z_OK; -} - -/*+++++*/ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - 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 */ - 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 */ - -}; - - -local inflate_codes_statef *inflate_codes_new( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, - z_stream *z -) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -local int inflate_codes( - inflate_blocks_statef *s, - z_stream *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 */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *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 = 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 & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", 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->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "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 & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & 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->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "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 & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (q - s->window)); -#endif - 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 */ - 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 - } -} - - -local void inflate_codes_free( - inflate_codes_statef *c, - z_stream *z -) -{ - ZFREE(z, c, sizeof(struct inflate_codes_state)); - Tracev((stderr, "inflate: codes free\n")); -} - -/*+++++*/ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush( - inflate_blocks_statef *s, - z_stream *z, - int r -) -{ - uInt n; - Bytef *p, *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 != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(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 != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - - -/*+++++*/ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#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)<>3);p-=c;k&=7;} - -/* 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. */ - -local int inflate_fast( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, - inflate_blocks_statef *s, - z_stream *z -) -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *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 */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = 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) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* 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 & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = "invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = "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; -} - - -/*+++++*/ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ - -char *zlib_version = ZLIB_VERSION; - -char *z_errmsg[] = { -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -""}; - - -/*+++++*/ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf) {s1 += *buf++; s2 += s1;} -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); -#define DO16(buf) DO8(buf); DO8(buf); - -/* ========================================================================= */ -uLong adler32( - uLong adler, - Bytef *buf, - uInt len -) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - k -= 16; - } - if (k != 0) do { - DO1(buf); - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} diff --git a/arch/ppc64/boot/zlib.h b/arch/ppc64/boot/zlib.h deleted file mode 100644 index f0b996c6864f..000000000000 --- a/arch/ppc64/boot/zlib.h +++ /dev/null @@ -1,432 +0,0 @@ -/* */ - -/* - * This file is derived from zlib.h and zconf.h from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. - */ - -/* - * ==FILEVERSION 960122== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 0.95, Aug 16th, 1995. - - Copyright (C) 1995 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 - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu - */ - -#ifndef _ZLIB_H -#define _ZLIB_H - -/* #include "zconf.h" */ /* included directly here */ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ - -/* - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. - */ - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints - * at addresses which are not a multiple of their size. - * Under DOS, -DFAR=far or -DFAR=__far may be needed. - */ - -#ifndef STDC -# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) -# define STDC -# endif -#endif - -#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ -# include -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -#ifndef FAR -# define FAR -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -/* end of original zconf.h */ - -#define ZLIB_VERSION "0.95P" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same - stream interface. - - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidp opaque; /* private data object passed to zalloc and zfree */ - - Byte data_type; /* best guess about the data type: ascii or binary */ - -} z_stream; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_FULL_FLUSH 2 -#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ -#define Z_FINISH 4 -#define Z_PACKET_FLUSH 5 -/* See deflate() below for the usage of these constants */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -/* error codes for the compression/decompression functions */ - -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Used to set the data_type field */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -extern char *zlib_version; -/* The application can compare zlib_version 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. - */ - - /* basic functions */ - -extern int inflateInit OF((z_stream *strm)); -/* - Initializes the internal stream state for decompression. The fields - zalloc and zfree must be initialized before by the caller. If zalloc and - zfree are set to Z_NULL, inflateInit updates them to use default allocation - functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory. msg is set to null if there is no error message. - inflateInit does not perform any decompression: this will be done by - inflate(). -*/ - - -extern int inflate OF((z_stream *strm, int flush)); -/* - Performs one or both of the following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() always provides as much output as possible - (until there is no more input data or no more space in the output buffer). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). - - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_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_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. - - 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 - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - 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 - may be used for the single inflate() call. - - 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_DATA_ERROR if the input data was corrupted, 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. */ - - -extern int inflateEnd OF((z_stream *strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* advanced functions */ - -extern int inflateInit2 OF((z_stream *strm, - int windowBits)); -/* - This is another version of inflateInit with more compression options. The - fields next_out, zalloc and zfree must be initialized before by the caller. - - 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 value 16 will be allowed soon). 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. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1< Date: Fri, 28 Oct 2005 17:46:40 -0700 Subject: [PATCH 1234/1939] [PATCH] ppc64 boot: remove need for imagesize.c Compute the vmlinux size at runtime. Use Z_FULL_FLUSH instead of Z_FINISH, to extract only the ELF header and ELF program header. ->p_memsz is the required memory range for the executable, including bss ->p_filesz is the size of .text, .data and other runtime sections These values must be used for the claim call. All additional memory needed by the kernel is claimed in prom_init, remove the extra Mb. Pass the full memsize as target area to gunzip, otherwise not everything will be uncompressed. flush_cache has to flush all runtime sections, do not reduce the memrange by the ->p_offset value because its just that: an offset. Remove the Makefile code to produce an imagesize.c, its not needed anymore. Remove all FORCE flags, to not rebuild the zImage if vmlinux was not changed. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/Makefile | 32 ++++++---------- arch/ppc64/boot/main.c | 80 ++++++++++++++++++++-------------------- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 3c78d72a84bb..d79dfd60d8f8 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -34,7 +34,7 @@ zliblinuxheader := zlib.h zconf.h zutil.h $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h) -src-boot := crt0.S string.S prom.c main.c imagesize.c div64.S +src-boot := crt0.S string.S prom.c main.c div64.S src-boot += $(zlib) src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) @@ -87,7 +87,7 @@ src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) hostprogs-y := addnote addRamDisk -targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd imagesize.c \ +targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ @@ -100,9 +100,9 @@ quiet_cmd_ramdisk = RAMDISK $@ quiet_cmd_stripvm = STRIP $@ cmd_stripvm = $(STRIP) -s $< -o $@ -vmlinux.strip: vmlinux FORCE +vmlinux.strip: vmlinux $(call if_changed,stripvm) -$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE +$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz $(call if_changed,ramdisk) quiet_cmd_addsection = ADDSEC $@ @@ -110,48 +110,38 @@ quiet_cmd_addsection = ADDSEC $@ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \ --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS) -quiet_cmd_imagesize = GENSIZE $@ - cmd_imagesize = ls -l vmlinux.strip | \ - awk '{printf "/* generated -- do not edit! */\n" "unsigned long vmlinux_filesize = %d;\n", $$5}' \ - > $(obj)/imagesize.c && \ - $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ - awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' >> $(obj)/imagesize.c - quiet_cmd_addnote = ADDNOTE $@ cmd_addnote = $(obj)/addnote $@ -$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE +$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % $(call if_changed,gzip) $(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz cp -f $(obj)/ramdisk.image.gz $@ -$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz FORCE +$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz @touch $@ -$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c FORCE +$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c $(call if_changed_dep,bootcc) $(call cmd,addsection) $(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required)) -$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) FORCE +$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(call cmd,bootld,$(obj-boot)) $(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd)) -$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) FORCE +$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(call cmd,bootld,$(obj-boot)) -$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote FORCE +$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote @cp -f $< $@ $(call if_changed,addnote) -$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote FORCE +$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote @cp -f $< $@ $(call if_changed,addnote) -$(obj)/imagesize.c: vmlinux.strip - $(call cmd,imagesize) - install: $(CONFIGURE) $(BOOTIMAGE) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)" diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index 0b95ccfb143c..7485dcbf80bc 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -32,8 +32,6 @@ extern char _vmlinux_start[]; extern char _vmlinux_end[]; extern char _initrd_start[]; extern char _initrd_end[]; -extern unsigned long vmlinux_filesize; -extern unsigned long vmlinux_memsize; struct addr_range { unsigned long addr; @@ -45,6 +43,7 @@ static struct addr_range vmlinuz = {0, 0, 0}; static struct addr_range initrd = {0, 0, 0}; static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */ +static char elfheader[256]; typedef void (*kernel_entry_t)( unsigned long, @@ -78,6 +77,7 @@ static unsigned long try_claim(unsigned long size) void start(unsigned long a1, unsigned long a2, void *promptr) { unsigned long i; + int len; kernel_entry_t kernel_entry; Elf64_Ehdr *elf64; Elf64_Phdr *elf64ph; @@ -113,25 +113,45 @@ void start(unsigned long a1, unsigned long a2, void *promptr) claim_base = PROG_START; #endif - /* - * Now we try to claim some memory for the kernel itself - * our "vmlinux_memsize" is the memory footprint in RAM, _HOWEVER_, what - * our Makefile stuffs in is an image containing all sort of junk including - * an ELF header. We need to do some calculations here to find the right - * size... In practice we add 1Mb, that is enough, but we should really - * consider fixing the Makefile to put a _raw_ kernel in there ! - */ - vmlinux_memsize += ONE_MB; - printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); - vmlinux.addr = try_claim(vmlinux_memsize); + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + + /* gunzip the ELF header of the kernel */ + if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + len = vmlinuz.size; + gunzip(elfheader, sizeof(elfheader), + (unsigned char *)vmlinuz.addr, &len); + } else + memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader)); + + elf64 = (Elf64_Ehdr *)elfheader; + if ( elf64->e_ident[EI_MAG0] != ELFMAG0 || + elf64->e_ident[EI_MAG1] != ELFMAG1 || + elf64->e_ident[EI_MAG2] != ELFMAG2 || + elf64->e_ident[EI_MAG3] != ELFMAG3 || + elf64->e_ident[EI_CLASS] != ELFCLASS64 || + elf64->e_ident[EI_DATA] != ELFDATA2MSB || + elf64->e_type != ET_EXEC || + elf64->e_machine != EM_PPC64 ) + { + printf("Error: not a valid PPC64 ELF file!\n\r"); + exit(); + } + + elf64ph = (Elf64_Phdr *)((unsigned long)elf64 + + (unsigned long)elf64->e_phoff); + for(i=0; i < (unsigned int)elf64->e_phnum ;i++,elf64ph++) { + if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0) + break; + } + vmlinux.size = (unsigned long)elf64ph->p_filesz; + vmlinux.memsize = (unsigned long)elf64ph->p_memsz; + printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize); + vmlinux.addr = try_claim(vmlinux.memsize); if (vmlinux.addr == 0) { printf("Can't allocate memory for kernel image !\n\r"); exit(); } - vmlinuz.addr = (unsigned long)_vmlinux_start; - vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); - vmlinux.size = PAGE_ALIGN(vmlinux_filesize); - vmlinux.memsize = vmlinux_memsize; /* * Now we try to claim memory for the initrd (and copy it there) @@ -155,11 +175,10 @@ void start(unsigned long a1, unsigned long a2, void *promptr) /* Eventually gunzip the kernel */ if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { - int len; printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); len = vmlinuz.size; - gunzip((void *)vmlinux.addr, vmlinux.size, + gunzip((void *)vmlinux.addr, vmlinux.memsize, (unsigned char *)vmlinuz.addr, &len); printf("done 0x%lx bytes\n\r", len); } else { @@ -167,32 +186,11 @@ void start(unsigned long a1, unsigned long a2, void *promptr) } /* Skip over the ELF header */ - elf64 = (Elf64_Ehdr *)vmlinux.addr; - if ( elf64->e_ident[EI_MAG0] != ELFMAG0 || - elf64->e_ident[EI_MAG1] != ELFMAG1 || - elf64->e_ident[EI_MAG2] != ELFMAG2 || - elf64->e_ident[EI_MAG3] != ELFMAG3 || - elf64->e_ident[EI_CLASS] != ELFCLASS64 || - elf64->e_ident[EI_DATA] != ELFDATA2MSB || - elf64->e_type != ET_EXEC || - elf64->e_machine != EM_PPC64 ) - { - printf("Error: not a valid PPC64 ELF file!\n\r"); - exit(); - } - - elf64ph = (Elf64_Phdr *)((unsigned long)elf64 + - (unsigned long)elf64->e_phoff); - for(i=0; i < (unsigned int)elf64->e_phnum ;i++,elf64ph++) { - if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0) - break; - } #ifdef DEBUG printf("... skipping 0x%lx bytes of ELF header\n\r", (unsigned long)elf64ph->p_offset); #endif vmlinux.addr += (unsigned long)elf64ph->p_offset; - vmlinux.size -= (unsigned long)elf64ph->p_offset; flush_cache((void *)vmlinux.addr, vmlinux.size); @@ -263,7 +261,7 @@ static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; - r = zlib_inflate(&s, Z_FINISH); + r = zlib_inflate(&s, Z_FULL_FLUSH); if (r != Z_OK && r != Z_STREAM_END) { printf("inflate returned %d msg: %s\n\r", r, s.msg); exit(); From 6bcc20b5ade6c8e9d9a0767090c65024047d91c4 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:41 -0700 Subject: [PATCH 1235/1939] [PATCH] ppc64 boot: move gunzip function before use Move the gunzip function up. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/main.c | 115 ++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index 7485dcbf80bc..d039c47f8e5a 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -17,7 +17,6 @@ #include "prom.h" #include "zlib.h" -static void gunzip(void *, int, unsigned char *, int *); extern void flush_cache(void *, unsigned long); @@ -56,6 +55,63 @@ typedef void (*kernel_entry_t)( unsigned long, static unsigned long claim_base; +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } + + if (zlib_inflate_workspacesize() > sizeof(scratch)) { + printf("gunzip needs more mem\n"); + exit(); + } + memset(&s, 0, sizeof(s)); + s.workspace = scratch; + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FULL_FLUSH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); +} + static unsigned long try_claim(unsigned long size) { unsigned long addr = 0; @@ -213,60 +269,3 @@ void start(unsigned long a1, unsigned long a2, void *promptr) exit(); } -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } - - if (zlib_inflate_workspacesize() > sizeof(scratch)) { - printf("gunzip needs more mem\n"); - exit(); - } - memset(&s, 0, sizeof(s)); - s.workspace = scratch; - r = zlib_inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = zlib_inflate(&s, Z_FULL_FLUSH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - zlib_inflateEnd(&s); -} - From 83097c5d543894864a564cde6c27d4e523d67674 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:43 -0700 Subject: [PATCH 1236/1939] [PATCH] ppc64 boot: bootfiles depend on linker script bootfiles must be relinked if linker script changes Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index d79dfd60d8f8..f8f35999e1a6 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -127,11 +127,11 @@ $(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c $(call cmd,addsection) $(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required)) -$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) +$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds $(call cmd,bootld,$(obj-boot)) $(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd)) -$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) +$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds $(call cmd,bootld,$(obj-boot)) $(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote From 06cf26beffc54bb43aebbefa60f84e0dffde3141 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:44 -0700 Subject: [PATCH 1237/1939] [PATCH] ppc64 boot: cleanup linker script Remove userland related stuff from ld.script, they are not required for zImage use wildcards for some sections. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/zImage.lds | 59 ++++---------------------------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds index 8fe5e7071f54..fb465a4d89b5 100644 --- a/arch/ppc64/boot/zImage.lds +++ b/arch/ppc64/boot/zImage.lds @@ -1,62 +1,19 @@ OUTPUT_ARCH(powerpc:common) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ SECTIONS { - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .plt : { *(.plt) } .text : { *(.text) *(.fixup) - *(.got1) } - . = ALIGN(4096); _etext = .; - PROVIDE (etext = .); - .rodata : - { - *(.rodata) - *(.rodata1) - } - .kstrtab : { *(.kstrtab) } - __vermagic : { *(__vermagic) } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - /* Read-write section, merged into data segment: */ . = ALIGN(4096); .data : { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS + *(.rodata*) + *(.data*) + *(.sdata*) + *(.got*) } . = ALIGN(4096); @@ -71,20 +28,14 @@ SECTIONS . = ALIGN(4096); _edata = .; - PROVIDE (edata = .); - - .fixup : { *(.fixup) } . = ALIGN(4096); __bss_start = .; .bss : { - *(.sbss) *(.scommon) - *(.dynbss) + *(.sbss) *(.bss) - *(COMMON) } . = ALIGN(4096); _end = . ; - PROVIDE (end = .); } From 9b0cbe97566dd7123eee0462d91703434fe61090 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:45 -0700 Subject: [PATCH 1238/1939] [PATCH] ppc64 boot: use memset to clear bss Use memset to clear bss, instead of own version. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/crt0.S | 19 ------------------- arch/ppc64/boot/main.c | 3 +++ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S index 3861e7f9cf19..da6618a865c9 100644 --- a/arch/ppc64/boot/crt0.S +++ b/arch/ppc64/boot/crt0.S @@ -25,24 +25,5 @@ _start: sync isync - ## Clear out the BSS as per ANSI C requirements - - lis r7,_end@ha - addi r7,r7,_end@l # r7 = &_end - lis r8,__bss_start@ha # - addi r8,r8,__bss_start@l # r8 = &_bss_start - - ## Determine how large an area, in number of words, to clear - - subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 - addi r7,r7,3 # r7 += 3 - srwi. r7,r7,2 # r7 = size in words. - beq 3f # If the size is zero, don't bother - addi r8,r8,-4 # r8 -= 4 - mtctr r7 # SPRN_CTR = number of words to clear - li r0,0 # r0 = 0 -2: stwu r0,4(r8) # Clear out a word - bdnz 2b # Keep clearing until done -3: b start diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index d039c47f8e5a..c2c1f3309113 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -26,6 +26,7 @@ extern void flush_cache(void *, unsigned long); #define ONE_MB 0x100000 extern char _start[]; +extern char __bss_start[]; extern char _end[]; extern char _vmlinux_start[]; extern char _vmlinux_end[]; @@ -138,6 +139,8 @@ void start(unsigned long a1, unsigned long a2, void *promptr) Elf64_Ehdr *elf64; Elf64_Phdr *elf64ph; + memset(__bss_start, 0, _end - __bss_start); + prom = (int (*)(void *)) promptr; chosen_handle = finddevice("/chosen"); if (chosen_handle == (void *) -1) From 844ae3a0d1638753802770cde881dff0e0704551 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:46 -0700 Subject: [PATCH 1239/1939] [PATCH] ppc64 boot: fix typo in asm comments Update comment in memcpy, r7 contains the byte count. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/string.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/boot/string.S b/arch/ppc64/boot/string.S index 7ade87ae7718..b1eeaed7db17 100644 --- a/arch/ppc64/boot/string.S +++ b/arch/ppc64/boot/string.S @@ -104,7 +104,7 @@ memmove: .globl memcpy memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */ addi r6,r3,-4 addi r4,r4,-4 beq 2f /* if less than 8 bytes to do */ @@ -146,7 +146,7 @@ memcpy: .globl backwards_memcpy backwards_memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */ add r6,r3,r5 add r4,r4,r5 beq 2f From afbe8c4bb0155f533d6e57edd269c93e2f23c2fa Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:47 -0700 Subject: [PATCH 1240/1939] [PATCH] ppc64 boot: remove global initializers No need to initialize global variables. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index c2c1f3309113..3304ed34c44b 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -38,9 +38,9 @@ struct addr_range { unsigned long size; unsigned long memsize; }; -static struct addr_range vmlinux = {0, 0, 0}; -static struct addr_range vmlinuz = {0, 0, 0}; -static struct addr_range initrd = {0, 0, 0}; +static struct addr_range vmlinux; +static struct addr_range vmlinuz; +static struct addr_range initrd; static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */ static char elfheader[256]; From a4497235f00d811943831c9d76995d36c4ffab2d Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:48 -0700 Subject: [PATCH 1241/1939] [PATCH] ppc64 boot: make the zImage relocateable Make the zImage relocateable. So yaboot could just load and run any ELF binary, without worrying about its load address. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/Makefile | 2 +- arch/ppc64/boot/crt0.S | 29 +++++++++++++++++++++++++++++ arch/ppc64/boot/zImage.lds | 4 +++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index f8f35999e1a6..9e19351f3dfa 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -22,7 +22,7 @@ HOSTCC := gcc -BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem $(shell $(CROSS32CC) -print-file-name=include) +BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem $(shell $(CROSS32CC) -print-file-name=include) -fPIC BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds OBJCOPYFLAGS := contents,alloc,load,readonly,data diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S index da6618a865c9..5788a453a7a2 100644 --- a/arch/ppc64/boot/crt0.S +++ b/arch/ppc64/boot/crt0.S @@ -14,9 +14,38 @@ .text .globl _start _start: + bl reloc_offset + +reloc_offset: + mflr r0 + lis r9,reloc_offset@ha + addi r9,r9,reloc_offset@l + subf. r0,r9,r0 + beq clear_caches + +reloc_got2: + lis r9,__got2_start@ha + addi r9,r9,__got2_start@l + lis r8,__got2_end@ha + addi r8,r8,__got2_end@l + subf. r8,r9,r8 + beq clear_caches + srwi. r8,r8,2 + mtctr r8 + add r9,r0,r9 +reloc_got2_loop: + lwz r8,0(r9) + add r8,r8,r0 + stw r8,0(r9) + addi r9,r9,4 + bdnz reloc_got2_loop + +clear_caches: lis r9,_start@h + add r9,r0,r9 lis r8,_etext@ha addi r8,r8,_etext@l + add r8,r0,r8 1: dcbf r0,r9 icbi r0,r9 addi r9,r9,0x20 diff --git a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds index fb465a4d89b5..79d62c733ec0 100644 --- a/arch/ppc64/boot/zImage.lds +++ b/arch/ppc64/boot/zImage.lds @@ -13,7 +13,9 @@ SECTIONS *(.rodata*) *(.data*) *(.sdata*) - *(.got*) + __got2_start = .; + *(.got2) + __got2_end = .; } . = ALIGN(4096); From 67a1b68263d58a3ed5ce024468606044a1561312 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:49 -0700 Subject: [PATCH 1242/1939] [PATCH] ppc64 boot: proof that reloc works To prove that the relocation works, move the crt0.o away from the beginning. Move linker options from command line into linker script. rename entry point because '_start' is referenced in printf output. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/Makefile | 4 ++-- arch/ppc64/boot/crt0.S | 4 ++-- arch/ppc64/boot/zImage.lds | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 9e19351f3dfa..301bc1536c49 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -24,7 +24,7 @@ HOSTCC := gcc BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem $(shell $(CROSS32CC) -print-file-name=include) -fPIC BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc -BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds +BOOTLFLAGS := -T $(srctree)/$(src)/zImage.lds OBJCOPYFLAGS := contents,alloc,load,readonly,data zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c @@ -34,7 +34,7 @@ zliblinuxheader := zlib.h zconf.h zutil.h $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h) -src-boot := crt0.S string.S prom.c main.c div64.S +src-boot := string.S prom.c main.c div64.S crt0.S src-boot += $(zlib) src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S index 5788a453a7a2..8bfdeaf3be83 100644 --- a/arch/ppc64/boot/crt0.S +++ b/arch/ppc64/boot/crt0.S @@ -12,8 +12,8 @@ #include "ppc_asm.h" .text - .globl _start -_start: + .globl _zimage_start +_zimage_start: bl reloc_offset reloc_offset: diff --git a/arch/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds index 79d62c733ec0..4b6bb3ffe3dc 100644 --- a/arch/ppc64/boot/zImage.lds +++ b/arch/ppc64/boot/zImage.lds @@ -1,6 +1,9 @@ OUTPUT_ARCH(powerpc:common) +ENTRY(_zimage_start) SECTIONS { + . = (4*1024*1024); + _start = .; .text : { *(.text) From 7e658118faa9faf71f8a8295cdaeb7ca71c04672 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:50 -0700 Subject: [PATCH 1243/1939] [PATCH] ppc64 boot: print firmware provided stackpointer Show firmware provided stackpointer during boot. This helps to find the "taboo" areas on the various boards. claim tends to fail for these memory areas, but some jokers return success anyway. Use %p to print the load address, its a pointer. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/crt0.S | 1 + arch/ppc64/boot/main.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S index 8bfdeaf3be83..9cc442263939 100644 --- a/arch/ppc64/boot/crt0.S +++ b/arch/ppc64/boot/crt0.S @@ -54,5 +54,6 @@ clear_caches: sync isync + mr r6,r1 b start diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index 3304ed34c44b..c1dc876bccab 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -131,7 +131,7 @@ static unsigned long try_claim(unsigned long size) return addr; } -void start(unsigned long a1, unsigned long a2, void *promptr) +void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) { unsigned long i; int len; @@ -151,7 +151,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr) if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) exit(); - printf("\n\rzImage starting: loaded at 0x%lx\n\r", (unsigned long) _start); + printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp); /* * The first available claim_base must be above the end of the From 08124f958997ac14bb2284af787752125a892e9f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:51 -0700 Subject: [PATCH 1244/1939] [PATCH] ppc64: AC Power handling broken for desktops Currently, AC Power is 0 on a desktop G4. No batteries present should mean AC Power == 1. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/macintosh/apm_emu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c index 19d3e05d6825..e5a2bbf99399 100644 --- a/drivers/macintosh/apm_emu.c +++ b/drivers/macintosh/apm_emu.c @@ -430,8 +430,8 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) -1: Unknown 8) min = minutes; sec = seconds */ - unsigned short ac_line_status = 0xff; - unsigned short battery_status = 0xff; + unsigned short ac_line_status; + unsigned short battery_status = 0; unsigned short battery_flag = 0xff; int percentage = -1; int time_units = -1; @@ -446,6 +446,7 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); for (i=0; i Date: Fri, 28 Oct 2005 17:46:54 -0700 Subject: [PATCH 1245/1939] [PATCH] ppc64: compile nls_cp437 and nls_iso8859_1 into the kernel in defconfig compile nls_cp437 and nls_iso8859_1 into the kernel in defconfig. This is already enabled in pSeries_defconfig. Reason: if one just boots the new shiny zImage and the root filesystem is on a filesystem not readable by yaboot (like jfs, raid or lvm) upgrading the bootloader will fail because the FAT bootpartition can not be mounted. Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/defconfig b/arch/ppc64/defconfig index 37c157c93cef..e79fd60bc122 100644 --- a/arch/ppc64/defconfig +++ b/arch/ppc64/defconfig @@ -1318,7 +1318,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m CONFIG_NLS_CODEPAGE_850=m @@ -1342,7 +1342,7 @@ CONFIG_NLS_ISO8859_8=m CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m CONFIG_NLS_ISO8859_4=m From 1eee4daa9940f7044806d83006051104cc8680b3 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:55 -0700 Subject: [PATCH 1246/1939] [PATCH] ppc64: reenable make install with defconfig 'make ARCH=ppc64 O=../O install' does not work with the defconfig. CONFIG_PPC_BPA is part of it, but the BPA bootimage variable is wrong: make[2]: *** No rule to make target `zImage', needed by `install'. Stop. Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index db1b25cdb5be..fdbd6f44adc0 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -108,7 +108,7 @@ $(boottargets-y): vmlinux bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage bootimage-$(CONFIG_PPC_PMAC) := vmlinux bootimage-$(CONFIG_PPC_MAPLE) := $(boot)/zImage -bootimage-$(CONFIG_PPC_BPA) := zImage +bootimage-$(CONFIG_PPC_BPA) := $(boot)/zImage bootimage-$(CONFIG_PPC_ISERIES) := vmlinux BOOTIMAGE := $(bootimage-y) install: vmlinux From 18c5332bc17e75efdc02cc17410c647a627861f2 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:56 -0700 Subject: [PATCH 1247/1939] [PATCH] ppc64: change name of target file during make install 'make install' creates a /boot/zImage[.vmode] file when the defconfig is used. It uses the second arg as file content, which is the vmlinux, and the 5th arg as file name, which is the BOOTIMAGE name. A comment in an earlier patch to install.sh states that yaboot can not load a zImage+initrd combo. This was true in kernel 2.6.5 because it did use bi_recs to pass the initrd info. But this concept was always broken. Register r3 holds the initrd address and r4 holds the initrd size. This works with all kernel versions. The current code in main.c leaves r3 and r4 alone, so the kernel should be able to see and use the memory range with the initrd content. If one wants to rerun mkinitrd, it is currently hard to get the uname -r value for the installed zImage. Without this info, mkinitrd can not know what modules to use. This would be fixable by including the /proc/version output of the new kernel. But it is simpler to just use the plain vmlinux. So all this patch does is to write to /boot/vmlinux instead to /boot/zImage Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc64/boot/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc64/boot/install.sh b/arch/ppc64/boot/install.sh index cb2d6626b555..eacce9590816 100644 --- a/arch/ppc64/boot/install.sh +++ b/arch/ppc64/boot/install.sh @@ -28,7 +28,7 @@ if [ -x /sbin/${CROSS_COMPILE}installkernel ]; then exec /sbin/${CROSS_COMPILE}i # Default install # this should work for both the pSeries zImage and the iSeries vmlinux.sm -image_name=`basename $5` +image_name=`basename $2` if [ -f $4/$image_name ]; then mv $4/$image_name $4/$image_name.old From ea6526605a60cf9a6f758605f73062fac6d974cf Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 28 Oct 2005 17:46:57 -0700 Subject: [PATCH 1248/1939] [PATCH] ppc64: remove duplicate local variable in set_preferred_console remove duplicate local variable, saves 2 asm instructions. Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup-common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index aa743a50a20a..1292460fcde2 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -361,7 +361,6 @@ static int __init set_preferred_console(void) if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { /* Host Virtual Serial Interface */ - int offset; switch (reg[0]) { case 0x30000000: offset = 0; From ffa27b6bc61c3be76a756100f777372768bcc3ab Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 28 Oct 2005 17:46:58 -0700 Subject: [PATCH 1249/1939] [PATCH] ppc64 memory model depends on NUMA Currently when we first select memory model (FLAT, DISCONTIG, SPARSE) then select whether the machine is NUMA. However NUMA systems may not be FLAT. This constraint it not honoured and we may configure a NUMA/FLAT system. Reorder the configuration such that we choose NUMA first which allows us to only list the memory models which are valid. We now default NUMA for known NUMA systems. Note that this new order also matches that used in x86. Signed-off-by: Andy Whitcroft Signed-off-by: Joel Schopp Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 13 +++++-------- arch/ppc64/Kconfig | 11 ++++------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c71ddc0c191a..967ecf92d6a7 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -538,6 +538,11 @@ config IRQ_ALL_CPUS source "arch/powerpc/platforms/pseries/Kconfig" +config NUMA + bool "NUMA support" + depends on PPC64 + default y if SMP && PPC_PSERIES + config ARCH_SELECT_MEMORY_MODEL def_bool y depends on PPC64 @@ -554,10 +559,6 @@ config ARCH_DISCONTIGMEM_DEFAULT def_bool y depends on ARCH_DISCONTIGMEM_ENABLE -config ARCH_FLATMEM_ENABLE - def_bool y - depends on PPC64 - config ARCH_SPARSEMEM_ENABLE def_bool y depends on ARCH_DISCONTIGMEM_ENABLE @@ -581,10 +582,6 @@ config NODES_SPAN_OTHER_NODES def_bool y depends on NEED_MULTIPLE_NODES -config NUMA - bool "NUMA support" - default y if DISCONTIGMEM || SPARSEMEM - config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" depends on PPC64 && SMP diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index b889277ab7de..42677cc96508 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -248,6 +248,10 @@ config HMT This option enables hardware multithreading on RS64 cpus. pSeries systems p620 and p660 have such a cpu type. +config NUMA + bool "NUMA support" + default y if SMP && PPC_PSERIES + config ARCH_SELECT_MEMORY_MODEL def_bool y @@ -263,9 +267,6 @@ config ARCH_DISCONTIGMEM_DEFAULT def_bool y depends on ARCH_DISCONTIGMEM_ENABLE -config ARCH_FLATMEM_ENABLE - def_bool y - config ARCH_SPARSEMEM_ENABLE def_bool y depends on ARCH_DISCONTIGMEM_ENABLE @@ -288,10 +289,6 @@ config NODES_SPAN_OTHER_NODES def_bool y depends on NEED_MULTIPLE_NODES -config NUMA - bool "NUMA support" - default y if DISCONTIGMEM || SPARSEMEM - config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" depends on SMP From d3f67fbb96b827c1a6a7a82689e589865581155c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 29 Oct 2005 15:31:17 +1000 Subject: [PATCH 1250/1939] powerpc: Add -mno-altivec for ARCH=powerpc builds Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 29cda0732703..2f4cce06a7e5 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -93,6 +93,9 @@ else endif endif +# No AltiVec instruction when building kernel +CFLAGS += $(call cc-option,-mno-altivec) + # Enable unit-at-a-time mode when possible. It shrinks the # kernel considerably. CFLAGS += $(call cc-option,-funit-at-a-time) From 0cb7b2afd79c5715cbd1d4eee826571fb17fdd65 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 29 Oct 2005 22:07:56 +1000 Subject: [PATCH 1251/1939] powerpc: Merge maple support code to arch/powerpc/platforms/maple Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Makefile | 1 + arch/powerpc/platforms/maple/Makefile | 1 + arch/powerpc/platforms/maple/maple.h | 12 ++++++++++++ .../maple_pci.c => powerpc/platforms/maple/pci.c} | 2 ++ .../platforms/maple/setup.c} | 11 +++-------- .../maple_time.c => powerpc/platforms/maple/time.c} | 2 ++ arch/ppc64/kernel/Makefile | 3 +-- 7 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 arch/powerpc/platforms/maple/Makefile create mode 100644 arch/powerpc/platforms/maple/maple.h rename arch/{ppc64/kernel/maple_pci.c => powerpc/platforms/maple/pci.c} (99%) rename arch/{ppc64/kernel/maple_setup.c => powerpc/platforms/maple/setup.c} (95%) rename arch/{ppc64/kernel/maple_time.c => powerpc/platforms/maple/time.c} (99%) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 01723d491b5d..172c0db63504 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_4xx) += 4xx/ obj-$(CONFIG_85xx) += 85xx/ obj-$(CONFIG_PPC_PSERIES) += pseries/ obj-$(CONFIG_PPC_ISERIES) += iseries/ +obj-$(CONFIG_PPC_MAPLE) += maple/ diff --git a/arch/powerpc/platforms/maple/Makefile b/arch/powerpc/platforms/maple/Makefile new file mode 100644 index 000000000000..1be1a993c5f5 --- /dev/null +++ b/arch/powerpc/platforms/maple/Makefile @@ -0,0 +1 @@ +obj-y += setup.o pci.o time.o diff --git a/arch/powerpc/platforms/maple/maple.h b/arch/powerpc/platforms/maple/maple.h new file mode 100644 index 000000000000..0657c579b840 --- /dev/null +++ b/arch/powerpc/platforms/maple/maple.h @@ -0,0 +1,12 @@ +/* + * Declarations for maple-specific code. + * + * Maple is the name of a PPC970 evaluation board. + */ +extern int maple_set_rtc_time(struct rtc_time *tm); +extern void maple_get_rtc_time(struct rtc_time *tm); +extern unsigned long maple_get_boot_time(void); +extern void maple_calibrate_decr(void); +extern void maple_pci_init(void); +extern void maple_pcibios_fixup(void); +extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel); diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/powerpc/platforms/maple/pci.c similarity index 99% rename from arch/ppc64/kernel/maple_pci.c rename to arch/powerpc/platforms/maple/pci.c index 633324b5e61b..340c21caeae2 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -25,6 +25,8 @@ #include #include +#include "maple.h" + #ifdef DEBUG #define DBG(x...) printk(x) #else diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/powerpc/platforms/maple/setup.c similarity index 95% rename from arch/ppc64/kernel/maple_setup.c rename to arch/powerpc/platforms/maple/setup.c index a107ed69a355..7ece8983a105 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -1,5 +1,5 @@ /* - * arch/ppc64/kernel/maple_setup.c + * Maple (970 eval board) setup code * * (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org), * IBM Corp. @@ -62,19 +62,14 @@ #include #include +#include "maple.h" + #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) #else #define DBG(fmt...) #endif -extern int maple_set_rtc_time(struct rtc_time *tm); -extern void maple_get_rtc_time(struct rtc_time *tm); -extern unsigned long maple_get_boot_time(void); -extern void maple_calibrate_decr(void); -extern void maple_pci_init(void); -extern void maple_pcibios_fixup(void); -extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel); extern void generic_find_legacy_serial_ports(u64 *physport, unsigned int *default_speed); diff --git a/arch/ppc64/kernel/maple_time.c b/arch/powerpc/platforms/maple/time.c similarity index 99% rename from arch/ppc64/kernel/maple_time.c rename to arch/powerpc/platforms/maple/time.c index 445cb7470bf5..40fc07a8e606 100644 --- a/arch/ppc64/kernel/maple_time.c +++ b/arch/powerpc/platforms/maple/time.c @@ -36,6 +36,8 @@ #include #include +#include "maple.h" + #ifdef DEBUG #define DBG(x...) printk(x) #else diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 3cf7f3dab511..327c08ce4291 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -55,8 +55,7 @@ obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_PPC_PMAC) += udbg_scc.o -obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ - udbg_16550.o +obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += smp-tbsync.o From c1c3a554a32c3de1340887caa5729d67ed6684d6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 29 Oct 2005 22:08:55 +1000 Subject: [PATCH 1252/1939] powerpc: 32-bit needs cur_cpu_spec exported too Somehow we ended up with an #ifdef CONFIG_PPC64 around the export of cur_cpu_spec, but raid6 as a module needs it on ppc32 as well as ppc64. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 1fb80baebc87..b91345fa0805 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -21,9 +21,7 @@ #include struct cpu_spec* cur_cpu_spec = NULL; -#ifdef CONFIG_PPC64 EXPORT_SYMBOL(cur_cpu_spec); -#endif /* NOTE: * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's From 3ee1fcac33eae824422b9b98d972a85e79672426 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 29 Oct 2005 22:10:38 +1000 Subject: [PATCH 1253/1939] powerpc: import a gfp_t fix to arch/powerpc/mm/pgtable_32.c This applies the same fix as Al Viro recently made to arch/ppc/mm/pgtable.c. Signed-off-by: Paul Mackerras --- arch/powerpc/mm/pgtable_32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 5792e533916f..f54fb9d3927a 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -114,9 +114,9 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) struct page *ptepage; #ifdef CONFIG_HIGHPTE - int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT; + gfp_t flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT; #else - int flags = GFP_KERNEL | __GFP_REPEAT; + gfp_t flags = GFP_KERNEL | __GFP_REPEAT; #endif ptepage = alloc_pages(flags, 0); From eb66ce6333742e32825f0294310ff53e284fa828 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 29 Oct 2005 22:11:06 +1000 Subject: [PATCH 1254/1939] powerpc: Remove T command from xmon help text since it no longer exists Signed-off-by: Paul Mackerras --- arch/powerpc/xmon/xmon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index d0623e0fd8ee..1124f1146202 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -210,7 +210,6 @@ Commands:\n\ s single step\n\ S print special registers\n\ t print backtrace\n\ - T Enable/Disable PPCDBG flags\n\ x exit monitor and recover\n\ X exit monitor and dont recover\n" #ifdef CONFIG_PPC64 From fb31690fbac6f4055c1765522752e4746759f5de Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 13:15:10 +0100 Subject: [PATCH 1255/1939] [ARM] Ensure machine information structures aren't optimised away Since the machine information structures are now static, the compiler might optimise them away. Mark them with __attribute_used__ to prevent this occuring. Signed-off-by: Russell King --- include/asm-arm/mach/arch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index 7273c6fd95b5..eb262e078c46 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -50,6 +50,7 @@ struct machine_desc { */ #define MACHINE_START(_type,_name) \ static const struct machine_desc __mach_desc_##_type \ + __attribute_used__ \ __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_##_type, \ .name = _name, From 8c18fe2562c45180c407872d05857c55c1e5e37b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 13:18:10 +0100 Subject: [PATCH 1256/1939] [ARM] Fix buggy __phys_to_pfn / __pfn_to_phys Macro arguments should _always_ be surrounded by parentheses when used to prevent unexpected problems with operator precedence. Signed-off-by: Russell King --- include/asm-arm/mach/map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h index 0619522bd926..b338936bde4f 100644 --- a/include/asm-arm/mach/map.h +++ b/include/asm-arm/mach/map.h @@ -27,8 +27,8 @@ struct meminfo; #define MT_ROM 6 #define MT_IXP2000_DEVICE 7 -#define __phys_to_pfn(paddr) (paddr >> PAGE_SHIFT) -#define __pfn_to_phys(pfn) (pfn << PAGE_SHIFT) +#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) +#define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) extern void create_memmap_holes(struct meminfo *); extern void memtable_init(struct meminfo *); From 57725f0a94435355214977bb9b0e5089bba1b173 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 15:51:14 +0100 Subject: [PATCH 1257/1939] [ARM] Rename 'data' to 'plat' in sa1100 MTD map driver Signed-off-by: Russell King --- drivers/mtd/maps/sa1100-flash.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 6a8e0caf9fdc..1920bcbc05d7 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -130,7 +130,7 @@ struct sa_subdev_info { char name[16]; struct map_info map; struct mtd_info *mtd; - struct flash_platform_data *data; + struct flash_platform_data *plat; }; struct sa_info { @@ -143,7 +143,7 @@ struct sa_info { static void sa1100_set_vpp(struct map_info *map, int on) { struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map); - subdev->data->set_vpp(on); + subdev->plat->set_vpp(on); } static void sa1100_destroy_subdev(struct sa_subdev_info *subdev) @@ -187,7 +187,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r goto out; } - if (subdev->data->set_vpp) + if (subdev->plat->set_vpp) subdev->map.set_vpp = sa1100_set_vpp; subdev->map.phys = phys; @@ -204,7 +204,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r * Now let's probe for the actual flash. Do it here since * specific machine settings might have been set above. */ - subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map); + subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map); if (subdev->mtd == NULL) { ret = -ENXIO; goto err; @@ -245,7 +245,7 @@ static void sa1100_destroy(struct sa_info *info) } static struct sa_info *__init -sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash) +sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) { struct sa_info *info; int nr, size, i, ret = 0; @@ -288,7 +288,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash subdev->map.name = subdev->name; sprintf(subdev->name, "sa1100-%d", i); - subdev->data = flash; + subdev->plat = plat; ret = sa1100_probe_subdev(subdev, res); if (ret) @@ -346,16 +346,16 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __init sa1100_mtd_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct flash_platform_data *flash = pdev->dev.platform_data; + struct flash_platform_data *plat = pdev->dev.platform_data; struct mtd_partition *parts; const char *part_type = NULL; struct sa_info *info; int err, nr_parts = 0; - if (!flash) + if (!plat) return -ENODEV; - info = sa1100_setup_mtd(pdev, flash); + info = sa1100_setup_mtd(pdev, plat); if (IS_ERR(info)) { err = PTR_ERR(info); goto out; @@ -372,8 +372,8 @@ static int __init sa1100_mtd_probe(struct device *dev) } else #endif { - parts = flash->parts; - nr_parts = flash->nr_parts; + parts = plat->parts; + nr_parts = plat->nr_parts; part_type = "static"; } From 0d2ef7d73e0b5173af3940139569bebd2375f441 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 15:57:20 +0100 Subject: [PATCH 1258/1939] [ARM] Add support for init/exit methods in sa1100 MTD map driver Signed-off-by: Russell King --- drivers/mtd/maps/sa1100-flash.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 1920bcbc05d7..50a1d434906a 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -223,7 +223,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r return ret; } -static void sa1100_destroy(struct sa_info *info) +static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat) { int i; @@ -242,6 +242,9 @@ static void sa1100_destroy(struct sa_info *info) for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); kfree(info); + + if (plat->exit) + plat->exit(); } static struct sa_info *__init @@ -275,6 +278,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) memset(info, 0, size); + if (plat->init) { + ret = plat->init(); + if (ret) + goto err; + } + /* * Claim and then map the memory regions. */ @@ -336,7 +345,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) return info; err: - sa1100_destroy(info); + sa1100_destroy(info, plat); out: return ERR_PTR(ret); } @@ -397,8 +406,11 @@ static int __init sa1100_mtd_probe(struct device *dev) static int __exit sa1100_mtd_remove(struct device *dev) { struct sa_info *info = dev_get_drvdata(dev); + struct flash_platform_data *plat = dev->platform_data; + dev_set_drvdata(dev, NULL); - sa1100_destroy(info); + sa1100_destroy(info, plat); + return 0; } From 822e5e72697ce06e4425c17d161b0482c7d9b6d4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 16:03:24 +0100 Subject: [PATCH 1259/1939] [ARM] Fix MTD device/partition destruction We should not delete MTD partitions when we registered a MTD device. Signed-off-by: Russell King --- drivers/mtd/maps/sa1100-flash.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 50a1d434906a..c38c2c311b8e 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -137,6 +137,7 @@ struct sa_info { struct mtd_partition *parts; struct mtd_info *mtd; int num_subdev; + unsigned int nr_parts; struct sa_subdev_info subdev[0]; }; @@ -228,8 +229,12 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla int i; if (info->mtd) { - del_mtd_partitions(info->mtd); - + if (info->nr_parts == 0) + del_mtd_device(info->mtd); +#ifdef CONFIG_MTD_PARTITIONS + else + del_mtd_partitions(info->mtd); +#endif #ifdef CONFIG_MTD_CONCAT if (info->mtd != info->subdev[0].mtd) mtd_concat_destroy(info->mtd); @@ -396,6 +401,8 @@ static int __init sa1100_mtd_probe(struct device *dev) add_mtd_partitions(info->mtd, parts, nr_parts); } + info->nr_parts = nr_parts; + dev_set_drvdata(dev, info); err = 0; From 14e66f767f5e8d023e098b475dc24ddc9a5dbdfd Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 16:08:31 +0100 Subject: [PATCH 1260/1939] [ARM] Allow MTD device name to be passed via platform data Allow SA1100 devices to pass the name of the flash device to the SA1100 map driver. Signed-off-by: Russell King --- arch/arm/mach-sa1100/generic.c | 2 ++ drivers/mtd/maps/sa1100-flash.c | 6 +++--- include/asm-arm/mach/flash.h | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 93619497779c..f94b0fbcdcc8 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "generic.h" @@ -283,6 +284,7 @@ static struct platform_device sa11x0mtd_device = { void sa11x0_set_flash_data(struct flash_platform_data *flash, struct resource *res, int nr) { + flash->name = "sa1100"; sa11x0mtd_device.dev.platform_data = flash; sa11x0mtd_device.resource = res; sa11x0mtd_device.num_resources = nr; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c38c2c311b8e..acf01ef9b575 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -301,7 +301,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) break; subdev->map.name = subdev->name; - sprintf(subdev->name, "sa1100-%d", i); + sprintf(subdev->name, "%s-%d", plat->name, i); subdev->plat = plat; ret = sa1100_probe_subdev(subdev, res); @@ -323,7 +323,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) * otherwise fail. Either way, it'll be called "sa1100". */ if (info->num_subdev == 1) { - strcpy(info->subdev[0].name, "sa1100"); + strcpy(info->subdev[0].name, plat->name); info->mtd = info->subdev[0].mtd; ret = 0; } else if (info->num_subdev > 1) { @@ -336,7 +336,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) cdev[i] = info->subdev[i].mtd; info->mtd = mtd_concat_create(cdev, info->num_subdev, - "sa1100"); + plat->name); if (info->mtd == NULL) ret = -ENXIO; #else diff --git a/include/asm-arm/mach/flash.h b/include/asm-arm/mach/flash.h index a92887d4b2cb..cd57436d9874 100644 --- a/include/asm-arm/mach/flash.h +++ b/include/asm-arm/mach/flash.h @@ -14,6 +14,7 @@ struct mtd_partition; /* * map_name: the map probe function name + * name: flash device name (eg, as used with mtdparts=) * width: width of mapped device * init: method called at driver/device initialisation * exit: method called at driver/device removal @@ -23,6 +24,7 @@ struct mtd_partition; */ struct flash_platform_data { const char *map_name; + const char *name; unsigned int width; int (*init)(void); void (*exit)(void); From 183e1a349466a1b90430a58f3efad25a3e555cb2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 16:09:59 +0100 Subject: [PATCH 1261/1939] [ARM] Add support for SA1100 Jornada flash device support This got dropped from the SA1100 flash driver a while back and never added to the platform support file. Add it back. Signed-off-by: Russell King --- arch/arm/mach-sa1100/jornada720.c | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 9c363bfcf310..89af0c831e8f 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -16,6 +18,7 @@ #include #include +#include #include #include @@ -108,6 +111,66 @@ static void __init jornada720_map_io(void) sa1100_register_uart(1, 1); } +static struct mtd_partition jornada720_partitions[] = { + { + .name = "JORNADA720 boot firmware", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "JORNADA720 kernel", + .size = 0x000c0000, + .offset = 0x00040000, + }, { + .name = "JORNADA720 params", + .size = 0x00040000, + .offset = 0x00100000, + }, { + .name = "JORNADA720 initrd", + .size = 0x00100000, + .offset = 0x00140000, + }, { + .name = "JORNADA720 root cramfs", + .size = 0x00300000, + .offset = 0x00240000, + }, { + .name = "JORNADA720 usr cramfs", + .size = 0x00800000, + .offset = 0x00540000, + }, { + .name = "JORNADA720 usr local", + .size = 0, /* will expand to the end of the flash */ + .offset = 0x00d00000, + } +}; + +static void jornada720_set_vpp(int vpp) +{ + if (vpp) + PPSR |= 0x80; + else + PPSR &= ~0x80; + PPDR |= 0x80; +} + +static struct flash_platform_data jornada720_flash_data = { + .map_name = "cfi_probe", + .set_vpp = jornada720_set_vpp, + .parts = jornada720_partitions, + .nr_parts = ARRAY_SIZE(jornada720_partitions), +}; + +static struct resource jornada720_flash_resource = { + .start = SA1100_CS0_PHYS, + .end = SA1100_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static void __init jornada720_mach_init(void) +{ + sa11x0_set_flash_data(&jornada720_flash_data, &jornada720_flash_resource, 1); +} + MACHINE_START(JORNADA720, "HP Jornada 720") /* Maintainer: Michael Gernoth */ .phys_ram = 0xc0000000, @@ -117,4 +180,5 @@ MACHINE_START(JORNADA720, "HP Jornada 720") .map_io = jornada720_map_io, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, + .init_machine = jornada720_mach_init, MACHINE_END From 13bfb34c10fae6016710f5f070043c8b94b40583 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 16:14:08 +0100 Subject: [PATCH 1262/1939] [ARM] Fix Assabet reboot with SA1100 MTD map driver Unfortunately, some devices forgot to reset the flash on reboot. Arrange for the map driver to suspend & resume the flash to ensure that it is in a sane state before rebooting. Signed-off-by: Russell King --- drivers/mtd/maps/sa1100-flash.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index acf01ef9b575..c81bec7b14d5 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -440,9 +440,17 @@ static int sa1100_mtd_resume(struct device *dev) info->mtd->resume(info->mtd); return 0; } + +static void sa1100_mtd_shutdown(struct device *dev) +{ + struct sa_info *info = dev_get_drvdata(dev); + if (info && info->mtd->suspend(info->mtd) == 0) + info->mtd->resume(info->mtd); +} #else #define sa1100_mtd_suspend NULL #define sa1100_mtd_resume NULL +#define sa1100_mtd_shutdown NULL #endif static struct device_driver sa1100_mtd_driver = { @@ -452,6 +460,7 @@ static struct device_driver sa1100_mtd_driver = { .remove = __exit_p(sa1100_mtd_remove), .suspend = sa1100_mtd_suspend, .resume = sa1100_mtd_resume, + .shutdown = sa1100_mtd_shutdown, }; static int __init sa1100_mtd_init(void) From 931db7d6880027bb2b6b0cb78a488ab1486e28b7 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 29 Oct 2005 16:28:26 +0100 Subject: [PATCH 1263/1939] [ARM] 3050/1: remove ixp2000_reg_write erratum #66 workaround Patch from Lennert Buytenhek The workaround that we do for avoiding triggering ixp2400 erratum #66 involves mapping I/O pages using XCB=101 instead of XCB=000 so that we prevent the I/O signal to the gasket from being asserted (which can cause data corruption.) But XCB=101 mappings are write-buffered while mappings using XCB=000 are not, which is why if we use XCB=101 mappings we do a readback for every CSR store in an attempt to make sure that the store has been pushed out of the xscale core and the gasket. Unfortunately, there are two issues with this: - we do a readback for every CSR store, which is wrong, because the register we are writing to might have unwanted side-effects on read, for example, in the case of the scratchpad ring enqueue/dequeue registers; and - the readback is totally ineffective in the way we currently do it, because we just issue a load but do not issue any instruction that depends on the return value of that load, so the xscale core does not wait for the load to complete before continuing. See this linux-arm-kernel mailing list post for further information: http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2005-September/031314.html This means that my ixp2400 boxes have been running for many months without a working readback in ixp2000_reg_write, without any apparent adverse effects. Two of them have been running for a week now with the actual readback deleted from ixp2000_reg_write, also without any apparent ill effects. So, because in its current form it does more harm than good, the readback in ixp2000_reg_write should simply be killed, as the patch below does. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/platform.h | 29 ------------------------- 1 file changed, 29 deletions(-) diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index abdcf51bd283..aabeef2454dd 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -15,39 +15,10 @@ #ifndef __ASSEMBLY__ -/* - * The IXP2400 B0 silicon contains an erratum (#66) that causes writes - * to on-chip I/O register to not complete fully. What this means is - * that if you have a write to on-chip I/O followed by a back-to-back - * read or write, the first write will happen twice. OR...if it's - * not a back-to-back transaction, the read or write will generate - * incorrect data. - * - * The official work around for this is to set the on-chip I/O regions - * as XCB=101 and then force a read-back from the register. - * - */ -#if defined(CONFIG_ARCH_ENP2611) || defined(CONFIG_ARCH_IXDP2400) || defined(CONFIG_ARCH_IXDP2401) - -#include /* Pickup local_irq_ functions */ - -static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) -{ - unsigned long dummy; - unsigned long flags; - - local_irq_save(flags); - *((volatile unsigned long *)reg) = val; - barrier(); - dummy = *((volatile unsigned long *)reg); - local_irq_restore(flags); -} -#else static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) { *((volatile unsigned long *)reg) = val; } -#endif /* IXDP2400 || IXDP2401 */ #define ixp2000_reg_read(reg) (*((volatile unsigned long *)reg)) /* From ecbea7a2dae94092db9566bcd1f38535e9b3cde9 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 29 Oct 2005 16:28:27 +0100 Subject: [PATCH 1264/1939] [ARM] 3051/1: turn ixp2000_reg_read into an inline function Patch from Lennert Buytenhek Turn ixp2000_reg_read into an inline function. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/platform.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index aabeef2454dd..6e5b6a955abe 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -15,11 +15,15 @@ #ifndef __ASSEMBLY__ +static inline unsigned long ixp2000_reg_read(volatile void *reg) +{ + return *((volatile unsigned long *)reg); +} + static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) { *((volatile unsigned long *)reg) = val; } -#define ixp2000_reg_read(reg) (*((volatile unsigned long *)reg)) /* * Boards may multiplex different devices on the 2nd channel of From b4a1f67fbfb848ded8cf0c6c305224534144ab2d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 29 Oct 2005 16:28:28 +0100 Subject: [PATCH 1265/1939] [ARM] 3053/1: introduce ixp2000_reg_wrb (ixp2000_reg_write plus readback) Patch from Lennert Buytenhek Introduce ixp2000_reg_wrb, which is a variant of ixp2000_reg_write that does a readback from the target register, to make sure that the write has been flushed out of the write buffer. Unlike the previous (ineffective) readback in ixp2000_reg_write, this readback is followed by an instruction that depends on the value of the readback so that the CPU actually stalls until the readback has completed. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/platform.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index 6e5b6a955abe..a66317ab2071 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -25,6 +25,31 @@ static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) *((volatile unsigned long *)reg) = val; } +/* + * On the IXP2400, we can't use XCB=000 due to chip bugs. We use + * XCB=101 instead, but that makes all I/O accesses bufferable. This + * is not a problem in general, but we do have to be slightly more + * careful because I/O writes are no longer automatically flushed out + * of the write buffer. + * + * In cases where we want to make sure that a write has been flushed + * out of the write buffer before we proceed, for example when masking + * a device interrupt before re-enabling IRQs in CPSR, we can use this + * function, ixp2000_reg_wrb, which performs a write, a readback, and + * issues a dummy instruction dependent on the value of the readback + * (mov rX, rX) to make sure that the readback has completed before we + * continue. + */ +static inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val) +{ + unsigned long dummy; + + *((volatile unsigned long *)reg) = val; + + dummy = *((volatile unsigned long *)reg); + __asm__ __volatile__("mov %0, %0" : "+r" (dummy)); +} + /* * Boards may multiplex different devices on the 2nd channel of * the slowport interface that each need different configuration From 1a47ebc0d971fbc47cd859a09956f7c7d001f5fd Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 29 Oct 2005 16:28:29 +0100 Subject: [PATCH 1266/1939] [ARM] 3059/1: fix XIP support Patch from Nicolas Pitre Fix XIP support after recent bootmem code refactoring. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/init.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index f4496813615a..fd079ff1fc53 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -363,20 +363,16 @@ static void __init bootmem_init(struct meminfo *mi) memcpy(&meminfo, mi, sizeof(meminfo)); -#ifdef CONFIG_XIP_KERNEL -#error needs fixing - p->pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PMD_MASK); - p->virtual = (unsigned long)&_stext & PMD_MASK; - p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK; - p->type = MT_ROM; - p ++; -#endif - /* * Clear out all the mappings below the kernel image. - * FIXME: what about XIP? */ - for (addr = 0; addr < PAGE_OFFSET; addr += PGDIR_SIZE) + for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); +#ifdef CONFIG_XIP_KERNEL + /* The XIP kernel is mapped in the module area -- skip over it */ + addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK; +#endif + for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE) pmd_clear(pmd_off_k(addr)); /* @@ -435,6 +431,18 @@ static void __init devicemaps_init(struct machine_desc *mdesc) for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) pmd_clear(pmd_off_k(addr)); + /* + * Map the kernel if it is XIP. + * It is always first in the modulearea. + */ +#ifdef CONFIG_XIP_KERNEL + map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PGDIR_MASK); + map.virtual = MODULE_START; + map.length = ((unsigned long)&_etext - map.virtual + ~PGDIR_MASK) & PGDIR_MASK; + map.type = MT_ROM; + create_mapping(&map); +#endif + /* * Map the cache flushing regions. */ From c514e58cb8eac0d21f4ab5011df75a09eb5edd50 Mon Sep 17 00:00:00 2001 From: Kenneth Tan Date: Sat, 29 Oct 2005 16:32:14 +0100 Subject: [PATCH 1267/1939] [ARM] 3022/1: Missing peripheral devices memory mapping definition for IXP46X processor Patch from Kenneth Tan Defining IXP46X peripheral devices memory mapping definitions that have been missed out: o Peripheral virtual base address is being adjusted to allow more headroom to add extra peripheral device addresses o Peripheral size is being increased to address the above needs o Virtual address of expansion bus and PCI configuration register needs to be adjusted as new peripheral device memory space is overlapping with their virtual address space Signed-off-by: Kenneth Tan Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp4xx/ixp4xx-regs.h | 73 +++++++++++++++-------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h index 004696a95bdb..2b149ed59149 100644 --- a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h +++ b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h @@ -36,11 +36,11 @@ * * 0x6000000 0x00004000 ioremap'd QMgr * - * 0xC0000000 0x00001000 0xffbfe000 PCI CFG + * 0xC0000000 0x00001000 0xffbff000 PCI CFG * - * 0xC4000000 0x00001000 0xffbfd000 EXP CFG + * 0xC4000000 0x00001000 0xffbfe000 EXP CFG * - * 0xC8000000 0x0000C000 0xffbf2000 On-Chip Peripherals + * 0xC8000000 0x00013000 0xffbeb000 On-Chip Peripherals */ /* @@ -52,22 +52,22 @@ * Expansion BUS Configuration registers */ #define IXP4XX_EXP_CFG_BASE_PHYS (0xC4000000) -#define IXP4XX_EXP_CFG_BASE_VIRT (0xFFBFD000) +#define IXP4XX_EXP_CFG_BASE_VIRT (0xFFBFE000) #define IXP4XX_EXP_CFG_REGION_SIZE (0x00001000) /* * PCI Config registers */ #define IXP4XX_PCI_CFG_BASE_PHYS (0xC0000000) -#define IXP4XX_PCI_CFG_BASE_VIRT (0xFFBFE000) +#define IXP4XX_PCI_CFG_BASE_VIRT (0xFFBFF000) #define IXP4XX_PCI_CFG_REGION_SIZE (0x00001000) /* * Peripheral space */ #define IXP4XX_PERIPHERAL_BASE_PHYS (0xC8000000) -#define IXP4XX_PERIPHERAL_BASE_VIRT (0xFFBF2000) -#define IXP4XX_PERIPHERAL_REGION_SIZE (0x0000C000) +#define IXP4XX_PERIPHERAL_BASE_VIRT (0xFFBEB000) +#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000) /* * Debug UART @@ -115,25 +115,48 @@ /* * Peripheral Space Register Region Base Addresses */ -#define IXP4XX_UART1_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x0000) -#define IXP4XX_UART2_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x1000) -#define IXP4XX_PMU_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x2000) -#define IXP4XX_INTC_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x3000) -#define IXP4XX_GPIO_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x4000) -#define IXP4XX_TIMER_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x5000) -#define IXP4XX_EthA_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x9000) -#define IXP4XX_EthB_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xA000) -#define IXP4XX_USB_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xB000) +#define IXP4XX_UART1_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x0000) +#define IXP4XX_UART2_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x1000) +#define IXP4XX_PMU_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x2000) +#define IXP4XX_INTC_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x3000) +#define IXP4XX_GPIO_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x4000) +#define IXP4XX_TIMER_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x5000) +#define IXP4XX_NPEA_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x6000) +#define IXP4XX_NPEB_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x7000) +#define IXP4XX_NPEC_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x8000) +#define IXP4XX_EthB_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x9000) +#define IXP4XX_EthC_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xA000) +#define IXP4XX_USB_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xB000) +/* ixp46X only */ +#define IXP4XX_EthA_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xC000) +#define IXP4XX_EthB1_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xD000) +#define IXP4XX_EthB2_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xE000) +#define IXP4XX_EthB3_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0xF000) +#define IXP4XX_TIMESYNC_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x10000) +#define IXP4XX_I2C_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x11000) +#define IXP4XX_SSP_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x12000) -#define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000) -#define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000) -#define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000) -#define IXP4XX_INTC_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x3000) -#define IXP4XX_GPIO_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x4000) -#define IXP4XX_TIMER_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x5000) -#define IXP4XX_EthA_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x9000) -#define IXP4XX_EthB_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xA000) -#define IXP4XX_USB_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xB000) + +#define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000) +#define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000) +#define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000) +#define IXP4XX_INTC_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x3000) +#define IXP4XX_GPIO_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x4000) +#define IXP4XX_TIMER_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x5000) +#define IXP4XX_NPEA_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_PHYS + 0x6000) +#define IXP4XX_NPEB_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_PHYS + 0x7000) +#define IXP4XX_NPEC_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_PHYS + 0x8000) +#define IXP4XX_EthB_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x9000) +#define IXP4XX_EthC_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xA000) +#define IXP4XX_USB_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xB000) +/* ixp46X only */ +#define IXP4XX_EthA_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xC000) +#define IXP4XX_EthB1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xD000) +#define IXP4XX_EthB2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xE000) +#define IXP4XX_EthB3_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0xF000) +#define IXP4XX_TIMESYNC_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x10000) +#define IXP4XX_I2C_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x11000) +#define IXP4XX_SSP_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x12000) /* * Constants to make it easy to access Interrupt Controller registers From 47e627ce83b6df9f4bb8e4b0a4dde1c5d7a4c929 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 29 Oct 2005 18:18:42 +0900 Subject: [PATCH 1268/1939] [PATCH] blk: fix merge bug in as-iosched as-iosched deals with aliased requests differently from other ioscheds. It links together aliased requests using rq->queuelist instead of spilling alises to dispatch queue like other ioscheds do. Requests linked in this way cannot be merged. Unfortunately, generic q->last_merge handling patch didn't take this into account and q->last_merge could be set to an aliased request resulting in Badness, corrupt list and eventually panic. This explicitly marks aliased requests to be unmergeable. Signed-off-by: Tejun Heo Signed-off-by: Linus Torvalds --- drivers/block/as-iosched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 4081c36c8c19..564172234819 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -1344,6 +1344,7 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia * Don't want to have to handle merges. */ as_del_arq_hash(arq); + arq->request->flags |= REQ_NOMERGE; } /* From 8d027de54c77d38eedc9b331c7a2a39807d34691 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 29 Oct 2005 19:37:40 +0400 Subject: [PATCH 1269/1939] [PATCH] fix ->signal->live leak in copy_process() exit_signal() (called from copy_process's error path) should decrement ->signal->live, otherwise forking process will miss 'group_dead' in do_exit(). Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/signal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/signal.c b/kernel/signal.c index f2b96b08fb44..6904bbbfe116 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -406,6 +406,8 @@ void __exit_signal(struct task_struct *tsk) void exit_signal(struct task_struct *tsk) { + atomic_dec(&tsk->signal->live); + write_lock_irq(&tasklist_lock); __exit_signal(tsk); write_unlock_irq(&tasklist_lock); From 7533624527b9afa5585ca43ba534758052d848e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 06:36:27 +0100 Subject: [PATCH 1270/1939] [PATCH] s2io iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/s2io.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d303d162974f..62d5041845e3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3045,7 +3045,7 @@ int s2io_set_swapper(nic_t * sp) int wait_for_msix_trans(nic_t *nic, int i) { - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 val64; int ret = 0, cnt = 0; @@ -3066,7 +3066,7 @@ int wait_for_msix_trans(nic_t *nic, int i) void restore_xmsi_data(nic_t *nic) { - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 val64; int i; @@ -3084,7 +3084,7 @@ void restore_xmsi_data(nic_t *nic) void store_xmsi_data(nic_t *nic) { - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 val64, addr, data; int i; @@ -3107,7 +3107,7 @@ void store_xmsi_data(nic_t *nic) int s2io_enable_msi(nic_t *nic) { - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + XENA_dev_config_t __iomem *bar0 = nic->bar0; u16 msi_ctrl, msg_val; struct config_param *config = &nic->config; struct net_device *dev = nic->dev; @@ -3157,7 +3157,7 @@ int s2io_enable_msi(nic_t *nic) int s2io_enable_msi_x(nic_t *nic) { - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 tx_mat, rx_mat; u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; From 4b4a5eaedfc098d825d4c34cad1f1115802512b7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 06:38:44 +0100 Subject: [PATCH 1271/1939] [PATCH] sata_sil24 iomem annotations and fixes trivial iomem annotations + missing memcpy_fromio() caught by those Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/sata_sil24.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 32d730bd5bb6..51855d3bac64 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -220,8 +220,8 @@ struct sil24_port_priv { /* ap->host_set->private_data */ struct sil24_host_priv { - void *host_base; /* global controller control (128 bytes @BAR0) */ - void *port_base; /* port registers (4 * 8192 bytes @BAR2) */ + void __iomem *host_base; /* global controller control (128 bytes @BAR0) */ + void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */ }; static u8 sil24_check_status(struct ata_port *ap); @@ -349,10 +349,12 @@ static struct ata_port_info sil24_port_info[] = { static inline void sil24_update_tf(struct ata_port *ap) { struct sil24_port_priv *pp = ap->private_data; - void *port = (void *)ap->ioaddr.cmd_addr; - struct sil24_prb *prb = port; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + struct sil24_prb __iomem *prb = port; + u8 fis[6 * 4]; - ata_tf_from_fis(prb->fis, &pp->tf); + memcpy_fromio(fis, prb->fis, 6 * 4); + ata_tf_from_fis(fis, &pp->tf); } static u8 sil24_check_status(struct ata_port *ap) @@ -376,9 +378,9 @@ static int sil24_scr_map[] = { static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) { - void *scr_addr = (void *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { - void *addr; + void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; return readl(scr_addr + sil24_scr_map[sc_reg] * 4); } @@ -387,9 +389,9 @@ static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) { - void *scr_addr = (void *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { - void *addr; + void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); } @@ -454,7 +456,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) static int sil24_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *port = (void *)ap->ioaddr.cmd_addr; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); @@ -467,7 +469,7 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } -static int __sil24_reset_controller(void *port) +static int __sil24_reset_controller(void __iomem *port) { int cnt; u32 tmp; @@ -493,7 +495,7 @@ static void sil24_reset_controller(struct ata_port *ap) { printk(KERN_NOTICE DRV_NAME " ata%u: resetting controller...\n", ap->id); - if (__sil24_reset_controller((void *)ap->ioaddr.cmd_addr)) + if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr)) printk(KERN_ERR DRV_NAME " ata%u: failed to reset controller\n", ap->id); } @@ -527,7 +529,7 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); struct sil24_port_priv *pp = ap->private_data; - void *port = (void *)ap->ioaddr.cmd_addr; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; u32 irq_stat, cmd_err, sstatus, serror; irq_stat = readl(port + PORT_IRQ_STAT); @@ -574,7 +576,7 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) static inline void sil24_host_intr(struct ata_port *ap) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - void *port = (void *)ap->ioaddr.cmd_addr; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; u32 slot_stat; slot_stat = readl(port + PORT_SLOT_STAT); @@ -689,7 +691,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_port_info *pinfo = &sil24_port_info[board_id]; struct ata_probe_ent *probe_ent = NULL; struct sil24_host_priv *hpriv = NULL; - void *host_base = NULL, *port_base = NULL; + void __iomem *host_base = NULL; + void __iomem *port_base = NULL; int i, rc; if (!printed_version++) @@ -771,7 +774,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) writel(0, host_base + HOST_CTRL); for (i = 0; i < probe_ent->n_ports; i++) { - void *port = port_base + i * PORT_REGS_SIZE; + void __iomem *port = port_base + i * PORT_REGS_SIZE; unsigned long portu = (unsigned long)port; u32 tmp; int cnt; From 2d3c0b7bedfd7a8e1870a046a434bd467e7c5349 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 06:46:03 +0100 Subject: [PATCH 1272/1939] [PATCH] missing include in infiniband use of IS_ERR/PTR_ERR in infiniband/core/agent.c, without a portable chain of includes pulling err.h (breaks on a bunch of platforms). Signed-off-by: Al Viro Acked-by: Roland Dreier Signed-off-by: Linus Torvalds --- drivers/infiniband/core/agent.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h index c5f3cfec942a..86d72fab37b0 100644 --- a/drivers/infiniband/core/agent.h +++ b/drivers/infiniband/core/agent.h @@ -39,6 +39,7 @@ #ifndef __AGENT_H_ #define __AGENT_H_ +#include #include extern int ib_agent_port_open(struct ib_device *device, int port_num); From f6b52e85a5d022008fe9f99eab7c9f41f155e3cd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 07:06:59 +0100 Subject: [PATCH 1273/1939] [PATCH] arguments out of order in class_device_create() call (s390) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/s390/char/vmlogrdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index a107fec4457a..b2d75de144c6 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -787,8 +787,8 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { return ret; } priv->class_device = class_device_create( - NULL, vmlogrdr_class, + NULL, MKDEV(vmlogrdr_major, priv->minor_num), dev, "%s", dev->bus_id ); From 9d86b7d37018c917837477dd4501d44bf8f3f98c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 07:08:49 +0100 Subject: [PATCH 1274/1939] [PATCH] missing bits in sparkspkr conversion Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/input/misc/sparcspkr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 5778220a18d2..29d97b12be7a 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -143,7 +143,7 @@ static int __init init_isa_beep(struct sparc_isa_device *isa_dev) sparcspkr_dev->name = "Sparc ISA Speaker"; sparcspkr_dev->event = isa_spkr_event; - input_register_device(&sparcspkr_dev); + input_register_device(sparcspkr_dev); return 0; } From 943eae03143790c71cf42fe13529f1b74ceb0266 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 07:32:07 +0100 Subject: [PATCH 1275/1939] [PATCH] missing exports of do_settimeofday() variants frv, sh64, ia64 and sparc64 do not have do_settimeofday() exported (the last two are using variant in kernel/time.c). Exports added to match the rest of architectures. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/frv/kernel/time.c | 1 + arch/sh64/kernel/time.c | 1 + kernel/time.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 8d6558b00e44..f43b734482e3 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -221,6 +221,7 @@ int do_settimeofday(struct timespec *tv) clock_was_set(); return 0; } +EXPORT_SYMBOL(do_settimeofday); /* * Scheduler clock - returns current time in nanosec units. diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index f4a62a10053c..43e395a14f49 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -253,6 +253,7 @@ int do_settimeofday(struct timespec *tv) return 0; } +EXPORT_SYMBOL(do_settimeofday); static int set_rtc_time(unsigned long nowtime) { diff --git a/kernel/time.c b/kernel/time.c index 40c2410ac99a..a3c2100470e1 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -532,6 +532,7 @@ int do_settimeofday (struct timespec *tv) clock_was_set(); return 0; } +EXPORT_SYMBOL(do_settimeofday); void do_gettimeofday (struct timeval *tv) { From 32b32c2c3566b206988fa30336ec6534759823b5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 11:49:33 +0100 Subject: [PATCH 1276/1939] [PATCH] amikbd fix it's input_allocate_device(), not input_dev_allocate()... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/input/keyboard/amikbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 3d63bc1ad322..4c8fb1f8631f 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -199,7 +199,7 @@ static int __init amikbd_init(void) if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) return -EBUSY; - amikbd_dev = input_dev_allocate(); + amikbd_dev = input_allocate_device(); if (!amikbd_dev) { printk(KERN_ERR "amikbd: not enough memory for input device\n"); release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100); From 018a2cdf1e633497bb4f01eb86a7cbffa611776d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 11:56:13 +0100 Subject: [PATCH 1277/1939] [PATCH] idmouse cleanup and overflow fix switched to simple_read_from_buffer(), killed broken use of min(). Incidentally, that use of min() had been fixed once, only to be reintroduced in commit 4244f72436ab77c3c29a6447af81734ab3925d85: [PATCH] USB: upgrade of the idmouse driver [snip] - if (count > IMGSIZE - *ppos) - count = IMGSIZE - *ppos; + count = min ((loff_t)count, IMGSIZE - (*ppos)); Note the lovely use of cast to shut the warning about misuse of min() up... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/misc/idmouse.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 3944a55ed74c..1dc3e0f73014 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -319,20 +319,8 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count return -ENODEV; } - if (*ppos >= IMGSIZE) { - up (&dev->sem); - return 0; - } - - count = min ((loff_t)count, IMGSIZE - (*ppos)); - - if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { - result = -EFAULT; - } else { - result = count; - *ppos += count; - } - + result = simple_read_from_buffer(buffer, count, ppos, + dev->bulk_in_buffer, IMGSIZE); /* unlock the device */ up(&dev->sem); return result; From a6e0eb3791dcefc6dd4db53a23de5cfb18fe9a97 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 12:02:00 +0100 Subject: [PATCH 1278/1939] [PATCH] bluetooth hidp is broken on s390 Bluetooth HIDP selects INPUT and it really needs it to be there - module depends on input core. And input core is never built on s390... Marked as broken on s390, for now; if somebody has better ideas, feel free to fix it and remove dependency... Signed-off-by: Al Viro Acked-by: Marcel Holtmann Signed-off-by: Linus Torvalds --- net/bluetooth/hidp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index 4e958f7d9418..edfea772fb67 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig @@ -1,6 +1,6 @@ config BT_HIDP tristate "HIDP protocol support" - depends on BT && BT_L2CAP + depends on BT && BT_L2CAP && (BROKEN || !S390) select INPUT help HIDP (Human Interface Device Protocol) is a transport layer From 942b6f62164cf8822dd03b1569777f4663d1abd7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 29 Oct 2005 12:07:11 +0100 Subject: [PATCH 1279/1939] [PATCH] type fix in arm/boot/compressed/misc.c spot the typo... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/boot/compressed/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 23434b56786a..50f13eec6cd7 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -30,7 +30,7 @@ unsigned int __machine_arch_type; #define putstr icedcc_putstr #define putc icedcc_putc -extern void idedcc_putc(int ch); +extern void icedcc_putc(int ch); static void icedcc_putstr(const char *ptr) From ac19bff25b6834d858274406a686f2227dd8489d Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 29 Oct 2005 13:58:21 -0400 Subject: [PATCH 1280/1939] [libata] ensure ->tf_read() hook reads Status and Error registers We want ->tf_read() to get a complete snapshot of all taskfile registers, without requiring the callers to manually call ata_chk_status() and ata_chk_err() themselves. This also fixes a minor bug in sata_vsc where the lower bits of the feature register were incorrectly placed in the HOB (high order bits) portion of struct ata_taskfile. --- drivers/scsi/libata-core.c | 4 ++++ drivers/scsi/pdc_adma.c | 2 +- drivers/scsi/sata_qstor.c | 2 +- drivers/scsi/sata_svw.c | 22 ++++++++++++++++------ drivers/scsi/sata_vsc.c | 20 ++++++++++++++------ 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f53d7b8ac33f..56c81f0aa1d9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -370,6 +370,8 @@ static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = ata_chk_err(ap); tf->nsect = inb(ioaddr->nsect_addr); tf->lbal = inb(ioaddr->lbal_addr); tf->lbam = inb(ioaddr->lbam_addr); @@ -402,6 +404,8 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = ata_chk_err(ap); tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 7999817915c3..af99feb9d237 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -490,7 +490,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_chk_status(ap); + u8 status = ata_check_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 250dafa6bc36..1aaf3304d397 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -433,7 +433,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_chk_status(ap); + u8 status = ata_check_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index e0f9570bc6dd..46208f52d0e1 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -84,6 +84,8 @@ /* Port stride */ #define K2_SATA_PORT_OFFSET 0x100 +static u8 k2_stat_check_status(struct ata_port *ap); + static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { @@ -136,16 +138,24 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = k2_stat_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readw(ioaddr->error_addr) >> 8; + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 5af05fdf8544..54273e0063c7 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -153,16 +153,24 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = ata_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; From d052d1beff706920e82c5d55006b08e256b5df09 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 29 Oct 2005 19:07:23 +0100 Subject: [PATCH 1281/1939] Create platform_device.h to contain all the platform device details. Convert everyone who uses platform_bus_type to include linux/platform_device.h. Signed-off-by: Russell King Acked-by: Greg Kroah-Hartman --- arch/arm/common/locomo.c | 2 +- arch/arm/common/sa1111.c | 2 +- arch/arm/common/scoop.c | 2 +- arch/arm/mach-aaec2000/core.c | 2 +- arch/arm/mach-h720x/h7202-eval.c | 2 +- arch/arm/mach-imx/generic.c | 2 +- arch/arm/mach-imx/mx1ads.c | 1 + arch/arm/mach-integrator/integrator_ap.c | 2 +- arch/arm/mach-integrator/integrator_cp.c | 2 +- arch/arm/mach-iop3xx/iop321-setup.c | 2 +- arch/arm/mach-iop3xx/iop331-setup.c | 2 +- arch/arm/mach-ixp2000/enp2611.c | 2 +- arch/arm/mach-ixp2000/ixdp2x00.c | 2 +- arch/arm/mach-ixp2000/ixdp2x01.c | 2 +- arch/arm/mach-ixp4xx/common.c | 1 + arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 2 +- arch/arm/mach-omap1/board-h2.c | 2 +- arch/arm/mach-omap1/board-h3.c | 2 +- arch/arm/mach-omap1/board-innovator.c | 2 +- arch/arm/mach-omap1/board-netstar.c | 2 +- arch/arm/mach-omap1/board-osk.c | 2 +- arch/arm/mach-omap1/board-perseus2.c | 2 +- arch/arm/mach-omap1/board-voiceblue.c | 2 +- arch/arm/mach-omap1/devices.c | 2 +- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/corgi_lcd.c | 2 +- arch/arm/mach-pxa/corgi_ssp.c | 2 +- arch/arm/mach-pxa/generic.c | 2 +- arch/arm/mach-pxa/idp.c | 2 +- arch/arm/mach-pxa/lubbock.c | 2 +- arch/arm/mach-pxa/mainstone.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/spitz.c | 2 +- arch/arm/mach-s3c2410/clock.c | 2 +- arch/arm/mach-s3c2410/cpu.c | 2 +- arch/arm/mach-s3c2410/devs.c | 2 +- arch/arm/mach-s3c2410/devs.h | 1 + arch/arm/mach-s3c2410/mach-anubis.c | 2 +- arch/arm/mach-s3c2410/mach-bast.c | 2 +- arch/arm/mach-s3c2410/mach-h1940.c | 1 + arch/arm/mach-s3c2410/mach-n30.c | 2 +- arch/arm/mach-s3c2410/mach-nexcoder.c | 2 +- arch/arm/mach-s3c2410/mach-otom.c | 2 +- arch/arm/mach-s3c2410/mach-rx3715.c | 1 + arch/arm/mach-s3c2410/mach-smdk2410.c | 1 + arch/arm/mach-s3c2410/mach-smdk2440.c | 1 + arch/arm/mach-s3c2410/s3c2410.c | 2 +- arch/arm/mach-s3c2410/s3c2440.c | 2 +- arch/arm/mach-sa1100/badge4.c | 2 +- arch/arm/mach-sa1100/cerf.c | 2 +- arch/arm/mach-sa1100/collie.c | 2 +- arch/arm/mach-sa1100/generic.c | 1 + arch/arm/mach-sa1100/jornada720.c | 2 +- arch/arm/mach-sa1100/neponset.c | 2 +- arch/arm/mach-sa1100/pleb.c | 2 +- arch/arm/mach-sa1100/simpad.c | 2 +- arch/arm/mach-versatile/core.c | 1 + arch/arm/plat-omap/usb.c | 2 +- arch/m32r/kernel/setup_m32700ut.c | 2 +- arch/m32r/kernel/setup_mappi.c | 2 +- arch/m32r/kernel/setup_mappi2.c | 2 +- arch/m32r/kernel/setup_mappi3.c | 2 +- arch/m32r/kernel/setup_opsput.c | 2 +- arch/mips/au1000/common/platform.c | 2 +- arch/ppc/platforms/4xx/ibm440ep.c | 1 + arch/ppc/platforms/4xx/ibmstb4.c | 1 + arch/ppc/platforms/4xx/redwood5.c | 2 +- arch/ppc/platforms/4xx/redwood6.c | 2 +- arch/ppc/platforms/chrp_pegasos_eth.c | 2 +- arch/ppc/platforms/cpci690.c | 1 + arch/ppc/platforms/ev64260.c | 1 + arch/ppc/platforms/ev64360.c | 1 + arch/ppc/platforms/hdpu.c | 1 + arch/ppc/platforms/katana.c | 1 + arch/ppc/platforms/radstone_ppc7d.c | 1 + arch/ppc/syslib/mpc52xx_devices.c | 1 + arch/ppc/syslib/mv64x60.c | 1 + arch/ppc/syslib/pq2_devices.c | 2 +- arch/sh/boards/superh/microdev/setup.c | 2 +- arch/um/drivers/net_kern.c | 1 + arch/um/drivers/ubd_kern.c | 1 + arch/xtensa/platform-iss/network.c | 1 + drivers/base/platform.c | 2 +- drivers/block/floppy.c | 2 +- drivers/char/s3c2410-rtc.c | 2 +- drivers/char/sonypi.c | 1 + drivers/char/tb0219.c | 2 +- drivers/char/vr41xx_giu.c | 2 +- drivers/char/vr41xx_rtc.c | 2 +- drivers/char/watchdog/mpcore_wdt.c | 2 +- drivers/char/watchdog/mv64x60_wdt.c | 2 ++ drivers/char/watchdog/s3c2410_wdt.c | 2 +- drivers/eisa/virtual_root.c | 2 +- drivers/firmware/dcdbas.c | 2 +- drivers/firmware/dell_rbu.c | 2 +- drivers/hwmon/hdaps.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-isa.c | 1 + drivers/i2c/busses/i2c-ixp2000.c | 2 +- drivers/i2c/busses/i2c-ixp4xx.c | 2 +- drivers/i2c/busses/i2c-mpc.c | 2 ++ drivers/i2c/busses/i2c-mv64xxx.c | 2 ++ drivers/i2c/busses/i2c-pxa.c | 1 + drivers/i2c/busses/i2c-s3c2410.c | 2 +- drivers/i2c/chips/isp1301_omap.c | 2 +- drivers/i2c/i2c-core.c | 1 + drivers/i2c/i2c-dev.c | 1 + drivers/input/keyboard/corgikbd.c | 2 +- drivers/input/keyboard/spitzkbd.c | 2 +- drivers/input/serio/ct82c710.c | 1 + drivers/input/serio/i8042.c | 1 + drivers/input/serio/maceps2.c | 2 +- drivers/input/serio/q40kbd.c | 1 + drivers/input/serio/rpckbd.c | 1 + drivers/input/touchscreen/corgi_ts.c | 2 +- drivers/mfd/mcp-sa11x0.c | 2 +- drivers/misc/hdpuftrs/hdpu_cpustate.c | 2 +- drivers/misc/hdpuftrs/hdpu_nexus.c | 2 +- drivers/mmc/pxamci.c | 2 +- drivers/mmc/wbsd.c | 2 +- drivers/mtd/maps/bast-flash.c | 2 +- drivers/mtd/maps/integrator-flash.c | 2 +- drivers/mtd/maps/ixp2000.c | 2 +- drivers/mtd/maps/ixp4xx.c | 2 +- drivers/mtd/maps/omap_nor.c | 2 +- drivers/mtd/maps/plat-ram.c | 2 +- drivers/mtd/maps/sa1100-flash.c | 2 +- drivers/mtd/nand/s3c2410.c | 2 +- drivers/net/depca.c | 2 +- drivers/net/dm9000.c | 1 + drivers/net/gianfar.c | 2 +- drivers/net/gianfar_mii.c | 1 + drivers/net/irda/pxaficp_ir.c | 1 + drivers/net/irda/sa1100_ir.c | 2 +- drivers/net/irda/smsc-ircc2.c | 1 + drivers/net/jazzsonic.c | 2 +- drivers/net/macsonic.c | 2 +- drivers/net/mipsnet.c | 1 + drivers/net/mv643xx_eth.c | 2 ++ drivers/net/smc91x.c | 2 +- drivers/net/tokenring/proteon.c | 1 + drivers/net/tokenring/skisa.c | 1 + drivers/pcmcia/au1000_generic.c | 2 +- drivers/pcmcia/hd64465_ss.c | 2 +- drivers/pcmcia/i82365.c | 2 +- drivers/pcmcia/m32r_cfc.c | 2 +- drivers/pcmcia/m32r_pcc.c | 2 +- drivers/pcmcia/omap_cf.c | 2 +- drivers/pcmcia/pxa2xx_base.c | 1 + drivers/pcmcia/pxa2xx_mainstone.c | 2 +- drivers/pcmcia/pxa2xx_sharpsl.c | 2 +- drivers/pcmcia/sa1100_generic.c | 1 + drivers/pcmcia/tcic.c | 2 +- drivers/pcmcia/vrc4171_card.c | 1 + drivers/scsi/hosts.c | 1 + drivers/serial/8250.c | 2 +- drivers/serial/imx.c | 2 +- drivers/serial/mpc52xx_uart.c | 2 +- drivers/serial/mpsc.c | 2 ++ drivers/serial/pxa.c | 2 +- drivers/serial/s3c2410.c | 2 +- drivers/serial/sa1100.c | 2 +- drivers/serial/vr41xx_siu.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/lh7a40x_udc.c | 2 ++ drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/host/isp116x-hcd.c | 1 + drivers/usb/host/ohci-au1xxx.c | 2 ++ drivers/usb/host/ohci-lh7a404.c | 2 ++ drivers/usb/host/ohci-omap.c | 2 ++ drivers/usb/host/ohci-ppc-soc.c | 2 ++ drivers/usb/host/ohci-pxa27x.c | 2 +- drivers/usb/host/ohci-s3c2410.c | 2 ++ drivers/usb/host/sl811-hcd.c | 1 + drivers/usb/host/sl811_cs.c | 1 + drivers/video/acornfb.c | 2 +- drivers/video/arcfb.c | 1 + drivers/video/backlight/corgi_bl.c | 2 +- drivers/video/dnfb.c | 2 ++ drivers/video/epson1355fb.c | 2 ++ drivers/video/gbefb.c | 2 +- drivers/video/imxfb.c | 2 +- drivers/video/pxafb.c | 2 +- drivers/video/q40fb.c | 1 + drivers/video/s1d13xxxfb.c | 2 +- drivers/video/s3c2410fb.c | 1 + drivers/video/sa1100fb.c | 2 +- drivers/video/sgivwfb.c | 2 ++ drivers/video/vesafb.c | 2 ++ drivers/video/vfb.c | 2 ++ drivers/video/w100fb.c | 2 +- include/asm-ppc/ppc_sys.h | 2 +- include/linux/device.h | 26 ------------------------ include/linux/serial_8250.h | 2 +- sound/arm/pxa2xx-ac97.c | 2 +- sound/core/init.c | 2 ++ 198 files changed, 214 insertions(+), 158 deletions(-) diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 5cdb4122f057..ad55680726ed 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 21e2a518ad3a..174aa86ee816 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index e8356b76d7c6..68b06d16f253 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -11,7 +11,7 @@ * */ -#include +#include #include #include diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 0c53dab80905..4e706d9ad368 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c index db9078ad008c..d75c8221d2a5 100644 --- a/arch/arm/mach-h720x/h7202-eval.c +++ b/arch/arm/mach-h720x/h7202-eval.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index cb14b0682cef..60e2361e98e8 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#include +#include #include #include #include diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index 4cbdc1fe04b1..708e1b3faa14 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index f368b85f0447..1f9061ca7ef4 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index aa34c58b96c4..93f7ccb22c27 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c index bb5091223b63..80770233b8d4 100644 --- a/arch/arm/mach-iop3xx/iop321-setup.c +++ b/arch/arm/mach-iop3xx/iop321-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c index a2533c3ab42f..53f60614498b 100644 --- a/arch/arm/mach-iop3xx/iop331-setup.c +++ b/arch/arm/mach-iop3xx/iop331-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index 9aa54de44740..643f5e1c3d93 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 8b4a839b6279..05dfcb48c2b6 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index fee1d7b73503..b21249908ae4 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 6c396447c4e0..f3c687cf0071 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index a20eabc132b0..4eb962fdb3a8 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index d46a70063b0c..4ee6bd8a50b8 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 2798613696fa..fc824361430d 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index fd9183ff2ed5..a2eac853b2da 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index d904e643f5ec..c851c2e4dfcb 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 21103df50415..a88524e7c315 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 2ba26e239108..354b157acb3a 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index bf30b1acda0b..3f018b296861 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index e8b3981444cd..3c5d901efeaa 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 60c8b9d8bb9c..247147f29b93 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index 370df113dc06..54162ba95414 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 136c269db0b7..591e5f32dbec 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 3248bc9b9495..afd5063b0ebe 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 01a83ab09ac3..7de159e2ab42 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index beccf455f796..1f6857d7747d 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index a48c64026e1f..887a8cb7b721 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -14,7 +14,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index f25638810017..86326307ab9f 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -16,7 +16,7 @@ */ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 09a5d593f04b..c722a9a91fcc 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index d0ab428c2d7d..4182ddf330da 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 8b3d5dc35de5..82e8253b1fa0 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index ca366e9e264d..687fe371369d 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index 08bc7d95a45d..f58406e6ef5a 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h index d6328f96728b..52c4bab5c761 100644 --- a/arch/arm/mach-s3c2410/devs.h +++ b/arch/arm/mach-s3c2410/devs.h @@ -15,6 +15,7 @@ * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv */ #include +#include extern struct platform_device *s3c24xx_uart_devs[]; diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 5ae80f4e3e67..8390b685c2b6 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index c1b5c63ec24a..0b71c896bbd1 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index 7efeaaad2361..0aa8760598f7 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 5c0f2b091f95..378d640ab00b 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c index c22f8216032d..42b0eeff2e0f 100644 --- a/arch/arm/mach-s3c2410/mach-nexcoder.c +++ b/arch/arm/mach-s3c2410/mach-nexcoder.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c index ad1459e402e2..a2eb9ed48fcd 100644 --- a/arch/arm/mach-s3c2410/mach-otom.c +++ b/arch/arm/mach-s3c2410/mach-otom.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 22d9e070fd68..8f2a90bf940b 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 2eda55a6b678..2c91965ee1c8 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index 6950e61b7914..d666c621ad06 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index a8bf5ec82602..0a2013a76549 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 833fa36bce05..4d63e7133b48 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index c92cebff7f8e..edccd5eb06be 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 23cb74885275..508593722bc7 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 7fd6e29c36b7..522abc036d3a 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 93619497779c..976380bde417 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 9c363bfcf310..9fb65cffa578 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 052e4caedb89..69f1970646c6 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index e17b58fb9c9c..58c18f9e9b7b 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index cfb6658e5cdf..439ddc9b06d6 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 7e4bdd07f4af..a1ca46630dda 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 14a836d7ac25..205e2d0b826d 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c index 708634b685e4..cb76916b014d 100644 --- a/arch/m32r/kernel/setup_m32700ut.c +++ b/arch/m32r/kernel/setup_m32700ut.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c index 4e709809efc5..501d798cf050 100644 --- a/arch/m32r/kernel/setup_mappi.c +++ b/arch/m32r/kernel/setup_mappi.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c index a1d801598aa4..7f2db5bfd626 100644 --- a/arch/m32r/kernel/setup_mappi2.c +++ b/arch/m32r/kernel/setup_mappi2.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c index a76412e883e8..9c79341a7b45 100644 --- a/arch/m32r/kernel/setup_mappi3.c +++ b/arch/m32r/kernel/setup_mappi3.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c index d7b7ec6d30f8..1fbb140854e7 100644 --- a/arch/m32r/kernel/setup_opsput.c +++ b/arch/m32r/kernel/setup_opsput.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c index 0776b2db5641..3c778d0f58a6 100644 --- a/arch/mips/au1000/common/platform.c +++ b/arch/mips/au1000/common/platform.c @@ -7,7 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#include +#include #include #include #include diff --git a/arch/ppc/platforms/4xx/ibm440ep.c b/arch/ppc/platforms/4xx/ibm440ep.c index 4712de8ff80f..65ac0b9c2d05 100644 --- a/arch/ppc/platforms/4xx/ibm440ep.c +++ b/arch/ppc/platforms/4xx/ibm440ep.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include #include diff --git a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c index d90627b68faa..7e33bb635443 100644 --- a/arch/ppc/platforms/4xx/ibmstb4.c +++ b/arch/ppc/platforms/4xx/ibmstb4.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include diff --git a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c index bee8b4ac8afd..611ac861804d 100644 --- a/arch/ppc/platforms/4xx/redwood5.c +++ b/arch/ppc/platforms/4xx/redwood5.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/ppc/platforms/4xx/redwood6.c b/arch/ppc/platforms/4xx/redwood6.c index 8b1012994dfc..b13116691289 100644 --- a/arch/ppc/platforms/4xx/redwood6.c +++ b/arch/ppc/platforms/4xx/redwood6.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c index cad5bfa153b2..d1af11c73ea1 100644 --- a/arch/ppc/platforms/chrp_pegasos_eth.c +++ b/arch/ppc/platforms/chrp_pegasos_eth.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c index f64ac2acb603..6ca7bcac9474 100644 --- a/arch/ppc/platforms/cpci690.c +++ b/arch/ppc/platforms/cpci690.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c index aa50637a5cfb..32358b3fb236 100644 --- a/arch/ppc/platforms/ev64260.c +++ b/arch/ppc/platforms/ev64260.c @@ -33,6 +33,7 @@ #include #include #include +#include #if !defined(CONFIG_SERIAL_MPSC_CONSOLE) #include #include diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c index 9811a8a52c25..4e6cc64b3efd 100644 --- a/arch/ppc/platforms/ev64360.c +++ b/arch/ppc/platforms/ev64360.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef CONFIG_BOOTIMG #include #endif diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c index ff3796860123..0f07e963de3c 100644 --- a/arch/ppc/platforms/hdpu.c +++ b/arch/ppc/platforms/hdpu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index 2b53afae0e9c..beb617141456 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_BOOTIMG #include #endif diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 0376c8cff5d1..7e65b7f1f626 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c index ad5182efca1d..da3c74bfdc92 100644 --- a/arch/ppc/syslib/mpc52xx_devices.c +++ b/arch/ppc/syslib/mpc52xx_devices.c @@ -15,6 +15,7 @@ #include #include +#include #include #include diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index 4849850a59ed..1227521c0da2 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c index 1d3869768f96..61668aad86e2 100644 --- a/arch/ppc/syslib/pq2_devices.c +++ b/arch/ppc/syslib/pq2_devices.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c index c18919941ec0..1c1d65fb12df 100644 --- a/arch/sh/boards/superh/microdev/setup.c +++ b/arch/sh/boards/superh/microdev/setup.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 1495007bf6c0..721e2601a75d 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -20,6 +20,7 @@ #include "linux/ctype.h" #include "linux/bootmem.h" #include "linux/ethtool.h" +#include "linux/platform_device.h" #include "asm/uaccess.h" #include "user_util.h" #include "kern_util.h" diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f73134333f64..b2c86257b0f8 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -35,6 +35,7 @@ #include "linux/blkpg.h" #include "linux/genhd.h" #include "linux/spinlock.h" +#include "linux/platform_device.h" #include "asm/segment.h" #include "asm/uaccess.h" #include "asm/irq.h" diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index 498d7dced1f4..0682ffd38175 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c @@ -33,6 +33,7 @@ #include #include #include +#include #include diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 75ce8711bca5..95f2af322c8f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -10,7 +10,7 @@ * information. */ -#include +#include #include #include #include diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 00895477155e..5eadbb9d4d71 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -177,7 +177,7 @@ static int print_unex = 1; #include #include #include -#include +#include #include /* for invalidate_buffers() */ /* diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index 887b8b2d7882..d724c0de4f28 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index f86c15587238..d05067dcea01 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index eb7058cbf015..24355b23b2ca 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -17,7 +17,7 @@ * 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 diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 683278bc5241..94641085faf8 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -19,7 +19,7 @@ * 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 diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c index a6dbe4da030c..5e3292df69d8 100644 --- a/drivers/char/vr41xx_rtc.c +++ b/drivers/char/vr41xx_rtc.c @@ -17,7 +17,7 @@ * 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 diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index 75ca84ed4adf..47a5f6ab4879 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c index 6d3ff0836c44..04e0d7e9680d 100644 --- a/drivers/char/watchdog/mv64x60_wdt.c +++ b/drivers/char/watchdog/mv64x60_wdt.c @@ -22,6 +22,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index b732020acadb..e7e20a6d64b0 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c index 15677f20bd85..0f97a0cb0ff4 100644 --- a/drivers/eisa/virtual_root.c +++ b/drivers/eisa/virtual_root.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 955537fe9958..8ed6ddbb9c5d 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -20,7 +20,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include #include diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 4f4ba9b6d182..125929c9048f 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 0015da5668a1..1e5dfc7805e2 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -27,7 +27,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 9888fae1f37a..13752bcb2afd 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 4fdc02411609..03672c9ca409 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -38,6 +38,7 @@ #include #include #include +#include static u32 isa_func(struct i2c_adapter *adapter); diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 42016ee6ef13..64552a376f2d 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 69303ab65e04..cc652c350814 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 8491633005b8..65b939a059e9 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -19,6 +19,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d0d2a6f1386e..6b48027b2ee3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -17,6 +17,8 @@ #include #include #include +#include + #include /* Register defines */ diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 44b595d90a4a..67ccbea24ba4 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6ced28e90070..a1268e534254 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index eaa4742e04fa..9dbb72fffbe2 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 02e335a04f09..82ea1b7ec914 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ea14c8f1c82b..8af0bd1424d2 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include static struct i2c_client i2cdev_client_template; diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 3210d298b3bc..d00d14bb637a 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -12,7 +12,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index cee9c734a048..0fa38a559cdf 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -12,7 +12,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index dd0f5bd90241..4da6c86b5d76 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -37,6 +37,7 @@ #include #include #include +#include #include diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 4bc40f159996..01e186422021 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -20,6 +20,7 @@ #include #include #include +#include #include diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 9880fc145d90..d857f7081adb 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 46093c507988..b44d255596c2 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 106f5eefd89a..52c49258f8a4 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 0ba3e6562bff..15e88eeae8d6 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -11,7 +11,7 @@ #include -#include +#include #include #include #include diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 720e7a326308..7daa0ed7331c 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 46de5c940555..9c4dd682ac74 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index c203b27269ea..165f3405df27 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -21,7 +21,7 @@ #include #include -#include +#include static int hdpu_nexus_probe(struct device *ddev); static int hdpu_nexus_remove(struct device *ddev); diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 8eba373d42d7..4da4a98bd590 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 3ace875decc4..942668e93a74 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 0ba0ff7d43b9..5f248ebe68e0 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index e39a98a0171c..d14a0185b8f4 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index a9f86c7fbd52..6815baee89d7 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 3fcc32884074..06e1c7fffed3 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index b17bca657daf..9c9f4116e50a 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -30,7 +30,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include #include #include #include diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 118b04544cad..e751e05fcc65 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 6a8e0caf9fdc..66b4c2780adc 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b47ebcb31e0f..bf2325df80c7 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/depca.c b/drivers/net/depca.c index c4aa5fe2840e..4d26e5e7d18b 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -254,7 +254,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index abce1f730d00..c0af6fb1fbba 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ae5a2ed3b264..962580f2c4ab 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -81,7 +81,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 1eca1dbca7f1..5a74d3d3dbe1 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index aef80f5e7c9c..9571145c2090 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 06883309916d..76e0b9fb5e96 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index bbac720cca63..424515d35932 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 8423cb6875f0..a74a5cfaf5bc 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 405e18365ede..e9c999d7eb39 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index f79f7ee72ab8..bbffb585b3b3 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 25c9a99c377b..6fe948c10e72 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -39,6 +39,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 0ddaa611cc61..901c960d342a 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -77,7 +77,7 @@ static const char version[] = #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index eb1423ede75c..d04c918ebef8 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -29,6 +29,7 @@ static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n #include #include #include +#include #include #include diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 3c7c66204f74..72cf708396be 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -36,6 +36,7 @@ static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n"; #include #include #include +#include #include #include diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index d90a634cebf5..f591839ab9cd 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index b57a0b98b4d6..561706ba4499 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 4a41f67d185d..7ce455d01cc9 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index c6ed70ea4812..2c22b4b3619d 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 3397ff28de6a..356a6fb416a1 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 2558c3cc91ec..47b5ade95bde 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index c2a12d53f6c7..7fa18fb814bc 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index bbe69b07ce50..5209d8c7764f 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a1178a600e3c..b54a8b8c0fca 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index b768fa81f043..122fb29b1e34 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index f158b67f6610..e31263864377 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 3d2dca675e02..38a028c725d4 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -24,6 +24,7 @@ #include #include #include +#include #include diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index f24d84538fd5..71dd1ebbe58f 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index afb7ddf200e0..f47d2c454e33 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5b3933b0c997..b9a1f523c9a8 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 8a79968f8ce1..0dd08a09e7e6 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -45,7 +45,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index efe79b1fd431..f4c709bc464b 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -52,6 +52,8 @@ * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. */ +#include + #include "mpsc.h" /* diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 8cc4cedadd99..16b2f9417af9 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 06a17dff1a73..036792328d49 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -63,7 +63,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index c4a789e6af44..ed618cc7ae96 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 2b623ab0e36e..01696b3e3f61 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -26,7 +26,7 @@ #endif #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 02106bebd5c1..975ace3f5b1e 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -50,7 +50,7 @@ #include #include #include - +#include #include #include diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 9b3673904daf..bc6269f10cbb 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -21,6 +21,8 @@ * */ +#include + #include "lh7a40x_udc.h" //#define DEBUG printk diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 41c96b0afbb3..387692a3611e 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f83a9262f953..ee9cd7869d92 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index ddb8fc591466..f9c3f5b8dd1c 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index a277e258eb6c..f0c78cf14b6c 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -18,6 +18,8 @@ * This file is licenced under the GPL. */ +#include + #include #define USBH_ENABLE_BE (1<<0) diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 238fa4ade615..336c766c6e29 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -16,6 +16,8 @@ * This file is licenced under the GPL. */ +#include + #include diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 45efeed1fcc3..277bcb902d3b 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -14,6 +14,8 @@ * This file is licenced under the GPL. */ +#include + #include #include #include diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 4832e57ae579..92cf6f4a1374 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -14,6 +14,8 @@ * This file is licenced under the GPL. */ +#include + /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index d287dcccd415..5181999c56c9 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -19,7 +19,7 @@ * This file is licenced under the GPL. */ -#include +#include #include #include #include diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index fab420a2ce71..ee1fc605b402 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -19,6 +19,8 @@ * This file is licenced under the GPL. */ +#include + #include #include #include diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 40169d9cf2b1..5607c0ae6835 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 38aebe361ca1..e73faf831b24 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index f02965f39501..9b6a39348f81 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index d28457e0c063..126daff1c848 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -47,6 +47,7 @@ #include #include #include +#include #include diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 1991fdb32dfb..4867498f68e8 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 1dbb82dca40b..1785686a7f11 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -6,6 +6,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 116e808d71cd..7363d0b25fdf 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -54,6 +54,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index d3c1922cb13a..fc0a1beef968 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 0b9301facbd3..64d9bcc38da3 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 6206da9dd5da..efd9333b05c2 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index 162012bb9264..8416b2e2b501 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index cb2f7a1de947..f4437430dc5f 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 3862d3cb1fb2..3cef90456a4b 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #include diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 78e5f194b0df..3d35b28aaac7 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -173,7 +173,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 8413907b379a..cf5106eab2d5 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -18,6 +18,8 @@ #include #include #include +#include + #include #include diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index b1243da55fc5..3cc23106641d 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -19,6 +19,8 @@ #include #include #include +#include + #include